GD32F4单片机 使用 FMC(闪存控制器)对片内Flash擦写读测试

一、GD32 片上flash 介绍

GD32F4xx系列微控制器可以提供高密度片上FLASH存储器,按以下分类进行组织:
1、高达3072KB主FLASH存储器。
2、高达30KB引导装载程序(boot loader)信息块存储器。
3、 高达512B OTP(一次性可编程)存储器。
4、器件配置的选项字节。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、fmc 函数 和 操作方法

  闪存控制器(FMC),提供了片上闪存需要的所有功能。MCU执行指令零等待的区域最大支持到1024K字节空间。FMC也提供了扇区擦除和整片擦除,以及32位整字或16位半字、字节编程等闪存操作。另外GD32F470xx,GD32F427xx 和 GD32F425xx系列还额外提供了页(4KB)擦除操作。

2.1 函数

gd32f4xx_fmc.h 文件中的函数声明

/* function declarations */
/* FMC main memory programming functions */
/* set the FMC wait state counter */
void fmc_wscnt_set(uint32_t wscnt);
/* unlock the main FMC operation */
void fmc_unlock(void);
/* lock the main FMC operation */
void fmc_lock(void);
/* FMC erase sector */
fmc_state_enum fmc_sector_erase(uint32_t fmc_sector);
/* FMC erase whole chip */
fmc_state_enum fmc_mass_erase(void);
/* FMC erase whole bank0 */
fmc_state_enum fmc_bank0_erase(void);
/* FMC erase whole bank1 */
fmc_state_enum fmc_bank1_erase(void);
/* FMC program a word at the corresponding address */
fmc_state_enum fmc_word_program(uint32_t address, uint32_t data);
/* FMC program a half word at the corresponding address */
fmc_state_enum fmc_halfword_program(uint32_t address, uint16_t data);
/* FMC program a byte at the corresponding address */
fmc_state_enum fmc_byte_program(uint32_t address, uint8_t data);

/* FMC option bytes programming functions */
/* unlock the option byte operation */
void ob_unlock(void);
/* lock the option byte operation */
void ob_lock(void);
/* send option byte change command */
void ob_start(void);
/* erase option byte */
void ob_erase(void);
/* enable write protect */
void ob_write_protection_enable(uint32_t ob_wp);
/* disable write protect */
void ob_write_protection_disable(uint32_t ob_wp);
/* enable erase/program protection and D-bus read protection */
void ob_drp_enable(uint32_t ob_drp);
/* disable erase/program protection and D-bus read protection */
void ob_drp_disable(uint32_t ob_drp);
/* set the option byte security protection level */
void ob_security_protection_config(uint8_t ob_spc);
/* write the FMC option byte user */
void ob_user_write(uint32_t ob_fwdgt, uint32_t ob_deepsleep, uint32_t ob_stdby);
/* option byte BOR threshold value */
void ob_user_bor_threshold(uint32_t ob_bor_th);
/* configure the boot mode */
void ob_boot_mode_config(uint32_t boot_mode);
/* get the FMC option byte user */
uint8_t ob_user_get(void);
/* get the FMC option byte write protection */
uint16_t ob_write_protection0_get(void);
/* get the FMC option byte write protection */
uint16_t ob_write_protection1_get(void);
/* get the FMC erase/program protection and D-bus read protection option bytes value */
uint16_t ob_drp0_get(void);
/* get the FMC erase/program protection and D-bus read protection option bytes value */
uint16_t ob_drp1_get(void);
/* get option byte security protection code value */
FlagStatus ob_spc_get(void);
/* get the FMC threshold value */
uint8_t ob_user_bor_threshold_get(void);

/* FMC interrupts and flags management functions */
/* enable FMC interrupt */
void fmc_interrupt_enable(uint32_t fmc_int);
/* disable FMC interrupt */
void fmc_interrupt_disable(uint32_t fmc_int);
/* get flag set or reset */
FlagStatus fmc_flag_get(uint32_t fmc_flag);
/* clear the FMC pending flag */
void fmc_flag_clear(uint32_t fmc_flag);
/* return the FMC state */
fmc_state_enum fmc_state_get(void);
/* check FMC ready or not */
fmc_state_enum fmc_ready_wait(void);

2.2 读

在这里插入图片描述

2.3 擦除

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2.4 写

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

三、测试代码

3.1 相关宏定义

#define ADDR_FLASH_SECTOR_0     ((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbytes */
#define ADDR_FLASH_SECTOR_1     ((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes */
#define ADDR_FLASH_SECTOR_2     ((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes */
#define ADDR_FLASH_SECTOR_3     ((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbytes */

#define ADDR_FLASH_SECTOR_4     ((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbytes */

#define ADDR_FLASH_SECTOR_5     ((uint32_t)0x08020000) /* Base @ of Sector 5, 128 Kbytes */
#define ADDR_FLASH_SECTOR_6     ((uint32_t)0x08040000) /* Base @ of Sector 6, 128 Kbytes */
#define ADDR_FLASH_SECTOR_7     ((uint32_t)0x08060000) /* Base @ of Sector 7, 128 Kbytes */



#define ADDR_FLASH_SECTOR_8     ((uint32_t)0x08080000) /* Base @ of Sector 8, 128 Kbytes */
#define ADDR_FLASH_SECTOR_9     ((uint32_t)0x080A0000) /* Base @ of Sector 9, 128 Kbytes */
#define ADDR_FLASH_SECTOR_10    ((uint32_t)0x080C0000) /* Base @ of Sector 10, 128 Kbytes */
#define ADDR_FLASH_SECTOR_11    ((uint32_t)0x080E0000) /* Base @ of Sector 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  */
    



#define GD32_FLASH_START_ADRESS     ((uint32_t)0x08000000)
#define GD32_FLASH_SIZE             (1024 * 1024)  //512 code +  512 data
#define GD32_FLASH_END_ADDRESS      ((uint32_t)(GD32_FLASH_START_ADRESS + GD32_FLASH_SIZE))

3.2 获取扇区

static uint32_t GetSector(uint32_t Address)
{

    uint32_t sector = 0;

    if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0))
    {
        sector = 0;
    }
    else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1))
    {
        sector = 1;
    }
    else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2))
    {
        sector = 2;
    }
    else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3))
    {
        sector = 3;
    }
    else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4))
    {
        sector = 4;
    }
    else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5))
    {
        sector = 5;
    }
    else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6))
    {
        sector = 6;
    }
    else if((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7))
    {
        sector = 7;
    }
    else if((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8))
    {
        sector = 8;
    }

    else if((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9))
    {
        sector = 9;
    }
    else if((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10))
    {
        sector = 10;
    }
    else if((Address < GD32_FLASH_END_ADDRESS) && (Address >= ADDR_FLASH_SECTOR_11))
    {
        sector = 11;
    }
    else
    {
    }
    return sector;
}

3.3 读 测试代码

static int gd32_flash_read(uint32_t addr, uint8_t *buf, size_t size)
{
    size_t i;

    if ((addr + size) > GD32_FLASH_END_ADDRESS)
    {
        printf("read outrange flash size! addr is (0x%p)\r\n", (void*)(addr + size));
        return -1;
    }

    for (i = 0; i < size; i++, buf++, addr++)
    {
        *buf = *(uint8_t *) addr;
        printf("read  flash  addr is (0x%p) ,data is %d\r\n", (void*)(addr ),*buf);
    }

    return size;
}

3.4 擦除 测试代码

static int gd32_flash_erase(uint32_t addr, uint32_t size)
{
    int result = 0;
    uint32_t FirstSector = 0, NbOfSectors = 0;

    if ((addr + size) > GD32_FLASH_END_ADDRESS)
    {
        printf("ERROR: erase outrange flash size! addr is (0x%p)\r\n", (void*)(addr + size));
        return -1;
    }

    fmc_unlock();        //解锁flash保护

    /* Get the 1st sector to erase */
    FirstSector = GetSector(addr);
    /* Get the number of sector to erase from 1st sector*/
    NbOfSectors = GetSector(addr + size - 1) - FirstSector + 1;

    fmc_flag_clear(FMC_FLAG_END);
    fmc_flag_clear( FMC_FLAG_OPERR );   
    fmc_flag_clear(FMC_FLAG_WPERR );   
    fmc_flag_clear( FMC_FLAG_PGMERR );   
    fmc_flag_clear(FMC_FLAG_PGSERR );   
    fmc_flag_clear(FMC_FLAG_RDDERR);       

    for(int i=0;i<NbOfSectors;i++,FirstSector++)
    { 
        if(fmc_sector_erase(CTL_SN(FirstSector))!=FMC_READY)//CTL_SN(FirstSector)
        {
            result = -1;
            goto __exit;
        }
    }    
__exit:
    
	fmc_lock();        //flash上锁
    if (result != 0)
    {
        return result;
    }

    printf("erase done: addr (0x%p), size %d\r\n", (void*)addr, size);
    return size;
}

3.5 写 测试代码

static int gd32_flash_write(uint32_t addr, const uint8_t *buf, uint32_t size)
{
    int result      = 0;
    uint32_t end_addr = addr + size;

    if ((end_addr) > GD32_FLASH_END_ADDRESS)
    {
        printf("write outrange flash size! addr is (0x%p)\r\n", (void*)(addr + size));
        return -1;
    }

    if (size < 1)
    {
        return -1;
    }

    fmc_unlock();        //解锁flash保护
    

    fmc_flag_clear(FMC_FLAG_END);
    fmc_flag_clear( FMC_FLAG_OPERR );   
    fmc_flag_clear(FMC_FLAG_WPERR );   
    fmc_flag_clear( FMC_FLAG_PGMERR );   
    fmc_flag_clear(FMC_FLAG_PGSERR );   
    fmc_flag_clear(FMC_FLAG_RDDERR);  
    
    
    
    for (uint32_t i = 0; i < size; i++, addr++, buf++)
    {

        /* write data to flash */
        if( fmc_byte_program(addr, (uint8_t)(*buf)) == FMC_READY )
        {
            if (*(uint8_t *)addr != *buf)
            {
                result = -1;
                break;
            }
        }
        else
        {
            result = -1;
            break;
        }
    }

    fmc_lock();        //flash上锁

    if (result != 0)
    {
        return result;
    }

    return size;
}

测试结果
在这里插入图片描述

参考
GD32F450ZGT6 手册

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值