微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM中MMU使用实例

ARM中MMU使用实例

时间:11-11 来源:互联网 点击:
MMU使用实例:地址映射

本开发板SDRAM的物理地址范围处于0x30000000 - 0x33FFFFFF,S3C2410/S3C2440的寄存器地址范围都处于0x48000000 - 0x5FFFFFFF。在第5章中,通过往GPBCON和GPBDAT这两个寄存器的物理地址0x56000010、0x56000014写入特定数据来驱动4个LED

本章的实例中,将开启MMU,并将虚拟地址空间0xA0000000 - 0xA0100000映射到物理地址空间0x56000000 - 0x56100000上,这样,就可以通过操作地址0xA0000010、0xA0000014来达到驱动这4个LED的同样的效果。

另外,将虚拟地址空间0xB0000000 - 0xB3FFFFFF映射到物理地址空间0x30000000 - 0x33FFFFFF上,并在连接程序时将一部分代码的运行地址指定为0xB0004000(这个数值有些奇怪,看下去就会明白),看看能否使程序跳转到0xB0004000处执行。

本章程序只使用一级页表,以段的方式进行地址映射。32位CPU的虚拟地址空间达到4GB,一级页表中使用4096个描述符来表示这4GB空间(每个描述符对应1MB的虚拟地址),每个描述符占用4字节,所以一级页表占16KB。本实例使用SDRAM的开始16KB来存放一级页表,所以剩下的内存开始物理地址为0x30004000。

将程序代码分为两部分:第一部分的运行地址设为0,它用来初始化SDRAM、复制第二部分代码到SDRAM中(存放在0x30004000开始处)、设置页表、启动MMU,最后跳到SDRAM中(地址0xB0004000)去继续执行;第二部分的运行地址设为0xB0004000,它用来驱动LED。

程序源代码有3个文件:head.S、init.c、leds.c

(1)、head.S代码详解

head.S文件如下:

@*************************************************************************

@ File:head.S

@功能:设置SDRAM,将第二部分代码复制到SDRAM,设置页表,启动MMU,

@然后跳到SDRAM继续执行

@*************************************************************************

.text

.global _start

_start:

ldr sp, =4096@设置栈指针,以下都是C函数,调用前需要@设好栈

bldisable_watch_dog@关闭WATCHDOG,否则CPU会不断重启

blmemsetup@设置存储控制器以使用SDRAM

blcopy_2th_to_sdram@将第二部分代码复制到SDRAM

blcreate_page_table@设置页表

blmmu_init@启动MMU

ldr sp, =0xB4000000@重设栈指针,指向SDRAM顶端(使用虚拟地址)

ldr pc, =0xB0004000@跳到SDRAM中继续执行第二部分代码

halt_loop:

bhalt_loop

head.S中调用的函数都在init.c中实现。

值得注意的是,在第15行开启MMU后,无论是CPU取指还是CPU读写数据,使用的都是虚拟地址。

在第14行设置页表时,在create_page_table函数中令head.S、init.c程序所在内存的虚拟地址和物理地址一样,这使得head.S和init.c中的代码在开启MMU后能够没有任何障碍地继续运行。

(2)init.c代码详解。

init.c中的disable_watch_dog、memsetup函数实现的功能在前面两章已经讨论过,不再重复,下面列出代码方便阅读。

/*

* init.c:进行一些初始化,在Steppingstone中运行

*它和head.S同属第一部分程序,此时MMU未开启,使用物理地址

*/

/* WATCHDOG寄存器*/

#define WTCON(*(volatile unsigned long *)0x53000000)

/*存储控制器的寄存器起始地址*/

#define MEM_CTL_BASE0x48000000

/*

*关闭WATCHDOG,否则CPU会不断重启

*/

void disable_watch_dog(void)

{

WTCON = 0;//关闭WATCHDOG很简单,往这个寄存器写0即可

}

/*

*设置存储控制器以使用SDRAM

*/

void memsetup(void)

{

/* SDRAM 13个寄存器的值*/

unsigned longconstmem_cfg_val[]={ 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

};

inti = 0;

volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;

for(; i < 13; i++)

p[i] = mem_cfg_val[i];

}

copy_2th_to_sdram函数用来将第二部分代码(即由leds.c编译得来的代码)从Steppingstone中复制到SDRAM中,在连接程序时,第二部分代码的加载地址被指定为2048,重定位地址为0xB0004000,所以系统从NAND Flash启动后,第二部分代码就存储在Steppingstone中地址2048之后,需要把它复制到0x30004000处(此时尚未开启MMU,虚拟地址0xB0004000对应的物理地址在后面设为0x30004000)。Steppingstone总大小为4KB,不妨把地址2048之后的所有数据复制到SDRAM中,所以源数据的结束地址为4096。

copy_2th_to_sdr

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top