24 bit SPI TransmitReceive oddity
- August 19, 2018
- 12 replies
- 4312 views
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)