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 uart::flush with FIFO at Half-Duplex mode #2895

Merged
merged 1 commit into from
May 21, 2024

Conversation

qwerty19106
Copy link
Contributor

@qwerty19106 qwerty19106 commented Apr 30, 2024

CC #2875

The problem (STM32G030C8, usart_v4, FIFO always enabled)

I make Uart with Half-Duplex mode, write ~16 bytes, then call blocking_flush, then call read_until_idle. No other side, only pull up.
As result I get ~7 last bytes which was sent over uart.write.

I did a little research and found out that the TC flag works correctly. It this is confirmed by tests also.

When the last data is written to the USART_TDR register, wait until TC = 1.
–When FIFO mode is disabled, this indicates that the transmission of the last frame
is complete.
–When FIFO mode is enabled, this indicates that both TXFIFO and shift register are
empty.
изображение

Possible it is errate, but I not found it within official errata.

Solution

Now I clear cr1.re flag before write, this solves the problem.

The ideal cycle read-write in Half-Duplex master mode:
write - write - ... - flush - read
Then we can clear cr1.re before write, and set after flush.
But we should call flush before read, but it is impossible with current API.

I propose two variants (only for half-duplex):

  1. Add flush to start of read, clear cr1.re before write, and set after flush.
    It requires the real async flush, which I can add some later.
  2. Clear cr1.re before write, and set after flush, and set before read.
    It is some not obvious because after flush the some bytes can be read before we call read. But without flush the receiver will be disabled until read.

It implement variant 1 in this PR, and wait any ideas and discussion.

@@ -502,6 +515,10 @@ impl<'d, T: BasicInstance> UartRx<'d, T, Async> {
) -> Result<ReadCompletionEvent, Error> {
let r = T::regs();

if r.cr3().read().hdsel() {
r.cr1().modify(|reg| reg.set_re(false));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be true?

@Dirbaio
Copy link
Member

Dirbaio commented Apr 30, 2024

I think with Option 2 you can still receive your own bytes if you do .write(), .read() without a flush, because .read() will reenable the receiver when still transmitting. Perhaps do option 2, but instead make .read() do a flush? so .write(); .read() Just Works even if you don't call flush?

@qwerty19106
Copy link
Contributor Author

I didn't quite understand your point.
You suggest call flush at the end of write?
Some driver calls write - write - flush - read. In this case the flush will be called between two write.

@Dirbaio
Copy link
Member

Dirbaio commented Apr 30, 2024

no. call flush at the start of read. so that write + read works. with the changes in this PR, only write + flush + read works.

@qwerty19106
Copy link
Contributor Author

Done.
I think the Uart::split method should not be available for Half-Duplex mode. But I not know how do it in current API: it requires particular struct HalfDuplexUart, and it broke BufferedUart.

Copy link
Member

@Dirbaio Dirbaio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you!

@Dirbaio Dirbaio marked this pull request as ready for review May 21, 2024 21:25
@Dirbaio Dirbaio added this pull request to the merge queue May 21, 2024
Merged via the queue into embassy-rs:main with commit 4b5026e May 21, 2024
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants