我要投搞

标签云

收藏小站

爱尚经典语录、名言、句子、散文、日志、唯美图片

当前位置:六合平特一肖 > 范例重用 >

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

归档日期:04-26       文本归类:范例重用      文章编辑:爱尚语录

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  在写入数据前,需确保写入地址已被擦除。即将需要变为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。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  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 中的宏:

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

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

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

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

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

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

  当调用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。

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

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

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

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

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

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

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

  C8051F02X系列混合信号ISP FLASH微控制器的中文数据手册免费下载

本文链接:http://prozacraft.com/fanlizhongyong/224.html