【兆易GD32H759I-EVAL】 内部Flash 读写实验
[复制链接]
通过本实验主要内容:
• FMC控制器原理;
• FMC擦写读操作;
GD32H7系列的MCU FLASH存储器区域分类
- 高达3840KB主FLASH存储器;
- 高达64KB引导装载程序(boot loader)信息块存储器;
- 器件配置的选项字节。
FMC(Flash Memory Controller)为GD32H7XX系列MCU提供了全面的片上Flash内存管理功能:
- Flash控制器(FMC):
- FMC负责管理和控制GD32H7XX系列MCU上的Flash内存。
- 它提供了所有必要的接口和功能,用于执行Flash内存的读取、编程(写入)和擦除操作。
- Flash内存大小:
- GD32H7XX系列MCU配备了高达3840KB(或3.75MB)的片上Flash内存。
- 这片内存可用于存储程序代码、常量数据或可修改的数据。
- 读取操作:
- Flash支持多种读取操作,包括64字节双字(即128位)、32位整字、16位半字和字节读操作。
- 这些不同的读取方式可以满足不同性能和应用需求。
- 编程(写入)操作:
- Flash编程支持64位双字(即8字节)和32位整字编程。
- 这意味着你可以直接写入一个完整的双字或整字到Flash内存中,而不需要单独写入每个字节。
- 擦除操作:
- FMC支持扇区擦除和整片擦除两种操作。
- 扇区擦除允许你选择性地擦除Flash内存中的某个特定区域,而整片擦除则会清除整个Flash内存。
- 代码保护区域:
- Flash内存包含专用的代码保护区域,这些区域只能执行,不能被读取或写入。
- 这种设计有助于保护存储在Flash中的程序代码免受未授权访问或篡改,从而增强了系统的安全性。
- 它也支持二次合作开发,因为开发者可以在不暴露原始代码的情况下,与其他团队或合作伙伴共享硬件平台。
- 其他特性:
- Flash内存可能还具有其他特性,如耐久性(可擦写次数)、读取速度、写入延迟等,这些都会影响Flash内存在具体应用中的性能和用途。
闪存包括3840KB字节主闪存,分为960个扇区,扇区大小为4KB,和64KB用于引导加载程序的信息块。主存储闪存的每个扇区都可以单独擦除 。
有关Flash擦写操作均需要先解锁Flash,然后进行擦写操作,擦写完成后再进行锁Flash,注意Flash特性只能由1写0,也就是Flash需要先擦除才能写入新的数据,如果确保写入地址的数据为全0xFF,也可以直接写入。读取Flash数据可以采取直接寻址的方式进行读取。
函数接口
解锁FMC_CTL寄存器 fmc_unlock 函数
fmc_unlock 函数的目标是解锁 FMC(Flash Memory Controller)的控制寄存器(FMC_CTL)
锁定FMC_CTL寄存器
/*!
\brief unlock FMC_CTL register
\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;
}
}
函数首先 ,检查是否已经解锁,如果 FMC 控制器是锁定的,函数会连续写入两个解锁密钥(UNLOCK_KEY0 和 UNLOCK_KEY1)到 FMC_KEY 寄存器中。这通常是微控制器特定的解锁序列,用于安全地解锁 Flash 控制器的配置寄存器。
锁定FMC_CTL寄存器
/*!
\brief lock FMC_CTL register
\param[in] none
\param[out] none
\retval none
*/
void fmc_lock(void)
{
/* set the LK bit*/
FMC_CTL |= FMC_CTL_LK;
}
全字编程
/*!
\brief FMC program a word at the corresponding address
\param[in] address: address to program
\param[in] data: word to program
\param[out] none
\retval state of FMC
\arg FMC_READY: the operation has been completed
\arg FMC_BUSY: the operation is in progress
\arg FMC_WPERR: erase/program protection error
\arg FMC_PGSERR: program sequence error
\arg FMC_RPERR: read protection error
\arg FMC_RSERR: read secure error
\arg FMC_ECCCOR: one bit correct error
\arg FMC_ECCDET: two bits detect error
\arg FMC_OBMERR: option byte modify error
\arg FMC_TOERR: timeout error
*/
fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
{
fmc_state_enum fmc_state = FMC_READY;
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
if(FMC_READY == fmc_state) {
/* set the PG bit to start program */
FMC_CTL |= FMC_CTL_PG;
__ISB();
__DSB();
REG32(address) = data;
__ISB();
__DSB();
/* wait for the FMC ready */
fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
/* reset the PG bit */
FMC_CTL &= ~FMC_CTL_PG;
}
/* return the FMC state */
return fmc_state;
}
实验代码
/*!
* 说明 读取Flash地址数据
* 输入[1] write_read_addr:需要读取的Flash地址
* 返回值 读取的数据
*/
uint8_t fmc_read_8_data(uint32_t write_read_addr)
{
return *(uint8_t *)write_read_addr;
}
/*!
* 说明 读取Flash地址数据
* 输入[1] write_read_addr:需要读取的Flash地址
* 返回值 读取的数据
*/
uint8_t fmc_read_32_data(uint32_t write_read_addr)
{
return *(uint32_t *)write_read_addr;
}
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
/* enable the CPU Cache */
cache_enable();
uint8_t x = 0;
gd_eval_com_init(EVAL_COM);
printf(" address = %02x\n\r", x);
// systick_config();
/* initialize led on the board */
gd_eval_led_init(LED1);
// gd_eval_led_init(LED2);
//
__disable_irq();
//解锁
fmc_unlock();
/* 清除所有挂起的标志 */
fmc_all_flags_clear();
/* erase the flash sectors */
fmc_sector_erase(FMC_WRITE_START_ADDR);
fmc_all_flags_clear();
//上锁
fmc_lock();
__enable_irq();
address = fmc_read_32_data(FMC_WRITE_START_ADDR);
printf(" address = %02x\n\r", address);
/* 判断要不要擦写 */
if(fmc_read_32_data(FMC_WRITE_START_ADDR) != data)
{
__disable_irq();
//解锁
fmc_unlock();
/* 清除所有挂起的标志 */
fmc_all_flags_clear();
/* erase the flash sectors */
fmc_sector_erase(FMC_WRITE_START_ADDR);
fmc_all_flags_clear();
fmc_word_program(FMC_WRITE_START_ADDR, data);
fmc_all_flags_clear();
//上锁
fmc_lock();
__enable_irq();
}
address = fmc_read_32_data(FMC_WRITE_START_ADDR);
printf(" address = %02x\n\r", address);
while(1) {
gd_eval_led_toggle(LED1);
}
}
实验现象
|