cancel
Showing results for 
Search instead for 
Did you mean: 

24 bit SPI TransmitReceive oddity

Carl Farrington
Associate III

Hi. I think I have an idea why this does what it does, but wanted to ask advice anyway.

I am interfacing an STM32F767 over SPI with an SSD2828 parallel RGB to MIPI bridge.

It (amongst other options), uses what they describe as 24 bit SPI.

I am using the SPI peripheral in 8 bit mode, and it seems to work just fine.

The issue is, when using DMA, everything looks nice and the communication is all in one transaction.

When not using DMA, the SPI clock stops after 16 bits, and then after a delay picks up again.

I think it's because of the 16 bit buffer, and the software function having to empty the RX FIFO or whatever.

The annoying thing though, is that the recevied data is actually only 16 bits. The first byte is empty, but the HAL_TransmitReceive doesn't, erm, have a way of telling it to ignore the first byte on the rx side.

The communication protocol goes something like:

SPI Send: {73, 0 , 0

SPI Receive: {00, data, data]

so on the TX side we send the first byte to indicate that we want to receive data. So only 1 byte is send, and only 2 are received, in the overall 24-bit packet. Am I making any sense?

I suppose I was wondering, well, given that I'm a complete beginner with C/C++, and have relied on CubeMX to do all the DMA setup for me, well, I would rather not use DMA for this simple bit of LCD/bridge initialisation, because it's code I won't really understand.

Is it OK that the non-DMA SPI is broken up and the clock stops like it does? I seemed to get the correct response to that ID requests (it returned 0x28, 0x28 which is the chip ID).

I suppose it's a compromise given that HAL_SPI_TransmitReceive only allows you to give a single data size that is used for both tx and rx size, and that it can't be told to skip the first byte of the Receive side.

Here's my function:

void SSD2828_SPI_ReadReg24b3(uint8_t reg, uint8_t* data){
	//SSD2828's 24 bit 3 wire SPI mode. Set the STM32 peripheral for 8 bit mode, hardware NSS.
 
	 /* this is the initial register select, with the first byte identifying command, and write.
	  * you'd think it should be 0x71 to indicate read, but apparently not. We're just selecting the register
	  * next two bytes are the register. for 24 bit format it's MS-byte first in the data.
	  */
	uint8_t SPI24bitPkt1[3] = {0x70, 0x00, reg};
	HAL_SPI_Transmit(&hspi5, SPI24bitPkt1, 3, 100); // 
 
	uint8_t SPI24bitPkt2[3] = {0x73, 0, 0}; // yes this time we set the 1 for Read. The SSD2828 will start sending after the first byte.
	uint8_t receivedData[3];
	HAL_SPI_TransmitReceive(&hspi5, SPI24bitPkt2, receivedData, 3, 100);
	
	//now I want to lose that first byte and just return the actual data
	data[0]=receivedData[1];
	data[1]=receivedData[2];
}

And here's what I'm talking about.. the clean one is DMA, the other one is not DMA.

(I'm having trouble using the Image button here - I've just used Attach instead)

Also, totally unrelated, but there seem to be lots of people who don't realise that the Size parameter is one number for both rx & tx and that rx and tx have to be the same size. Loads of people on stackoverflow thinking it should be rx+tx (i.e. 6)

12 REPLIES 12
Carl Farrington
Associate III

You lost me a bit at the start there.. the not trying to stretch thing. Are you saying that you're not trying to stretch but you thought I was suggesting that you were?

If so that's not what I meant, I am talking about my LA capture above where there is a huge low-hold on the clock line between bytes 2 and 3. That would constitute a clock stretch in i2c wouldn't it.

> The bottom line though is that without DMA, that 24 bit SPI transaction looks nothing like what my

> target chip's datasheet says I should be sending it.

It's very unlikely that an SPI slave would not tolerate a gap in the transmission.

OTOH there's nothing wrong with DMA, too.

JW

Carl Farrington
Associate III

Thank you guys that's great.

Yes on the DMA side, it's just that I have zero understanding of what's going on - callback functions or dma-finished interrupts or whatever it might be, or if there are any other implications (limited number of DMA channels... therefore save them for stuff that needs performance?), but anyway perhaps I'll just read up and learn about it.