2025-01-17 01:06 PM - edited 2025-01-17 01:13 PM
uint8_t my_buffer[ 1B_LEN_PREFIX + 24B_LEN_DATA + nB_LEN_SUFFIX ] = {0};
(void) HAL_SPI_TRANSMIT_DMA(&hspi2, &my_buffer[0], sizeof(my_buffer));
I'm using the SPI TX line only to drive an addressable LED, making a custom waveform from SPI bits to LED bits. Not using the SPI CLK line, although it does have to be defined in AF Mode for SPI to work at all.
Scenario:
* Using GPDMA in a non-linked list mode
* I am always ending on a low bit.
* After transfer complete, the MOSI goes high
* It usually floats down softly
* When I start a new transmission, there is a 40ns spike before my prefix (1B 0x00) data on subsequent transfers. This is because the SPI was disabled after ending high, re-enabled, and immediately goes high for a moment before DMA data loads.
* If I ended on a high bit, I would expect MOSI to be and stay high at the end of the transfer
* If we pad the DMA buffer with 15 bytes of 0x00 data or less, the line stays high, and floats back low
* If we pad the DMA buffer with 16 bytes or more of 0x00, the MOSI terminates low as expected
First scope picture, less than 15 bytes of data on the suffix. Notice the 40ns spike before the data, the dwell after when DMA finishes it raises high and weakly drops off (when debugger running, this stays high, IDK!). The spike is when starting a new transfer and immediately trying to go high again but DMA loading prefix data in.
Second scope picture, 16+ bytes of data on the suffix. No spike up front, because there is no raise at the end before disabling/completing DMA.
I'm using HAL to remove any possibility of my code causing the issue.
My working theory is that the DMA is loading an additional byte into the TXDR at the end of the transfer, that this byte starts high, this causes the SPI to end high but it's out of data so it stops. By padding it with enough data I'm shifting the "bad DMA" data out too. The SPI FIFO is 4B, this is GPDMA1 CH4 which is an 8 word / 32B block, but the numbers don't add up, my prefix + data is 25 bytes, so it would only need +7 to get to 32B. Something else is happening, and I feel it's behind the scenes.
I have no idea what is going on, and I'm not entirely confident in my solution.
Solved! Go to Solution.
2025-01-17 03:00 PM - edited 2025-01-19 02:34 PM
It's not an issue of leading. I'm ok with that padding, and it's fine. The issue is the number of bytes held low, doesn't matter until it does.
It's not the value I'm ending on. It's not an amount of time I'm holding for the LED data line low. It's a number of bytes loaded into DMA that allows MOSI to interpret that it's last held or next ready data is a zero, not a one to pre-set as high.
EDIT: Adding "an appropriate number of zeros before the data" is not a solution. This LED unlatches at a (datahseet lie) of 50us. For me, that's 300-some bytes of zeros to send first, even doing this as a GPIO hold, or an SPI output of fixed source/destination and 300 len, this is not acceptable.
The spike/glitch of turning SPI back on after it thought it ended ready to transmit a high bit next, at 40us is enough to throw our data off, it counts as a high bit with some low after it, not in datasheet spec at all, but the LED counts it and shifts our data out.
The only acceptable solution has been to pad the DMA with so much zero data that is happens to hold low, we can not however confirm WHY this is happening, so we aren't confident that another change later won't move that padding around and we see the effect some back.
Because the DMA buffer appears to be all zeros, and the SPI-TXDR register is not readable, I'm not sure we'll ever know for sure.
2025-01-17 02:34 PM
That's know for ages, nasty but not really a big problem. Just add the proper number of all-zero frames for reset before WS data. Long one after the useful data does not spoil anything for WS2812.
2025-01-17 03:00 PM - edited 2025-01-19 02:34 PM
It's not an issue of leading. I'm ok with that padding, and it's fine. The issue is the number of bytes held low, doesn't matter until it does.
It's not the value I'm ending on. It's not an amount of time I'm holding for the LED data line low. It's a number of bytes loaded into DMA that allows MOSI to interpret that it's last held or next ready data is a zero, not a one to pre-set as high.
EDIT: Adding "an appropriate number of zeros before the data" is not a solution. This LED unlatches at a (datahseet lie) of 50us. For me, that's 300-some bytes of zeros to send first, even doing this as a GPIO hold, or an SPI output of fixed source/destination and 300 len, this is not acceptable.
The spike/glitch of turning SPI back on after it thought it ended ready to transmit a high bit next, at 40us is enough to throw our data off, it counts as a high bit with some low after it, not in datasheet spec at all, but the LED counts it and shifts our data out.
The only acceptable solution has been to pad the DMA with so much zero data that is happens to hold low, we can not however confirm WHY this is happening, so we aren't confident that another change later won't move that padding around and we see the effect some back.
Because the DMA buffer appears to be all zeros, and the SPI-TXDR register is not readable, I'm not sure we'll ever know for sure.