cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F446 SPI DMA too fast for SSD1362

fing
Associate II

Hello,

I have implemented 4 wire SPI for my SSD1362 OLED controller. Here are my SPI transfer functions (both normal and DMA)

 

void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) {
	// Deselect when Tx Complete
	if (hspi == &hspi1) {
		HAL_GPIO_WritePin(GPIOA, OLED_CS_Pin, GPIO_PIN_SET);
	}
}

void SSD1362_SPI_Tx(uint8_t data) {
	while (!__HAL_SPI_GET_FLAG(&hspi1, SPI_FLAG_TXE));
	HAL_SPI_Transmit_DMA(&hspi1, &data, 1);
}

void SSD1362_SPI_TxBuffer(uint8_t *buffer, uint16_t len) {
	while (!__HAL_SPI_GET_FLAG(&hspi1, SPI_FLAG_TXE));
	HAL_SPI_Transmit_DMA(&hspi1, buffer, len);
}

void writeCommand(uint8_t byte) {
	HAL_GPIO_WritePin(GPIOA, OLED_CS_Pin, GPIO_PIN_RESET); // select OLED
	HAL_GPIO_WritePin(GPIOA, OLED_DC_Pin, GPIO_PIN_RESET); // command
	SSD1362_SPI_Tx(byte);
}

void writeData(uint8_t byte) {
	HAL_GPIO_WritePin(GPIOA, OLED_CS_Pin, GPIO_PIN_RESET); // select OLED
	HAL_GPIO_WritePin(GPIOA, OLED_DC_Pin, GPIO_PIN_SET); // data
	SSD1362_SPI_Tx(byte);
}

void writeData2(uint8_t *adat, uint16_t meret) {
	HAL_GPIO_WritePin(GPIOA, OLED_CS_Pin, GPIO_PIN_RESET); // select OLED
	HAL_GPIO_WritePin(GPIOA, OLED_DC_Pin, GPIO_PIN_SET); // data
	SSD1362_SPI_TxBuffer(adat, meret);
}

 

I am using big arrays to store the displayed pixels.  The OLED is 256x64 so for the whole screen, I need an uint8_t array with the size of 8192. 

What I have noticed is that when I use the DMA transfer function the display is unstable (shifted, or some pixels jitter). It looks like it is too fast for the SSD1362 so I need to introduce a small delay (even 1 ms works), then it works correctly.  I suspect it has to do something with the DMA buffer.

3 REPLIES 3
J_and_J
Associate

Hi Fing,

I would suggest two things.  First would be to slow down the SPI clock and see if you get the same problem.  The other suggestion would be, depending on how your system is set up, you might need some delay between when you turn on (or chip select "CS" and/or Reset) the SSD1362 and when you write the command/data.  If you're not using a hardwired CS pin, I would suggest you add some time between when you turn on the CS pin and when you start communication.  e.g.:

HAL_GPIO_WritePin(GPIOA, OLED_CS_Pin, GPIO_PIN_RESET); // select OLED

HAL_GPIO_WritePin(GPIOA, OLED_DC_Pin, GPIO_PIN_SET); // data

HAL_Delay(10); // insert a delay here.  Even 1ms is probably overkill. 

SSD1362_SPI_Tx(byte);

After re-reading your post, it seems you're adding the delay which solves the problem.  If you think about it, your MCU is running at a high speed and there is virtually no delay between when you turn on the CS pin and when you start the clock/data transfer.  The SSD1362 needs some time between CS and when it can start accepting clock cycles/data.  I looked at the spec sheet but it wasn't immediately clear what the minimum setup time is but it should be on the order of some microseconds, if that, so even 1ms is overkill.  You could add some NOPs in place of the delay to see exactly how much of a delay you need (or figure it out from the datasheet) in case you don't like waiting the whole millisecond.  

Can you provide a stripped-down version of your code including initilization and MCU settings?  (STM32CubeIDE files will be okay)  I would like to try a known working example on my system here.

fing
Associate II

Hi, 

Thank you for the answer, is it possible to do this in a non-blocking way?

Hi Fing,

I also have both normal and DMA transfer set up in my code.  I verified both transfer functions on SSD1306 and hacked the SSD1306 code to SSD1362.  I have my SSD1362 code working now but I've only tested on normal and haven't moved to DMA yet.  That said, my normal transfer does not use a delay between the CS/DC and my transmit function.  I have a couple of bugs left but will move back to DMA in the upcoming days.  I'll check if I need a delay or not then. I suspect that I won't need a delay because the HAL_SPI_TransmitReceive_DMA() has code in it that needs to run before SPI starts.  Granted, it's just a few 10s of clock cycles but I suspect that provides enough of a delay for the SSD1362 to settle before receiving data.  But it's just a guess.  In reality, I don't know.  I'll know more within some days I think.

To answer your question about non-blocking.  I can think of one way to do so.  In your code, first turn on the CS/DC pins and then set an internal timer for the amount of time you need for the delay (let's say 1ms) and have it generate an interrupt after hitting the timeout period (~1ms).  Then have timer's interrupt service routine turn off the timer, call your  HAL_SPI_TransmitReceive_DMA() function, and return.  You will lose a few clock cycles to turn on the timer and call/run your interrupt service routine but it's about as close to non-blocking as I can think of. 

There may be a function in STM32 SPI hardware that allows you to set a delay but I don't know...something you might want to check out.

I would suggest checking your code to make sure you're not having an indexing/"off by one" issue in copying/sending your data buffer to the SSD1362.

Please send an update here if you were/were not able to fix the issue.