历史上的今天

今天是:2024年10月14日(星期一)

正在发生

2018年10月14日 | JZ2440裸板之MMU操作

发布者:VelvetSoul 来源: eefocus关键字:JZ2440  裸板  MMU操作 手机看文章 扫描二维码
随时随地手机看文章

启动文件head.S:

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

@ File:head.S

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

@       然后跳到SDRAM继续执行

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

.text

.global _start

_start:

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

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

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

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

    bl  create_page_table                @ 设置页表

    bl  mmu_init                              @ 启动MMU,可以使用虚拟地址了

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

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

    @ ldr pc, =main

halt_loop:

    b   halt_loop

====================================================================

init.c源码:

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

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

  

// WATCHDOG寄存器 

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

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

#define MEM_CTL_BASE    0x48000000

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

void disable_watch_dog(void)

{

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

}

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

void memsetup(void)

{

    // SDRAM 13个寄存器的值 

    unsigned long  const    mem_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

                                    };

    int     i = 0;

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

    for(; i < 13; i++)

        p[i] = mem_cfg_val[i];

}

// 将第二部分代码复制到SDRAM

void copy_2th_to_sdram(void)

{

    //参考链接文件,第二部分代码放在2048地址

    unsigned int *pdwSrc  = (unsigned int *)2048;

    //此地址为实际的物理地址,先拷贝到实际的SDRAM中,初始化MMU之后才能使用虚拟地址进行访问

    unsigned int *pdwDest = (unsigned int *)0x30004000; 

    

    while (pdwSrc < (unsigned int *)4096)   // SRAM的最大地址4M

    {

        *pdwDest = *pdwSrc;

        pdwDest++;

        pdwSrc++;

    }

}

// 设置页表

void create_page_table(void)

{

// 用于段描述符的一些宏定义

#define MMU_FULL_ACCESS     (3 << 10)   // 访问权限 

#define MMU_DOMAIN            (0 << 5)    // 属于哪个域 

#define MMU_SPECIAL              (1 << 4)    // 必须是1 

#define MMU_CACHEABLE       (1 << 3)    // cacheable 

#define MMU_BUFFERABLE      (1 << 2)    // bufferable 

#define MMU_SECTION            (2)             // 表示这是段描述符 

#define MMU_SECDESC         (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | \

                             MMU_SECTION)

#define MMU_SECDESC_WB      (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | \

                             MMU_CACHEABLE | MMU_BUFFERABLE | MMU_SECTION)

#define MMU_SECTION_SIZE    0x00100000

    unsigned long virtuladdr, physicaladdr;

    unsigned long *mmu_tlb_base = (unsigned long *)0x30000000;

    

    // Steppingstone的起始物理地址为0,第一部分程序的起始运行地址也是0,

    // 为了在开启MMU后仍能运行第一部分的程序,

    // 将0~1M的虚拟地址映射到同样的物理地址

    virtuladdr = 0;

    physicaladdr = 0;

    *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \

                                            MMU_SECDESC_WB;

    // 0x56000000是GPIO寄存器的起始物理地址,

    // GPFCON和GPFDAT这两个寄存器的物理地址0x56000050、0x56000054,

    // 为了在第二部分程序中能以地址0xA0000050、0xA0000054来操作GPFCON、GPFDAT,

    // 把从0xA0000000开始的1M虚拟地址空间映射到从0x56000000开始的1M物理地址空间

    virtuladdr = 0xA0000000;

    physicaladdr = 0x56000000;

    *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \

                                            MMU_SECDESC;

    // SDRAM的物理地址范围是0x30000000~0x33FFFFFF,

    // 将虚拟地址0xB0000000~0xB3FFFFFF映射到物理地址0x30000000~0x33FFFFFF上,

    // 总共64M,涉及64个段描述符

    virtuladdr = 0xB0000000;

    physicaladdr = 0x30000000;

    while (virtuladdr < 0xB4000000)

    {

        *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \

                                                MMU_SECDESC_WB;

        virtuladdr += 0x100000;

        physicaladdr += 0x100000;

    }

}

// 启动MMU

void mmu_init(void)

{

    unsigned long ttb = 0x30000000;

// ARM休系架构与编程

// 嵌入汇编:LINUX内核完全注释

__asm__(

    "mov    r0, #0\n"

    "mcr    p15, 0, r0, c7, c7, 0\n"    // 使无效ICaches和DCaches 

    

    "mcr    p15, 0, r0, c7, c10, 4\n"   // drain write buffer on v4 

    "mcr    p15, 0, r0, c8, c7, 0\n"     // 使无效指令、数据TLB 

    

    "mov    r4, %0\n"                       // r4 = 页表基址 

    "mcr    p15, 0, r4, c2, c0, 0\n"    // 设置页表基址寄存器 

    

    "mvn    r0, #0\n"                   

    "mcr    p15, 0, r0, c3, c0, 0\n"    // 域访问控制寄存器设为0xFFFFFFFF,

                                                       // 不进行权限检查 

                                             

    // 对于控制寄存器,先读出其值,在这基础上修改感兴趣的位,

    // 然后再写入

    "mrc    p15, 0, r0, c1, c0, 0\n"    // 读出控制寄存器的值 

    

    // 控制寄存器的低16位含义为:.RVI ..RS B... .CAM

    // R : 表示换出Cache中的条目时使用的算法,

    //     0 = Random replacement;1 = Round robin replacement

    // V : 表示异常向量表所在的位置,

    //     0 = Low addresses = 0x00000000;1 = High addresses = 0xFFFF0000

    // I : 0 = 关闭ICaches;1 = 开启ICaches

    // R、S : 用来与页表中的描述符一起确定内存的访问权限

    // B : 0 = CPU为小字节序;1 = CPU为大字节序

    // C : 0 = 关闭DCaches;1 = 开启DCaches

    // A : 0 = 数据访问时不进行地址对齐检查;1 = 数据访问时进行地址对齐检查

    // M : 0 = 关闭MMU;1 = 开启MMU

     

    // 先清除不需要的位,往下若需要则重新设置它们    

                                                      // .RVI ..RS B... .CAM  

    "bic    r0, r0, #0x3000\n"          // ..11 .... .... .... 清除V、I位 

    "bic    r0, r0, #0x0300\n"          // .... ..11 .... .... 清除R、S位 

    "bic    r0, r0, #0x0087\n"          // .... .... 1... .111 清除B/C/A/M 

    // 设置需要的位

    "orr    r0, r0, #0x0002\n"          // .... .... .... ..1. 开启对齐检查 

    "orr    r0, r0, #0x0004\n"          // .... .... .... .1.. 开启DCaches 

    "orr    r0, r0, #0x1000\n"          // ...1 .... .... .... 开启ICaches 

    "orr    r0, r0, #0x0001\n"          // .... .... .... ...1 使能MMU 

    

    "mcr    p15, 0, r0, c1, c0, 0\n"    // 将修改的值写入控制寄存器 

    : // 无输出 

    : "r" (ttb) );

}

====================================================================

leds.c源码:

// leds.c: 循环点亮4个LED

// 属于第二部分程序,此时MMU已开启,使用虚拟地址

  

#define GPFCON      (*(volatile unsigned long *)0xA0000050)     // 物理地址0x56000050

#define GPFDAT      (*(volatile unsigned long *)0xA0000054)     // 物理地址0x56000054

#define GPF4_out (1<<(4*2))

#define GPF5_out (1<<(5*2))

#define GPF6_out (1<<(6*2))

// wait函数加上“static inline”是有原因的,

// 这样可以使得编译leds.c时,wait嵌入main中,编译结果中只有main一个函数。

// 于是在连接时,main函数的地址就是由连接文件指定的运行时装载地址。

// 而连接文件mmu.lds中,指定了leds.o的运行时装载地址为0xB4004000,

// 这样,head.S中的“ldr pc, =0xB4004000”就是跳去执行main函数。

 

static inline void wait(unsigned long dly)

{

    for(; dly > 0; dly--);

}

int main(void)

{

unsigned long i = 0;

GPFCON = GPF4_out|GPF5_out|GPF6_out; // 将LED1,2,4对应的GPF4/5/6三个引脚设为输出

while(1){

wait(30000);

GPFDAT = (~(i<<4)); // 根据i的值,点亮LED1,2,4

if(++i == 8)

i = 0;

}

return 0;

}

====================================================================

Makefile文件;

objs := head.o init.o leds.o

mmu.bin : $(objs)

    arm-linux-ld -Tmmu.lds -o mmu_elf $^

    arm-linux-objcopy -O binary -S mmu_elf $@

    arm-linux-objdump -D -m arm mmu_elf > mmu.dis

    

%.o:%.c

    arm-linux-gcc -Wall -O2 -c -o $@ $<

%.o:%.S

    arm-linux-gcc -Wall -O2 -c -o $@ $<

clean:

    rm -f mmu.bin mmu_elf mmu.dis *.o        

    

===================================================================

mmu.lds文件:

SECTIONS { 

  firtst         0x00000000 : { head.o init.o }          //第一段链接地址为0

  second    0xB0004000 : AT(2048) { leds.o }     //第二段存放地址为2048,链接地址为虚拟地址0xB0004000 

 

===============================================================


关键字:JZ2440  裸板  MMU操作 引用地址:JZ2440裸板之MMU操作

上一篇:100万遥控器?你不知泰捷电视机顶盒坚持15年了!
下一篇:JZ2440裸板之SDRAM启动分析

推荐阅读

 现代社会的高速运转离不开稳定、高效的物流系统,无论是人们出行还是货物流通等,均是如此。以航空业为例,国际航空运输协会最近发布的报告显示,全球航空旅客在2017年超过40亿人次。每一位旅客托运的行李都要依靠机场物流系统准确地配送,一旦这一系统出现故障,对于整个机场的秩序可谓影响巨大。 作为全球分布式供电方案的国际领先企业,威琅电气研发...
  近日,记者从市发改委获悉,全省最大的电动汽车充电站——赣州杉杉奥特莱斯充电站正式投入运行。至今,该充电站累计为电动汽车提供充电服务700余次,充电量达到15500余千瓦时。   据了解,该电动汽车充电站总投资500万元,配备充电桩150个,可同时为150台电动汽车提供充电服务。   此外,该项目同步搭建了赣州首个新能源汽车充电运营监控平台...
十三届全国人大常委会第二十二次会议于10月13日至17日在北京举行。据悉,本次常委会会议继续审议的法律案包括出口管制法草案三次审议稿等。新法律预计将覆盖核、生物、化学、导弹以及军品等物项的出口管制。随着美国政府加大对华为等中国企业的管制,这一出口管制法或许意味着中国将根据新法律拟定禁运企业名单,禁止向特定企业出口。日经中文版指出,这相...
日本电产的驱动马达系统“E-Axle”200kW机型被采用于吉利汽车高端电动汽车品牌“Zeekr”的首款车型中  中国的知名造车企业——吉利控股已决定在其高端品牌“Zeekr”(极氪)所发布的新款电动汽车“ZEEKR 001”中采用日本电产(以下简称“本公司”)的驱动马达系统“E-Axle”的200kW机型“Ni200Ex”。 “ZEEKR 001”是一款基于吉利控股-极氪智能科技 ...

史海拾趣

问答坊 | AI 解惑

ProFiBus现场总线在空调参数测试系统上的应用

  在分析 ProFiBus现场总线的基础上,设计实现了ProFiBus现场总线在空调参数测试系统上的应用…

查看全部问答∨

汽车安全与维修~~有了问题,到这里来找找答案吧!

1. 汽车气囊注意事项 >> https://bbs.eeworld.com.cn/thread-715-1-51.html 2. 汽车转速传感器的维修 >>https://bbs.eeworld.com.cn/thread-455-1-51.html 3. 解析奥迪防盗器7位密码的秘密>>https://bbs.eeworld.com.cn/thread-432-1-50 ...…

查看全部问答∨

开关电源中的电感

饱和电感是一种磁滞回线矩形比高,起始磁导率高,矫顽力小,具有明显磁饱和点的电感,在电子电路中常被当作可控延时开关元件来使用。由于其独特的物理特性,使之在高频开关电源的开关噪声抑制,大电流输出辅路稳压,移相全桥变换器,谐振变换器及逆 ...…

查看全部问答∨

求教:设备意外删除后收不到IRP_MN_REMOVAL_DEVICE?

为什么SURPRISE_REMOVE后没有REMOVE_DEVICE 小弟写的一个USB驱动程序在安装完成之后,插入设备,设备正常启动,然后直接拔出设备,有时候会出现收不到IRP_MN_REMOVAL_DEVICE的现象。 在log中,IRP序列为: 1)IRP_MN_QUERY_DEVICE_RELATION 连续 ...…

查看全部问答∨

LM3S9B92烧写不成功及FLASH烧写次数限制

请问9b92 C1版本的FLASH是不是有烧写限制?是多少次?我在网上看到一些说是的100次左右,这说法是否正确? 同时能否解释下下面的问题?谢谢~~~ 我下载时提示“Could not power up debug port: Control/Status register reads 000000F0” 用JLINK ...…

查看全部问答∨

430也能玩嵌入式:Contiki内核在IAR+MSP430下移植(八)

四、其他地方(1)loader-arch.hcpu/msp430/loader-arch.c文件中的#include "loader/loader-arch.h"改成#include "loader/elfloader-arch.h"。(通过逻辑判断)(2)FSSEL_SMCLKcontiki-2.5/cpu/msp430/rom.c文件中的FCTL2 = FWKEY | FSSEL_SMCLK ...…

查看全部问答∨

高湿度100%结露环境下,哪个品牌的CO2传感器比较适用?

求大侠推荐一款CO2传感器,可以应用于高湿度环境的,需要是进口的。…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved