1. SDRAM
当加电默认从NAND启动时,先将4K代码复制到Steppingstone内RAM执行,在执行Steppingstone代码时,会将剩余的代码复制到SDRAM执行,但是使用SDRAM必须先对其有关SDRAM的寄存器进行初始化,以便能使用SDRAM
主要包括寄存器: BWSCON、BANKCON0~7、REFRESH、BANKSIZE、MRSRB6~7
这些寄存器要根据相应的单板进行设置,如下为Mini2440默认设置
0x22011110, //BWSCON
0x00000700, //BANKCON0
0x00000700, //BANKCON1
0x00000700, //BANKCON2
0x00000700, //BANKCON3
0x00000700, //BANKCON4
0x00000700, //BANKCON5
0x00018005, //BANKCON6
0x00018005, //BANKCON7
0x008C07A3, //REFRESH
0x000000B1, //BANKSIZE
0x00000030, //MRSRB6
0x00000030, //MRSRB7
0x22011110 ; @ BWSCON //对不同的128M块进行设置
0x00000700 ; @ BANKCON0 //块0的设置,以下类同
。。。
0x00018005 ; @ BANKCON6 //主要考虑内存的列地址的位数,下一个类同
。。。
0x008C07A3 ; @ REFRESH //这个值要注意晶振频率导致的差异,Mini440初始晶振=12mhz
0x000000B1 ; @ BANKSIZE //内存块选取的设置
0x00000030 ; @ MRSRB6 //对SDRAM时间参数进行设置
对块初始化为例,如下
#define MEM_CTL_BASE 0x48000000
void memsetup(void)
{
unsigned long const mem_cfg_val[] = {0x22011110,
0x00000700,
0x00000700,
0x00000700,
0x00000700,
0x00000700,
0x00000700,
0x00018005,
0x008c07a3,
0x000000b1,
0x00000030,
0x00000030,
};
int i;
volatile unsigned long* p = (volatile unsigned long*)MEM_CTL_BASE;
for(i = 0; i<13; i++ )
{
p[i] = mem_cfg_val[i];
}
}
这里将存储控制器所有的块以及特殊寄存器的设置都放到数组里,然后对他们一一初始化
2. MMU(内存管理单元)
一般主要设置页表和内存的地址映射问题,先看一段启动的汇编代码
AREA head,CODE,READONLY
ENTRY
CODE32
start
ldr sp,=4096
bl disable_watch_dog
bl memsetup
bl copy_2th_to_sdram
bl create_page_table
bl mmu_init
ldr sp,=0xb4000000
ldr pc,=0xb0004000
halt_loop
b halt_loop
END
这里可以看到主要有create_page_table 和mmu_init两部分进行MMU的设置,主要是地址的映射
下面看create_page_table虚拟地址的映射
void create_page_table(void)
{
unsigned long virtaddr,physaddr;
unsigned long *mmu_tlb_base = (unsigned long *)0x30000000;
#define MMU_FULL_ACESS (3<<10)
#define MMU_DOMAIN (0<<5)
#define MMU_SPECIAL (1<<4)
#define MMU_CACHEABLE (1<<3)
#define MMU_BUFFERABLE (1<<2)
#define MMU_SECTION (2<<0)
#define MMU_SECDESC (MMU_FULL_ACESS | MMU_DOMAIN | MMU_SPECIAL | MMU_SECTION)
#define MMU_SECTION_WB (MMU_SECDESC | MMU_CACHEABLE | MMU_BUFFERABLE)
virtaddr = 0;
physaddr = 0;
//这个应该为mmu_tlb_base&fff00000
*(mmu_tlb_base + (virtaddr>>20)) = (physaddr&0xfff00000)|MMU_SECTION_WB;
virtaddr = 0xa0000000;
physaddr = 0x56000000;
*(mmu_tlb_base + (virtaddr>>20)) = (physaddr&0xfff00000)|MMU_SECTION;
virtaddr = 0xb0000000;
physaddr = 0x30000000;
while(virtaddr < 0xb4000000)
{
*(mmu_tlb_base + (virtaddr>>20)) = (physaddr&0xfff00000)|MMU_SECTION_WB;
physaddr += 0x100000;
virtaddr += 0x100000;
}
}
这个主要是虚拟地址的映射
virtaddr = 0xb0000000; //虚拟地址,即连接后的地址
physaddr = 0x30000000; //物理地址,实际程序在内存的运行地址
while(virtaddr < 0xb4000000)
{
*(mmu_tlb_base + (virtaddr>>20)) = (physaddr&0xfff00000)|MMU_SECTION_WB;
physaddr += 0x100000;
virtaddr += 0x100000;
}
这里是一级页表也就是采用段的方式,将页表的内存放到虚拟地址去,怎么放呢?
首先怎么得到页表?(physaddr&0xfff00000)段基址 MMU_SECTION_WB设置段的访问权限
那么如何放到虚拟地址呢?首先他一般是需要TLB寄存器的值和MVA的值组成,MVA即是virtaddr,TLB即是mmu_tlb_base,各位怎么放置请看手册
对于为何physaddr、virtaddr都是加0x100000? 这里段默认是只能访问1M的空间,而0x100000正好是1M
对于如何实现MMU呢?
void mmu_init(void)
{
__asm{
mov r0,#0
mcr p15,0,r0,c7,c7,0 //使无效Icache和Dcache
mcr p15,0,r0,c7,c10,0
mcr p15,0,r0,c8,c7,0 //使无效指令,数据TLB
mov r4,#0
mcr p15,0,r4,c2,c0,0 //设置页表寄存器
mov r0,#0
mcr p15,0,r0,c3,c0,0 //域访问控制寄存器,不进行权限检查
mrc p15,0,r0,c1,c0,0 //读取控制寄存器
bic r0,r0,#0x3000 //清除V、I位
bic r0,r0,#0x300 //清除R、S位
bic r0,r0,#0x0087 //清除B、C、A、M位
orr r0,r0,#0x0002 //对齐检查
orr r0,r0,#0x0004 //开启Dcache
orr r0,r0,#0x1000 //开启Icache
orr r0,r0,#0x0001 //使能MMU
mcr p15,0,r0,c1,c0,0 //写入寄存器
}
}
请看右侧的注释
3.NAND设置
请先看如下设置图示
上一篇:Mini2440 裸机实验之LED程序、按键、中断
下一篇:mini2440 LCD驱动
推荐阅读最新更新时间:2024-11-09 13:05
设计资源 培训 开发板 精华推荐
- LTC2862AHS8-1 网络的典型应用,用于针对 5kV 浪涌、5kV EFT 和 30kV IEC ESD Plus ±360V 过压保护的 IEC 4 级保护
- LTC3886IUKG 高效 425kHz 4 相 5V 降压转换器的典型应用电路
- DC2389A,基于 LTM8073 的演示板 7V = VIN = 60V,Vout = 5V @ 3A Silent Switcher 降压模块
- 用于笔记本电脑的 MOSFET 功率驱动器
- 使用 Sanken Electric Co., Ltd 的 SSC2001 的参考设计
- 自行车风火轮 arduino
- 【训练营】WS2812小爱同学炫光底座 694846A
- 5 至 32V DC 至 DC 单路输出电源
- XL7015E1降压稳压3.3V模块
- ADR3440 4.096-Vout 微功率、高精度电压基准的典型应用