-
Notifications
You must be signed in to change notification settings - Fork 19
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
STM32 processors cannot receive UART at even moderate baudrates while asleep #205
Comments
Hi, I just created a UART DMA driver for STM32 processors, you may check it out: |
This looks neat! Will have to take a deeper look sometime. By the way, you might be interested in this header: https://github.com/mbed-ce/mbed-os/blob/master/targets/TARGET_STM/stm_dma_utils.h It handles all the family-specific parts of setting up a DMA transaction and should let you remove the burden of implementing the ISR handlers correctly for each family (which was quite difficult to get right!) |
By the way, I would definitely accept PRs for adding this (or other UART functionality like enabling the FIFOs) into Mbed! |
OK, I'll consider submitting a PR later. |
Oh like, cherry pick the remaining changes from Mbed master? Yeah someone needs to do that, I'd accept a PR! The last time we did this was #185 |
@Ky-Ng and I were investigating a mysterious issue where an Mbed processor was dropping bytes sent to it by a Python script over a serial port (at 115200 baud). We were eventually able to localize the issue to this old Mbed bug: ARMmbed#8714. As it turns out, this is quite a serious issue.
It's a long thread, but to summarize:
This is a kinda difficult issue, and a case can be made that it's actually the STMicro hardware's fault for not including a FIFO buffer in the UART, something that I have never seen any MCU do before. And, to their credit, they did actually fix this, but only in their LPUART peripheral and in some of their newer processors (G0, G4, L5, U5, WB, WL). To make matters worse, even when the FIFO does exist in hardware, Mbed's TARGET_STM/serial_api.c isn't capable of actually using it! So this issue currently affects all STMicro chips, even the ones that wouldn't, in theory, be subject to the problem.
Conditions to Reproduce
This issue shows up under the following conditions:
Under these conditions, on an STM32L4 at 115200 baud, we observed that second byte sent by the PC would almost always be lost, and the firmware would only receive the 1st and 3rd bytes transmitted.
Note that this is easier to reproduce in Mbed CE than in Mbed OS, because we changed the default baudrate to 115200, and we also recommend that projects use buffered serial by default. Buffered serial is blocking by default, meaning that if you do a scanf() which scans multiple bytes from the console, and then send those bytes via a script (as in, not typing them by hand), that will create the necessary conditions for this problem to appear.
Also note that the following options do not cause or fix the issue, but might change the exact baudrate where it happens (making it appear to show up or go away):
target.lpticker_delay_ticks
optiontarget.tickless-from-us-ticker
optionCurrent Workarounds
Reducing the Baudrate
If you need sleeping, but can tolerate a slow console, the easy solution is to just slow down the serial port. 9600 baud should be OK, because that allows about 1ms for the processor to process each character. Just drop the following in your mbed_app.json:
and that should sort out the issue (though it will also take your serial speeds back to the 90s).
Disabling Sleep
If you want a fast console, but don't need sleeping, you can also easily work around the issue by disabling sleep entirely. To do that, you must create a custom target for your board, and add a block like
to its custom_targets.json file. This prevents the MCU from ever going to sleep, ensuring that it will be awake and alert whenever something sends it UART data. However, it is, of course, totally inappropriate for any applications which rely on low power operation.
Also note that if something else locks interrupts (via a critical section) for 10s of microseconds, the issue could still show up. So, I would advise using a little bit of caution with high baudrates even with this workaround, as there could be other places in first or third party code that are potential problem areas -- an exhaustive test hasn't been done.
Future Fixes
Making Use of the UART FIFO
If the Mbed drivers could be updated to use the UART peripheral's buffer, that could be the cleanest fix for the majority of devices -- the majority of STM32 chips either have a LPUART available or have UARTs with FIFOs. We just have to make sure that PCB designers know to prioritize the LPUARTs for any application that needs to receive at high-ish baudrates...
Reducing Default Baudrate
It would be fairly easy to reduce the baudrate for STM32 devices down to 9600 baud in targets.json5. However, I really don't like the idea of doing this, because is isn't intuitive for users why some devices would run at different baudrates than others. Plus, 9600 baud is just so damn slow... I hate the idea that we'd be using a serial port at 1980s speeds.
Printing a Warning
Another easy fix would be to update Mbed to print a warning at runtime if all 4 of the following conditions are true:
This way, users would be directed to either reduce the baudrate, turn off sleep, or disable serial Rx.
Using DMA
The best and most universal fix for this issue would be to use DMA to empty the UART Rx buffer instead of relying on an interrupt. This way, the buffer could be emptied as soon as the DMA controller is powered back on (if it even gets put to sleep at all!). This is definitely supported by the hardware, and we have at least some of the software infrastructure implemented now thanks to my prior work on SPI DMA. However, as @kjbracey mentioned here, using DMA for UART can be tough because you might want to do a circular buffer, and/or you need to carefully monitor how many characters the DMA has actually written in the background.
The text was updated successfully, but these errors were encountered: