2019-08-23 02:02 AM
Hi everyone,
I'm using the STM HAL for my SPI
communication in master mode. To
readout my ADC, I implemented a state machine, which starts
the ADC conversion and then once a data ready signal is received, the data is
clock out in SPI full duplex mode.
Once in a while the SPI handling stalls due to an overrun error. I can clear the error and reset the communication FSM, everything works as before, but I would like to know why I even end up with an overrun error... What I don’t get: the SPI is in master mode and the master/HAL decides when it is ready to clock another byte out. But somehow the HAL starts the next transfer even though the byte is not ready yet.
Here is a short overview how I use the HAL in the code, maybe I missunterstood how to use it...
SPI initialization:
The SPI is setup like this:
// SETUP SPI
adc->spiHandle = spiHandle;
// SPI: Master / Full duplex / 8bit data / MSB first
adc->initStruct.Mode = SPI_MODE_MASTER;
adc->initStruct.Direction = SPI_DIRECTION_2LINES;
adc->initStruct.DataSize = SPI_DATASIZE_8BIT;
adc->initStruct.FirstBit = SPI_FIRSTBIT_MSB;
// CPOL = 0 = low (in idle) / CPHA = 1 = triggers on falling edge
adc->initStruct.CLKPolarity = SPI_POLARITY_LOW;
adc->initStruct.CLKPhase = SPI_PHASE_2EDGE;
// software chip select
adc->initStruct.NSS = SPI_NSS_SOFT;
// F_SCL_max <= 2MHz, SPI base frequency = 42MHz -> prescaler = 8 (2 would be possible too)
adc->initStruct.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
// unused additional functionality
adc->initStruct.TIMode = SPI_TIMODE_DISABLE;
adc->initStruct.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
adc->initStruct.CRCPolynomial = 10;
// trigger HAL init
if (HAL_SPI_Init(adc->spiHandle) != HAL_OK) {
Error_Handler();
}
To initiate a conversion, the FSM waits until the SPI is ready to be used and then starts the transfer with HAL_Transmit_IT:
// FSM while loop:
while(1) {
...
case Start_Conversion:
if(HAL_SPI_GetState(adc->spiHandle) == HAL_SPI_STATE_READY) {
// SPI free to use -> start config upload
// data preparation in pBuffer and dataLen
...
HAL_SPI_Transmit_IT(adc->spiHandle, pBuffer, dataLen);
// move to next state -> await SPI TX complete event
}
break;
...
}
Once the SPI transfer is complete, the FSM waits for the data ready signal and starts reading the ADC data:
while(1) {
...
Case Read_Conversion:
if(HAL_SPI_GetState(adc->spiHandle) == HAL_SPI_STATE_READY) {
// SPI free to use -> start config upload
// data preparation in pBuffer and dataLen
...
if(HAL_SPI_TransmitReceive_IT(adc->spiHandle, adc->txBuffer, adc->rxBuffer, 4) == HAL_OK) {
// reinit FSM to start a new conversion
...
return true;
}
}
break;
...
}
Thanks and best regards
Daniel