【stm32f407】SPI experimental driver W25Q128

Publisher:吾道明亮Latest update time:2019-01-31 Source: eefocusKeywords:stm32f407 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

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

}   


Keywords:stm32f407 Reference address:【stm32f407】SPI experimental driver W25Q128

Previous article:【stm32f407】CAN bus
Next article:【stm32f407】I2C experiment

Recommended ReadingLatest update time:2024-11-17 03:30

Stm32f407DISCOVEY study uart serial port baud rate summary
I have been debugging Stm32f407DISCOVEY these days. Since there is no ready-made library function routine for the serial port, I used the routine on the Shenzhouwang development board to directly debug. As a result, the serial port output is always messy, 115200 baud rate; I tried to change it to 38400 and it can actu
[Microcontroller]
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号