I am experimenting with the SPI protocol (fast speeds where 5 bytes of data is transferred in slightly less than 500us) on the STM32F410 configured as a SPI full duplex slave. A master device sends a command byte to the STM32F4 and the STM32F4 responds with 4 acknowledge bytes followed by a routine that executes at about 1.3ms (measured through the DWT clock cycle count). This 5 byte data transfer is expected to happen around 25 to 27 times a second.
I notice that sometimes, the master device can send the exact same data consecutively in a span of 90us (The STM32F4 slave should expect to receive alternating data through SPI in a span of at least 4ms in between). I have attached screenshots of the logic analyzer showing this occurrence:
The first 0x42 byte received is to be expected, and the STM32F4 slave responded with the appropriate bytes (note that the second 0x42 afterwards should not be there):
The second 0x42 byte received should not have occurred (Master device cannot be configured/programmed in this scenario):
After the occurrence above, the STM32F4 slave could never respond to the master device correctly again (the acknowledge bytes sent back to the master is always 0x99 - which is the byte configured in the SPI interrupt send buffer):
In this situation, I tried removing the function call __AppliSendBuff()
, which commands an RF transceiver to transmit data, and when the unusual occurrence happens, the STM32F4 slave is still able to correctly respond to the master.
My question is: How could I ignore the SPI data coming from the master at unexpected times? Why is it that one failed SPI transaction causes every other future SPI transactions to fail? What precautions should I take when writing code for the STM32F4 slave?
What I tried: Disabling the SPI_CS GPIO interrupts whenever the CS chip is pulled down so that in the middle of the whole process, the SPI transaction would not occur until I re-enable the SPI_CS GPIO interrupt. Before this change, in the second 0x42 command received, the STM32F4 slave would just respond 0x99 to the 0x42 and 0xFF's tailing the 0x42. Despite this, every other SPI transactions still fail and the slave would respond with 0x99's.
My STM32F4 code:
The interrupt segment:
/*** STM32F4 INTERRUPT HANDLERS ***/
/* GPIO Interrupt Handler */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
if(GPIO_Pin == SPI2_CS_PIN) {
/* Temporarily disable SPI2 CS interrupt */
HAL_NVIC_DisableIRQ(EXTI1_IRQn);
/* Generate interrupt flags when master device sends SPI data */
/* dummybyte is a uint8_t array of size 1, with the element being 0x99 */
HAL_SPI_TransmitReceive_IT(&hspi2, (uint8_t*)dummybyte, (uint8_t*)pSpi2RxBuff, cSpi2RxLen);
}
else if (...) {
...
}
}
/* SPI Interrupt Handler */
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
if(hspi->Instance == SPI2) {
if (...) {
...
}
else if(pSpi2RxBuff[0] == 0x41) {
/* Activate 0x41 flag for further processing in main loop if 0x41 was received */
xFlag_41 = SET;
}
else if(pSpi2RxBuff[0] == 0x42) {
/* Activate 0x42 flag for further processing in main loop if 0x42 was received */
xFlag_42 = SET;
}
else {
/* Discard data by doing nothing */
}
}
}
The main loop:
while (1) {
if(xFlag_41 == SET) {
/* Respond back to system with acknowledge bytes */
HAL_SPI_TransmitReceive(&hspi2, (uint8_t*)pSend41Data, (uint8_t*)pTempRxBuff, cSpi2TxLen, SPI2_TIMEOUT);
/* Commands RF Transceiver to transmit data respective to received command from master */
__AppliSendBuff(&command41);
xFlag_41 = RESET;
/* Re-enable SPI2_CS interrupts. Note that priority was set in MX_GPIO_Init() */
HAL_NVIC_EnableIRQ(EXTI1_IRQn);
}
else if(xFlag_42 == SET) {
/* Respond back to system with acknowledge bytes */
HAL_SPI_TransmitReceive(&hspi2, (uint8_t*)pSend42Data, (uint8_t*)pTempRxBuff, cSpi2TxLen, SPI2_TIMEOUT);
/* Commands RF Transceiver to transmit data respective to received command from master */
__AppliSendBuff(&command42);
xFlag_42 = RESET;
/* Re-enable SPI2_CS interrupts. Note that priority was set in MX_GPIO_Init() */
HAL_NVIC_EnableIRQ(EXTI1_IRQn);
}
}
Do I also have to configure the SPI slave to transmit 4 dummy bytes (maybe to flush the SPI data registers) in the event that I do receive a junk/unregistered command byte?
Thank you!
Update: I omitted disabling the CS Line interrupt disable (which is a GPIO interrupt disable) and moved the flag reset actions to be the first line in the else if blocks and there were some changes shown in the logic analyzer (the first correct sequence was still the same):
0x41 exactly after the second incorrect sequence above:
0x42 exactly after the 0x41 above (incorrect bytes sent back to master):
And all the bytes exchanged afterwards are as below (regardless 0x41 or 0x42):
I forgot to include the Interrupt Priorities in the original post above:
/* SPI CS line has the highest interrupt priority */
HAL_NVIC_SetPriority(EXTI1_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(EXTI1_IRQn);
/* SPI Peripheral connected to the master device */
HAL_NVIC_SetPriority(SPI2_IRQn, 1, 1);
HAL_NVIC_EnableIRQ(SPI2_IRQn);