STM32F4 HAL库开发 -- SPI Flash
生活随笔
收集整理的這篇文章主要介紹了
STM32F4 HAL库开发 -- SPI Flash
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、驅動
bsp_spi_flash.c
#include "THC_Board_include_h.h"/* Private define ------------------------------------------------------------*/ #define W25X_WriteEnable 0x06 //寫使能 #define W25X_WriteDisable 0x04 //寫失能#define W25X_ReadStatusReg_1 0x05 //讀控制和狀態寄存器 #define W25X_ReadStatusReg_2 0x35 //讀控制和狀態寄存器 #define W25X_ReadStatusReg_3 0x15 //讀控制和狀態寄存器#define W25X_WriteStatusReg_1 0x01 //寫控制和狀態寄存器 #define W25X_WriteStatusReg_2 0x31 //寫控制和狀態寄存器 #define W25X_WriteStatusReg_3 0x11 //寫控制和狀態寄存器#define W25X_ReadData 0x03 //讀數據 #define W25X_FastReadData 0x0B //快速讀數據 #define W25X_FastReadDual 0x3B #define W25X_PageProgram 0x02 //頁編程 #define W25X_BlockErase 0xD8 //64kB塊擦除 #define W25X_SectorErase 0x20 //扇區擦除 #define W25X_ChipErase 0xC7 //整片擦除 #define W25X_PowerDown 0xB9 #define W25X_ReleasePowerDown 0xAB #define W25X_DeviceID 0xAB #define W25X_ManufactDeviceID 0x90 #define W25X_JedecDeviceID 0x9F #define WIP_FlagMask 0x01 /* Write In Progress (WIP) flag */#define Dummy_Byte 0xA5 //w25q80//#define Dummy_Byte 0xFF //w25q128 //SPI1 讀寫一個字節 //TxData:要寫入的字節 //返回值:讀取到的字節/**-----------------------------------------------------------------* @函數名 SPI_FLASH_SectorErase* @功能 擦除SPI FLASH一個扇區的驅動函數* Erases the specified FLASH sector.* @參數 SectorAddr: 扇區地址 address of the sector to erase.* @返回值 無 ***----------------------------------------------------------------*/ void SPI_FLASH_SectorErase(uint32_t SectorAddr) {/* Send write enable instruction */SPI_FLASH_WriteEnable();/* Sector Erase *//* Select the FLASH: Chip Select low */SPI2_FLASH_CS_LOW();/* Send Sector Erase instruction */SPI_FLASH_SendByte(W25X_SectorErase);/* Send SectorAddr high nibble address byte */SPI_FLASH_SendByte((SectorAddr & 0xFF0000) >> 16);/* Send SectorAddr medium nibble address byte */SPI_FLASH_SendByte((SectorAddr & 0xFF00) >> 8);/* Send SectorAddr low nibble address byte */SPI_FLASH_SendByte(SectorAddr & 0xFF);/* Deselect the FLASH: Chip Select high */SPI2_FLASH_CS_HIGH();/* Wait the end of Flash writing */SPI_FLASH_WaitForWriteEnd(); }/**-----------------------------------------------------------------* @函數名 SPI_FLASH_ChipErase* @功能 擦除整個SPI FLASH的驅動函數* Erases the entire FLASH.* @參數 無* @返回值 無 ***----------------------------------------------------------------*/ void SPI_FLASH_ChipErase(void) {/* Send write enable instruction */SPI_FLASH_WriteEnable();/* Bulk Erase *//* Select the FLASH: Chip Select low */SPI2_FLASH_CS_LOW();/* Send Bulk Erase instruction */SPI_FLASH_SendByte(W25X_ChipErase);/* Deselect the FLASH: Chip Select high */SPI2_FLASH_CS_HIGH();/* Wait the end of Flash writing */SPI_FLASH_WaitForWriteEnd(); }/**-----------------------------------------------------------------* @函數名 SPI_FLASH_PageWrite* @功能 單個寫周期寫入大于一個字節而小于等于一頁大小的數據* Writes more than one byte to the FLASH with a single * WRITE cycle(Page WRITE sequence). The number of byte * can't exceed the FLASH page size.* @參數 - pBuffer : 指向包含寫入數據緩沖器的地址指針* pointer to the buffer containing the data to be* written to the FLASH.* - WriteAddr : flash的寫入地址* FLASH's internal address to write to.* - NumByteToWrite : 寫入的字節數* number of bytes to write to the FLASH, must be* equal or less than "SPI_FLASH_PageSize" value.* @返回值 無 ***----------------------------------------------------------------*/ void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) {/* Enable the write access to the FLASH */SPI_FLASH_WriteEnable();/* Select the FLASH: Chip Select low */SPI2_FLASH_CS_LOW();/* Send "Write to Memory " instruction */SPI_FLASH_SendByte(W25X_PageProgram);/* Send WriteAddr high nibble address byte to write to */SPI_FLASH_SendByte((WriteAddr & 0xFF0000) >> 16);/* Send WriteAddr medium nibble address byte to write to */SPI_FLASH_SendByte((WriteAddr & 0xFF00) >> 8);/* Send WriteAddr low nibble address byte to write to */SPI_FLASH_SendByte(WriteAddr & 0xFF);if(NumByteToWrite > SPI_FLASH_PerWritePageSize){NumByteToWrite = SPI_FLASH_PerWritePageSize;}/* while there is data to be written on the FLASH */while (NumByteToWrite--){/* Send the current byte */SPI_FLASH_SendByte(*pBuffer);/* Point on the next byte to be written */pBuffer++;}/* Deselect the FLASH: Chip Select high */SPI2_FLASH_CS_HIGH();/* Wait the end of Flash writing */SPI_FLASH_WaitForWriteEnd(); }/**-----------------------------------------------------------------* @函數名 SPI_FLASH_BufferWrite* @功能 向SPI FLASH寫入一堆數據,寫入的字節數可以大于一頁容量* Writes block of data to the FLASH. In this function,* the number of WRITE cycles are reduced,* using Page WRITE sequence.* @參數 - pBuffer : 指向包含寫入數據緩沖器的地址指針* pointer to the buffer containing the data to be* written to the FLASH.* - WriteAddr : flash的寫入地址* FLASH's internal address to write to.* - NumByteToWrite : 寫入的字節數* number of bytes to write to the FLASH.* @返回值 無 ***----------------------------------------------------------------*/ void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite) {uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;Addr = WriteAddr % SPI_FLASH_PageSize;count = SPI_FLASH_PageSize - Addr;NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;if (Addr == 0) /* WriteAddr is SPI_FLASH_PageSize aligned */{if (NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */{SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);}else /* NumByteToWrite > SPI_FLASH_PageSize */{while (NumOfPage--){SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);WriteAddr += SPI_FLASH_PageSize;pBuffer += SPI_FLASH_PageSize;}SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);}}else /* WriteAddr is not SPI_FLASH_PageSize aligned */{if (NumOfPage == 0) /* NumByteToWrite < SPI_FLASH_PageSize */{if (NumOfSingle > count) /* (NumByteToWrite + WriteAddr) > SPI_FLASH_PageSize */{temp = NumOfSingle - count;SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);WriteAddr += count;pBuffer += count;SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);}else{SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);}}else /* NumByteToWrite > SPI_FLASH_PageSize */{NumByteToWrite -= count;NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);WriteAddr += count;pBuffer += count;while (NumOfPage--){SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);WriteAddr += SPI_FLASH_PageSize;pBuffer += SPI_FLASH_PageSize;}if (NumOfSingle != 0){SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);}}} }/**-----------------------------------------------------------------* @函數名 SPI_FLASH_BufferRead* @功能 從SPI FLASH讀出一段數據,寫入的字節數可以大于一頁容量* Reads a block of data from the FLASH.* @參數 - pBuffer : 指向包含寫入數據緩沖器的地址指針* pointer to the buffer that receives the data read* from the FLASH.* - ReadAddr : flash的讀起始地址* FLASH's internal address to read from.* - NumByteToWrite : 讀出的字節數* number of bytes to read from the FLASH.* @返回值 無 ***----------------------------------------------------------------*/ void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead) {/* Select the FLASH: Chip Select low */SPI2_FLASH_CS_LOW();/* Send "Read from Memory " instruction */SPI_FLASH_SendByte(W25X_ReadData);/* Send ReadAddr high nibble address byte to read from */SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);/* Send ReadAddr medium nibble address byte to read from */SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);/* Send ReadAddr low nibble address byte to read from */SPI_FLASH_SendByte(ReadAddr & 0xFF);while (NumByteToRead--) /* while there is data to be read */{/* Read a byte from the FLASH */*pBuffer = SPI_FLASH_SendByte(Dummy_Byte);/* Point to the next location where the byte read will be saved */pBuffer++;}/* Deselect the FLASH: Chip Select high */SPI2_FLASH_CS_HIGH(); }/**-----------------------------------------------------------------* @函數名 SPI_FLASH_ReadID* @功能 讀取SPI FLASH廠商ID和設備ID(設備ID包含類型和容量)* Reads Manufacturer ID and two Device ID bytes* @參數 無* @返回值 24bit,高到底依次為廠商ID、類型和容量 ***----------------------------------------------------------------*/ uint32_t SPI_FLASH_ReadID(void) {uint32_t Temp = 0, Temp0 = 0, Temp1 = 0, Temp2 = 0;/* Select the FLASH: Chip Select low */SPI2_FLASH_CS_LOW();/* Send "RDID " instruction */SPI_FLASH_SendByte(W25X_JedecDeviceID);/* Read a byte from the FLASH */Temp0 = SPI_FLASH_SendByte(Dummy_Byte);/* Read a byte from the FLASH */Temp1 = SPI_FLASH_SendByte(Dummy_Byte);/* Read a byte from the FLASH */Temp2 = SPI_FLASH_SendByte(Dummy_Byte);/* Deselect the FLASH: Chip Select high */SPI2_FLASH_CS_HIGH();Temp = (Temp0 << 16) | (Temp1 << 8) | Temp2;return Temp; }/**-----------------------------------------------------------------* @函數名 SPI_FLASH_ReadDeviceID* @功能 讀取SPI FLASH設備ID* Read one Device ID bytes* @參數 無* @返回值 一個字節的Device ID ***----------------------------------------------------------------*/ uint32_t SPI_FLASH_ReadDeviceID(void) {uint32_t Temp = 0;/* Select the FLASH: Chip Select low */SPI2_FLASH_CS_LOW();/* Send "RDID " instruction */SPI_FLASH_SendByte(W25X_DeviceID);SPI_FLASH_SendByte(Dummy_Byte);SPI_FLASH_SendByte(Dummy_Byte);SPI_FLASH_SendByte(Dummy_Byte);/* Read a byte from the FLASH */Temp = SPI_FLASH_SendByte(Dummy_Byte);/* Deselect the FLASH: Chip Select high */SPI2_FLASH_CS_HIGH();return Temp; }/**-----------------------------------------------------------------* @函數名 SPI_FLASH_StartReadSequence* @功能 發起一個讀取SPI FLASH的訪問,包括發送讀命令和起始地址* Initiates a read data byte (READ) sequence from the Flash.* This is done by driving the /CS line low to select the device,* then the READ instruction is transmitted followed by 3 bytes* address. This function exit and keep the /CS line low, so the* Flash still being selected. With this technique the whole* content of the Flash is read with a single READ instruction.* Read one Device ID bytes* @參數 ReadAddr FLASH的訪問地址* FLASH's internal address to read from.* @返回值 無 ***----------------------------------------------------------------*/ void SPI_FLASH_StartReadSequence(uint32_t ReadAddr) {/* Select the FLASH: Chip Select low */SPI2_FLASH_CS_LOW();/* Send "Read from Memory " instruction */SPI_FLASH_SendByte(W25X_ReadData);/* Send the 24-bit address of the address to read from -----------------------*//* Send ReadAddr high nibble address byte */SPI_FLASH_SendByte((ReadAddr & 0xFF0000) >> 16);/* Send ReadAddr medium nibble address byte */SPI_FLASH_SendByte((ReadAddr& 0xFF00) >> 8);/* Send ReadAddr low nibble address byte */SPI_FLASH_SendByte(ReadAddr & 0xFF); }/**-----------------------------------------------------------------* @函數名 SPI_FLASH_ReadByte* @功能 讀取SPI FLASH的一個字節,未包含發送讀命令和起始地址* @參數 無* @返回值 從SPI_FLASH讀取的一個字節 ***----------------------------------------------------------------*/ uint8_t SPI_FLASH_ReadByte(void) {return (SPI_FLASH_SendByte(Dummy_Byte)); }//uint8_t SPI2_ReadWriteByte(uint8_t TxData) //{ // uint8_t Rxdata; // HAL_SPI_TransmitReceive(&hspi2,&TxData,&Rxdata,1, 1000); // return Rxdata; //返回收到的數據 //}/**-----------------------------------------------------------------* @函數名 SPI_FLASH_SendByte* @功能 通過SPI總線發送一個字節數據(順便接收一個字節數據)* Sends a byte through the SPI interface and return the byte* received from the SPI bus.* @參數 要寫入的一個字節數據* @返回值 在發數據時,MISO信號線上接收的一個字節 ***----------------------------------------------------------------*/ uint8_t SPI_FLASH_SendByte(uint8_t TxData) {uint8_t Rxdata;HAL_SPI_TransmitReceive(&hspi2,&TxData,&Rxdata,1, 1000); return Rxdata; //返回收到的數據 }/**-----------------------------------------------------------------* @函數名 SPI_FLASH_WriteEnable* @功能 SPI FLASH寫使能* Enables the write access to the FLASH.* @參數 無* @返回值 無 ***----------------------------------------------------------------*/ void SPI_FLASH_WriteEnable(void) {/* Select the FLASH: Chip Select low */SPI2_FLASH_CS_LOW();/* Send "Write Enable" instruction */SPI_FLASH_SendByte(W25X_WriteEnable);/* Deselect the FLASH: Chip Select high */SPI2_FLASH_CS_HIGH(); }/**-----------------------------------------------------------------* @函數名 SPI_FLASH_WaitForWriteEnd* @功能 通過反復讀取SPI FLASH的狀態寄存器判斷寫入是否執行結束* Polls the status of the Write In Progress (WIP) flag in the* FLASH's status register and loop until write opertaion* has completed.* @參數 無* @返回值 無 ***----------------------------------------------------------------*/ void SPI_FLASH_WaitForWriteEnd(void) {uint8_t FLASH_Status = 0;/* Select the FLASH: Chip Select low */SPI2_FLASH_CS_LOW();/* Send "Read Status Register" instruction */SPI_FLASH_SendByte(W25X_ReadStatusReg_1);/* Loop as long as the memory is busy with a write cycle */do{/* Send a dummy byte to generate the clock needed by the FLASHand put the value of the status register in FLASH_Status variable */FLASH_Status = SPI_FLASH_SendByte(Dummy_Byte);}while ((FLASH_Status & WIP_FlagMask) == SET); /* Write in progress *//* Deselect the FLASH: Chip Select high */SPI2_FLASH_CS_HIGH(); }/**-----------------------------------------------------------------* @函數名 SPI_Flash_PowerDown* @功能 SPI FLASH進入掉電模式(待機)* @參數 無* @返回值 無 ***----------------------------------------------------------------*/ void SPI_Flash_PowerDown(void) { /* Select the FLASH: Chip Select low */SPI2_FLASH_CS_LOW();/* Send "Power Down" instruction */SPI_FLASH_SendByte(W25X_PowerDown);/* Deselect the FLASH: Chip Select high */SPI2_FLASH_CS_HIGH(); } /**-----------------------------------------------------------------* @函數名 SPI_Flash_WAKEUP* @功能 喚醒SPI FLASH* @參數 無* @返回值 無 ***----------------------------------------------------------------*/ void SPI_Flash_WAKEUP(void) {/* Select the FLASH: Chip Select low */SPI2_FLASH_CS_LOW();/* Send "Power Down" instruction */SPI_FLASH_SendByte(W25X_ReleasePowerDown);/* Deselect the FLASH: Chip Select high */SPI2_FLASH_CS_HIGH(); }bsp_spi_flash.h
#ifndef __FLASH_W25Q_H #define __FLASH_W25Q_H #include "sys.h" #define W25Q180_FLASH_ID 0xEF4018#define SPI2_FLASH_CS_LOW() HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_RESET) #define SPI2_FLASH_CS_HIGH() HAL_GPIO_WritePin(SPI2_CS_GPIO_Port, SPI2_CS_Pin, GPIO_PIN_SET)#define W25Q80_FLASH_ID 0xEF4014/* Private typedef -----------------------------------------------------------*/ #define SPI_FLASH_PageSize 256 #define SPI_FLASH_PerWritePageSize 256 #define SPI_FLASH_SectorSize (4096) // 扇區大小(可擦除的最小單元)0x1000 #define SPI_FLASH_BlockSize (65536) // 塊大小0x10000/*----- High layer function -----*/ void SPI_FLASH_Init(void); void SPI_FLASH_SectorErase(uint32_t SectorAddr); void SPI_FLASH_ChipErase(void); void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite); void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite); void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead); uint32_t SPI_FLASH_ReadID(void); uint32_t SPI_FLASH_ReadDeviceID(void); void SPI_FLASH_StartReadSequence(uint32_t ReadAddr); void SPI_Flash_PowerDown(void); void SPI_Flash_WAKEUP(void);/*----- Low layer function -----*/ uint8_t SPI_FLASH_ReadByte(void); uint8_t SPI_FLASH_SendByte(uint8_t byte); uint16_t SPI_FLASH_SendHalfWord(uint16_t HalfWord); void SPI_FLASH_WriteEnable(void); void SPI_FLASH_WaitForWriteEnd(void); void SPI_Flash_Read_Send(void);extern uint32_t FLASH_WriteAddress; //寫地址 extern uint32_t FLASH_SectorToErase; //擦除地址 extern uint32_t FLASH_ReadAddress; //讀地址 #endif二、實例
static u8 TestBuf[16] = {0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A}; #define SystemSettings1_Time_Start (0x000000) u32 THC_SPI_FLASH_TEST(void) {u8 HexBuf[20] = { 0 };u8 i = 0, len = sizeof(TestBuf);u32 id = SPI_FLASH_ReadID();SPI_FLASH_SectorErase(SPI_FLASH_SectorSize);SPI_FLASH_BufferWrite(TestBuf, SystemSettings1_Time_Start, len);SPI_FLASH_BufferRead(HexBuf, SystemSettings1_Time_Start, len);for(i = 0; i < len; i++){if(HexBuf[i] != TestBuf[i]) {break;}}if(i < len) {id = 0xFFFFFFFF;}SPI_FLASH_SectorErase(SPI_FLASH_SectorSize);return id; }三、問題
需要注意:
1、每次寫入之前都要擦除,只能整個扇區的擦除。
2、第一次讀取失敗,網上的辦法都試了還是不行。處理方法是初始化的時候讀取ID。
總結
以上是生活随笔為你收集整理的STM32F4 HAL库开发 -- SPI Flash的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 服装零售行业洞察报告
- 下一篇: 2021年中国电商SaaS行业研究报告