2014-03-09 04:01 AM
This is my code for SPI and I am getting the below mentioned errors, I can't seem to resolve these.
&sharpinclude <stm32f2xx.h>&sharpinclude <stm32f2xx_conf.h>&sharpinclude <stm32f2xx_spi.h>&sharpinclude <stm32f2xx_gpio.h>&sharpinclude <stm32f2xx_rcc.h>// this function initializes the SPI1 peripheralvoid init_SPI1(void){ GPIO_InitTypeDef GPIO_InitStruct; SPI_InitTypeDef SPI_InitStruct; // enable clock for used IO pins RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); /* configure pins used by SPI1 * PA5 = SCK * PA6 = MISO * PA7 = MOSI */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStruct); // connect SPI1 pins to SPI alternate function GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1); // enable clock for used IO pins RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); /* Configure the chip select pin in this case we will use PE7 */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOE, &GPIO_InitStruct); GPIOE->BSRRL |= GPIO_Pin_7; // set PE7 high // enable peripheral clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); /* configure SPI1 in Mode 0 * CPOL = 0 --> clock is low when idle * CPHA = 0 --> data is sampled at the first edge */ SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines SPI_InitStruct.SPI_Mode = SPI_Mode_Master; // transmit in master mode, NSS pin has to be always high SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // clock is low when idle SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // data sampled at first edge SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set; // set the NSS management to internal and pull internal NSS high SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // SPI frequency is APB2 frequency / 4 SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first SPI_Init(SPI1, &SPI_InitStruct); SPI_Cmd(SPI1, ENABLE); // enable SPI1}/* This funtion is used to transmit and receive data * with SPI1 * data --> data to be transmitted * returns received value */uint8_t SPI1_send(uint8_t data){ SPI1->DR = data; // write data to be transmitted to the SPI data register while( !(SPI1->SR & SPI_I2S_FLAG_TXE) ); // wait until transmit complete while( !(SPI1->SR & SPI_I2S_FLAG_RXNE) ); // wait until receive complete while( SPI1->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore return SPI1->DR; // return received data from SPI data register}int main(void){ uint8_t received_val = 0; init_SPI1(); while(1){ GPIOE->BSRRH |= GPIO_Pin_7; // set PE7 (CS) low SPI1_send(0xAA); // transmit data received_val = SPI1_send(0x00); // transmit dummy byte and receive data GPIOE->BSRRL |= GPIO_Pin_7; // set PE7 (CS) high } }I am getting the following errors, how to get around these:Build target 'Target 1'linking....\spi_1.axf: Error: L6218E: Undefined symbol assert_param (referred from stm32f2xx_gpio.o)..\spi_1.axf: Error: L6218E: Undefined symbol main (referred from rtentry2.o).Not enough information to list image symbols.Finished: 1 information, 0 warning and 2 error messages.''.\spi_1.axf'' - 2 Error(s), 0 Warning(s).Target not created #spi #stm32f2xx #stm32f2-spi2014-03-09 06:33 AM
Using Keil, your project isn't correctly formed, likely missing a startup file, and with USE_FULL_ASSERT defined (stm32f2xx_conf.h?), but lacking the body function for assert_failed() in main.c
Review the construction of the template project, and clone it if required. STM32F2xx_StdPeriph_Lib_V1.1.0\Project\STM32F2xx_StdPeriph_Template\MDK-ARM\Project.uvproj Honestly I'd be checking TXE before stuffing data to the SPI peripheral, review also SPI example code from the firmware libraries.2014-04-16 11:16 AM
I changed my code, now I am using Atollic.
I have some doubts - can you please resolve them?1. When I check the clock on the Oscilloscope - I don't get a square wave (it's something like a square wave with it's upper part curved), why is that happening? Is it OK to not to have a perfectly square wave?2. What's wrong with the code below, I am trying to read the status register of the EEPROM. received_val remains 0 even after completely executing the code (I am debugging step by step)3. However, when I start the code - it starts with a default value of 224 (does that mean that it read something during the previous execution of the code, I am asking this because I am making it 0 every time in code so how come it automatically becomes 224?) If it's correct why doesn't it reflect during the debugging?PS - I have been stuck with this for almost about two months and I can't seem to figure out - I have tried all possible things to test SPI but none of them seem to work. I'd really appreciate some help. #include <stddef.h>#include ''stm32f2xx.h'' void init_SPI1(void){ GPIO_InitTypeDef GPIO_InitStruct; SPI_InitTypeDef SPI_InitStruct; // enable clock for used IO pins RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); /* configure pins used by SPI1 * PA5 = SCK * PA6 = MISO * PA7 = MOSI * PB0 - CS * PB1 - HLD * PB2 - WP */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStruct); // connect SPI1 pins to SPI alternate function GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1); // enable clock for used IO pins RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); /* Configure the chip select pin in this case we will use PE7 */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOB, &GPIO_InitStruct); GPIOB->BSRRL |= GPIO_Pin_0; // set PB0 high GPIOB->BSRRL |= GPIO_Pin_0; // set PB1 high GPIOB->BSRRL |= GPIO_Pin_0; // set PB2 high // enable peripheral clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); /* configure SPI1 in Mode 0 * CPOL = 0 --> clock is low when idle * CPHA = 0 --> data is sampled at the first edge */ SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines SPI_InitStruct.SPI_Mode = SPI_Mode_Master; // transmit in master mode, NSS pin has to be always high SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // clock is low when idle SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // data sampled at first edge SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set; // set the NSS management to internal and pull internal NSS high SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // SPI frequency is APB2 frequency / 4 SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first SPI_Init(SPI1, &SPI_InitStruct); SPI_Cmd(SPI1, ENABLE); // enable SPI1 } uint8_t SPI1_send(uint8_t data){ SPI1->DR = data; // write data to be transmitted to the SPI data register while( !(SPI1->SR & SPI_I2S_FLAG_TXE) ); // wait until transmit complete while( !(SPI1->SR & SPI_I2S_FLAG_RXNE) ); // wait until receive complete while( SPI1->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore return SPI1->DR; // return received data from SPI data register }int main(void){ uint8_t received_val = 0; init_SPI1(); while(1) { GPIOB->BSRRH |= GPIO_Pin_0; // set PE7 (CS) low received_val=SPI1_send(0xA5); GPIOB->BSRRL |= GPIO_Pin_0; // set PE7 (CS) high }}2014-04-16 11:37 AM
Well I don't know what SPI device you're using, and I don't have an SPI EEPROM/FLASH on my board.
You need to send a dummy byte to the device to get status back, when you shift the command out you get back bits at the same time, the device HASN'T received the command at this point, so you're almost certainly going to need to send at least one more byte to generate the clocks to get status back. What does the documentation show? What is the bandwidth of the scope and probe you are using? What's the frequency of the clock signal? Use a 1X/10X probe, and switch it to 10X mode!2014-04-16 11:56 AM
I am using an external EEPROM - http://www.atmel.in/Images/Atmel-5165-SEEPROM-AT25512-Datasheet.pdf
And so you mean to say that I must send the status read opcode again and then read from the status register?Something like this?GPIOB->BSRRH |= GPIO_Pin_0; // set PE7 (CS) low
SPI1_send(0xA5);
received_val=SPI1_send(0xA5);
GPIOB->BSRRL |= GPIO_Pin_0; // set PE7 (CS) high
Does the rest of the code look fine to you?I am also not able to figure out the clock. The ''clock rate'' of the device is 20MHz. And if I am not wrong isn't it supposed to be the same as the SPI clock? How do I make sure that it is same (do I need to change the BaudRate_PresScaler?)I don't have access to the Oscilloscope at the moment however I will get back to you later with the details?2014-04-16 12:37 PM
Where did you pluck 0xA5 from? Isn't the
http://forums.xilinx.com/xlnx/attachments/xlnx/ELINUX/3453/1/at25.c
command 0x05? I'd send 0x05, 0x00 In these two months did you read the documentation? Most 1X/10X scope probes in 1X mode have a bandwidth BELOW 8 MHz, so at 20 MHz the signal will look pretty awful. Yes, the 20 MHz is the bit rate for the SPI bus2014-04-18 11:27 PM
Yes, I know that read status command is 0x05 - I just made a mistake while posting it here and yes I did read the user manual as well as the data sheet of both the board as well as the memory.
1. I checked MISO with the Oscilloscope, it always stays low (The other pins are behaving properly). 2. I made a change - CPHA = 1, since according to the timing diagram the data is being sent at the trailing edge. (RDSR timing diagram).3. I tried with sending a dummy byte. I still have no luck. (I sent both 00 as well as FF as the dummy byte)4. I found another mistake - I wasn't making the HOLD and WP high (while copy-pasting I forgot to change the pin number)5. The maximum APB2 frequency is 60MHz and APB2/4 will be 15 MHz, however the EEPROM requires 20MHz - will that be a problem?Does the ''SPI1_send'' function seem fine to you? Have I initialized SPI properly?This is the code that I finally tried with - #include ''stm32f2xx.h'' void init_SPI1(void) { GPIO_InitTypeDef GPIO_InitStruct; SPI_InitTypeDef SPI_InitStruct; // enable clock for used IO pins RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); /* configure pins used by SPI1 * 1 - CS - PB0 * 2 - MISO - PA6 * 3 - WP - PB2 * 4 - GND * 5 - MOSI - PA7 * 6 - SCK - PA5 * 7 - HLD - PB1 * 8 - VCC */ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_6 | GPIO_Pin_5; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStruct); // connect SPI1 pins to SPI alternate function GPIO_PinAFConfig(GPIOA, GPIO_PinSource5, GPIO_AF_SPI1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource6, GPIO_AF_SPI1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_SPI1); // Configure the HLD,CS and WP pins GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOB, &GPIO_InitStruct); GPIOB->BSRRL |= GPIO_Pin_0; // set PB0 (CS) high GPIOB->BSRRL |= GPIO_Pin_1; // set PB1 (HLD) high GPIOB->BSRRL |= GPIO_Pin_2; // set PB2 (WP) high // enable peripheral clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); /* configure SPI1 in Mode 0 * CPOL = 0 --> clock is low when idle * CPHA = 1 --> data is sampled at the second edge */ SPI_InitStruct.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // set to full duplex mode, seperate MOSI and MISO lines SPI_InitStruct.SPI_Mode = SPI_Mode_Master; // transmit in master mode, NSS pin has to be always high SPI_InitStruct.SPI_DataSize = SPI_DataSize_8b; // one packet of data is 8 bits wide SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; // clock is low when idle SPI_InitStruct.SPI_CPHA = SPI_CPHA_1Edge; // data sampled at second edge SPI_InitStruct.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set; // set the NSS management to internal and pull internal NSS high SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // SPI frequency is APB2 frequency / 4 SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;// data is transmitted MSB first SPI_Init(SPI1, &SPI_InitStruct); SPI_Cmd(SPI1, ENABLE); // enable SPI1 } uint16_t SPI1_send(uint8_t data) { SPI1->DR = data; // write data to be transmitted to the SPI data register while( !(SPI1->SR & SPI_I2S_FLAG_TXE) ); // wait until transmit complete while( !(SPI1->SR & SPI_I2S_FLAG_RXNE) ); // wait until receive complete while( SPI1->SR & SPI_I2S_FLAG_BSY ); // wait until SPI is not busy anymore return SPI1->DR; // return received data from SPI data register }int main(void){ uint16_t received_val = 0; init_SPI1(); while(1) { GPIOB->BSRRH |= GPIO_Pin_0; // set PB0 (CS) low SPI1_send(0x05); //The read status opcode GPIOB->BSRRL |= GPIO_Pin_0; // set PB0 (CS) high GPIOB->BSRRH |= GPIO_Pin_0; // set PB0 (CS) low received_val=SPI1_send(0xFF); //The dummy byte GPIOB->BSRRL |= GPIO_Pin_0; // set PB0 (CS) high }}2014-04-19 01:58 AM
I did not look at the whole thing, but am pretty sure that you do not need to deassert CS between the command and the data bytes in main:
GPIOB->BSRRH |= GPIO_Pin_0; // set PB0 (CS) low
SPI1_send(0x05); //The read status opcode
// do not release CS
//GPIOB->BSRRL |= GPIO_Pin_0; // set PB0 (CS) high
//GPIOB->BSRRH |= GPIO_Pin_0; // set PB0 (CS) low
received_val=SPI1_send(0xFF); //The dummy byte
GPIOB->BSRRL |= GPIO_Pin_0; // set PB0 (CS) high
2014-04-19 06:11 AM
Yes, one of the salient details expressed in the timing diagram is the CS is low during the transaction.
20 MHz is the maximum speed, it can run significantly slower. I've used code materially similar to readhttp://www.winbond.com/NR/rdonlyres/7EB3B29C-1B35-421C-AA24-F430B51C776A/0/W25Q16BV.pdf
parts2014-04-19 09:53 PM
Also you should probably observe that you don't need to RMW the BSRRL/H registers, you simply write the bits you want to set/reset.
I would focus on sending the READ ID or JEDEC ID type commands and getting back recognizable data.