[Linux驱动]-----NAND FLASH

2023-05-16

一、NAND原理及硬件操作

C: fopen,fread,fwrite
APP: open,read,write “1.txt”
------------------------------------------ 文件读写
文件系统:vfat,ext2,ext3,yaffs (把文件的读写转换成对扇区的读写)
------------------ll_rw_block-------------- 扇区读写
块设备驱动程序
硬件:硬盘、FLASH

1.1NAND FLASH硬件

在这里插入图片描述问1:原理图上 NAND FLASH 和 S3C2440 之间只有数据线(LDATA0~7),没有看到地址引脚,怎么传输地址(如何将地址信号告诉 NAND)?
答1:在 DATA0~DATA7 上既传输数据,又传输地址。用一个信号 ALE 分辨是“地址”还是“信号”,当 ALE 为高电平时传输的是地址。当 ALE 为低电平是传输的是数据
问2:要操作 NAND FLASH 需要先发出命令,只有 8 条DATA0~7 的数据线 怎么传入命令?
答2:在 DATA0~DATA7 上既传输数据,又传输地址,也传输命令。
当 ALE 为高电平时传输的是地址,
当 CLE 为高电平时传输的是命令,
当 ALE 和 CLE 都为低电平时传输的是数据。
问3:数据线既接到 NAND FLASH,也接到 NOR FLASH,还接到 SDRAM、DM9000 等等 那么怎么避免干扰
答3:这些设备,要访问之前必须"选中",没有选中的芯片不会工作,相当于没接一样,要“选中”这就是它们都有“片选” 信号
问4:假设烧写 NAND FLASH,把命令、地址、数据发给它之后 NAND FLASH 肯定不可能瞬间完成烧写的怎么判断烧写完成?
答4:通过状态引脚 RnB 来判断:它为高电平表示就绪,它为低电平表示正忙。
问 5.:怎么操作 NAND FLASH 呢?
答 5.:根据 NAND FLASH 的芯片手册,一般的过程是:
发出命令
发出地址
发出数据 或 读数据

1.2NAND结构

在这里插入图片描述NAND FLASH的结构是一页一页(一个扇区一个扇区)的结构,一页是 2KB,除了这 2KB 外还有 64B 的空间,这个 64B 区叫“OOB”(out of bank 叫作在 BANK 之外的东西)。这个 OOB 区不参与“统一编址”,就是说假若某一页 A 的地址是“2-2047”,那么 2048 这个地址不是在 OOB 区,而是在页 B 上(2048-4095)。
引入 OOB,是因为 NAND 有个缺点:位反转。如读一页数据时,里面很可能有某一位发生了位反转。本来值为 0,读出来为“1”。写的时候也有可能发生“位反转”,这样引入了“ECC”校验
解决位反转:
写时:
1,写一页数据。
2,用这一页数据生成 ECC 码(校验码)。
3,把 ECC 写入 OOB 里。
读时:
1,读整页的数据。
2,读 OOB 里的 ECC 码。3,通过读出来的一页数据算校验码。
4,比较从 OOB 里读出来的 ECC 码和通过读到的一页数据算出来的 ECC 码是否相同不同则是发生了位反转。ECC 码是特定设置的,可以通过它知道是哪一位发生了反转。

ECC 校验码,可以用硬件生成,也可以用软件生成。

二、NAND驱动编写

2.1init函数框架

static int __init s3c_nand_init(void)
{
    printk("s3c_nand_init NAND Driver, (c) 2020 Simtec Electronics\n");
    /* 1. 分配一个nand_chip结构体 */
    s3c_nand = kzalloc(sizeof(struct nand_chip),GFP_KERNEL);

    /* 2. 设置nand_chip */
    /* 设置nand_chip是给nand_scan函数使用的, 如果不知道怎么设置, 先看nand_scan怎么使用 
     * 它应该提供:选中,发命令,发地址,发数据,读数据,判断状态的功能
     */
    s3c_nand->select_chip = s3c2440_select_chip;
    s3c_nand->cmd_ctrl = s3c2440_nand_cmd_ctrl;
    s3c_nand->IO_ADDR_R   = "NFDATA的虚拟地址";
    s3c_nand->IO_ADDR_W   = "NFDATA的虚拟地址";
    s3c_nand->dev_ready = s3c2440_dev_ready;
    /* 3. 硬件相关的设置 */

    /* 4. 使用: nand_scan */
    s3c_mtd = kzalloc(sizeof(struct mtd_info),GFP_KERNEL);
    mtd->priv = nand_chip;
    mtd->owner = THIS_MODULE;

    nand_scan(s3c_mtd,1);   /* 识别NAND FLASH, 构造mtd_info */
    /* 5. add_mtd_partitions */
    return 0;
}

2.1.1设置nand_chip结构

通过分析"nand_scan"中使用 nand_chip的情况分析如何使用他,如下是nand_scan函数:

nand_scan   // drivers/mtd/nand/nand_base.c,构造mtd_info
nand_scan_ident
  busw = chip->options & NAND_BUSWIDTH_16;  //总线宽度即FLASH为8位还是16位
  nand_set_defaults //成员函数为空时默认函数,nandflash协议层
        if (!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_ready
    nand_get_flash_type //硬件相关层
        chip->select_chip(mtd, 0);
        chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
        *maf_id = chip->read_byte(mtd); //读厂家ID 
         dev_id = chip->read_byte(mtd); //读设备ID 
nand_scan_tail
    //ECC
    mtd->erase = nand_erase;
    mtd->read = nand_read;
    mtd->write = nand_write; 

片选芯片
chip->select_chip(mtd, 0)平台默认函数如下,并没有做其他操作,因此需要做一些客制化来片选目前的芯片。

static void nand_select_chip(struct mtd_info *mtd, int chipnr)
{
    struct nand_chip *chip = mtd->priv;

    switch (chipnr) {
    case -1:
        chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
        break;
    case 0: //为0时为第一个芯片,里面什么也没做 
        break;

    default:
        BUG();
    }
}

看2440的NAND控制器可知,片选就是在"NFCONT"寄存器"Reg_nCE"bit1域设置为0,具体如下

static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr)
{
    if(chipnr == -1)
    {
        s3c_nand_regs->nfcont |= (1<<1); 
        /* 取消选中: NFCONT[1]设为1 */
    }else{
        s3c_nand_regs->nfcont &= ~(1<<1);  
        /* 选中: NFCONT[1]设为0 */
    }
}

发命令/地址/数据
首先NAND FLASH取地址时,先看哪一页再看是页内的哪个地址
默认函数:chip->cmdfunc = nand_command;

void nand_command(struct mtd_info *mtd, unsigned int command, int column, int page_addr) 
//“column”:页内地址(页内哪一个地址) 
//“page_addr”:页地址
chip->cmd_ctrl(mtd, readcmd, ctrl);//参 2 为命令值或地址值,参 3 控制了是发命令还是发地址。

查2440 NAND控制器实现2440接口

static void s3c2440_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
    if (ctrl & NAND_CLE)
    {
        /* 发命令: NFCMMD=dat */
        s3c_nand_regs->nfcmd = dat;
    }else{
        /* 发地址: NFADDR=dat */
        s3c_nand_regs->nfaddr = dat;
    }
}

读数据:厂家ID、设备ID
默认函数:chip->read_byte = busw ? nand_read_byte16 : nand_read_byte
从原理图看,使用的是8bit的nand flash,故使用下面的函数

static uint8_t nand_read_byte(struct mtd_info *mtd)
{
    struct nand_chip *chip = mtd->priv;
    return readb(chip->IO_ADDR_R);
}

默认函数中需要提供:nand_chip->IO_ADDR_R
s3c_nand->IO_ADDR_R = &s3c_nand_regs->nfdata; //需要提供NFDATA寄存器的地址读数据
写数据
默认函数:chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;

static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
{
    int i;
    struct nand_chip *chip = mtd->priv;

    for (i = 0; i < len; i++)
        writeb(buf[i], chip->IO_ADDR_W);
}

判断状态
默认函数:chip->waitfunc = nand_wait
使用2440 nand 控制器中的’NFSTAT"寄存器

static int s3c2440_dev_ready(struct mtd_info *mtd) 
{ 
return (s3c_nand_regs->nfstat & (1<<0)); 
} 

2.1.2设置硬件状态

在这里插入图片描述从上图2440 nand控制器时序图可知
发出“CLE/ALE”后,要过“TACLS”时间才能开始发一个“nWE”写信号。“nWE”写信号变成高电平之后,还要过“TWRPH1”时间,“CLE/ALE”就变成低电平。
再看 NAND 芯片的时序图:

在这里插入图片描述
对照数据手册,计算出时间差

#define TACLS 0 //因为TACLS=0 
#define TWRPH0 1 //因为TWRPH0 >= 1 
#define TWRPH1 0 //因为TWRPH1 >= 0 
s3c_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4); 

为了省电。内核启动时会将一些用不到的模块都关掉。要使用某模块就得使能CLKCON相关位域,开启CLKCON

clk = clk_get(NULL, "nand"); 
clk_enable(clk); /* CLKCON'bit[4] 设置为1*/ 

添加分区
若只是把 NAND 分成一个分区,则只要用“add_mtd_device(mtd_info 结构)”就可以。若要构造分区,则用“add_mtd_partitions()

/*
参 1,mtd_info 结构体。 
参 2,mtd_partition 结构指针。相当于一个结构数组。最终是数组,组元是结构体。 
参 3,就是参 2 这个 mtd_partition 结构数组的组元有多少项。 
*/
int add_mtd_partitions
(struct mtd_info *master,const struct mtd_partition *parts,int  nbparts)
{
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,
    }
};

2.2exit函数

static void s3c_nand_exit(void)
{
    del_mtd_partitions(s3c_mtd);//清除分区结构数组
    kfree(s3c_mtd);
    iounmap(s3c_nand_regs);
    kfree(s3c_nand);
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[Linux驱动]-----NAND FLASH 的相关文章

  • jpegtran 优化而不更改文件名

    我需要优化一些图像 但不更改它们的名称 jpegtran copy none optimize image jpg gt image jpg 但是 这似乎创建了 0 的文件大小 当我对不同的文件名执行此操作时 大小仍然完全相同 怎么样 jp
  • 如何授予 apache 使用 NTFS 分区上的目录的权限?

    我在一台带有 20GB 硬盘的旧机器上运行 Linux Lubutu 12 10 我有一个 1 TB 外部硬盘 上面有一个 NTFS 分区 在该分区上 有一个 www 目录 用于保存我的网页内容 它在启动时自动安装为 media t515
  • 有没有办法将 SWF 转换为 SVG 格式?

    有没有办法将 FLA 或 SWF 转换为 SVG 格式 它可以是一个软件吗 或者甚至是网络转换器 我尝试了一些方法 但没有一个有效 所有这些似乎都已经过时了 不 SWF 支持的功能太多 而 SVG 格式无法创建有效的 SWF 版本 如果您只
  • jq中如何分组?

    这是 json 文档 name bucket1 clusterName cluster1 name bucket2 clusterName cluster1 name bucket3 clusterName cluster2 name bu
  • ftrace:仅打印trace_printk()的输出

    是否可以只转储trace printk 输出于trace文件 我的意思是过滤掉函数跟踪器 或任何其他跟踪器 中的所有函数 一般来说 您可以在选项目录中关闭选项 sys kernel debug tracing options Use ls显
  • 查找哪个程序运行另一个程序

    我有一个 NAS 运行在 Redhat Linux 的有限版本上 我按照指示破解了它 这样我就可以访问 shell 这很有帮助 我还做了一些修改 其他人也做过修改 除了一个问题之外 它们似乎都工作得很好 不知何故 每隔 22 天 系统就会关
  • CoAP数据包的大小是多少?

    我是这项技术的新手 有人可以帮助我了解一些疑问吗 Q 1 CoAP数据包的大小是多少 我知道有 4 字节固定标头 但是包括标头 选项和负载在内的最大大小限制是多少 Q 2 有像MQTT那样的Keep Alive的概念吗 它在UDP上工作 它
  • Linux 上的用户空间能否实现本机代码的抢占式多任务处理?

    我想知道是否可以在 Linux 用户空间的单个进程中实现本机代码的抢占式多任务处理 也就是说 从外部暂停一些正在运行的本机代码 保存上下文 交换到不同的上下文 然后恢复执行 所有这些都由用户空间精心安排 但使用可能进入内核的调用 我认为这可
  • 当 grep "\\" XXFile 我得到“尾随反斜杠”

    现在我想查找是否有包含 字符的行 我试过grep XXFile但它暗示 尾随反斜杠 但当我尝试时grep XXFile没关系 谁能解释一下为什么第一个案例无法运行 谢谢 区别在于 shell 处理反斜杠的方式 当你写的时候 在双引号中 sh
  • 如何在基于 Linux 的系统上的 C 程序中使用 mqueue?

    如何在基于 Linux 的系统上的 C 程序中使用 mqueue 消息队列 我正在寻找一些好的代码示例 可以展示如何以正确且正确的方式完成此操作 也许是一个操作指南 下面是一个服务器的简单示例 该服务器接收来自客户端的消息 直到收到告诉其停
  • waitpid() 的作用是什么?

    有什么用waitpid 它通常用于等待特定进程完成 或者如果您使用特殊标志则更改状态 基于其进程 ID 也称为pid 它还可用于等待一组子进程中的任何一个 无论是来自特定进程组的子进程还是当前进程的任何子进程 See here http l
  • 进程退出后 POSIX 名称信号量不会释放

    我正在尝试使用 POSIX 命名信号量进行跨进程同步 我注意到进程死亡或退出后 信号量仍然被系统打开 在进程 打开它 死亡或退出后是否有办法使其关闭 释放 早期的讨论在这里 当将信号量递减至零的进程崩溃时 如何恢复信号量 https sta
  • 监视目录的更改

    很像一个类似的问题 https stackoverflow com questions 112276 directory modification monitoring 我正在尝试监视 Linux 机器上的目录以添加新文件 并希望在这些新文
  • 确定我可以向文件句柄写入多少内容;将数据从一个 FH 复制到另一个 FH

    如何确定是否可以将给定数量的字节写入文件句柄 实际上是套接字 或者 如何 取消读取 我从其他文件句柄读取的数据 我想要类似的东西 n how much can I write w handle n read r handle buf n a
  • 我们可以在 Actionscript 中将编译后的 Haxe swf 的 SWC 用作普通库吗?

    我们可以在 Actionscript 中将编译后的 Haxe swf 的 SWC 用作普通库吗 我有一个从haxe代码编译的swf 我可以尝试将它编译成其他SWC 我想将它用作AS3中的lib 是否可以 如果是的话怎么办 是的 可以 性能提
  • 如何找到 AS3 中 xml 子级的数量

    所以现场文档说这是在 XML 对象上调用 length 对于 XML 对象 此方法始终 返回整数 1 length XMLList 类的方法返回一个 对于 XMLList 对象 值为 1 仅包含一个值 我在 xml 上调用它 如下所示
  • 在 unix 中编译 dhrystone 时出错

    我是使用基准测试和 makefile 的新手 我已经从下面的链接下载了 Dhrystone 基准测试 我正在尝试编译它 但我遇到了奇怪的错误 我尝试解决它 但没有成功 有人可以帮助我运行 dhrystone 基准测试吗 以下是我尝试编译的两
  • 无法在 Perl 中找到 DBI.pm 模块

    我使用的是 CentOS 并且已经安装了 Perl 5 20 并且默认情况下存在 Perl 5 10 我正在使用 Perl 5 20 版本来执行 Perl 代码 我尝试使用 DBI 模块并收到此错误 root localhost perl
  • 使用 plistBuddy 获取值数组

    var keychain access groups declare a val usr libexec PlistBuddy c Print var sample plist echo val echo val 0 Ouput Array
  • Awk - 计算两个文件之间的每个唯一值和匹配值

    我有两个文件 首先 我尝试获取第 4 列中每个唯一字段的计数 然后匹配第二个文件的第二列中的唯一字段值 File1 第 4 列的每个唯一值和 File2 第 2 列包含我需要在两个文件之间匹配的值 所以本质上 我试图 gt 如果 file2

随机推荐

  • Linux驱动的软件架构(一):驱动的软件设计模式理念

    这个内容是我观看 Linux设备驱动开发详解 的学习笔记 xff0c 其实书里面是先讲了关于驱动的很多的基础知识 xff0c 然后再讲驱动的软件架构 但是我最近深深地沉迷于自顶向下的学习逻辑 xff0c 所以打算先对整个驱动有了框架之后 x
  • java.lang.NoClassDefFoundError: com/jspsmart/upload/SmartUploadException

    问题描述 我在使用Smartupload上传图片的时候 xff0c 代码没问题 xff0c 编译也没有报错 xff0c 但是启动服务器 xff0c 便出现了java lang NoClassDefFoundError com jspsmar
  • datetime-local数据类型和Date数据类型转化(前端到后端,后端到前端)

    前端的datetime local传递到后端为Date类型 前端的input输入框 span class token tag span class token tag span class token punctuation lt span
  • Ubuntu18.04中LXC安装配置以及简单使用

    LXC安装配置 安装LXC sudo apt install lxc y 安装完毕之后 xff0c 默认的文件路径为 etc lxc 查看LXC版本 sudo lxc version 然后创建Ubuntu的LXC容器 t 指定模板 xff0
  • STM32 串口详解

    目录 01 USART的特点 02 USART简介 2 1 数据传输模型 2 2 帧结构 2 3 波特率 03 STM32的USART 04 代码配置 01 USART的特点 USART是通用异步收发传输器 xff08 UniversalA
  • Ubuntu18.04安装配置FRR

    FRR 文章描述了如何在Ubuntu18 04的环境下安装配置frr 0 更新安装源 vi etc apt sources list 更改文件内容 deb http mirrors aliyun com ubuntu bionic main
  • Ubuntu中安装配置JDK1.8

    JDK1 8安装配置 下载JDK 点击下载jdk 解压 将下载的压缩包解压到 opt目录下 span class token function tar span zxvf 下载的jdk压缩包名字 C opt 设置软链接 切换到 opt目录下
  • 使用Systemback制作Ubuntu20.04自定义系统镜像和系统备份

    为了方便我们自定义系统的镜像文件和系统下载的软件 xff0c 减轻再次部署的麻烦 xff0c 我们会制作镜像文件 本文就是利用Systemback来制作Ubuntu20 04自定义系统镜像和系统备份 查看网上的Systemback安装教程很
  • Key exchange was not finished, connection is closed.解决办法

    错误 利用java连接Linux服务器中碰到错误 xff1a Key exchange was not finished connection is closed xff0c 导致服务器的连接失败 xff0c 报错如下 原因 是ssh中的k
  • JAVA数据结构之顺序表、单向链表及双向链表的设计和API实现

    一 顺序表 顺序表在内存中是数组的形式存储 类名SequenceList构造方法SequenceList int capacity xff1a 创建容量为capacity的SequenceList对象成员方法1 public void cl
  • 单向链表快慢指针实际应用问题

    快慢指针 所谓快慢指针 xff1a 就是利用两个指针移动速度的不同来实现需求 xff0c 一般设置两个指针 xff0c 慢指针每次移动一格 xff0c 快指针每次移动两格 下面分享利用快慢指针解决中间值 链表环路以及环路入口的问题 中间值问
  • Caused by: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax 解决方法

    问题描述 Caused by java sql SQLSyntaxErrorException You have an error in your SQL syntax xff1b check the manual that corresp
  • 数组和JSON之间的格式转换

    数组和JSON之间的格式转换 主要代码 xff1a span class token keyword const span a span class token operator 61 span span class token const
  • Linux vncpasswd and passwd

    1 vncpasswd 功能 xff1a 使用vncpasswd命令可以创建或更改一个VNC的登录密码 xff0c 这将同时在用户的主目录下创建一个隐藏的目录 vnc xff0c 该目录内有一个文件passwd保存着VNC登录密码 语法 v
  • 修改运行中的docker容器的端口映射(简单、高效)

    提示 xff1a 文章写完后 xff0c 目录可以自动生成 xff0c 如何生成可参考右边的帮助文档 文章目录 前言查看已经存在容器id关闭docker服务 xff0c 修改配置文件结束 xff0c 启动容器 前言 在docker run创
  • 人脸识别系列(十六):AMSoftmax

    论文链接 xff1a Additive Margin Softmax for Face Verification 2019 1 24 xff1a 注 xff1a 腾讯AI Lab的 CosFace Large Margin Cosine L
  • C语言:strtok()的用法。

    char strtok char str const char sep 1 sep参数是个字符串 xff0c 定义了用作分隔符的字符集合 xff1b 2 第一个参数指定一个字符串 xff0c 它包含了0个或者多个由sep字符串中一个或者多个
  • 日积月累

    目录 PYTHONUBUNTUTRACKINGNEURAL NETWORKMACHINE LEARNING PYTHON 有路径的地方要注意区别 和 ubuntu使用 分割文件夹 xff1b 对于别人的代码 xff0c 首先仔细阅读read
  • 19.RFID复习

    题型 填空题30分 xff08 一空一分 xff09 简答题30分 xff08 三道题 xff09 综合题40分 xff08 两道题 xff09 重点章节第一章 xff0c 第二章 xff08 见整理的练习题 xff09 xff0c 第四章
  • [Linux驱动]-----NAND FLASH

    一 NAND原理及硬件操作 C xff1a fopen xff0c fread xff0c fwrite APP open read write 1 txt 文件读写 文件系统 xff1a vfat ext2 ext3 yaffs xff0