来源:韦东山嵌入式专栏_ARM裸机加强版维基教程
作者:韦东山
(本笔墨数:8142,阅读时长:12分钟)

首先来剖析下操作GPIO掌握器和操作UART掌握器两者的差异。
如图是S3C2440是个片上系统,有GPIO掌握器(接有GPIO管脚),有串口掌握器 (接有TXD RXD引脚)。
配置GPIO掌握器相应的寄存器,即可让引脚输出高低电平;配置UART掌握器相应的寄存器,即可让引脚输出波形。前者相对大略,类似门电路,后者相对繁芜,属于协议类接口。类似的协议类接口还有iic、iis、spi等。对付CPU是不管什么接口的,它只写相应的寄存器,由掌握器根据寄存器的配置去掌握详细的引脚。
那么CPU是如何访问各个不同的寄存器的呢?
CPU只管发出一个地址,内存掌握器根据该地址选择不同的模块,然后从模块中得到数据或者发送数据到模块中。
前面的GPIO/门电路接口、协议类接口,都不会把地址输出到外部,接下来的内存类接口,会把地址输出到外部,比如Nor Flash、网卡、SDRAM。
如图,SDRAM、DM9000网卡、Nor Flash都接在JZ2440的数据总线和地址总线上,CPU把数据和地址发送出去,然后内存掌握器根据片选旗子暗记选择相应的设备吸收地址和数据旗子暗记,互不滋扰。
片选旗子暗记和地址的关系怎么确定?
这个是由2440芯片特性决定的。
当选择Nor Flash启动时,CPU发出的指令的地址范围处于0x0000000 - 0x06000000,内存掌握器就会使nGCS0处于低电平(片选引脚当选中),Nor Flash当选中。当CPU发出的指令的地址范围处于0x20000000 - 0x26000000,内存掌握器就会使nGCS4处于低电平(片选引脚当选中),网卡当选中。当CPU发出的指令的地址范围处于0x30000000 - 0x36000000,内存掌握器就会使nGCS6处于低电平(片选引脚当选中),SDRAM当选中。内存掌握器根据不同的地址地址范围,发出不同的片选引脚,只有被片选引脚选中的芯片才能正常事情,不当选中的芯片就像不存在一样,不事情。
GPIO/门电路接口、协议类接口、内存类接口都属于CPU的统一编址。对付Nand Flash,在事理图上它的地址线并没有连接到CPU,因此它不参与CPU的统一编址。但它的数据线也接到了数据总线上,为了防止滋扰,它也有一个片选旗子暗记(CE)。当CPU访问Nand Flash时,Nand Flash掌握器才会片选Nand Flash,让其吸收数据总线上的数据。
再来看下Nor Flash的空间,0x00000000 0x06000000,为128M,即每一个片选旗子暗记可以选择的空间是128M=2^27,也就须要A0、A1……A26,共27根地址线。CPU发出的32位地址线,内存掌握器根据地址范围,片选上相应的bank,并将地址转化为27位。
第002节辅线1硬件知识_不同位宽设备的连接
参考2440芯片手册,可以看到内存接口与8-bit ROM连接时,2440的A0与外部芯片的A0相连。
当与两个8-bit ROM拼接成的一个16-bit ROM连接时,2440的A1与外部芯片的A0相连。
当与四个8-bit ROM拼接成的一个32-bit ROM连接时,2440的A2与外部芯片的A0相连。
当与一个16-bit ROM连接时,2440的A1与外部芯片的A0相连。
可以看出外接芯片的位宽有变革时,地址线的接法也会有变革。那这个变革有什么规律呢?
假设CUP实行:
MOV R0, #3 @去地址为3的内存上LDRB R1, [R0] @ 从内存为3的地址上,读出一个字节
如图有8bitROM、16bitROM、32bitROM。
8个bit组成一个字节,字节是打算机的最小的存储单位,因此我们读取数据肯定都是8bit的倍数。 对付8bitROM ,8bit是一次读写的最小单位,即0地址是第一个8bit,1地址是第二个8bit;CPU发出的命令是读取地址为3上的数据,即A0和A1都为1,8bitROM的A0和A1收到的也都是1,于是找到了ROM上地址为3的8bit数据,包含了我们须要的数据。 对付16bitROM ,16bit是一次读写的最小单位,即0地址是第一个16bit,里面有两个8bit数据;CPU发出的命令是读取地址为3上的数据,即A0和A1都为1,16bitROM的A0和A1分别收到的是1和0,于是找到了ROM上地址为1的16bit数据,包含了我们须要的数据,末了内存掌握器再帮我们挑选出所需的8bit数据。 对付32bitROM ,32bit是一次读写的最小单位,即0地址是第一个32bit,里面有四个8bit数据;CPU发出的命令是读取地址为3上的数据,即A0和A1都为0,32bitROM的A0和A1收到的都是0,于是找到了ROM上地址为0的32bit数据,包含了我们须要的数据,末了内存掌握器再帮我们挑选出所需的8bit数据。
接到芯片上的引脚用来确定读取芯片上的哪一个单元的数据,把这个单元的数据返回给内存掌握器,内存掌握器会根据没有连接芯片的引脚,来确定返回哪一个单元的数据给CPU,
再举一个例子:如果通报一个32位的数据时
MOV R0, #4LDR R1, [R0] @去地址4,读取4字节数据
实行过程如下:
8bitROM: 当CPU发出地址(000100),内存掌握器会把000100,000101,000110,000111处的地址转发给ROM,ROM会把得到的地址000100,000101,000110,000111,上的数据返回给内存掌握器,内存掌握器会把得到的4个8bit的数据组装成一个32位的数据返回给CPU。16bitROM: 当CPU发出地址(000100),内存掌握器会把00010,00011处的地址转发给ROM,ROM会把得到的地址00010,00011,上的数据返回给内存掌握器,内存掌握器会把得到的2个16bit的数据组装成一个32位的数据返回给CPU。32bitROM: 当CPU发出地址(000100),内存掌握器会把0001处的地址发送给ROM,ROM会把得到的地址0001上的数据返回给内存掌握器,内存掌握器会把得到的1个32bit数据返回给CPU。若何确定芯片的访问地址:1. 根据片选旗子暗记确定基地址,2. 根据芯片所接地址线确定范围
实例:Nor Flash 利用的是片选0(nGCS0),基地址为0,用到A20,A19……A1,A0共21条地址线,以是地址范围为0x00000000 ~ 0x1FFFFF也便是2M的空间大小。网卡(Net)利用的是片选4(nGCS4),基地址为0x20000000,用到A2,A0共2根地址线,以是地址范围为0x20000000 ~ 0x20000005。SDRAM利用的是片选6(nGCS6),基地址为0x30000000。
第003节辅线1硬件知识_时序图剖析示例这节我们剖析一下我们理解时序图,旗子暗记之间是若何一起事情的,以Nor Flash 为例。
2440和Nor Flash 之间有地址线,数据线,还有各种数据线连接。
以Nor Flash为例,剖析下如何设置它的时序。
如图是S3C2440的Nor Flash掌握器的读时序图,里面很多参数都须要根据外接芯片的性能进行设置,有的芯片性能好、相应韶光快,就可以把参数韶光设置小一点,开释更好的性能。
如图是Nor Flash芯片的读时序。
我们须要做的便是设置S3C2440的Nor Flash掌握器时序去知足Nor Flash芯片的时序。每个参数的参考范围可以通过AC CHARACTERISTICS得到。
结合Nor Flash芯片的两张图,可以得到如下信息:
发出地址数据(Addresses)后,要等待Taa(哀求大于即是70ns)韶光,地址数据才有效;发出片选旗子暗记(CE#)后,要等待Tce(哀求大于即是70ns)韶光,片选旗子暗记才有效;发出读旗子暗记(OE#)后要等待Toe(哀求大于即是30ns)韶光,读旗子暗记才有效;为了大略我们把地址数据(Addresses),片选旗子暗记(CE#),读旗子暗记(OE#),同时发出,然后让它们都等待70ns(等待旗子暗记有效)。对应S3C2440的Nor Flash掌握器的读时序图,须要让地址旗子暗记A[24:0]、片选旗子暗记nGCS、读旗子暗记nOE同时发出,保持Tacc大于即是70ns。
查阅S3C2240的参考手册,Nor Flash是接在BANKCON0上的,因此只须要设置BANKCON0即可。
可以看到Tacc上电初始值是111,对应14个clocks。系统上电采取12MHz的晶振,HCLK=12MHz,Tacc=(1000/1214)≈1166ns,这个值很大,险些可以知足所有Nor Flash的哀求。
启动后,将HCLK设置为100MHz,T=1000/100=10ns,Tacc须要大于即是70ns,因此设置Tacc即是101,8个clocks即可。
在前面uart实验的源码根本上,新建init.c和init.h两个文件。
在init.c里面只须要设置BANKCON0寄存器即可。
#include "s3c2440_soc.h"void bank0_tacc_set(int val){ BANKCON0 = val << 8;}
init.h进行函数声明。
#ifndef _INIT_H#define _INIT_Hvoid bank0_tacc_set(int val);#endif
末了在主函数里面,通过串口获取输入的值,传入bank0_tacc_set()函数里,设置Tacc,然后再读取Nor Flash上的闪灯程序。
#include "s3c2440_soc.h"#include "uart.h"#include "init.h"int main(void){ unsigned char c; uart0_init(); puts("Enter the Tacc val: \n\r"); while(1) { c = getchar(); putchar(c); if (c >= '0' && c <= '7') { bank0_tacc_set(c - '0'); led_test(); } else { puts("Error, val should between 0~7\n\r"); puts("Enter the Tacc val: \n\r"); } } return 0;}
实验效果:
输入0~4,Tacc小于70ns,无法读取Nor Flash上数据,LED不能闪烁。
输入4~7,Tacc大于70ns,可以读取Nor Flash上数据,LED不断闪烁,且值越小越快(差异不明显)。
第004节辅线1硬件知识_SDRAM的设置
本节将讲解如何设置SDRAM,如果想对内存有更多的理解,可以在网上搜索看下这篇文档“高手进阶_终极内存技能指南——完全/进阶版”。
在JZ2440上接有64M的SDRAM,如果想要利用SDRAM,须要对内存掌握器做一些设置。在前面第一节讲到,CPU将数据或地址发给内存掌握器,内存掌握器再去访问外部的SDRAM,因此设置内存掌握器就说本节的核心。
如图是SDRAM存储构造逻辑图:
SDRAM统共有4个块(Banks),可以认为每个块便是一个表格,里面的每个格子表示的是16bit数据。
问题1:若何访问里面的某个格子呢?首先发出一个片选旗子暗记,选中全体芯片;发出Bank地址,选择是哪一个Bank(块,即表格);发出行地址;末了发出列地址,才能选中是个格子;问题2:那么多的旗子暗记有谁发出呢?由内存掌握器发出,以是我们须要设置内存掌握器,CPU只是大略的实行读写内存的命令,其他的都交给内存掌握器来处理。
例如:
LDR R0,=0x30000000LDR R1,[R0]
CPU把0x30000000这个地址发给内存掌握器,内存掌握器根据这个地址,判断属于哪个范围,然后发出相应的片选旗子暗记。根据类型(比如SDRAM)拆分成三部分:发出Bank地址、发出行地址、发出列地址。对付上面的三个,若何拆分呢?
行地址线有几条,列地址线有几条,都要设置内存掌握器里面干系寄存器。
读数据综上所述:对SDRAM的访问可以分为如下步:
CPU发出的片选旗子暗记nSCS6有效,它选中SDRAM芯片。SDRAM中有4个L-Bank,须要两根地址旗子暗记来选中个中之一,根据事理图,可知利用ADDR24,ADDR25作为L-Bank的选择旗子暗记。对当选中的芯片进行统一的行/列(存储单元)寻址。根据SDRAM芯片的列地址线数目设置CPU的干系寄存器后,CPU就会从32位的地址中自动分出L_Bank片选旗子暗记,行地址旗子暗记,列地址旗子暗记,然后先后发出行地址旗子暗记,列地址旗子暗记。L_Bank选择旗子暗记在发出行地址旗子暗记的同时发出,并坚持到列地址旗子暗记结束。
根据事理图可知:
地址、列地址共用地线ADDR2—ADDRI4(BANK6位宽为32,ADDRO/I没有利用),利用nSRAS、nSCAS两个旗子暗记来区分它们。
比如本开拓板中,利用两根地址线ADDR24、ADDR25作为L-Bank的选择旗子暗记:SDRAM芯片K4s5m632的行地址数为13,列地址数为9,以是当nSRAS旗子暗记有时,ADDR2—ADDR14上发出是行地址旗子暗记,它对应32位地址空间的b可23m]:当nSCAS旗子暗记有效时,ADDR2—ADDR10上发出的是列地址旗子暗记,它对应32位地址空间的bit[0:2];由于BANK6以32位的宽度外接DRAM,ADDR0、ADDR1恒为0,不参与译码。
找到了存储单元后,当选中的芯片就要进行统一的数据传输了。开拓板中利用两片16位的SDRAM芯片并联组成32位的位宽,与CPU的32根数据线(DATA0—DATA31)相连。BANK6的起始地址为0x30000000,以是SDRAM的访问地址为0x30000000~低0x33FFFFFF,共64MB。
2440内存掌握器设置:
内存掌握器共有13个寄存器,
BANK0–BANK5只须要设置BWSCON和BANKCONx(x为0~5)两个寄存器;
BANK6、BANK7外接SDRAM时,除BWSCON和BANKCONx(x为6、7)外,还要设置REFRESH、BANKSIZE、MRSRB6、MRSRB7等4个寄存器。
下面分类解释各个寄存器的设置。
1.位宽和等待掌握寄存器BWSCON(BUSWIDTH&WAITCONTROLREGISTER)BWSCON中每4位掌握一个BANK,最高4位对应BANK7(没有利用)、接下来4位对应BANK6。
(1)ST6[27]: 启动/禁止SDRAM的数据掩码引脚,对付SDRAM,此位为0:对付SRAM此位为1。
(2)WS6[26]:是否利用存储器的WAIT旗子暗记,常日设为0。
(3)DW6[25:24]:利用两位来设置相应BANK的位宽,0b00对应8位,0b01对应16位,0b10对应32位(开拓板用的便是32位的),0b11表示保留。
因此BWSCON寄存器的值为:0x22000000。
2.BANK掌握寄存器BANKCON6(BANKCONTROLREGISTER)在8个BANK中,只有BANK6和BANK7可以外接SRAM或SDRAM。(1)MT[16:15]:用于设置本BANK外接的是ROM/SRAM还是SDRAM,SRAM:0b00,SDRAM:0b11(开拓板利用的是SDRAM)。当MT[16:15]设置为00时,此寄存器与BANKC0N0、BANKCON5类似,不再赘述。
当MT[16:15]设置为11时,此寄存器其他值如下设置。
(2)Trcd[3:2]:行地址和列地址间隔多永劫光,看芯片手册韶光间隔是20ns,本来开拓板的HCLK是100MHZ,clocks为10ns,以是设置为推举值0b00(2clocks)。
(3)SCAN[1:0]:SDRAM的列地址位数,对付本开拓板利用的SDRAMK4S561632。列地址位数为9,以是SCAN=0b010如果利用其他型号的SDRAM,须要查看其数据手册。来决定SCAN的取值。0b00表示8位,0b01表示9位,0b10表示10位。
综上所述,本开拓板中BANKCON6设为0x017001。
3.刷新掌握寄存器REFRESH(REFRESHCONTROLREGISTER)(1)REFEN[23]:0=禁止SDRAM的刷新功能,1:开启SDRAM的刷新功能(设置开启SDRAM的刷新功能)。
(2)TREFMD[22]:SDRAM的刷新模式,0=CBR/AutoRefresh,1=SelfRefresh(一样平常在系统休眠时利用),我们设置默认值。
(3)Trp[21:20):根据芯片手册设为0即可。
(4)Tsrc[19:18]:根据芯片手册设为默认值0b01即可。
(5)RefreshCounter[10:0]:即R_CNT
R_CNT可如下汁算(SDRAM时钟频率便是HCLK):R_CNT=2^11+1-SDRAM时钟频率(MZ)SDRAM刷新周期(us)
SDRAM的刷新周期在SDRAM的数据手册上有标明,在本开拓板利用的SDRAM:K4S561632的数据手册上,可瞥见这么一行“64msrefreshpenod(8KCycle)以是,刷新周期=64ms/8192=7.8125us。Refreshcount=2^11+1-100x7.8=1269=0x4F5。
因此,本开拓板中REFRESH设为0x8404F5。
4.BANKSIZE寄存器REFRESH(BANKSIZEREG ISTER)(1)BURST_EN[7]:0=ARM核禁上突发传输,1=ARM核支持突发传输(推举);
(2)SCKEEN[5]:0=不该用SCKE旗子暗记令SDRAM进入省电模式,1=利用SCKE旗子暗记令SDRAM进入省电模式(推举);
(3)SCLK-EN[4]:0=时候发出SCLK旗子暗记,1=仅在访问SDRAM期间发出SCLK旗子暗记(推举);
(4)BK76MAP[2:0]:设置BANK6的大小。本开拓板BANK6外接64MB的SDRAM,令[2:0]=b001(64M/64M),表示BANK6/7的容量都是64MB,虽然BANK7没有利用。
因此,本开拓板中BANKSIZE设为0xB1。
5.SDRAM模式设置寄存器MRSRBx6(SDRAM MODE REGISTER SET REGISTER)能修正的只有位CL[6:4],这是SDRAM时序的一个韶光参数,表示发出行、列地址后,等多久才返回收到数据,CL可以取值为0b0l0(2 clocks)或0b011(3 clocks)。
本开拓板取最守旧的值0b010,以是MRSRB6的值为0x20。
下面开始写程序:在init.c里面进行对内存掌握器的寄存器依次进行设置:
void sdram_init(void){ BWSCON = 0x22000000; BANKCON6 = 0x17001; BANKCON7 = 0x17001; REFRESH = 0x8404f5; BANKSIZE = 0xb1; MRSRB6 = 0x20; MRSRB7 = 0x20;}
再写一个测试函数,向SDRAM里面连续写1000个数,再读出数据比拟是否是设置的数,返回比拟结果:
int sdram_test(void){ volatile unsigned char p = (volatile unsigned char )0x30000000; int i; // write sdram for (i = 0; i < 1000; i++) p[i] = 0x55; // read sdram for (i = 0; i < 1000; i++) if (p[i] != 0x55) return -1; return 0;}
在主函数里调用sdram_test()测试函数,如果测试成功,LED闪烁:
int main(void){ uart0_init(); sdram_init(); if (sdram_test() == 0) led_test(); return 0;}
实验结果:
LED按预期闪烁,屏蔽掉sdram_init()后,LED不闪烁。
「新品首发」STM32MP157开拓板火爆预售!
首批仅300套