做p2p投资理财的网站,wxparse wordpress,wordpress不显示引用图片,专业的网站建设网络目录
一:介绍
1:引入
2:概念
3:通信
A:片选信号
B:片选信号的地址空间范围
4:地址线
A:不同位数的接法
B:访问原理
C:访问地址
5:时序
1:NOR FLASH A:2440NOR FLASH时序
B:原理/时序图
C:寄存器
6:SDARM
A:访问方式
B:原理图
C:BWSCON
D:BANKCON…目录
一:介绍
1:引入
2:概念
3:通信
A:片选信号
B:片选信号的地址空间范围
4:地址线
A:不同位数的接法
B:访问原理
C:访问地址
5:时序
1:NOR FLASH A:2440NOR FLASH时序
B:原理/时序图
C:寄存器
6:SDARM
A:访问方式
B:原理图
C:BWSCON
D:BANKCON6
E:REFRESH
F:ANKSIZE
G:MRSR
二:代码
1:NOR FLASH
2:SDARM 一:介绍
1:引入 操作GPIO: 我们可以编写程序让CPU去访问里面的寄存器 eg:GPFCON配置寄存器 . 可以设置这个寄存器,把某个引脚设置为输出或者输入; GPFDATA数据寄存器, 可以设置某个引脚发出高低电平. UART一样我们可以写程序让CPU访问某些特定的寄存器. 对于CPU来说我不关心你这些具体的接口我只是去操作某个寄存器。我CPU把某些值写给某些寄存器由这些对应的控制器发出特定的波形。所以这个时候我们的内存控制器就来了
2:概念 CPU发出的地址信号并不会传到外面来(eg:GPIO口)。CPU只是用地址来选择里面的不同寄存器。然后CPU把数据发给里面的寄存器至于这些数据这些地址会起什么作用完全由里面的控制器决定。CPU发出来这些信号呢并不会直接的输出到外部电路去。凡事都有例外(内存接口). 内存接口:对于这种接口的设备CPU发出来的地址可以直接传给这些设备。 在原理图种也可以看到 数据信号CPU发出的地址和数据直接传给这个芯片 内存控制器作用: 3:通信 A:片选信号 内存控制器根据CPU发出的地址设置不同的片选引脚只有被选中的芯片才会工作,没有选中的芯片不会影的他 只有使得某个片选引脚输出低电平的时候对应的芯片才会开始工作 SDRAM: 在SDRAM中只有LnWE, 所以LnWE负责写入数据和读取数据 NOR FLASH LnOE:拉低负责读取数据, LnWE负责写入数据 DM900: LnOE:拉低负责读取数据, LnWE负责写入数据 CPU根据指令发出地址信号内存控制器来根据这些地址来决定选中哪一些芯片。 B:片选信号的地址空间范围
每个片选引脚相隔134217758位, 当地址处于某一个范围的时候, 对于的片选信号才会有效----见4地址线C:访问地址 至少需要A0~A27条地址线: 内存的存储单元个数2^地址线的条数因此计算内存的总地址线数的公式为: 地址线的条数log2(内存的存储单元个数. CPU有32位地址线, 但是内存控制器他的能力只能控制27位地址线 只有使得某个片选引脚输出低电平的时候对应的芯片才会开始工作
4:地址线
A:不同位数的接法
8位 CPU的A0接到芯片的A0
16位 当使用两个8位的芯片拼接(DATA0-7接一个芯片,DATA8-15接一个芯片,也就是组成了一个16位的芯片)的时候,CPU的A1接芯片的A0(CPU的A0用来判断高8位有效还是低8位有效) CPU的A1接的位芯片的A0
32位 CPU的A2接到芯片的A0
B:访问原理 CPU把地址发送给内存控制器, 内存控制器找到了相应地址的内存类设备(ROM), 内存类设备(ROM)返回数据给内存控制器, 内存控制器找到了储存单元种的数据发送给CPU. 内存控制器所发出的地址线, 有一部分接到了芯片上. 有一部分没有接接到芯片上。 接到了芯片上的这些引脚呢用来确定,读取这个芯片上哪一个单元把这个单元返回给内存控制器。而内存控制器呢会使用那些没有接的引脚来确定从这个单元中取出哪一个字节返回给CPU eg: C:访问地址 5:时序
1:NOR FLASH
我们这里面只研究读时序 A:2440NOR FLASH时序 Taa: 发出add后时间DATA才有效, 可以看到max时间为70ns, 如果在70ns之内访问数据,数据可能不太稳定, 导致我们读取数据错误. Tce: 和上面的差不多, 片选信号的max为70 所以我们为了简单可以把地址,片选,读写,数据信号以70ns一起发出 B:原理/时序图 我们可以看到NOR FLASH有21根地址信号(但是CPU只连接芯片的20根), 16个数据信号, 以及片选限号NCS0, 和写信号LnWE读信号LnOE 我们可以计算一下我们这个2440NOR FLASH内存的大小
2^21/1024/10242MB 先发出地址信号经过Tacs时间发出片选信号(nGCS),然后经过Tcos时间发出读信号,过一会数据才有效,把数据读走然后把读信号释放掉把片选信号释放掉,然后才开始新的地址周期 Tacs TcosTaccTacp...这些需要根据不同的芯片来进行设置 因为J2440可以接不同类型的内存类芯片这些内存内芯片性能不同所以所用的时间周期也不同。 C:寄存器
在上次种我们把HCLK该为了100MHZ 他默认为14clocks(14*1014070), 所以每次时序都可以正常的运行
6:SDARM
A:访问方式 不像NOR FLSAH一样直接发送地址 SDRAM拆分地址在发送
B:原理图 SDARM是由2个16为的芯片组合而成, 成为32位的芯片。 故内存大小
2^324294967296bit4194304KB4096MB4GB 挂载在BANK6上片选引脚为nGCS6
C:BWSCON 因为我们的SDRAM只挂载在BANK6上 所以我们只关系BANK6。 DW6: 我们的bank是32位的所以选择---10 WS6: WAIT是由芯片发送给CPU的信号 以前的芯片准备数据慢 在CPU给内存控制器发送地址后。内存控制器给给芯片发送各种信号准备采集数据但是芯片如果还没有准备好数据可以给CPU发送WAIT信号。最大的宽限时间。 等待信号的使能由于现在的内存速度足够快在读数据时不需要内存控制器等待选择0。 ST6:BANK6的带宽选择32位 BWSCON0x02000000
D:BANKCON6 MT: 我们使用的位SDRAM使用选择11 Trcd这个域的配置表示的是发送行有效命令到列有效命令之间的时间间隔。在发送列读写命令时必须要与行有效命令有一个间隔这个间隔被定义为tRCD即RAS to CAS DelayRAS至CAS延迟可以理解为行选通周期这应该是根据芯片存储阵列电子元件响应时间从一种状态到另一种状态变化的过程所制定的延迟。 我们使用HCLK为10ns所以选择00 SCAN列地址的位数 选择01 --9位 BANKCON60x00018001
E:REFRESH 之所以称为DRAM就是因为它要不断进行刷新Refresh才能保留住数据因此它是DRAM最重要的操作 REFRE肯定要使能刷新操作。---1 TREFMD刷新操作分为两种自动刷新Auto Refresh简称AR与自刷新Self Refresh简称SR。对于AR SDRAM内部有一个行地址生成器也称刷新计数器用来自动的依次生成行地址。SR则主要用于休眠模式低功耗状态下的数据保存这方面最著名的应用就是STRSuspend to RAM休眠挂起于内存。这里不使用低功耗模式故TREFMD0B使用自动刷新。-----0 Trp:预充电时间。其实就是读取不同行之间的时间间隔。L-Bank关闭现有工作行准备打开新行的操作就是预充电Precharge。在发出预充电命令之后要经过一段时间才能允许发送RAS行有效命令打开新的工作行这个间隔被称为tRPPrecharge command Period预充电有效周期。-----00即20ns Tsrc:--01 Trc我们取70ns, Trp我们设置的为20ns, 所以TsrcTrc-Trp70-2050ns Refresh Conuter:我们根据SDARM芯片的Refresh period刷新周期的值确定刷新计数器的值。 64ms/8192bit7.8ms Refresh count 2^11 1 100x7.8 12690x4f5---以为我们使用的HCLK为100MHZ REFRESH0x008404f5
F:ANKSIZE
BURST_EN使能突发传输 突发Burst是指在同一行中相邻的存储单元连续进行数据传输的方式连续传输所涉及到存储单元列的数量就是突发长度Burst Lengths简称BL。 BURST_EN :使能他一次访问多个字节 SCKE_EN 使用时钟使能休眠模式 ANKSIZE0x000000b1
G:MRSR CL: WBL突发长度选择固定第二个值为reserved也没得选 TM只能选00B CLCL是SDRAM很重要的参数 在选定列地址后就已经确定了具体的存储单元剩下的事情就是数据通过数据I/O通道DQ输出到内存总线上了。但是在CAS发出之后仍要经过一定的时间才能有数据输出从CAS与读取命令发出到第一笔数据输出的这段时间被定义为CLCAS LatencyCAS潜伏期。由于CL只在读取时出现所以CL又被称为读取潜伏期RLRead Latency。CL的单位与tRCD一样为时钟周期数具体耗时由时钟频率决定。 设置CL为2个时钟周期。CL010B。 BT只能选0 BL只能选0 MRSR0x00000020
二:代码
1:NOR FLASH
/* CLKDIVN(0x4C000014) 0X5, tFCLK:tHCLK:tPCLK 1:4:8 */ldr r0, 0x4C000018ldr r1, (09)str r1, [r0]ldr r0, 0x4C000014ldr r1, 0x5str r1, [r0]/* 设置CPU工作于异步模式 */mrc p15,0,r0,c1,c0,0orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iAmcr p15,0,r0,c1,c0,0/*设置MPLLCON*/ldr r0, 0x4C000004ldr r1, (9212)|(14)|(10)str r1, [r0]/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定* 然后CPU工作于新的频率FCLK*//*设置内存: sp栈* 我们判断是nor启动还是nand启动/mov r1, #0ldr r0, [r1] /* 读出原来的值备份 */str r1, [r1] /* 0-[0] */ ldr r2, [r1] /* r2[0] */cmp r1, r2 /* r1r2? 如果相等表示是NAND启动 */ldr sp, 0x400000004096 /* 先假设是nor启动 */moveq sp, #4096 /* nand启动 */streq r0, [r1] /* 恢复原来的值 */bl mainhalt:b halt#define ULCON0 (*((volatile unsigned int*)0x50000000))
#define UCON0 (*((volatile unsigned int*)0x50000004))
#define UBRDIV0 (*((volatile unsigned int*)0x50000028))
#define GPHCON (*((volatile unsigned int*)0x56000070))
#define GPHUP (*((volatile unsigned int*)0x56000078))
#define UFCON0 (*((volatile unsigned int*)0x50000008))
#define UTRSTAT0 (*((volatile unsigned int*)0x50000010))
#define UTXH0 (*((volatile unsigned char*)0x50000020))
#define URXH0 (*((volatile unsigned char*)0x50000024))
#define BANKCON0 (*((volatile unsigned int*)0x48000004))
#define GPFCON (*((volatile unsigned int*)0x56000050))
#define GPFDAT (*((volatile unsigned int*)0x56000054))int LED_on()
{ /*设置寄存器 点亮LED2*//*设置输出模式*/GPFCON 0x400;/*输出低电平*/GPFDAT 0;return 0;
}void init_nc_tacc(int val)
{BANKCON0 val 8;}
void UART_init()
{/*引脚设置*/GPHCON ~((3 4) | (3 6));GPHCON | ((2 4) | (2 6));GPHUP ~((1 2) | (1 3)); /* 使能内部上拉 *//*设置波特率---设置波特率位115200*//*UBRDIVn (int)(selected clock / (baudrate x 16) ) –1我们使用我们的FCLK作为我们的时钟源--在汇编中是50MHZUBRDIVn(5000 0000 /(115200*16))-126*/UCON0 0x00000005;UBRDIV0 26;/*数据格式*/ULCON0 0x00000003; //不能写为这个ULCON0 | (3 1)因为还要关注其他位;/*数据位8,停止位1,无奇偶校验 8n1*/
}
int putchar(int c)
{/*发送数据*/while ((UTRSTAT0 (1 2)) 0); //while (!(UTRSTAT0 (1 2)));UTXH0 (unsigned char)c;
}int getchar(void)
{/*接收数据*/while ((UTRSTAT0 (1 0)) 0); //while (!(UTRSTAT0 (1 0)));return URXH0;
}int puts(const char* s)
{while (*s){putchar(*s);s;}}#include uart.h
#include sc2440_so.h
#include NOR.h
#include led.h
int main(void)
{unsigned char c;UART_init();puts(Please enter the numbesr:\n\r);while (1){c getchar();putchar(c);if (c 0 c 7){init_nc_tacc(c-0);LED_on();}else{puts(Error: The number you entered is not between 0 and 7\n\r);puts(Please rewrite input\n\r);}}return 0;
}
init_nc_tacc(c-0);和init_nc_tacc(c);的区别 在编程中init_nc_tacc(c-0); 和 init_nc_tacc(c); 的区别取决于 init_nc_tacc 函数如何定义和 c 的数据类型。 如果 c 是一个字符型变量如 char并且代表一个数字字符例如 1、2、3 等 c-0 通常用于将字符型数字转换为实际的整数。在ASCII编码中数字字符 0 到 9 是连续的因此通过减去 0其ASCII值为48可以将字符型数字转换为整数。例如如果 c 是 3c-0 将得到整数 3。init_nc_tacc(c-0); 会将转换后的整数传递给函数。init_nc_tacc(c); 则会将字符型变量传递给函数。 如果 c 不是代表数字的字符那么 c-0 可能没有明确的意义并且可能不会得到预期的结果。 如果 init_nc_tacc 函数对字符和整数有不同的处理逻辑那么两个调用会有不同的效果。 如果 c 是其他数据类型比如已经是一个整数那么 c-0 就没有意义并且可能导致编译错误或不可预测的行为。 2:SDARM
代码大致和NOR FLASH不变, 我们这里只展示改变的
#include sc2440_so.h
void SDARMA_init(void)
{BWSCON 0x02000000;BANKCON6 0x00018001;BANKCON7 0x00018001;REFRESH 0x008404f5;ANKSIZE 0x000000b1;MRSRB6 0X00000020;MRSRB7 0X00000020;
}
int init_test(void)
{ //片选引脚为nGCS6volatile unsigned char* p (volatile unsigned char*)0X30000000;int i;//write 操作for (i 0; i 1000; i){p[i] 0x55;}//读操作for (i 0; i 1000; i){if (p[i] ! 0x55) {return -1;}}return 0;}#include uart.h
#include sc2440_so.h
#include NOR.h
#include led.h
int main(void)
{unsigned char c;UART_init();puts(Please enter the numbesr:\n\r);while (1){c getchar();putchar(c);if (c 1) {SDARMA_init();if(init_test() 0){LED_on();}}else{puts(Error: Please retype:\n\r);}}return 0;
}