cancel
Showing results for 
Search instead for 
Did you mean: 

I2C2+DMA1 and UART4+DMA1

EJohn.17
Associate II

Hi all,

I'm having some trouble getting DMA to service sequential uses of I2C+DMA transactions.​

​I can have the I2C+DMA initialize our demodulator, which involves some 12,000 reads and writes. (So, I2C+DMA works *very, very well* when it works.) I can then send some text out UART using DMA, which works. (I’ve also done a lot of testing of just UART+DMA, and it similarly works very, very well when it works.) But, when I go back and try another I2C+DMA transaction -- even with no UART+DMA going on -- it hangs as soon as I try to start the DMA. That is, the stream turns on, but never seems to actually do anything, and no interrupts are ever called for it.

I took some screenshots of the registers for DMA1 as I was doing this, and there was absolutely no difference between the registers -- especially for stream 4, which is UART TX -- between just before doing the first, successful I2C+DMA series (demodulator initialization) and the second, unsuccessful I2C+DMA series (demodulator status getting). The only thing that happened between them was some UART+DMA, which completed fully and turned off the stream. Like I said, the registers for the UART+DMA stream were identical both before doing any UART stuff and after it was all done. Even LISR and HISR flags were fully cleaned up by UART to try and be safe.

The only thing I can think of is some artifact of the UART+DMA that is causing the DMA’s arbiter to get hung up on servicing UART and preventing I2C from getting time to run.

My work's wonderful firewall is unfortunately blocking my computer from logging into this forum, so I'm doing this mostly on my phone. As such, I will get back to posting the specific setup of each peripheral and DMA in a bit. But in short, the DMAs are just set up in normal mode (not circular, since lengths change) and are not using the FIFOs (direct mode). Stream 2 services I2C RX, stream 4 services UART TX, and stream 7 services I2C TX.

Thanks​!

3 REPLIES 3

A blind shot: Try maybe resetting I2C in the respective reset register in RCC, before the second round.

Which STM32, btw?

JW

EJohn.17
Associate II

Sorry for the delay. Looks like my work just finished getting the firewall to let me use the login process on this site.

Anyway, while waiting for all of that to get done, I worked more on this and eventually found that if I dropped the priority of the I2C and UART streams when they weren't in use, the streams that were hanging would get serviced by the arbiter. So, it does indeed appear to be some signal in the arbiter's logic that's getting stuck/staying asserted and preventing the lesser-priority streams from getting some service.

I found this in the reference manual for my STM32F446ZE:

9.3.3 DMA transactions

A DMA transaction consists of a sequence of a given number of data transfers. The number

of data items to be transferred and their width (8-bit, 16-bit or 32-bit) are softwareprogrammable.

Each DMA transfer consists of three operations:

• a loading from the peripheral data register or a location in memory, addressed through

the DMA_SxPAR or DMA_SxM0AR register

• a storage of the data loaded to the peripheral data register or a location in memory

addressed through the DMA_SxPAR or DMA_SxM0AR register

• a post-decrement of the DMA_SxNDTR register, containing the number of transactions

that still have to be performed

After an event, the peripheral sends a request signal to the DMA controller. The DMA

controller serves the request depending on the channel priorities. As soon as the DMA

controller accesses the peripheral, an Acknowledge signal is sent to the peripheral by the

DMA controller. The peripheral releases its request as soon as it gets the Acknowledge

signal from the DMA controller. Once the request has been deasserted by the peripheral,

the DMA controller releases the Acknowledge signal. If there are more requests, the

peripheral can initiate the next transaction.

It could for sure be me stopping the DMA too soon or turning off the peripheral too soon and the ACK signal not getting fully routed through everything and causing the arbiter to sit around waiting for it or something similar. Unfortunately, it seems no amount of delaying or reading of I2C registers makes the hanging go away; I still have to muck with the priorities of the streams in order to keep using everything. Resetting I2C also doesn't make the arbiter start servicing UART, either (but thanks for the suggestion, JW!).

For the time being, this is a good enough workaround for me. Because we have low, medium, high, and very high priorities I can keep everything parked in low and bump them up to either medium (for UART) or high (for I2C) when being used. UART and I2C will then get properly serviced and receive the DMA stream interrupts, as expected. The arbiter does appear to properly switch between the two according to their priorities and stream indices when both active, as well.

As far as I can tell, there's no silicon bug in the arbiter, just some condition where the requests from peripherals are getting stuck asserted.

EJohn.17
Associate II

Also, as for the FIFO stuff I mentioned, I ended up trying to just ignore them when set (and they get set a lot, typically immediately after a stream is enabled), and that's worked so far. It doesn't seem that the flag getting set is actually preventing either the DMA or the arbiter from just continuing normally.