韦东山视频实验之Nand驱动

本文详细探讨了Nand驱动的实现,包括Nand的原理分析、驱动细节,如时钟和时序设置、自动探测以及分区管理。在实践中遇到的挑战包括oops错误和文件复制问题。通过源代码解析,深入理解Nand驱动的编写过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里主要牵涉到static struct nand_chip mtd_info这两个底层封装的函数

Nand原理分析:

Nand驱动分析:

1)要进行nand时钟和时序的设置

     这里面会进行nand的寄存器的片选,命令的设置,地址或者数据的设置,状态位的读取,nand时钟和时序的设置等

2)nand flash底层的自动探测,识别nand

     这里面会进行初始的函数设置nand的函数,否则使用默认的底层函数进行探测与设置

3)增加nand分区

      使用struct mtd_partition可以对nand进行分区:nand_chip-> mtd_info->nand_scan->add_mtd_partitons

遇到的问题:

1.发生oops错误,各种指针都是null,最后定位到时寄存器地址设置错误

2.就是无法使用flash_erase flash_eraseall这两个复制到/bin目录下的文件

源代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.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_regs{
	unsigned long nfconf;  //0x4E000000
	unsigned long nfcont;
	unsigned long nfcmmd;
	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 nfmecc0;
	unsigned long nfmecc1;
	unsigned long nfsecc;
	unsigned long nfsblk;
	unsigned long nfeblk;
};

static struct nand_regs*		nand_regs_base;
static struct nand_chip*		mini2440_nand;
static struct mtd_info*			mini2440_mtd;


static struct mtd_partition mini2440_partiton[] = {
	[0] = {
		.name	= "supervivi",
		.size	= 0x00040000,
		.offset	= 0,
	},
	[1] = {
		.name	= "param",
		.offset = MTDPART_OFS_APPEND,
		.size	= 0x00020000,
	},
	[2] = {
		.name	= "Kernel",
		.offset = MTDPART_OFS_APPEND,
		.size	= 0x00500000,
	},
	[3] = {
		.name	= "root",
		.offset = MTDPART_OFS_APPEND,
		.size	= MTDPART_SIZ_FULL, //
	}
};



//片选
static void mini2440_select_chip(struct mtd_info *mtd, int chip)
{
	if (chip == -1)
	{
		nand_regs_base->nfcont |= (1<<1);
	}
	else
	{
		nand_regs_base->nfcont &= ~(1<<1);
	}
}

//发送命令/地址
static void	mini2440_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
	if ( ctrl & NAND_CLE ) //命令
	{
		nand_regs_base->nfcmmd = dat;
	}
	else //地址
	{
		nand_regs_base->nfaddr = dat;
	}
}

//nand状态
static 	int mini2440_dev_ready(struct mtd_info *mtd)
{
	return (nand_regs_base->nfstat & (1<<0));
}


static int nand_init(void)
{
	struct clk* clk;
	// 1 分配nand_chip空间
	mini2440_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
	nand_regs_base = ioremap(0x4E000000, sizeof(struct nand_regs));

	// 2 设置nand_chip
	mini2440_nand->select_chip	= mini2440_select_chip;
	mini2440_nand->cmd_ctrl		= mini2440_cmd_ctrl;
	mini2440_nand->IO_ADDR_R	= &nand_regs_base->nfdata;
	mini2440_nand->IO_ADDR_W	= &nand_regs_base->nfdata;
	mini2440_nand->dev_ready	= mini2440_dev_ready;
	mini2440_nand->ecc.mode		= NAND_ECC_SOFT;


	//3.硬件相关的设置 
	//1) nand时钟
	clk = clk_get(NULL, "nand");
	clk_enable(clk);
	//2) nand 时序
	/* HCLK=100MHz
	 * TACLS:  发出CLE/ALE之后多长时间才发出nWE信号, 从NAND手册可知CLE/ALE与nWE可以同时发出,所以TACLS=0
	 * TWRPH0: nWE的脉冲宽度, HCLK x ( TWRPH0 + 1 ), 从NAND手册可知它要>=12ns, 所以TWRPH0>=1
	 * TWRPH1: nWE变为高电平后多长时间CLE/ALE才能变为低电平, 从NAND手册可知它要>=5ns, 所以TWRPH1>=0
	 */
#define TACLS		0
#define TWRPH0		1
#define TWRPH1		0
	nand_regs_base->nfconf = (TACLS<<12) | (TWRPH0<<8) |(TWRPH1<<4);
	nand_regs_base->nfcont = (1<<1) | (1<<0); //取消片选,使能控制器

	// 4.使用nand_scan
	mini2440_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
	mini2440_mtd->owner		= THIS_MODULE;
	mini2440_mtd->priv		= mini2440_nand;

	//识别nand flash
	nand_scan(mini2440_mtd, 1);

	// 5 增加分区
	add_mtd_partitions(mini2440_mtd, mini2440_partiton, 4);

	return 0;
}

static void nand_exit(void)
{
	del_mtd_partitions(mini2440_mtd);
	kfree(mini2440_mtd);
	iounmap((nand_regs_base));
	kfree(mini2440_nand);
}

module_init(nand_init);
module_exit(nand_exit);

MODULE_AUTHOR("LCL");
MODULE_LICENSE("GPL");

 

<think>好的,用户想了解NAND Flash时序图的工作原理和相关原理。首先,我需要回顾一下NAND Flash的基本结构和工作流程。NAND Flash通过命令、地址和数据线进行操作,这些操作需要严格按照时序图来执行。 根据引用内容,用户提供的参考资料提到了命令格式、时序图的重要性以及配置引脚的作用。例如,引用3提到读命令需要两个周期,0x00和0x30,而发送命令前需要准备相关信号。同时,配置引脚如NCON、GPG13等用于设置Nand Flash的基本信息,控制器通过这些引脚获取配置(引用4)。 接下来要解释时序图中的关键信号:CLE、ALE、WE、RE等。需要说明每个信号的作用,例如CLE在命令周期有效,ALE在地址周期有效。然后,结合具体的读操作时序,分步骤说明各个阶段的操作,比如命令阶段、地址阶段、数据输出阶段,每个阶段的时序要求,如建立时间、保持时间等。 还需要注意不同芯片的时序可能有差异,但基本方法是通用的(引用2)。另外,开发板上的控制器可能已经处理了部分时序细节,但理解时序对底层驱动开发仍然重要。最后,应该生成相关问题,帮助用户进一步学习。</think>### NAND Flash时序图解释及工作原理 #### 1. **核心信号与时序阶段** NAND Flash操作依赖以下关键信号: - **CLE**(Command Latch Enable):高电平时,I/O端口传输的是**命令**(如读、写、擦除)[^3]。 - **ALE**(Address Latch Enable):高电平时,I/O端口传输的是**地址**(如页地址、列地址)[^3]。 - **WE#**(Write Enable):低电平触发时,控制器向NAND Flash写入数据或命令。 - **RE#**(Read Enable):低电平触发时,控制器从NAND Flash读取数据。 - **CE#**(Chip Enable):低电平时选中芯片。 #### 2. **读操作时序详解(以K9K8G08U0A为例)** **步骤1:发送读命令** - **CLE=1**,将I/O端口设置为命令模式。 - **WE#**下降沿发送**0x00**(第一个命令周期)[^3]。 - **WE#**再次下降沿发送**0x30**(第二个命令周期)[^3]。 **步骤2:发送地址** - **ALE=1**,进入地址模式。 - 分5个周期发送地址(例如:列地址+页地址+块地址),每次通过**WE#**下降沿锁存地址。 **步骤3:等待数据就绪** - NAND Flash内部执行读取操作(需等待**tR**时间,通常数十微秒)。 - 通过检查**R/B#**(Ready/Busy)引脚状态判断是否完成[^3]。 **步骤4:读取数据** - **RE#**下降沿触发数据输出,每次读取一页(例如2048字节+冗余区)。 #### 3. **时序关键参数** - **建立时间(t\_su)**:信号有效前需保持稳定的最小时间(如地址在WE#下降沿前需稳定)[^2]。 - **保持时间(t\_h)**:信号有效后需保持稳定的最小时间。 - **脉冲宽度(t\_wp/t\_rp)**:WE#或RE#低电平持续时间,需满足芯片规格(如K9F1G08X0C要求至少12ns)。 #### 4. **配置引脚与控制器协同** 开发板通过**NCON、GPG13等引脚**设置NAND Flash的位宽、页大小等信息,控制器根据这些配置自动生成时序信号[^4]。例如: - **GPG13=1**表示使用大页(2048字节/页); - **GPG14=0**表示8位数据总线。 ```c // 示例:S3C2440控制器初始化代码片段 void nand_init() { rNFCONF = (1<<15)|(1<<12)|(7<<8)|(7<<4); // 使能控制器,设置时序参数 rNFCONT = (1<<0)|(1<<1); // 开启NAND Flash片选 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值