2012-12-12 03:57 PM
Hi,
I am writing data into an ST 95M02SPI eeprom memory, from a STM32F051 micro but I am unable to read it back. On the scope I can see the proper data on MISO (just an incrementing count). SCK looks to be fine, (stops after LSB on MISO) and CS goes high just after that. However, I just can't read the returned value into the main app. All I read is 00h It looks as if MISO data is not being shifted in the shift register or RXFIFO just contains all zeros.Using the SPI_Config function below was the only way I could get the SPI signals to show anything. If anyone could help, I'd greatly appreciate it. I'm using the SPI2 port on the microcontroller. void SPI_Config(void) { SPI_InitTypeDef SPI_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; /* Enable SPI clock, SPI2 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); /* SPI pin mappings */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_1; /* SPI SCK pin configuration */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_Init(GPIOB, &GPIO_InitStructure); /* SPI MOSI pin configuration */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; GPIO_Init(GPIOB, &GPIO_InitStructure); /* SPI MISO pin configuration */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // This needs to have a PULL-UP GPIO_Init(GPIOB, &GPIO_InitStructure); // Configure CS pin as output floating GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOB, &GPIO_InitStructure); /* SPI configuration -------------------------------------------------------*/ SPI_I2S_DeInit(SPIx); SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init(SPIx, &SPI_InitStructure); SPI_SSOutputCmd(SPIx, ENABLE); SPI_Cmd(SPIx, ENABLE); } uint8_t SPI_Flash_Read(uint8_t ins, uint8_t address) { uint8_t spi_rd_data_local; EEPROM_CS_LOW; // Send SPI instruction SPI_SendData8(SPIx, ins); while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) != SET); // Send SPI address H SPI_SendData8(SPIx, 0x00); while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) != SET); // Send SPI address M SPI_SendData8(SPIx, 0x00); while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) != SET); // Send SPI address SPI_SendData8(SPIx, address); while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) != SET); // Send Dummy Byte for Clocks SPI_SendData8(SPIx, 0xFF); // Now sit back and wait for the data while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET); spi_rd_data_local = SPI_ReceiveData8(SPIx); while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_BSY) == SET); EEPROM_CS_HIGH; printf(''\n\r Local Read Data Received = %.2X'', spi_rd_data_local); return (spi_rd_data_local); }2012-12-12 05:20 PM
As a blind build I might offer this, I think you need to watch RXNE as it only gets cleared if you actually read the data register, so in your case you get some prior data.
Your BUSY was waiting on SPI1?/* Enable SPI clock, SPI2 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
/* SPI SCK, MOSI, MISO pin configuration */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15 | GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_1; // 10 MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);
// Configure CS pin as output floating
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_0); // SPI2 SCK
GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_0); // SPI2 MOSI
GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_0); // SPI2 MISO
/* SPI configuration -------------------------------------------------------*/
SPI_I2S_DeInit(SPIx);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPIx, &SPI_InitStructure);
SPI_SSOutputCmd(SPIx, ENABLE);
SPI_Cmd(SPIx, ENABLE);
}
uint8_t SPI_SendByte(uint x)
{
while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET); // TX Empty (Front Test)
SPI_SendData8(SPIx, x);
while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET); // Wait for data to shift out
return(SPI_ReceiveData8(SPIx)); // Read to clear RXNE
}
uint8_t SPI_Flash_Read(uint8_t ins, uint8_t address)
{
uint8_t spi_rd_data_local;
EEPROM_CS_LOW;
// Send SPI instruction
SPI_SendByte(ins);
// Send SPI address H
SPI_SendByte(0x00);
// Send SPI address M
SPI_SendByte(0x00);
// Send SPI address
SPI_SendByte(address);
// Send Dummy Byte for Clocks
spi_rd_data_local = SPI_SendByte(0xFF);
while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_BSY) == SET);
EEPROM_CS_HIGH;
printf(''
Local Read Data Received = %.2X'', spi_rd_data_local);
return (spi_rd_data_local);
}
2012-12-13 06:57 AM
/**
* @brief Shift data in/out
* @param Iob pointer to I/O control block
* @param pData data to shift out
* @retval data read by shift out
*
* This routine shifts out one byte and returns the data shifted in.
*/
static unsigned char SpiDev_Shift(SpiDev_IOB *Iob, unsigned char pData)
{
unsigned char i;
// make sure shift register empty
while(SPI_I2S_GetFlagStatus(Iob->Info.SPIx, SPI_I2S_FLAG_TXE) == RESET)
{ // clear any pending shift out/in
while(SPI_I2S_GetFlagStatus(Iob->Info.SPIx, SPI_I2S_FLAG_RXNE) == SET)
{ // empty rx buffer
i = SPI_I2S_ReceiveData(Iob->Info.SPIx); // clear SPI buffer
if( SPI_I2S_GetFlagStatus(Iob->Info.SPIx, SPI_I2S_FLAG_OVR) == SET)
spiOvers[Iob->Info.SpiPort]++; // count overruns, reset
}
} // shift register cleared
// shift out one byte, shift in one byte
SPI_I2S_SendData(Iob->Info.SPIx, pData); // Send byte to the SPI peripheral
while(SPI_I2S_GetFlagStatus(Iob->Info.SPIx, SPI_I2S_FLAG_RXNE) == RESET) ; // wait for data shifted in
i = SPI_I2S_ReceiveData(Iob->Info.SPIx); // empty SPI buffer
if( SPI_I2S_GetFlagStatus(Iob->Info.SPIx, SPI_I2S_FLAG_OVR) == SET)
spiOvers[Iob->Info.SpiPort]++; // count overruns, reset
return i;
}
There are two issues you need to check. The first is making sure the RXNE stays clear so you don't have a RX overrun. This is the routine I use to send and receive on SPI.
The second issue has to do with your EEPROM. You need to check the SPI timing for the clock edge when data is clocked in and out of the part. A problem with the ST SPI hardware is that it only handles one clock edge (CPOL setting) for read and write, so parts that require different clock edges for read (typically falling edge)and write (typically rising edge)are somewhat complicated to use with the STM If this is the case you need to change CPOL clock polarity between read and write.
Jack Peacock
2012-12-13 11:12 AM
Hi Clive
Thanks for that. It tidied it up but I still read 00h. Again I still see the correct data from the EEprom. It seems to me that a lot of zero bytes have been clocked into the RX buffer and I'm reading these, but I'm not sure. So, I'm using Clive's read function and my SPI Write functions looks like. All help is appreciated. uint8_t SPI_Flash_Write(uint8_t ins, uint8_t address, uint8_t data) { EEPROM_CS_LOW; SPI_SendByte(ins); SPI_SendByte(0x00); SPI_SendByte(0x00); SPI_SendByte(address); SPI_SendByte(data); while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_BSY) == SET); EEPROM_CS_HIGH; return (1); } void WriteEnable(void) { EEPROM_CS_LOW; SPI_SendData8(SPIx, 0x06); // Wait for SPI Tx buffer empty while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) != SET); // Clear receive buffer Clr_Rcv_Buf(); EEPROM_CS_HIGH; } void Clr_Rcv_Buf(void) { uint8_t spi_rd_data; // Clears the receive buffer if (SPI_I2S_GetFlagStatus(SPIx,SPI_I2S_FLAG_RXNE) == SET) spi_rd_data = SPI_ReceiveData8(SPIx); } My main calling routine is for (ee_add = 0; ee_add<128; ee_add++) { WriteEnable(); spi_wr_flag = SPI_Flash_Write(0x02, ee_add, ee_add); Delay(100); } printf(''\n\r Flash Write Complete''); for (ee_add = 0; ee_add<128; ee_add++) { spi_rd_data = SPI_Flash_Read(0x03, ee_add); Delay(100); }2012-12-13 11:15 AM
Hi Jack,
I'll check out the polarity issue on the datasheet. This may be indeed valid, but I would expect to see at least something returned, not all zeros.2012-12-14 04:39 AM
Hi Lads,
Thanks for the help. Working perfectly now. It was the receive flag that was causing the bother.2014-03-21 01:28 AM
Hi, clive! I have the same problem, I got always 0 for the variable status. When I made the main.c file, there was a warning ''variable status was set but never used'' which calls my attention. But I always cant find the problem, here is my code, could you help?
static __IO uint32_t TimingDelay; void spiInit(void); uint8_t Send( uint8_t data); void spiInit() { GPIO_InitTypeDef GPIO_InitStruct; SPI_InitTypeDef SPI_InitStruct; /*Enable peripheral clock for SPI1*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); /* Enable SCK, MOSI and MISO GPIO clocks */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); /* define a variable of type GPIO_InitTypeDef* */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7 | GPIO_Pin_6; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // this sets the pin type to push / pull (as opposed to open drain) GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN; // this sets the pullup / pulldown resistors to be active GPIO_Init(GPIOA, &GPIO_InitStruct); /* Configure GPIO PIN for Lis Chip select */ //on fait deux fois GPIO_Init() ? Pin NSS est bien Slave Select, il faut utiliser!http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus// GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP ; GPIO_Init(GPIOA,&GPIO_InitStruct); /* choose alternate function 0 for certain pins */ GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_0); GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_0); GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_0); /* using the SPI_Init() function to do the initialization */ //Program the Polarity, Phase, First Data, Baud Rate Prescaler, Slave // Management, Peripheral Mode and CRC Polynomial values //SPI_I2S_DeInit(SPI1); SPI_InitStruct.SPI_Mode = SPI_Mode_Master; SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStruct.SPI_NSS = SPI_NSS_Soft; SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB; SPI_Init(SPI1,&SPI_InitStruct); SPI_SSOutputCmd(SPI1, ENABLE); /* Enable the SPI */ SPI_Cmd(SPI1, ENABLE); /* Configure the FIFO threshold to select at which threshold the RXNE event is generated */ SPI_RxFIFOThresholdConfig(SPI1, SPI_RxFIFOThreshold_QF); //XNE event is generated if the FIFO level is greater or equal to 1/4// /* send data */ GPIO_SetBits(GPIOA,GPIO_Pin_10); //test if the flag related set?// } uint8_t Send( uint8_t data) { SPI_SendData8(SPI1, data); while( SPI1->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore //Delay(1); return SPI_ReceiveData8(SPI1); } /** * @brief Inserts a delay time. * @param nTime: specifies the delay time length, in 1 ms. * @retval None */ void Delay(__IO uint32_t nTime) { TimingDelay = nTime; while(TimingDelay != 0); } /** * @brief Decrements the TimingDelay variable. * @param None * @retval None */ void TimingDelay_Decrement(void) { if (TimingDelay != 0x00) { TimingDelay--; } } /** * @brief Decrements the TimingDelay variable. * @param None * @retval None */ int main(void) { /*!< At this stage the microcontroller clock setting is already configured, this is done through SystemInit() function which is called from startup file (startup_stm32f0xx.s) before to branch to application main. To reconfigure the default setting of SystemInit() function, refer to system_stm32f0xx.c file */ /* Add your application code here */ RCC_ClocksTypeDef RCC_Clocks; /* SysTick end of count event each 1ms */ RCC_GetClocksFreq(&RCC_Clocks); SysTick_Config(RCC_Clocks.HCLK_Frequency / 1000); spiInit(); /* Infinite loop */ while (1) { uint8_t status = 0; GPIO_WriteBit(GPIOA, GPIO_Pin_10, Bit_RESET); Send(0x05); status = Send(0xFF); GPIO_WriteBit(GPIOA, GPIO_Pin_10, Bit_SET); } }