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

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

3天内不再提示

详细讲解重用外设驱动代码_SPI_NOR_Flash存储器

UtFs_Zlgmcu7890 来源:互联网 作者:佚名 2017-12-21 07:59 次阅读

第六章为重用外设驱动代码,本文内容为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 数据库综合范例程序

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

    关注

    10

    文章

    1549

    浏览量

    146632
  • SPI
    SPI
    +关注

    关注

    17

    文章

    1612

    浏览量

    89582
  • 外设驱动器
    +关注

    关注

    0

    文章

    3

    浏览量

    3409
  • ametal
    +关注

    关注

    2

    文章

    24

    浏览量

    11350

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

文章出处:【微信号:Zlgmcu7890,微信公众号:周立功单片机】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    BY25QXXX系列NOR FLASH存储器驱动设计与实现

    在有一些应用中,我们可能需要大一些容量的存储单元,而实现的形式多种多样,在这一篇中我们将来讨论怎么使用BY25QXXX系列NOR FLASH存储器的问题。
    发表于 12-07 10:07 1477次阅读
    BY25QXXX系列<b class='flag-5'>NOR</b> <b class='flag-5'>FLASH</b><b class='flag-5'>存储器</b>的<b class='flag-5'>驱动</b>设计与实现

    NAND FlashNOR Flash的差别

    存储器NOR 与NAND 存储逻辑的差异导致二者的应用场景有很大不同。NOR 的优势在于随机读取与擦写寿命,因此适合用来存储
    发表于 09-11 16:59 2229次阅读
    NAND <b class='flag-5'>Flash</b>和<b class='flag-5'>NOR</b> <b class='flag-5'>Flash</b>的差别

    使用高速SPI Nor Flash的FPGA配置

    存储器是并行EPROM。NOR Flash技术出现了,并因其系统内可重新编程性和成本效益而被广泛采用。第二个演进过渡是,SPI存储器接口在大
    发表于 09-18 15:18

    AT32 支持的几种与SRAM/PSRAN/NOR FLASH界面简介

    XMC:AT32的XMC是一个将AHB传输信号转换与外部存储器信号相互转换的外设。支持的外部存储器有静态随机存储器SRAM、NOR
    发表于 03-14 20:31

    CH32V103基础教程27-DMA (存储器外设

    关于DMA,具有三种数据传输方式:存储器存储器存储器外设外设存储器。前面已
    发表于 04-20 16:35

    单板硬件设计:存储器( NAND FLASH)

    flash中运行。嵌入式系统多用一个小容量的nor flash存储引导代码,用一个大容量的nand f
    发表于 05-19 15:59

    单片机编程技巧之重用外设驱动代码

    第六章为重用外设驱动代码,本文内容为6.5 键盘与数码管接口。
    的头像 发表于 11-14 05:16 8298次阅读
    单片机编程技巧之<b class='flag-5'>重用</b><b class='flag-5'>外设</b><b class='flag-5'>驱动</b><b class='flag-5'>代码</b>

    旺宏NOR快闪存储器 形塑超高省电应用与发展

    随著半导体制程技术不断演进,芯片的晶体管的密集度屡创新高之际,同步也朝向更省电的发展推进,旺宏电子(Macronix)自推出业界最快的SPI NOR Flash系列存储器产品,以500
    发表于 01-02 10:06 1486次阅读

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

    存储器内的信息仍然存在,主要是闪存(Nand FLASHNOR FLASH),NOR 主要应用于
    的头像 发表于 04-09 15:45 11w次阅读

    非易失性存储器-Nor Flash的特点都有哪些

    Flash(快闪或闪存)由Intel公司于1988年首先推出的是一种可用电快速擦除和编程的非易失性存储器,其快速是相对于EEPROM而言的。Flash从芯片工艺上分为Nor
    发表于 12-07 14:17 3112次阅读

    一文了解SPI NAND FlashSPI NOR Flash的区别

    在嵌入式系统领域,作为存储设备的NOR Flash和NAND Flash,大家应该不陌生。早期NOR F
    的头像 发表于 03-06 09:49 5113次阅读

    TWS蓝牙耳机SPI NOR Flash

    蓝牙耳机大量出货的推动下,NOR Flash带来了巨大的商机。       TWS蓝牙耳机必须配备NOR Flash,因为它有更多的功能。为了存储
    的头像 发表于 07-31 14:33 489次阅读

    NAND FlashNOR Flash存储器的区别

    摘要:本文主要对两种常见的非易失性存储器——NAND FlashNOR Flash进行了详细的比较分析。从
    发表于 09-27 17:46 574次阅读

    为什么Nor Flash可以实现XIP,而Nand flash就不行呢?

    移动部件,它们的寿命更长。 NOR Flash和NAND Flash都是Flash存储器的类型,但它们的应用非常不同。
    的头像 发表于 10-29 16:32 788次阅读

    Nor Flash的基本概念 Nor Flash的内部结构解析

    Nor Flash是一种非易失性存储技术,用于存储数据和代码。它是一种闪存存储器,类似于NAND
    的头像 发表于 12-05 13:57 1026次阅读