I use an STM32F0 discovery board.
I am trying to program an EEPROM to save an QR-code and display it on an LCD.
Right now I am working on getting the STM32 to receive the data from the EEPROM, my code works if I short MISO and MOSI (I changed it a bit but not much), but when I try to get it to work with the EEPROM, it doesnt work.
My code below. Header file:
#include "stm32f0xx_conf.h"
#include <string.h>
//Pin definitions
//#define NSSA GPIO_PinSource12
#define SCKA GPIO_PinSource13
#define MISOA GPIO_PinSource14
#define MOSIA GPIO_PinSource15
#define TXPINA GPIO_PinSource9
//#define NSS GPIO_Pin_12
#define CS GPIO_Pin_12
#define SCK GPIO_Pin_13
#define MISO GPIO_Pin_14
#define MOSI GPIO_Pin_15
#define TXPIN GPIO_Pin_9
#define HOLD GPIO_Pin_11
#define GreenLED_Pin GPIO_Pin_9
#define BlueLED_Pin GPIO_Pin_8
//EEPROM INSTRUCTIONS:
uint8_t READMEM = 0x003; //READ - 0000 0011 Read data from memory array beginning at selected address
uint8_t WRITEMEM = 0x002; //WRITE - 0000 0010 Write data to memory array beginning at selected address
uint8_t READSR = 0x005; //RDSR - 0000 0101 Read STATUS register
uint8_t WRITESR = 0x001; //WRSR - 0000 0001 Write STATUS register
uint8_t WRITEDI = 0x004; //WRDI - 0000 0100 Reset the write enable latch (disable write operations)
uint8_t WRITEEN = 0x006; //WREN - 0000 0110 Set the write enable latch (enable write operations)
uint8_t NULLBYTE = 0x000;
SPI initialization:
void SPI_EEPROM()
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
GPIO_PinAFConfig(GPIOB,SCKA,GPIO_AF_0);
GPIO_PinAFConfig(GPIOB,MISOA,GPIO_AF_0);
GPIO_PinAFConfig(GPIOB,MOSIA,GPIO_AF_0);
GPIO_InitTypeDef SPIGPIO;
SPIGPIO.GPIO_Mode = GPIO_Mode_AF;
SPIGPIO.GPIO_OType = GPIO_OType_PP;
SPIGPIO.GPIO_PuPd = GPIO_PuPd_NOPULL;
SPIGPIO.GPIO_Speed = GPIO_Speed_50MHz;
SPIGPIO.GPIO_Pin = SCK;
GPIO_Init(GPIOB, &SPIGPIO);
SPIGPIO.GPIO_Pin = MISO;
GPIO_Init(GPIOB, &SPIGPIO);
SPIGPIO.GPIO_Pin = MOSI;
GPIO_Init(GPIOB, &SPIGPIO);
SPI_I2S_DeInit(SPI2);
SPI_InitTypeDef SPIEPR;
SPIEPR.SPI_Mode = SPI_Mode_Master;
SPIEPR.SPI_CPHA = SPI_CPHA_1Edge;
SPIEPR.SPI_CPOL = SPI_CPOL_Low;
SPIEPR.SPI_FirstBit = SPI_FirstBit_MSB;
SPIEPR.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; //-> _16~3.2MHZ CLOCK | _32 ~1.6MHZ CLOCK
SPIEPR.SPI_NSS = SPI_NSS_Soft;
SPIEPR.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPIEPR.SPI_DataSize = SPI_DataSize_8b;
SPI_Init(SPI2, &SPIEPR);
SPI_NSSInternalSoftwareConfig(SPI2,SPI_NSSInternalSoft_Set);
//SPI2 -> CR2 |= SPI_CR2_FRXTH;
SPI_Cmd(SPI2,ENABLE);
GPIO initialization:
void GPIO()
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = BlueLED_Pin|GreenLED_Pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_3;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitTypeDef GPIO2_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
GPIO2_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO2_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO2_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO2_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO2_InitStructure.GPIO_Pin = HOLD;
GPIO_Init(GPIOB, &GPIO2_InitStructure);
GPIO2_InitStructure.GPIO_Pin = CS;
GPIO_Init(GPIOB, &GPIO2_InitStructure);
The simple send and recieve function:
uint8_t SPISendByte(uint8_t data)
uint8_t databck;
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) != RESET);
SPI_SendData8(SPI2,data);
while(SPI_GetReceptionFIFOStatus(SPI2) != 0x0000)
SPI_ReceiveData8(SPI2); //read RXFIFO until empty
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); //wait until TXFIFO is empty
SPI_SendData8(SPI2,NULLBYTE); //send 0-byte to recive answer from EEPROM
while(SPI_GetReceptionFIFOStatus(SPI2) != 0x0200); //wait until the RXFIFO is a quarter full (8bit)
return SPI_ReceiveData8(SPI2);
Main function:
SystemInit();
SPI_EEPROM();
GPIO();
GPIO_ResetBits(GPIOB, CS); //CS low to enable the EEPROM
SPI_SendData8(SPI2,WRITEEN); //send the WREN instruction to set the write enable latch
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) != RESET);
GPIO_SetBits(GPIOB, CS); //Toggle on and off to set bit in the Status register
GPIO_ResetBits(GPIOB, CS);
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) != RESET);
USART_SendData(USART1, SPISendByte(READSR)); //Read Status Reg and print it to USART (should be ..0010)
I set up the EEPROM like its datasheet tells me to. Clock setup from the sheet(should be CPOL and CPHA 0):
Instructions, addresses or data present on the SI pin are latched on the rising edge of the clock input, while data on the SO pin is updated after the falling edge of the clock input.
This is not my entire code but what I use for testing.
It should work; I double checked it with my scope (it returns ..0010 on MISO with the logic mode) and looked at the RXFIFO with the debugger if its empty and receives actual data:
It does, but the code always returns 0.
I also tried a lot of different Flags instead of reading the RXFIFO but it seemed to be the best solution.
So, after bashing my head against my table and my coworker stealing my oscilloscope, it worked, so i found out that the oscilloscope channels pulled my signal down bc i had the inputs in 50 Ohm mode and not 1MOhm. Switching that fixed it.
Related
I try to make master and slave stm32f103 (bluepills) communicate. But I am having trouble with receiving. When I connect my master to logic analyser I can see MOSI as in the picture
Logic Analyser
In the picture, MOSI is sending "Y" letter. But not all clock pulses same.(I don't know if this is the reason of communication fail)
here is my schematics and my code I simplified as much as I can.
Master Code:
int i;
RCC ->APB2ENR |= 0x00001004; //SPI1,GPIOA clock en
GPIOA ->CRL &= 0x00000000;
GPIOA ->CRL |= 0xb0b33333;
SPI1->CR1 = SPI_CR1_SSM| SPI_CR1_SSI| SPI_CR1_MSTR|SPI_CR1_BR_2;
SPI1->CR1 |= SPI_CR1_SPE; // enable SPI
while(1){
SPI1 -> DR = 'A';
for(int i = 0 ;i<400000;i++);
while( !(SPI1->SR & SPI_SR_TXE) ); // wait until transmit buffer empty
}
and Slave
int i;
RCC ->APB2ENR |= 0x0000100c; //SPI1,GPIOA,GPIOB clock en
GPIOB ->CRH &= 0x00000000;
GPIOB ->CRH |= 0x33333333;
GPIOA ->CRL &= 0x00000000;
GPIOA ->CRL |= 0x4b443333;
GPIOA ->CRH &= 0x00000000;
GPIOA ->CRH |= 0x33333333;
SPI1->CR1 = SPI_CR1_SSM| SPI_CR1_SSI| SPI_CR1_BR_2;
SPI1->CR1 |= SPI_CR1_SPE; // enable SPI
SPI1->CR1 &=~SPI_CR1_MSTR; //disable master
for(int c=0;c<5;c++){
LCD_INIT(cmd[c]);
}
while(1){
while( !(SPI1->SR & SPI_SR_RXNE));
char a = SPI1 ->DR;
for (i=0;i<400000;i++);
LCD_DATA(a);
for (i=0;i<400000;i++);
}
}
My Schematic:
Schematic
The problem is slave is not receiving any data.
It stucks in the loop while( !(SPI1->SR & SPI_SR_RXNE));
First, what are your HCLK and APB2 bus frequencies? If I'm not mistaken, you seem to use (fPLCK / 32) for SPI clock and your logic analyzer shows ~2 or 3 MHz clock. If your APB2 frequency is higher than the 72 MHz limit, you may experience clock problems.
In the slave, you use SSM (software slave management) and activate SSI (internal slave select). The name of the SSI bit is misleading: It mimics the physical NSS pin. So when SSI = 1, the slave is not selected. This is probably the reason why the slave ignores the incoming bytes.
Am trying to set a Chip Enable (CE) of a pin to go high before a SPI transfer and go back low upon accomplishing of the transfer (either TX or RX). Am using the NRF24L01 and Nucleo-F303. It is said that when the CE is high, thats when i can do a real SPI transfer to the NRF24L01. However, the CE pin goes momentarily low and then high again even before the real transfer hasnt been accomplished
The rest of the pins seem to be synching accordingly. How do i get the CE pin to exactly go high prior to making a SPI transfer and then Low when am done or not doing any more transfers.
Here is how i've attempted to solve the problem
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI1_Init();
MX_USART1_UART_Init();
HAL_Delay(5);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
uint8_t data[6] = {0x5C, 0xBA, 0xBB, 0x4D, 0x5E, 0xFB,};
uint8_t data1[6] = {0};
while (1)
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
if(HAL_SPI_TransmitReceive(&hspi1, data, data1, 6, HAL_MAX_DELAY) == HAL_OK)
{
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
}
}
}
and this is how i have configured GPIO_PIN_3 to function
GPIO_InitStruct.Pin = GPIO_PIN_3;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // digital Output
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
Usually the Slave Select signal of SPI is active low but you can change this behaviour through bit SSIOP (it is the name of the bit on STM32H7 , might be different on other STM32).
About your other question, the Slave Select signal going inactive between two bytes, you can change that behaviour thanks to bit SSOM.
The different SPI configurations are usually pretty well described in the Reference Manual.
I ended up going bare-metal because the libraries were giving a lot of delay and had so many abstract layers
I am trying to bring up one of the ADC's on the STM32L476 Nucleo board. I think i have things configured ok, but i must be missing a step. I know this can be done use the HAL API and CubeMX, but i prefer register level access when bringing up a new board. Here is my code - i think it's commented to enough so it can be understood. I stripped out the rest of the code to keep it simple.
The problem i don't understand is that when the code starts the while loop - the ADC is not ready - that is the ADC1->ISR[0] is not set - and does not get set. I have confirmed the bits are set where i think they should be using keil.
Can anyone spot what is missing?
#include <stm32l4xx.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C"
#endif
int main(void)
{
uint32_t adcResult = 0;
/* Configure the clocks - using MSI as SYSCLK #16MHz */
RCC->CR &= 0xFFFFFF07; //Clear ~MSIRANGE bits and MSIRGSEL bit
RCC->CR |= 0x00000089; //Set MSI to 16MHz and MSIRGSEL bit
char *dataPtr = NULL;
//init ADC1
ADC1->CR &= 0xDFFFFFFF; //Take ADC out of deep power down - i break at this point to allow enough time - doesn't help
ADC1->CR |= 0x10000000; //Enable ADC1 votage regulator
RCC->AHB2ENR |= 0x00002001; //Enable the ADC clock, and GPIOA clk
GPIOA->ASCR |= 0x00000001; //Connect analog switch to GPIOA[0]
GPIOA->MODER |= 0x00000003; //Set A0 for analog input mode
ADC1->ISR |= 0x00000001; //Clear the ADRDY bit in the ADCx_ISR register by writing ‘1’.
ADC1->SQR1 |= 0x00000040; //Set for a sequence of 1 conversion on CH0
while (1)
{
ADC1->CR |= 0x00000004; //Convst
while(!(ADC1->ISR & 0x4));
adcResult = ADC1->DR;
sprintf(dataPtr, "%d", adcResult);
}
}
I solved this - finally. If anyone gets into the same place. I had set the SYSCLK as the ADC clock source, but this needs to be setup in RCC->CCIPR[29:28].
It's the little things...
I am trying to drive a EEPROM Chip 25LC256 with a STM32F469I-DISCO but can't achieve it.
I have tried to make my own function with HAL API bases but apparently something is wrong : I don't know if I write datas on the chip since I can't read it. Let me explain more.
So my chip is a DIP 25LC256 (DS is above is you wish). PINs HOLD and WP of EEPROM are tied to VCC (3.3V). PIN CS is connected to PH6 (ARD_D10 on board) and is managed by the software. PIN SI and PIN SO are respectively connected to PB15 (ARD_D11) and PB14 (ARD_D12) with the right alternate function (GPIO_AF5_SPI2). PIN SCK is also connected to PD3 (ADR_D13).
Here is my SPI configuration code :
EEPROM_StatusTypeDef ConfigurationSPI2(SPI_HandleTypeDef *spi2Handle){
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
GPIO_InitTypeDef gpioInit;
//// SCK [PD3]
gpioInit.Pin = GPIO_PIN_3;
gpioInit.Mode = GPIO_MODE_AF_PP;
gpioInit.Pull = GPIO_PULLDOWN;
gpioInit.Speed = GPIO_SPEED_FREQ_HIGH;
gpioInit.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOD, &gpioInit);
//// MOSI [PB15]
gpioInit.Pin = GPIO_PIN_15;
gpioInit.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOB, &gpioInit);
//// MISO [PB14]
gpioInit.Pin = GPIO_PIN_14;
gpioInit.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &gpioInit);
//// CS [PH6]
gpioInit.Pin = GPIO_PIN_6;
gpioInit.Mode = GPIO_MODE_OUTPUT_PP;
gpioInit.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOH, &gpioInit);
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, GPIO_PIN_SET);
//// SPI2
__HAL_RCC_SPI2_CLK_ENABLE();
spi2Handle->Instance = SPI2;
spi2Handle->Init.Mode = SPI_MODE_MASTER;
spi2Handle->Init.Direction = SPI_DIRECTION_2LINES;
spi2Handle->Init.DataSize = SPI_DATASIZE_8BIT;
spi2Handle->Init.CLKPolarity = SPI_POLARITY_LOW;
spi2Handle->Init.CLKPhase = SPI_PHASE_1EDGE;
spi2Handle->Init.NSS = SPI_NSS_SOFT;
spi2Handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
spi2Handle->Init.FirstBit = SPI_FIRSTBIT_MSB;
spi2Handle->Init.TIMode = SPI_TIMODE_DISABLE;
spi2Handle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE ;
spi2Handle->Init.CRCPolynomial = 7;
if(HAL_SPI_Init(spi2Handle) != HAL_OK){
return EEPROM_ERROR;
}
return EEPROM_OK;
}
And two functions allowing respectively (and theorically) to WRITE and READ into the the chip :
Write Function :
EEPROM_StatusTypeDef WriteEEPROM(SPI_HandleTypeDef *spi2Handle, uint8_t *txBuffer, uint16_t size, uint16_t addr){
uint8_t addrLow = addr & 0xFF;
uint8_t addrHigh = (addr >> 8);
uint8_t wrenInstruction = WREN_EEPROM; // Value : 0x06
uint8_t buffer[32] = {WRITE_EEPROM, addrHigh, addrLow}; //Value : 0x02
for(uint i = 0 ; i < size ; i++){
buffer[3+i] = txBuffer[i];
}
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, RESET);
if(HAL_SPI_Transmit(spi2Handle, &wrenInstruction, 1, TIMEOUT_EEPROM) != HAL_OK){
return EEPROM_ERROR;;
}
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, SET);
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, RESET);
if(HAL_SPI_Transmit(spi2Handle, buffer, (size + 3), TIMEOUT_EEPROM) != HAL_OK){
return EEPROM_ERROR;
}
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, SET);
return EEPROM_OK;
}
Read Function :
EEPROM_StatusTypeDef ReadEEPROM(SPI_HandleTypeDef *spi2Handle, uint8_t *rxBuffer, uint16_t size, uint16_t addr){
uint8_t addrLow = addr & 0xFF;
uint8_t addrHigh = (addr >> 8);
uint8_t txBuffer[3] = {READ_EEPROM, addrHigh, addrLow};
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, RESET);
HAL_SPI_Transmit(spi2Handle, txBuffer, 3, TIMEOUT_EEPROM);
HAL_SPI_Receive(spi2Handle, rxBuffer, size, TIMEOUT_EEPROM);
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_6, SET);
return EEPROM_OK;
}
I know my function are not very "beautiful" but it was a first attempt. In my main, I have tried in the first place to write into the chip the data "0x05" at the 0x01 adress then to read this data back :
uint8_t bufferEEPROM[1] = {5};
uint8_t bufferEEPROM2[1] = {1};
WriteEEPROM(&spi2Handle, bufferEEPROM, 1, 0x01);
ReadEEPROM(&spi2Handle, bufferEEPROM2, 1, 0x01);
I have an oscilloscope so since it didn't work (monitoring with STM Studio) I visualized the CLK and SI PINs then CLK and SO PINs (can only see two channel at the same time) :
As you can see, with the first picture that shows CLK (yellow) and SI (or MOSI) in blue, I have all the data expected : The WRite ENable instruction then the WRITE instruction. Following the ADDRESS, then the DATA.
After that, the Read Function starts. First the READ instruction and the ADDRESS where I want to fetch the data. The last 8 bits are supposed to be the data stored at the address (0x01 in this case). Something happens on SI PIN but I guess this is because the HAL_SPI_Receive() function actually calls HAL_SPI_TransmitReceive() with my array bufferEEPROM2 as parameter (that's why we can se 0b00000001). And so it is because of my SPI configuration parameter (Full-duplex).
Anyway, theorically I am supposed to see 0b00000101 on SO PIN but as you can see in the second picture.... nothing.
I have tried to change gpioInit.Pull for SO PIN on PULLUP and PULLDOWN but nothing changed. NOPULL is because that's the last thing I have tried.
The thing is I don't know where to start. My transmission seems to work (but is it actually ?). Is there anything wrong with my initialization ? Acutally my main question would be : why I don't receive any data from my EEPROM ?
Many thanks !
Write operations need some time to complete (your datasheet says 5 ms on page 4), during that time no operation other than read status is possible. Try polling the status register with the RDSR (0x05) opcode to find out when it becomes ready (bit 0). You could also check the status (bit 1) before and after issuing WREN to see if it was successful.
So the problem is now solved. Here are the improvements :
There was actually two issues. The first one and certainly the most important is, as berendi stated, a timing issue. In my WRITE function I didn't let the time for the EEPROM to complete its write cycle (5 ms on datasheet). I added the following code line at the end of all my WRITE functions :
HAL_Delay(10); //10 ms wait for the EEPROM to complete the write cycle
The delay value could be less I think if time is preicous (theorically 5ms). I didn't test below 10 ms though. An other thing. With the oscilloscope I also saw that my Chip Select used to went HIGH in the middle of my last clock edge. I could not say if this could also imply some issues since that's a thing I solved in the first place by adding a code line before HAl_Delay(10). All my SPI transmission functions finishes this way now :
while(HAL_GPIO_ReadPin(CLK_PORT, CLK_PIN) == GPIO_PIN_SET){
}
HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);
HAL_Delay(10);
This way I have the proper pattern and I can write in the EEPROM and read back what I wrote.
NB : A last thing that made me goes deeper into my misunderstanding of the events : since my write functions didn't work, I focused on STATUS REGISTER write and read function (in order to solve this step by step). The write function didn't work either and in fact it was because the WRENbit wasn't set. I though (wrong one) that the fact to write into the STATUS REGISTER didn't ask also to set WREN like the WRITE functions into the memory ask to. Actually, it is also necessary.
Thanks for the help !
I am a new to stm32f103c8t6. Now I am trying to learn the SPI function and finished the code from the RCC to SPI initialization. I used oscilloscope to measure the SPI1 SCK signal due to test equipment limitation. Indeed that is clock signal but much lower than my RCC configuration. I tried to search the reason, but still failed. So may I ask if someone knows the answer.
RCC_DeInit();
RCC_HSEConfig(RCC_HSE_ON);
Errsts = RCC_WaitForHSEStartUp();
if (Errsts == SUCCESS)
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
RCC_PLLConfig(RCC_PLLSource_HSE_Div2, RCC_PLLMul_9);
RCC_PLLCmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY == RESET))
{
}
FLASH_SetLatency(FLASH_Latency_1);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PCLK2Config(RCC_HCLK_Div1);
while (RCC_GetSYSCLKSource() != 0x08)
{
}
}
The code above shows my configuration about RCC, I used HSE as clock and the final frequency is 8Mhz/2*9=36Mhz. Below is my SPI and GPIO initialization:
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5| GPIO_Pin_6| GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_WriteBit(GPIOA, GPIO_Pin_4,Bit_SET);
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_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
/* Enable SPI2 */
SPI_Cmd(SPI1, ENABLE);
So SPI_BaudRatePrescaler=4 means my SPI clock is 36Mhz/4=9Mhz, but actually the oscilloscope shows the frequecy is around 200Khz, it is much lower the the expectation. Also I tried to config SPI_BaudRatePrescaler with different value, it seems that the outcome is not linear.
Therefore I would like to ask if someone knows the answer. Thanks a lot!
Double check your prescaler value in your configuration. According to the reference manual, a value of 4 in the baud rate field will result in a divider of 32. To get to a clock of around 200 kHz, you need a value in that register of 6 or 7, which results in a divider of 128 or 256 (281 kHz or 140 kHz). If you want a divider of 4, you'll need to put a value of 1 in there. Check and see if SPI_BaudRatePrescaler_4 results in a value of 4 in the register, or a value of 1.
The outcome is not linear because they are using it as an exponent of 2. A value of 0 is 2^(0+1), while 1 is 2^(1+1), etc, etc.