XMC4400 Spurious SPI Interrupts?

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Not applicable
Hi,

we are using a XMC4400-512 microcontroller in our product. Most of our peripherals are attached to the controller via SPI.
For historical reasons and because we need more SPI chip select lines than are offered by the package and thus use
GPIOs as chip selects, we have implemented our own SPI driver using the Infineon XMC Library without DAVE. Now for
some time we have noticed that SPI interrupts occour although no SPI transfer was triggered. This happens very rarely
sometimes only every 120 hours.

We use the USIC transmit and receive FIFO. Our driver only uses the RX interrupt, triggered by the RX Fifo. We start a
transfer by writing the data into the transmit FIFO and wait for the RX interrupt to occour. Inside the RX ISR we check
whether more data needs to be transferred. If so, we write the next data bytes into the transmit FIFO until it is full, exit the
ISR and wait for the next interrupt. When the transfer is finished, i.e. no more data to be written/read, we pull the GPIOs
used as chip selects high and are done.

It might be that our setup of the RXFIFO interrupt is wrong or that we generate a race condition by the way we write the
data to the TX Fifo inside the ISR. I have posted a simplified version of our Setup code and the interrupt handler. Can
anyone spot the problem? Thanks for your help

The SPI core initialization:


void SPI_Init() {
IRQn_Type _numIRQ;

XMC_SPI_CH_CONFIG_t _config = {
.baudrate = 200000,
.bus_mode = XMC_SPI_CH_BUS_MODE_MASTER,
.selo_inversion = XMC_SPI_CH_SLAVE_SEL_INV_TO_MSLS,
.parity_mode = XMC_USIC_CH_PARITY_MODE_NONE
};

/* Initialize SPI */
XMC_SPI_CH_Init(XMC_SPI0_CH0, &_config);

/* Bitorder */
XMC_SPI_CH_SetBitOrderMsbFirst(XMC_SPI0_CH0);

/* Shift clock */
XMC_SPI_CH_ConfigureShiftClockOutput(
XMC_SPI0_CH0,
XMC_USIC_CH_BRG_SHIFT_CLOCK_PASSIVE_LEVEL_0_DELAY_ENABLED,
XMC_USIC_CH_BRG_SHIFT_CLOCK_OUTPUT_SCLK);

/* Input source selected */
XMC_SPI_CH_SetInputSource(
XMC_SPI0_CH0,
XMC_USIC_CH_INPUT_DX0,
SUSIC0_C0_DX0_P1_4);

/* Configure FIFO */
XMC_USIC_CH_TXFIFO_Configure(XMC_SPI0_CH0, 0, XMC_USIC_CH_FIFO_SIZE_4WORDS, 1);
XMC_USIC_CH_TXFIFO_Flush(XMC_SPI0_CH0);

XMC_USIC_CH_RXFIFO_Configure(XMC_SPI0_CH0, 16, XMC_USIC_CH_FIFO_SIZE_4WORDS, 3);
XMC_USIC_CH_RXFIFO_Flush(XMC_SPI0_CH0);

/* Word & Frame length */
XMC_SPI_CH_SetWordLength(XMC_SPI0_CH0, 8);
XMC_SPI_CH_SetFrameLength(XMC_SPI0_CH0, 32);

/* Enable Interrupt */
XMC_USIC_CH_RXFIFO_EnableEvent(
XMC_SPI0_CH0,
XMC_USIC_CH_RXFIFO_EVENT_CONF_STANDARD);
XMC_USIC_CH_RXFIFO_SetInterruptNodePointer(
XMC_SPI0_CH0,
XMC_USIC_CH_RXFIFO_INTERRUPT_NODE_POINTER_STANDARD,
1);

NVIC_SetPriority(USIC0_0_IRQn, 80);
NVIC_EnableIRQ(_numIRQ);

/* Default slave select */
XMC_SPI_CH_EnableSlaveSelect(XMC_SPI0_CH0, XMC_SPI_CH_SLAVE_SELECT_0);

/* Start SPI */
XMC_SPI_CH_Start(XMC_SPI0_CH0);
}


The interrupt handler:

void SPI_ProcSPI(spi_bus_t bus) {
uint32_t _remaining;
uint32_t _rdbytes, _wrbytes, _txsize;
uint32_t _fifo_flags;

XMC_USIC_CH_t *_spi = XMC_SPI0_CH0;

_fifo_flags = XMC_USIC_CH_RXFIFO_GetEvent(_spi);
XMC_USIC_CH_RXFIFO_ClearEvent(_spi, _fifo_flags);

// Read out data from fifo
while ((_rdbytes = XMC_USIC_CH_RXFIFO_GetLevel(_spi))) {
_rxbuf[rx_index] = (uint8_t) XMC_SPI_CH_GetReceivedData(_spi);
rx_index++;
}

// Write new data
_remaining = transfer_size - tx_index;
_wrbytes = fifo_size - XMC_USIC_CH_TXFIFO_GetLevel(_spi);

if (_remaining > 0) {
if (_remaining > _wrbytes) {
_txsize = _wrbytes;
} else {
_txsize = _remaining;
}

// disable interrupts as interrupting the the transmit function leads to a
// deadlock.
__disable_irq();
for (uint32_t _i = 0; _i < _txsize; _i++) {
XMC_SPI_CH_Transmit(_spi,
(uint16_t) txbuf[tx_index++],
XMC_SPI_CH_MODE_STANDARD);
}

// Adapt FIFO interrupt level
XMC_USIC_CH_RXFIFO_Configure(
_spi,
16,
XMC_USIC_CH_FIFO_SIZE_4WORDS,
_txsize - 1);

__enable_irq(); // re-enable interrupts
} else {
// Read out rxbuffer and handle GPIO chip selects..
spi_finish_transfer(_spif);
}
}
0 Likes
1 Reply
Not applicable
Upon request, the finish_transfer function.

static void spi_finish_transfer(spi_interface_t* spif) {
spi_transfer_t* _transfer;

tbuf_push(51);
XMC_GPIO_SetOutputHigh(
SPI_Channel[spif->transfer->channel].cs->port,
SPI_Channel[spif->transfer->channel].cs->pin);
_transfer = spif->transfer;
spif->transfer = NULL;
mutex_unlock(&spif->mtx);

_transfer->complete((void *)_transfer->context);
}
0 Likes