ARM学习笔记--day09

存储设备:
处理器中必须额外接存储设备
    RAM(内存,掉电数据丢失):
        原理分类:
            1.SRAM
                静态RAM,线性存储的结构,不会刷数据,每增加个数据,就会在末尾处加一块内存,这样存取数据会快一些,同时也导致SRAM的面积大一些
                小的SRAM集成到CPU上(小的4~8k,大的几十k)
            2.DRAM
                动态RAM(常用),特点就是便宜,会每间隔ms就刷一次内存数据,这段间隔时间内存储器时无法使用的,这是个缺点,但DRAM面积小一些
                嵌入式处理器,外接DRAM
                处理器中有控制器,然后根据接口控制外接DRAM(SDRAM和DDRAM),外接DRAM必须一开机初始化才能使用,但是开机的一刹那,程序如果是在DRAM上运行,则会导致程序无法运行,所以就需要SRAM,把DRAM的初始化工作放到SRAM中,等到他初始化完成之后,再执行DRAM中的程序
        本身具有随机访问的能力
    FLASH(代替电脑的硬盘):
        NandFlash
            同与(N and),与DRAM优点差不多,就是便宜,NandFlash没有地址线,所以不能直接执行程序,操作系统把其中的内容读出来放到内存中,然后才能被执行,操作Nandflash要按块去操作,不可以按字节去操作
            最小结构叫做页
            可以存储启动代码
            处理器中内置nandflash控制器
            CPU利用nandflash控制器从nandflash读出数据后放到DRAM后,再由处理器从内存中取指执行
            我们编写程序主要还是对nandflash控制器编程
        NorFlash
            同或(N or),NorFlash与SRAM的处理器接口是完全一样,NorFlash中的程序可以直接运行,本身具有随机访问的能力
    Nandflash:
        分析原理
            需要单独学习nandflash的datasheet(三星的nandflash datasheet)
                先弄清楚管脚的定义,共48根管脚其中N.C(not connect)是未连接的
                IO0~7:数据输入输出的8根管脚,因此从NandFlash中分批次的读写数据,就是8位数据,作为输出管脚的话,把数据传递给CPU,作为输入管脚的话,把数据/命令/地址从CPU读进flash里边,nandflash没有地址线,所以CPU就不能直接寻址,对nandflash的操作就是操作命令(读,写,擦除命令)
                CPU给Nandflash发送数据可以是数据,地址,命令,那么怎么区分,就引入了下述两根管脚,比如发送0x30
                CLE(command latch enable):命令锁存使能管脚,CLE拉高那么ALE就不会拉高,拉高就表示IO中传递的是谁,当两者都拉低的时候IO传递就是数据
                ALE(address latch enable):地址锁存使能管脚,同上
                CE(chip enable):芯片使能管脚,flash内部分块的,片选就是选择一个内存块,比如3G,分成3个块,片选一个就可以用一个G,片选信号一般都是低电平有效
                CE1同上
                CE2同上
                这里有个小标记,在datasheet中,CE上边有小横线,就代表是低电平有效,CE/CE1/CE2都有小横线,所以都是低电平有效,有的时候#/n都是代表低电平有效
                RE(read enable):读使能,一根信号线,低电平有效,激活的话就是nandflash要读数据,数据流向处理器,就是处理器读
                WE(write enable):写使能,一根信号线,低电平有效,激活的话就是nandflash要写数据,数据流向存储器,处理器写
                WP(write protect):写保护,只读不写,不可以写,只可以读
                RnB(ready busy):B低电平有效,R高电平有效,他俩复用,B是忙的状态,R是准备状态,这个就是通知Nandflash是否是忙状态
                Vcc:点烟
                GND:地
                待续??
        看原理图
            flash的IO连接处理器的数据线的低八位
            片选使能,使能命令管脚,传递命令,使能地址所存,传递地址,读/写使能,传输数据,这些都是nandflash控制器硬件完成
        看datasheet
            找到与nandflash相关的部分
            写入数据,要先写校验,然后再写数据,读也需要先校验,暂不考虑校验
            NFCONF寄存器:
                1位:AddrCycle,对nandflash操作需要传递地址周期,地址是分周期传递的,这个周期是看页大小,地址周期?页大小?从哪知道周期?
                地址周期:nandflash没有地址线,CPU如何操作nandflash的地址,处理器地址和设备地址(nandflash地址),处理器的地址空间0~4G,是ARM最大寻址空间,是处理器地址,是处理器可以直接访问,通过ldr与str可以直接访问,但是ARM不能直接访问nandflash的地址(设备地址),我们要把5存到0x10000(nandflash的地址)上(处理器上也会有这个地址0x10000),我们要操作的设备地址,理论上16个G的nandflash,需要34位的数,但实际处理器与nandflash只有8根线,所以传递一个地址,需要多次传递过去,这个次数就是地址周期,所以需要5个周期来传递地址,这个周期还需要页的大小是谁,周期为5时,页大小是2k(这个可以从nandflash的datasheet中得到)
                每个页式基本单位,每个页后边跟一块存储区,是校验用的,校验方法:硬件校验与软件校验,写入之前要校验,校验完成,写的数据放到2k中,校验数据放到64字节中,读取的时候,2k与64字节都需要寻址,所以寻址一个页需要12个位数据来寻址,若干个页构成一个块,三星的这款NandFlash是64个页组成的块,对Flash擦除是整块擦除,还有个特点,在写到Flash前要先擦除,默认的全是F,写数据是把1变成0可以,要把0变成1,只能擦除整个块,若干个块构成一个device(8192个块)
                2位:PageSize,页大小,要看MLCFlash是多少,来决定这个位的值代表的页大小
                3位:MLCFlash,FLASH的类型,SLC(单层的,1~2个G)与MLC(多层的,比较大的)这两种flash
                4~15:TWRPH1,TWRPH0,TACLS
                    这几位的配置需要看时序图,HCLK是时钟用来驱动nandflash的时钟,差不多是130M左右,PCLK是外设时钟,串口控制器,GPIO控制器,SPI控制器都会用,HCLK对速度要求高点的设备用,nandflash就是用这个时钟,H2CLK高速设备,没来一个周期,控制器做一件事,来一个周期,CLE与ALE先变化,都先拉高,从这里可以知道ALE和CLE先拉高,然后数据会变化,数据先往上放,数据会持续一段时间会在8个IO上,然后WE再变化,此时是写使能稳定一段时间之后,拉低,在写使能拉低的过程中,会将数据发送出去,其他的那些都是准备时间
                    TACLS(time address command):地址或命令锁存建立时间,这个时间应该越短越好,但肯定是要有的,因为要使能地址和命令锁存器时间是Duration = HCLK(时钟周期) x TACLS,Duration是已知的,HCLK由uboot决定,从而计算出TACLS
                    TWRPH0(time write RPH0):写使能持续时间,Duration = HCLK x ( TWRPH0 + 1 ),取值同上
                    TWRPH1(time write RPH1):写使能持续时间,Duration = HCLK x ( TWRPH1 + 1 ),取值同上
                23~24:ECCType0,ECC校验类型
                MsgLength:与校验相关的
            NFCONT寄存器:(与中断相关)
                0位:MODE,是nandflash控制器的模式
            NFCMMD寄存器(命令寄存器):
                8位
            NFADDR寄存器(地址寄存器):
                8位
            NFDATA寄存器(数据寄存器):
                可以当做32位/16位/8位,一次性可以读8位,如果读一个页,需要读2k次,如果一次传32位,则需要循环512次,nandflash控制器中肯定是有缓冲,缓存32位后一下发到寄存器中,所以CPU读这个寄存器可以读到32位,决定读多少位是咱们告诉CPU的,采用int型的就是按4字节读,采用short是采用2字节读,采用char就是按1字节读
以上三个寄存器都是通过8根IO来控制,nandflash控制器把传递的功能映射到3个寄存器(NFCMMD,NFADDR,NFDATA)上,然后由处理器来处理            
U盘就是USB+FLASH
实现从nandflash中读ID的操作:
    读nandflash的datasheet,可以看到read ID operation的时序
    1.使能片选信号,CPU发送片选信号给nandflash
    2.然后命令锁存寄存器使能,同时写寄存器使能,这就代表发送命令,CPU发送命令给nandflash
    3.然后地址锁存寄存器使能,同时写寄存器使能,这就代表发送地址,CPU发送地址给nandflash
    4.读寄存器使能,这个时候IO不断有数据出来,是CPU从nandflash中读出来
        读出来数据是EC DC 35 75 75,这几个值读对了,就代表是正确的
读ID是确定nandflash是否正常,是否好用,所以驱动都先是读ID
读flash代码
                start.s
                .global start@为了让.c看得到    
            start:
                bl uart_run    @没有赋值,说明uart_run没有参数
                bl 
                b .            @b .是死循环
                            uart.c
                char shell_buffer[256];
                void uart_init(void){
                    配置寄存器,就是操作地址
                }
                char getc(void){
                    volatile int *b = (int *)0xe2900010;
                    //1.查看状态
                    while(!(*b&0x1)){
                        //2.读出字符
                        b = (int *)0xe2900024;
                        return (char)*b;
                    }
                }
                void putc(char a){
                    volatile int *b = (int *)0xe2900010;
                    //1.查看状态
                    while(!(*b&0x2)){
                        //2.写入字符
                        b = (int *)0xe2900024;
                        (char)*b = a;
                    }
                }
                void puts(char* s){
                    
                }
                void gets(void){
                    int i = 0;
                    while(1){
                        if((shell_buffer[i] != '\r')&&(i<256)){    //输入回车结束,'\r'是回车
                            shell_buffer[i] = getc();    //获取输入的指令
                            putc(shell_buffer[i]);        //这里是为了在终端显示
                            i++;
                        }else{
                            if(shell_buffer[i] == '\r'){
                                shell_buffer[i] = '\0';
                            }else{
                                /*do nothing*/
                            }
                            break;
                        }
                    }
                }
                void nand_init(void){
                    //配置寄存器,nandflash,config寄存器
                    
                    //控制寄存器,nandflash,contrl寄存器
                    
                }
                void nand_read(){
                    //操作命令寄存器
                    
                    //操作地址寄存器
                    
                    //操作数据寄存器
                    //itoa具体实现
                    //puts
                }
                void do_nand_id(){
                    //1.nandflash初始化
                    nand_init();
                    //2.读id
                    nand_read();
                }
                void parse_cmd(void){
                    char cmd_buffer[5] = "test";
                    char cmd_buffer1[9] = "donandID";
                    for(int i=0;((shell_buffer[i] != '\0')&&(i<5));i++){
                        if(shell_buffer[i] != cmd_buffer[i]){
                            puts("cmd is error");
                            break;
                        }
                        else if(shell_buffer[i] == cmd_buffer1[i]){
                            do_nand_id();
                        }                        
                        else{
                            do_test_cmd();//硬盘上的一段程序,通常需要shell进程去做这个函数的处理
                        }
                    }
                }
                void uart_run(void){
                    uart_init();
                    while(1){
                        char a = getc();
                        putc(a);
                        puts("##");
                        gets();
                        parse_cmd();
                    }
                }
32位地址怎么变成5周期地址,5个8位地址有CPU上的nandflash控制器传递地址给nandflash
通常这个位置(32位整数)变成5周期的地址
5周期地址分成两部分:2周期是列地址(页内部地址,一个页内的地址),3周期是行地址(页偏移地址,是一个块内的页的地址)
我操作的一个页是2k的,我想读0x100000的地址,怎么读?
0x100000除以2k就是页偏移地址,一个周期只能使用8根IO传递数据,需要24位数来传递,所以需要3个周期
余数就是页内地址需要11位,就需要2个周期
按页读取的话,地址一定是2k页的整数倍,所以页内便宜一定是0
R/B信号(ready/busy):就是在读大的数据量的时候,显示busy状态,这个时候就是准备过程,等到,ready状态后,CPU可以读出数据,R/B寄存器只会由0变1,但是由1变0不可以,所以操作R/B状态时,需要在读操作之前先给它写0,然后再检测什么时候被拉高变1,变1说明是进入ready状态


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值