SPI DMA XMC4400 automatic slave select update

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

cross mob
Not applicable
DAVE version 4.2.8
MCU: XMC4400-F100x512
SPI_MASTER APP version: 4.3.18

We are trying to setup a SPI Master communication via DMA to an external slave. Using the DAVE app SPI_MASTER, we can successfully setup the SPI communication with interrupt settings. When changing the configuration in the DAVE app to DMA on both RX and TX, the data sent and received becomes invalid.

We are also trying to set the Automatic Slave Select Update (chapter 15.4.3.3 in reference manual). This is not configurable in the DAVE app so we have added some modified code after the DAVE app initialization.

The configuration is setup as following:
After the DAVE_init(SPI_MASTER_0), the following code is executed: (We followed the information in chapter 15.4.3.3 in the reference manual)
uint32_t mask = SPI_MASTER_0.channel->TCSR;
mask &= ~USIC_CH_TCSR_WLEMD_Msk;
mask &= ~USIC_CH_TCSR_FLEMD_Msk;
mask &= ~USIC_CH_TCSR_WAMD_Msk;
mask &= ~USIC_CH_TCSR_HPCMD_Msk;
mask |= USIC_CH_TCSR_SELMD_Msk;
SPI_MASTER_0.channel->TCSR = mask;

mask = SPI_MASTER_0.channel->PCR_SSCMode;
mask |= USIC_CH_PCR_SSCMode_MSLSEN_Msk;
mask |= USIC_CH_PCR_SSCMode_SELCTR_Msk;
mask |= USIC_CH_PCR_SSCMode_SELINV_Msk;
mask &= ~USIC_CH_PCR_SSCMode_FEM_Msk;
SPI_MASTER_0.channel->PCR_SSCMode = mask;


The following problems then arise:

1) Hardware controlled Chip Select does not work when using DAVE app generated code.
Currently we modify the code by using Automatic Slave Select Update (chapter 15.4.3.3 in reference manual).
We modify the function SPI_MASTER_StartTransmitDMA() with the following:


SPI_MASTER_STATUS_t SPI_MASTER_StartTransmitDMA(const SPI_MASTER_t *const handle, uint8_t *data_ptr, uint32_t block_size)
{
...
mode = 8; /* Set mode to 8 (TCI information will generate CHIPSELECT on P1.13 for USCI0 channel1)
XMC_DMA_CH_SetDestinationAddress(handle->global_dma->dma,
handle->dma_ch_tx_number,
(uint32_t)&(handle->channel->TBUF[mode]));
...
}


The chip select is chosen by writing to the corresponding index in TXBUF[CHIP_SELECT_INDEX].
This is not handled in the DAVE app generated code.

Is this the correct approach?


2) The first transaction only sends NumberOfBytes - 1. It does not send the first byte for some reason. After the first transaction, it works well.
This is of course an error in the initialization of the SPI DMA (Dave app generated init code).
This is the code used for the first transaction:
uint8_t spiTxBuf[3] = {0x01,0x02,0x03};
SPI_MASTER_Transmit(&SPI_MASTER_0, &spiTxBuf[0], 3);

Viewing the results (oscilloscope) on MOSI, CHIPSELECT and SCLK shows that only 0x02 and 0x03 are sent on the bus. CHIPSELECT works as it should.

We have not changed anything in the generated function SPI_MASTER_0_lInit(void). There is something in the initialization that is missing. What?

3) Waiting for the SPI_MASTER_0.runtime->tx_busy flag before sending the next frame does not work correctly.
The tx_busy flag will be set to false too early which causes the chip select line to not de-assert between two sent frames.

We are sending a couple of frames when setting up the slave chip. The chip select line must de-assert between these frames. We are sending the frames as follows (pseudocode):
uint8_t spiTxBuf[3] = {0x01,0x02,0x03};
SPI_MASTER_STATUS_t status = SPI_MASTER_Transmit(&SPI_MASTER_0, spiTxBuf, 3);
while(SPI_MASTER_0.runtime->tx_busy){}
spiTxBuf[3] = {0x04,0x05,0x06};
SPI_MASTER_STATUS_t status = SPI_MASTER_Transmit(&SPI_MASTER_0, spiTxBuf, 3);
while(SPI_MASTER_0.runtime->tx_busy){}
spiTxBuf[3] = {0x09,0x0a,0x0b};
SPI_MASTER_STATUS_t status = SPI_MASTER_Transmit(&SPI_MASTER_0, spiTxBuf, 3);
while(SPI_MASTER_0.runtime->tx_busy){}


Viewing the results on an oscilloscope show that the CHIP_SELECT line is never de-asserted between the frames. Further debugging shows that the tx_busy flag is set to false way too early, about 1,5 bytes before the actual frame transfer is completed. This will of course make the USIC module continue to write data on the bus without de-asserting the CHIP SELECT line.

We fixed this by modifying the DAVE generated code to wait for the MSLS (chip select active bit) to be reset before setting the tx_busy flag to false.
void SPI_MASTER_0_DMA_tx_handler(XMC_DMA_CH_EVENT_t event)
{
if (event == XMC_DMA_CH_EVENT_TRANSFER_COMPLETE)
{
while(SPI_MASTER_0.channel->PSR & USIC_CH_PSR_SSCMode_MSLS_Msk); // Wait until Chip select is deactivated
//while(XMC_USIC_CH_GetTransmitBufferStatus(XMC_SPI0_CH1) == XMC_USIC_CH_TBUF_STATUS_BUSY);
SPI_MASTER_0.runtime->tx_busy = false;
}
}


Is this the correct method to solve this?

Thanks!
0 Likes
2 Replies
Not applicable
Bumping this. No answer yet.
0 Likes
Not applicable
Bumping again. Still waiting for an answer.
0 Likes