-
Notifications
You must be signed in to change notification settings - Fork 49
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
SPI DMA for L4 #87
Comments
Could be a set up/tear down thing. I think Start the transfer like this: .cs_imu.set_low();
unsafe {
spi.transfer_dma(
&WRITE_BUF,
&mut IMU_READINGS,
IMU_TX_CH,
IMU_RX_CH,
ChannelCfg::default(),
ChannelCfg::default(),
DmaPeriph::Dma1,
);
} On TC interrupt, close it out like this: dma::clear_interrupt(
setup::IMU_DMA_PERIPH,
setup::IMU_RX_CH,
DmaInterrupt::TransferComplete,
);
cx.local.cs_imu.set_high();
cx.shared.spi1.lock(|spi1| {
// Note that this step is mandatory, per STM32 RM.
spi1.stop_dma(
setup::IMU_TX_CH,
Some(setup::IMU_RX_CH),
setup::IMU_DMA_PERIPH,
);
}); |
Oh interesting - I hadn't seen the need to call In the setup: let mut dma = Dma::new(dp.DMA1);
dma.enable_interrupt(DmaChannel::C2, DmaInterrupt::TransferComplete);
dma.enable_interrupt(DmaChannel::C5, DmaInterrupt::TransferComplete);
unsafe {
NVIC::unmask(Interrupt::TIM2);
NVIC::unmask(Interrupt::DMA1_CH2);
NVIC::unmask(Interrupt::DMA1_CH5);
} In the timer interrupt (which is working fine): self.spi.transfer_dma(
&[0; 8], // I don't really need this but don't know if possible to read without it
&mut BUFFER, // also of size 8
DmaChannel::C3,
DmaChannel::C2,
ChannelCfg::default(),
ChannelCfg::default(),
DmaPeriph::Dma1,
) Also tried: self.spi.read_dma(
&mut BUFFER,
DmaChannel::C2,
ChannelCfg::default(),
DmaPeriph::Dma1,
) And then this is never calling my |
Oh and I also added the |
I suspect the issue is with the write buffer. When transferring, the first Val is generally the device's first or only reg to read; the rest are padded to the read len. I think this might depend on the device you're reading from. So, the transfer you posted is telling the device to read from reg addr 0. |
Yes so in this case, I don't care about the SPI transfer data. I'm actually dealing with an SSI encoder, and given a clock it will output valid data on the SPI_MISO bus. It might be a factor in all of this, but I actually don't even configure the MISO pin, because I don't use it (and writing data to it might affect other things). I guess I should try configuring for RX only mode, but it was working without DMA so I didn't do that yet |
would it be possible to do something like this? self.spi.transfer_dma(
&[],
&mut BUFFER, // size 8
DmaChannel::C3,
DmaChannel::C2,
ChannelCfg::default(),
ChannelCfg::default(),
DmaPeriph::Dma1,
) I think I tried this but it didn't work. Your examples have one byte in the write buffer? |
Gotcha! I do a fair bit of SPI DMA (On G4 and H7), but the construct for the devices I use is, pass the first register to read, then the device fills the buf, incrementing the register. It does sound like for this you need I'll let you know if I have any ideas. So, I mislead you on |
Thanks for confirmation on that. Is there a set of registers you recommend poking around in? And I noticed there is a |
Status register; check what flags are set. |
Here's another mind-boggling one: I set up the DMA SPI write such that it will trigger when complete to unset the chip select. #[interrupt]
fn DMA1_CH5() {
dma::clear_interrupt(
DmaPeriph::Dma1,
DmaChannel::C5,
DmaInterrupt::TransferComplete,
);
defmt::println!("DMA1_CH5"); // this one here
free(|cs| {
access_global!(DRIVER, driver, cs);
driver.dma_tx_complete();
});
} But, when I take the |
Just remembered something that is definitely relevant here: I think your buffers are dropping before the reads/writes complete. The easiest way around this is using static buffers. (But any Rusty tricks you have to keep them alive will work). This is why I marked the dma fns as |
The main buffer I'm trying to read into is already static - pub static mut BUFFER: [u8;8] = [0; 8];
self.spi.read_dma(
&mut BUFFER,
DmaChannel::C2,
ChannelCfg::default(),
DmaPeriph::Dma1,
) I will double check the other buffers and see what they look like. Thanks! |
So I did some poking around the last couple days on this issue. One thing I notice off the bat is that I have an overrun flag set after I do the spi write with DMA. Since I'm using the Also I was trying to retrace the code and compare to the reference manual steps. I see that the I published the sample code I was playing with from above in a separate repo, so you can take a look and evaluate the same things I'm looking at: https://github.com/gworkman/reproduce-spi-dma-error I printed all of the register status, they are below. I realize you might not have access to L4 hardware so I appreciate that you've been very willing to help me out thus far :)
|
Hi @David-OConnor, I wanted to ping you and see if there is anything I can do to further debug this issue. After putting it down for a while, I'm looking to pick back up our rust-based firmware, as it is much more maintainable and enjoyable to write then the C-based alternative :) Any suggestions for debugging next steps? The repo in the above comment is still a valid reproduction of the issue |
Hello again!
Back again with another question, but perhaps a possible bug I've found. After reading all of the examples, I can't figure out why DMA isn't working on my STM32L431 board for SPI reads (writes work okay). Some of the things that I double checked:
SPI1_RX
, the channel isDMA1_CH2
, and forSPI2_RX
, the channel isDMA1_CH4
.NVIC
spi.read_dma
Also note that this happens for
SPI1
and forSPI2
.I'm happy to poke around some registers, but not sure where to start. Help appreciated!
Minimal reproducible example:
The console output:
The text was updated successfully, but these errors were encountered: