开发板:IMX6ULL Mini
配置启动文件+汇编点亮LED
一、启动流程
cpu上电之后,pc指向0x00,指向异常向量表中的Reset指令,之后跳转到Reset指令对应的异常服务函数中。此时处于SVC模式,最终需要切换到system模式,所以在_reset_handler异常服务函数中切换模式并设置要切换的模式的栈。
_start: ldr pc, =_reset_handler ldr pc, =_undefine_handler ldr pc, =_svc_handler ldr pc, =_prefetch_aboart_handler ldr pc, =_data_abort_handler ldr pc, =_reserved_handler ldr pc, =_irq_handler ldr pc, =_fiq_handler _fiq_handler: ldr pc, =_fiq_handler _irq_handler: ldr pc, =_irq_handler _reserved_handler: ldr pc, =_reserved_handler _data_abort_handler: ldr pc, =_data_abort_handler _prefetch_aboart_handler: ldr pc, =_prefetch_aboart_handler _svc_handler: ldr pc, =_svc_handler _undefine_handler: ldr pc, =_undefine_handler _reset_handler:切换模式的核心是CPSR寄存器的M[4:0],使用CPSR的低5为来编码当前处理器模式。
对于点灯流程来说需要在_reset_handler中线切换到IRQ模式,需要给低5清0之后写入0x12,使用MRS和MSR两个指令来读取CPSR到通用寄存器进行修改,之后写回CPSR寄存器中。然后给IRQ模式分配栈,在异常产生时,cpu切换到该异常模式时,sp就是该模式的栈指针了。之后再切换到system模式,同样的修改CPSR寄存器和分配栈。
_reset_handler: // 切换工作模式:IRQ mrs r0, cpsr bic r0, r0, #0x1F orr r0, r0, #0x12 msr cpsr, r0 // 设置IRQ模式下的栈 ldr sp, =0x86000000 // 切换工作模式:System mrs r0, cpsr bic r0, r0, #0x1F orr r0, r0, #0x1F msr cpsr, r0 // 设置System模式下的栈 ldr sp, =0x84000000这样就完成了LED点灯的启动程序,但是还不够完善。
二、GPIO需要配置的寄存器
1、CCM:使能GPIO时钟
CCM_CCGR(Clock Controller Module Clock Gate Register):控制各组GPIO时钟的开关。
以CCM_CCGR0寄存器为例:地址为0x020C4068,打开所有时钟(0xFFFFFFFF)
寄存器地址设置为:
CCM_CCGR0:0x020C4068
CCM_CCGR1:0x020C406C
CCM_CCGR2:0x020C4070
CCM_CCGR3:0x020C4074
CCM_CCGR4:0x020C4078
CCM_CCGR5:0x020C407C
CCM_CCGR6:0x020C4080
2、IOMUXC:配置引脚复用功能与电气属性
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03(引脚复用控制器):
地址为0x020E0068,配置为GPIO功能。也可以配置为其他具体功能(GPIO、UART、I2C)
可以通过MUX_MODE字段对应的ALT模式,也就是ALT5。
IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03(配置引脚电气属性):
地址为0x020E02F4,配置为低压摆率、中速、关闭开漏输出、关闭迟滞比较器。
给地址写入0x10B0即可。
3、GPIO模块配置
主要配置:
1.GPIO1_DR(GPIO数据寄存器):
地址为0x0209C000,用来控制输出引脚的电平,将对应的bit写1为输出高电平,写0为输出低电平。
2.GPIO1_GDIR(方向寄存器):
地址为0x0209C004,主要是配置GPIO输入输出方向,将对应 bit 写1设为输出,写0设为输入。
LED点灯汇编程序
.global _start _start: ldr pc, =_reset_handler ldr pc, =_undefine_handler ldr pc, =_svc_handler ldr pc, =_prefetch_aboart_handler ldr pc, =_data_abort_handler ldr pc, =_reserved_handler ldr pc, =_irq_handler ldr pc, =_fiq_handler _fiq_handler: ldr pc, =_fiq_handler _irq_handler: ldr pc, =_irq_handler _reserved_handler: ldr pc, =_reserved_handler _data_abort_handler: ldr pc, =_data_abort_handler _prefetch_aboart_handler: ldr pc, =_prefetch_aboart_handler _svc_handler: ldr pc, =_svc_handler _undefine_handler: ldr pc, =_undefine_handler _reset_handler: // 切换工作模式:IRQ bic r0, r0, #0x1F orr r0, r0, #0x12 msr cpsr, r0 // 设置IRQ模式下的栈 ldr sp, =0x86000000 // 切换工作模式:System mrs r0, cpsr bic r0, r0, #0x1F orr r0, r0, #0x1F msr cpsr, r0 // 设置System模式下的栈 ldr sp, =0x84000000 // 使能所有外设时钟 bl _enable_clocks // LED初始化 bl _led_init // LED亮 bl _led_on b finished _enable_clocks: // CCGR0 ldr r0, =0x020C4068 ldr r1, =0xFFFFFFFF str r1, [r0] // CCGR1 ldr r0, =0x020C406C ldr r1, =0xFFFFFFFF str r1, [r0] // CCGR2 ldr r0, =0x020C4070 ldr r1, =0xFFFFFFFF str r1, [r0] // CCGR3 ldr r0, =0x020C4074 ldr r1, =0xFFFFFFFF str r1, [r0] // CCGR4 ldr r0, =0x020C4078 ldr r1, =0xFFFFFFFF str r1, [r0] // CCGR5 ldr r0, =0x020C407C ldr r1, =0xFFFFFFFF str r1, [r0] // CCGR6 ldr r0, =0x020C4080 ldr r1, =0xFFFFFFFF str r1, [r0] bx lr _led_init: // 配置GPIO1_IO03引脚复用功能:GPIO1_IO03 ldr r0, =0x020E0068 mov r1, #0x05 str r1, [r0] // 配置引脚电气属性: 默认属性 ldr r0, =0x020E02F4 ldr r1, =0x10B0 str r1, [r0] // 配置引脚工作模式:输出模式 ldr r0, =0x0209C004 ldr r1, [r0] orr r1, r1, #(1 << 3) str r1, [r0] bx lr _led_on: // LED亮:向GPIO1_IO03写入低电平 ldr r0, =0x0209C000 ldr r1, [r0] bic r1, r1, #(1 << 3) str r1, [r0] bx lr finished: b finished