STM32 SPI flash read and write test experiment report
1. Experimental Purpose
1. Learn the basic working principle of SPI
2. Deepen your understanding of STM32SPI through experiments
3. Use STM32's SPI11 and SPI interface flash chip to communicate, read and write tests, and print the test results through the serial port
2. Experimental Principle
1. SPI Basics
SPI Features
● 3-wire full-duplex synchronous transmission
● Two-wire simplex synchronous transmission with or without a third bidirectional data line
● 8 or 16 bit transmission frame format selection
● Master or slave operation
● Support multi-master mode
● 8 master mode baud rate pre-scaling factors (maximum fPCLK/2)
● Slave mode frequency (maximum fPCLK/2)
● Fast communication between master mode and slave mode
● NSS management can be performed by software or hardware in both master and slave modes: Dynamic change of master/slave operation mode
● Programmable clock polarity and phase
● Programmable data order, MSB first or LSB first
● Dedicated transmit and receive flags that can trigger interrupts
● SPI bus busy status flag
● Hardware CRC to support reliable communication
─ In transmit mode, the CRC value can be sent as the last byte
─ Automatic CRC check on the last byte received in full-duplex mode
● Master mode fault, overload and CRC error flags that can trigger interrupts
● 1-byte transmit and receive buffer supporting DMA function: generates transmit and receive requests
Slave Select (NSS) Foot Management
There are 2 NSS modes:
Figure 211 ● Software NSS mode: This mode can be enabled by setting the SSM bit in the SPI_CR1 register (see ).
In this mode, the NSS pin can be used for other purposes, and the internal NSS signal level can be driven by writing the SSI bit of SPI_CR1.
● Hardware NSS mode, divided into two situations:
─NSS output is enabled: When the STM32F10xxx works as the master SPI, and the NSS output has been registered via SPI_CR2
The SSOE bit of the SPI master is enabled, and the NSS pin is pulled low. All NSS pins are connected to the NSS pin of the master SPI.
SPI devices configured as hardware NSS will automatically become slave SPI devices.
When an SPI device needs to send broadcast data, it must pull down the NSS signal to notify all other devices that it is the master.
device; if it cannot pull NSS low, it means that there is another master device communicating on the bus, and a
Hardware failure error (Hard Fault).
─NSS output is disabled: allows operation in a multi-master environment.
The phase and polarity of the clock signal can be combined into four different modes. The following are two of them.
Data frame format
The data bits can be output MSB first or LSB first, depending on the LSBFIRST bit in the SPI_CR1 register.
Each data frame can be 8 or 16 bits depending on the DFF bit in the SPI_CR1 register. The selected data frame format is valid for both transmission and/or reception.
Configure SPI to master mode
In master configuration, a serial clock is generated on the SCK pin.
Configuration steps
1. Define the serial clock baud rate by the BR[2:0] bits in the SPI_CR1 register.
2. Select the CPOL and CPHA bits to define the phase relationship between the data transmission and the serial clock (see Figure 212).
3. Set the DFF bit to define 8-bit or 16-bit data frame format.
4. Configure the LSBFIRST bit of the SPI_CR1 register to define the frame format.
5. If the NSS pin is required to work in input mode, in hardware mode, the NSS pin should be connected to
to high level; in software mode, the SSM bit and SSI bit of the SPI_CR1 register need to be set.
In output mode, just set the SSOE bit.
6. The MSTR bit and the SPE bit must be set (these bits will only remain set if the NSS pin is tied high).
In this configuration, the MOSI pin is the data output and the MISO pin is the data input.
The SPI module can operate in simplex mode in two configurations:
● 1 clock line and 1 bidirectional data line;
● 1 clock line and 1 data line (receive only or send only);
SPI communication can use CRC by following the steps below:
● Set the values of CPOL, CPHA, LSBFirst, BR, SSM, SSI, and MSTR;
● Enter the polynomial in the SPI_CRCPR register;
● Enable CRC calculation by setting the CRCEN bit in the SPI_CR1 register. This operation will also clear the SPI_RXCRCR register.
and SPI_TXCRC;
● Set the SPE bit of the SPI_CR1 register to start the SPI function;
● Start communication and maintain communication until only the last byte or half word remains;
● When writing the last byte or half word into the transmit buffer, set the CRCNext bit of SPI_CR1 to instruct the hardware to
After sending the last data, send the CRC value. Stop CRC calculation during sending the CRC value.
● After the last byte or half word is sent, the SPI sends the CRC value and the CRCNext bit is cleared.
The CRC of the SPI_RX is compared with the SPI_RXCRCR value and if the comparison does not match, the CRCERR flag on the SPI_SR is set
When the ERRIE bit of the SPI_CR2 register is set, an interrupt is generated.
Personal understanding: CRC check, the sender calculates the CRC value, the receiver calculates the CRC value, and then the sender sends the calculated CRC value. After receiving it, the receiver compares it with the value calculated by the receiver. If they are different, an error flag is returned
SPI communication using DMA
In order to achieve the maximum communication speed, the SPI transmit buffer needs to be filled with data in a timely manner, and the data in the receive buffer must also be filled in a timely manner.
To facilitate high-speed data transfer, SPI implements a DMA that uses a simple request/response
mechanism.
When the corresponding enable bit in the SPI_CR2 register is set, the SPI module can issue a DMA transfer request.
The receive buffers also have their own DMA requests (see ).
● When sending, a DMA request is issued every time TXE is set to '1', and the DMA controller writes data to the SPI_DR register.
The TXE flag is cleared.
● When receiving, a DMA request is issued each time RXNE is set to '1', and the DMA controller reads the data from the SPI_DR register.
According to the RXNE flag, it is cleared.
When only using SPI to send data, you only need to enable the SPI's transmit DMA channel. At this time, because there is no received data to read,
OVR is set to '1' (Translator's note: software does not need to pay attention to this flag).
When only using SPI to receive data, you only need to enable the SPI receive DMA channel.
SPI Registers
SPI Control Register 1 SPI_CR1
(For the function of each bit, refer to page 486 of the data sheet)
SPI Control Register 2 (SPI_CR2)
SPI Status Register (SPI_SR)
SPI Data Register (SPI_DR)
SPI CRC Polynomial Register
SPI Rx CRC Register (SPI_RXCRCR)
When CRC calculation is enabled, RXCRC[15:0] contains the CRC value calculated based on the received bytes.
This register is reset when the CRCEN bit is written to '1'. The CRC calculation uses the polynomial in SPI_CRCPR.
When the data frame format is set to 8 bits, only the lower 8 bits are involved in the calculation and the calculation is performed according to the CRC8 method; when the data frame format is set to 8 bits, only the lower 8 bits are involved in the calculation and the calculation is performed according to the CRC8 method;
When it is 16 bits, all 16 bits in the register are involved in the calculation and follow the CRC16 standard.
SPI Tx CRC Register (SPI_TXCRCR)
When CRC calculation is enabled, TXCRC[15:0] contains the CRC value calculated based on the bytes to be transmitted.
This register is reset when the CRCEN bit in SPI_CR1 is written as '1'. The CRC calculation uses multiple bits in SPI_CRCPR.
Mode.
When the data frame format is set to 8 bits, only the lower 8 bits are involved in the calculation and the calculation is performed according to the CRC8 method; when the data frame format is set to 8 bits, only the lower 8 bits are involved in the calculation and the calculation is performed according to the CRC8 method;
When the bit is 16, all 16 bits in the register are involved in the calculation and follow the CRC16 standard.
2. Experimental circuit diagram
W25X16 has 8192 programmable pages, each with 256 bytes. You can program 256 bytes at a time using the "page programming instruction". You can erase 16 pages at a time using the "sector instruction", 256 pages at a time using the "block erase instruction", and the entire chip can be erased using the "whole chip erase instruction". W25X16 has 512 erasable sectors or 32 erasable blocks.
W25X16 supports standard SPI interface with a maximum transmission rate of 75MHz.
Dual output SPI mode
W25X16 supports SPI dual output mode, which requires the use of "fast read dual output command 0x3B". At this time, the transmission rate is equivalent to twice the standard SPI rate. This command is very suitable for situations where you need to quickly download code to memory as soon as power is turned on or when you need to cache code segments to memory for operation. After using the "fast dual output command", the DIO pin becomes an output pin.
Instructions: Write Enable, Page Program, Sector Erase, Block Erase, Chip Erase, Write Status Register
3. Experimental Content
software design
Configure the STM32 SPI as master mode to read the SPI flash to implement read and write functions.
The SPI1 part is configured below.
In master mode, the SCK pin outputs the serial clock.
Configuration steps:
1) Configure the SPI serial clock bit rate
2) Define the phase relationship between data transmission and serial
3) Set 8-bit or 16-bit data frame format
4) If the NSS pin is required to work in input mode, in hardware mode, the NSS pin should be connected to a high level during the entire data frame transmission. In software mode, the SSM bit and SSI bit of SPI1_CR1 need to be set. If the NSS pin works in output mode, the SSOE bit needs to be set.
5) The MSTR and SPE bits must be set (these bits will only remain set if the NSS pin is tied high)
//Initialization of the serial peripheral interface SPI, SPI is configured into master mode
//This example uses SPI1 to read and write W25X16, and initializes SPI1
void SPIx_Init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable SPI1 and GPIOA clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOC|RCC_APB2Periph_SPI1|RCC_APB2Periph_AFIO, ENABLE);
/* Configure SPI1 pins: NSS, SCK, MISO and MOSI */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//SPI1 NSS
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC, GPIO_Pin_4);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_4);
/* SPI1 configuration */
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //SPI1 is set to two-line full-duplex
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //Set SPI1 to master mode
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI sends and receives 8-bit frame structure
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //When the serial clock is not in operation, the clock is high
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //Start sampling data at the second clock edge
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS signal is managed by software (using SSI bit)
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //Define the baud rate prescaler value: the baud rate prescaler value is 8
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //Data transmission starts from the MSB bit
SPI_InitStructure.SPI_CRCPolynomial = 7; // CRC value calculation polynomial
SPI_Init(SPI1, &SPI_InitStructure);
/* Enable SPI1 */
SPI_Cmd(SPI1, ENABLE); //Enable SPI1 peripheral
}
SPI interface reads and writes Flash one byte
//SPIx read and write a byte
//Return value: the bytes read
u8 SPIx_ReadWriteByte(u8 TxData)
{
u8 retry=0;
while((SPI1->SR&1<<1)==0)//Wait for the send area to be empty
{
retry++;
if(retry>200)return 0;
}
SPI1->DR=TxData; //Send a byte
retry=0;
while((SPI1->SR&1<<0)==0) //Wait for receiving a byte
{
retry++;
if(retry>200)return 0;
}
return SPI1->DR; //Return received data
}
Get SPI flash ID
//Read chip ID W25X16 ID: 0XEF14
u16 SPI_Flash_ReadID(void)
{
u16 Temp = 0;
SPI_FLASH_CS=0;
SPIx_ReadWriteByte(0x90); //Send read ID command
SPIx_ReadWriteByte(0x00);
SPIx_ReadWriteByte(0x00);
SPIx_ReadWriteByte(0x00);
Temp|=SPIx_ReadWriteByte(0xFF)<<8;
Temp|=SPIx_ReadWriteByte(0xFF);
SPI_FLASH_CS=1;
return Temp;
}
Start reading data of the specified length at the specified position
//Read SPI FLASH
//Start reading data of the specified length at the specified address
//pBuffer: data storage area
//ReadAddr: start reading address (24bit)
//NumByteToRead: the number of bytes to read (maximum 65535)
void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)
{
u16 i;
SPI_FLASH_CS=0; //Enable device
SPIx_ReadWriteByte(W25X_ReadData); //Send read command
SPIx_ReadWriteByte((u8)((ReadAddr)>>16)); //Send 24-bit address
SPIx_ReadWriteByte((u8)((ReadAddr)>>8));
SPIx_ReadWriteByte((u8)ReadAddr);
for(i=0;i { pBuffer[i]=SPIx_ReadWriteByte(0XFF); //Loop reading } SPI_FLASH_CS=1; //Cancel chip select } Write data of specified length at specified location //Write SPI FLASH //Start writing data of the specified length at the specified address //This function has erase operation! //pBuffer: data storage area //WriteAddr: start writing address (24bit) //NumByteToWrite: the number of bytes to be written (maximum 65535) u8 SPI_FLASH_BUF[4096]; void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite) { u32 secpos; u16 secoff; u16 secremain; u16 i; secpos=WriteAddr/4096; //sector address 0~511 for w25x16 secoff=WriteAddr%4096; //Offset within the sector secremain=4096-secoff; //Sector remaining space size if(NumByteToWrite<=secremain)secremain=NumByteToWrite; //No more than 4096 bytes while(1) { SPI_Flash_Read(SPI_FLASH_BUF,secpos*4096,4096);//Read the contents of the entire sector for(i=0;i { if(SPI_FLASH_BUF[secoff+i]!=0XFF)break;//need to erase } if(i { SPI_Flash_Erase_Sector(secpos); //Erase this sector for(i=0;i { SPI_FLASH_BUF[i+secoff]=pBuffer[i]; } SPI_Flash_Write_NoCheck(SPI_FLASH_BUF,secpos*4096,4096);//Write the entire sector }else SPI_Flash_Write_NoCheck(pBuffer,WriteAddr,secremain);//Write the erased content and directly write to the remaining area of the sector. if(NumByteToWrite==secremain)break;//Writing is finished else //Writing is not finished { secpos++; //sector address increment by 1 secoff=0; //Offset position is 0 pBuffer+=secremain; //Pointer offset WriteAddr+=secremain; //write address offset NumByteToWrite-=secremain; //Number of bytes decreases if(NumByteToWrite>4096)secremain=4096; //The next sector still cannot be written else secremain=NumByteToWrite; //The next sector can be written } }; } In the main function, first write the data of the specified length into the Flash, then read and print it to the serial port, compare the read and written data, and display the result to the serial port. int main(void) { u8 i=0; u8 datatemp[SIZE]; GPIO_Configuration(); USART_Configuration(); GPIO_SetBits(GPIOF, GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9); SPI_Flash_Init(); while(SPI_Flash_ReadID()!=FLASH_ID) //Cannot detect W25X16 { i=SPI_Flash_ReadID(); printf("\n\r ID:%d",i); printf("\n\rThe correct W25X16 chip ID was not read, please check the hardware connection"); Delay(0xaFFFF); Delay(0xaFFFF); GPIO_ResetBits(GPIOF, GPIO_Pin_7); GPIO_SetBits(GPIOF, GPIO_Pin_7); } printf("\n\rStart writing to W25X16 SPI FLASH chip...."); SPI_Flash_Write((u8*)TEXT_Buffer,1000,SIZE);//Starting from 1000 bytes, write data of SIZE length printf("\n\rWrite completed!"); //Prompt that the transfer is completed printf("\n\r"); Delay(0xFFFFFF); printf("\n\r"); printf("\n\rStart reading data from W25X16 SPI FLASH chip.... "); SPI_Flash_Read(datatemp,1000,10000); //Start from address 1000 and read SIZE bytes printf("\n\rReading completed, the data read is: %s ",datatemp); //Prompt that the transmission is completed while(1) { i++; Delay(0xFFFF); if(i>0&& i<100) { GPIO_SetBits(GPIOF, GPIO_Pin_6); //Prompt that the system is running } else if(i >= 100 && i < 200) { GPIO_ResetBits(GPIOF, GPIO_Pin_6); //Prompt that the system is running } i = i % 200; } }
Previous article:STM32CubeMX learning tutorial 1: GPIO output marquee
Next article:STM32CubeMX tutorial introduction and basic use
Recommended ReadingLatest update time:2024-11-16 15:04
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- MSP430 MCU Development Record (12)
- EEWORLD University Hall----Choosing the latest boost converter and Class D amplifier from Texas Instruments to significantly increase the battery life of the trolley speakers
- Award-winning live broadcast | TI Embedded Live Broadcast Month is waiting for you [Low-power Wi-Fi MCU, Sitara AM57X platform, machine learning]
- SPI settings for msp430f149
- Please recommend a board
- Streamlining mobile phone system design
- EEWORLD University - High-Speed Transimpedence Amplifier Design Process
- PCB
- Please help analyze this statement IS_RCC_APB2_PERIPH(PERIPH)
- At the age of thirty, I am penniless and have nothing to lose. I have to start all over again!!!