0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

ametal中如何使用flash存储器?

AGk5_ZLG_zhiyua 来源:互联网 作者:佚名 2017-11-07 14:33 次阅读

周立功教授新书《面向AMetal框架与接口编程(上)》,对AMetal框架进行了详细介绍,通过阅读这本书,你可以学到高度复用的软件设计原则和面向接口编程的开发思想,聚焦自己的“核心域”,改变自己的编程思维,实现企业和个人的共同进步。经周立功教授授权,即日起,致远电子公众号将对该书内容进行连载,愿共勉之。

第六章为重用外设驱动代码,本文内容为6.2 SPI NOR Flash 存储器。

6.2 SPI NOR Flash 存储器

SPI NOR Flash 是一种SPI 接口的非易失闪存芯片,本节以***旺宏电子的MX25L1606为例详细介绍在AMetal 中如何使用类似的Flash 存储器。

>>> 6.2.1 基本功能

MX25L1606 总容量为16M(16×1024×1024)bits,即2M字节。每个字节对应一个存储地址,因此其存储数据的地址范围为0x000000 ~ 0x1FFFFF。

在MX25L1606 中,存储器有块(block)、扇区(sector)和页(page)的概念。页大小为256 字节,每个扇区包含16页,扇区大小为4K(4096)字节,每个块包含16 个扇区,块的大小为64K(65536)字节,其组织结构示意图详见表6.5。

表6.5 MX25L1606 存储器组织结构

MX25L1606 的通信接口为标准4 线SPI 接口(支持模式0 和模式3),即CS、MOSI、MISO、CLK,详见图6.3。其中,CS(#1)、SO(#2)、SI(#5)、SCLK(#6)分别为SPI 的CS、MISO、MOSI 和CLK 信号引脚。特别地,WP(#3)用于写保护,HOLD(#7)用于暂停数据传输。一般来说,这两个引脚不会使用,可通过上拉电阻上拉至高电平。MicroPort-NorFlash 模块通过MicroPort 接口与AM824-Core 相连。

图6.3 SPI Flash 电路原理

>>> 6.2.2 初始化

AMetal 提供了支持常见的MX25L8006、MX25L1606……等系列SPI Flash 器件的驱动函数,使用其它各功能函数前必须先完成初始化,其函数原型(am_mx25xx.h)为:

该函数意在获取器件的实例句柄mx25xx_handle。其中,p_dev 为指向am_mx25xx_dev_t类型实例的指针,p_devinfo 为指向am_mx25xx_devinfo_t 类型实例信息的指针。

(1)实例

定义am_mx25xx_dev_t 类型(am_mx25xx.h)实例如下:

其中,g_mx25xx_dev 为用户自定义的实例,其地址作为p_dev 的实参传递。

(2)实例信息

实例信息主要描述了具体器件的固有信息,即使用的SPI 片选引脚、SPI 模式、SPI 速率和器件具体型号等,其类型am_mx25xx_devinfo_t 的定义(am_mx25xx.h)如下:

其中,spi_mode 为SPI 模式,MX25L1606 支持模式0(AM_SPI_MODE_0)和模式3(AM_SPI_MODE_3)。spi_cs_pin 为与实际电路相关的片选引脚,MicroPort-NorFlash 模块通过MicroPort 接口与AM824-Core 相连时,默认片选引脚为PIO0_1。spi_speed 为时钟信号的频率,针对MX25L1606,其支持的最高频率为86MHz,因此可以将该值直接设置为86000000。但由于LPC824 芯片的主频为30MHz,所以SPI 最大速率仅30MHz。type 为具体器件的型号,其包含了具体型号相关的信息,比如,页大小信息等,当前已经支持的器件型号详见am_mx25xx.h 中对应的宏,MX25L1606 对应的宏为:AM_MX25XX_MX25L1606。

基于以上信息,实例信息定义如下:

其中,g_mx25xx_devinfo 为用户自定义的实例信息,其地址作为p_devinfo 的实参传递。

(3)SPI 句柄spi_handle

若使用LPC824 的SPI0 与MX25L1606 通信,则通过LPC82x 的SPI0 实例初始化函数am_lpc82x_spi0_inst_init()获得SPI 句柄。即:

SPI 句柄即可直接作为spi_handle 的实参传递。

(4)实例句柄

MX25L1606 初始化函数am_mx25xx_init ()的返回值MX25L1606 实例的句柄,作为其它功能接口(擦除、读、写)的第一个参数(handle)的实参。

其类型am_mx25xx_handle_t(am_mx25xx.h)定义如下:

若返回值为NULL,说明初始化失败;若返回值不为NULL,说明返回了有效的handle。

基于模块化编程思想,将初始化相关的实例、实例信息等的定义存放到对应的配置文件中,通过头文件引出实例初始化函数接口,源文件和头文件的程序范例分别详见程序清单6.14 和程序清单6.15。

程序清单6.14 实例初始化函数范例程序(am_hwconf_mx25xx.c)

程序清单6.15 实例初始化函数接口(am_hwconf_mx25xx.h)

后续只需要使用无参数的实例初始化函数,即可获取到MX25xx 的实例句柄。即:

注意,spi_handle 用于区分SPI0、SPI1,mx25xx_handle 用于区分同一系统中的多个MX25xx 器件。

>>> 6.2.3 接口函数

SPI Flash 比较特殊,在写入数据前必须确保相应的地址单元已经被擦除,因此除读写函数外,还有一个擦除函数,其接口函数详见表6.6。

表6.6 MX25xx 接口函数

各API 的返回值含义都是相同的:AM_OK 表示成功,负值表示失败,失败原因可根据具体的值查看am_errno.h 文件中相对应的宏定义。正值的含义由各API 自行定义,无特殊说明时,表明不会返回正值。

1. 擦除

擦除就是将数据全部重置为0xFF,即所有存储单元的位设置为1。擦除操作并不能直接擦除某个单一地址单元,擦除的最小单元为扇区,即每次只能擦除单个或多个扇区。擦除一段地址空间的函数原型为:

其中,handle 为MX25L1606 的实例句柄,addr 为待擦除区域的首地址,由于擦除的最小单元为扇区,因此该地址必须为某扇区的起始地址0x000000(0)、0x001000(4096)、0x002000(2×4096)……同时,擦除长度必须为扇区大小的整数倍。

如果返回AM_OK,说明擦除成功,反之失败。假定需要从0x001000 地址开始,连续擦除2 个扇区,范例程序详见程序清单6.16。

程序清单6.16 擦除范例程序

0x001000 ~ 0x3FFF 空间被擦除了,即可向该段地址空间内写入数据。

2. 写入数据

在写入数据前,需确保写入地址已被擦除。即将需要变为0 的位清0,但写入操作无法将0 变为1。比如,写入数据0x55 就是将bit1、bit3、bit5、bit7 清0,其余位的值保持不变。若存储的数据已经是0x55,再写入0xAA(写入0xAA 实际上就是将bit0、bit2、bit4、bit6清0,其余位不变),则最终存储的数据将变为0x00,而不是后面再写入的0xAA。因此为了保证正常写入数据,写入数据前必须确保相应的地址段已经被擦除了。

从指定的起始地址开始写入一段数据的函数原型为:

如果返回AM_OK,说明写入数据成功,反之失败。假定从0x001000 地址开始,连续写入128 字节数据,范例程序详见程序清单6.17。

程序清单6.17 写入数据范例程序

虽然只写入了128 字节数据,但由于擦除的最小单元为扇区,因此擦除了4096 字节(一个扇区)。已经擦除的区域后续可以直接写入数据,而不必再次擦除,比如,紧接着写入128字节数据后的地址,再写入128 字节数据,详见程序清单6.18。

程序清单6.18 写入数据范例程序

若需要再次从0x001000 地址连续写入128 字节数据,由于之前已经写入过数据,因此必须重新擦除后方可再次写入。

3. 读取数据

从指定的起始地址开始读取一段数据的函数原型为:

如果返回值为AM_OK,则说明读取成功,反之失败。假定从0x001000 地址开始,连续读取128 字节数据,详见程序清单6.19。

程序清单6.19 读取数据范例程序

范例程序的实现和接口详见程序清单6.20 和程序清单6.21。

程序清单6.20 MX25XX 测试程序实现(app_test_mx25xx.c)

由于读写数据需要的缓存空间较大(128 字节),因此在缓存的定义前增加了static 修饰符,使其内存空间从全局数据区域中分配。如果直接从函数的运行栈中分配128 字节空间,则完全有可能导致栈溢出,进而系统崩溃。

程序清单6.21 MX25XX 测试程序接口声明(app_test_mx25xx.h)

相应的范例程序详见程序清单6.22。

程序清单6.22 MX25L1602 读写范例程序

由于app_test_mx25xx()的参数为MX25XX 的实例handle,与MX25xx 器件具有依赖关系,因此无法实现跨平台调用。

>>> 6.2.4 MTD 通用接口函数

由于MX25L1606 是典型的FLASH 存储器件,因此将其抽象为一个读写MX25L1606的MTD(Memory Technology Device),使之与具体器件无关,实现跨平台调用,其函数原型详见表6.7。

表6.7 MTD 通用接口函数

1 MTD 初始化函数

MTD 初始化函数意在获取MTD 实例句柄,其函数原型为:

其中,MX25L1606 实例句柄(mx25xx_handle)作为实参传递给handle,p_mtd 为指向am_mtd_serv_t 类型实例的指针,reserved_nblks 作为实例信息,表明保留的块数。

  • 实例(MTD 存储设备)

定义am_mtd_serv_t 类型(am_mtd.h)实例如下:

其中,g_mx25xx_mtd 为用户自定义的实例,其地址作为p_mtd 的实参传递。

  • 实例信息

reserved_nblks 表示实例相关的信息,用于MX25L1606 保留的块数,这些保留的块不会被MTD 标准接口使用。保留的块从器件的起始块开始计算,若该值为5,则MX25XX 器件的块0~块4 将不会被MTD 使用,MTD 读写数据将从块5 开始。如果没有特殊需求,则该值设置为0。

将MTD 初始化函数的调用存放到配置文件中,引出对应的实例初始化接口,详见程序清单6.23 和程序清单6.24。

程序清单6.23 新增MTD 实例初始化函数(am_hwconf_mx25xx.c)

程序清单6.24 am_hwconf_mx25xx.h 文件内容更新(1)

am_mx25xx_mtd_inst_init()函数无任何参数,与其相关实例和实例信息的定义均在文件内部完成,因此直接调用该函数即可获得MTD 句柄。即:

这样一来,在后续使用其它MTD 通用接口函数时,均可使用该函数的返回值mtd_handle作为第一个参数(handle)的实参传递。

显然,若使用MX25XX 接口,则调用am_mx25xx_inst_init()获取MX25XX 实例句柄;若使用MTD 通用接口,则调用am_mx25xx_mtd_inst_init()获取MTD 实例句柄。

2. 擦除

写入数据前需要确保相应地址已经被擦除,其函数原型为:

擦除单元的大小可以使用宏AM_MTD_ERASE_UNIT_SIZE_GET()获得。比如:

其中的addr 表示擦除区域的首地址,必须为擦除单元大小的整数倍。同样地,len 也必须为擦除单元大小的整数倍。由于MX25L1606 擦除单元的大小与扇区大小(4096)一样,因此addr 必须为某扇区的起始地址0x000000(0)、0x001000(4096)、0x002000(2×4096)……

如果返回AM_OK,说明擦除成功,反之失败。假定从0x001000 地址开始,连续擦除2个扇区,范例程序详见程序清单6.25。

程序清单6.25 擦除范例程序

使用该段程序后,地址空间0x001000 ~ 0x3FFF 即被擦除了,后续即可向该段地址空间内写入数据。

3. 写入数据

写入数据前需要确保写入地址已被擦除,其函数原型为:

如果返回AM_OK,说明写入数据成功,反之失败。假定从0x001000 地址开始,连续写入128 字节数据的范例程序详见程序清单6.26。

程序清单6.26 写入数据范例程序

4. 读取数据

从指定的起始地址开始读取一段数据的函数原型为:

如果返回值为AM_OK,则说明读取成功,反之失败。假定从0x001000 地址开始,连续读取128 字节数据的范例程序详见程序清单6.27。

程序清单6.27 读取数据范例程序

MTD 通用接口测试程序和接口分别详见程序清单6.28 和程序清单6.29。

程序清单6.28 MTD 测试程序实现(app_test_mtd.c)

程序清单6.29 接口声明(app_test_mtd.h)

由于该程序只需要MTD 句柄,因此与具体器件无关,可以实现跨平台复用。若读写数据的结果完全相等,则返回AM_OK,反之返回AM_ERROR,范例程序详见程序清单6.30。

程序清单6.30 MTD 读写范例程序

>>> 6.2.5 FTL 通用接口函数

由于此前的接口需要在每次写入数据前,确保相应的存储空间已经被擦除,则势必会给编程带来很大的麻烦。与此同时,由于MX25L1606 的某一地址段擦除次数超过10 万次的上限,则在相应段地址空间存储数据将不再可靠。

假设将用户数据存放到0x001000~0x001FFF 连续的4K 地址中,则每次更新这些数据都要重新擦除该地址段。而其它存储空间完全没有使用过,MX25L1606 的使用寿命大打折扣。AMetal 提供了FTL(Flash Translation Layer)通用接口供用户使用,其函数原型详见表6.8。

表6.8 FTL 通用接口函数(am_ftl.h)

1. FTL 初始化函数

FTL 初始化函数意在获取FTL 实例句柄,其函数原型为:

其中,p_ftl 为指向am_ftl_serv_t 类型实例的指针,p_buf 和len 作为实例信息,为FTL驱动程序提供必要的RAM 空间,MTD 初始化函数获得mtd_handle 为MTD 实例句柄。

(1)实例

定义am_ftl_serv_t 类型(am_mtd.h)实例如下:

其中,g_ftl 为用户自定义的实例,其地址作为p_ftl 的实参传递。

(2)实例信息

FTL 驱动程序需要使用一定的RAM 空间,这也是使用FTL 通用接口所要付出的代价。由于该空间的大小与具体器件的容量大小、擦除单元大小相关,因此该内存空间由用户根据实际情况提供。需要的内存大小(字节数)由下面的公式得到:

其中,sizeerase 为擦除单元的大小,对于MX25L1606,其为扇区大小,即4096。sizemtd_chip为MTD 实例的总容量。MX25L1606 对应的MTD 实例,其大小为除去保留块的总容量,若保留块为0,就是MX25L1606 的容量大小,即2M。需要的内存容量大小为:

对于MX25L1606,若使用FTL,则需要大约2.5KB 的RAM。显然对于一些小型嵌入式系统来说,RAM 的耗费实在“太大”了,所以要根据实际情况选择是否使用FTL。若RAM充足,而又比较在意Flash 的使用寿命,可以选择使用FTL。容量大小使用am_ftl.h 中的宏:

该宏根据器件总容量和擦除单元大小,自动计算实际需要的RAM 大小。

若使用FTL 通用接口操作MX25L1606,则需要定义如下内存空间供FTL 使用。即:

其中,g_ftl_buf 为内存空间的首地址,其作为p_buf 的实参传递,内存空间的大小(即数组元素的个数)作为len 的实参传递。

(3)MTD 句柄mtd_handle

该MTD 句柄可以通过MTD 实例初始化函数获得。即:

获得的MTD 句柄即可直接作为mtd_handle 的实参传递。

(4)实例句柄

FTL 初始化函数am_ftl_init ()的返回值为FTL 实例句柄,该句柄将作为读写接口第一个参数(handle)的实参。其类型am_ftl_handle_t(am_ftl.h)定义如下:

若返回值为NULL,说明初始化失败;若返回值不为NULL,说明返回了有效的handle。

将FTL 初始化函数的调用存放到配置文件中,引出对应的实例初始化接口,详见程序清单6.31 和程序清单6.32。

程序清单6.31 新增FTL 实例初始化函数(am_hwconf_mx25xx.c)

程序清单6.32 am_hwconf_mx25xx.h 文件内容更新(2)

am_mx25xx_ftl_inst_init()无任何参数,与其相关实例和实例信息的定义均在文件内部完成,因此直接调用该函数即可获得FTL 句柄。即:

这样一来,在后续使用其它FTL 通用接口函数时,均可使用该函数的返回值ftl_handle作为第一个参数(handle)的实参传递。

2. 写入数据

当调用FTL 通用接口时,读写数据都是以块为单位,每块数据的字节数固定为512 字节。其函数原型为:

为了延长Flash 的使用寿命,在实际写入时,会数据写入到擦除次数最少的区域。因此lbn 只是一个逻辑块序号,与实际的存储地址没有关系。逻辑块只是一个抽象的概念,每个逻辑块的大小固定为512 字节,与MX25L1606 的物理存储块没有任何关系。

由于MX25L1606 每个逻辑块固定为512 字节,因此理论上逻辑块的个数为4096(2×1024×1024÷512),lbn 的有效值为0 ~ 4095。但实际上擦除每个单元都要耗费一个逻辑块,MX25L1606 擦除单元的大小为4096,即512 个擦除单元,因此FTL 消耗了512 个逻辑块,则可用的逻辑块为3584(4096~512)个,lbn 的有效值为0~3583。

由此可见,FTL 不仅要占用2.5K RAM,还要占用256K 的MX25L1606 存储空间(512个逻辑块,每个逻辑块大小为512 字节),这也是使用FTL 要付出的“代价”。如果返回AM_OK,说明写入数据成功,反之失败。假定写入一块数据(512 字节)至逻辑块2 中,其范例程序详见程序清单6.33。

程序清单6.33 写入数据范例程序

3. 读取数据

读取一块数据的函数原型为:

如果返回值为AM_OK,则说明读取成功,反之失败。假定从逻辑块2 中读取一块(512字节)数据,其范例程序详见程序清单6.34。

程序清单6.34 读取数据范例程序

FTL 通用接口测试程序和接口分别详见程序清单6.35 和程序清单6.36。

程序清单6.35 FTL 测试程序实现(app_test_ftl.c)

程序清单6.36 FTL 测试接口声明(app_test_ftl.h)

由于写入前无需再执行擦除操作,则编写应用程序更加便捷。同样,由于应用程序仅仅只需要FTL 句柄,则所有接口也全部为FTL 通用接口,因此应用程序是可以跨平台复用的,范例程序详见程序清单6.37。

程序清单6.37 FTL 读写范例程序

>>> 6.2.6 微型数据库

由于哈希表所使用的链表头数组空间、关键字和记录值等都存储在malloc 分配的动态空间中,这些信息在程序结束或系统掉电后都会丢失。在实际的应用中,往往希望将信息存储在非易失存储器中。典型的应用是将信息存储在文件中,从本质上来看,只要掌握了哈希表的原理,无论信息存储在什么地方,操作的方式都是一样的。

在AMetal 中,基于非易失存储器实现了一套可以直接使用的哈希表接口,由于数据不会因为掉电或程序终止而丢失,因此可以将其视为一个微型数据库,相关接口详见表6.9。

表6.9 数据库接口(hash_kv.h)

显然,除命名空间由 hash_db_*修改为了hash_kv_*(为了与之前的程序进行区分)外,仅仅是初始化函数中,多了一个文件名参数,即内部不再使用malloc 分配空间存储记录信息,而是使用该文件名指定的文件存储相关信息。如此一来记录存储在文件中,信息不会因掉电或程序终止而丢失。其中,hash_kv_t 为数据库结构体类型,使用数据库前,应使用该类型定义一个数据库实例,比如,“hash_kv_t hash;”。

由于各个函数的功能与《程序设计与数据结构》一书中介绍的哈希表的各个函数的功能完全一致,因此可以使用如程序清单6.38 所示的代码进行测试验证。

程序清单6.38 数据库综合范例程序


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

原文标题:周立功:重用外设驱动代码——SPI NOR Flash 存储器

文章出处:【微信号:ZLG_zhiyuan,微信公众号:ZLG致远电子】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    求助 数据存储器 FLASH程序存储器 FLASH数据存储器的区别

    数据存储器 FLASH程序存储器 FLASH数据存储器 片内RAM数据存储器16M字节外部数据
    发表于 11-29 09:50

    Flash存储器分为哪几类?Flash存储器有什么特点?

    Flash存储器分为哪几类?Flash存储器有什么特点?Flash与DRAM有什么区别?
    发表于 06-18 07:03

    C8051F020Flash存储器的在线擦写方法

    从C8 0 5 1F0 2 x Fl a s h 存储器的结构可以知道,C8051F02x 的Flash 存储器,不仅具有64KB 的Flash
    发表于 04-15 10:50 124次下载

    Flash存储器的内建自测试设计

    内建自测试是一种有效的测试存储器的方法。分析了NOR型flash存储器的故障模型和测试存储器的测试算法,在此基础上,设计了flash
    发表于 07-31 17:08 35次下载

    Flash存储器概述

      Flash 存储器的简介   在众多的单片机中都集成了 Flash 存储器系统,该存储器系统可用作代码和数据
    发表于 11-11 18:25 4937次阅读
    <b class='flag-5'>Flash</b><b class='flag-5'>存储器</b>概述

    flash存储器在线编程

    高、低功耗、成本较低等特点。一般我们都认为Flash储存器具备固有不挥发性、易更新性,可靠性好的基本特性。 从 Flash储存的基本特点可以看出,在单片机,可以利用F1ash
    发表于 10-11 18:57 4029次阅读
    <b class='flag-5'>flash</b><b class='flag-5'>存储器</b>在线编程

    flash存储器的读写原理及次数

    FLASH存储器又称闪存,是一种长寿命的非易失性(在断电情况下仍能保持所存储的数据信息)的存储器,由于其断电时仍能保存数据,FLASH
    发表于 10-13 16:34 2.1w次阅读

    flash存储器原理及作用是什么?

    flash存储器,及闪速存储器,这一类型的存储器具有速度快、方便等特点,是人们使用电脑办公或者娱乐时必备的工具。
    发表于 10-30 08:54 3.3w次阅读

    DRAM、NAND FLASH、NOR FLASH三大存储器分析

    存储器内的信息仍然存在,主要是闪存(Nand FLASH 和 NOR FLASH),NOR 主要应用于代码存储介质,而 NAND 则用于
    的头像 发表于 04-09 15:45 11.2w次阅读

    如何区分各种存储器(ROM、RAM、FLASH

    相信有很多人都对计算机里的各种存储器(ROM、RAM、FLASH 等等)傻傻分不清,就会存在,内存条是 dram 还是 nand?nand flash 和 nor flash 的区别又
    的头像 发表于 12-17 14:56 1.1w次阅读

    Flash存储器在MCS-51系统的应用

    介绍了 Flash 存储器的特性和应用场合 ,在16 位地址总线扩展大容量存储的一般方法。讨论了 MCS-51 系列单片机与 Flash
    发表于 03-18 09:50 7次下载
    <b class='flag-5'>Flash</b><b class='flag-5'>存储器</b>在MCS-51系统<b class='flag-5'>中</b>的应用

    Flash存储器的工作原理和基本结构

      Flash存储器是一种非易失性存储器,即使在供电电源关闭后仍能保持片内信息。
    发表于 09-09 16:22 5378次阅读

    NAND Flash和NOR Flash存储器的区别

    摘要:本文主要对两种常见的非易失性存储器——NAND Flash和NOR Flash进行了详细的比较分析。从存储容量、性能、成本等方面进行了深入探讨,以帮助读者更好地理解这两种
    发表于 09-27 17:46 1456次阅读

    EEPROM与Flash存储器的区别

    在电子技术和计算机系统存储器是不可或缺的组成部分,其类型和功能繁多。EEPROM(Electrically Erasable Programmable Read-Only Memory,电可擦除
    的头像 发表于 05-23 16:35 5221次阅读

    铁电存储器Flash的区别

    铁电存储器(Ferroelectric RAM, FRAM)与闪存(Flash)是两种不同类型的非易失性存储器,它们在工作原理、性能特点、应用场景等方面存在显著的差异。
    的头像 发表于 09-29 15:25 589次阅读