Hello,
We are on a problem that the SPI module seems not to receive all data thus we never end waiting for it. This happens on heavy load (i.e. lot of data has to be send to different participants on SPI).
For this a MK66FN2M0VLQ18 (Mask 0N65N) is configured with RTX. Many other modules are running on the MCU (CAN0, CAN1, UART, ADC0, ADC1, Ports, etc.).
The code keeps track of how much data has been written to the PUSHR and how many bytes have been collected from the POPR. When the problem occurs the data we have pushed out is one more than the data we have popped. The TCR is always the same number as the push-counter.
Checking on the bus how much data actually have been transmitted it reveals sometimes the data was not on the bus, so there is really one byte missing. However sometimes it was there and in case it was one of the very latest bytes it is missing in the RX FIFO.
Many thanks in advance for any tips.
Regards Dani
Stripped code looks like this
#include <MK66F18.h>
...
void D_SPI_IRQHandler( T_D_SPI_IF * spi, const uint32_t fifoLength )
{
SPI_Type* spiBase = spi->base_ptr;
volatile uint32_t* statRegPtr = &(spiBase->SR);
if( (*statRegPtr & SPI_SR_RFOF_MASK) ) {
*statRegPtr = SPI_SR_RFOF_MASK;
ERROR_MSG("SPI%d RX-Overflow. Is SPI FIFO length properly set?\n", spi->id);
}
D_SPI_irqRxHandler( spi, spiBase );
D_SPI_irqEoCHandler( spi, spiBase );
D_SPI_irqTxHandler( spi, spiBase, fifoLength );
}
void D_SPI_irqRxHandler( T_D_SPI_IF * spi, SPI_Type* spiBase) {
volatile uint32_t* statRegPtr = &(spiBase->SR);
uint32_t *rxBuf = &(spi->rxBuffer[spi->rxBufferLength]);
while(*statRegPtr & SPI_SR_RFDF_MASK ) {
uint16_t data = spi->base_ptr->POPR;
*statRegPtr = SPI_SR_RFDF_MASK;
if( spi->rxBufferLength >= ELEMENTS_OF(spi->rxBuffer) ) {
ERROR_MSG("SPI %d, RxBuf Overflow", spi->id );
} else {
*(rxBuf++) = data;
}
spi->rxBufferLength++;
}
}
void D_SPI_irqTxHandler( T_D_SPI_IF * spi, SPI_Type* spiBase, const uint32_t fifoLength) {
volatile uint32_t* statRegPtr = &(spiBase->SR);
if(!spi->inCom) {
T_U_RingBuffer_32bit_Elem data;
spi->rxLen = 0;
if( E_U_RingBuffer_RS_OK == E_U_RingBuffer_32bit_takeOut( &spi->txBuf, &data ) ) {
spi->rxLen = data;
}
spi->txDone = 0;
spiBase->RSER &= ~SPI_RSER_TFFF_RE_MASK;
}
T_U_RingBuffer_32bit_Elem txCommand;
while( *statRegPtr & SPI_SR_TFFF_MASK &&
spi->txDone < spi->rxLen &&
spi->txDone - spi->rxBufferLength < fifoLength
) {
spi->inCom = 1;
E_U_RingBuffer_32bit_takeOut( &spi->txBuf, &txCommand );
spi->base_ptr->PUSHR = txCommand;
*statRegPtr = SPI_SR_TFFF_MASK;
spi->txDone++;
}
}
void D_SPI_irqEoCHandler( T_D_SPI_IF * spi, SPI_Type* spiBase) {
if( spi->inCom ) {
if ( spi->rxLen == spi->rxBufferLength ) {
T_D_SPI_Callback* func;
void* ctx;
E_U_RingBuffer_RS rsF = E_U_RingBuffer_32bit_takeOut( &spi->txBuf, (uint32_t*) &func );
E_U_RingBuffer_RS rsC = E_U_RingBuffer_32bit_takeOut( &spi->txBuf, (uint32_t*) &ctx );
if( E_U_RingBuffer_RS_OK == rsF && func != NULL && E_U_RingBuffer_RS_OK == rsC ) {
func(ctx, spi->id, spi->rxBuffer, spi->rxBufferLength );
}
spi->base_ptr->SR |= SPI_SR_EOQF_MASK;
spi->rxBufferLength=0;
spi->inCom = 0;
int len = E_U_RingBuffer_32bit_length(&spi->txBuf);
if( len >= 4 ) {
spiBase->MCR |= SPI_MCR_HALT_MASK;
spiBase->MCR |= SPI_MCR_CLR_TXF_MASK |
SPI_MCR_CLR_RXF_MASK;
T_U_RingBuffer_32bit_Elem elem;
E_U_RingBuffer_32bit_at( &spi->txBuf, 1, &elem );
uint32_t pcs = count_trailing_zeros((SPI_PUSHR_PCS_MASK & elem) >> SPI_PUSHR_PCS_SHIFT);
spiBase->CTAR[0] = spi->devices[pcs].CTARn.reg32;
spiBase->MCR &= (uint32_t)~(uint32_t)(SPI_MCR_HALT_MASK);
} else if ( len > 0 ) {
ERROR_MSG("Invalid TX Buffer size %d",len);
}
}
}
}
E_D_SPI_Err D_SPI_Init_LL( uint8_t interface,
E_D_SPI_SM masterSlave, uint8_t priority)
{
T_D_SPI_IF *spi = &D_SPI_interfaces[interface];
spi->id = interface;
spi->rxBufferLength = 0;
uint8_t nvicP;
switch( interface )
{
case 0 :
SIM->SCGC6 |= SIM_SCGC6_SPI0_MASK;
nvicP = SPI0_IRQn;
break;
case 1 :
SIM->SCGC6 |= SIM_SCGC6_SPI1_MASK;
nvicP = SPI1_IRQn;
break;
case 2 :
SIM->SCGC3 |= SIM_SCGC3_SPI2_MASK;
nvicP = SPI2_IRQn;
break;
default :
ERROR_MSG("Unknown SPI %d", interface);
return E_D_SPI_Err_UkwnIf;
}
spi->base_ptr = SPI_BASE_PTRS_AR[interface];
nvicP += NVIC_OFFSET;
uint32_t nvic_idx = nvicP/32;
uint32_t nvic_bit = nvicP%32;
NVIC->ICPR[nvic_idx] |= (1<< nvic_bit);
NVIC->ISER[nvic_idx] |= (1<< nvic_bit);
NVIC->IP[nvicP] = (priority & 0xFF) << 4;
spi->base_ptr->MCR = SPI_MCR_MSTR_MASK |
SPI_MCR_PCSIS(0x00) |
SPI_MCR_ROOE_MASK |
SPI_MCR_SMPL_PT(0x00) |
SPI_MCR_CLR_TXF_MASK |
SPI_MCR_CLR_RXF_MASK |
SPI_MCR_HALT_MASK;
spi->base_ptr->SR = SPI_SR_TCF_MASK |
SPI_SR_EOQF_MASK |
SPI_SR_TFUF_MASK |
SPI_SR_TFFF_MASK |
SPI_SR_RFOF_MASK |
SPI_SR_RFDF_MASK |
SPI_SR_TXCTR(0x00) |
SPI_SR_TXNXTPTR(0x00) |
SPI_SR_RXCTR(0x00) |
SPI_SR_POPNXTPTR(0x00) |
0x00200000U;
spi->base_ptr->RSER = SPI_RSER_RFDF_RE_MASK |
SPI_RSER_RFOF_RE_MASK;
spi->base_ptr->MCR &= (uint32_t)~(uint32_t)(SPI_MCR_HALT_MASK);
spi->inCom = 0;
return E_D_SPI_Err_Ok;
}
E_D_SPI_Err D_SPI_transfer( uint8_t interface, E_D_SPI_PCS pcs, uint16_t * data, uint16_t length, T_D_SPI_Callback cbFunc, void * cbCtx)
{
if( length == 0 )
return E_D_SPI_Err_Length;
T_D_SPI_IF *spi = &D_SPI_interfaces[interface];
EnterCritical();
if( E_U_RingBuffer_32bit_spaceLeft( &spi->txBuf ) < (length+3) )
{
ExitCritical();
return E_D_SPI_Err_Busy;
}
uint32_t spiInUse = E_U_RingBuffer_32bit_length( &spi->txBuf );
uint32_t dataFlags = 0U;
uint8_t pcsNum = getPcsNumber(pcs);
if( ! spiInUse ) {
spi->base_ptr->MCR |= SPI_MCR_HALT_MASK;
spi->base_ptr->MCR |= SPI_MCR_CLR_TXF_MASK |
SPI_MCR_CLR_RXF_MASK;
spi->base_ptr->CTAR[0] = spi->devices[pcsNum].CTARn.reg32;
spi->base_ptr->MCR &= (uint32_t)~(uint32_t)(SPI_MCR_HALT_MASK);
spi->base_ptr->SR |= SPI_SR_TXRXS_MASK;
spi->base_ptr->RSER |= SPI_RSER_TFFF_RE_MASK;
}
E_U_RingBuffer_32bit_insert( &spi->txBuf, (T_U_RingBuffer_32bit_Elem) length );
for(int i=0;i<length;i++)
{
if( E_U_RingBuffer_RS_Full == E_U_RingBuffer_32bit_insert( &spi->txBuf,
(T_U_RingBuffer_32bit_Elem) (
data[i] |
dataFlags |
((i==(length-1))?SPI_PUSHR_EOQ_MASK:SPI_PUSHR_CONT_MASK) |
((i==0)?SPI_PUSHR_CTCNT_MASK:0)
) )
)
{
ERROR_MSG("FATAL: SPI queue overflow!");
ExitCritical();
return E_D_SPI_Err_Length;
}
}
E_U_RingBuffer_32bit_insert( &spi->txBuf, (T_U_RingBuffer_32bit_Elem) cbFunc);
E_U_RingBuffer_32bit_insert( &spi->txBuf, (T_U_RingBuffer_32bit_Elem) cbCtx);
ExitCritical();
return E_D_SPI_Err_Ok;
}