1. Introduction to SPI
SPI is the abbreviation of Serial Peripheral interface. As the name suggests, it is a serial peripheral device interface. It was first defined by Motorola on its MC68HCXX series processors. The SPI interface is mainly used in
EEPROM, FLASH, real-time clock, AD converter, and digital signal processor and digital signal decoder. SPI is a high-speed, full-duplex, synchronous communication bus, and is used in the chip
Only four wires are used on the pins, which saves the pins of the chip and saves space on the PCB layout, providing convenience. It is precisely because of this simple and easy-to-use feature that more and more chips are now integrated with this
Communication protocol, STM32F4 also has SPI interface. Let's take a look at the internal diagram of SPI
The SPI interface generally uses 4 lines for communication:
MISO Master device data input, slave device data output.
MOSI Master device data output, slave device data input.
SCLK clock signal, generated by the master device.
CS is the chip select signal from the device and is controlled by the master device.
As can be seen from the figure, both the master and the slave have a serial shift register. The master sends the SPI serial register to its
Write a byte to initiate a transfer. The register transmits the byte to the slave through the MOSI signal line, and the slave also returns the contents of its shift register to the master through the MISO signal line. In this way, the contents of the two shift registers are exchanged. The write and read operations of the peripheral are completed synchronously. If only a write operation is performed, the master only needs to ignore the received byte; conversely, if the master wants to read a byte from the slave, it must send a null byte to trigger the slave's transmission.
The main features of SPI are: it can send and receive serial data at the same time; it can work as a master or a slave; it provides frequency
Programming clock; sending end interrupt flag; write conflict protection; bus contention protection, etc.
Four working modes of SPI bus In order to exchange data with peripherals, the SPI module outputs serial
The serial synchronous clock polarity and phase can be configured, and the clock polarity (CPOL) has no significant impact on the transmission protocol. If CPOL=0, the idle state of the serial synchronous clock is low; if CPOL=1, the idle state of the serial synchronous clock is high. The clock phase (CPHA) can be configured to select one of two different transmission protocols for data transmission. If CPHA=0, the data is sampled on the first transition edge (rising or falling) of the serial synchronous clock; if CPHA=1, the data is sampled on the second transition edge (rising or falling) of the serial synchronous clock. The clock phase and polarity of the SPI master module and the external device communicating with it should be consistent. The bus data transmission timing under different clock phases is shown in the figure.
The SPI function of TM32F4 is very powerful. The SPI clock can reach up to 37.5Mhz, supports DMA, and can be configured as SPI
protocol or I2S protocol (supports full-duplex I2S).
2. Library Function Application
SPI
The relevant library functions and definitions are distributed in the file stm32f4xx_spi.c and the header file stm32f4xx_spi.h. The steps for configuring the master mode of STM32 are as follows:
Take SPI1 as an example
1) Configure the multiplexing function of the relevant pins and enable the SPI1 clock.
PB3, 4, and 5 (SCK., MISO, MOSI, and CS use software management), so these three are set as multiplexed IO, and the multiplexing function is AF5.
The method to enable the SPI1 clock is:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); //Enable SPI1 clock
The method to multiplex PB3, PB4, and PB5 as SPI1 pins is:
GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1); //PB3 is multiplexed as SPI1
GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1); //PB4 is multiplexed as SPI1
GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_SPI1); //PB5 is multiplexed as SPI1
At the same time, we need to set the corresponding pin mode to multiplexed function mode:
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //Multiplexing function
2) Initialize SPI1, set SPI1 working mode, etc.
This step is all set up through SPI1_CR1. We set SPI1 to host mode, set the data format to 8 bits, and then set the SCK clock polarity and sampling mode through CPOL and CPHA bits. And set the SPI1 clock frequency (maximum 37.5Mhz) and the data format (MSB first or LSB first). The function to initialize SPI in the library function is:
void SPI_Init(SPI_TypeDef* SPIx, SPI_InitTypeDef* SPI_InitStruct);
Like other peripheral initializations, the first parameter is the SPI number, here we use SPI1. Let's take a look at the definition of the second parameter structure type SPI_InitTypeDef:
typedefstruct
{
uint16_tSPI_Direction;
uint16_tSPI_Mode;
uint16_tSPI_DataSize;
uint16_tSPI_CPOL;
uint16_tSPI_CPHA;
uint16_tSPI_NSS;
uint16_tSPI_BaudRatePrescaler;
uint16_tSPI_FirstBit;
uint16_tSPI_CRCPolynomial;
}SPI_InitTypeDef;
There are many structure member variables. Let's briefly explain them:
The first parameter SPI_Direction is used to set the SPI communication mode. You can choose half-duplex, full-duplex, and serial transmission and serial reception. Here we choose full-duplex mode.
SPI_Direction_2Lines_FullDuplex。
The second parameter SPI_Mode is used to set the master-slave mode of SPI. Here we set it to the master mode SPI_Mode_Master. Of course, you can also choose the slave mode SPI_Mode_Slave if necessary.
The third parameter SPI_DataSiz is an 8-bit or 16-bit frame format selection item. Here we are using 8-bit transmission, so select SPI_DataSize_8b.
The fourth parameter SPI_CPOL is used to set the clock polarity. We set the idle state of the serial synchronous clock to a high level so we select SPI_CPOL_High.
The fifth parameter SPI_CPHA is used to set the clock phase, that is, to select the number of transition edges (rising or falling) of the serial synchronous clock at which the data is sampled. It can be the first or second edge. Here we choose the second transition edge, so select SPI_CPHA_2Edge
The sixth parameter SPI_NSS sets whether the NSS signal is controlled by hardware (NSS pin) or software. Here we control the NSS key by software instead of automatic hardware control, so select SPI_NSS_Soft.
The seventh parameter SPI_BaudRatePrescaler is very important. It is to set the SPI baud rate prescaler value, which is the parameter that determines the SPI clock. There are 8 optional values from 2 division to 256 division. During initialization, we choose the 256 division value SPI_BaudRatePrescaler_256, and the transmission speed is 84M/256=328.125KHz.
The eighth parameter SPI_FirstBit sets the data transmission order, whether the MSB bit is first or the LSB bit is first. Here we choose SPI_FirstBit_MSB high bit first.
The ninth parameter SPI_CRCPolynomial is used to set the CRC check polynomial to improve communication reliability. It only needs to be greater than 1.
After setting the above 9 parameters, we can initialize the SPI peripheral. The example format of initialization is:
SPI_InitTypeDef SPI_InitStructure;
SPI_InitStructure.SPI_Direction =SPI_Direction_2Lines_FullDuplex; //Two-line bidirectional full-duplex
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //SPI sends and receives 8-bit frame structure
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //The idle state of the serial synchronous clock is high
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //The second transition edge data is sampled
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS signal is controlled by software
SPI_InitStructure.SPI_BaudRatePrescaler =SPI_BaudRatePrescaler_256; //预分频256
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(SPI2, &SPI_InitStructure); //Initialize the peripheral SPIx register according to the specified parameters
3) Enable SPI1.
This step is to set bit6 of SPI1_CR1 to start SPI1. After starting, we can start SPI communication. The library function method to enable SPI1 is:
SPI_Cmd(SPI1, ENABLE); //Enable SPI1 peripheral
4) SPI data transmission
The communication interface of course needs to have functions for sending and receiving data. The prototype of the sending data function provided by the firmware library is:
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data);
This function is easy to understand. It writes data to the SPIx data register to achieve transmission.
The prototype of the data receiving function provided by the firmware library is:
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx) ;
This function is not difficult to understand. It reads the received data from the SPIx data register.
5) Check SPI transmission status
During SPI transmission, we often need to determine whether the data transmission is complete, whether the sending area is empty, and so on. This is achieved through the function SPI_I2S_GetFlagStatus. This function is very simple and will not be explained in detail. The method to determine whether the transmission is completed is:
SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE);
3. Library function application source code
voidSPI1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); //Enable GPIOB clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE); //Enable SPI1 clock
//GPIOFB3,4,5 initialization settings
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5; //PB3~5 multiplexing function output
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AF; //Multiplexing function
GPIO_InitStructure.GPIO_OType =GPIO_OType_PP; //Push-pull output
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd =GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure); // Initialization
GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1); //PB3 is multiplexed as SPI1
GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1); //PB4 is multiplexed as SPI1
GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_SPI1); //PB5 is multiplexed as SPI1
//Here is only for SPI port initialization
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE); //Reset SPI1
RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE); //Stop resetting SPI1
SPI_InitStructure.SPI_Direction =SPI_Direction_2Lines_FullDuplex; //Set SPI unidirectional or bidirectional data mode: SPI is set to two-line bidirectional full-duplex
SPI_InitStructure.SPI_Mode =SPI_Mode_Master; //Set SPI working mode: set to master SPI
SPI_InitStructure.SPI_DataSize =SPI_DataSize_8b; //Set the SPI data size: SPI sends and receives 8-bit frame structure
SPI_InitStructure.SPI_CPOL =SPI_CPOL_High; //The idle state of the serial synchronous clock is high
SPI_InitStructure.SPI_CPHA =SPI_CPHA_2Edge; //The second transition edge (rising or falling) of the serial synchronous clock data is sampled
SPI_InitStructure.SPI_NSS =SPI_NSS_Soft; //NSS signal is managed by hardware (NSS pin) or software (using SSI bit): internal NSS signal is controlled by SSI bit
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256; //Define the baud rate prescaler value: the baud rate prescaler value is 256
SPI_InitStructure.SPI_FirstBit =SPI_FirstBit_MSB; //Specify whether data transmission starts from the MSB bit or the LSB bit: Data transmission starts from the MSB bit
SPI_InitStructure.SPI_CRCPolynomial =7; // CRC value calculation polynomial
SPI_Init(SPI1,&SPI_InitStructure); //Initialize the peripheral SPIx registers according to the parameters specified in SPI_InitStruct
SPI_Cmd(SPI1, ENABLE); //Enable SPI peripheral
SPI1_ReadWriteByte(0xff); //Start transmission
}
//SPI1 speed setting function
//SPI speed = fAPB2/frequency division coefficient
//@refSPI_BaudRate_Prescaler:SPI_BaudRatePrescaler_2~SPI_BaudRatePrescaler_256
//fAPB2 clock is generally 84Mhz:
voidSPI1_SetSpeed(u8 SPI_BaudRatePrescaler)
{
assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler)); //Judge validity
SPI1->CR1&=0XFFC7; // bits 3-5 are cleared to set the baud rate
SPI1->CR1|=SPI_BaudRatePrescaler; //Set SPI1 speed
SPI_Cmd(SPI1,ENABLE); //Enable SPI1
}
//SPI1 reads and writes a byte
//TxData: Bytes to be written
//Return value: the bytes read
u8SPI1_ReadWriteByte(u8 TxData)
{
while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET){}//Wait for the send area to be empty
SPI_I2S_SendData(SPI1, TxData); //Send a byte of data through peripheral SPIx
while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) == RESET){} //Wait for receiving a byte
return SPI_I2S_ReceiveData(SPI1); //Return the data most recently received via SPIx
}
4. Introduction of W25Q128
W25Q128 is a large-capacity SPI FLASH product launched by Winbond. The capacity of W25Q128 is 128Mb. This series also includes W25Q80/16/32/64, etc.
W25Q128 divides the 16M capacity into 256 blocks, each block is 64K bytes, each block is divided into 16 sectors, each sector is 4K bytes. The minimum erase unit of W25Q128 is a sector, which means that 4K bytes must be erased each time. In this way, we need to open up a cache area of at least 4K for W25Q128, which has a relatively high requirement on SRAM. The chip must have more than 4K SRAM to operate well.
W25Q128 has an erase/write cycle of up to 10W times, a data retention period of 20 years, and supports a voltage range of 2.7~3.6V.
W25Q128 supports standard SPI and dual-output/quad-output SPI. The maximum SPI clock can reach 80Mhz (equivalent to 160Mhz for dual output and 320Mhz for quad output). For more information about W25Q128, please refer to the DATASHEET of W25Q128.
5. SPI Operation W25Q128
1. Read Manufacturer / Device ID(90h)
Programs and timing diagrams correspond one to one
The program means: first select the chip, select W25Q128, then send the command and address, then read the ID, and then cancel the chip select
2. Sector Erase (20h)
The corresponding timing diagram is
The program means to select 25Q128, then send the command and address, then cancel the chip select and wait for the erase to complete.
3.Read Data (03h)
The corresponding timing diagram is:
Only these three are introduced. You can refer to the datasheet to read the source code. The source code will be attached later.
6. Operating W25Q128 source code
W25qxx.h
#ifndef__W25QXX_H
#define__W25QXX_H
#include"sys.h"
//W25X series/Q series chip list
//W25Q80 ID 0XEF13
//W25Q16 ID 0XEF14
//W25Q32 ID 0XEF15
//W25Q64 ID 0XEF16
//W25Q128ID 0XEF17
#defineW25Q80 0XEF13
#defineW25Q16 0XEF14
#defineW25Q32 0XEF15
#defineW25Q64 0XEF16
#defineW25Q128 0XEF17
externu16 W25QXX_TYPE; //define W25QXX chip model
#define W25QXX_CS PBout(14) //W25QXX chip select signal
//////////////////////////////////////////////////////////////////////////////////
//Instruction table
#defineW25X_WriteEnable 0x06
#defineW25X_WriteDisable 0x04
#defineW25X_ReadStatusReg 0x05
#defineW25X_WriteStatusReg 0x01
#defineW25X_ReadData 0x03
#defineW25X_FastReadData 0x0B
#defineW25X_FastReadDual 0x3B
#defineW25X_PageProgram 0x02
#defineW25X_BlockErase 0xD8
#defineW25X_SectorErase 0x20
#defineW25X_ChipErase 0xC7
#defineW25X_PowerDown 0xB9
#defineW25X_ReleasePowerDown 0xAB
#defineW25X_DeviceID 0xAB
#defineW25X_ManufactDeviceID 0x90
#defineW25X_JedecDeviceID 0x9F
voidW25QXX_Init(void);
u16 W25QXX_ReadID(void); //Read FLASH ID
u8 W25QXX_ReadSR(void); //Read status register
voidW25QXX_Write_SR(u8 sr); //Write status register
voidW25QXX_Write_Enable(void); //Write enable
voidW25QXX_Write_Disable(void); //Write protection
voidW25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);
voidW25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead); //读取flash
voidW25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);//写入flash
voidW25QXX_Erase_Chip(void); // Erase the entire chip
voidW25QXX_Erase_Sector(u32 Dst_Addr); // sector erase
voidW25QXX_Wait_Busy(void); //Wait for idle time
voidW25QXX_PowerDown(void); //Enter power-down mode
voidW25QXX_WAKEUP(void); //Wake up
#endif
W25qxx.c
#include"w25qxx.h"
#include"spi.h"
#include"delay.h"
#include"usart.h"
u16W25QXX_TYPE=W25Q128; //The default is W25Q128
//4Kbytes is a Sector
//16 sectors make up 1 Block
//W25Q128
//The capacity is 16M bytes, with a total of 128 blocks and 4096 sectors
//Initialize the SPI FLASH IO port
voidW25QXX_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); //Enable GPIOB clock
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG,ENABLE); //Enable GPIOG clock
//GPIOB14
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_14;//PB14
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_OUT;//输出
GPIO_InitStructure.GPIO_OType =GPIO_OType_PP; //Push-pull output
GPIO_InitStructure.GPIO_Speed =GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd =GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure); // Initialization
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_7;//PG7
GPIO_Init(GPIOG, &GPIO_InitStructure); // Initialization
GPIO_SetBits(GPIOG,GPIO_Pin_7); //PG7 outputs 1 to prevent NRF from interfering with SPI FLASH communication
W25QXX_CS=1; //SPI FLASH is not selected
SPI1_Init(); //Initialize SPI
SPI1_SetSpeed(SPI_BaudRatePrescaler_4); //Set to 21M clock, high speed mode
W25QXX_TYPE=W25QXX_ReadID(); //Read FLASH ID.
}
//Read the status register of W25QXX
//BIT7 6 5 4 3 2 1 0
//SPR RV TBBP2 BP1 BP0 WEL BUSY
//SPR: default 0, status register protection bit, used with WP
//TB,BP2,BP1,BP0: FLASH area write protection setting
//WEL: Write Enable Lock
//BUSY: busy flag (1, busy; 0, idle)
//Default: 0x00
u8W25QXX_ReadSR(void)
{
u8 byte=0;
W25QXX_CS=0; //Enable device
SPI1_ReadWriteByte(W25X_ReadStatusReg); //Send the read status register command
byte=SPI1_ReadWriteByte(0Xff); //Read a byte
W25QXX_CS=1; //Cancel chip select
return byte;
}
//Write W25QXX status register
//Only SPR, TB, BP2, BP1, BP0 (bit7, 5, 4, 3, 2) can be written!!!
voidW25QXX_Write_SR(u8 sr)
{
W25QXX_CS=0; //Enable device
SPI1_ReadWriteByte(W25X_WriteStatusReg); //Send the command to write the status register
SPI1_ReadWriteByte(sr); //Write a byte
W25QXX_CS=1; //Cancel chip select
}
//W25QXX write enable
//Set WEL
voidW25QXX_Write_Enable(void)
{
W25QXX_CS=0; //Enable device
SPI1_ReadWriteByte(W25X_WriteEnable); //Send write enable
W25QXX_CS=1; //Cancel chip select
}
//W25QXX write disabled
// Clear WEL
voidW25QXX_Write_Disable(void)
{
W25QXX_CS=0; //Enable device
SPI1_ReadWriteByte(W25X_WriteDisable); //Send write disable command
W25QXX_CS=1; //Cancel chip select
}
//Read chip ID
//The return value is as follows:
//0XEF13, indicating the chip model is W25Q80
//0XEF14, indicating the chip model is W25Q16
//0XEF15, indicating the chip model is W25Q32
//0XEF16, indicating the chip model is W25Q64
//0XEF17, indicating the chip model is W25Q128
u16W25QXX_ReadID(void)
{
u16 Temp = 0;
W25QXX_CS=0;
SPI1_ReadWriteByte(0x90); //Send read ID command
SPI1_ReadWriteByte(0x00);
SPI1_ReadWriteByte(0x00);
SPI1_ReadWriteByte(0x00);
Temp|=SPI1_ReadWriteByte(0xFF)<<8;
Temp|=SPI1_ReadWriteByte(0xFF);
W25QXX_CS=1;
return Temp;
}
//Read SPIFLASH
//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)
voidW25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)
{
u16i;
W25QXX_CS=0; //Enable device
SPI1_ReadWriteByte(W25X_ReadData); //Send read command
SPI1_ReadWriteByte((u8)((ReadAddr)>>16)); //Send 24-bit address
SPI1_ReadWriteByte((u8)((ReadAddr)>>8));
SPI1_ReadWriteByte((u8)ReadAddr);
for(i=0;i { pBuffer[i]=SPI1_ReadWriteByte(0XFF); //Loop reading } W25QXX_CS=1; } //SPI writes less than 256 bytes of data in one page (0~65535) //Start writing data up to 256 bytes at the specified address //pBuffer: data storage area //WriteAddr: start writing address (24bit) //NumByteToWrite: The number of bytes to be written (maximum 256), this number should not exceed the remaining bytes of the page!!! voidW25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite) { u16i; W25QXX_Write_Enable(); //SET WEL W25QXX_CS=0; //Enable device SPI1_ReadWriteByte(W25X_PageProgram); //Send write page command SPI1_ReadWriteByte((u8)((WriteAddr)>>16)); //Send 24-bit address SPI1_ReadWriteByte((u8)((WriteAddr)>>8)); SPI1_ReadWriteByte((u8)WriteAddr); for(i=0;i W25QXX_CS=1; //Cancel chip select W25QXX_Wait_Busy(); //Wait for writing to end } //Write SPI FLASH without checking // Make sure that all data in the address range you write is 0XFF, otherwise data written at non-0XFF will fail! //With automatic page change function //Start writing data of the specified length at the specified address, but make sure the address does not cross the boundary! //pBuffer: data storage area //WriteAddr: start writing address (24bit) //NumByteToWrite: the number of bytes to be written (maximum 65535) //CHECKOK voidW25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite) { u16 pageremain; pageremain=256-WriteAddr%256; //Number of bytes remaining in a single page if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite; //No more than 256 bytes while(1) { W25QXX_Write_Page(pBuffer,WriteAddr,pageremain); if(NumByteToWrite==pageremain)break;//Writing is finished else //NumByteToWrite>pageremain { pBuffer+=pageremain; WriteAddr+=pageremain; NumByteToWrite-=pageremain; //Subtract the number of bytes already written if(NumByteToWrite>256)pageremain=256; //256 bytes can be written at a time elsepageremain=NumByteToWrite; //Not enough 256 bytes } }; } //Write SPIFLASH //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) u8W25QXX_BUFFER[4096]; voidW25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite) { u32 secpos; u16 secoff; u16 secremain; u16i; u8 * W25QXX_BUF; W25QXX_BUF=W25QXX_BUFFER; secpos=WriteAddr/4096; //sector address secoff=WriteAddr%4096; //Offset within the sector secremain=4096-secoff; //Sector remaining space size //printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//for testing if(NumByteToWrite<=secremain)secremain=NumByteToWrite; //No more than 4096 bytes while(1) { W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//Read the contents of the entire sector for(i=0;i { if(W25QXX_BUF[secoff+i]!=0XFF)break;//need to erase } if(i { W25QXX_Erase_Sector(secpos); //Erase this sector for(i=0;i { W25QXX_BUF[i+secoff]=pBuffer[i]; } W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//Write the entire sector }elseW25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//Write what has been erased, 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 elsesecremain=NumByteToWrite; //The next sector can be written } }; } // Erase the entire chip //Waiting time is too long... voidW25QXX_Erase_Chip(void) { W25QXX_Write_Enable(); //SET WEL W25QXX_Wait_Busy(); W25QXX_CS=0; //Enable device SPI1_ReadWriteByte(W25X_ChipErase); //Send chip erase command W25QXX_CS=1; //Cancel chip select W25QXX_Wait_Busy(); //Wait for chip erasure to end } // Erase a sector //Dst_Addr: sector address is set according to actual capacity //Minimum time to erase a mountain area: 150ms voidW25QXX_Erase_Sector(u32 Dst_Addr) { //Monitor falsh erasure, for testing printf("fe:%x\r\n",Dst_Addr); Dst_Addr*=4096; W25QXX_Write_Enable(); //SET WEL W25QXX_Wait_Busy(); W25QXX_CS=0; //Enable device SPI1_ReadWriteByte(W25X_SectorErase); //Send sector erase command SPI1_ReadWriteByte((u8)((Dst_Addr)>>16)); //Send 24-bit address SPI1_ReadWriteByte((u8)((Dst_Addr)>>8)); SPI1_ReadWriteByte((u8)Dst_Addr); W25QXX_CS=1; //Cancel chip select W25QXX_Wait_Busy(); //Wait for erasing to complete } //Wait for free time voidW25QXX_Wait_Busy(void) { while((W25QXX_ReadSR()&0x01)==0x01); // Wait for BUSY bit to clear } //Enter power-down mode void W25QXX_PowerDown(void) { W25QXX_CS=0; //Enable device SPI1_ReadWriteByte(W25X_PowerDown); //Send power-down command W25QXX_CS=1; //Cancel chip select delay_us(3); //Wait for TPD } //wake voidW25QXX_WAKEUP(void) { W25QXX_CS=0; //Enable device SPI1_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB W25QXX_CS=1; //Cancel chip select delay_us(3); //Wait for TRES1 }
Previous article:【stm32f407】CAN bus
Next article:【stm32f407】I2C experiment
Recommended ReadingLatest update time:2024-11-17 03:30
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!
- Rambus Launches Industry's First HBM 4 Controller IP: What Are the Technical Details Behind It?
- 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
- [Starting at 13:30 pm] TI wireless connectivity product series application design guidance, online hands-on demo
- Inductance and Q value of transformer
- MSP430 ADC analog-to-digital routines
- Shenying series SY-Y1000 intelligent partition long-range laser perimeter warning radar
- DSP online upgrade procedure steps
- The nonlinearity of the diode will cause some new waveforms to be generated. What is the underlying formation principle? Who can explain it to me?
- The weekly review information is here~ The fresh delivery is here
- STM32F030 AD signal acquisition
- Does anyone have a working stm32F7 or H7 fmc interface lcd driver? I've been having a lot of trouble with it recently.
- The output data of the ADC chip is incorrect no matter how I process it. Please help.