S5PV210系列 (裸机十五)之 iNand

iNand介绍

iNand/eMMC/SDCard/MMCCard的关联

(1)最早出现的是 MMC 卡,卡片式结构,按照 MMC 协议设计。(相较于NandFlash芯片来说,MMC卡 有 2 个优势:第一是卡片化,便于拆装;第二是统一了协议接口,兼容性好。)

(2)后来出现 SD卡,兼容 MMC 协议。SD卡 较 MMC 有一些改进,譬如写保护、速率、容量等。

(3)SD卡 遵守 SD 协议,有多个版本。多个版本之间向前兼容。

(4)iNand/eMMC 在 SD 卡的基础上发展起来,较 SD卡 的区别就是将 SD卡 芯片化了(解决卡的接触不良问题,便于设备迷你化)。

(5)iNand 和 eMMC 的关联:eMMC 是协议,iNand 是 Sandisk 公司符合 eMMC 协议的一种芯片系列名称。

iNand/eMMC的结构框图及其与NandFlash的区别

(1) iNand 内部也是由存储系统和接口电路构成(和 Nand 结构特性类似,不同之处在于接口电路功能不同)。

(2) iNand 的接口电路挺复杂,功能很健全。譬如:
第一,提供 eMMC 接口协议,和 SoC 的 eMMC 接口控制器通信对接。
第二,提供块的 ECC 校验相关的逻辑,也就是说 iNand 本身自己完成存储系统的 ECC 功能,SoC 使用 iNand 时自己不用写代码来进行 ECC 相关操作,大大简化了 SoC 的编程难度。( NandFlash 分 2 种:SLC 和 MLC,SLC 更稳定,但是容量小价格高;MLC 容易出错,但是容量大价格低)
第三,iNand 芯片内部使用 MLC Nand 颗粒,所以性价比很高。
第四,iNand 接口电路还提供了 cache 机制,所以 inand 的操作速度很快。

iNand / eMMC 的物理接口和 SD 卡物理接口的对比

(1) S5PV210 芯片本身支持 4 通道的 SD/MMC,在 X210 中实际是在 SD/MMC0通道接了 iNand 芯片,而 SD/MMC2 接了 SD 卡( SD/MMC3 也接了 SD卡 )。

(2)对比 inand 和 SD卡 接线,发现:这两个接线几乎是一样的,唯一的区别就是SD卡 IO 线有 4 根,而 iNand 的 IO 线有 8 根。

(3)这个告诉我们,我们在实际操作 iNand芯片 时和操作 SD卡 时几乎是一样的(物理接线几乎一样,软件操作协议几乎一样)。

结论:

iNand / eMMC 其实就是芯片化的 SD/MMC 卡,软件操作和 SD 卡相同。
分析 iNand 芯片的操作代码时,其实就是以前的 SD卡 的操作代码。一些细节的区别就是为了区分各种不同版本的 SD卡、iNand 的细节差异。

SD卡/iNand操作

硬件接口:DATA、CLK、CMD

(1) iNand 的 IO 线有 8 根,支持 1、4、8 线并行传输模式;SD 卡 IO 线有 4 根,支持 1、4 线并行传输模式。

(2) CMD 线用来传输命令、CLK 线用来传输时钟信号。

(3)接口有 CLK 线,工作时主机 SoC 通过 CLK 线传输时钟信号给 SD卡/iNand 芯片,说明:SD/iNand 是同步的,SD/iNand 的工作速率是由主机给它的CLK频率决定的。

命令响应的操作模式

(1) SD 协议事先定义了很多标准命令(CMD0、CMD1·····),每个命令都有它的作用和使用条件和对应的响应。SD 卡工作的时候就是一个一个的命令周期组合起来的,在一个命令周期中,主机先发送 CMD 给 SD 卡,然后 SD卡 解析这个命令并且执行这个命令,然后 SD 卡根据结果回发给主机 SoC 一个响应。(有些命令是不需要响应的,这时 SD 卡不会给主机回发响应,主机也不用等待响应)。标准的命令+响应的周期中,主机发完一个命令后应该等待 SD卡 的响应而不是接着发下一条命令。

这里写图片描述

SD/iNand的体系结构图

(1) SD 卡内部有一个接口控制器,这个控制器类似于一个单片机,这个单片机的程序功能就是通过 CMD 线接收外部主机 SoC 发给 SD卡 的命令码,然后执行这个命令并且回发响应给主机 SoC。这个单片机处理命令及回发响应遵循的就是SD 协议。这个单片机同时可以控制 SD卡 内部的存储单元,可以读写存储单元。

这里写图片描述

SD / iNand 的寄存器(重点是 RCA 寄存器)

(1)注意这里说的是 SD卡 内部的寄存器,而不是主机 SoC 的 SD 控制器的寄存器。(很多外置芯片内部都是有寄存器的,这些寄存器可以按照一定的规则访问,访问这些寄存器可以得知芯片的一些信息)。

(2) RCA(relative address,相对地址寄存器)。我们在访问 SD卡 时,实际上 SD卡内部每个存储单元的地址没有绝对数字,都是使用相对地址。相对地址由 SD卡自己决定的,存放在 RCA 寄存器中。

SoC 的 SD/MMC/iNand 控制器简介

(1)不同的 SoC 可能在 SD/MMC/iNand 等支持方面有差异,但是如果支持都是通过内部提供 SD 控制器来支持的。

(2)S5PV210 的 SD卡 控制器在 Section8.7 部分

SD/iNand代码实战分析

// SD协议规定的命令码   
#define CMD0    0
#define CMD1    1
#define CMD2    2   
#define CMD3    3   
#define CMD6    6
#define CMD7    7
#define CMD8    8
#define CMD9    9
#define CMD13   13
#define CMD16   16
#define CMD17   17
#define CMD18   18
#define CMD23   23  
#define CMD24   24
#define CMD25   25  
#define CMD32   32  
#define CMD33   33  
#define CMD38   38  
#define CMD41   41  
#define CMD51   51
#define CMD55   55  

// 卡类型
#define UNUSABLE        0
#define SD_V1           1   
#define SD_V2           2   
#define SD_HC           3
#define MMC             4

// 卡状态
#define CARD_IDLE       0           // 空闲态
#define CARD_READY      1           // 准备好
#define CARD_IDENT      2
#define CARD_STBY       3
#define CARD_TRAN       4
#define CARD_DATA       5
#define CARD_RCV        6
#define CARD_PRG        7           // 卡编程状态
#define CARD_DIS        8           // 断开连接

// 卡回复类型    
#define CMD_RESP_NONE   0           // 无回复
#define CMD_RESP_R1     1
#define CMD_RESP_R2     2
#define CMD_RESP_R3     3
#define CMD_RESP_R4     4
#define CMD_RESP_R5     5
#define CMD_RESP_R6     6
#define CMD_RESP_R7     7
#define CMD_RESP_R1B    8

命令码 CMD 和 ACMD

(1) SD卡 工作在命令 + 响应的模式下。

(2) SD协议 的命令分 2 种:CMDx 和 ACMDx。CMD 是单命令命令,就是单独发一个 CMD 即可表示一个意思。ACMD 是一种扩展,就是发 2 个 CMD 加起来表示一个意思。可以认为 ACMDx = CMDy + CMDz( y 一般是 55 )

卡类型识别 SD or MMC?

(1) MMC 协议、SD 协议、eMMC 协议本身是一脉相承的,所以造成了一定的兼容性,所以当我们 SoC 控制器工作时连接到 SoC 上的可能是一个 MMC 卡、也可能是 SD 卡、也可能是 iNand 芯片。主机 SoC 需要去识别这个卡到底是什么版本的卡

(2) SoC 如何区分卡种类?因为不同版本的卡内部协议不同的,所以对卡识别命令的响应也是不同的。SoC 通过发送一些命令、听取响应就可以根据不同的响应判定卡的版本。

卡状态

(1) SD卡 内部的接口控制器类似于一个单片机,这个单片机其实是一个状态机。所以 SD卡 任何时候都属于某一种状态(空闲状态、准备好状态、读写状态、出错状态····都是事先定义好的),在这种状态下能够接受的命令是一定的,接受到命令之后执行一定的操作然后根据操作结果会跳转为其他状态。如果主机发过来的命令和当前状态不符状态机就不响应,如果收到命令和当前状态相符就会执行相应操作,执行完之后根据结果跳转为其他状态。

卡回复类型

(1)一般来说,SD 卡的命令都属于:命令 + 响应的模式。也有极少数的 SD 卡命令是不需要回复的。

(2)卡回复有 R1、R7、R1B 等 8 种类型,每种卡回复类型都有自己的解析规则。然后卡在特定状态下响应特定命令时有可能回复哪种响应都是 SD 协议事先规定好的,详细细节要查阅协议文档。

这里写图片描述

这里写图片描述

linux内核风格的寄存器定义

(1)定义一个基地址,然后定义要访问的寄存器和基地址之间的偏移量,在最终访问寄存器时地址就等于基地址+偏移量。

SD/iNand相关的GPIO初始化

#if (HSMMC_NUM == 0)
#define HSMMC_BASE  (0xEB000000)
#elif (HSMMC_NUM == 1)
#define HSMMC_BASE  (0xEB100000)
#elif (HSMMC_NUM == 2)
#define HSMMC_BASE  (0xEB200000)
#elif (HSMMC_NUM == 3)
#define HSMMC_BASE  (0xEB300000)
#else
#error "Configure HSMMC: HSMMC0 ~ HSMM3(0 ~ 3)"
#endif

SD/iNand的时钟设置

(1)SD卡本身工作需要时钟,但是自己又没有时钟发生单元,依靠主机SoC的控制器通过SD接口中的CLK线传一个时钟过来给SD卡内部使用。所以主机SD卡控制器先初始化好自己的时钟,然后将自己的时钟传给SD卡。

(2)因为此时刚开始和SD卡通信,主机不清楚SD卡属于哪个版本(高版本和低版本的SD卡的读写速率不同,高版本的可以工作在低版本的速率下,低版本的SD卡不能工作在高版本速率下),所以先给SD卡发400KHz的低速率时钟,SD卡拿到这个时钟后就能工作了。然后在后面和SD卡进行进一步通信时去识别SD卡的版本号,识别后再根据SD卡的版本进一步给它更合适的时钟。

static void Hsmmc_ClockOn(uint8_t On)
{
    uint32_t Timeout;
    if (On) {
        __REGw(HSMMC_BASE+CLKCON_OFFSET) |= (1<<2); // sd时钟使能
        Timeout = 1000; // Wait max 10 ms
        while (!(__REGw(HSMMC_BASE+CLKCON_OFFSET) & (1<<3))) {
            // 等待SD输出时钟稳定
            if (Timeout == 0) {
                return;
            }
            Timeout--;
            Delay_us(10);
        }
    } else {
        __REGw(HSMMC_BASE+CLKCON_OFFSET) &= ~(1<<2); // sd时钟禁止
    }
}

static void Hsmmc_SetClock(uint32_t Clock)
{
    uint32_t Temp;
    uint32_t Timeout;
    uint32_t i;
    Hsmmc_ClockOn(0); // 关闭时钟   
    Temp = __REG(HSMMC_BASE+CONTROL2_OFFSET);
    // Set SCLK_MMC(48M) from SYSCON as a clock source  
    Temp = (Temp & (~(3<<4))) | (2<<4);
    Temp |= (1u<<31) | (1u<<30) | (1<<8);
    if (Clock <= 500000) {
        Temp &= ~((1<<14) | (1<<15));
        __REG(HSMMC_BASE+CONTROL3_OFFSET) = 0;
    } else {
        Temp |= ((1<<14) | (1<<15));
        __REG(HSMMC_BASE+CONTROL3_OFFSET) = (1u<<31) | (1<<23);
    }
    __REG(HSMMC_BASE+CONTROL2_OFFSET) = Temp;

    for (i=0; i<=8; i++) {
        if (Clock >= (48000000/(1<<i))) {
            break;
        }
    }
    Temp = ((1<<i) / 2) << 8; // clock div
    Temp |= (1<<0); // Internal Clock Enable
    __REGw(HSMMC_BASE+CLKCON_OFFSET) = Temp;
    Timeout = 1000; // Wait max 10 ms
    while (!(__REGw(HSMMC_BASE+CLKCON_OFFSET) & (1<<1))) {
        // 等待内部时钟振荡稳定
        if (Timeout == 0) {
            return;
        }
        Timeout--;
        Delay_us(10);
    }

    Hsmmc_ClockOn(1); // 使能时钟
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值