ARM学习笔记--day10

1.理解ARM启动原理
    除了通用原理还有各个厂商的独特的启动方式
    ARM里边的程序永远冲0地址开始运行,这个内存0地址是ARM的0~4G的内存地址空间的0地址
    ARM是32位最大寻址能力就是4个G,就决定了内存地址空间是4个G,这个空间是CPU的访问能力,CPU从0地址取指译码执行,储存器(内存DRAM)是实际上地址范围是0x20008000~40000000是512M的大小,指令的执行从寻址空间的0地址开始执行与实际内存没有关系,nandflash没有地址线,只能通过8个IO管脚来读取,但是一开机不能直接运行nandflash中的程序,一开机只能从内存中开始运行,然后再读出nandflash中的东西到内存,CPU再运行。0地址处存储着内置的ROM(几十K),IROM中固化好了一部分代码,是只读的,所以起始代码是在IROM中开始执行;不是210的处理器,起始代码不一定是在0地址中开始执行
    其他ARM可以在0地址就可以访问norflash或者直接访问DRAM中的代码
    IROM运行后怎么跑到Nandflash/USB/SD卡启动的?
        在datasheet中有描述启动的过程
        a.关看门狗(超时重启,在超时前重置看门狗(喂狗),这个的作用就是防止死锁或者跑飞了,因为如果出现死锁或者跑飞了,没办法喂狗,就会重启,这样就避免了程序跑飞或者死锁)
        b.I cache 初始化,是由协处理器来初始化指令cache,cache可以提高效率
        c.判断唤醒的原因,是休眠状态下唤醒(回复休眠前的状态)还是关机状态下唤醒
        d.栈以及变量的初始化
        e.设置时钟初始化相关的参数,设置完之后,各个控制器的主频就可以动了
        f.OM Pin,判断一组管脚的高低电平,这组管脚的值不同就意味着从不同的存储器取程序,修改OM Pin就可以决定从哪个存储器来取程序
        g.是否支持校验,不支持校验,就从一种存储设备开始执行第二段代码
    第二段程序运行:
        根据OM Pin决定的启动的存储器,来执行其中的代码,我选的OM Pin是nandflash上启动第二段代码
        OM pin是根据拨码开关来决定的
2.启动代码基本步骤
    a.硬件满足条件已经哪些硬件必须初始化
        ①时钟的初始化,处理器内部,所有的控制器都需要时钟
            时钟如果不初始化,处理器有默认的时钟频率,这时候时钟频率特别低,告诉器件无法使用,所以这里要做的就是提高频率
            传递时每秒跳变的速率,输入时外部晶振,经过时钟控制器,输出给处理器或者其他器件,控制器的作用就是保证工作频率是想要的值
            锁相环(PLL):作用就是可以升频
                相关寄存器:APLL_CON0,APLL的控制寄存器,配置这个寄存器,来达到升频的目的
                bit31,ENABLE位:使能位
                bit25~16,MDIV
                bit13~8,PDIV
                bit2~0,SDIV
            计算公式:FOUT = MDIV X FIN / (PDIV × 2SDIV-1),这里边FOUT是已知的,是我们想要的值,FIN是输入值,这里边随意带入值,算出一组MDIV,PDIV,SDIV的值分别设定到寄存器中
            
            多路选择器(MUX):有0,1两路与多路选择器连接,输出是一路管脚,选择0,1中额一路通过
                CLK_SRC0:多路选择器的寄存器
                第0位就是APLL锁相环后边的多路选择器,然后根据管脚的接通到0还是1上,如果是1上,则把CLK_SRC0的第0位写1就可以了
            分频器(DIV):是减低频率的,例如输入时1G频率,采用8路分频的话,输出就变成128M
                CLK_DIV0:分频寄存器
                bit0~2,APLL_RATIO:是收到多路选择器的输出结果后,进行分频
                计算公式:ARMCLK = MOUT_MSYS / (APLL_RATIO + 1),MOUT_MSYS是输入端的名字,如果想要1分频,就将APLL_RATIO赋值为0就可以了
        ②DRAM的初始化,处理器的内存
    b.软件环境,初始化保证程序运行环境没有问题
        ①栈初始化,mov sp,#xxx,ARM中栈指针有6种sp指针,修改sp指针需要先切换模式再对sp赋值
        ②bss段的清空,以上两点都是C语言需要的,bss段如果不清0,会导致,未初始化的全局变量是一个随机值,这个时候就可能引发问题,所以必须清0
    C语言内存:BSS段(未初始化与初始化为0的全局变量,编译器知道BSS段在内存中的地址,如果想知道BSS段的起始/结束地址,需要链接脚本),代码段,堆栈
3.链接脚本(链接脚本是在gnu中的,通常gcc中会有默认的连接脚本,但是在嵌入式开发中根据不同芯片需要配置连接脚本)
    编译的过程:预处理,汇编,编译,链接
    链接(把.o文件合并成一个可执行程序,这个过程叫做链接)
    .o目标文件中已经包含代码段,数据段,BSS段,但是不同的.o文件可能存在依赖关系,并且.o文件没有具体的地址,给代码地址是在链接的时候给出的
    编译器默认会将摆在前面先连接到内存,就是在内存的开头,把不同的.o代码段,数据段,BSS段分配到内存中
    作用:就是给代码的组成各个部分链接到内存中,给链接器一个配置,让链接器去按照我们配置去链接
    链接脚本写法:
        main.lds
        ENTRY(start)    //关键字ENTRY():就是指定程序入口,start就是入口函数
        SECTIONS        //段(包含代码段,数据段,BSS段),在这里边确定各个段的地址
        {
            . = 0x20004000;        //这种方法对各个段赋值,这句话的意思就是代码段就是从0x20004000开始存储
            .text :{    //代码段
                start.o(.text)    //先链接start.o
                *.o(.text);        //写*,就会按照字母表来决定链接顺序
            }
            加关键字空出一段内存,什么都不加就是代码段与数据段与BSS段是连续分配的内存
            .data :{    //数据段
                *.o(.data);
            }
            bss_start = .;        //bss_start这个就是常量,这个值在汇编中可以直接使用,在C语言中,则需要先声明外部变量,然后取地址值赋值给指针再使用
            .bss:{        //BSS段
                *.o(.bss);
            }
            bss_end = .;        //bss_end这个也是常量,根据bss_end与bss_start就可以知道这个bss段的起始结束都在哪里
        }
很多处理器0地址上没有东西
start.s要初始化栈,bss段,时钟,DROM

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值