一、一个简单的nand_flash驱动
1.定义nand_chip、mtd_info两个结构体

如上图所示:
nand_chip 结构体:是给nand_scan函数用的,而nand_scan函数提供了选中nand、发出命令、发出地址、发出数据、读取数据、判断状态等功能,所以nand_chip结构体上必须定义一系列实现上面功能能的函数,包括选中函数,负责发地址与命令的函数,以及判断状态的函数,最重要的就是io读取的虚拟地址。
mtd_info结构体:MTD(Memory Technology Device)即内存技术设在linux内核中,引入mtd层为NOR Flash和NAND Flash设备提供统一的接口,将文件系统于底层Flash存储设备进行了隔离。
MTD设备可以分为四层,从上到下依次为:设备节点层,MTD设备层,MTD原始设备层,Flash硬件驱动层。
Flash硬件驱动层:负责对Flash硬件的读、写和擦除操作。MTD设备的NAND flash芯片的驱动在drivers/mtd/nand目录下,nor flash芯片驱动位于drivers/mtd/chips目录下。
MTD原始设备层:用于描述MTD原始设备的数据结构体是mtd_info ,它定义了大量的关于MTD的数据和操作函数,其中mtdcore.c:实现原始设备接口的相关实现,mtdpart.c:实现mtd分区接口相关实现。
MTD设备层: 基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号31)和字符设备(设备号90),其中mtdchar.c实现mtd字符设备接口相关实现,mtdblock.c用于实现块设备接口相关实现。
设备节点层:通过mknode在/dev子目录下建立MTD块设备节点,通过此设备节点即可访问MTD字符设备和块设备。
2.在init函数中初始化结构体
1 static int lhy_nand_init(void){
2
3 /* 1.分配一个nand_chip结构体 */
4 lhy_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
5 /* 2.设置 */
6 /* 2.1设置nand_chip是给nand_scan函数用的,如果不知道怎么设置,先看nand_scan怎么用
7 * 它应该提供:选中,发命令,发地址,发数据,读数据,判断状态等功能
8 */
9 lhy_nand->select_chip = lhy_select_chip; //选中,芯片选择函数
10 lhy_nand->cmd_ctrl = lhy_nand_cmd_ctrl; //负责发送地址,命令
11 lhy_nand->IO_ADDR_R = 'NFDATA 的虚拟地址';
12 lhy_nand->IO_ADDR_R = 'NFDATA 的虚拟地址';
13 lhy_nand->dev_ready = lhy_dev_ready;
14 /* 3.硬件相关的操作 */
15
16 /* 4.使用nand_scan */
17 lhy_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
18 lhy_mtd->priv = lhy_nand; //私有数据为我们的nand_chip结构体
19 lhy_mtd->owner = THIS_MODULE;
20
21 nand_scan(lhy_mtd,1); //扫描识别nand flash,并且构造mtd,最大芯片个数为1
22 /* 5.add_mtd_partitions */
23
24
25 return 0;
26 }
3.实现上述方法:
1 /* 芯片选择 */
2 static void lhy_select_chip(struct mtd_info *mtd,int chipnr)
3 {
4 if(chipnr == -1){
5 /* 取消选中,NFCONT[1]设为0 */
6 }else{
7 /* 选中:NFCONT[1]设为1 */
8 }
9 }
10 //发送命令,地址,数据
11 static void lhy_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
12 {
13 if (ctrl & NAND_CLE){
14 /* 发命令 : NFCMMD=dat*/
15 writeb(cmd, host->io_base + (1 << host->board->cle));
16 }else{
17 writeb(cmd, host->io_base + (1 << host->board->ale));
18 }
19 }
20 //判断状态
21 static int lhy_dev_ready(struct mtd_info *mtd)
22 {
23 return 'NFSTAT 的 bit[0]';
24 }
附上驱动程序nand_flash1:
1 /*
2 * 参考:linux-2.6.31driversmtdnands3c2410.c atmel_nand.c
3 */
4
5 #include 6 #include 7 #include 8 #include 9 #include 10 #include 11 #include 12 #include 13 #include 14 #include 15 #include 16 17 static struct nand_chip *lhy_nand; 18 static struct mtd_info *lhy_mtd; //定义一个mtd_info结构体 19 20 /* 芯片选择 */ 21 static void lhy_select_chip(struct mtd_info *mtd,int chipnr) 22 { 23 if(chipnr == -1){ 24 /* 取消选中,NFCONT[1]设为0 */ 25 }else{ 26 /* 选中:NFCONT[1]设为1 */ 27 } 28 } 29 //发送命令,地址,数据 30 static void lhy_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) 31 { 32 if (ctrl & NAND_CLE){ 33 /* 发命令 : NFCMMD=dat*/ 34 writeb(cmd, host->io_base + (1 << host->board->cle)); 35 }else{ 36 writeb(cmd, host->io_base + (1 << host->board->ale)); 37 } 38 } 39 //判断状态 40 static int lhy_dev_ready(struct mtd_info *mtd) 41 { 42 return 'NFSTAT 的 bit[0]'; 43 } 44 45 static int lhy_nand_init(void){ 46 47 /* 1.分配一个nand_chip结构体 */ 48 lhy_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL); 49 /* 2.设置 */ 50 /* 2.1设置nand_chip是给nand_scan函数用的,如果不知道怎么设置,先看nand_scan怎么用 51 * 它应该提供:选中,发命令,发地址,发数据,读数据,判断状态等功能 52 */ 53 lhy_nand->select_chip = lhy_select_chip; //选中,芯片选择函数 54 lhy_nand->cmd_ctrl = lhy_nand_cmd_ctrl; //负责发送地址,命令 55 lhy_nand->IO_ADDR_R = 'NFDATA 的虚拟地址'; 56 lhy_nand->IO_ADDR_R = 'NFDATA 的虚拟地址'; 57 lhy_nand->dev_ready = lhy_dev_ready; 58 /* 3.硬件相关的操作 */ 59 60 /* 4.使用nand_scan */ 61 lhy_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); 62 lhy_mtd->priv = lhy_nand; //私有数据为我们的nand_chip结构体 63 lhy_mtd->owner = THIS_MODULE; 64 65 nand_scan(lhy_mtd,1); //扫描识别nand flash,并且构造mtd,最大芯片个数为1 66 /* 5.add_mtd_partitions */ 67 68 69 return 0; 70 } 71 72 static void lhy_nand_exit(void){ 73 if(lhy_nand) 74 kfree(lhy_nand); 75 if(lhy_mtd) 76 kfree(lhy_mtd); 77 } 78 79 module_init(lhy_nand_init); 80 module_exit(lhy_nand_exit); 81 MODULE_LICENSE('GPL'); 82 83 84 /* 85 S3C2440 U-BOOT 的NAND操作 86 87 1.读取ID 88 选中 NFCONT的bit1设为0 md.1 0x4E000004 1; mw.1 0x4e000004 1 89 发出命令0x90 NFCMMD=0X90 mw.b 0x4E000008 0x90 90 发出地址0x00 NFADD=0X00 mw.b 0x4E00000c 0x00 91 读出数据得到0XEC val=NFDATA md.b 0x4E000010 1 92 读数据得到device code val=NFDATA md.b 0x4E000010 1 93 退出读ID状态 NFCMMD=0xff mw.b 0x4E000008 0xff 94 95 2.读内容 读0地址的数据 96 输入命令: nand dump 0 得到nand 97 98 选中 NFCONT的bit1设为0 md.1 0x4E000004 1; mw.1 0x4e000004 1 99 发出命令0x00 NFCMMD=0X00 mw.b 0x4E000008 0x00 100 101 发出地址0x00 NFADD=0X00 mw.b 0x4E00000c 0x00 102 发出地址0x00 NFADD=0X00 mw.b 0x4E00000c 0x00 103 发出地址0x00 NFADD=0X00 mw.b 0x4E00000c 0x00 104 发出地址0x00 NFADD=0X00 mw.b 0x4E00000c 0x00 105 发出地址0x00 NFADD=0X00 mw.b 0x4E00000c 0x00 106 107 发出命令0x30 NFCMMD=0X00 mw.b 0x4E000008 0x30 108 109 //接下来就是从0地址开始一个字节一个字节的读出数据,和前面nand dump 0 的数据一样 110 读出数据得到0x17 val=NFDATA md.b 0x4E000010 1 111 读出数据得到0x00 val=NFDATA md.b 0x4E000010 1 112 读出数据得到0x00 val=NFDATA md.b 0x4E000010 1 113 114 退出读状态 NFCMMD=0xff mw.b 0x4E000008 0xff 115 116 3.NAND flash 驱动层次 Atmel_nand.c Mtdchar.c 117 块设备: 知道怎么优化 118 NAND Flash协议:知道发什么来读写,擦除,识别 119 硬件相关: 知道怎样发命令/地址,读写数据 120 121 硬件相关: 122 ①分配nand_chip 结构体 123 ②设置nand_chip 124 ③硬件相关设备 125 ④使用 nand_scan / add_mtd_partitions 126 127 */ 二、完善前面的程序 1.定义芯片的内存地址,由于其地址是互相相连的所以我们可以使用结构体来省事。 //寄存器结构体 struct lhy_nand_regs{ unsigned long NFCONF ; //偏移地址: S3C2410_NFREG(0x00)
上一篇:S3C实现DMA驱动程序编写
下一篇:GNU μC/OS-II 在 S3C2440 上中断的实现
推荐阅读最新更新时间:2026-03-22 10:03
- RDR-142 - 35W电源
- i.MX RT1060 Evaluation Kit
- 使用 Embedded Planet 的 5CEFA9U27 的参考设计
- DC1369A-D、LTC2258-14 演示板、14 位 65 Msps ADC、LVDS 输出、5-170MHz
- LT3990EMSE-5 12V 降压转换器的典型应用
- 使用 Analog Devices 的 LTC1148 的参考设计
- LT1377IS8 具有直接反馈的正负转换器的典型应用
- 使用 NXP Semiconductors 的 TL431AI 的参考设计
- LT8304IS8E 18V 至 80Vin、5Vout 隔离反激式转换器的典型应用电路
- LT3512EMS 演示板,单片式高压隔离反激式转换器 36V VIN 75V,VOUT = 5V @ 500mA



Linux技术手册
智能机械臂
现代雷达系统的信号设计
BFR340T






京公网安备 11010802033920号