关于flash的介绍
详情见数据手册的第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)
{
}
}
实验结果
通过串口调试助手显示读取到的数据