嵌入式Linux之我行——S3C2440上Flash驱动实例开发讲解(to_be_continue)
- 格式:doc
- 大小:167.00 KB
- 文档页数:9
文章记录了作者在S3C2440开发板上实现按键点亮LED驱动开发的详细过程,还记录了一些容易出现的错误,以及怎么解决这些错误。
一、驱动开发流程Linux驱动开发不同于应用程序的开发。
驱动开发是直接和硬件打交道的,通过对硬件的操作给应用程序提供一些接口函数,使得应用程序能够“间接”的控制硬件来工作。
对于按键点亮LED的驱动开发流程如下。
二、驱动开发具体步骤1、查看开发板TQ2440底板原理图,找到按键和LED模块,如下图:图-2 按键和LED电路图从上图我们可以清楚地看到K1~K4对应的管脚是ENT1~ENT4,LED1~LED4对应的管脚是nLED_1~nLED_4.2、查看TQ2440_核心板原理图,找到对应的CPU管脚,如下图:图-3 按键和LED对应CPU管脚电路图3、查看s3c2440芯片手册,查看CPU管脚的模式,如下图从上图我们可以看出按键对应的CPU管脚GPF0~GPF4都是占两位(如:GPF0[1:0])。
按键是一种中断,要想让按键工作在中断模式下,就要设置GPF0~GPF4(GPF3除外)管脚都设置在中断模式下,即为10。
对于LED对应的CPU管脚GPB5~GPB8也是占两位。
要想让LED工作,就要让LED工作在输出模式下,即对应管脚设置为01.4、编写按键点亮LED驱动程序/*调用内核头文件,和应用程序调用的头文件不一样*/#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <asm/irq.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include <asm/arch/regs-gpio.h>#include <asm/hardware.h>#include <linux/device.h>#include <linux/poll.h>#define DEVICE_NAME "tope-buttons" //自定义驱动称为“tope-buttons”。
嵌入式Linux中Flash设备驱动的研究与优化一、嵌入式Linux中Flash设备驱动的介绍与应用二、Flash设备基础知识与架构分析三、Flash设备在驱动中的应用场景及其实现方法四、Flash设备驱动的优化与实现五、测试与验证Flash设备驱动的可靠性与稳定性六、Flash设备驱动在系统中的性能分析及优化七、Flash设备驱动的应用实例分析一、嵌入式Linux中Flash设备驱动的介绍与应用嵌入式Linux已经成为很多嵌入式应用的首选系统。
而Flash 设备作为嵌入式系统中常见且重要的存储设备,其驱动也非常关键。
本章将介绍Flash设备驱动的介绍与应用,为后续章节的深入研究做好铺垫。
首先,本章将概述Flash设备驱动的基础知识和应用场景,并介绍Flash设备驱动实现的基本流程。
其次,本章将通过实例讲解Flash设备的驱动在嵌入式Linux系统中的应用。
在介绍的过程中,本章将深入探讨Flash设备驱动的优化,包括如何提高Flash驱动的读写性能以及如何增强Flash设备的可靠性和稳定性。
对于本章的内容,毕业生需要深入理解Flash设备和Flash设备驱动的基础知识,并掌握Flash设备驱动的工作原理和实现方法。
毕业生还需要将理论与实践结合起来,进行相关实验和测试,以充分掌握Flash设备驱动的应用方法。
二、Flash设备基础知识与架构分析本章将深入分析Flash设备的基础知识和架构,包括Flash存储器的基本原理、Flash存储器的工作模式和Flash设备的存储结构等。
如今的嵌入式平台上,闪存设备已经替代了传统的机械硬盘。
因此,对于Flash存储器的基本原理和工作模式的研究非常重要。
本章将通过深入分析Flash存储器的基本原理、工作模式和存储结构,为后续章节中的Flash设备驱动优化和性能测试等提供必要的技术支持。
本章将着重介绍Flash设备的存储结构和工作模式,以及介绍常见的Flash存储器类型和驱动器。
Jflash-s3c2410(linux 版本)源码分析最近在远峰公司买了arm9的板子,S3C2410,ARM920T ,没有Nor flash ,Nand Flash 是64M ,SDRAM 是K9f1208,本人对linux 的热情大于windows ,所以想在linux 下做开发,可是远峰公司只给我YFSJF.exe 文件,而且没有源代码,每次在linux 下编译好了后还得切换到windows 下烧录,很是麻烦,于是在网上找了很多Jflash 类似的程序,不过不同的烧录针对不同的硬件平台,Jflash 是跟硬件紧密结合的,比如有的针对Nor Flash ,有的针对Nand Flash 的,不同内核有不同的Jflash ,而且相同的内核也有不同的版本,因为Jtag 的原理图不同,就只能有相对应的Jflash ,程序中的定义要与pc 机并口与Jtag 接口的对应相一致。
在进入源码分析之前要介绍一些预备的知识,有助于理解源代码,毕竟这个程序和硬件联系很紧密的。
首先介绍一下对PC 并口做一些简要的介绍一、PC 标准配备并行口介绍本文主要介绍计算机的标准配备并行端口即25针的母接头端口的应用,在此基础上可以运用相同的原理使用其它模式的并行端口。
并行端口共有25支脚,但不是每支脚均被使用到。
这些脚被区图1分为3种主要的功能,分别是用于数据的传送、检查打印机的状态及控制打印机,其接口如下所示:注:18~脚为GND在PC 机中,标准并行口使用3个8位对这些寄存器,也就是所说的数据、25号的端口寄存器,PC 就是通过状态、控制寄存器的读写访问并口的信号的。
本文中使用一些通用的叫法,8个数据位分别为D0~D7,5个状态位为S3~S7,4个控制为C0~C3。
其中字母表示了端口寄存器,数字则表示该信号在寄存器中的位。
数据寄存器据端口或称数据寄存器(D0~D7)保存了写入数据输出端口的一字节信息。
数据端口可以写入数数据寄存器(即数据输出端口)可擦写、基地址数据,也可以读出数据(即可擦写);写进去的当然是我们希望从数据端口引脚输出的数据,不过读进来的也只是我们上次写进去的数据,或是原来保留在里面的数据,并不是从端口引脚输入PC 的数据。
嵌⼊式Linux驱动学习之路(⼆⼗三)NANDFLASH驱动程序NAND FLASH是⼀个存储芯⽚。
在芯⽚上的DATA0~DATA7上既能传输数据也能传输地址。
当ALE为⾼电平时传输的是地址。
当CLE为⾼电平时传输的是命令。
当ALE和CLE都为低电平时传输的是数据。
将数据发给nand Flash后,在发送第⼆次数据之前还要判断芯⽚是否处于空闲状态。
⼀般是通过引脚RnB来判断,⼀般是⾼电平代表就绪,低电平代表正忙。
操作Nand Flash的⼀般步骤是: 1. 发命令 选中芯⽚ CLE设置为⾼电平 在DATA0~DATA7上输出命令值 发出⼀个写脉冲 2. 发地址 选中芯⽚ ALE为⾼电平 在DATA0~DATA7上传输数据 发出⼀个写脉冲 3. 发数据 选中芯⽚ 发出读脉冲 读取DATA0~DATA7上的数据。
使⽤UBOOT来体验NAND FLASH的操作:读ID 选中 NFCONT的bit1设置为0 md.l 0x4e000004 1; mw.l 0x4e000004 1 发出命令0x90 NFCMMD=0X90 mw.b 0x4e000008 0x90; 发出地址0x00 NFADDR=0X00 mw.b 0x4e00000C 0x00; 读取数据得到0XEC val=NFDATA md.b 0x4e000010 1 读取数据得到device code val=NFDATA md.b 0x4e000010 1 退出读ID的状态 NFCMMD=0XFF mw.b 0x4e000008 0xffNAND FLASH驱动程序层次看内核启动信息S3C24XX NAND Driver, (c) 2004 Simtec Electronicss3c2440-nand s3c2440-nand: Tacls=3, 30ns Twrph0=7 70ns, Twrph1=3 30nsNAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)Scanning device for bad blocksBad eraseblock 256 at 0x02000000Bad eraseblock 257 at 0x02020000Bad eraseblock 319 at 0x027e0000Bad eraseblock 606 at 0x04bc0000Bad eraseblock 608 at 0x04c00000Creating 4 MTD partitions on "NAND 256MiB 3,3V 8-bit":0x00000000-0x00040000 : "bootloader"0x00040000-0x00060000 : "params"0x00060000-0x00260000 : "kernel"0x00260000-0x10000000 : "root"搜"S3C24XX NAND Driver" S3c2410.c (drivers\mtd\nand)s3c2410_nand_inithws3c2410_nand_init_chipnand_scan // drivers/mtd/nand/nand_base.c 根据nand_chip的底层操作函数识别NAND FLASH,构造mtd_infonand_scan_identnand_set_defaultsif (!chip->select_chip)chip->select_chip = nand_select_chip; // 默认值不适⽤if (chip->cmdfunc == NULL)chip->cmdfunc = nand_command;chip->cmd_ctrl(mtd, command, ctrl);if (!chip->read_byte)chip->read_byte = nand_read_byte;readb(chip->IO_ADDR_R);if (chip->waitfunc == NULL)chip->waitfunc = nand_wait;chip->dev_readynand_get_flash_typechip->select_chip(mtd, 0);chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);*maf_id = chip->read_byte(mtd);dev_id = chip->read_byte(mtd);nand_scan_tailmtd->erase = nand_erase;mtd->read = nand_read;mtd->write = nand_write;s3c2410_nand_add_partitionadd_mtd_partitionsadd_mtd_devicelist_for_each(this, &mtd_notifiers) { // 问. mtd_notifiers在哪设置// 答. drivers/mtd/mtdchar.c,mtd_blkdev.c调⽤register_mtd_userstruct mtd_notifier *not = list_entry(this, struct mtd_notifier, list);not->add(mtd);// mtd_notify_add 和 blktrans_notify_add先看字符设备的mtd_notify_addclass_device_createclass_device_create再看块设备的blktrans_notify_addlist_for_each(this, &blktrans_majors) { // 问. blktrans_majors在哪设置// 答. drivers\mtd\mdblock.c或mtdblock_ro.c register_mtd_blktransstruct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list);tr->add_mtd(tr, mtd);mtdblock_add_mtd (drivers\mtd\mdblock.c)add_mtd_blktrans_devalloc_diskgd->queue = tr->blkcore_priv->rq; // tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock); add_disk驱动程序代码:/** drivers\mtd\nand\s3c2410.c* drivers\mtd\nand\at91_nand.c*/#include <linux/module.h>#include <linux/types.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/ioport.h>#include <linux/platform_device.h>#include <linux/delay.h>#include <linux/err.h>#include <linux/slab.h>#include <linux/clk.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/nand_ecc.h>#include <linux/mtd/partitions.h>#include <asm/io.h>#include <asm/arch/regs-nand.h>#include <asm/arch/nand.h>struct nand_chip *s3c_nand;struct mtd_info *s3c_mtd;struct clk *clk;struct s3c_nand_regs{unsigned long nfconf;unsigned long nfcont;unsigned long nfcmd;unsigned long nfaddr;unsigned long nfdata;unsigned long nfeccd0;unsigned long nfeccd1;unsigned long nfeccd;unsigned long nfstat;unsigned long nfestat0;unsigned long nfestat1;unsigned long nfeecc0;unsigned long nfeecc1;unsigned long nfsecc;unsigned long nfsblk;unsigned long nfeblk;};static struct mtd_partition s3c_nand_parts[] = {[0] = {.name = "bootloader",.size = 0x00040000,.offset= 0,},[1] = {.name = "params",.offset = MTDPART_OFS_APPEND,.size = 0x00020000,},[2] = {.name = "kernel",.offset = MTDPART_OFS_APPEND,.size = 0x00200000,},[3] = {.name = "root",.offset = MTDPART_OFS_APPEND,.size = MTDPART_SIZ_FULL,}};static volatile struct s3c_nand_regs *nand_regs;static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr ){if(chipnr == -1 ){/* 取消选中 */nand_regs->nfcont |= (1<<1);}else{/* 选中 NFCONT^1 设置为1 */nand_regs->nfcont &= ~(1<<1);}}static void s3c2440_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) {if (cmd == NAND_CMD_NONE)return;if (ctrl & NAND_CLE){/* 发命令 */nand_regs->nfcmd = cmd;}else{/* 发地址 */nand_regs->nfaddr = cmd;}}static int s3c2440_dev_ready(struct mtd_info *mtd){/**/return (nand_regs->nfstat & (1<<0));}static int s3c_nand_init(void){/* 分配⼀个nand_chip结构体 */s3c_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);nand_regs = ioremap(0x4e000000,sizeof(struct s3c_nand_regs));clk = clk_get(NULL,"nand");clk_enable(clk);/* 设置 */s3c_nand->select_chip = s3c2440_select_chip;s3c_nand->cmd_ctrl = s3c2440_nand_cmd_ctrl;s3c_nand->IO_ADDR_R = (void *)&nand_regs->nfdata;s3c_nand->IO_ADDR_W = (void *)&nand_regs->nfdata;s3c_nand->dev_ready = s3c2440_dev_ready;s3c_nand->ecc.mode = NAND_ECC_SOFT;/* 硬件相关的操作:根据nand Flash的⼿册设置时间参数 *//* HCLK = 100MHz *//* TACLS: 发出cle/ale之后多长时间才发出nWE信号 *//* TWRPHO: nWE的脉冲宽度 */nand_regs->nfconf = (1<<8);nand_regs->nfcont = 0x03;/* 使⽤:nand_scan */s3c_mtd = kzalloc( sizeof(struct mtd_info), GFP_KERNEL );s3c_mtd->owner = THIS_MODULE;s3c_mtd->priv = s3c_nand;nand_scan(s3c_mtd,1); /* 扫描识别 *//* add_mtd_partitions */add_mtd_partitions(s3c_mtd,s3c_nand_parts,4);//add_mtd_device(s3c_mtd); //整个flash只有⼀个分区的话可以⽤这个return0;}static void s3c_nand_exit(void){del_mtd_partitions(s3c_mtd);kfree(s3c_mtd);iounmap(nand_regs);kfree(s3c_nand);}module_init(s3c_nand_init);module_exit(s3c_nand_exit);MODULE_LICENSE("GPL");在添加这个内核模块的时候,⾸先卸载内核中的nand Flash驱动。
S3C2440上LCD驱动(FrameBuffer)实例开发讲解一、开发环境主机:VMWare--Fedora 9开发板:Mini2440--64MB Nand, Kernel:2.6.30.4编译器:arm-linux-gcc-4.3.2二、背景知识1. LCD工作的硬件需求:要使一块LCD正常的显示文字或图像,不仅需要LCD驱动器,而且还需要相应的LCD控制器。
在通常情况下,生产厂商把LCD驱动器会以COF/COG的形式与LCD玻璃基板制作在一起,而LCD控制器则是由外部的电路来实现,现在很多的MCU内部都集成了LCD控制器,如S3C2410/2440等。
通过LCD控制器就可以产生LCD驱动器所需要的控制信号来控制STN/TFT屏了。
2. S3C2440内部LCD控制器结构图:我们根据数据手册来描述一下这个集成在S3C2440内部的LCD控制器:a:LCD控制器由REGBANK、LCDCDMA、TIMEGEN、VIDPRCS寄存器组成;b:REGBANK由17个可编程的寄存器组和一块256*16的调色板内存组成,它们用来配置LCD控制器的;c:LCDCDMA是一个专用的DMA,它能自动地把在侦内存中的视频数据传送到LCD驱动器,通过使用这个DMA通道,视频数据在不需要CPU的干预的情况下显示在LCD屏上;d:VIDPRCS接收来自LCDCDMA的数据,将数据转换为合适的数据格式,比如说4/8位单扫,4位双扫显示模式,然后通过数据端口VD[23:0]传送视频数据到LCD驱动器;e:TIMEGEN由可编程的逻辑组成,他生成LCD驱动器需要的控制信号,比如VSYNC、HSYNC、VCLK和LEND等等,而这些控制信号又与REGBANK寄存器组中的LCDCON1/2/3/4/5的配置密切相关,通过不同的配置,TIMEGEN就能产生这些信号的不同形态,从而支持不同的LCD驱动器(即不同的STN/TFT屏)。
/liangkaiyang/archive/2010/05/02/5550709.aspxS3C2440上LCD驱动(FrameBuffer)实例开发讲解(一)Linux内核驱动编程2010-04-07 23:49:19 阅读1746 评论0 字号:大中小S3C2440上LCD驱动(FrameBuffer)实例开发讲解(一)嵌入式Linux之我行,主要讲述和总结了本人在学习嵌入式linux中的每个步骤。
一为总结经验,二希望能给想入门嵌入式Linux的朋友提供方便。
如有错误之处,谢请指正。
∙共享资源,欢迎转载:一、开发环境∙主机:VMWare--Fedora 9∙开发板:Mini2440--64MB Nand, Kernel:2.6.30.4∙编译器:arm-linux-gcc-4.3.2二、背景知识1. LCD工作的硬件需求:要使一块LCD正常的显示文字或图像,不仅需要LCD驱动器,而且还需要相应的LCD控制器。
在通常情况下,生产厂商把LCD驱动器会以COF/COG的形式与LCD玻璃基板制作在一起,而LCD控制器则是由外部的电路来实现,现在很多的MCU内部都集成了LCD 控制器,如S3C2410/2440等。
通过LCD控制器就可以产生LCD驱动器所需要的控制信号来控制STN/TFT屏了。
2. S3C2440内部LCD控制器结构图:我们根据数据手册来描述一下这个集成在S3C2440内部的LCD控制器:a:LCD控制器由REGBANK、LCDCDMA、TIMEGEN、VIDPRCS寄存器组成;b:REGBANK由17个可编程的寄存器组和一块256*16的调色板内存组成,它们用来配置LCD控制器的;c:LCDCDMA是一个专用的DMA,它能自动地把在侦内存中的视频数据传送到LCD 驱动器,通过使用这个DMA通道,视频数据在不需要CPU的干预的情况下显示在LCD屏上;d:VIDPRCS接收来自LCDCDMA的数据,将数据转换为合适的数据格式,比如说4/8位单扫,4位双扫显示模式,然后通过数据端口VD[23:0]传送视频数据到LCD驱动器;e:TIMEGEN由可编程的逻辑组成,他生成LCD驱动器需要的控制信号,比如VSYNC、HSYNC、VCLK和LEND等等,而这些控制信号又与REGBANK寄存器组中的LCDCON1/2/3/4/5的配置密切相关,通过不同的配置,TIMEGEN就能产生这些信号的不同形态,从而支持不同的LCD驱动器(即不同的STN/TFT屏)。
基于S3C2440的嵌入式Linux内核移植及字符设备驱动开发胡祖宝;董国通【期刊名称】《工业控制计算机》【年(卷),期】2015(028)012【摘要】It is important to port kernel system and code driver when applying Linux kernel in a special embedded plat-form.In this work,the embedded platform has been adopted Linux 2.6.22.6 system based onS3C2440 processor.The archi-tecture of Linux kernel is described in detail,and kernel system has been ported successfully in thispaper.Meanwhile,the root filesystem has been established.Furthermore,a character device driver is built as wel.%嵌入式平台多种多样,在一个特定的嵌入式系统应用Linux内核,需要内核的移植和驱动的开发.基于S3C2440芯片的嵌入式开发平台,操作系统选用Linux2.6.22.6版本,分析了Linux内核的体系结构,完成了内核移植过程,构建了根文件系统,对字符设备驱动程序进行了设计与开发.实验证明该方法可行,系统运行可靠.【总页数】3页(P14-15,18)【作者】胡祖宝;董国通【作者单位】上海宝信软件股份有限公司,上海 201203;上海大学机电工程与自动化学院,上海 200072【正文语种】中文【相关文献】1.基于嵌入式Linux的字符设备驱动开发 [J], 王科;姚振东2.基于S3C2440 Codec通道的视频驱动开发 [J], 崔小川;马田;李玉超3.基于ARM的嵌入式Linux字符设备驱动设计研究 [J], 梁金宏;叶海蓉;孙世菊4.基于DSP的嵌入式Linux内核移植的研究与实现 [J], 王晓东5.基于嵌入式Linux内核移植设备驱动的微喷自动装置 [J], 王慧;张璐因版权原因,仅展示原文概要,查看原文内容请购买。
S3C2440完全开发流程作者:dreamer2006@2009-11-3 一.简介 (3)二.建立开发环境 (4)1、编译器ARM-LINUX-GCC-3.4.1 (4)2、J FLASH-S3C2440:S3C2440芯片的JTAG工具 (4)3、安装GDB调试工具 (5)4、USB下载工具 (6)5、UBUNTU开发环境建立 (6)三.S3C2440基础实验 (8)1、实验一:LED_ON (8)2、实验二:LED_ON_C (9)3、实验三:I/O PORTS (11)5、实验五:MEMORY CONTROLLER (15)6、实验六:NAND FLASH CONTROLLER (17)7、实验七:UART (20)8、实验八:PRINTF、SCANF (23)9、实验九:INTERRUPT CONTROLLER (24)10、实验十:TIMER (28)11、实验十一:MMU (31)12、实验十二:CLOCK (39)四.BOOTLOADER VIVI (43)1、阶段1:ARCH/S3C2440/HEAD.S (43)2、阶段2:INIT/MAIN.C (45)1)、Step 1:reset_handler() (45)2)、Step 2:board_init() (46)3)、Step 3:建立页表和启动MMU (47)4)、Step 4:heap_init() (50)5)、Step 5:mtd_dev_init() (52)6)、Step 6:init_priv_data() (56)7)、Step 7:misc()和init_builtin_cmds() (57)8)、Step 8:boot_or_vivi() (58)五.附录一VI命令解释 (65)1、HELP命令 (65)2、MEM命令 (65)3、LOAD命令 (66)4、PARAM命令 (67)5、PART命令 (69)6、BOOT命令 (70)7、BON命令 (71)一.简介本书面向由传统51单片机转向ARM嵌入式开发的硬件工程师、由硬件转嵌入式软件开发的工程师、没有嵌入式开发经验的软件工程师,本书开发板基于天嵌科技的TQ S3C2440开发板,其官方网站为:/,共分9个部分:1、开发环境建立2、S3C2440功能部件介绍与实验(含实验代码)3、Bootloader vivi详细注释4、Linux移植5、Linux驱动6、Yaffs文件系统详解7、调试工具8、GUI开发简介9、UC/OS移植通过学习第二部分,即可了解基于ARM CPU的嵌入式开发所需要的外围器件及其接口。
嵌入式Linux之我行,主要讲述和总结了本人在学习嵌入式linux中的每个步骤。一为总结经验,二希望能给想入门嵌入式Linux的朋友提供方便。如有错误之处,谢请指正。
共享资源,欢迎转载:http://hbhuanggang.cublog.cn 一、Linux中Flash硬件知识 1. Flash用途和分类:
在嵌入式系统开发设计中,存储模块是不可缺少的重要部分,而 Flash是目前市场上主要的非易失闪存技术,他主要分为:Nor Flash和Nand Flash两种。那么他们有什么区别呢?简单的讲:Nor Flash容量小,价格高,写速度慢但随机读速度快,所以较适合存储少量的程序代码,比如u-boot启动代码;而Nand Flash则容量大,价格低,写速度快但读速度慢,所以他相当于PC上的硬盘用于存储大量的数据。Nor Flash与Nand Flash更详细区别如下表:
2. Flash在硬件设计中的应用:
以Mini2440开发板为例:该开发板上带有一块2M的Nor Flash和一块64M的Nand Flash。下面先看看他们是怎样被应用于嵌入式Linux的。Nor Flash和Nand Flash电路原理图分别如下:(由mini2440提供) 从 原理图上可以看到,Nor Flash内部提供的是有类似于DRam之类的地址总线,可以直接与CPU相连,CPU可以直接通过地址总线对Nor Flash进行访问;而Nand Flash没有这类的总线,其内部只提供IO接口,因此只能通过IO接口发送命令和地址,对Nand Flash内部数据进行访问。这可以说是二者最大的区别了,也说明了二者读写速度不同的所在。因此,各有各的优点,Nor Flash访问快,Nand Flash简化了电路。注意:电路原理图中字母上面有一横杠的表示该引脚是低电平有效,没有的是默认的高电平。
二、Linux中Flash软件知识 1. Linux MTD子系统:
在Linux系统中,提供了MTD(内存技术设备)子系统来建立Flash针对Linux的统一、抽象的接口。MTD子系统将上层文件系统与底层 Flash硬件进行了隔离,使Flash驱动开发者无需再关心Flash作为字符设备或者块设备与Linux内核的接口。MTD将Linux系统 Flash设备驱动及接口分成了4个层次,如图所示,从上往下分别为:设备节点、MTD设备层、MTD原始设备层和Flash硬件驱动层。 设备节点:用户在/dev目录下使用mknod命令建立MTD字符设备节点(主设备号为90),
或者MTD块设备节点(主设备号为31),使用该设备节点即可访问MTD设备。
MTD设备层:基于MTD原始设备层,系统将MTD设备可以定义为MTD字符设备(在
/mtd/mtdchar.c中实现)和MTD块设备(在/mtd/mtdblock.c中实现)。
MTD原始设备层:MTD原始设备层由两个部分组成,分别是MTD原始设备的通用代码和
各个特定的Flash的数据,如分区信息。
Flash硬件驱动层:Flash硬件驱动层负责对Flash硬件的读、写和擦除操作。MTD设
备的Nor Flash芯片驱动一般位于drivers/mtd/chips/子目录下,Nand Flash芯片的驱动则位于drivers/mtd/nand/子目录下。
综 合上述我们可知,MTD子系统已经对Flash设备对于上层的应用进行了封装,我们在写硬件驱动的时候直接调用MTD原始设备层提供的接口函数做相应的操 作即可。那么,对于MTD设备层,MTD原始设备层提供了哪些接口呢?对于Flash硬件驱动层,MTD原始设备层又提供了哪些接口呢?下面开始了解。
2. MTD子系统接口: 在MTD子系统中,MTD设备层、MTD原始设备层和Flash硬件驱动层之间的接口关系如下图所示: 从上图可知,MTD设备层是通过原始设备层提供的接口来注册MTD字符设备或MTD块设备的,同样,驱动工程师要编写的Flash硬件驱动也是通过原始设备层提供的接口来添加MTD设备和MTD分区的,分别如下:
//使用这两个接口函数进行添加和删除MTD设备 int add_mtd_device(struct mtd_info *mtd); int del_mtd_device(struct mtd_info *mtd)
//使用这两个接口函数进行添加和删除MTD分区 int add_mtd_partitions(struct mtd_info *master, struct mtd_partition *parts, int nbparts); int del_mtd_partitions(struct mtd_info *master)
3. 在 MTD中,一个MTD原始设备用mtd_info结构体来表示,定义在include/linux/mtd/mtd.h中;一个MTD原始设备分区用 mtd_part结构体来表示,定义在drivers/mtd/mtdpart.c中。其中每个分区也被认为是一个mtd_info,比如:有一个MTD 原始设备,上面有3个分区,那么将共有3个mtd_info,而这3个mtd_info的指针将被存放在mtd_table的数组中进行管理,定义在 drivers/mtd/mtdcore.h中,如下所示: extern struct mtd_info *mtd_table[MAX_MTD_DEVICES];//最多有MAX_MTD_DEVICES(默认定义为32)个设备
4. 5. MTD子系统中重要的一些数据结构: struct mtd_info { //硬件设备的类型,如:MTD_RAM,MTD_ROM,MTD_NORFlash,MTD_NANDFlash,MTD_PEROM等 u_char type;
//设备支持的选项,如:MTD_ERASEABLE(可擦除),MTD_WRITEB_WRITEALBE(可编程), //MTD_XIP(可片内执行),MTD_OOB(NAND额外数据),MTD_ECC(支持自动ECC)等 uint32_t flags;
uint64_t size;//MTD设备的大小 uint32_t erasesize;//主要的擦除块大小(注意:同一个MTD设备可能有几种不同的erasesize) uint32_t writesize;//编程块大小 uint32_t oobsize;//OOB数据大小 uint32_t oobavail;
unsigned int erasesize_shift; unsigned int writesize_shift; unsigned int erasesize_mask; unsigned int writesize_mask;
const char *name; int index;
struct nand_ecclayout *ecclayout;//ECC布局结构 int numeraseregions;//擦除区域的个数,通常为1 struct mtd_erase_region_info *eraseregions;//擦除区域的指针 //此方法将一个erase_info结构放入擦除队列中 int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
//point和unpoint方法分别用于允许和禁止芯片内执行(eXecute-In-Place,简称XIP),如果unpoint为NULL,则表示禁止XIP int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, void **virt, resource_size_t *phys); void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
//如果不为NULL,则表示允许无MMU单元的虚拟地址映射 unsigned long (*get_unmapped_area) (struct mtd_info *mtd,unsigned long len,unsigned long offset,unsigned long flags); struct backing_dev_info *backing_dev_info;
//read和write分别用于MTD设备的读和写 int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
//read_oob和write_oob分别用于读写MTD设备的OOB数据 int (*read_oob) (struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops); int (*write_oob) (struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops);
//一下几个方法是用于实现访问一些受保护的寄存器(一般这只是出现在某些特定的Flash设备上) int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);