汇编bringup LED

 
在STM32上,.s就是汇编,cortex A一般不会提供汇编,必须自己写汇编文件,对于A系列,初始化ram,没办法用c初始化,必须先初始化一些外设,这些外设必须用汇编初始化,但是用到的汇编不多,一开始初始化一些重要的外设,紧接着初始化DDR,DDR初始化完成之后,SP设置好就可以运行C语言了。
Cortex A汇编作用:
1、初始化一些SOC外设
2、初始化DDR,此处DDR不需要汇编会初始化,IMX内部的96k ROM存放了自己编写的启动代码,这些启动代码可以读取DDR配置信息,并且完成DDR的初始化
3、设置SP指针,一般指向DDR,cortex A系列一般不会指向内部ram,ram比较小,所以指向DDR,sp指针设置好C语言运行环境
 
i.MX6ULL芯片的GPIO被分成5组,并且每组GPIO的数量不尽相同,GPIO的控制分为两部分控制,分别如下:
IOMUX由其左侧的IOMUXC控制(C表示Controler),IOMUXC提供寄存器给用户进行配置, 它又分成MUX Mode(IO模式控制)以及Pad Settings(Pad配置)两个部分:
  • MUX Mode配置
MUX Mode就是用来配置引脚的复用功能,按上面的例子,即是具体是用于网络外设ENET的数据接收, 还是用于PWM外设的输出引脚,当然,也可以配置成普通的IO口,仅用于控制输出高低电平。
  • Pad Settings配置
Pad Settings用于配置引脚的属性,例如驱动能力,是否使用上下拉电阻, 是否使用保持器,是否使用开漏模式以及使用施密特模式还是CMOS模式等。 关于属性的介绍会在后面给出,在学习各种外设时,也将会接触到这些属性在不同场合下的应用。
在IOMUXC外设中关于MUX Mode和Pad Settings寄存器命名格式如下。
IOMUXC控制类型
寄存器名称
MUX Mode
IOMUXC_SW_MUX_CTL_PAD_XXXX
Pad Settings
IOMUXC_SW_PAD_CTL_PAD_XXXX
 

原理图分析:

0
从上图可以看出,LED0 接到了 GPIO_3 上,GPIO_3 就是 GPIO1_IO03,当 GPIO1_IO03输出低电平(0)的时候发光二极管 LED0 就会导通点亮,当 GPIO1_IO03 输出高电平(1)的时候发光二极管 LED0 不会导通,因此 LED0 也就不会点亮。所以 LED0 的亮灭取决于 GPIO1_IO03的输出电平,输出 0 就亮,输出 1 就灭。
总结LED初始化流程大致可分为以下三步:
  1. 开启GPIO时钟。
  2. 设置引脚的复用功能以及引脚属性。
  3. 设置引脚方向以及输出电平。
 
总体汇编代码如下:
.global _start  /* 全局标号 */

/*
 * 描述:       _start函数,程序从此函数开始执行此函数完成时钟使能、
 *                GPIO初始化、最终控制GPIO输出低电平来点亮LED灯。
 */
_start:
        /* 例程代码 */
        /* 1、使能所有时钟 */
        ldr r0, =0X020C4068     /* CCGR0 */
        ldr r1, =0XFFFFFFFF
        str r1, [r0]

        ldr r0, =0X020C406C     /* CCGR1 */
        str r1, [r0]

        ldr r0, =0X020C4070     /* CCGR2 */
        str r1, [r0]

        ldr r0, =0X020C4074     /* CCGR3 */
        str r1, [r0]

        ldr r0, =0X020C4078     /* CCGR4 */
        str r1, [r0]

        ldr r0, =0X020C407C     /* CCGR5 */
        str r1, [r0]

        ldr r0, =0X020C4080     /* CCGR6 */
        str r1, [r0]


        /* 2、设置GPIO1_IO03复用为GPIO1_IO03 */
        ldr r0, =0X020E0068     /* 将寄存器SW_MUX_GPIO1_IO03_BASE加载到r0中 */
        ldr r1, =0X5            /* 设置寄存器SW_MUX_GPIO1_IO03_BASE的MUX_MODE为5 */
        str r1,[r0]

        /* 3、配置GPIO1_IO03的IO属性
         *bit 16:0 HYS关闭
         *bit [15:14]: 00 默认下拉
     *bit [13]: 0 kepper功能
     *bit [12]: 1 pull/keeper使能
     *bit [11]: 0 关闭开路输出
     *bit [7:6]: 10 速度100Mhz
     *bit [5:3]: 110 R0/6驱动能力
     *bit [0]: 0 低转换率
     */
    ldr r0, =0X020E02F4 /*寄存器SW_PAD_GPIO1_IO03_BASE */
    ldr r1, =0X10B0
    str r1,[r0]

        /* 4、设置GPIO1_IO03为输出 */
    ldr r0, =0X0209C004 /*寄存器GPIO1_GDIR */
    ldr r1, =0X0000008
    str r1,[r0]

        /* 5、打开LED0
         * 设置GPIO1_IO03输出低电平
         */
        ldr r0, =0X0209C000     /*寄存器GPIO1_DR */
   ldr r1, =0
   str r1,[r0]

/*
 * 描述:       loop死循环
 */
loop:
        b loop
 

代码编译:

  1. 使用arm-linux-gnueabihf-gcc将.c .s文件变成.o文件
  2. 将所有的.o文件链接为elf格式的可执行文件,链接就是将所有的.o文件链接在一起,并且链接到指定的地方
  3. 将elf文件转成bin文件便于烧录
  4. 将elf文件反汇编,进行查看学习
arm-linux-gnueabihf-gcc -g -c led.s -o led.o
arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
arm-linux-gnueabihf-objdump -D led.elf > led.dis
链接的时候要指定链接起始地址 ,链接起始地址就是代码运行的起始地址
对于imx6ull来说,链接起始地址应该指向RAM地址。RAM分为内部RAM和外部RAM,也就是DDR,imx6ull内部RAM地址为0x900000-0x91ffff,也可以放在外部DDR中,对于alpha512字节开发板而言,DDR范围就是0x80000000-0x9fffffff。要使用DDR,那么必须初始化DDR,对于IMX来说bin文件不能直接运行,需要添加一个头部,这个头部信息包含了DDR的初始化参数,IMX系列SOC内部boot rom会从SD卡,EMMC等外置存储中读取头部信息,然后初始化DDR,并且将bin文件拷贝到链接地址处。
 

烧写bin文件:

imx6ull支持SD卡,EMMC、NAND、nor、spi flash等等启动。裸机例程选择烧写到sd卡中,ddr起始地址为0x87800000。
在ubuntu下向SD卡烧写裸机bin文件。烧写不是将bin文件拷贝到SD卡中,而是将bin文件烧写到SD卡绝对路径,需要借助imxdownload工具。imxdownload会向led.bin添加一个头部,这个头部信息会包含DDR的初始化参数,IMX系列SOC内部bootrom会从SD卡,EMMC等外部设备中读取头部信息,然后初始化DDR,并将bin文件拷贝到指定的地方。生成新的load.imx文件,这个load.imx文件就是最终烧写到SD卡里面去的。
Bin的运行地址一定要和链接起始地址一致。
 

反编译文件解析:

led.elf:     file format elf32-littlearm    // 表明这是由led.elf文件反汇编得到的dis文件


Disassembly of section .text:    // 说明反汇编文件是text格式

87800000 <_start>:
87800000:       e59f0068        ldr     r0, [pc, #104]  ; 87800070 <loop+0x4>
// 指令地址      指令机器码      指令机器码反汇编到的指令
 
posted @ 2024-03-16 21:36  lethe1203  阅读(4)  评论(0编辑  收藏  举报