Hello Dialog,
Our application runs on a DA14581 with SDK 5.0.4. It has an SPI ISR which does the following:
1. As a sanity check, see if the SPI interrupt is actually pending via SPI_CTRL_REG; log an error if not.
2. Read a word from SPI_RX_TX_REG1 and SPI_RX_TX_REG0.
3. Clear the pending SPI interrupt via SPI_CLEAR_INT_REG.
4. Process the received word.
5.回报。
The interrupt priority is set to 0 by NVIC_SetPriority (highest). We don't change the priority of the SPI interrupt.
This ISR has fired many many thousands of times without the step 1 error ever being detected. Recently we had a case where the error detected in step 1 DID occur and we are trying to figure out how (other than memory corruption).
It is possible that the SPI interrupt could occur again while the SPI ISR is executing (this would also be bad but for other reasons) but since the priority of this interrupt never changes, the interrupts should not nest.
Any other ideas or NVIC behavior we could be missing?
Hi JamesHiebert,
Could you please share what you have implemented? Are you using the APIs from the SPI drivers?
Thanks, PM_Dialog
Dialog,
Thanks for the quick response. Some code segments below.
We have a 2-chip system, with a custom ASIC communicating with the DA14581 via SPI. Some of this code implements the handshake between the 2 chips.
SPI_Handler is our SPI ISR for incoming words. The ASSERT_ERROR that is triggering is ASSERT_ERROR(spi_int_bit_set()). spi_int_bit_clear() is only called in this ISR and SPI_Handler is never directly called.
After putting an automated test in a loop, we have seen this issue several additional times.
__INLINE bool spi_int_bit_set(void)
{
return ((GetWord16(SPI_CTRL_REG) & SPI_INT_BIT) > 0x0000);
}
__INLINE void deassert_rf_rdyn(void)
{
// pull RF_RDYN GPIO line high (deassert RF_RDYN line)
// ASIC RF_ATTN interrupt is raised on the falling edge
SetWord16(RF_RDYN_SET_DATA_REG, RF_RDYN_MASK);
}
__INLINE uint32_t spi_rxtxreg_read(void)
{
uint32_t rd_word = (uint32_t) GetWord16(SPI_RX_TX_REG1); // read high part of the word
rd_word = (rd_word << 16) + (uint32_t) GetWord16(SPI_RX_TX_REG0); // read low part of the word
return rd_word;
}
__INLINE void spi_int_bit_clear(void)
{
SetWord16(SPI_CLEAR_INT_REG, 0x0001);
}
void SPI_Handler(void)
{
uint32_t recvWord;
ASSERT_ERROR(SPIRecvState != RECV_SPI_IDLE);
ASSERT_ERROR(spi_int_bit_set());
// deassert RF_ATTN line as soon as possible after
// an SPI word transfer is completed (as indicated by the SPI interrupt bit)
// to allow sufficient time in DEASSERTED state
deassert_rf_rdyn();
recvWord = spi_rxtxreg_read(); // Read word from SPI
spi_int_bit_clear ();/ /明确的SPI国米rupt bit
// <<< Process recvWord here >>>
if(SPIRecvState == RECV_SPI_DATA)
{
// the delay is needed to create a sufficient wide pulse for ASIC to trigger an interrupt
AppUtilDelayInUs(RF_RDYN_MIN_PULSE_WIDTH_IN_US);
// assert RF_ATTN line from deasserted state.
// this will cause RF_ATTN line on the ASIC side to be lowered.
assert_rf_rdyn();
}
else // SPIRecvState == RECV_SPI_IDLE
{
// set sleep mode back to default
arch_restore_sleep_mode();
// reconfigure MISO line as input pulldown at end of transfer to save power consumption
GPIO_ConfigurePin( GPIO_SPI_PORT, GPIO_SPI_DO_PIN, INPUT_PULLDOWN, PID_GPIO, false);
}
}
Hi JamesHiebert,
Apologies for the delay/ Let me check it and I will reply you as soon as possible.
Thanks, PM_Dialog
Hi JamesHiebert,
If you have SPI activity continuously, then you will get an interrupt and the SPI_Handler will be fired up. If I am able to understand correctly, the code gets stuck into ASSERT_ERROR(spi_int_bit_set()). However, an SPI interrupt will be occurred if data has been transmitted and received.
Thanks, PM_Dialog