Skip to main content
dave4
Associate II
January 15, 2010
Question

Communicating with an EEPROM over SPI

  • January 15, 2010
  • 12 replies
  • 3272 views
Posted on January 15, 2010 at 09:02

Communicating with an EEPROM over SPI

    This topic has been closed for replies.

    12 replies

    jj_it
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 13:37

    There is a similar ''failed MISO'' post just a few posts down. Indeed the SPI-NSS signal is most always ''prime suspect.''

    My past recommendation (which worked) was to temporarily ''break'' the connection between STM's NSS and CS of eeprom. Again temporarily tie the CS of eeprom to ground - see if then MISO behaves per expectation...

    chikos33
    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 13:37

    Hi Dave,

    It semms strange to me: why do you set NSS output function if you are handling the NSS by software? (GPIO_ResetBits(GPIOA, GPIO_Pin_4);) I suggest you either remove the NSS SPI_SSOutputCmd or the GPIO management (It would be safer to start with NSS managed by software).

    Are you sure you configured correctly the SPI MISO pin PA6 (Alternate function Push Pull or Input floating)?

    This EEPROM supports (CPOL = 0, CPHA = 0) and (CPOL = 1, CPHA = 1) so may be you can try the second configuartion.

    Note: RxNE interrupt will be generated in all cases (even when no data are received on the MISO line) because it is only relative to the clock signal.

    Now, as I've seen in the EEPROM datasheet, that the read sequence seems a little different from yours, they state:

    // Enable Chip select

    SPI_I2S_SendData(SPI1, EEPROM_READ); // send data read instruction

    SPI_I2S_SendData(SPI1, EEPROM_Address1); // send the MSB of the address

    SPI_I2S_SendData(SPI1, EEPROM_Address2); // send the LSB of the address

    SPI_I2S_SendData(SPI1, 0xff); // send dummy data

    while (!SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE)); // Wait for data to be received

    buffer[n] = SPI_I2S_ReceiveData(SPI1); // Or you can do it through interrupt of course.

    SPI_I2S_SendData(SPI1, 0xff); // Send dummy data

    while (!SPI_GetFlagStatus(SPI1, SPI_FLAG_RXNE)); // Wait for data to be received

    buffer[n + 1] = SPI_I2S_ReceiveData(SPI1); // ....

    ......

    And you continue sending dummy data and receiving data from EEPROM till the end of buffer

    That's what I understood from the datasheet, please tell me if I'm wrong?

    Thanks and Good luck!

    dave4
    dave4Author
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 13:37

    Hello,

    I am trying to communicate with an ST M95160 EEPROM device using an STM32F101R8T6, and while I can send instructions and data to the device, I cannot get the EEPROM to reply to my commands

    Here is my configuration for the SPI peripheral

    Code:

    void SPI_Configuration(void)

    {

    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // Configure as Full Duplex

    SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // Configure as SPI Master

    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // Use 8bit data frames

    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;

    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;

    SPI_InitStructure.SPI_NSS = SPI_NSS_Hard; // Use hardware slave select control

    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; // Set data rate APB/2 = (8MHz/2 = 4MHz)

    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // Send / receive data MSB first

    SPI_InitStructure.SPI_CRCPolynomial = 7;

    SPI_Init(SPI1, &SPI_InitStructure); // Configure SPI1

    SPI_I2S_ITConfig(SPI1, SPI_I2S_IT_RXNE, ENABLE); // Enable Rx not empty interrupt

    SPI_SSOutputCmd(SPI1, ENABLE); // Enable slave select output

    SPI_Cmd(SPI1, ENABLE); // Enable SPI1

    }

    and this is what I am sending (the commands are mapped with some #defines)

    Code:

    GPIO_ResetBits(GPIOA, GPIO_Pin_4);

    SPI_I2S_SendData(SPI1, EEPROM_WRITE_EN);

    SPI_I2S_SendData(SPI1, EEPROM_WRITE);

    SPI_I2S_SendData(SPI1, 0xFF);

    SPI_I2S_SendData(SPI1, 0xCC);

    SPI_I2S_SendData(SPI1, EEPROM_WRITE_DIS);

    SPI_I2S_SendData(SPI1, EEPROM_WRITE_EN);

    SPI_I2S_SendData(SPI1, EEPROM_WRITE);

    SPI_I2S_SendData(SPI1, EEPROM_READ);

    SPI_I2S_SendData(SPI1, 0xFF);

    SPI_I2S_SendData(SPI1, EEPROM_WRITE_DIS);

    GPIO_SetBits(GPIOA, GPIO_Pin_4);

    I have noticed that the RXNE interrupt fires during the sendData commands, where I have a routine to fill a buffer with what is received

    I have attached a scope trace showing what I am seeing (green = NSS, purple = SCK, blue = MOSI pin, yellow = MISO pin)

    I think that I should be seeing data coming back on the MISO line, why would that not be the case?

    Regards

    Dave

    chikos33
    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 13:37

    Hi dave,

    - In this case, remove the SPI_SSOutputCmd and NSS hardware management feature and use only the GPIO set/reset to have a clean code.

    - CPOL=0,CPHA=0 is the equivalent of SPI_CPOL_Low and SPI_CPHA_1Edge

    CPOL=1,CPHA=1 is the equivalent of SPI_CPOL_High and SPI_CPHA_2Edge

    - As jj.sprague said, it is often a NSS issue, so check you are setting the levels at the right time (I think NSS should rise again just after the write command is finished ? ....).

    - You have to send dummy data for each read operation because the SPI clock is generated only when data are sent through MOSI (I'm talking about 2linesFullDuplex mode only here). So after sending the address (on two bytes) you have to keep sending dummy data in order to generate clock and allow slave to send you data back on MISO line.

    - At first time, try to use only polling mode to verify that EEPROM is ''alive'' and responds correctly to your commands.

    Then, if you want to use RxNE interrupt, you will need for exampel to enable/disable the interrupt each time. You also can use a token (a global variable taking either 0 or 1 value to indicate if the data received on MISO is valid data or dummy) ... anyway, it should be managed by software.

    I hope it helps a little :)

    Regards.

    dave4
    dave4Author
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 13:37

    Hi,

    >why do you set NSS output function if you are handling the NSS by >software?

    I tried using the software configuration, but found that the line is not reset to 1 after the command block, even though I send

    SPI_NSSInternalSoftwareConfig(SPI1, SPI_NSSInternalSoft_Set);

    to reset it (or I am using this command incorrectly)

    >This EEPROM supports (CPOL = 0, CPHA = 0) and (CPOL = 1, CPHA = 1) so may >be you can try the second configuartion.

    Is CPOL=0,CPHA=0 the equivalent of SPI_CPOL_Low and SPI_CPHA_2Edge ?

    What is the purpose of sending dummy data at every stage of reading the memory ? Is this just for testing, or will I have to do this in my final application ?

    Also, you say that I can do the receiving through an interrupt, how would I stop it going to the interrupt routine on every clock cycle and just when I want to receive data which is actually in the buffer ?

    --dave

    dave4
    dave4Author
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 13:37

    Update - FIXED

    Thanks to chikos33 for all your help, I appreciate it.

    Regards

    Dave :)

    dave4
    dave4Author
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 13:37

    Hi,

    Thanks for the information, I can now poll the EEPROM with read_status and get sensible responses back.

    However, when I moved on to reading some real data using the following code

    Code:

    GPIO_SetBits(GPIOA, GPIO_Pin_4);

    GPIO_ResetBits(GPIOA, GPIO_Pin_4);

    SPI_I2S_SendData(SPI1, EEPROM_WRITE_EN);

    SPI_I2S_SendData(SPI1, EEPROM_WRITE);

    SPI_I2S_SendData(SPI1, 0x00);

    SPI_I2S_SendData(SPI1, 0xFE);

    SPI_I2S_SendData(SPI1, 0xCC);

    SPI_I2S_SendData(SPI1, EEPROM_WRITE_DIS);

    GPIO_SetBits(GPIOA, GPIO_Pin_4);

    GPIO_ResetBits(GPIOA, GPIO_Pin_4);

    //SPI_I2S_SendData(SPI1, EEPROM_WRITE_EN);

    //SPI_I2S_SendData(SPI1, EEPROM_WRITE);

    SPI_I2S_SendData(SPI1, EEPROM_READ);

    SPI_I2S_SendData(SPI1, 0x00);

    SPI_I2S_SendData(SPI1, 0xFE);

    SPI_I2S_SendData(SPI1, 0xFF);

    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);

    EEPROM_buffer[EE_idx] = SPI_I2S_ReceiveData(SPI1);

    SPI_I2S_SendData(SPI1, 0xFF);

    EE_idx++;

    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != SET);

    EEPROM_buffer[EE_idx] = SPI_I2S_ReceiveData(SPI1);

    SPI_I2S_SendData(SPI1, 0xFF);

    EE_idx++;

    GPIO_SetBits(GPIOA, GPIO_Pin_4);

    I get the clocks generated, but the receive line is a constant high, and the value 0xFF is written into my buffer instead of 0xCC which I was expecting. This is shown in the attached scope trace (yellow = MISO).

    Thanks

    Dave

    chikos33
    Visitor II
    May 17, 2011
    Posted on May 17, 2011 at 13:37

    All the pleasure is for me, Dave :p

    I wish you even better luck for the remaining application parts.

    dave4
    dave4Author
    Associate II
    May 17, 2011
    Posted on May 17, 2011 at 13:37

    Update - FIXED

    Thanks to chikos33 for all your help, I appreciate it.

    Regards

    Dave :)

    johnfitzgerald9
    Associate III
    May 17, 2011
    Posted on May 17, 2011 at 13:37

    Hi Dave6,

    To help the next person who reads this thread, please could you publish what you ''Fixed'' and how?

    thanks.