Control of SPI Chip select

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

cross mob
Not applicable
I am having trouble controlling the MSLS / Chip select signal.

I want it to enable at the start of a frame and disable after the last byte is transmitted.

The SPI001 app is configured to use FIFO.. Great. As long as the FIFO is not empty, the CS signal behaves properly. However, I am in an RTOS environment so occassionally, the service time allows the fifo to empty and CS pulses. This disturbs the slave - it cancels the current command.


I attempted to use the frame control interface..

EnableStartOfFrame( pScb->Handle );

// Send the command..
SendSpiWord( pScb, Cmd );
SendSpiWord( pScb, IDLE0 ); // Put something in the Rx buffer...

. . .

// Wait for all our data to go..
while ( ! SPI001_GetFlagStatus(&(pScb->Handle), SPI001_FIFO_TRANSMIT_FIFO_EMPTY ))
;
//while ( SPI001_GetFlagStatus(pScb->Handle, SPI001_TRANS_SHIFT_IND_FLAG ))
;
EnableEndOfFrame( pScb->Handle );

I enable the frame.. then send..finally wait for FIFO to empty... But that is too late to get the EOF set - the last character is transmitting.... So my sessions ends with CS active. Then the first byte of the next frame has CS pulsed just for that first byte...

Without the test on FIFO_TRANSMIT_FIFO_EMPTY, the CS EOF happens too early.

NOTE: FIFO EMPTY is something I defined to access that bit of TRSB.. It is defined at 64+Bit Number in the register.


The notes in the UM describe CS control, but most do not use FIFO.. The section on FIFO is vague.

What is my best strategy? Options seem:
- Use FIFO. Let it control CS... Just make sure it doesn't empty prematurely. Maybe tx interrupt service routine to extrace from RTOS queue.
- Switch to non-fifo interface, scrapping the app. More work, but precise control.

I looking for general direction suggestions.
0 Likes
21 Replies
Not applicable
Hi danbeadle,
for me it worked this way:
In the SPI001 App check "Enable Frame End Mode"
Set the frame length to 64 Bits (so you have to mark the beginning and the end of the frame with enable start/end of frame)

The data is then send with
EnableStartOfFrame( pScb->Handle );
SendSpiWord( pScb, IDLE0 );
.
.
.
and now BEFORE sending the last byte you have to set EnableEndOfFrame!
EnableEndOfFrame( pScb->Handle );
SendSpiWord( pScb, IDLE0 );


Hope its working for you too! I know the documentation on this is not so clear...

Greetings Werner
0 Likes
User5581
Level 3
Level 3
Hi All,

I am having problems getting the USIC to toggle the chip select pin.
I am using SPI001 v.1.0.18 on an XMC4500F144K1024AB Target.
Both tx and rx FIFO sizes are set to 16 in the GUI, with trigger limits of 1 on each.
Word length is set to 8 bits and I have tried both 8 and 64 bit frame length settings with no luck.
Frame length mode is enabled in the GUI, and I am using standard full duplex SPI.
In the following function, the SPI data gets transmitted out onto the bus, but no chip select is seen:

SPI_ResultType spi0_bytewrite(uint8_t *txbuffer, uint16_t length)
{
uint16_t i=0;
uint16_t waitcount=0;
if (length == 0)
return SPI_OK; //do nothing, but do not complain.
EnableStartOfFrame(SPI001_Handle0); // indicate to USIC that CS should be asserted before the next frame sent
do
{
while (USIC_IsTxFIFOfull(SPI001_Handle0.USICRegs))
{
if (waitcount++ > 1000) // Block until some room opens up in the Tx FIFO
{
SPI001_ClearFlag(&SPI001_Handle0,SPI001_MSLS_STATUS_FLAG); // rescind CS upon error
return (SPI_WRITE_TXBUF_TIMEOUT_ERR); // return indicating a timeout
}
}
if (i == length-1) // if last frame is being sent then ....
EnableEndOfFrame(SPI001_Handle0); // indicate to the USIC that CS should be rescinded after the next frame sent
SPI001_WriteData(&SPI001_Handle0,(uint16_t*)(txbuffer + i),SPI001_STANDARD); // send SPI frame data to the USIC
i++; // count the number of frames sent
} while(i < length);
return SPI_OK;


While stepping through with the debugger, I can see that the MSLS Status bit in the PSR_SSCMode register remains 0 - inactive.

Perhaps someone else can see what is wrong with this approach, as I am stumped at the moment.

Thanks!
0 Likes
Not applicable
Hi zoompig,

May I know which CS pin did you select?
Can you check if the MSLSEN in PCR_SSCMode is enable?
Thank you.
0 Likes
User5581
Level 3
Level 3
Hi Jackson,

I have P0.6 / pin 140 chosen as the chip select (/CS).

If I call the function above asking for 4 bytes to be sent (In this case 0xAA, 0x55, 0xAA, 0x55) I get the following SPI activity:

248.attach

You can see that /CS activates before the first byte is sent, but does not deactivate after the 4 bytes are sent.

If I set a breakpoint just after the first byte is sent, I get the following in USIC1_CH0.PCR_SSCMode:

249.attach

Here is the contents of USIC1_CH0.PSR_SSCMode at that same breakpoint:

250.attach

The MSLSEN bit appears to be active/enabled.

Thank you for helping me figure this out.
0 Likes
User5581
Level 3
Level 3
Additionally, here is the contents of SPI001_Conf.c:

SPI001_ConfigType SPI001_Config0 =
{
.Mode = SPI001_STANDARD_FULLDUPLEX,/* SPI Mode */
.HBMode = SPI001_LSB, /* Transmit LSB/MSB */
.ClkPol = SPI001_CLK_POL0, /* Clock Polarity */
.ClkPh = SPI001_CLK_PHASE0, /* Clock Phase */
.BaudRate = (uint32_t) 1000000,/* 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) 2, (uint8_t) 2, (uint8_t) 0, (uint8_t) 0},
.Pin_Num = {(uint8_t) 14, (uint8_t) 15,(uint8_t) 0, (uint8_t) 0},
/* Pin Port Base Address */
.PinPortRegs = {(SPI001_PORTS_TypeDef*)PORT2_BASE,
(SPI001_PORTS_TypeDef*)PORT2_BASE,
(SPI001_PORTS_TypeDef*)PORT0_BASE,
(SPI001_PORTS_TypeDef*)PORT0_BASE
},
.MRST_DSEL = (uint8_t) 2, /* 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) 1, /* No of ChipSelect line */
.ChipSelTable = {(uint8_t) 0, (uint8_t) 0, (uint8_t) 0, (uint8_t) 0,
(uint8_t) 0, (uint8_t) 0, (uint8_t) 0, (uint8_t) 0
},
.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
};


I notice that TxFifoSize and RxFifoSize are set to 4 in the generated code, even though I have them set to 16 in the GUI.
I am guessing this is a seperate issue and may not related to problems generating /CS.

I also notice that ChipSelTable has all zero entries here. Looking through SPI001.c, it appears that this field is used to set the SELO field in the PCR_SSCMode register. This appears to be cleared to all zeros when I stop on a breakpoint after the first byte is sent. Could this be the source of my /CS generation problem?

Additionally, the debug display of SELO in the PCR does not actually show the value stored in the field, as you can see in the earlier attached screen capture. Perhaps that should be ticketed for this to be added in future versions of the register definitions that come with DAVE3.

Thanks.
0 Likes
Not applicable
Hi zoompig,

I develop the same setting at my side here but everything works fine.
I wondering is it the EnableEndOfFrame(SPI001_Handle0); did not occurs.
Perhaps you can try something like this first:
	
uint16_t SendData = 0x05;

EnableStartOfFrame(SPI001_Handle0);

SPI001_WriteData(&SPI001_Handle0,&SendData,SPI001_STANDARD);
SPI001_WriteData(&SPI001_Handle0,&SendData,SPI001_STANDARD);
SPI001_WriteData(&SPI001_Handle0,&SendData,SPI001_STANDARD);
SPI001_WriteData(&SPI001_Handle0,&SendData,SPI001_STANDARD);

EnableEndOfFrame(SPI001_Handle0);


This code works well at my side with CS activated and deactivated.
0 Likes
User5581
Level 3
Level 3
Hi Jackson,

I have tried the code you just posted above and still have no luck generating a chip select. Could you post the working contents of SPI001_Conf.c that work so I may compare?

Thanks.
0 Likes
lock attach
Attachments are accessible only for community members.
Not applicable
Hi zoompig,

If you set the Frame Length to = 8, the CS will deactivated every byte it sent out.
This means, if you sending out 4 bytes, the CS signal will activate and deactivate for 4 times.
Attached the project I did with Frame Length = 8.


But if I understand what you would like to implement correctly, what you want are:
1) Activated CS signal when you call EnableStartOfFrame(SPI001_Handle0);
2) Sending out any number of bytes while keep CS is activated (no deactivated between byte to byte)
3) Deactivated CS signal after you sent all the data by calling EnableEndOfFrame(SPI001_Handle0);

Is this what you want to implement?
If so, in order for this, you need to set the Frame Length to 64.
This means the frame length is set to infinity until End of Frame (EOF) is set.
But if you refers to the Reference Manual for End-of-Frame Control in USIC chapter, the EOF bit (EnableEndOfFrame) is only valid to handle data in TBUF, not in FIFO.
As the generated code from DAVE3 is using FIFO, it is not possible to indicate end of frame in FIFO using the TCSR.EOF bit.
To handle end of frame in FIFO, user must set the TCSR.WLEMD = 1, and use TCI to control the end of frame.
	
USIC1_CH0->TCSR |= USIC_CH_TCSR_WLEMD_Msk; // Enable WLE mode
USIC1_CH0->IN[7] = SendData; // Send data (data size 8 bit)
USIC1_CH0->IN[7] = SendData; // Send data (data size 8 bit)
USIC1_CH0->IN[7] = SendData; // Send data (data size 8 bit)
USIC1_CH0->IN[17] = SendData; // Send data (data size 8 bit with EOF)


For more information, please refers to chapter End-of-Frame Control in XMC4500 Reference Manual.
0 Likes
User5581
Level 3
Level 3
Hi Jackson,

I will look into TCI and TCSR.WLEMD to try to accomplish this.

I am confused when you say that the EOF bit is only to handle data using TBUF and not for use with the FIFO.

In the XMC4500 Reference manual V1.2 2012-12 section 17.4.3.6 ‘End-of-Frame Control’ it says:

• FIFO-based address related end of frame handling:
This mechanism can be used if a data FIFO is used to store the transmit data. The
general behavior is similar to the software-based address related end of frame
handling, except that transmit data is not written to the locations TBUF[31:0], but to
the FIFO input locations IN[31:0] instead. In this case, software must not write to any
of the TBUF locations.



This seems to contradict your last post. Can you please explain in more detail regarding using End-Of-Frame mode and FIFO mode at the same time? Is the reference manual wrong about this?

Thanks for your help!
0 Likes
Not applicable
Hi zoompig,

I think you misunderstood the Reference Manual.
If you refers to the "Software-based address related end of frame handling", it is basically ask you to set TCSR.WLEMD = 1.
This is how you can handle the EOF using TCI control.
Then instead of placing your data into TBUF[31:0], you have to place your data into IN[31:0] if you using FIFO.

For handle End of Frame via register TSCR.EOF, which means means you directly setting the bit from the register itself.
This is only possible if the data is place on TBUF.
0 Likes
Not applicable
Jackson,

I was reading this thread with interest as I am having some problems controlling the CS line. However it seems not to be too clear on the conclusion on getting CS to be controlled from SW whilst using DAVE generated code (i.e. the FIFO).

I would like to:
Activate CS signal (from my SW)
Write a number of bytes to the SPI
Deactivate CS signal (from my SW)

The number of bytes I send depends on the message type and can be 1, 2 or 7 bytes.


From your example code I should:

USIC1_CH0->TCSR |= USIC_CH_TCSR_WLEMD_Msk; // Enable WLE mode
USIC1_CH0->IN[7] = SendData; // Send data (data size 8 bit)
USIC1_CH0->IN[7] = SendData; // Send data (data size 8 bit)
USIC1_CH0->IN[7] = SendData; // Send data (data size 8 bit)
USIC1_CH0->IN[17] = SendData; // Send data (data size 8 bit with EOF)

I have a few questions that you maybe able to answer with respect to this:

If the frame length is required to be set, what should it be set to? (At present I am changing this at run-time)
What should my Tx FIFO buffer length be set to? (At present this is set to 8 i.e. larger than my longest message).

At what point in your example does the CS go high? After Enabling WLE mode or on the first assignment of IN[7]

I don't understand the last line what is the connection between IN[17] and EOF?

Thanks for any help,

Steve
0 Likes
Not applicable
AlliedSteve,

Jackson can probably explaing better but there is one thing I would like to point out after having worked through this same problem.
The subscript in this line of code should be 0x17 not 17.
USIC1_CH0->IN[17] = SendData; // Send data (data size 8 bit with EOF).

Kirk
0 Likes
Not applicable
Hi Steve,

Kirk is correct, it should be 0x17h or decimal 23. Is my mistake on the code provided.

When TCSR.WLEMD = 1, bit field SCTR.WLE is updated with TCI[3:0] and TCSR.EOF is updated with TCI[4].
The 5 bit TCI[4:0] refers to the FIFO buffer number.

For example:
1) IN[7] = TCI[4:0] = 00111b.
So, SCTR.WLE = 0111b = 0x07h (Word size 8 bit)
TCSR.EOF = 0b (EOF is not set)

2) IN[23] = TCI[4:0] = 10111b.
So, SCTR.WLE = 0111b = 0x07h (Word size 8 bit)
TCSR.EOF = 1b (EOF is set)

The frame length (SCTR.FLE) has to be set to 63 or 0x3Fh and it will turn it to infinity. Hence, the CS line won't be deactivated during transmission until EOF bit is set.
The CS line will be activated when there is data need to be send which is USIC1_CH0->IN[7] = SendData; in this case.

I hope I clear your doubt.
0 Likes
Not applicable
Thanks for the replies Jackson and Kirk,

sorry but your explanations are not too clear. Are there some 'b's and 'h's in the wrong place in the examples 1 and 2?

Is the following correct?

So to activate CS, send three bytes of data and deactivate CS:

// Data to be sent over SPI
uint8_t data[3] = { 11, 22, 33 };

USIC1_CH0->SCTR.FLE = 0x3F; // Set frame length to infinity to prevent frame length affecting CS

USIC1_CH0->TCSR |= USIC_CH_TCSR_WLEMD_Msk; // Enable WLE mode

USIC1_CH0->IN[7] = data[0]; // Sent first byte, CS activated
USIC1_CH0->IN[7] = data[1];
USIC1_CH0->IN[23] = data[2]; // Send last byte and deactivate CS

Can the macro USIC_IsTxFIFOempty from USIC.h still be used in this scenario to check the SPI Tx buffer is empty? If not how can I check the Tx buffer is empty?

Steve
0 Likes
Not applicable
Hi Steve,

Yes, the USIC_IsTxFIFOempty is still valid. Once the data in the FIFO is empty, the flag will be set.
For your info, the FIFO empty does not mean all data has been sending out.
It is only indicated the data is transmitted from FIFO buffer to the shift register in order to be sent out.
So there will be some delay from the time the FIFO is empty and the data is completely sent out.

P/S: I have corrected the b's and h's in the previous post. 🙂
0 Likes
Not applicable
Hi,

thanks for that. More questions...

When I run the code (see below) it appears to do what I would expect. CS activated prior to data[0] being clocked out and CS deactivated after data[2] is sent.
However, when

USICRegs->IN[23] = 33;

is replaced with:

USICRegs->IN[7] = 33;

The CS is still deactivated when the third byte is sent. What's going on? What is controlling the deactivation of the CS after the line USICRegs->IN[7] = 33;? Is it the Tx FIFO going empty? If so, this is not want is wanted.

To reiterate: I would like to have sole control of the activation/deactivation of the CS line. I want to be able to send a varying number of bytes (within the confines of the size of the Tx FIFO buffer). Currently set at 8 bytes since my longest message (frame is 7 bytes).


USIC_CH_TypeDef* USICRegs = (&SPI001_Handle0)->USICRegs;

// Set to max to try to turn off aut CS
USICRegs->SCTR |= ( ( (uint32_t)( (uint32_t)64 - (uint32_t)1 ) << USIC_CH_SCTR_FLE_Pos ) & USIC_CH_SCTR_FLE_Msk );

USICRegs->TCSR |= USIC_CH_TCSR_WLEMD_Msk; // Enable WLE mode

while(1)
{
USICRegs->IN[7] = 11;
USICRegs->IN[7] = 22;
USICRegs->IN[23] = 33;

// Wait for transmit FIFO to empty...
while(!USIC_IsTxFIFOempty(SPI001_Handle0.USICRegs)){};

t=0;while( t} // while
0 Likes
Not applicable
Hi Steve,

Perhaps you need to check whether the PCR.FEM bit has been set or not?

Best regards,
Zain
0 Likes
Not applicable
Zain,

thanks for your reply. Setting FEM that seems to do the trick. It wasn't apparent from the previous posts. Now working.

Regards,

Steve
0 Likes
User7989
Level 2
Level 2
I have a SPI read loop which breaks when the result matches a specified value. Everything must be made in one single frame.

The normal way would be to put CS high when the condition is met and then break.

But this fix will force me to send out an extra dummy byte with EOF.


This could be overcomed by mapping CS to IO004-app, and to control it manually (without FIFO).
But to manage this am i still forced to know when all bits have been shifted out. Is this even possible to read out?

Or is there any other way to control it, without sending data?
0 Likes
Not applicable
Hi Anders,

What I understand in your case is that there is no data required to be sent out once the condition is met. The only thing needs to do is to put CS high. I was wondering why you need to check the contents in the shift register?

Best regards,
Sophia
0 Likes
Not applicable
Hi,
I am having trouble in SPI.I have interfaced ST M95320 (EEPROM) using SPI. I did the following configuration for infinite frame length.
1-> Enabled WLEMD That is TCSR.WLEMD = 1;
2-> Enabled Frame End Mode SCTR.FEM =1;
3-> Word length = 8;
4-> Frame length = 64;

For EOF last byte transmitted as USIC_CH_reg->IN[23] = Data; // Data with EOF.
and for previous bytes USIC_CH_reg ->IN[7] = Data; // Data without EOF.

After making all these configuration still there is nothing on MISO line, So what other configuration I need to do?
and another doubt is what should be the DPTR values in TBCTR and RBCTR..?
0 Likes