David-OConnor / stm32-hal

This library provides access to STM32 peripherals in Rust.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

F303 DMA operation hangs

MauroMombelli opened this issue · comments

after exactly 2 DMA transfer, the START bit from i2c CR2 remains HIGH, and the while loop inside of the write/read/write_dma/read_dma will hangs forever.
I know it is working because the data i read is as expected from when i use non-dma i2c, also i tried to use write_dma to start the chip, enabling only some of the axis, and i get data as expected, 0 fro disabled axis and actual values in expected range for the others.
So the dma read/write are "working"

snippet:

let BUF = [0x28 + 0x80]; // 0x80 mean multiread
let mut ANSWER = [0, 0, 0, 0, 0, 0];
loop {

    i2c.write(addr, &BUF).ok(); // request register, currently not using DMA as there is no way to know if it is completed

    unsafe { i2c.read_dma(addr, &mut ANSWER, stm32_hal2::dma::DmaChannel::C7, Default::default(), &mut dma); }

    delay.delay_ms(1000);
    //toggle led
    if led.is_high(){led.set_low()}else{led.set_high()}
}

NOTE 1:
For F303 many things are different from example/i2c.rs (that also should not compile as there are some spelling error)
in particular dma::mix() does not exist, i guess is not necessary for F3 and F4? it is very confusing, maybe should be thre anyway, simply doing nothing, at least wont break compilation.

NOTE 2:
now i have a delay before starting the next read/write operation, to make sure i am not trying to overlap the write on the dma read, but that is not good and i would love to have a way to know if the dma transfer is completed, without having to enable interrupt.

i reduced the test to:

let BUF = [0x20, 0x77];
unsafe { i2c.write_dma(addr, &BUF, true, stm32_hal2::dma::DmaChannel::C6, Default::default(), &mut dma); }
delay.delay_ms(10);
unsafe { i2c.write_dma(addr, &BUF, true, stm32_hal2::dma::DmaChannel::C6, Default::default(), &mut dma); }

the result are consistent:
first write is fine:
image
the second one hangs:
image

tested also disabling clock stretch, and changing i2c noise filter to analog or digital 5, without success. As the sensor works 100% reliable for long time on non-dma, im very lost. I could not find any errdata orclue about what is going on here

similar issue:
https://community.st.com/s/question/0D53W00000DGk7TSAT/stm32-communication-with-a-display-via-i2c-over-dma

I'll take a look and get back to you. And clarify the example. Mux is not used on F3 - it's for newer STM32s. F3 channels are hard-set.

If you don't want to use interrupts, you can poll on if the DMA xfer is complete (dma.transfer_is_complete() method) But you are then throwing out the main benefit of DMA.

I'll take a look and get back to you. And clarify the example. Mux is not used on F3 - it's for newer STM32s. F3 channels are hard-set.

thanks, im much more familiar with F4 series, so i was confused.

If you don't want to use interrupts, you can poll on if the DMA xfer is complete (dma.transfer_is_complete() method)

oh, i didnt think to look into the DMA class, thanks!

But you are then throwing out the main benefit of DMA.

Not in my case, I need to read few sensor on different bus @ ~1KHz, combine result and send the result to uart; reading one I2c sensor has shown here, take my main loop from 420000 loops/s to 1440 loops/s, so pretty much I am wasting all my precious time waiting for data.
By just moving the read of the slowest (or all) sensors to DMA should be more than enough to fix the problem.

What's the word?

Closing pending further information.

Issue is still present with 1.5.3
I looked around and it seems there may be some issue with i2c driver on all stm32, but i dont know enough to confirm if it is the case (see https://electronics.stackexchange.com/questions/267972/i2c-busy-flag-strange-behaviour)

I would like to propose an alternative solution tho; the driver should NOT have any infinite loop, or at least a timeout alternative should be provided, so it would be possible to try a software recover, or at least not hang the rest of the system.