XMC4200, SPI and two memories

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

cross mob
User3847
Level 3
Level 3
Dear all,

I have a board with an XMC4200 and two memories connected to an USIC channel.

As al other USICs are being used for other communications and the USIC I had left, U1CH0 had only one CS pin available, I decided that in order to interact with the second memory I would toggle the second CS pin manually. The problem is, the USIC is always activating the first CS, even if I tell it not to.

Things I tried:
* Different CESelected value for the SPI001_ConfigType I am using
* Changing from direct select mode to coded select mode when using the second memory
* Deactivating in PCR the first SELO
* Deactivating in PCR the first SELO and activating the second
* Deactivating MSLSEN in PCR

In any case, the USIC is always toggling the first chip select.

Is there any way to avoid that?

Best regards,
0 Likes
4 Replies
Not applicable
Hi sblanco,

I believe you are using XMC4200 64-pin package as you can used U1CH0 for SPI.
Currently I only have 48-pin device with me and can't really test it with USIC U1CH0.
But I have made a test on U0CH0 to disable the CS signal by writing '0' to PCR.SELO and this method works for me.
I can enable and disable the CS signal as whenever I want.

Perhaps you can try it on the other channel first to make sure your code to deactivating the SELO is correct.
If other channel is working fine and only U1CH0 is not working, then it could be some hardware bug.
Meanwhile, I try to see if I can find 64-pin package device to give it a try.
0 Likes
User3847
Level 3
Level 3
Hello Jackson,

Let me explain better.

I did not use the U0C0 for this as that USIC channel is used for PC communications ad probably ASC bootloader.

The thing is, I have two memories connected to U1C0: an Spansion S25FL032P and a Microchip 25LC1024. The dedicated chip select is connected to the Spansion memory and I have a normal IO for the 25LC chip select.

The Spansion memory works great, but when I want to use the 25LC, the idea is the following:

* Toggle the CS IO
* Use the USIC channel configured with a non connected CS
* Toggle the CS IO

Here is the code I am trying:


SPI001_ConfigType M25LC_Config =
{
.Mode = SPI001_STANDARD_FULLDUPLEX,/* SPI Mode */
.HBMode = SPI001_MSB, /* Transmit LSB/MSB */
.ClkPol = SPI001_CLK_POL0, /* Clock Polarity */
.ClkPh = SPI001_CLK_PHASE0, /* Clock Phase */
.BaudRate = (uint32_t) 1000,/* Baud Rate */
.LeadTrailDelay = SPI001_ONE_SCLK_PERIOD,/* Leading/TrailingDelay */
.NextFrameDelay = SPI001_ONE_SCLK_PERIOD,/* NextFrameDelay */
.WordLen = (uint8_t) 8,/* Wordlength */
.FrameLen = (uint8_t) 8,/* Framelength */
.CESelected = (uint8_t) CE_B /* Default Chip Select line selection */
};

SPI001_ConfigType* devices[1] =
{
&M25LC_Config
};

IO004_HandleType* cs[1] =
{
&IO004_25LC_CS
};

void SPI_Write(uint8_t device, uint8_t command, uint32_t addr, uint8_t* data, uint8_t length)
{
uint16_t tmp;
uint8_t Status1 = 0;
uint8_t Status2 = 0;
uint16_t Data = 0;

WR_REG(SPI001_Handle0.USICRegs->PCR, USIC_CH_PCR_SSCMode_SELCTR_Msk, USIC_CH_PCR_SSCMode_SELCTR_Pos, 0);

IO004_TogglePin((*(cs[device])));

SPI001_ConfigType spi_conf = *(devices[device]);

spi_conf.Mode = SPI001_STANDARD_FULLDUPLEX;

uint8_t frame_length = 1;
if(addr != 0xFFFFFFFF)
frame_length += 3;
frame_length += (length / 8);

spi_conf.FrameLen = frame_length;

/* Configure the channel with given configuration */
SPI001_Configure(&SPI001_Handle0,&spi_conf);

int data_cycle, Number_Of_Dummy_Bytes = 0;

if(spi_conf.FrameLen == 64)
EnableStartOfFrame(SPI001_Handle0);

SPI001_ClearFlag(&SPI001_Handle0,SPI001_RECV_IND_FLAG);
SPI001_ClearFlag(&SPI001_Handle0,SPI001_ALT_RECV_IND_FLAG);

Data = command;

// Write the command
SPI001_WriteData(&SPI001_Handle0,&Data,SPI001_STANDARD);

do
{
Status1 = SPI001_GetFlagStatus(&SPI001_Handle0,SPI001_RECV_IND_FLAG);
Status2 = SPI001_GetFlagStatus(&SPI001_Handle0,SPI001_ALT_RECV_IND_FLAG);
}while(!((Status1 == SPI001_SET) || (Status2 == SPI001_SET)));
SPI001_ReadData(&SPI001_Handle0,&tmp); // dummy read

SPI001_ClearFlag(&SPI001_Handle0,SPI001_RECV_IND_FLAG);
SPI001_ClearFlag(&SPI001_Handle0,SPI001_ALT_RECV_IND_FLAG);

// Write the address
if (addr != 0xFFFFFFFF)
{
Data = (uint8_t)((addr >> 16) & 0x000000FF);
SPI001_WriteData(&SPI001_Handle0,&Data,SPI001_STANDARD);

do
{
Status1 = SPI001_GetFlagStatus(&SPI001_Handle0,SPI001_RECV_IND_FLAG);
Status2 = SPI001_GetFlagStatus(&SPI001_Handle0,SPI001_ALT_RECV_IND_FLAG);
}while(!((Status1 == SPI001_SET) || (Status2 == SPI001_SET)));
SPI001_ReadData(&SPI001_Handle0,&tmp);

SPI001_ClearFlag(&SPI001_Handle0,SPI001_RECV_IND_FLAG);
SPI001_ClearFlag(&SPI001_Handle0,SPI001_ALT_RECV_IND_FLAG);

Data = (uint8_t)((addr >> 😎 & 0x000000FF);
SPI001_WriteData(&SPI001_Handle0,&Data,SPI001_STANDARD);

do
{
Status1 = SPI001_GetFlagStatus(&SPI001_Handle0,SPI001_RECV_IND_FLAG);
Status2 = SPI001_GetFlagStatus(&SPI001_Handle0,SPI001_ALT_RECV_IND_FLAG);
}while(!((Status1 == SPI001_SET) || (Status2 == SPI001_SET)));
SPI001_ReadData(&SPI001_Handle0,&tmp);

SPI001_ClearFlag(&SPI001_Handle0,SPI001_RECV_IND_FLAG);
SPI001_ClearFlag(&SPI001_Handle0,SPI001_ALT_RECV_IND_FLAG);

if(spi_conf.FrameLen == 64 && length == 0)
EnableEndOfFrame(SPI001_Handle0);

Data = (uint8_t) (addr & 0x000000FF);
SPI001_WriteData(&SPI001_Handle0,&Data,SPI001_STANDARD);

do
{
Status1 = SPI001_GetFlagStatus(&SPI001_Handle0,SPI001_RECV_IND_FLAG);
Status2 = SPI001_GetFlagStatus(&SPI001_Handle0,SPI001_ALT_RECV_IND_FLAG);
}while(!((Status1 == SPI001_SET) || (Status2 == SPI001_SET)));
SPI001_ReadData(&SPI001_Handle0,&tmp);

SPI001_ClearFlag(&SPI001_Handle0,SPI001_RECV_IND_FLAG);
SPI001_ClearFlag(&SPI001_Handle0,SPI001_ALT_RECV_IND_FLAG);
}

// Write the data
if (length != 0)
{
// Write the data using the relevant mode
for (data_cycle = 0; data_cycle < length; data_cycle++)
{
if(spi_conf.FrameLen == 64 && data_cycle == length - 1)
EnableEndOfFrame(SPI001_Handle0);

SPI001_ClearFlag(&SPI001_Handle0,SPI001_RECV_IND_FLAG);
SPI001_ClearFlag(&SPI001_Handle0,SPI001_ALT_RECV_IND_FLAG);
Data = data[data_cycle];
SPI001_WriteData(&SPI001_Handle0,&Data,SPI001_STANDARD);

do
{
Status1 = SPI001_GetFlagStatus(&SPI001_Handle0,SPI001_RECV_IND_FLAG);
Status2 = SPI001_GetFlagStatus(&SPI001_Handle0,SPI001_ALT_RECV_IND_FLAG);
}while(!((Status1 == SPI001_SET) || (Status2 == SPI001_SET)));
SPI001_ReadData(&SPI001_Handle0, &Data);
}

}
IO004_TogglePin((*(cs[device])));

WR_REG(SPI001_Handle0.USICRegs->PCR, USIC_CH_PCR_SSCMode_SELCTR_Msk, USIC_CH_PCR_SSCMode_SELCTR_Pos, 1);
}


I also tried activating another SELO manually, but the chip select of the spansion memory gets used:


WR_REG(SPI001_Handle0.USICRegs->PCR, USIC_CH_PCR_SSCMode_SELO_Msk, USIC_CH_PCR_SSCMode_SELO_Pos, 2);

...

WR_REG(SPI001_Handle0.USICRegs->PCR, USIC_CH_PCR_SSCMode_SELO_Msk, USIC_CH_PCR_SSCMode_SELO_Pos, 0);


In SPI001_Conf I have:


SPI001_ConfigType SPI001_Config0 =
{
.Mode = SPI001_QUAD,/* SPI Mode */
.HBMode = SPI001_MSB, /* Transmit LSB/MSB */
.ClkPol = SPI001_CLK_POL1, /* Clock Polarity */
.ClkPh = SPI001_CLK_PHASE0, /* Clock Phase */
.BaudRate = (uint32_t) 10000000,/* Baud Rate */
.LeadTrailDelay = SPI001_ONE_SCLK_PERIOD,/* Leading/TrailingDelay */
.NextFrameDelay = SPI001_ONE_SCLK_PERIOD,/* NextFrameDelay */
.WordLen = (uint8_t) 8,/* Wordlength */
.FrameLen = (uint8_t) 8,/* Framelength */
.CESelected = (uint8_t) CE_A /* Default Chip Select line selection */
};

SPI001_PinHandleType SPI001_PinHandle0 =
{

.Port_Num = {(uint8_t) 0, (uint8_t) 0, (uint8_t) 0, (uint8_t) 0},
.Pin_Num = {(uint8_t) 5, (uint8_t) 4,(uint8_t) 3, (uint8_t) 2},
/* Pin Port Base Address */
.PinPortRegs = {(SPI001_PORTS_TypeDef*)PORT0_BASE,
(SPI001_PORTS_TypeDef*)PORT0_BASE,
(SPI001_PORTS_TypeDef*)PORT0_BASE,
(SPI001_PORTS_TypeDef*)PORT0_BASE
},
.MRST_DSEL = (uint8_t) 0, /* DSEL Value */
.MTSR_IOCR = (uint8_t) 2 /* IOCR_PCR value */
};


const SPI001_HandleType SPI001_Handle0 =
{
.USICRegs = USIC1_CH0, /* Usic Channel offset value */
.FrmEndMode = SPI001_ENABLE_FEM,/* Frame End mode Selection*/
.Config = &SPI001_Config0,
.NoOfCS = (uint8_t) 2, /* No of ChipSelect line */
.ChipSelTable = {(uint8_t) 0, (uint8_t) 1, (uint8_t) 1, (uint8_t) 1,
(uint8_t) 1, (uint8_t) 1, (uint8_t) 1, (uint8_t) 1
},
.TxLimit = (uint8_t) 1,/* FIFO Tigger Level */
.RxLimit = (uint8_t) 1,/* FIFO Tigger Level */
.TxFifoSize = (uint8_t) 4,/* Tx FIFO Size */
.RxFifoSize = (uint8_t) 4,/* Rx FIFO Size */
.MSLSIntrEn = (bool) 0,/* MSLS Event enable */
.PinHandle = &SPI001_PinHandle0
};


You can see, I modified the ChipSelTable in hope that just doing that the peripheral internally would activate a SELO that is not connected to any pin, but still I got the main chip select activated.

Do you have any suggestion?

Thank you
0 Likes
Not applicable
Hi sblanco,

Where did you disable the SELO?
I would expect you disable it before you send any data.
0 Likes
User3847
Level 3
Level 3
Hi Jackson,

When I write the SELO bits, am I not disabling one and activating other?

How would you have me try?

Best regards,
0 Likes