2021-01-31 07:01 AM
I'm having a very strange issue. I update an OLED screen using SPI DMA.
The OLED itself is organized as 8 rows, 128bytes each.
I use the DMA to send framebuffer chunks containing the data (128 bytes) for one row.
When the callback is called, it checks if it's the last row and returns, or increases the row.
To set the row, it sends a 3-byte command in SPI blocking mode within the interrupt, then sends the next DMA transfer.
The issue is that randomly, the blocking transfer fails with HAL_BUSY.
It gets permanently stuck in BUSY state. I've tried adding big timeouts and continue trying, but no way.
The only function that access the SPI DMA reads the oledStatus and returns whenever is not in idle state.
This is basically my code:
uint8_t oledBuffer[1024];//
volatile uint8_t oledStatus=oled_idle;
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *device){
static uint8_t row=0;
if(device == &hspi2){ // Ensure its our spi handler
HAL_StatusTypeDef err=HAL_OK; // This was added for debugging
if(row>7){ // after the 8th row the screen refresh is complete, stop DMA
Oled_Set_CS(); // Release CS
row=0; // Reset row position
oledStatus = oled_idle;
return; // Return without retriggering DMA
}
oledStatus = oled_busy;
uint8_t cmd[3]={ 0xB0|row, 0x02, 0x10 }; // Set row command
Oled_Clear_CS(); // Enable OLED select
Oled_Clear_DC(); // Set command mode
// Send row command in blocking mode, 50mS timeout
err=HAL_SPI_Transmit(&hspi2, cmd, 3, 50);
if(err!=HAL_OK){
// This happens randomly, it can be after seconds or after 30 minutes
Error_Handler();
}
Oled_Set_DC(); // Set data mode
// Send row data in DMA interrupt mode
err=HAL_SPI_Transmit_DMA(&hspi2, oledBuffer+(128*row), 128);
if( err!= HAL_OK){
Error_Handler(); // This never happens
}
row++; // Increase row position
}
}
To debug where the error was being set , I turned off optimizations and set a lot of breakpoints in HAL_SPI_Transmit. They are never triggered.
As last resort I added this check at the end of HAL_SPI_Transmit, but it also never triggers.
However, the return code randomly changes to HAL_BUSY when it returns to the callback!
error:
hspi->State = HAL_SPI_STATE_READY;
/* Process Unlocked */
__HAL_UNLOCK(hspi);
if(errorcode!=HAL_OK){
asm("nop"); // If error code is not HAL_OK is should stop here, but never does!
}
return errorcode; // This should be always HAL_OK. But randomly changes to HAL_BUSY!
}
I've added lots of checks reading SPI hardware, HAL and handler bits to ensure everything is ready before transmiting, and they never detect anything wrong.
This happens both in STM32F072C8 and STM32F103C8 devices using the same hardware.
Am I missing something?
Regards