STM32L151 SPI in interrupt mode unable to send from within interrupt
STM32L151 running at 32MHZ
SPI prescaler 256 running at 125KBits/s
The interrrupt does fire, but the first call (from non interrupt context) to get the transfer started HAL_SPI_Transmit_IT hasn't yet finished.
Reason: In HAL_SPI_Transmit_IT __HAL_UNLOCK is called too late
The calling sequence is a follows:
1). main loop calls HAL_SPI_Transmit_IT( &hspi2, (uint8_t *)tx_buffer_ptr++, 1 )
2). Correct Data is sent (captured on logic analyser)
3). HAL_SPI_TxCpltCallback( ) is executed and calls HAL_SPI_Transmit_IT( &hspi2, (uint8_t *)tx_buffer_ptr++, 1 )
4). Data wasn't sent.
5). REASON: __HAL_LOCK at start of HAL_SPI_Transmit_IT fails, as initial call to HAL_SPI_Transmit_IT hadn't completed.
Taking the inspiration for the ADC HAL snippet below, and the comment regarding "potential interruption"
/* Process unlocked */
/* Unlock before starting ADC conversions: in case of potential */
/* interruption, to let the process to ADC IRQ Handler. */
__HAL_UNLOCK(hadc);I changed the SPI to same idea.
function: HAL_SPI_Transmit_IT, bottom half
#if (USE_SPI_CRC != 0U)
/* Reset CRC Calculation */
if (hspi->Init.CRCCalculation == SPI_CRCCALCULATION_ENABLE)
{
SPI_RESET_CRC(hspi);
}
#endif /* USE_SPI_CRC */
/* Process unlocked */
/* Unlock before starting SPI transmissions: in case of potential */
/* interruption, to let the process to SPI IRQ Handler. */
__HAL_UNLOCK(hspi); //<<<<<<<<<< UNLOCK EARLY !!!!!
/* Enable TXE and ERR interrupt */
__HAL_SPI_ENABLE_IT(hspi, (SPI_IT_TXE | SPI_IT_ERR));
/* Check if the SPI is already enabled */
if ((hspi->Instance->CR1 & SPI_CR1_SPE) != SPI_CR1_SPE)
{
/* Enable SPI peripheral */
__HAL_SPI_ENABLE(hspi);
}
return errorcode; // <<<<<<< RETURN EARLY don't unlock again
error :
__HAL_UNLOCK(hspi);
return errorcode;
}Now code works as expected.
Edit: All SPI functions would need fixing.
Also code reviewed STM32F4, STM32F1, STM32G0 (we use in another projects), they could potentially have the same problem, all of the ADC HAL code in these also call __HAL_UNLOCK early.
This SPI transfer stall could happen even on the faster processors if the first call to HAL_SPI_Transmit_IT is interrupted just before the __HAL_UNLOCK for a period longer than SPI transfer time, the SPI finishes the transfer and now the SPI interrupt fires while the SPI is still LOCKED.
Thanks
Alec Davis