stm32-rs icon indicating copy to clipboard operation
stm32-rs copied to clipboard

SPI DR is write-size sensitive

Open jonathanpallant opened this issue 3 years ago • 4 comments

The SPI2::DR field is defined in the PAC as 16-bits. However, writing a value to the FIFO this way places two 8-bit bytes into the FIFO, giving the same symptoms as this post: https://community.st.com/s/question/0D53W00000uVnbwSAC/spi-configured-to-send-8bit-sends-16bits

If I do this, I get eight bytes in the FIFO, every other byte is 0x00:

// Send data
dp.SPI2.dr.write(|w| w.dr().bits(buffer[0] as u16));
dp.SPI2.dr.write(|w| w.dr().bits(buffer[1] as u16));
dp.SPI2.dr.write(|w| w.dr().bits(buffer[2] as u16));
dp.SPI2.dr.write(|w| w.dr().bits(buffer[3] as u16));

If I do this instead, I get the four bytes I expect, not eight.

// Send data
let p = dp.SPI2.dr.as_ptr() as *mut u8;    
unsafe {
    p.write_volatile(buffer[0]);        
    p.write_volatile(buffer[1]);        
    p.write_volatile(buffer[2]);        
    p.write_volatile(buffer[3]); 
}

jonathanpallant avatar Aug 12 '22 20:08 jonathanpallant

The size of the field in the register doesn't change the access width, but instead it depends on the size of the register itself. I'm not sure which PAC you're looking at exactly but I guess most of them are similar. I believe the HALs generally do a direct pointer write as per your second example.

The CRC peripheral has a similar functionality which was addressed in https://github.com/stm32-rs/stm32-rs/pull/412 by adding some virtual registers for the other sizes - in fact looking over the comments there the applicability to SPI even came up then. If you'd like to try adding similar register aliases to SPI it sounds like a sensible thing to include.

adamgreig avatar Aug 13 '22 00:08 adamgreig

Oh, so it's doing a 32 bit write but the underlying register is only 16 bits so half gets thrown away.

Maybe the dr() docs could note that the hardware design makes the PAC function useless unless you are in 16 bit mode.

The chip was an STM32F030K6T6.

thejpster avatar Aug 13 '22 21:08 thejpster

Yea, it looks like at the moment the register is set to 32 bits wide in the SVD. It should be updated to 16 bits wide, and additionally you could add a second register at the same offset that was 8 bits wide and call it DR8 or something like that, which would then generate 8-bit writes when used.

I don't think it's useless even in 8-bit SPI mode - you can put two bytes in at once to load the SPI FIFO quicker. In any event it does accurately model the hardware peripheral; I think the HAL should be the place for abstracting over these details.

adamgreig avatar Aug 14 '22 00:08 adamgreig