Closed inodentry closed 4 years ago
You're probably getting an overrun error, i.e. you're receiving at least two bytes while the DMA is off. Semihosting could definitely be the problem. Are you compiling with --release
? If so, how does your release profile look like ?
Yes, I am.
[profile.release]
lto = "fat"
codegen-units = 1
opt-level = "z"
incremental = false
panic = "abort"
OK, your information about overruns is helpful. It seems that that was indeed what is happening, because the debug print is quite slow (takes over a second) and data is coming in 4 bytes at a time (which is more than 2), every second, so all of them might come in while the print is ongoing.
I changed the print to only print the first byte of the received buffer, so that it happens faster, and now it is no longer glitching. EDIT: it actually still glitched after a minute or two of running.
Could you give me some info about how to recover from such an overrun situation? I'd like to be able to keep receiving data, even if I lose some data / the current transfer.
It probably won't be a problem when I deploy my project, because there will be no debug prints (obviously), but I don't want to have the risk of my communications getting stalled like this.
Also, perhaps we should close the issue, since this is not a bug like I thought.
You can check if you're getting an overrun with something like this:
use stm32f1xx_hal::pac::USART1;
let usart = unsafe { &*USART1::ptr() };
let overrun = usart.sr.read().ore().bit_is_set();
hprintln!("overrun ? {:?}, overrun);
// The bit is cleared by a read to SR follow by a read to DR,
// you might need to reset the DMA to get it going again, but not sure.
let _ = usart.dr.read();
This isn't a proper solution though, just a test.
Hmm.. so the API of this crate does not provide any clean mechanism to clear the overrun. That's awful. So much for safe rust abstractions...
I feel uncomfortable poking the registers with unsafe code, when I am also going to be using the safe DMA API as well, because it seems like I could easily violate the invariants / the state that the abstraction expects the hardware to be in.
Err, there is nothing unsafe/unsound about getting an overrun. It seems like that the HAL automatically clears it when not using DMA. It's a bit harder to detect it when using the DMA though, the user would need to detect it somehow and clear it.
Right now the HAL doesn't provide a convenience method for clearing the error, but it should be easy to PR in, I guess no one had this problem before.
However, as an advice, getting this error with DMA is a bit of a design flaw, try using a circular transfer instead, it's more suitable for a continuous stream of data, since the DMA stays on all the time.
Yeah, I get it. I assumed unsoundness before, because I didn't understand how DMA works and that I can get overruns like this. But now I do, I even edited the issue title to not be misleading ;)
Yes, it would be nice to have a safe API to deal with the overrun when using DMA. I don't understand how to add it though, so I can't make a PR myself.
Thanks for the useful information and pointing me in the right direction. I will look at how to do "circular transfer", it sounds like what I might need. I see there is an example in the repo.
EDIT: the issue has been determined to be an overrun.
I am trying to get two pills (a blackpill sending data and a bluepill receiving data) to communicate with each other using serial on USART1.
As an initial test to get it working, I loaded a program onto the sender blackpill that does a DMA Tx every second, writing a small buffer of 4 consecutive bytes, increasing every time. This works fine, it keeps sending data.
I am trying to receive those 4-byte transfers using DMA on the bluepill. I am printing the values using semihosting (with
hprintln
) to see what was received. The first transfer is successful, but then it stops receiving more bytes after the first byte of the second transfer.The USART is configured identically on both boards:
Here is the receiving code:
Here is the output I am getting:
(no more bytes are received and it keeps repeating that forever)
It consistently glitches after the first byte of the second transfer.
However, I suspect this is affected by the delay due to the slow debug print. And indeed, if I start the next read operation before printing the values, I can get a few more successful transfers.
With this simple modification to the code, just swapping the two lines:
I can now get a few more successful transfers (sometimes 3, sometimes 4), but it still glitches out after that:
And here is another run:
Note that the other board has been kept running all along and it just keeps sending the successive numbers in the sequence. I keep reloading the receiving program, and every time, it starts OK, receives the first transfer(s), and then glitches out.
~This kind of inconsistent behaviour smells of unsoundness to me. Perhaps it is a bug in the DMA implementation?~ EDIT: the issue has been determined to be an overrun.