S3C2440访问SROM或寄存器
举例:
ldr r0,#100
ldr r1,[r0]
上面2条指令要求CPU将地址为100的数据内容取出,放入R1寄存器
而CPU会将地址100传给内存控制器,要求它去确定位置。
S3C2440对外引出27条地址线,8条片选线(对应8个BANK,每个BANK最大128MB)
S3C2440的内存控制器得到CPU传入的地址后,做了什么:
(1)根据地址范围,判断是哪一个BANKx。再使能对应的nGCSx片选信号。
(2)确定是哪个BANKx后,再由27条地址线决定偏移地址(128M范围),此时,对应BANKx上的数据就通过DATA总线送到了CPU上。
S3C2440访问SDRAM
MINI2440的BANK6接的是2片32MB的外部SDRAM,总共64MB,具体查看原理图。
(1)CPU发出的片选信号nSCS0(它与nGCS6是同一引脚的两个功能)有效,它选中SDRAM
(2)SDRAM中4个L-Bank(Logical Bank),需要两条地址线做片选;原理图中标明了ADDR24、ADDR25
(3)CPU使能行地址信号(nSRAS),同时输出行地址,进行行寻址;
(4)CPU使能列地址信号(nSCAS),同时输出列地址,进行列寻址;
根据SDRAM芯片的列地址线数目设置CPU相关寄存器后,
CPU就会从32为的地址自动分出L-Bank选择信号、行地址信号、列地址信号,先后发送出来。
(5)找到存储单元后,被选中的芯片就要进行数据输出。而两块16位宽的SDRAM并联组成32位宽的空间。
相关寄存器
BANK0~5只需要设置BWCON(总线位宽控制)和BANKCONx(控制);
BANK6、BANK7外接SDRAM时,还要额外设置REFRESH(刷新控制)、BANKSIZE(大小控制)、MRSRB6(BANK6控制模式)、MRSRB7
将程序拷贝到SDRAM(重定位)
- 在start.S中,使用汇编指令,配置SDRAM相关寄存器
- 配置C程序运行环境,调用C函数,将存储区start到end直接的内容全部拷贝到SDRAM中
- 使用绝对跳转指令,将pc指针指向SDRAM中的main函数,开始执行
/* main.c */
void copy2sdram(void)
{
/* 要从lds文件中获得 __code_start, __bss_start
* 然后从0地址把数据复制到__code_start
*/
extern int __code_start, __bss_start;
volatile unsigned int *dest = (volatile unsigned int *)&__code_start;
volatile unsigned int *end = (volatile unsigned int *)&__bss_start;
volatile unsigned int *src = (volatile unsigned int *)0;
while (dest < end)
{
*dest++ = *src++;
}
}
void clean_bss(void)
{
/* 要从lds文件中获得 __bss_start, _end
*/
extern int _end, __bss_start;
volatile unsigned int *start = (volatile unsigned int *)&__bss_start;
volatile unsigned int *end = (volatile unsigned int *)&_end;
while (start <= end)
{
*start++ = 0;
}
}
//
//
//
/* start.S */
.text
.global _start
_start:
/* 关闭看门狗 */
ldr r0, =0x53000000
ldr r1, =0
str r1, [r0]
/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */
/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */
ldr r0, =0x4C000000
ldr r1, =0xFFFFFFFF
str r1, [r0]
/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8 */
ldr r0, =0x4C000014
ldr r1, =0x5
str r1, [r0]
/* 设置CPU工作于异步模式 */
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0
/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0)
* m = MDIV+8 = 92+8=100
* p = PDIV+2 = 1+2 = 3
* s = SDIV = 1
* FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M
*/
ldr r0, =0x4C000004
ldr r1, =(92<<12)|(1<<4)|(1<<0)
str r1, [r0]
/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定
* 然后CPU工作于新的频率FCLK
*/
/* 设置内存: sp 栈 */
/* 分辨是nor/nand启动
* 写0到0地址, 再读出来
* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
* 否则就是nor启动
*/
mov r1, #0
ldr r0, [r1] /* 读出原来的值备份 */
str r1, [r1] /* 0->[0] */
ldr r2, [r1] /* r2=[0] */
cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */
ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
moveq sp, #4096 /* nand启动 */
streq r0, [r1] /* 恢复原来的值 */
bl sdram_init
//bl sdram_init2 /* 用到有初始值的数组, 不是位置无关码 */
/* 重定位text, rodata, data段整个程序 */
mov r0, #0
ldr r1, =_start /* 第1条指令运行时的地址 */
ldr r2, =__bss_start /* bss段的起始地址 */
sub r2, r2, r1
bl copy2sdram /* src, dest, len */
/* 清除BSS段 */
ldr r0, =__bss_start
ldr r1, =_end
bl clean_bss /* start, end */
//bl main /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */
ldr pc, =main /* 绝对跳转, 跳到SDRAM */
halt:
b halt
在上面的汇编文件中,调用C函数copy2sdram之前,将3个参数_start、__bss_start、(_start-__bss_start)分别给了R0、R1、R2,运行C程序时,参数就从寄存器中取出。
变量_start、__bss_start、_end均来自链接脚本文件.lds中的定义
链接脚本
SECTIONS
{
. = 0x30000000;
//当前运行地址为0x30000000
__code_start = .;
//定义一个符号变量,值为当前地址
. = ALIGN(4);
//4字节对齐
.text :
{
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) *(.COMMON) }
_end = .;
}