AS32A601型MCU芯片flash模块的擦除和编程

一、引言

在AS32A601中,片内Flash共包含两个存储器,分别为程序存储器(PFlash)和数据存储器(DFlash)。

Flash控制器作为CPU内核与片内Flash之间的桥梁,可用于管理任何主设备对片内Flash进行访问。Flash控制器可对Flash执行读取、编程和擦除操作,并实施写保护和读保护等安全机制。

二、Flash特性

EFlash存储器

  • PFlash最大支持2MB(包括4个block,即4×512KB)
  • DFlash最大支持512KB(包括1个block)
  • 寿命:≥100,000周期
  • 块(Block)容量:512KB/block
  • 扇区(Sector)容量:4KB/sector
  • 行(Row)容量:512B/row

EFlash控制器


操作列表:

  • 擦除:扇区擦除、块擦除、写保护信息区擦除、全片擦除
  • 编程:行编程,编程最小单位64-bit
  • 读:支持8-bit/16-bit/32-bit/64-bit宽度读数据

安全措施:

  • 支持写保护功能
  • 支持读保护功能
  • 可通过安全密钥临时解锁读保护功能
2.1 EFlash存储空间

表 2.1 EFlash存储器组织结构表

存储区

空间

地址范围

扇区

起始地址

结束地址

大小

PFlash

主存储区

2MB

0x0100_0000~0x011F_FFFF

sector0

0x0100_0000

0x0100_0FFF

4KB

sector1

0x0100_1000

0x0100_1FFF

4KB

sector2

0x0100_2000

0x0100_2FFF

4KB

sector511

0x011F_F000

0x011F_FFFF

4KB

信息区

16KB

0x0120_0000~0x0120_3FFF

info sector0

0x0120_0000

0x0120_0FFF

4KB

info sector1

0x0120_1000

0x0120_1FFF

4KB

info sector2

0x0120_2000

0x0120_2FFF

4KB

info sector3

0x0120_3000

0x0120_3FFF

4KB

DFlash

主存储区

512KB

0x0200_0000~0x0207_FFFF

sector512

0x0200_0000

0x0200_0FFF

4KB

sector513

0x0200_1000

0x0200_1FFF

4KB

sector514

0x0200_2000

0x0200_2FFF

4KB

sector639

0x0207_F000

0x0207_FFFF

4KB

信息区

4KB

0x0208_0000~0x0208_0FFF

info sector4

0x0208_0000

0x0208_0FFF

4KB

2.2 EFlash命令

表 2.2 EFlash命令表

操作类型

命令

ID

描述

擦除

扇区擦除

0x01

按扇区擦除PFlash或DFlash的主存储区

块擦除

0x02

擦除指定Block的主存储区

写保护信息扇区擦除

0x03

擦除写保护信息所在扇区

全片擦除

0x04

擦除PFlash的DFlash全部区域

编程

行编程

0x10

按照64-bit对齐的方式编程PFlash或DFlash,一次最大可编程一行

验证

Security Key验证

0x20

根据指定的安全密钥验证是否和存储在信息区的密钥匹配

三、应用说明

为了防止用户误操作EFlash,配置EFlash寄存器前首先需要解锁,否则无法写EFlash寄存器,解锁方式参考如下步骤1所描述。

为了保证EFlash正常工作,务必在系统时钟初始化完成后解锁EFlash,然后配置EFLASH_CNFG配置寄存器的CLKFRQ位,具体配置请参考该寄存器位说明。

EFlash命令操作流程均相同,操作步骤如下:

  1. 通过向EFLASH_KEY解锁寄存器写入正确的解锁密钥(依次写入0x01020304和0x0A0B0C0D)解锁EFlash;
  2. 通过检测EFLASH_STATE状态寄存器的BUSY位,判断当前是否有命令正在执行。如果有命令正在执行(BUSY=1)则等待当前命令执行完成后(BUSY=0或FINISH=1),再执行步骤3;
  3. 配置EFlash相关配置寄存器以及EFLASH_CMD命令ID寄存器,然后配置EFLASH_START命令触发寄存器的START位为1,触发EFlash命令执行。后续章节不同的命令仅针对该步骤做详细描述,其他通用的步骤不再做描述;
  4. 通过检测EFLASH_STATE状态寄存器的FINISH位来判断该命令是否执行完成,检测OPERR位、WPERR位等状态位来判断该命令执行是否发生错误;
  5. 配置EFLASH_STATE状态寄存器,清除相关状态位;
  6. 操作完EFlash寄存器后,可通过向EFLASH_KEY解锁寄存器写入非正确密钥即可锁定EFlash。
3.1擦除

AS32A601驱动库提供了扇区擦除和块擦除两个函数,本文档就扇区擦除函数详细讲解。

扇区擦除命令能把指定地址所在的扇区的数据全部擦除,该命令的配置步骤如下:

  1. 配置扇区擦除地址到EFLASH_ADDR地址寄存器,该地址需要8字节对齐,否则触发扇区擦除命令的执行时,会产生操作错误(即EFLASH_STATE寄存器的OPERR位置1);
  2. 配置扇区擦除命令(0x01)到EFLASH_CMD命令ID寄存器;
  3. 配置EFLASH_START寄存器的START位为1,触发扇区擦除命令的执行。

FLASHStatus_TypeDef FLASH_EraseSector(uint32_t Addr, uint32_t Size)  
{  
    FLASHStatus_TypeDef ret = FLASH_SUCCESS;  
    uint32_t sectorsize = 0x00;  
    uint32_t tempsize = Size;  
  
    /* Check the parameters */  
    assert_param((Addr % 0x08) == 0);  
    assert_param(Size > 0);  
  
    /* Check if command is completed by BUSY */  
    if(FLASH_GetFlagStatus(FLASH_FLAG_BUSY) == SET)  
    {  
        return FLASH_BUSY;  
    }  
  
    /* Determine the flash object of the operation */  
    if ((Addr >= P_FLASH_Main_BASE) && ((Addr + tempsize) <= (P_FLASH_Main_BASE + PFLASH_MAIN_SIZE)))   
    {  
        sectorsize = (uint32_t)PFLASH_SECTOR_SIZE;  
    }  
    else if ((Addr >= D_FLASH_Main_BASE) && ((Addr + tempsize) <= (D_FLASH_Main_BASE + DFLASH_MAIN_SIZE)))  
    {  
        sectorsize = (uint32_t)DFLASH_SECTOR_SIZE;  
    }  
    else  
    {  
        ret = FLASH_ERROR;  
        tempsize = 0U;  
        sectorsize = 0U;  
    }  
  
    while ((tempsize > 0U) && (FLASH_SUCCESS == ret))   
    {  
        /* Set flash sector erase command */  
        FLASH_SetAddress(Addr);  
        FLASH_SetCommand(FLASH_Cmd_SectorErase);  
  
  
        ret = FLASH_StartCmd();  
        /* Start command */  
        if (ret == FLASH_ERROR)   
        {  
            return FLASH_ERROR;  
        }  
        else if (ret == FLASH_BUSY)  
        {  
            return FLASH_BUSY;  
        }  
        else  
        {  
            /* Nothing to do */  
        }  
  
        /* Update size and address */  
        tempsize -= sectorsize;  
        Addr += sectorsize;  
    }  
  
    return ret;  
} 

第1行,Size参数单位为字节,固定为4096,与sector大小相等。第9行检查地址是否8字节对齐,要求余数必须为0,即地址必须是8的倍数。第33行,循环条件:当还有字节要擦除(tempsize > 0U)且操作状态为成功(FLASH_SUCCESS == ret) 。第36-38行,调用FLASH_SetAddress()函数设置当前要擦除的扇区地址,调用FLASH_SetCommand()函数设置命令为扇区擦除。

总结:在使用扇区擦除函数前,用户需要解锁flash,使用后给flash上锁,size参数应固定为4096。

3.2编程函数

编程命令用于编程数据到EFlash中,最小的编程单位为64-bit。需要注意的是:根据EFlash的要求,单次编程操作不允许跨行编程(即,每次编程只允许对EFlash的一行进行编程数据),EFlash一行的容量为512B(即64*64bit)。该命令的配置步骤如下:

  1. 配置编程地址到EFLASH_ADDR寄存器,该地址需要8字节对齐,否则触发编程命令的执行时,会产生操作错误(即EFLASH_STATE寄存器的OPERR位置1);
  2. 配置编程长度到EFLASH_LEN寄存器,该位的最小长度为1(即64-bit),最大长度为64(即EFlash一行的数据长度);
  3. 配置编程命令(0x10)到EFLASH_CMD寄存器;
  4. 配置编程数据低32-bit到EFLASH_DATA0寄存器;
  5. 配置编程数据高32-bit到EFLASH_DATA1寄存器;
  6. 若编程长度大于1,则需要继续执行步骤4,、5,直至将编程数据全部写入;
  7. 配置EFLASH_START寄存器的START位为1,触发编程命令的执行。

FLASHStatus_TypeDef FLASH_ProgramRom(uint32_t Addr, uint32_t Size, const uint32_t *Data)  
{  
    FLASHStatus_TypeDef ret = FLASH_SUCCESS;  
    uint32_t addrcount = 0x00, sizetemp = 0x00;  
    uint32_t romsize = 0x00;  
  
    /* Check the parameters */  
    assert_param((0 < Size) && ((Size % EFLASH_WRITE_UNIT_SIZE) == 0));  
    assert_param(NULL != Data);  
  
    /* Check if command is completed by BUSY */  
    if(FLASH_GetFlagStatus(FLASH_FLAG_BUSY) == SET)  
    {  
        return FLASH_BUSY;  
    }  
  
    /* Check address */  
    if ((Addr >= P_FLASH_Main_BASE) && ((Addr + Size) <= (P_FLASH_Main_BASE + PFLASH_MAIN_SIZE)))   
    {  
        romsize = PFLASH_ROM_SIZE;  
    }   
    else if ((Addr >= D_FLASH_Main_BASE) && ((Addr + Size) <= (D_FLASH_Main_BASE + DFLASH_MAIN_SIZE)))  
    {  
        romsize = DFLASH_ROM_SIZE;  
    }  
    else  
    {  
        ret = FLASH_ERROR;  
    }  
  
    /* Judge size and feed write */  
    addrcount = Size / romsize;  
    if(0 != (Size % romsize))  
    {  
        addrcount += 1;  
    }  
    else  
    {  
        /* Nothing to do */  
    }  
  
    while ((FLASH_SUCCESS == ret) && (addrcount > 0U))   
    {  
        if (Size >= romsize)   
        {  
            sizetemp  = romsize;  
        }   
        else   
        {  
            sizetemp  = Size;  
        }  
        /* Set address and data length */  
                    
                EFLASH->AR = Addr;  
        FLASH_SetAddress(Addr);  
        FLASH_SetDataLength(sizetemp / EFLASH_WRITE_UNIT_SIZE);  
  
        /* Set rom program command */  
        FLASH_SetCommand(FLASH_Cmd_Program);  
  
        while ((sizetemp > 0U) && (FLASH_SUCCESS == ret))   
        {  
            /* Write 64 bit data */  
            FLASH_SetLowData(Data[0]);  
            FLASH_SetHighData(Data[1]);  
  
            /* Update data adddress*/  
            Data += 2;  
            sizetemp -= EFLASH_WRITE_UNIT_SIZE;  
        }  
  
        ret = FLASH_StartCmd();  
  
        /* Start command */  
        if (ret == FLASH_ERROR)   
        {  
            return FLASH_ERROR;  
        }  
        else if (ret == FLASH_BUSY)  
        {  
            return FLASH_BUSY;  
        }  
        else  
        {  
            /* Nothing to do */  
        }  
  
        /* Update adddress*/  
        Addr += romsize;  
        addrcount--;  
        Size -= romsize;  
    }  
  
    return ret;  
}  

第13-17行,检查命令是否因忙状态而完成。第20-31行,检查地址,第一个if:检查是否在主Flash范围内,条件:地址在主Flash基址到结束地址之间,如果满足:设置romsize为主Flash的ROM大小,else if:检查是否在数据Flash范围内,else:地址无效,设置ret为FLASH_ERROR。第68-71行,分别设置低32位数据(Data[0])和高32位数据(Data[1])。第73-74行,指针增加2(64位/8字节),指向下一个64位数据

总结,最小编程单位64bit(8字节),因此,Size参数应为8的倍数。

3.3 ECC

EFlash支持ECC功能,相关功能如下:

  1. ECC 1-bit错误自动纠正,且会将EFLASH_STATE寄存器的ECC1ERR位置1;
  2. ECC 2-bit错误无法纠正,且会将EFLASH_STATE寄存器的ECC2ERR位置1,并记录发生该错误的地址,存入EFLASH_ECC_ADDR寄存器中;
  3. 若ECC错误中断使能(即EFLASH_CNFG寄存器的ECC2EIE位置1),则当检测到ECC发生2-bit错误时,会产生ECC中断,并将EFLASH_STATE的ECC2ERR位置1,建议在中断中写1清除该中断标记。

若用户出现编程或擦除失败,请关注EFLASH_STATE寄存器,是否ECC错误置1,调用clearflag函数清楚标志位后再对EFLASH操作

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值