GPDMA with USIC (SPI) Data transfer Master to Slave

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

cross mob
User10505
Level 1
Level 1
Hey,

i´ve got receive problems of my USIC(SPI) and GPDMA. I have an XMC4500 and I use DAVE 4.1.2 without Apps.
I would like to send some datas form an Array with the DMA->SPI(Master) to another SPI(Slave) which reseived it with a second DMA.
First I initialised the USIC's Master and Slave and then GPDMA's Master and Slave. I select USIC1_CH1, GPDMA0_CH2 for Master mode and USIC0_CH0, GPDMA0_CH3 for Slave mode.

I think the Master is probably right. On the scope I can see the datas and it seems to be correct.
If I Debug the Slave and read the array of my destination, I didn't reseived something. If I invert the (Slave) DX2CR (DPOL = 1), I reseived something but it is wrong.
Have you an idea?

Thanks.



#include
#include
#include
#include "xmc_spi.h"
#include "xmc_gpio.h"

#define TICKS_PER_SECOND 1000
#define TICKS_WAIT 10


// Sys-Tick Counter
#define CORE_SysTickEn() (*((uint32_t*)0xE0001000)) = 0x40000001
#define CORE_SysTickDis() (*((uint32_t*)0xE0001000)) = 0x40000000
#define CORE_GetSysTick() (*((uint32_t*)0xE0001004))

#define SPI_MASTER_MISO P0_0
#define SPI_MASTER_MOSI P0_1
#define SPI_MASTER_SS P0_9
#define SPI_MASTER_SCLK P0_10

#define SPI_SLAVE_MISO P0_5
#define SPI_SLAVE_MOSI P1_4
#define SPI_SLAVE_SS P1_0
#define SPI_SLAVE_SCLK P1_1

#define BUFFER_LENGTH 5


XMC_USIC_CH_t *spi_master_ch = XMC_SPI1_CH1;
XMC_USIC_CH_t *spi_slave_ch = XMC_SPI0_CH0;


uint16_t buffer[BUFFER_LENGTH];
uint16_t res_buffer[BUFFER_LENGTH];



XMC_DMA_CH_CONFIG_t dma_ch_config_master =
{
.src_addr = (uint32_t)&(buffer[0]),
.dst_addr = (uint32_t)&(USIC1_CH1->TBUF[0]),
.block_size = BUFFER_LENGTH,
.src_transfer_width = XMC_DMA_CH_TRANSFER_WIDTH_16,
.dst_transfer_width = XMC_DMA_CH_TRANSFER_WIDTH_16,
.src_address_count_mode = XMC_DMA_CH_ADDRESS_COUNT_MODE_INCREMENT,
.dst_address_count_mode = XMC_DMA_CH_ADDRESS_COUNT_MODE_NO_CHANGE,
.src_burst_length = XMC_DMA_CH_BURST_LENGTH_1,
.dst_burst_length = XMC_DMA_CH_BURST_LENGTH_1,
.transfer_flow = XMC_DMA_CH_TRANSFER_FLOW_M2P_DMA,
.transfer_type = XMC_DMA_CH_TRANSFER_TYPE_SINGLE_BLOCK,

.dst_handshaking = XMC_DMA_CH_DST_HANDSHAKING_HARDWARE,
.dst_peripheral_request = DMA0_PERIPHERAL_REQUEST_USIC1_SR1_2, // SR = 1, Line = 2;

.enable_interrupt = false

};

XMC_DMA_CH_CONFIG_t dma_ch_config_slave =
{
.block_size = BUFFER_LENGTH,

.src_addr = (uint32_t)&(USIC0_CH0->RBUF),
.src_transfer_width = XMC_DMA_CH_TRANSFER_WIDTH_16,
.src_address_count_mode = XMC_DMA_CH_ADDRESS_COUNT_MODE_NO_CHANGE,
.src_burst_length = XMC_DMA_CH_BURST_LENGTH_1,

.dst_addr = (uint32_t)&(res_buffer[0]),
.dst_transfer_width = XMC_DMA_CH_TRANSFER_WIDTH_16,
.dst_address_count_mode = XMC_DMA_CH_ADDRESS_COUNT_MODE_INCREMENT,
.dst_burst_length = XMC_DMA_CH_BURST_LENGTH_1,

.transfer_flow = XMC_DMA_CH_TRANSFER_FLOW_P2M_DMA,
.transfer_type = XMC_DMA_CH_TRANSFER_TYPE_SINGLE_BLOCK,

.src_handshaking = XMC_DMA_CH_SRC_HANDSHAKING_HARDWARE,
.src_peripheral_request = DMA0_PERIPHERAL_REQUEST_USIC0_SR0_1, // SR = 0, Line = 1;

.enable_interrupt = false
};

XMC_SPI_CH_CONFIG_t spi_master_config =
{
.baudrate = 100000,
.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
};


XMC_SPI_CH_CONFIG_t spi_slave_config =
{
.bus_mode = XMC_SPI_CH_BUS_MODE_SLAVE,
.selo_inversion = XMC_SPI_CH_SLAVE_SEL_INV_TO_MSLS,
.parity_mode = XMC_USIC_CH_PARITY_MODE_NONE
};


/* ------------------------------------------------------------------ */
void SysTick_Handler(void)
{
static uint32_t ticks = 0;
ticks++;
if (ticks == TICKS_WAIT)
{

ticks = 0;
}
}

/* ------------------------------------------------------------------ */
int main(void)
{


/* Start sending periodic message */
SysTick_Config(SystemCoreClock / TICKS_PER_SECOND);


/* ------------------------------------------------------------------------- */

/* MASTER */
/* ------------------------------------------------------------------------- */
#if 1
/*Initialize and Start SPI Master*/
XMC_SPI_CH_Init(spi_master_ch, &spi_master_config);
XMC_SPI_CH_SetWordLength(spi_master_ch, 16);
XMC_SPI_CH_SetFrameLength(spi_master_ch,16);
USIC1_CH1->PCR_SSCMode = 0x8001000F; // CS = LowActive

/*Input source selected for Master*/
XMC_SPI_CH_SetInputSource(spi_master_ch,XMC_SPI_CH_INPUT_DIN0,USIC1_C1_DX0_P0_0); // MISO

/*GPIO configuration for Master*/
XMC_GPIO_SetMode(SPI_MASTER_MOSI, XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT2);
XMC_GPIO_SetMode(SPI_MASTER_SS, XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT2);
XMC_GPIO_SetMode(SPI_MASTER_SCLK, XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT2);
XMC_GPIO_SetMode(SPI_MASTER_MISO, XMC_GPIO_MODE_INPUT_TRISTATE);
#endif
/* ------------------------------------------------------------------------- */

/* SLAVE */
/* ------------------------------------------------------------------------- */
#if 1
/*Initialize and Start SPI Slave*/
XMC_SPI_CH_Init(spi_slave_ch, &spi_slave_config);
XMC_SPI_CH_SetWordLength(spi_slave_ch, 16);
XMC_SPI_CH_SetFrameLength(spi_slave_ch,16);

/*Input source selected for Slave*/
XMC_SPI_CH_SetInputSource(spi_slave_ch,XMC_SPI_CH_INPUT_DIN0,USIC0_C0_DX0_P1_4); // MOSI
XMC_SPI_CH_SetInputSource(spi_slave_ch,XMC_SPI_CH_INPUT_SLAVE_SCLKIN,USIC0_C0_DX1_P1_1); // SCLK (from Master)
XMC_SPI_CH_SetInputSource(spi_slave_ch,XMC_SPI_CH_INPUT_SLAVE_SELIN,USIC0_C0_DX2_P1_0); // CS (from Master)

/*GPIO configuration for Slave*/
XMC_GPIO_SetMode(SPI_SLAVE_MOSI, XMC_GPIO_MODE_INPUT_TRISTATE);
XMC_GPIO_SetMode(SPI_SLAVE_SS, XMC_GPIO_MODE_INPUT_TRISTATE);
XMC_GPIO_SetMode(SPI_SLAVE_SCLK, XMC_GPIO_MODE_INPUT_TRISTATE);
XMC_GPIO_SetMode(SPI_SLAVE_MISO, XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT2);
#endif


/* ------------------------------------------------------------------------- */

/* MASTER DMA */
/* ------------------------------------------------------------------------- */
#if 1
XMC_DMA_Init(XMC_DMA0);
XMC_DMA_CH_Init(XMC_DMA0, 2, &dma_ch_config_master);
XMC_USIC_CH_SetInterruptNodePointer(XMC_UART1_CH1, XMC_USIC_CH_INTERRUPT_NODE_POINTER_TRANSMIT_SHIFT, 1);
XMC_USIC_CH_EnableEvent(XMC_UART1_CH1, XMC_USIC_CH_EVENT_TRANSMIT_SHIFT);
XMC_USIC_CH_TriggerServiceRequest(XMC_UART1_CH1, 1); /* make DMA ready */
#endif
/* ------------------------------------------------------------------------- */

/* SLAVE DMA */
/* ------------------------------------------------------------------------- */
#if 1
XMC_DMA_Init(XMC_DMA0);
XMC_DMA_CH_Init(XMC_DMA0, 3, &dma_ch_config_slave);
XMC_USIC_CH_SetInterruptNodePointer(XMC_UART0_CH0, XMC_USIC_CH_INTERRUPT_NODE_POINTER_RECEIVE, 0);
XMC_USIC_CH_EnableEvent(XMC_UART0_CH0, XMC_USIC_CH_EVENT_STANDARD_RECEIVE);
XMC_USIC_CH_TriggerServiceRequest(XMC_UART0_CH0, 0); /* make DMA ready */
#endif
/* ------------------------------------------------------------------------- */


/* ------------------------------------------------------------------------- */
#if 1

USIC0_CH0->DX2CR |= 0x1 << 8; // ?

XMC_SPI_CH_Start(spi_master_ch);
XMC_SPI_CH_Start(spi_slave_ch);

#endif

for (i = 0; i < BUFFER_LENGTH; ++i){
buffer = i+1;
}

XMC_DMA_CH_Enable(XMC_DMA0, 2);
XMC_DMA_CH_Enable(XMC_DMA0, 3);

while(1);

}

0 Likes
8 Replies
Travis
Employee
Employee
First solution authored Welcome! 500 replies posted
Hi,

I recommend that you enable your DMA channel before the start of communication.



XMC_DMA_CH_Enable(XMC_DMA0, 2);
XMC_DMA_CH_Enable(XMC_DMA0, 3);


#if 1

USIC0_CH0->DX2CR |= 0x1 << 8; // ?

XMC_SPI_CH_Start(spi_master_ch);
XMC_SPI_CH_Start(spi_slave_ch);

#endif

for (i = 0; i < BUFFER_LENGTH; ++i){
buffer = i+1;
}





If it is not working and to narrow down your problem, can you disable your GPDMA and ensure that your SPI slave is able to received properly first.

Best Regards
Travis
0 Likes
User10505
Level 1
Level 1
thanks for your comment.

Now, first I enable the GPDMA as I can see in your example but it doesn't work. After that I changed the BUFFER_LENGTH= 1 and disabled the GPDMA Slave
As you can see in the code below, I received with the " XMC_SPI_CH_GetReceivedData()" function and it's correct.



/* SLAVE DMA */
/* ------------------------------------------------------------------------- */
#if 0
XMC_DMA_Init(XMC_DMA0);
XMC_DMA_CH_Init(XMC_DMA0, 3, &dma_ch_config_slave);
XMC_USIC_CH_SetInterruptNodePointer(XMC_UART0_CH0, XMC_USIC_CH_INTERRUPT_NODE_POINTER_RECEIVE, 0);
XMC_USIC_CH_EnableEvent(XMC_UART0_CH0, XMC_USIC_CH_EVENT_STANDARD_RECEIVE);
XMC_USIC_CH_TriggerServiceRequest(XMC_UART0_CH0, 0); /* make DMA ready */
#endif
/* ------------------------------------------------------------------------- */
for (i = 0; i < BUFFER_LENGTH; ++i){
buffer = i+10;
}

/* ------------------------------------------------------------------------- */
XMC_DMA_CH_Enable(XMC_DMA0, 2);
// XMC_DMA_CH_Enable(XMC_DMA0, 3);

#if 1

USIC0_CH0->DX2CR |= 0x1 << 8; // why?

XMC_SPI_CH_Start(spi_master_ch);
XMC_SPI_CH_Start(spi_slave_ch);

#endif

while((XMC_SPI_CH_GetStatusFlag(spi_slave_ch) &(XMC_SPI_CH_STATUS_FLAG_RECEIVE_INDICATION | XMC_SPI_CH_STATUS_FLAG_ALTERNATIVE_RECEIVE_INDICATION)) ==0U)
{
/* wait for ACK */
}

res_buffer[0] = XMC_SPI_CH_GetReceivedData(spi_slave_ch);




while(1);



thanks.
0 Likes
User10505
Level 1
Level 1
I saw that I use XMC_UART_... functions after I initialised the GPDMA. I changed it and now I uses XMC_SPI_CH_EnableEvent() and XMC_SPI_CH_TriggerServiceRequest().
Is the function XMC_SPI_CH_SetInterruptNodePointer() necessary?

Now, the master send only one Datapackage (the first one) as you can see on the scope.
1544.attach

After I Change the

XMC_DMA_CH_CONFIG_t dma_ch_config_master =
{
...
.dst_handshaking = XMC_DMA_CH_DST_HANDSHAKING_HARDWARE,
.dst_peripheral_request = DMA0_PERIPHERAL_REQUEST_USIC1_SR1_2, // SR = 1, Line = 2;


to


XMC_DMA_CH_CONFIG_t dma_ch_config_master =
{
...
.dst_handshaking = XMC_DMA_CH_DST_HANDSHAKING_HARDWARE,
.dst_peripheral_request = DMA0_PERIPHERAL_REQUEST_USIC1_SR0_0, // SR = 0, Line = 0;
}
XMC_DMA_CH_CONFIG_t dma_ch_config_slave =
{
.src_peripheral_request = DMA0_PERIPHERAL_REQUEST_USIC0_SR0_1, // SR = 0, Line = 1;
}


and


/* ------------------------------------------------------------------------- */

/* MASTER DMA */
/* ------------------------------------------------------------------------- */
#if 1
XMC_DMA_Init(XMC_DMA0);
XMC_DMA_CH_Init(XMC_DMA0, 2, &dma_ch_config_master);
XMC_SPI_CH_SetInterruptNodePointer(XMC_SPI1_CH1, 0);
XMC_SPI_CH_EnableEvent(XMC_SPI1_CH1, XMC_SPI_CH_EVENT_TRANSMIT_SHIFT);
XMC_SPI_CH_TriggerServiceRequest(XMC_SPI1_CH1, 0); /* make DMA ready */
#endif
/* ------------------------------------------------------------------------- */

/* SLAVE DMA */
/* ------------------------------------------------------------------------- */
#if 1
XMC_DMA_Init(XMC_DMA0);
XMC_DMA_CH_Init(XMC_DMA0, 3, &dma_ch_config_slave);
XMC_SPI_CH_SetInterruptNodePointer(XMC_SPI0_CH0, 0);
XMC_SPI_CH_EnableEvent(XMC_SPI0_CH0, XMC_SPI_CH_EVENT_STANDARD_RECEIVE);
XMC_SPI_CH_TriggerServiceRequest(XMC_SPI0_CH0, 0); /* make DMA ready */
#endif


the master send all data packages but the slave isn't correct.

1545.attach
1546.attach

Is the init of the DLR right? Or have I some mistake?
0 Likes
chismo
Employee
Employee
First like received
Hello,

I think that the alternate receive event needs to be enabled as well, on top of the receive event:

  /* ------------------------------------------------------------------------- */

/* SLAVE DMA */
/* ------------------------------------------------------------------------- */
#if 1
XMC_DMA_Init(XMC_DMA0);
XMC_DMA_CH_Init(XMC_DMA0, 3, &dma_ch_config_slave);
XMC_SPI_CH_SetInterruptNodePointer(XMC_SPI0_CH0, 0);
XMC_SPI_CH_EnableEvent(XMC_SPI0_CH0, XMC_SPI_CH_EVENT_STANDARD_RECEIVE);
XMC_USIC_CH_EnableEvent(spi_slave_ch, XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE);
// XMC_SPI_CH_TriggerServiceRequest(XMC_SPI0_CH0, 0); /* make DMA ready */
#endif
/* ------------------------------------------------------------------------- */


With this, it is also no longer necessary to manually force a service request to the DMA channel for the slave (commented out in the code above).

The function XMC_SPI_CH_SetInterruptNodePointer() is not necessary in this case since the default is already node 0.

Regards,
Min Wei
0 Likes
Travis
Employee
Employee
First solution authored Welcome! 500 replies posted
Please check the DLR table from the user manual.
0 Likes
User10505
Level 1
Level 1
Well, thank you very much for your help.

It works!

Sorry but I don`t understand the DLR table. I checked the user Manual on page 4-10 and I dont`t no which DMA Line I can use because if I changed the peripheral_request to e. g. SR1 Line 2 (Slave) it doesen't woks.
And why are both function nessesary ?


XMC_SPI_CH_EnableEvent(XMC_SPI0_CH0, XMC_SPI_CH_EVENT_STANDARD_RECEIVE);
XMC_SPI_CH_EnableEvent(spi_slave_ch, XMC_USIC_CH_EVENT_ALTERNATIVE_RECEIVE);
0 Likes
chismo
Employee
Employee
First like received
Hello MaJa,

The DMA configuration looks fine.
For slave, I see that you are using USIC0_SR0 and DMA line 1, and this should work.
DMA line 2 supports only SR1 for USIC0 and therefore, you will need to re-assign the alternate receive and receive interrupts to node 1 (SR1) in order to use this.

Regarding the need to have both functions, the reasons are:
1) The first data word received is always indicated by the alternate receive event (AIF). If a frame consists of multiple words, subsequent received words are indicated by the receive interrupt (RIF).
2) For the case of XMC4500, unfortunately we have an erratum that RIF may be triggered in place of AIF. Therefore, both events need to be monitored in order not to lose any data.
Link to errata sheet for AC step: http://www.infineon.com/dgdl/XMC4500_AC_Errata_Sheet_v1_1.pdf?fileId=db3a304340a01a660140ab03a162153...

Regards,
Min Wei
0 Likes
User10505
Level 1
Level 1
Thank you very much for your support!
0 Likes