This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

f28335 McBSP as SPI issues

Other Parts Discussed in Thread: SYSBIOS

Hello everyone

My target is F28335, boards are custom, CCS 6.0.1, Compiler 6.2.7, SYSBIOS used
Flash accessed by SPI is Spansion S25FL512S

I use the McBSP peripheral of F28335 in SPI mode

I made it work to write and read in a flash memory at 2.5 MHz.
But the slightest change in the code or in the speed config, make it fail to read/write.

The oscilloscope shows correct data read from the flash, so it's a software issue.

In loopback mode everything works (it's too basic)
On the ez eval board with TI example code (multiday workshop module 14) it works too.

I have a few questions about the example code for READ, reproduced below

int McBSP_B_EEPROM_Read(int address)
{
	int data;
	CS_EEPROM = 0;							// activate /CS for the EEPROM
	McbspbRegs.DXR1.all = READ;				// Read op-code
	while (McbspbRegs.SPCR2.bit.XRDY == 0);
	McbspbRegs.DXR1.all = address>>8;		// Higher byte of starting address
	while (McbspbRegs.SPCR2.bit.XRDY == 0);
	McbspbRegs.DXR1.all = address;			// Lower byte of starting address
	while (McbspbRegs.SPCR2.bit.XRDY == 0);
	McbspbRegs.DXR1.all = 0x00;				// send dummy Data
	while (McbspbRegs.SPCR2.bit.XRDY == 0);
	data = McbspbRegs.DRR1.all;				// Clears receive flag
	while (McbspbRegs.SPCR1.bit.RRDY == 0);
	data = McbspbRegs.DRR1.all;				// Reads data from memory
	CS_EEPROM = 1;							// deactivate /CS for the EEPROM 
	return(data);
}

1) Why is it needed to read DRR1 twice ?

It doesn't make sense to me and it's NOT explained anywhere in the McBSP guide or any documentation

Now if we take a look at the init code reproduced below

void McBSPB_Init()
{   	
    EALLOW;
   	McbspbRegs.SPCR1.all=0x0000;		// Reset Receiver
	McbspbRegs.SPCR1.bit.CLKSTP = 3;	// 3: Clockstop mode set to inactive low.
										// McBSP transmits data 1/2 cycle ahead of CLKX
	McbspbRegs.SPCR1.bit.RRST = 1;		// 1: Enables receiver

	McbspbRegs.SPCR2.all=0x0000;		// Reset FS generator, sample rate generator & transmitter
 	McbspbRegs.SPCR2.bit.FREE  = 1;		// Free run in break event 
	McbspbRegs.SPCR2.bit.GRST = 1;		// 1: Enables sample rate generator
	McbspbRegs.SPCR2.bit.XRST = 1;		// 1: Enables transmitter
	McbspbRegs.SPCR2.bit.FRST=1;		// 1: release frame logic from reset
	
	McbspbRegs.PCR.bit.CLKXP = 0;			// 0: Transmit data sampled on rising edge of CLKX
	McbspbRegs.PCR.bit.CLKRP = 1;			// 1: Receive data sampled on rising edge of MCLKR
	McbspbRegs.PCR.bit.CLKXM = 1;			// 1: McBSP is master in SPI-mode; 
											//    CLKX drives pin MCLKX and MCLKR(internally)
	McbspbRegs.PCR.bit.SCLKME = 0;			// 0: McBSP clock generator derived from LSPCLK 
	McbspbRegs.PCR.bit.FSXM = 1;			// 1: Transmit frame sync generated internally by CLKG
	McbspbRegs.PCR.bit.FSXP = 1;			// 1: Transmit frame sync pulses are active low

	McbspbRegs.SRGR1.bit.CLKGDV = 37;		// 37: CLKG = LSPCLK/(37+1) = 1 MHz on McBSP 

	McbspbRegs.SRGR2.bit.CLKSM = 1;			// 1: McBSP clock generator derived from LSPCLK
	McbspbRegs.SRGR2.bit.FSGM = 0;			// 0: McBSP generates a frame sync when DXR is copied into XSR

	McbspbRegs.XCR1.bit.XFRLEN1 = 0;		// 0: One word per frame for transmit
	McbspbRegs.XCR1.bit.XWDLEN1 = 0;		// 0: 8 bit transmit word
	
	McbspbRegs.XCR2.bit.XPHASE = 0;			// 0: Single phase transmit
	McbspbRegs.XCR2.bit.XDATDLY = 0;		// 0: No data delay between sync and first data bit

 	McbspbRegs.RCR1.bit.RFRLEN1 = 0;		// 0: One word per frame for receive
	McbspbRegs.RCR1.bit.RWDLEN1 = 0;		// 0: 8 bit receive word

	McbspbRegs.RCR2.bit.RDATDLY = 0;		// 0: No data delay because FSX not needed for chip select
	McbspbRegs.RCR2.bit.RPHASE = 0;			// 0: Single phase receive

    EDIS;
}

2) Why are XDATDLY and RDATDLY set to 0 ?

In the McBSP user guide table 6.3 it is explicitely said XDATDLY and RDATDLY must be set to 1 in SPI mode

3) Why the init code does not follow the 6-step configuration procedure ?

In the user guide there is a procedure (6.5) that includes waiting clock periods and a specific order of initialization.

Now here's my init routine

{
	/* Step 1. Place the transmitter and receiver in reset. */
	p_mcbsp_regs->SPCR1.bit.RRST = 0;
	p_mcbsp_regs->SPCR2.bit.XRST = 0;

	/* Step 2. Place the sample rate generator in reset. */
	p_mcbsp_regs->SPCR2.bit.GRST = 0;

	/* Step 3. Program registers that affect SPI operation. */

	/* Stop mode --> SPI + no delay (phase) */
	p_mcbsp_regs->SPCR1.bit.CLKSTP = 2;

	/* Loopback disabled */
	p_mcbsp_regs->SPCR1.bit.DLB = 0;

	/* Right justify the data received and zero fills MSBs */
	p_mcbsp_regs->SPCR1.bit.RJUST = 0;

	/* Additionnal delay disabled */
	p_mcbsp_regs->SPCR1.bit.DXENA = 0;

	/* Free run during breakpoints */
	p_mcbsp_regs->SPCR2.bit.FREE = 1;
	p_mcbsp_regs->SPCR2.bit.SOFT = 1;


	/* Receive polarity */
	/* Transmit polarity */
	/*
	 * no delay
	 * data captured on RISING edge
	 * data out on FALLING edge
	 */
	p_mcbsp_regs->PCR.bit.CLKRP = 1;
	p_mcbsp_regs->PCR.bit.CLKXP = 1;

	/* Master */
	p_mcbsp_regs->PCR.bit.CLKXM = 1;

	p_mcbsp_regs->PCR.bit.CLKRM = 1;

	/* single phase transmit/receive frame */
	p_mcbsp_regs->XCR2.bit.XPHASE = 0;
	p_mcbsp_regs->RCR2.bit.RPHASE = 0;

	/* frame length of one serial word */
	p_mcbsp_regs->XCR1.bit.XFRLEN1 = 0;
	p_mcbsp_regs->RCR1.bit.RFRLEN1 = 0;

	/* One word is 8 bits */
	p_mcbsp_regs->XCR1.bit.XWDLEN1 = 0;
	p_mcbsp_regs->RCR1.bit.RWDLEN1 = 0;

	p_mcbsp_regs->RCR2.bit.RCOMPAND = 0;
	/* Must be Set to 1 for proper SPI master operation */
	p_mcbsp_regs->RCR2.bit.RDATDLY = 1;
	p_mcbsp_regs->RCR2.bit.RFIG = 1;

	p_mcbsp_regs->XCR2.bit.XCOMPAND = 0;
	/* Must be Set to 1 for proper SPI master operation */
	p_mcbsp_regs->XCR2.bit.XDATDLY = 1;
	p_mcbsp_regs->XCR2.bit.XFIG = 1;

	/*
	 * McBSP generates a transmit frame-synchronization pulse when the content of DXR[1,2] is copied to XSR
	 * (even though we use the CS pin as a classic GPIO and not let McBSP drive it)
	 */
	p_mcbsp_regs->SRGR2.bit.FSGM = 0;

	/* Input Clock For Sample Rate Generator -> Low Speed Clock LSPCLK */
	p_mcbsp_regs->PCR.bit.SCLKME = 0;
	p_mcbsp_regs->SRGR2.bit.CLKSM = 1;

	/*
	 * CLKG freq with LSCLK = SYSCLKOUT / 8
         * CLKG freq = LSPCLK / (CLKGDV + 1)
	 * CLKG freq = 5 MHz
	 */
	p_mcbsp_regs->SRGR1.bit.CLKGDV = 1;

	/*
	 * FSX ~= SPI CS need to be generated internally
	 * Transmit frame synchronization is generated internally by the Sample Rate generator,
	 * as determined by the FSGM bit of SRGR2
	 * (even though we use the CS pin as a classic GPIO and not let McBSP drive it)
	 */
	p_mcbsp_regs->PCR.bit.FSXM = 1;

	/* Receive frame synchronization is supplied by the sample rate generator */
	p_mcbsp_regs->PCR.bit.FSRM = 1;

	/*
	 * Transmit frame-synchronization pulses = "Chip select" --> active low
	 * (even though we use the CS pin as a classic GPIO and not let McBSP drive it)
	 */
	p_mcbsp_regs->PCR.bit.FSXP = 1;

	/* Step 4. Enable the sample rate generator. */
	p_mcbsp_regs->SPCR2.bit.GRST = 1;

	/*
	 * After the sample rate generator is released from reset,
	 * wait two sample rate generator clock periods for the McBSP logic to stabilize
	 */
	wait(MCBSP_TWO_CLOCK_WAIT);

	/* Step 5. Enable the transmitter and receiver. */
	p_mcbsp_regs->SPCR1.bit.RRST = 1;
	p_mcbsp_regs->SPCR2.bit.XRST = 1;

	/*
	 * After the transmitter and receiver are released from reset,
	 * wait two sample rate generator clock periods for the McBSP logic to stabilize.
	 */
	wait(MCBSP_TWO_CLOCK_WAIT);

	/*
	 * Step 6. Enable the frame-synchronization logic of the sample rate generator.
	 * After the required data acquisition setup is done (DXR[1,2] is loaded with data),
	 * set FRST = 1 if the McBSP is the SPI master)
	 */
	p_mcbsp_regs->DXR1 = 0;
	p_mcbsp_regs->SPCR2.bit.FRST = 1;

}

4) Do you notice anything wrong with my init routine ?

Regards,
Clement

  • Clement,

    I cannot seem to find the example project you are working from. Can you share the link that you downloaded it from.

    Thanks,
    Mark
  • Hello Mark,

    It comes from the CD provided with the F28335 evaluation board. I don't know if it's available for download online.

    It's composed of Hardware, Libraries, Modules and Software.

    Inside Modules there are 19 different topics with powerpoint presentations, PDF docs and example code.
    On the powerpoint it is written "Texas Instruments Incorporated European Customer Training Centre University of Applied Sciences Zwickau"

    The Module 13 handles F2833x Multichannel Buffered Serial Port and provide example code to use the peripheral as SPI.

    I can upload the docs and code if needed.

    Clement

  • Hi Clement

    Have you tried looking at the code examples that comes with the TI Control Suite? (there is a mcbsp spi example)
     
    www.ti.com/.../controlsuite

  • Hi Mads,

    Yes of course but the Control Suite example for McBSP as SPI is only tested in loopback mode. It's not very useful compared with a real-world example.

    Clement
  • Hi Clement

    I found the example very useful.
    Just disable loopback, configure word length and SPI mode and you have a very simple and basic (almost real-world) example.
  • I just quickly looked at the TI code you provided.

    1) I guess you really need to clear the read flag else the second loop (waiting for received data ready) would return too early (before the data you wish to read is ready, due to old data). There is a bit delay from clocking out the last bit to receiving the last bit + the time for copying data internally to the DRR register. They use this time to clear the RRDY flag.

    But I do see a problem in how this is done (if the code where to be interrupted) etc.

    2) Now I do not know the example you are looking at, but they definitely needs to be set.

    3) -

    4) I just quickly compared your init function with an init function we use for the 28377, and yours seems OK to me.

    Perhaps you could share more code (simple project) for review?
  • Hi
    It's not possible for me to share more code (too glued with other code)

    in 1) you talk about a delay : is it something you have seen/measured or deduced from your experience with the peripheral ?

    I found a workaround for my 'read' function
    a) I read DRR
    b) I wait for XRDY to be ON
    c) I write 0 to TX
    d) I wait for RRDY
    e) I read DRR

    It's working reliably now.

    Clement
  • 1) SPI transmits (puts data on the bus) on the first clock edge and samples on the next clock edge. Thus I assumed XRDY would be done before RRDY.

    You work around looks fine.

    It is a rather large flash you have on the SPI bus :-)
    So if you are doing much of SPI communication, I would recommend using DMA (if possible) with the MCBSP - then you would also avoid any cumbersome and CPU consuming handling of XRDY and RRDY etc. And it would be possible to send and receive large chunks of data in one go.
  • Mads,

    Thank you for your input and recommendation.
    I'll see if I have the time to implement DMA mode later down the road.

    Data comes from the CAN (slow!) so we don't have to write large chunks at once.

    Clement