YTM32的Flash控制器EFM模块详解

发布时间:2023年12月23日

YTM32的Flash控制器EFM模块详解

Flash存储器控制器EFM模块概述

Flash(闪存)是一种可擦除的只读存储器,按照实现方式和运行特性Flash一般还会分为NORNAND两种。其中NOR Flash支持随机地址的读取方式,在读取操作上类似于RAM,比较适合程序的直接读取运行,而NAND Flash读取是基于页的方式,一般无法随机读取。在微控制器中,Flash需要存储程序和数据,所以大多使用NOR Flash

YTM32的Flash存储器特性

YTM32系列MCU中通过Flash控制器EFM(Embedded Flash Module)控制管理Flash存储器,这里以ME0x系列MCU为例,EFM模块支持如下的一些功能:

  • 512KB x 2 的程序存储区域PFlash,带有ECC功能,Sector大小为2K
  • 256KB 单独的数据存储块DFlash,带有ECC功能,Sector大小为1K
  • 4KB的NVR区域,带有ECC功能,Sector大小为1K
  • 支持Flash按区域(16KB单位)的写保护功能。YTM32的M系列设计写保护固定为32x2个区域,总Flash
  • 支持配置禁用调试器
  • 支持产生Flash命令执行结束和异常中断
  • 支持Block Swap的OTA升级功能
  • 支持ECC错误地址记录和单比特、多比特中断
  • 支持OTP(One Time Program,一次可编程)区域
  • 支持HCU 密钥存储(可擦写,不可读取)
  • 支持块擦除、扇区(Sector)擦除和整个Chip的擦除操作
  • 最小写入页大小为 8 Bytes

Flash的约定术语

这里梳理使用Flash过程中常用的一些约定术语:

  • PFlash,程序Flash,实际也可以保存数据,属于基于应用场景的一种约定名称。
  • DFlash,数据Flash,实际也可以运行程序,属于基于应用场景的一种约定名称。
  • Block,Flash块的存储映射空间,表示物理上的一个Flash块(PFlash0、PFlash1、DFlash等),不同物理块的Flash相互之间可以支持Read While Write(RWW)特性。
  • Sector,扇区,是Flash擦除的最小单位,属于Flash的物理特性,软件无法修改。
  • Page,Flash 编程的最小单位,同样属于Flash物理特性,软件无法修改。
  • RWW,Read While Write,在运行擦除或者编程Flash的操作时,同时支持读Flash的操作。
  • ECC校验,纠错算法的一种,可以纠正单比特错误,检测多比特错误。

存储器的地址空间及定义

以ME0x微控制器为例,芯片系统存储的映射地址空间,如表x所示。

表x YTM32微控制器片内存储映射空间
Flash Device NameAddress SpaceSize(KB)BlockProtect
PFlash00x0000_0000 - 0x0007_FFFF512 KB0ADDR_PROT0
PFlash10x0008_0000 - 0x000F_FFFF512 KB1ADDR_PROT1
DFlash0x0010_0000 - 0x0013_FFFF256 KB2ADDR_PROT2
AES_NVR / HCU_NVR0x1000_0000 - 0x1000_03FF1 KB0No Read + Customer Key
OTP_NVR0x1001_0000 - 0x1001_03FF1 KB0No Erase
BOOT_NVR0x1002_0000 - 0x1002_03FF1 KB1SWAP CMD only
CUS_NVR0x1003_0000 - 0x1003_03FF1 KB1Customer Key

表x中PFlash0PFlash1是两个物理存储设备,可用于存储用户程序。当使用OTA应用时,这两个Block可以通过物理地址的重映射互换(BOOT_SWAP),方便实现应用升级。

AES_NVR(也有的手册上使用HCU_NVR的命名)主要用于保存HCU(硬件加密单元)中使用的密钥,该部分占用1KB空间,可以存放32 x 256 bit的密钥数据。为了可以保证密钥的安全,该部分区域支持用户的擦除和写入,但是不支持读取操作。当HCU需要使用密钥的时候,软件可以直接调用Flash的命令(Load AES Key (0x20))将需要用到的Key直接载入到HCU中使用,整个过程中,软件只能选择Key(的索引)而不能读取或者修改Key(的内容)。注意,对AES Key区域的写入和擦除操作,都需要先用Customer Key解锁(向EFM_CUS_KEY寄存器中写一次0x4dff32)。

OTP_NVR可以用于保存一次性可编程数据,OTP(One Time Program)区域的特点是,只能一次写入,不支持擦写和二次写入。在具体应用中,可以在该区域保存产品ID信息或者永久固化的信息。注意,对该区域的读取并没有限制。

BOOT_NVR可用来保存与OTA升级相关的数据,例如,当前作为Block0的PFlash索引,软件应该避免对该区域进行操作。

CUS_NVR包含Flash擦写保护配置和调试端口禁用的特定的数据标签(相当于是配置寄存器的值),用户可以向该区域的特定地址写入特定值,以启用对Flash的擦写保护和禁用调试端口。CUS_NVR的剩余部分是用户可以自由使用的,但对CUS_NVR的读写操作需要先通过写入Customer Key来解锁。

使用Flash存储器

读取(Read)、写入(Program)和擦除(Erase)是使用MCU内部集成Flash存储器的基本操作,Flash的特性是:擦除之后比特位的值变成1,写入操作是将相应的比特位的值改写成0。

由于YTM32的MCU的存储器都有ECC的机制,YTM32系列MCU都不支持二次写入操作(Re-Program),即不支持在Flash页的数据有非1的情况(已经被编程过)时再次对页编程。EFM外设在执行写入命令之前,会先从Flash中读取页数据,验证其数据为全1才能执行编程操作,否则若验证失败(无法通过ECC验证)则该页无法编程。

对Flash物理块的操作,在同一个时间,只能执行读取、写入或者擦除的任一操作,这就意味着用户在对一个物理块进行写入或者擦除操作时,不能读取Flash中的内容。也就是说,Flash在执行写入或者擦除的时候,处理器不能从Flash中继续读取程序执行代码,否则EFM模块会直接产生Bus Error(M0+中对应为hardfault)。这也是L系列MCU(仅有一块Flash物理存储块)在对Flash操作(包括DFlash)的时必须关闭中断的原因。

而M系列MCU内部集成了多块Flash物理存储块(MD集成了2个PFlash存储块,ME集成了2个PFlash存储块和1个DFlash存储块),在使用过程中,按照上述原则,虽然处理器在不能对同一个Block同时进行读写操作,但可以相互从操作,避开读写冲突,所以典型的使用方式有如下几种:

  1. PFlash0PFlash1用于保存程序和运行数据,DFlash用于保存Bootloader程序和模拟EEPROM的代码(模拟EEPROM的存储器在PFlash上)。这样,在Boot模式下,软件可以直接对两块PFlash进行读写操作而不必禁用系统中断;而在应用软件运行过程中,软件可以直接操作模拟EEPROM区域而不必禁用系统中断。
  2. 在上述配置的基础上使用OTA功能,PFlash0PFlash1分别保存一套程序代码,通过BOOT_SWAP指令,决定下次复位之后从哪个Block启动。当使用OTA功能的时候,当前Block运行的程序可以直接对另一个Block的Flash存储器进行擦写操作而不用关闭中断,因为这个时候软件是不会跳转到另外一个Block运行的,当然,如果软件在操作另外一个Block时,对这个Block的读操作也是不允许的。

擦写Flash的操作流

读取Flash的内容,只要按照常规访问存储空间的方式,使用地址寻址读数即可。无论是编译器,还是人为指定访问空间均可。

对于Flash的擦除和写入操作,则都是基于专门的命令来执行的,有命令清单如表x所示。

表x EFM模块操作Flash的命令列表
CodeDescriptionNeed Address
0x02Program 64 bitsY
0x03Program 64bits and read back verifyY
0x10Sector eraseY
0x11Sector erase and verifyY
0x12Erase block (only main array)Y
0x13Erase block and then verify (only main array)Y
0x1EErase chipN
0x20Load AES KeyN (Y in MD1)
0x30Boot SwapN
0x40Program NVRY
0x41Erase NVRY
0x42Read NVRY

用户可以写这些命令到EFM_CMD[CMD]寄存器字段中生效。如图x所示。
在这里插入图片描述

图x EFM CMD寄存器中可以生效的命令

表x中,需要传入地址的命令(Need Address一栏中为Y),获取地址参数的方式可分为两类:

  • 写PFlash和DFlash,是由EFM通过用户写特定地址的操作中提取出地址信息,作为EFM命令引擎中的地址参数。
  • 写NVR(各种NVR区域),通过向EFM_NVR_ADDR寄存器写地址值,再向EFM_NVR_DATA寄存器写将要写入的数值。之后再执行擦除或者写入NVR的命令。

以写入Flash的操作为例,执行一次64 bits数据的写入操作,并验证的命令流程如下:

  • 确认EFM的时钟参数设置合适,配置寄存器包括:EFM_TIMING1[TPREPROG]EFM_TIMING1[TPROG]EFM_TIMING2[TERASE]EFM_TIMING2[TERASE_RETRY]EFM_CTRL[PRESCALER]。(编程手册中并没有明确讲述确切的指标,但可参见SDK中的样例代码进行配置,大致是要确保操作Flash的时钟频率低于某个频率,24Mhz ???)。
  • 跳转到RAM中执行代码,并根据需要决定是否需要关闭全局中断。(如果是不同的Flash物理存储块之间相互操作,就不需要将代码复制到RAM中了,也不需要关中断)
  • 读取EFM_STS寄存器,判断EFM在当前是否正在执行命令。如果正忙就原地等一等。
  • 向需要写入Flash存储器的地址写入64bit长度数据。此时,将要写入的地址和数据,都被缓存在EFM的缓冲区中。
  • 0xfd9573f5EFM_CMD_UNLOCK寄存器,解锁EFM的命令引擎。每次解锁后只能执行一次命令,然后自动上锁。
  • 0x03EFM_CMD寄存器,开始执行写入并验证的命令。
  • 轮询读取EFM_STS寄存器,等待命令执行结束,并验证命令执行结果正常。

注意,若是执行擦除操作,用户仍需要通过写数到Flash地址空间的方式传入将要擦除Sector的地址,其中写数操作的数值无所谓,例如在SDK的驱动中,就随便用了一个0x12345678

操作Flash的时长

有些应用中对于Flash的写入和擦写的时间比较敏感,需要通过配合其他功能的时序完成功能,此处列写Flash基本操作的典型时间参数。如表x所示。

图x Flash操作的典型时长
操作M系列L系列
Sector Erase16ms4.5ms
Block Erase16ms35ms
Chip Erase16ms35ms
Page Program45us50us

操作Flash的时间同预分频和EFM_TIMING寄存器配置有关,上述表格的数据是在Prescaler预分频正确配置和TIMING保持默认值下的数据(参见SDK代码中的配置)。

M系列MCU擦除的时间都是16ms,Flash array支持多扇区同时擦写,所以整个Block块甚至整个芯片的擦除时间都是16ms,当采用Erase Retry的擦除方式时,EFM会按照800us的周期对Flash进行擦除尝试,这种方式下擦写的时间是800us~16ms。Erase Retry仅支持单个Sector的擦写。

L系列MCU只有一个Block的缘故,Block Erase和Chip Erase并没有什么区别,也不支持erase retry功能,另外L系列的DFlash实际和PFlash属于同一个Block,所以对DFlash进行擦写操作时候,也不支持对PFlash进行读操作。因此用DFlash模拟eeprom的时,仍然需要禁用系统中断。

EFM的其他关于Flash的“骚操作”

交换启动操作(Boot Swap Operation)

YTM32的两块PFlash(PFlash0PFlash1)会映射到两个地址Block块(Block0Block1),并且按照顺序映射地址空间。

在默认情况下,访问Block0的地址区间,在物理上就是访问PFlash0存储器。但若执行了BOOT_SWAP命令后(向EFM_CMD[CMD]寄存器字段中写命令码0x30,如图x所示),再复位重新上电,则会交换地址空间向PFlash0PFlash1的映射区间,Block0将会映射到PFlash1Block1将会映射到PFlash0
在这里插入图片描述

图x 向`EFM_CMD`寄存器中写`BOOT_SWAP`命令

当执行了BOOT_SWAP命令后,可通过查看标志位置位EFM_STS[BOOT_INFO]=1,确认BOOT_SWAP命令已生效。

当再次向EFM发送BOOT_SWAP命令后,两个Flash的Block块地址映射会再次反转,恢复成默认的情况,同时标志位清零EFM_STS[BOOT_INFO]=0

需要特别注意的是,如果刚执行BOOT_SWAP命令后,标志位被置位EFM_STS[BOOT_INFO]=1,则CUS_NVR存储区中的数据将被清除,这就意味着用户需要重新配置其中的选项,包括禁用SWD端口和地址保护等功能。

禁用调试端口和Flash保护

为了保护用户的软件代码不会被恶意地读取到芯片外面(被破解),ME系列支持通过EFM模块禁用芯片调试端口,这个过程是在芯片执行ROM中的初始化过程中通过硬件操作序列生效的。同样,为了避免程序在运行过程中对Flash进行意外操作,Flash同样支持基于地址的擦写保护,应用程序可以根据实际应用需求限制。

在YTM32B1ME0x中,CUS_NVR的起始地址是0x1001_0000U ,这部分NVR区域中数据定义如下:

Region(32bits)AddressDescription
Debugger Disable Tag 00x10010000TAG=0x5a5a5a5a Disable debugger
Debugger Disable Tag 10x10010004TAG=0x5a5a5a5a Disable debugger
PROT0 Tag0x10010008TAG=0x5a5a5a5a
PROT0 Value0x1001000CADDR_PROT0 Init value
PROT1 Tag0x10010010TAG=0x5a5a5a5a
PROT1 Value0x10010014ADDR_PROT1 Init value
PROT2 Tag0x10010018TAG=0x5a5a5a5a
PROT2 Value0x1001001CADDR_PROT2 Init value
User NVRUser can use other left space

因为NVR区域的页大小也是8 Bytes(64bits),实际单次至少写入两个32b字。例如,若需要在上电后禁用调试端口,需要向0x10010000U地址写入0x5a5a5a5a, 0x5a5a5a5a,如此,下次芯片复位后,调试端口默认就不会开启了。

需要特别注意,使用禁用JTAG/SWD模块的功能要特别小心,一旦关停之后,用户将不能通过调试器连处理器内核。建议用户在使用关停JTAG/SWD模块之前,先预留好“后门”,可通过使用其他通信端口的Bootloader更新Flash中的固件,或者能够通过预先准备好的程序擦除该区域以恢复使用JTAG/SWD模块。

表x中,ROT相应的tagvalue也是一起编程的,当tag匹配的时候(验证写数有效),下次上电对应的value就会自动载入到相应的寄存器(EFM_ADDR_PROT)实现对Flash的保护。

地址保护

可以通过配置EFM_PROTn寄存器(EFM_ADDR_PROTn),为Flash的地址存储区设置写保护,防止Flash中的关键存储区被意外篡改。以YTM32B1ME05 MCU为例,其中集成了1MB Flash存储区,设计了EFM_PROT0EFM_PROT1两个寄存器,分别对应两个地址块Block0和Block1,每个Block分为32个小块(对应EFM_PROTn寄存器中的每个寄存器位),每个小块对应16KB的存储区。

在默认情况下,EFM_PROTn寄存器中的所有寄存器位均为1,表示对应的存储区域可以正常擦写。一旦其中某个寄存器位被清零,表示对应的存储区域被保护起来,向这些区域的读写操作将被EFM忽视掉。

这组寄存器有Flash的特性,即仅能从1写0,不能从0写1。实际上,EFM_PROTn寄存器的物理存储地址,就映射在CUR_NVM区域中。因此,向EFM_PROTn寄存器中写数的方式有两种:

  • 直接向EFM_PROTn寄存器中写数。
  • CUR_NVM区域中偏移地址为0x10、0x18的区域中写入值,这些值将作为EFM_PROTn寄存器的初值(在上电复位后生效),每次写入的值都是64位,其中高32位必须为0x5A5A5A5A,低32位则位数则为指定的设置值。

参考文献

  • YTM32B1ME0x_RM_v1.3.pdf
  • 《YTM32系列MCU Flash模块功能详解》,https://www.linmingjie.cn/index.php/archives/378/
文章来源:https://blog.csdn.net/suyong_yq/article/details/135169257
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。