Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix one byte UART transmissions for lowrisc (maybe) #1817

Merged
merged 1 commit into from
May 11, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
51 changes: 22 additions & 29 deletions chips/lowrisc/src/uart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,14 @@ impl Uart<'a> {
let len = self.tx_len.get();

if idx < len {
// If we are going to transmit anything, we first need to enable the
// TX interrupt. This ensures that we will get an interrupt, where
// we can either call the callback from, or continue transmitting
// bytes.
self.enable_tx_interrupt();

// Read from the transmit buffer and send bytes to the UART hardware
// until either the buffer is empty or the UART hardware is full.
self.tx_buffer.map(|tx_buf| {
let tx_len = len - idx;

Expand All @@ -187,33 +195,6 @@ impl Uart<'a> {
self.tx_index.set(tx_idx + 1)
}
});

// If the FIFO started empty above, when the first character was written, it would have
// been immediately dispatched to the shift register, latching the TX_EMPTY state.
// That should be cleared before enabling the interrupt, so a subsequent empty state
// will latch the state transition again.
regs.intr_state.write(intr::tx_empty::SET);

// With data queued, (re)enable the TX interrupt if the FIFO is not empty
if !regs.status.is_set(status::txempty) {
self.enable_tx_interrupt();
if !regs.status.is_set(status::txempty) {
// Assuming the FIFO stayed non-empty while the interrupt was being enabled,
// our work here is done
return;
} else {
// Otherwise, turn off the interrupt and handle below
self.disable_tx_interrupt();
}
}
}

if self.tx_index.get() == self.tx_len.get() {
self.tx_client.map(|client| {
self.tx_buffer.take().map(|tx_buf| {
client.transmitted_buffer(tx_buf, self.tx_len.get(), ReturnCode::SUCCESS);
});
});
}
}

Expand All @@ -223,7 +204,19 @@ impl Uart<'a> {

if intrs.is_set(intr::tx_empty) {
self.disable_tx_interrupt();
self.tx_progress();

if self.tx_index.get() == self.tx_len.get() {
// We sent everything to the UART hardware, now from an
// interrupt callback we can issue the callback.
self.tx_client.map(|client| {
self.tx_buffer.take().map(|tx_buf| {
client.transmitted_buffer(tx_buf, self.tx_len.get(), ReturnCode::SUCCESS);
});
});
} else {
// We have more to transmit, so continue in tx_progress().
self.tx_progress();
}
} else if intrs.is_set(intr::rx_watermark) {
self.disable_rx_interrupt();
// TODO: real RX processing
Expand Down Expand Up @@ -268,7 +261,7 @@ impl hil::uart::Transmit<'a> for Uart<'a> {
tx_data: &'static mut [u8],
tx_len: usize,
) -> (ReturnCode, Option<&'static mut [u8]>) {
if tx_len == 0 {
if tx_len == 0 || tx_len > tx_data.len() {
(ReturnCode::ESIZE, Some(tx_data))
} else if self.tx_buffer.is_some() {
(ReturnCode::EBUSY, Some(tx_data))
Expand Down