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.

TMS320F28379S: SPI Issue - 8 bit character mode

Part Number: TMS320F28379S

Hi,

I am using TMS320F28379s C2000 series micro controller (Master) to interface SRAM 23LCV1024 (Slave) via SPI. I have configured the SPI in the FIFO mode as per the example code provided in the control suite, SPI Configuration are as follows controller is in master mode, Clock polarity to rising, clock phase is normal (0), data character length is 8 bit and bit rate is 500KHz have been configured.

 I’m trying to write the 1 byte data - 111 (0x6F) to the NVRAM and to read the same from the NVRAM IC. But I’m not getting the data as expected 111 (0x6F) instead I’m getting  as 255 (0xFF) always…! while checking the pulses of the SPI pins I’m getting the data from the Slave device(in MISO pin)

But the responded data is not fetched by MCU.. while checking in oscilloscope the below results were observed in below case 1 the pulse pattern found correct but in MCU read SPI memory 0xff is found always.

I have attached the Pulse pattern in the attached document & SPI Code for reference.

Thanks

Rajamurugan

#define CPU_FREQ 200			// CPU_Freq is 200MHz

#define SPI_CLK_in_KHz  500     // 2500 -> 2.5 MHz // 1000 -> 1MHz (Now its for the 500KHz)
#define LSPCLK_in_KHz   50000   // (200 MHz / 4) = 50 MHz
#define SPI_BRR         (LSPCLK_in_KHz / SPI_CLK_in_KHz) - 1

#define RAM_INS_READ    0x03    //Read data from memory array beginning at selected address
#define RAM_INS_WRITE   0x02    //Write data to memory array beginning at selected address

#define RAM_INS_RDMR    0x05    //Read Mode Register
#define RAM_INS_WRMR    0x01    //Write Mode Register

unsigned char write_array[20];
unsigned char Read_array[20];
unsigned char Read_NVRAM_data = 0;
unsigned int _10ms_timer_counter = 0;

__interrupt void cpu_timer0_isr(void)	// 50us timer Interrrupt
void chip_select_NVRAM1(void);
void chip_deselect_NVRAM1(void);
void NVRAM1_set_mode(unsigned char mode);
void Write_to_NVRAM(unsigned char Write_data, unsigned long int Write_address);
unsigned char Read_From_NVRAM(unsigned long int Read_address);
void ram_write_data(unsigned long int write_address, unsigned char *write_buffer, unsigned int write_buffer_size);
void read_data(unsigned long int read_address, unsigned char *read_buffer, unsigned int read_buffer_size);

void Setup_GPIO()
{
    EALLOW;    // For enabling the access for the protected registers
// SPI
    GpioCtrlRegs.GPAPUD.bit.GPIO24 = 0; //  Enable internal pull-up for the selected SPI pin - MOSI
    GpioCtrlRegs.GPAPUD.bit.GPIO25 = 0; //  Enable internal pull-up for the selected SPI pin - MISO
    GpioCtrlRegs.GPAPUD.bit.GPIO26 = 0; //  Enable internal pull-up for the selected SPI pin - CLK
    GpioCtrlRegs.GPAPUD.bit.GPIO27 = 0; //  Enable internal pull-up for the selected SPI pin - EN

    GpioCtrlRegs.GPAQSEL2.bit.GPIO24 = 3; // Set qualification for the selected SPI pin - MOSI
    GpioCtrlRegs.GPAQSEL2.bit.GPIO25 = 3; // Set qualification for the selected SPIpin - MISO
    GpioCtrlRegs.GPAQSEL2.bit.GPIO26 = 3; // Set qualification for the selected SPIpin - CLK
    GpioCtrlRegs.GPAQSEL2.bit.GPIO27 = 3; // Set qualification for the selected SPIpin - EN

    GpioCtrlRegs.GPAGMUX2.bit.GPIO24 = 1; // Configure GPIO24 as SPI pin - MOSI GMUX selection
    GpioCtrlRegs.GPAMUX2.bit.GPIO24 = 2;  // GPIO24 is MOSI
    GpioCtrlRegs.GPAGMUX2.bit.GPIO25 = 1; // Configure GPIO25 as SPI pin - MISO GMUX selection
    GpioCtrlRegs.GPAMUX2.bit.GPIO25 = 2;  // GPIO25 is MISO
    GpioCtrlRegs.GPAGMUX2.bit.GPIO26 = 1; // Configure GPIO26 as SPI_CLK- GMUX selection
    GpioCtrlRegs.GPAMUX2.bit.GPIO26 = 2;  // GPIO26 is CLK
    GpioCtrlRegs.GPAGMUX2.bit.GPIO27 = 1; // Configure GPIO27 as SPI_EN- GMUX selection
    GpioCtrlRegs.GPAMUX2.bit.GPIO27 = 2;  // GPIO27 is EN

//    GpioCtrlRegs.GPAMUX2.bit.GPIO27 = 0;  // GPIO27 is EN
//    GpioCtrlRegs.GPADIR.bit.GPIO27 = 1;   // Making the GPIO27 as the Digital Output

    EDIS;    // For disabling the access for the protected registers

}

void SetupTimers()
{
    ConfigCpuTimer(&CpuTimer0, CPU_FREQ, 50); //Timer0 is configured to interrupt on every 50 µ seconds with the time base of 200MHz
    CpuTimer0Regs.TCR.all = 0x4000; // Use write-only instruction to set TSS bit = 0 & TIE = 1 (Start the timer & Timer interrupt is enabled)
}


void SetupSPI(void)
{

    SpibRegs.SPIFFTX.all = 0xE040; // FIFO Transmit register 1.Interrupt clear 2.Release transmit FIFO from reset 3.Enhancement enable 4.SPI FIFO resume transmit or receive.
    SpibRegs.SPIFFRX.all = 0x2044; // SPI FIFO Receive Register // To clear receive FIFO interrupt ,re enable receive FIFO operation.
    SpibRegs.SPIFFCT.all = 0x0000; // SPI FIFO Control Register // delayed transfer.

    SpibRegs.SPICCR.bit.SPISWRESET  = 0;    // Set reset low before configuration changes
    SpibRegs.SPICCR.bit.CLKPOLARITY = 1;    // Clock polarity selection (0 == rising, 1 == falling)
    SpibRegs.SPICCR.bit.HS_MODE     = 0;    // SPI High Speed mode Enable Bit (0 == Disable, 1 == Enable)
    SpibRegs.SPICCR.bit.SPILBK      = 0;    // SPI Loop back Mode Select (0 == Disable, 1 == Enable)
    SpibRegs.SPICCR.bit.SPICHAR     = (8-1);// Character length control bit - 8-bit

    SpibRegs.SPICTL.bit.OVERRUNINTENA = 0;  // Overrun Interrupt Enable bit (0 == Disable, 1 == Enable)
    SpibRegs.SPICTL.bit.CLK_PHASE     = 0;  // SPI CLOCK PHASE SELECT (0 == normal, 1 == delayed)
    SpibRegs.SPICTL.bit.MASTER_SLAVE  = 1;  // Enable Master mode (0 == slave, 1 == master)
    SpibRegs.SPICTL.bit.TALK          = 1;  // Enable Transmission (Talk)
    SpibRegs.SPICTL.bit.SPIINTENA     = 0;  // SPI interrupts are disabled
    SpibRegs.SPIBRR.bit.SPI_BIT_RATE  = SPI_BRR; // Set the baud rate

    SpibRegs.SPIPRI.bit.FREE = 1;           // Set FREE bit // Halting on a breakpoint will not halt the SPI

    SpibRegs.SPICCR.bit.SPISWRESET = 1;     // Release the SPI from reset WHEN the value = 1 SPI ready to transmit and receive
    NVRAM1_set_mode(RAM_MODE_BYTE);
//    NVRAM1_set_mode(RAM_MODE_SEQUENTIAL);
}

unsigned char rdata = 0;

unsigned char spi_xmit(unsigned char sdata)
{
//    while (SpibRegs.SPIFFTX.bit.TXFFST != 0);
    SpibRegs.SPITXBUF = sdata<<8;  // SPI Serial Output Buffer Register -SPITXBUF

    while (SpibRegs.SPIFFRX.bit.RXFFST == 0);
    rdata = SpibRegs.SPIRXBUF;  // SPI Serial Input Buffer Register

    return rdata;
}

void SetupInterrupt(void) // Interrupts that are used in this example are re-mapped to ISR functions found within this file.
{
    PieCtrlRegs.PIECTRL.bit.ENPIE = 1;   // Enable the PIE block
	
    EALLOW;         // This is needed to write to EALLOW protected registers
    PieVectTable.TIMER0_INT = &cpu_timer0_isr; // Interrupts that are used in this example are re-mapped to ISR functions found within this file
    EDIS;           // This is needed to disable write to EALLOW protected registers

    PieCtrlRegs.PIEIER1.bit.INTx7 = 1; // Enable TINT0 in the PIE: Group 1 interrupt 7

    IER |= M_INT1;  // Enable CPU int1 which is connected to CPU-Timer 0

    EINT;    // Enable Global interrupt INTM
    ERTM;    // Enable Global real time interrupt DBGM
}

void main(void)
{
    InitSysCtrl();      // For Initialize PLL,Peripheral clocks & Disable watch dog timer

    DINT;               // Disable all CPU interrupts and initialize PIE vector table interrupts

    InitPieCtrl();      // Initialize the PieControl registers
    IER = 0x0000;       // Disable All CPU interrupts
    IFR = 0x0000;       // Clear All interrupt Flags
    InitPieVectTable(); // Initialize the PIE vector table with pointers to the shell Interrupt Service Routines (ISR).

    InitCpuTimers();    // Initialization of timer module

    InitGpio();

    Setup_GPIO();       // Set the GPIOs configuration registers
    SetupTimers();      // Set the Timer configuration registers
    SetupSPI();         // Set the SPI configuration registers
    SetupInterrupt();   // Set the common interrupt Enable Function

    Write_to_NVRAM(111, 5000); // Write the data to NVRAM Using Function Call - (Data, Address)

//    unsigned int i = 0;
//    for (i = 0; i < 10; i++)
//    {
//        write_array[i] = i;
//    }
//
//    ram_write_data(123,write_array,10);

    while (1)
    {

    }
}


//******************************************************************************************************
//     Function : chip_select_NVRAM1()
//     Purpose  : Sets the SS pin to the low state in order to enable SPI mode
//******************************************************************************************************

void chip_select_NVRAM1(void)
{
    GpioDataRegs.GPACLEAR.bit.GPIO27 = 1;
}

//******************************************************************************************************
//       Function : chip_deselect_NVRAM1()
//       Purpose  : Sets the SS pin to the high state in order to disable SPI mode
//******************************************************************************************************

void chip_deselect_NVRAM1(void)
{
    GpioDataRegs.GPASET.bit.GPIO27 = 1;
}

//******************************************************************************************************
//       Function : NVRAM1_send_address()
//       Purpose  : sending address in a specified format as mentioned in datasheet
//******************************************************************************************************

void NVRAM1_send_address(unsigned long int address)
{
    spi_xmit((address >> 16) & 0xFF);
    spi_xmit((address >> 8) & 0xFF);
    spi_xmit((address) & 0xFF);
}

//**********************************************************************************************************************************************
//       Function : NVRAM1_set_mode()
//       Purpose  : Send the address to the mode register in order to Set the memory operation mode (byte, page, sequential <default>)
//**********************************************************************************************************************************************

void NVRAM1_set_mode(unsigned char mode)
{
    chip_select_NVRAM1();
    spi_xmit(RAM_INS_WRMR);
    spi_xmit(mode);
    chip_deselect_NVRAM1();
}

//************************************************************************************************************************
//       Function : NVRAM1_read_mode()
//       Purpose  : To know which mode is selected for the write operation among byte, page, sequential operations
//************************************************************************************************************************

unsigned char NVRAM1_read_mode(void)
{
    unsigned char data;

    chip_select_NVRAM1();
    spi_xmit(RAM_INS_RDMR);
    data = spi_xmit(0);
    chip_deselect_NVRAM1();

    return data;
}

void Write_to_NVRAM(unsigned char Write_data, unsigned long int Write_address)
{

    chip_select_NVRAM1();
    spi_xmit(RAM_INS_WRITE);
    NVRAM1_send_address(Write_address);
    spi_xmit(Write_data);
    chip_deselect_NVRAM1();

}

//************************************************************************************************************************
//       Function : ram_write_data()
//       Purpose  : To write data into the SRAM in page wise
//************************************************************************************************************************

void ram_write_data(unsigned long int write_address, unsigned char *write_buffer, unsigned int write_buffer_size)
{
    unsigned long int write_page;

    chip_select_NVRAM1();
    spi_xmit(RAM_INS_WRITE);
    NVRAM1_send_address(write_address);
    for (write_page = 0; write_page < write_buffer_size; ++write_page)
    {
        spi_xmit(*(write_buffer + write_page));
    }
    chip_deselect_NVRAM1();
}


unsigned char Read_From_NVRAM(unsigned long int Read_address)
{
    unsigned char Read_data;

    chip_select_NVRAM1();
    spi_xmit(RAM_INS_READ);
    spi_xmit(Read_address >> 16);
    spi_xmit(Read_address >> 8);
    spi_xmit(Read_address);
    Read_data = spi_xmit(0x00);
    chip_deselect_NVRAM1();

    return Read_data;
}

//************************************************************************************************************************
//       Function : read_data()
//       Purpose  : To read a data from SRAM page wise
//************************************************************************************************************************

void read_data(unsigned long int read_address, unsigned char *read_buffer, unsigned int read_buffer_size)
{
    chip_select_NVRAM1();
    spi_xmit(RAM_INS_READ);
    NVRAM1_send_address(read_address);
    while (read_buffer_size)
    {
        *read_buffer = spi_xmit(0);
        ++read_buffer;
        --read_buffer_size;
    }
    chip_deselect_NVRAM1();
}


__interrupt void cpu_timer0_isr(void)	// 50us timer Interrrupt
{
    _10ms_timer_counter++;

    if (_10ms_timer_counter >= 200)   // For 10milli second
    {
        _10ms_timer_counter = 0;
        Read_NVRAM_data = Read_From_NVRAM(5000);	// Read the data from NVRAM using the function call - (Address)
//        read_data(123,Read_array,10);
        GpioDataRegs.GPCTOGGLE.bit.GPIO88 = 1; 		// For Toggling the MCU_STS_LED GPIO
    }

    PieCtrlRegs.PIEACK.all |= PIEACK_GROUP1;    	// Acknowledge this interrupt to receive more interrupts from group 1
    EDIS;    // The CPU acknowledges the interrupt.
}
         SPI_Query.docx

  • Hello Rajamurugan,

    I took a look at your code and attachment. Nothing obvious pops out at me. I would recommend a couple of things:

    1. Verify the clock polarity and phase configuration matches the expected 23LCV1024 SPI bus timings. Do not assume the SPI mode definition given in the 23LCV1024 data sheet matches the SPI mode definition given the C2000 data manual.

    2. Try enabling loop-back mode in the SPI to see if you can get any correct data from the SPIRXBUF register. Your pinmux configuration looks ok to me, so it's a bit of a puzzle as to why you always get 0xFF from the SPIRXBUF register.

    Regarding your specific questions:

    >> When receiving the data without checking the RX Fifo status buffer  (SpibRegs.SPIFFRX.bit.RXFFST) it shows the values as 7 , 14 …etc & sometimes the Overrun flag bit (SpibRegs.SPISTS.bit.OVERRUN_FLAG)  is also getting  High(1).

    You have to check the RXFFST first to be sure there is actual data in the FIFO. You have the correct sequence:

        SpibRegs.SPITXBUF = sdata<<8;  // SPI Serial Output Buffer Register -SPITXBUF
    
        while (SpibRegs.SPIFFRX.bit.RXFFST == 0);
        rdata = SpibRegs.SPIRXBUF;  // SPI Serial Input Buffer Register

    >> SPI Pulses When RX FIFO status (SpibRegs.SPIFFRX.bit.RXFFST) is Checked

    Receive data when 1 or more word is available. 

    1. As per the above configuration the clock is not continuous ?
    2. Master is sending the data when there is no Clock (CLK) pulse available ?
    3. I’m not getting any data on the MISO pin (from the slave device)

    The clock is not continuous because there will be a small time during which the SPITXBUF is empty and the CPU writes new data since spi_xmit() only sends one character and you have to call it multiple times. You could change your spi_xmit() function to leverage the SPI TX FIFO fully. In other words, change spi_xmit() to accept an array of characters and write all characters to SPITXBUF at the same time (checking that TXFFST doesn't overflow the FIFO size of course). 

    I don't see the master sending data when there is no clock. The clock is simply stopped and the MOSI pin is holding the last value transmitted.

    Not sure why the slave device doesn't respond with data in this case. Check the slave datasheet to see if maybe there is a timeout feature when the SPICLK stops for some time. 

  • Hi Gus Martinez,

    Thanks for the reply.....but my issue is not resolved......I've attached the results & my questions in the below document.

    Regards

    Rajamurugan 

    5164.SPI_1.docx

  • Rajamurugan,

    When you write a character to the SPITXBUF register, the character will be transmitted, and simultaneously a character will be received. So you always have to issue a dummy read from SPIRXBUF to clear this data. If you don't clear this data, the data will stay in the RX FIFO and the RXFFST will increment by 1. I believe the issues you are seeing is because you do not have this dummy read from the RX FIFO.

    Before, in your spi_xmit() function you were properly reading the SPIRXBUF after every write to the SPITXBUF. However, since you were polling for data to arrive in SPIRXBUF, the CPU was forced to wait for the SPI transfer to complete.

    Here is a suggestion. In the function below, there are a total of 5 writes to SPITXBUF (if I count these right). So you need 5 reads from SPIRXBUF.

    void Write_to_NVRAM(unsigned char Write_data, unsigned long int Write_address)
    {
    
        chip_select_NVRAM1();
        spi_xmit(RAM_INS_WRITE);
        NVRAM1_send_address(Write_address);
        spi_xmit(Write_data);
        chip_deselect_NVRAM1();
    
    }

    You can do this as:

    • Write to SPITXBUF
    • Wait while RXFFST == 0;
    • Dummy read SPIRXBUF
    • repeat 4 more times

    Downside is that you will have breaks in the SPI CLK since the SPI TX FIFO will always be empty at the end of the character transmission. By the time the RXFFST = 1, the CPU is too late to load a new character to the SPI TX FIFO to keep the SPI CLK going.

    Or you can do this as:

    • Write to SPITXBUF
    • Write to SPITXBUF
    • Write to SPITXBUF
    • Write to SPITXBUF
    • Write to SPITXBUF
    • Wait while RXFFST < 5;
    • Dummy read SPIRXBUF x 5

    In this case the SPITXBUF is always loaded with data and the SPI CLK will be continuous. 

    Although, I am a little surprised that a continuous SPI CLK is required at all. I do not see anything in the 23LCV1024 datasheet SPI timings which indicates this is a requirement. Your original implementation of spi_xmit() should have been perfectly acceptable. Unless you goal was to increase data throughput by eliminating dead time between characters? 

  • Hai ,

    Thanks for the Support...Our Issue has been solved now i'm able to read & write the data from the SRAM (23LCV1024) 

    Following updates I've made in  my code

    1. Changed the default SPI EN pin to GPIO ...which i made HIGH and LOW manually to avoid the toggle EN pin in between the data.

    2. Have checked both the RX Fifo Status (RXFFST)  and the TX Fifo status (TXFFST) .

    And i've a one final question : Is there any other default method for controlling the EN pin by using SPI registers (without GPIO control) for continous ON ?

    Regards,

    RajaMurugan

  • Changed the default SPI EN pin to GPIO ...which i made HIGH and LOW manually to avoid the toggle EN pin in between the data.

    Ah! I can't believe I didn't see the CS pin going high in your scope plots! That explains a lot. 

    And i've a one final question : Is there any other default method for controlling the EN pin by using SPI registers (without GPIO control) for continous ON ?

    The only way it to ensure the SPI TX FIFO always has data.