2010-01-15 12:02 AM
Communicating with an EEPROM over SPI
2011-05-17 04:37 AM
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 peripheralCode:
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 Dave2011-05-17 04:37 AM
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!2011-05-17 04:37 AM
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...2011-05-17 04:37 AM
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 ? --dave2011-05-17 04:37 AM
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.2011-05-17 04:37 AM
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 codeCode:
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 Dave2011-05-17 04:37 AM
Update - FIXED
Thanks to chikos33 for all your help, I appreciate it. Regards Dave :)2011-05-17 04:37 AM
Update - FIXED
Thanks to chikos33 for all your help, I appreciate it. Regards Dave :)2011-05-17 04:37 AM
All the pleasure is for me, Dave :p
I wish you even better luck for the remaining application parts.