SPI Slave Configuration

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

cross mob
Not applicable
How do I configure a SPI port as slave using Dave App? The options are all for Master side. I have two XMC4500 CPUs - one is to be master, then other a slave. I am using the built in clock in the slave, so a normal UART is not workable. I need a synchronous slave.
The SPI Slave App was planned. Will be announced once released.
0 Likes
6 Replies
User5581
Level 3
Level 3
Is there any news of a planned availability date for slave SPI support on an XMC4500 in a DAVE3 app?
0 Likes
Georg_Huba
Employee
Employee
This DAVE App is planned to be released by end of October this year.
0 Likes
User5327
Level 4
Level 4
Is there any news of a planned availability date for slave SPI support on an XMC4500 in a DAVE3 app?
(or already exists?)
0 Likes
Halim
Employee
Employee
First question asked First reply posted First solution authored
Hi all

I just want to share a simple workaround to configure SPI slave. I am using XMC4200 to implement this, but I believe this should also work with XMC4500.

This workaround is implemented with USIC0_CH0, with the following pinout setup:
MRST pin at P1.4 (XMC resource name: U0C0.DOUT1)
MTSR pin at P1.5 (XMC resource name: U0C0.DX0A)
CLKIN pin at P1.1 (XMC resource name: U0C0.DX1A)
CS pin at P0.7 (XMC resource name: U0C0.DX2B)

In DAVE3, I called SPI001 app (SPI Master App) and change the register settings after DAVE_Init(). This workaround will receive 1 data byte sent by the Master and store it to a variable called ReadData.

Here is how the code looks like:

int main(void)
{
// status_t status; // Declaration of return variable for DAVE3 APIs (toggle comment if required)


DAVE_Init(); // Initialization of DAVE Apps

/* Slave Mode at USIC0_CH0
* P1.4 = MRST(U0C0.DOUT1),
* P1.5 = MTSR(U0C0.DX0A),
* P1.1 = CLKIN(U0C0.DX1A),
* P0.7 = CS(U0C0.DX2B)
*/

/* Disable USIC Channel */
USIC0_CH0->CCR &= ~0x000F;

/* Configure P1.5, MTSR (U0C0.DX0A) */
USIC0_CH0->DX0CR =
(0 << USIC_CH_DX0CR_DSEL_Pos) | // DX0A is selected
(1 << USIC_CH_DX0CR_INSW_Pos) |
(0 << USIC_CH_DX0CR_DFEN_Pos) |
(0 << USIC_CH_DX0CR_DSEN_Pos) |
(0 << USIC_CH_DX0CR_DPOL_Pos) |
(0 << USIC_CH_DX0CR_SFSEL_Pos) |
(0 << USIC_CH_DX0CR_CM_Pos) |
(0 << USIC_CH_DX0CR_DXS_Pos) ;

/* Configure P1.1, CLKIN (U0C0.DX1A) */
USIC0_CH0->DX1CR =
(0 << USIC_CH_DX0CR_DSEL_Pos) | // DX1A is selected
(1 << USIC_CH_DX0CR_INSW_Pos) |
(0 << USIC_CH_DX0CR_DFEN_Pos) |
(0 << USIC_CH_DX0CR_DSEN_Pos) |
(0 << USIC_CH_DX0CR_DPOL_Pos) |
(0 << USIC_CH_DX0CR_SFSEL_Pos) |
(0 << USIC_CH_DX0CR_CM_Pos) |
(0 << USIC_CH_DX0CR_DXS_Pos) ;

/* Configure P0.7, CS (U0C0.DX2B) */
USIC0_CH0->DX2CR =
(1 << USIC_CH_DX0CR_DSEL_Pos) | // DX2B is selected
(1 << USIC_CH_DX0CR_INSW_Pos) |
(0 << USIC_CH_DX0CR_DFEN_Pos) |
(0 << USIC_CH_DX0CR_DSEN_Pos) |
(1 << USIC_CH_DX0CR_DPOL_Pos) | // Polarity is inverted
(0 << USIC_CH_DX0CR_SFSEL_Pos) |
(0 << USIC_CH_DX0CR_CM_Pos) |
(0 << USIC_CH_DX0CR_DXS_Pos) ;

/* Switch off fractional divider and baud rate generator */
USIC0_CH0->FDR=0;
USIC0_CH0->BRG=0;

/* Enable USIC Channel in SPI mode */
USIC0_CH0->CCR |= 0x0001;

/* Control P0.7 as Input pin, Strong drive strength */
PORT0->IOCR4 = (PORT0->IOCR4 & ~0xF8000000) | (0 << 27);
PORT0->PDR0 = (PORT0->PDR0 & ~0x70000000) | (2 << 28);

/* Control P1.1 as Input pin, Strong drive strength */
PORT1->IOCR0 = (PORT1->IOCR0 & ~0x0000F800) | (0 << 11);
PORT1->PDR0 = (PORT1->PDR0 & ~0x00000070) | (2 << 4);

/* Control P1.5 as Input pin, Strong drive strength */
PORT1->IOCR4 = (PORT1->IOCR4 & ~0x0000F800) | (0 << 11);
PORT1->PDR0 = (PORT1->PDR0 & ~0x00700000) | (2 << 20);

/* Wait for Receive Buffer Flag is set */
while((SPI001_GetFlagStatus(&SPI001_Handle0, SPI001_FIFO_STD_RECV_BUF_FLAG))!=SPI001_SET);

/* Read data */
SPI001_ReadData(&SPI001_Handle0,&ReadData);

while(1)
{

}
return 0;
}


This code based on the guideline set in Chapter 14.4.4 of XMC4200 Reference Manual (version 1.3) on "Operating the SSC in Slave Mode". For XMC4500, it will be in Chapter 17.4.4 of XMC4500 Reference Manual (version 1.3).
0 Likes
Not applicable
Hello Halim,
thank you for the code example. Can you add some sample code to send data from slave to master?
0 Likes
Halim
Employee
Employee
First question asked First reply posted First solution authored
Hi all

This is the continuation from my previous SPI Slave workaround code. I can send reply data to Master from Slave. However, I need to reconfigure the SPI a little bit to the following:

MRST pin at P1.5 (XMC resource name: U0C0.DOUT0)
MTSR pin at P1.4 (XMC resource name: U0C0.DX0B)
CLKIN pin at P1.1 (XMC resource name: U0C0.DX1A)
CS pin at P0.7 (XMC resource name: U0C0.DX2B)

This is because transmit capability for SPI only exists on DOUT0 pins. In other words, both MTSR and MRST must be assigned to DOUT0 pin. (Refer to Table 14-2 of XMC4200 Reference Manual or Table 17-2 of XMC4500 RM)

After calling SPI001 App (SPI Master App), please configure the following pins in DAVE3 Manual Pin Assignment window:
MRST at P1.5
CLKOUT at P1.1
ChipSelectA at P0.7

The solver will assign P1.7 as the MTSR (for XMC4200) but we would like to change this to P1.4. Please find the workaround in the following code.


uint8_t ReadData = 0;


uint8_t Idx;
uint8_t cReply[] = {0x50, 0x0F, 0x32};


int main(void)
{
// status_t status; // Declaration of return variable for DAVE3 APIs (toggle comment if required)




DAVE_Init(); // Initialization of DAVE Apps


/* Slave Mode at USIC0_CH0
* P1.5 = mrST(U0C0.DOUT0),
* P1.4 = mtSR(U0C0.DX0B),
* P1.1 = CLKIN(U0C0.DX1A),
* P0.7 = CS(U0C0.DX2B)
*/


/* Disable P1.7 as transmit pin (assigned by solver) */
PORT1->IOCR4 = (PORT1->IOCR4 & ~0xF8000000) | (16 << 27);
PORT1->PDR0 = (PORT1->PDR0 & ~0x70000000) | (2 << 28);


/* Set P1.7 to Low */
PORT1->OMR = 0x00800000;




/* Disable USIC Channel */
USIC0_CH0->CCR &= ~0x000F;


/* Configure P1.4, mtSR (U0C0.DX0B) */
USIC0_CH0->DX0CR =
(1 << USIC_CH_DX0CR_DSEL_Pos) | // DX0B is selected
(1 << USIC_CH_DX0CR_INSW_Pos) |
(0 << USIC_CH_DX0CR_DFEN_Pos) |
(0 << USIC_CH_DX0CR_DSEN_Pos) |
(0 << USIC_CH_DX0CR_DPOL_Pos) |
(0 << USIC_CH_DX0CR_SFSEL_Pos) |
(0 << USIC_CH_DX0CR_CM_Pos) |
(0 << USIC_CH_DX0CR_DXS_Pos) ;


/* Configure P1.1, CLKIN (U0C0.DX1A) */
USIC0_CH0->DX1CR =
(0 << USIC_CH_DX0CR_DSEL_Pos) | // DX1A is selected
(1 << USIC_CH_DX0CR_INSW_Pos) |
(0 << USIC_CH_DX0CR_DFEN_Pos) |
(0 << USIC_CH_DX0CR_DSEN_Pos) |
(0 << USIC_CH_DX0CR_DPOL_Pos) |
(0 << USIC_CH_DX0CR_SFSEL_Pos) |
(0 << USIC_CH_DX0CR_CM_Pos) |
(0 << USIC_CH_DX0CR_DXS_Pos) ;


/* Configure P0.7, CS (U0C0.DX2B) */
USIC0_CH0->DX2CR =
(1 << USIC_CH_DX0CR_DSEL_Pos) | // DX2B is selected
(1 << USIC_CH_DX0CR_INSW_Pos) |
(0 << USIC_CH_DX0CR_DFEN_Pos) |
(0 << USIC_CH_DX0CR_DSEN_Pos) |
(1 << USIC_CH_DX0CR_DPOL_Pos) | // Polarity is inverted
(0 << USIC_CH_DX0CR_SFSEL_Pos) |
(0 << USIC_CH_DX0CR_CM_Pos) |
(0 << USIC_CH_DX0CR_DXS_Pos) ;


/* Switch off fractional divider and baud rate generator */
USIC0_CH0->FDR=0;
USIC0_CH0->BRG=0;


/* Configure PCR register. Disable MSLSEN, SELCTR, SELINV, etc... */
SPI001_Handle0.USICRegs->PCR_SSCMode =
(0 << USIC_CH_PCR_SSCMode_MSLSEN_Pos) |
(0 << USIC_CH_PCR_SSCMode_SELCTR_Pos) |
(0 << USIC_CH_PCR_SSCMode_SELINV_Pos) |
(0 << USIC_CH_PCR_SSCMode_CTQSEL1_Pos) |
(0 << USIC_CH_PCR_SSCMode_PCTQ1_Pos) |
(0 << USIC_CH_PCR_SSCMode_MSLSIEN_Pos) |
(0 << USIC_CH_PCR_SSCMode_SELO_Pos) |
(0 << USIC_CH_PCR_SSCMode_TIWEN_Pos) ;


/* Control P0.7 as Input pin, Strong drive strength */
PORT0->IOCR4 = (PORT0->IOCR4 & ~0xF8000000) | (0 << 27);
PORT0->PDR0 = (PORT0->PDR0 & ~0x70000000) | (2 << 28);


/* Control P1.1 as Input pin, Strong drive strength */
PORT1->IOCR0 = (PORT1->IOCR0 & ~0x0000F800) | (0 << 11);
PORT1->PDR0 = (PORT1->PDR0 & ~0x00000070) | (2 << 4);


/* Control P1.4 as Input pin, Strong drive strength */
PORT1->IOCR4 = (PORT1->IOCR4 & ~0x000000F8) | (0 << 3);
PORT1->PDR0 = (PORT1->PDR0 & ~0x00070000) | (2 << 16);


/* Enable USIC Channel in SPI mode */
USIC0_CH0->CCR |= 0x0001;


/* Set P1.5 as mrST pin (Solver assign P1.7 as MTsr pin). We are interested in the Transmit capability of the pin. (Remember, this implementation use SPI Master App) */
PORT1->IOCR4 = (PORT1->IOCR4 & ~0x0000F800) | (18 << 11);
PORT1->PDR0 = (PORT1->PDR0 & ~0x00700000) | (2 << 20);


while(1)
{
if (Idx < sizeof(cReply))
{
/* Wait for Receive Buffer Flag is set */
while((SPI001_GetFlagStatus(&SPI001_Handle0, SPI001_FIFO_STD_RECV_BUF_FLAG))!=SPI001_SET);


/* Read incoming data from Master */
SPI001_ReadData(&SPI001_Handle0,&ReadData);


/* Clear Standard Receive Buffer Flag */
SPI001_ClearFlag(&SPI001_Handle0,SPI001_FIFO_STD_RECV_BUF_FLAG);


/* Send data to Master */
SPI001_WriteData(&SPI001_Handle0,&cReply[Idx],SPI001_STANDARD);


/* Increase index*/
Idx++;
}
else
{
/* Reset index*/
Idx = 0;
}
}
return 0;
}



In my setup, I have a Master that continuously send 0xAB to the slave. The code above will reply the Master with 0x50, 0x0F and 0x32.
In practical application,the Slave can only reply to the Master when there is a Clock signal. Therefore, the Master must send a few dummy bytes depending on the number of replies it expect from the Slave.
0 Likes