文章目录
前言
准备
一、存储信息
1、存储信息寄存器
这个寄存器可以获取 片上FLASH存储器容量、片上SRAM容量
2、系统架构示意图
可见Flash的操作可以通过FMC控制器尽心操作,提供字、半字、字节闪存操作,可以扇区擦除、块擦除和部分系列(GD32F470xx, GD32F427xx and GD32F425xx )还提供页擦除(4KB)
3、存储器映射
这个F4系列最大3072KB,我们用的芯片只有 512K
4、存储扇区基地址和大小
可以看出,不同的扇区大小还不一样,有16K、64K、128K不同大小的扇区
二、解锁
1、解锁FMC_CTL、FMC_OBCTLx
复位之后 如果要操作FMC前要解锁 FMC_CTL这个控制寄存器、若果要操作选项字节需解锁FMC_OBCTLx 选项字节控制寄存器,都是先后往对应的KEY解锁寄存器写入两个对应的序列,上锁是把对应 的 LK bit 置1
FMC_CTL解锁上锁例程
/*! \brief unlock the main FMC operation \param[in] none \param[out] none \retval none */ void fmc_unlock(void) { if((RESET != (FMC_CTL & FMC_CTL_LK))) { /* write the FMC key */ FMC_KEY = UNLOCK_KEY0; FMC_KEY = UNLOCK_KEY1; } } /*! \brief lock the main FMC operation \param[in] none \param[out] none \retval none */ void fmc_lock(void) { /* set the LK bit*/ FMC_CTL |= FMC_CTL_LK; }
2、解锁 也擦除配置寄存器 FMC_PECFG
当需要执行页擦除操作时需要 往 FMC_PEKEY 寄存器写入 0xA9B8C7D6来解锁FMC_PECFG寄存器
三、读操作
可以直接寻址访问
void fmc_read_8bit_data(uint32_t address, uint16_t length, int8_t* data_8) { uint8_t i; for(i=0; i<length; i++) { /*直接寻址访问*/ data_8[i] = *(__IO int8_t*)address; address++; } }
四、主flash编程操作
1、操作流程
a、确保FMC_CTL寄存器不处于锁定状态;
b、等待FMC_STAT寄存器的BUSY位变为0来确保没有闪存操作在进行,否则等待该操作完成;
c、按照需求设置PSZ位域,并置位FMC_CTL寄存器的PG位;
d、DBUS写一个32位整字/16位半字/8位字节(必须与FMC_CTL寄存器中的PSZ位匹配)到
目的绝对地址(0x08XX XXXX);
e、通过检查FMC_STAT寄存器的BUSY位是否清0,来确定写操作执行完毕;
f、如果需要,使用DBUS读操作验证是否编程成功。
2、8位字节编程例程
/* 单字节编程 */ fmc_state_enum fmc_byte_program(uint32_t address, uint8_t data) { fmc_state_enum fmc_state = FMC_READY; /* 等待BUSY忙碌标志清零、FMC就绪、FMC没有故障 */ fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT); if(FMC_READY == fmc_state) { /* 复位编程大小位有 32位整字/16位半字/8位字节*/ FMC_CTL &= ~FMC_CTL_PSZ; /* 选择新的编程大小位位 8位字节*/ FMC_CTL |= CTL_PSZ_BYTE; /* 置位 FMC_CTL_PG ,PG位必须在32位整字/16位半字/8位字节编程开始前进行置位*/ FMC_CTL |= FMC_CTL_PG; /* 开始编程,往对应的地址存入数据*/ REG8(address) = data; /* 等待BUSY忙碌标志清零,操作完成 */ fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT); /* 清零PG位 */ FMC_CTL &= ~FMC_CTL_PG; } /* 返回 FMC 状态 */ return fmc_state; }
3、页擦除(GD32F425、GD32F427、GD32F470支持)
1、流程
2、程序解析
/* 页擦除 */ fmc_state_enum fmc_page_erase(uint32_t page_addr) { fmc_state_enum fmc_state = FMC_READY; /* 等待BUSY忙碌标志清零、FMC就绪、FMC没有故障 */ fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT); if(FMC_READY == fmc_state) { /* 解锁 FMC_PECFG */ FMC_PEKEY = UNLOCK_PE_KEY; /* PE_EN置位使能页擦除、 page_addr要擦除的页地址*/ FMC_PECFG = FMC_PE_EN | page_addr; /* 选择擦除扇区号 */ FMC_CTL &= ~FMC_CTL_SN; /* 主存储块扇区擦除命令置位 */ FMC_CTL |= FMC_CTL_SER; /* 发送擦除命令位 */ FMC_CTL |= FMC_CTL_START; /* 等待BUSY忙碌标志清零,操作完成 */ fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT); /* PE_EN 停止页擦除 */ FMC_PECFG &= ~FMC_PE_EN; /* 主存储块扇区擦除命令清零 */ FMC_CTL &= ~FMC_CTL_SER; } return fmc_state; }
FMC还提供 扇区擦除、块擦除,这里不详细说明了。