關于flash的介紹
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLmZ2NyITZ0EDMxUmZlBTM5MTYxQjY3QTNjdTYjZDMzUzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
詳情見資料手冊的第53頁開始。
代碼是從正點原子的【探索者STM32F407開發闆資料】 修改而來。
而GD32的flash的相關庫函數檔案是【GD32F4xx_fmc.c】。
使用flash 的話,一定要導入這個檔案
上代碼
flash.c
#include "flash.h"
//讀取指定位址的半字(16位資料)
//faddr:讀位址
//傳回值:對應資料.
unsigned int GDFLASH_ReadWord(unsigned int faddr)
{
return *(volatile unsigned int*)faddr;
}
//擷取某個位址所在的flash扇區
//addr:flash位址
//傳回值:0~11,即addr所在的扇區
uint16_t GDFLASH_GetFlashSector(unsigned int addr)
{
if(addr<ADDR_FLASH_SECTOR_1) return FLASH_Sector_0;
else if(addr<ADDR_FLASH_SECTOR_2) return FLASH_Sector_1;
else if(addr<ADDR_FLASH_SECTOR_3) return FLASH_Sector_2;
else if(addr<ADDR_FLASH_SECTOR_4) return FLASH_Sector_3;
else if(addr<ADDR_FLASH_SECTOR_5) return FLASH_Sector_4;
else if(addr<ADDR_FLASH_SECTOR_6) return FLASH_Sector_5;
else if(addr<ADDR_FLASH_SECTOR_7) return FLASH_Sector_6;
else if(addr<ADDR_FLASH_SECTOR_8) return FLASH_Sector_7;
else if(addr<ADDR_FLASH_SECTOR_9) return FLASH_Sector_8;
else if(addr<ADDR_FLASH_SECTOR_10) return FLASH_Sector_9;
else if(addr<ADDR_FLASH_SECTOR_11) return FLASH_Sector_10;
return FLASH_Sector_11;
}
//從指定位址開始寫入指定長度的資料
//該函數對OTP區域也有效!可以用來寫OTP區!
//OTP區域位址範圍:0X1FFF7800~0X1FFF7A0F
//WriteAddr:起始位址(此位址必須為4的倍數!!)
//pBuffer:資料指針
//NumToWrite:字(32位)數(就是要寫入的32位資料的個數.)
void GDFLASH_Write(unsigned int WriteAddr,unsigned int *pBuffer,unsigned int NumToWrite)
{
fmc_state_enum status = FMC_READY;
unsigned int addrx=0;
unsigned int endaddr=0;
if(WriteAddr<GD32_FLASH_BASE||WriteAddr%4)return; //輸入的位址是非法位址
fmc_unlock(); //FMC解鎖
addrx=WriteAddr; //設定寫入的起始位址
endaddr=WriteAddr+NumToWrite*4; //設定寫入的結束位址
/* 隻有主存儲區,才需要執行擦除操作 */
if(addrx<0X1FFF0000)
{
/* 對非FFFFFFFF的地方,先擦除 */
while(addrx<endaddr)
{
/* 有非0XFFFFFFFF的地方,就擦除這個扇區 */
if(GDFLASH_ReadWord(addrx)!=0XFFFFFFFF)
{
/* 對指定扇區擦除并傳回擦除狀态 */
status=fmc_sector_erase(GDFLASH_GetFlashSector(addrx));
/* 擦除失敗或者發生錯誤 */
if(status != FMC_READY) break;
}
else
{
addrx+=4;//位址加4
}
}
}
/* 擦除成功 */
if(status==FMC_READY)
{
/* 寫入的位址沒有超過之前計算的結束位址 */
while(WriteAddr<endaddr)
{
/* 寫入一個字資料并傳回寫入狀态 */
if(fmc_word_program(WriteAddr,*pBuffer)!=FMC_READY)
{
break; //寫入異常
}
WriteAddr+=4; //寫入位址+4
pBuffer++; //資料位址自增
}
}
/* fmc上鎖 */
fmc_lock();
}
//從指定位址開始讀出指定長度的資料
//ReadAddr:起始位址
//pBuffer:資料指針
//NumToRead:字(4位)數
void GDFLASH_Read(unsigned int ReadAddr,unsigned int *pBuffer,unsigned int NumToRead)
{
unsigned int i;
for(i=0;i<NumToRead;i++)
{
pBuffer[i]=GDFLASH_ReadWord(ReadAddr);//讀取4個位元組.
ReadAddr+=4; //偏移4個位元組.
}
}
flash.h
#ifndef _FLASH_h_
#define _FLASH_h_
#include "gd32f4xx.h"
//FLASH起始位址
#define GD32_FLASH_BASE 0x08000000 //GD32 FLASH的起始位址
//FLASH 扇區的起始位址
#define ADDR_FLASH_SECTOR_0 ((unsigned int)0x08000000) //扇區0起始位址, 16 Kbytes
#define ADDR_FLASH_SECTOR_1 ((unsigned int)0x08004000) //扇區1起始位址, 16 Kbytes
#define ADDR_FLASH_SECTOR_2 ((unsigned int)0x08008000) //扇區2起始位址, 16 Kbytes
#define ADDR_FLASH_SECTOR_3 ((unsigned int)0x0800C000) //扇區3起始位址, 16 Kbytes
#define ADDR_FLASH_SECTOR_4 ((unsigned int)0x08010000) //扇區4起始位址, 64 Kbytes
#define ADDR_FLASH_SECTOR_5 ((unsigned int)0x08020000) //扇區5起始位址, 128 Kbytes
#define ADDR_FLASH_SECTOR_6 ((unsigned int)0x08040000) //扇區6起始位址, 128 Kbytes
#define ADDR_FLASH_SECTOR_7 ((unsigned int)0x08060000) //扇區7起始位址, 128 Kbytes
#define ADDR_FLASH_SECTOR_8 ((unsigned int)0x08080000) //扇區8起始位址, 128 Kbytes
#define ADDR_FLASH_SECTOR_9 ((unsigned int)0x080A0000) //扇區9起始位址, 128 Kbytes
#define ADDR_FLASH_SECTOR_10 ((unsigned int)0x080C0000) //扇區10起始位址,128 Kbytes
#define ADDR_FLASH_SECTOR_11 ((unsigned int)0x080E0000) //扇區11起始位址,128 Kbytes
/** @defgroup FLASH_Sectors
* @{
*/
#define FLASH_Sector_0 ((uint16_t)0x0000) /*!< Sector Number 0 */
#define FLASH_Sector_1 ((uint16_t)0x0008) /*!< Sector Number 1 */
#define FLASH_Sector_2 ((uint16_t)0x0010) /*!< Sector Number 2 */
#define FLASH_Sector_3 ((uint16_t)0x0018) /*!< Sector Number 3 */
#define FLASH_Sector_4 ((uint16_t)0x0020) /*!< Sector Number 4 */
#define FLASH_Sector_5 ((uint16_t)0x0028) /*!< Sector Number 5 */
#define FLASH_Sector_6 ((uint16_t)0x0030) /*!< Sector Number 6 */
#define FLASH_Sector_7 ((uint16_t)0x0038) /*!< Sector Number 7 */
#define FLASH_Sector_8 ((uint16_t)0x0040) /*!< Sector Number 8 */
#define FLASH_Sector_9 ((uint16_t)0x0048) /*!< Sector Number 9 */
#define FLASH_Sector_10 ((uint16_t)0x0050) /*!< Sector Number 10 */
#define FLASH_Sector_11 ((uint16_t)0x0058) /*!< Sector Number 11 */
#define FLASH_Sector_12 ((uint16_t)0x0080) /*!< Sector Number 12 */
#define FLASH_Sector_13 ((uint16_t)0x0088) /*!< Sector Number 13 */
#define FLASH_Sector_14 ((uint16_t)0x0090) /*!< Sector Number 14 */
#define FLASH_Sector_15 ((uint16_t)0x0098) /*!< Sector Number 15 */
#define FLASH_Sector_16 ((uint16_t)0x00A0) /*!< Sector Number 16 */
#define FLASH_Sector_17 ((uint16_t)0x00A8) /*!< Sector Number 17 */
#define FLASH_Sector_18 ((uint16_t)0x00B0) /*!< Sector Number 18 */
#define FLASH_Sector_19 ((uint16_t)0x00B8) /*!< Sector Number 19 */
#define FLASH_Sector_20 ((uint16_t)0x00C0) /*!< Sector Number 20 */
#define FLASH_Sector_21 ((uint16_t)0x00C8) /*!< Sector Number 21 */
#define FLASH_Sector_22 ((uint16_t)0x00D0) /*!< Sector Number 22 */
#define FLASH_Sector_23 ((uint16_t)0x00D8) /*!< Sector Number 23 */
unsigned int GDFLASH_ReadWord(unsigned int faddr); //讀出字
void GDFLASH_Write(unsigned int WriteAddr,unsigned int *pBuffer,unsigned int NumToWrite); //從指定位址開始寫入指定長度的資料
void GDFLASH_Read(unsigned int ReadAddr,unsigned int *pBuffer,unsigned int NumToRead); //從指定位址開始讀出指定長度的資料
#endif
main.c
#include "gd32f4xx.h"
#include "systick.h"
#include "usart0.h"
#include "stdio.h"
#include "flash.h"
//要寫入到GD32 FLASH的字元串數組
const unsigned char TEXT_Buffer[]={"Hello 立創梁山派!"};
#define TEXT_LENTH sizeof(TEXT_Buffer) //數組長度
#define SIZE TEXT_LENTH/4+((TEXT_LENTH%4)?1:0)
#define FLASH_SAVE_ADDR 0X0800C004 //設定FLASH 儲存位址(必須為偶數,且所在扇區,要大于本代碼所占用到的扇區.
//否則,寫操作的時候,可能會導緻擦除整個扇區,進而引起部分程式丢失.引起當機.
int main(void)
{
unsigned char datatemp[SIZE];
unsigned char temp_buff[200];
nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); // 優先級分組
systick_config(); //系統滴答定時器 定時1MS
USART1_Init();
USART0_send_String((unsigned char *)"--開始--");
/* 寫入TEXT_Buffer數組裡的資料 */
GDFLASH_Write(FLASH_SAVE_ADDR,(unsigned int*)TEXT_Buffer,SIZE);
delay_1ms(1000);
/* 讀出資料儲存至datatemp數組 */
GDFLASH_Read(FLASH_SAVE_ADDR,(unsigned int*)datatemp,SIZE);
/* 序列槽調試 */
sprintf((char *)temp_buff, "讀取的資料=%s\r\n", datatemp);
USART0_send_String(temp_buff);
while(1)
{
}
}
實驗結果
通過序列槽調試助手顯示讀取到的資料