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.

TMS320F28388D: Extending FRAM through SPI

Part Number: TMS320F28388D
Other Parts Discussed in Thread: C2000WARE, SYSCONFIG,

Hello everyone,

I'm using spi_ex6_eeprom.c example to communicate with an external FRAM(MB85RS2MTY).

I edited the example in order to write 10 values into FRAM and trying to read back:

// Included Files
#include "driverlib.h"
//#include "device.h"
#include "board.h"


// Defines
#define FRAM_ADDR                   0x4F          
#define NUM_BYTES                   8


// SPI FRAM status
//#define MSG_STATUS_READY_M        0x0001 // FRAM is ready (not busy)
#define MSG_STATUS_WRITE_READY_M    0x0002 // FRAM
#define MSG_STATUS_BUSY             0xFFFF // FRAM is busy (internal write)


// Opcodes for the FRAM (8-bit)
#define RDSR                        0x05
#define READ                        0x03
#define WRITE                       0x02
#define WREN                        0x06
#define WRDI                        0x04
#define WRSR                        0x01


#define CS_LOW                      GPIO_writePin(CS_FRAM, 0)           
#define CS_HIGH                     GPIO_writePin(CS_FRAM, 1)           


// Function Prototypes
uint16_t readStatusRegister(uint16_t statusRegister);
void writeData(uint16_t address, uint16_t * data, uint16_t length, uint16_t txdly);
void readData(uint16_t address, uint16_t * data, uint16_t length,  uint16_t txdly);
void enableWrite(void);

#define DUMMY_DATA 0
#define NO_DELAY   0

uint16_t SPI_readByte_FRAM(uint32_t base, uint16_t address);
uint16_t SPI_read16bits_FRAM(uint32_t base, SPI_endianess endianness, uint16_t address);
uint32_t SPI_read24bits_FRAM(uint32_t base, SPI_endianess endianness, uint16_t address);
uint32_t SPI_read32bits_FRAM(uint32_t base, SPI_endianess endianness, uint16_t address);

void done(void);

uint32_t base = SPIC_BASE;                      

#define BUFFER_SIZE 10

// Main
void main(void)
{
    //uint16_t i;
    //uint16_t pass = 0;
    //uint16_t fail = 0;

    // Initialize device clock and peripherals
    Device_init();


    // Disable pin locks and enable internal pullups.
    Device_initGPIO();


    // Board initialization
    Board_init();

    uint16_t TXbuff[BUFFER_SIZE] = {1,1,1,1,1,1,1,1,1,1}; //sample data to send to flash
    //uint16_t TXbuff[BUFFER_SIZE] = {2,2,2,2,2,2,2,2,2,2}; //sample data to send to flash
    uint16_t RXbuff[BUFFER_SIZE];

    CS_HIGH;


    // Enable write on the FRAM
    enableWrite();

    // Wait until the FRAM is ready to write data
    //while((readStatusRegister(RDSR) & MSG_STATUS_WRITE_READY_M) == MSG_STATUS_WRITE_READY_M)
    while((readStatusRegister(RDSR) & MSG_STATUS_WRITE_READY_M) == 0)
    {
    }

    writeData(FRAM_ADDR, &TXbuff[0], BUFFER_SIZE, NO_DELAY);                      //Operazione di scrittura

    // Read from the FRAM
    readData(FRAM_ADDR, &RXbuff[0], BUFFER_SIZE,NO_DELAY);

}

uint16_t SPI_readByte_FRAM(uint32_t base, uint16_t address)
{
    uint16_t RXdata = 0;

    CS_LOW;

    // Send the READ opcode.
    SPI_transmitByte(base, READ);

    // Send FRAM address to write data
    SPI_transmit16Bits(base, address);

    // Receive data byte from FRAM by sending dummy byte
    RXdata = SPI_receiveByte(base, DUMMY_DATA);

    CS_HIGH;

    return(RXdata);
}

uint16_t SPI_read16bits_FRAM(uint32_t base, SPI_endianess endianness, uint16_t address)
{
    uint16_t RXdata = 0;

    CS_LOW;

    // Send the READ opcode.
    SPI_transmitByte(base, READ);

    // Send FRAM address to write data
    SPI_transmit16Bits(base, address);

    // Receive data 16-bit word from FRAM by sending two dummy bytes
    RXdata = SPI_receive16Bits(base, endianness, DUMMY_DATA, NO_DELAY);

    CS_HIGH;

    return RXdata;
}

uint32_t SPI_read24bits_FRAM(uint32_t base, SPI_endianess endianness, uint16_t address)
{
    uint32_t RXdata = 0;

    CS_LOW;

    // Send the READ opcode.
    SPI_transmitByte(base, READ);

    // Send FRAM address to write data
    SPI_transmit16Bits(base, address);

    // Receive data 24-bit word from FRAM by sending three dummy bytes
    RXdata = SPI_receive24Bits(base, endianness, DUMMY_DATA, NO_DELAY);

    CS_HIGH;

    return RXdata;
}

uint32_t SPI_read32bits_FRAM(uint32_t base, SPI_endianess endianness, uint16_t address)
{
    uint32_t RXdata = 0;

    CS_LOW;

    // Send the READ opcode.
    SPI_transmitByte(base, READ);

    // Send FRAM address to write data
    SPI_transmit16Bits(base, address);

    // Receive data 32-bit word from FRAM by sending four dummy bytes
    RXdata = SPI_receive32Bits(base, endianness, DUMMY_DATA, NO_DELAY);

    CS_HIGH;

    return RXdata;
}

// Function to send RDSR opcode and return the status of the FRAM
uint16_t readStatusRegister(uint16_t statusRegister)
{
    uint16_t temp;
    //uint32_t base = SPIA_BASE;
    uint32_t base = SPIC_BASE;

    // Pull chip select low.
    CS_LOW;

    // Send RDSR opcode
    SPI_transmitByte(base, statusRegister);

    // Send dummy data to read status register.
    temp = SPI_receiveByte(base, 0x0);

    // Pull chip select high.
    CS_HIGH;

    // Read the status from the receive buffer
    return(temp);
}


// Function to send the WREN opcode
void enableWrite(void)
{
    //uint32_t base = SPIA_BASE;
    uint32_t base = SPIC_BASE;
    // Pull chip select low.
    CS_LOW;

    // Send the WREN opcode.
    SPI_transmitByte(base, WREN);

    // Pull chip select high.
    CS_HIGH;
}

// Function to write data to the FRAM
// - address is the byte address of the FRAM
// - data is a pointer to an array of data being sent
// - length is the number of characters in the array to send
void writeData(uint16_t address, uint16_t *data, uint16_t length, uint16_t txdly)
{
    //uint32_t base = SPIA_BASE;
    uint32_t base = SPIC_BASE;

    // Pull chip select low.
    CS_LOW;                                     //in modo da dare al Chip Select lo stato attivo

    // Send the WRITE opcode.
    SPI_transmitByte(base, WRITE);

    // Send FRAM address to write data
    //SPI_transmit16Bits(base, address);
    SPI_transmit24Bits(base, address, NO_DELAY);

    // Send data to be programmed
    SPI_transmitNBytes(base, data, length, txdly);

    // Pull chip select high.
    CS_HIGH;                                    //in modo da dare al Chip Select lo stato standby
}

// Function to read data from the FRAM
// - address is the byte address of the FRAM
// - data is a pointer to an array of data being received
// - length is the number of characters in the array to receive
void readData(uint16_t address, uint16_t *data, uint16_t length, uint16_t txdly)
{
    //uint32_t base = SPIA_BASE;
    uint32_t base = SPIC_BASE;

    CS_LOW;

    // Send the READ opcode.
    SPI_transmitByte(base, READ);

    // Send FRAM address to write data
    //SPI_transmit16Bits(base, address);
    SPI_transmit24Bits(base, address, NO_DELAY);

    // Receive length number of bytes
    SPI_receiveNBytes(base, data, length, txdly);


    CS_HIGH;
}

// End of File


From the read buffer, it does seem that all the words are write/read correctly, but if I change the values to write, after reprogramming I don't see the correct value as before (the read values are all 0).

Case1: First flashing (uint16_t TXbuff[BUFFER_SIZE] = {2,2,2,2,2,2,2,2,2,2};) :

Case2: Second flashing, at the same address (uint16_t TXbuff[BUFFER_SIZE] = {1,1,1,1,1,1,1,1,1,1};)

what could be the problem?

Thanks and Regards.

Gianni

  • Hi Gianni,

    A few questions for you:

    • Are you scoping the SPI lines for this as well? Do you see correct behavior on all lines?
    • And to clarify, your issue is only on the second run when you see the RXbuff receive all 0s?
    • Could you also clarify the below statement: 
    I change the values to write

    Just wanted to understand if you are saying that you are only writing SPI data and not reading? It's a bit unclear to me what exactly you are changing and when. 

    Best Regards,

    Allison

  • Are you scoping the SPI lines for this as well? Do you see correct behavior on all lines?

    Yes, the scope of "SI" is always correct for both cases. The scope of "SO" is correct only at the first run (Case1, I see the RXbuff correctly), at the second run "SO" is always high(Case2, I don't see the RXbuff correctly).

    And to clarify, your issue is only on the second run when you see the RXbuff receive all 0s?

    Exactly, in Case2 I changed the TXbuff values and after re-flashing and debug I see RXbuff receive all 0s.

    Could you also clarify the below statement: 

    I change the values to write, I mean that the code is always the same (except for the TXbuff array).


    Regards,

    Gianni

  • Hi Gianni,

    Yes, the scope of "SI" is always correct for both cases. The scope of "SO" is correct only at the first run (Case1, I see the RXbuff correctly), at the second run "SO" is always high(Case2, I don't see the RXbuff correctly).

    So since F2838x is the controller, this tells me the transmitted data from F2838x to FRAM is always correct. The issue is with receiving back data (reading data from FRAM), is that correct? Stepping through/into your code, can you help pinpoint what line in the code do you see RXbuff fill with correct data the first time? 

    Please allow for another day for me to look at your project. Appreciate the patience!

    Best Regards,

    Allison

  • The issue is with receiving back data (reading data from FRAM), is that correct?

    Exactly.

    Stepping through/into your code, can you help pinpoint what line in the code do you see RXbuff fill with correct data the first time? 

    I see RXbuff fill with correct data the first time after this line: readData(FRAM_ADDR, &RXbuff[0], BUFFER_SIZE,NO_DELAY);

    Thanks and Regards.

    Gianni

  • Hi Gianni,

    Can you set a breakpoint on that readData() line and then use the "Step Into" button and then "Step Over" buttons to go through the functions within readData() as well as those within readData() such as SPI_transmitByte()/SPI_pollingNonFIFOTransaction(), SPI_transmit24bits()/SPI_pollingFIFOTransaction(), and SPI_receiveNBytes()/SPI_pollingFIFOTransaction? If you do so while watching the buffers, SPI RXEMU and/or scope lines, do you see the expected behavior/data?

    The RXbuff should be filled specifically when you call the SPI_receiveNBytes() function within the readData(). SPI_receiveNBytes() uses the SPI_pollingFIFOTransaction() defined in spi.c. When stepping through within this function, do you see expected behavior/data or any errors appear?

    If I understood your earlier comment, all you are changing in between the first and second run is the TXbuff values from 1's to 2's? Or are you changing the op code you are sending to FRAM?

    From my first pass through your code, it seems like it should be ok. I am not familiar with the FRAM device functionality, but if you are changing what you are sending to FRAM, perhaps that is affecting what is transmitted back in the wrong way - let me know your thoughts on that and if you are able to step through your code as I mentioned. 

    Best Regards,

    Allison

  • Can you set a breakpoint on that readData() line and then use the "Step Into" button and then "Step Over" buttons to go through the functions within readData() as well as those within readData() such as SPI_transmitByte()/SPI_pollingNonFIFOTransaction(), SPI_transmit24bits()/SPI_pollingFIFOTransaction(), and SPI_receiveNBytes()/SPI_pollingFIFOTransaction? If you do so while watching the buffers, SPI RXEMU and/or scope lines, do you see the expected behavior/data?

    I tried using this approach but if I click on "Step Into" inside ReadData() I'm not able to watch values of RXbuff (I see "identifier not found" for each function):

    SPI_transmitByte(base, READ);

    SPI_transmit24Bits(base, address, NO_DELAY);

    SPI_receiveNBytes(base, data, length, txdly);

    The RXbuff should be filled specifically when you call the SPI_receiveNBytes() function within the readData(). SPI_receiveNBytes() uses the SPI_pollingFIFOTransaction() defined in spi.c. When stepping through within this function, do you see expected behavior/data or any errors appear?

    At Case1(first run), by clicking "Step Over" on SPI_receiveNBytes() RXbuff is filled with the correct values.

    At Case2(second run), by clicking "Step Over" on SPI_receiveNBytes() RXbuff is filled but with the uncorrect values.

    If I understood your earlier comment, all you are changing in between the first and second run is the TXbuff values from 1's to 2's? Or are you changing the op code you are sending to FRAM?

    Exactly, I'm changing only TXbuff values from 1's to 2's, the address "FRAM_ADDR" is always the same.

    if you are changing what you are sending to FRAM, perhaps that is affecting what is transmitted back in the wrong way - let me know your thoughts on that and if you are able to step through your code as I mentioned. 

    I tried an other case where in the first run TXbuff was {2,2,2,2,2,2,2,2,2, 2} and in the second run was {2,2,2,1,2,2,1,2,2,2}, the result is the following:

    TXbuff {2,2,2,2,2,2,2,2,2,2}  -----> RXbuff {2,2,2,2,2,2,2,2,2,2}   ------>correct values.

    TXbuff {2,2,2,1,2,2,1,2,2,2}  -----> RXbuff {2,2,2,0,2,2,0,2,2,2}   ------>uncorrect values.

    So, in the second run, as you can see, the values that i changed on TXbuff becomes 0 in RXbuff (They should be 1).

    Thanks for the attention and support,

    Gianni

  • Hi Gianni,

    Allison is currently out of office. You can expect a response from her on Monday 4/8. Sorry for any inconvenience.

    Best Regards,

    Delaney

  • Hi Gianni,

    I tried using this approach but if I click on "Step Into" inside ReadData() I'm not able to watch values of RXbuff (I see "identifier not found" for each function):

    If this happens, you should be able to use the "locate file" button that pops up and navigate to the driverlib folder for the device to allow for CCS to find the file path and pull it up. Alternatively, you can go into your C2000Ware folder to {C2000Ware}\driverlib\f2838x\driverlib\spi.c or spi.h to search for and view exactly what is happening in those functions if you'd like.

    I tried an other case where in the first run TXbuff was {2,2,2,2,2,2,2,2,2, 2} and in the second run was {2,2,2,1,2,2,1,2,2,2}, the result is the following:

    TXbuff {2,2,2,2,2,2,2,2,2,2}  -----> RXbuff {2,2,2,2,2,2,2,2,2,2}   ------>correct values.

    TXbuff {2,2,2,1,2,2,1,2,2,2}  -----> RXbuff {2,2,2,0,2,2,0,2,2,2}   ------>uncorrect values.

    Based on this other trial you ran, there seems to be an error in communication that may be caused by an incorrect configuration from the first run. Please allow for another day for me to look into this a bit further. Thanks for the patience!

    Best Regards,

    Allison

  • Hi Gianni,

    Just letting you know I haven't had much tangible progress on this at the moment, but let me also reach out to another colleague and let you know our findings. Feel free to update if you have any other tests/conclusions in the mean time. 

    Best Regards,

    Allison

  • Hi Gianni,

    Thanks for the patience. Which C2000Ware version are you using? The general code looks ok, but there was recently a bug within particular SPI DriverLib functions (the bug is that the character length is re-configured within some functions, and reconfiguring character length outside of SPI initialization was found to cause a small glitch in the SPICLK before actual SPI clock pulses should occur). This incorrect behavior could be corrupting the SPI communication. Fortunately, this has already been fixed in the latest version of C2000Ware, so please be sure you download version 5.02.00.00 (https://www.ti.com/tool/download/C2000WARE/5.02.00.00) and check that your project/code uses this newer version of DriverLib. Let me know if you have any trouble here!

    Best Regards,

    Allison

  • Which C2000Ware version are you using?

    I was using "C2000Ware_5_01_00_00".

    so please be sure you download version 5.02.00.00 (https://www.ti.com/tool/download/C2000WARE/5.02.00.00) and check that your project/code uses this newer version of DriverLib. Let me know if you have any trouble here!

    Now I installed the last version "C2000Ware_5_02_00_00", I managed the project/code to use the newer version of DriverLib.

    Re-running the code, the issue is still present.

    Thanks for the support.

    Regards,

    Gianni

  • Hi Gianni,

    Thanks for the response. Another thing I'd like to see is if you can try instead transmitting numbers other than 2 and 1 in your TXbuff. For example, could you try 3's and 4's? Or other numbers like 10 and 11? Would like to see if this reveals more information about the behavior. 

    Could you also scope all 4 SPI lines and show a transmission with all these lines so we can double check the behavior is as expected for all?

    Best Regards,

    Allison

  • Hello Allison,

    I tryed writing different numbers, I noticed that using different numbers (e.g. 10 or more) RXbuff receive all 0s at the first run.

    I'm using the function "SPI_transmit24Bits()" to send FRAM address to write data, because 16bits + 6 (invalid bits).
    If I put "SPI_transmit16Bits()" instead of "SPI_transmit24Bits()" I see the first elements of array RXbuff equal to 255, is it correct to put SPI_transmit24Bits() right?

    From datasheet of FRAM: The READ command reads FRAM memory cell array data. Arbitrary 16 bits address and op-code of READ are input to SI. The 6-bit upper address bit is invalid. Then, 8-cycle clock is input to SCK. SO is output synchronously to the falling edge of SCK.

    Regards,

    Gianni

  • Hi Gianni,

    The SPI_transmit16bits function uses a nonFIFO method of writing 16 bits from SPI (in one transmission) whereas the the SPI_transmit24bits uses FIFO (technicallt 2 separate transmissions of 16 bits and then 6 bits). This is because C2000 SPI module is optimized for 16-bit transactions, so if you want to transmit more than 16, you would have to use more than one level in the FIFO (or more than one transmission in nonFIFO).

    What is the device number of the FRAM you are using? I'm wondering if there is some format that the FRAM is not expecting that is causing this. You confirmed that the correct clock mode is being used here, right? What is the FRAM device expecting in terms of clock phase and polarity? 

    Are you able to share oscilloscope/analyzer images of the 4 lines? That would also help us to visualize this.

    Best Regards,

    Allison

  • Hello, sorry for the delay in response.

    What is the device number of the FRAM you are using? I'm wondering if there is some format that the FRAM is not expecting that is causing this. You confirmed that the correct clock mode is being used here, right? What is the FRAM device expecting in terms of clock phase and polarity?

    I'm using the FRAM MB85RS2MTY, it corresponds to the SPI mode 0 (CPOL  0, CPHA  0) , and SPI mode 3 (CPOL  1, CPHA  1).

    In Sysconfig I setted "Transfer Protocol" in Mode 0, Polarity 0, phase 0 and the use of FIFO is disabled.

    Are you able to share oscilloscope/analyzer images of the 4 lines? That would also help us to visualize this.

    This is an example of wrong transmit at second run:

    WRITE:

    READ:

    The transmission is ok, because the data is present in SI signal.

    So, in conclusion, the problem seems to be in readDATA, but I don't understand the cause.

  • Hi Gianni,

    Please note that different manufacturers define SPI clock modes differently. This looks to be the case here:

    • MB85RS2MTY SPI Mode 0 = F2838x Mode 1 (Rising Edge with Delay; POL = 0, PHS = 1)
      • Clock line is idle low; Data is received/latched on the rising edge of the clock and transmitted on the falling edge.
    • MB85RS2MTY SPI Mode 3 = F2838x Mode 2 (Falling Edge without Delay; POL = 1, PHS = 0)
      • Clock line is idle high; Data is received/latched on the rising edge of the clock and transmitted on the falling edge.

    From MB85RS2MTY:

    From F2838x:

    Please be sure both devices are expected the same receive/transmit format by using equivalent clocking schemes.

    Best Regards,

    Allison

  • Hi Allison,

    Thanks for the osservation. Now I setted "F2838x Mode 1" but nothing changed, the issue is still present.

     

     

  • Hi Gianni,

    I know you mentioned a while back that you selected to send the address as 24 bits due to some invalid 6 bits- could you explain a bit more why you chose to do this and the context of it? Does the behavior still change in the same manner as before when you instead just send the 16 bits?

    Best Regards,

    Allison

  • Hello Allison, 

    The issue is fixed and the code was correct. I tried the example with the TMS320F28388D controlCARD and it works correctly.

    At this point, the issue was due to an uncorrect connection of the WP Write Protect pin present in the custom board.

    Really thank you for the support.

    Best Regards,

    Gianni.

  • Hi Gianni,

    So glad to hear the issue is resolved! Always happy to support - feel free to open another thread if you run into further issues Slight smile

    Best Regards,

    Allison