2015-02-23 12:04 PM
I would like to verify whether my solution is correct and robust. I already read a lot of similar topics, but didn't found reliable confirmation of my ideas. I just learned that many people suffer from stupid GP DMA implementation in STM32 and being advised to use dirty hacks like timers or even external rx pin interconnections (holy sh*t!)...
Hope my solution will be useful for others. Problem: System has large interrupt latencies (due to flash programming operations requiring disabling interrupts), which requires to use DMA for USART Rx. Implementation requirements: - write to circular buffer (classic circular buffer with read/write pointers, having nothing common with that stupid circular/double-buffering modes in DMA); - signal each byte reception (since it's not possible to predict DMA transfer size); - signal overflow condition and stop writing to buffer (in order to not disrupt data still not read by application); - interrupt handler execution time must be small. Proposed solution: Allocate small(!) DMA buffer, configure it in non-circular direct mode. Use USART RXNE interrupt handler to process reception in this way: - stop DMA - read DMA_SxNDTR register to calculate how much bytes received - flush data from DMA buffer to software circular buffer (if not overflowed) - restart DMA - signal reception to application. Use USART ORE flag to signal overflow to application. Why small DMA buffer ? Because interrupt handler must have time to process it completely, while DMA suspended and before next symbol arrives from USART shift register. For example, just 12 bytes will be enough to protect 1Mbaud stream from 100us latency, and make interrupt handler execution time short enough. Things make me worrying: - Reference Manual states: ''Note: If DMA is used for reception, do not enable the RXNEIE bit.'' - DMA transfer suspended while peripheral enabled. I expect that it's ok for peripheral-to-memory mode (at least). In case, if USART receive symbol, it should normally assert DMA request, and when DMA transfer enabled again, it should handle request immidiately, and everything should be ok... Please, confirm that solution is completely correct, i.e. it doesn't use undocumented features, doesn't rely on undefined behavior, does account all possible tricky edge cases. Thanks, Artem #stm32-usart-rx-dma-interrupt2015-02-23 01:24 PM
>>- Reference Manual states: ''Note: If DMA is used for reception, do not enable the RXNEIE bit.''
Yes, because you can only actually clear it by reading the USARTx->DR, now admittedly the DMA should get to it long before you're interrupt, if it does get to the interrupt and the DMA's not clearing it, you'll be stuck in the interrupt indefinitely. Having parallel DMA/IRQ just seems to create lots of race hazards. For a 1-byte solution, interrupts work just fine, the problem most people have is doing far too much in the interrupt service routines.2015-02-23 06:47 PM
Ah. Now I've got it! Thank you.
So... it means that my solution is incorrect. It was last chance. (I already spent several days trying to invent how to deal with this weird DMA.) P.S. Thank you, STMicroelectronics for such ''high-performance and flexible'' MCUs. We just should continue to be in pain...2015-02-25 09:29 PM
I didn't give up too easy and found out something you might be interested also !
AN3109 fragments:The receiver receives m (potentially unknown) data items using DMA. It is still possible to get the peripheral’s RXNE interrupt even when using DMA. In fact, the interrupt from the peripheral emulates the FIFO nonempty interrupt....There is no need to clear the RXNE flag in the receive interrupt routine, as it was automatically cleared by the DMA data read operation. However, the interrupt remains pending in the NVIC (even though the RXNE flag is no longer set).''FIFO nonempty interrupt'' - that's exactly what my intention to use this interrupt as. Also I inspected ''ARMv7-M Architecture Reference Manual'' carefully and come to following conclusion. If USART peripheral asserts RXNE interrupt signal regradless of mode, and processor always latches signal before DMA deasserts it, then interrupt guaranteed to be invoced (unless DMA explicitly clears NVIC pending flag, which seems to be highly unlikely). If so, it will always get to interrupt.Also it's possible to implement protection from scenario you described, when it may be stuck in interrupt indefinitely. Thank you for pointing that out. I'm ready to fight these race hazards ! :)
2015-02-25 11:51 PM
Are you aware of the fact that the named AN deals with the 'F10x family?
JW2015-02-26 12:05 AM
Yes, I noticed it some time ago and just now finished comparison and came to conclusion that it has no difference with F20x, I'm targeting. Or does have ? The only small difference I found is that F10x Reference Manual doesn't includes that note about RXNEIE...
2015-02-26 12:27 AM
>The only small difference I found is that F10x Reference Manual doesn't includes that note about RXNEIE...
And how small is that difference? ;) JW2015-02-26 05:11 AM
An alternative solution to the problem would be to have:
- the Vector Table - and USART RX ISRboth in RAM.A way to disable all other interrupts would be to set RAM-based interrupts as the highest priority ones and then set BASEPRI to the appropriate level.Hope this helps,Danish2015-02-26 07:52 PM
>>The only small difference I found is that F10x Reference Manual doesn't includes that note about RXNEIE...
>And how small is that difference? ;)
Are you going to ruin my last hope ? :)
>An alternative solution to the problem would be to have:
> - the Vector Table
> - and USART RX ISR
>both in RAM.
>A way to disable all other interrupts would be to set RAM-based interrupts as the highest priority ones and then set BASEPRI to >the appropriate level.
It's not clear what relation it have to defined problem. Assuming that you suppose solution for the example cause of problem (flash programming operations), it's not correct.Firstly, it's not enough to place only vector table and ISR in RAM, because ISR accesses other code in Flash (particullary, it calls RTOS functions in order to signal event to application). Therefore, whole code should be placed in RAM.Secondly, it was just example of what may cause high interrupt latency. My intention is to implement generic USART driver tolerant to any predefined max latency.2015-03-02 03:54 AM
I've just got official answer from ST !
That note is just safety warning to not clear RXNE status in interrupt routine in any way.In summary, I can assume my solution to be correct, since there are no other disproofs was given.