参考文档:1. imx6ull裸机(v1.2).pdf
从内核切换到外设的学习
1.开发板介绍
(1)IMX6ULL-Mini开发板是由正点原子提供的, 搭载NXP生产i.MX6ULL的SOC, 主打高性能、低功耗与紧凑体积
(2)整个开发板由核心板与底板组成,核心板通过双列直插方式与底板连接
(3) 核心板 六层板
CPU:NXP i.MX 6ULL Cortex-A7单核处理器,主频 528MHz(工业级) 或 800MHz(商业级)467, BGA封装
内存:512MB DDR3L RAM,支持高速数据存取。
存储:8GB eMMC,支持多种启动模式(SD卡、NAND、eMMC)
屏幕:4.3寸屏 800*480分辨率
(4)底板(看了LED模块)
红色led灯提供用户可控的的LED灯
蓝色led灯是电源指示灯
510欧姆限流电阻作用防止电流过大保护灯珠。
Cortex-A7 核心设计:ARM
i.MX6ULL SOC: NXP
IMX6ULL-Mini 开发板: 正点原子
2.开发工具下载
(1)安装Visual Studio Code
汇编高亮插件:Arm Assembly
(2)创建工程文件夹 D:\IMX6ULL\led_asm
(3)创建启动代码 start.S(注意大写S后缀,会进行预处理,后期用到一些宏)
3.编写启动代码
(1).global _start
rom: 0x8000 0000 size:512M
(2) cps指令:
CPS<effect> <iflags>{, #<mode>}
CPS #<mode>
示例: cpsid i (i f a)
cps #0x12
ldr sp, =0x820000000
cps #0x1F
ldr sp, =0x840000000
cpsie i
3.点亮LED灯
(1)查阅手册
参考文档:1. IMX6ULL_MINI_V2.2(Mini底板原理图).pdf
- IMX6ULL参考手册.pdf
(1)初始化
(1)复用功能配置
Chapter 32:IOMUX Controller (IOMUXC)
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03: 低四位(0101)
(2)电气特性
Chapter 32:IOMUX Controller (IOMUXC)
IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03
(3)GPIO方向寄存器
Chapter 28:General Purpose Input/Output (GPIO)
GPIOx_GDIR
(2)运行时开关灯
(1)GPIO数据寄存器
Chapter 28:General Purpose Input/Output (GPIO)
GPIOx_DR
(2)修改外设寄存器
LDR<c> <Rt>, \
LDR<c> <Rt>, \
LDR<c> <Rt>, \
LDR<c> <Rt>, <label>
LDR<c> <Rt>, PC, #-0
LDR<c> <Rt>, \
LDR<c> <Rt>, \
STR<c> <Rt>, \
STR<c> <Rt>, \
STR<c> <Rt>, \
STR<c> <Rt>, \
STR<c> <Rt>, \
STRB<c> <Rt>, \
STRB<c> <Rt>, \
STRB<c> <Rt>, \
ldr r0, =0x020C4068
ldr r1, =0xFFFFFFFF
str r1, r0
(3)编译器安装
(1)拷贝 gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz 到/usr/local/arm
(2)解压 sudo tar -xvf gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz
(3)删除 sudo rm gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz
(4)配置 回家目录, 修改环境变量配置文件 vi .bashrc
export PATH=$PATH:/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/
(5)重启虚拟机:reboot
(6)检查编译器版本:arm-linux-gnueabihf-gcc -v
(4)FileZilla Client工具:它是一个Windows系统下免费的ftp工具。(可选)
a.手动配置Ubuntu的ftp服务。
(1) 安装ftp服务: sudo apt-get install vsftpd
(2) 修改配置: VI 命令打开/etc/vsftpd.conf
找到local_enable=YES write_enable=YES 确保这两行之前没有 #,(line28/line31)
(3) 重启ftp服务, sudo /etc/init.d/vsftpd restart
(4) 查看ftp服务器工作状态: sudo /etc/init.d/vsftpd status; 绿灯正常
b.win下安装FileZilla Client
(1)IMX6ULL资料/软件/FileZilla_3.39.0_win64-setup_bundled.exe s双击。
(2)记得可以选择创建桌面快捷方式:Desktop icon
(5)上传代码(可选)
(1)文件->站点管理器->新站点->
主机(H):ens33IP:192.168.71.134
用户(U):linux
密码(W):1
点击连接
(2)右侧win本地站点,左侧Ubuntu远程站点,选择对应文件夹
右键点击上传文件夹->上传
(6)编译代码
(1)使用arm-linux-gnueabihf-gcc只汇编不链接
arm-linux-gnueabihf-gcc -c start.S -o start.o -g
(2)使用arm-linux-gnueabihf-ld链接代码到特定地址(得到可执行,可连接程序linux executable linkable file)
arm-linux-gnueabihf-ld -Ttext 0x87800000 start.o -o start.elf
(3)使用arm-linux-gnueabihf-objcopy 格式转换
arm-linux-gnueabihf-objcopy -O binary -S(去符号信息) -g(去调试信息) start.elf start.bin
(4)使用arm-linux-gnueabihf-objdump 反汇编(此处只是为了阅读代码,非必要步骤)
arm-linux-gnueabihf-objdump -D start.elf > start.dis
(7)led.bin拷贝到TFcard
(1)连接SD卡到Ubuntu
(1)可移动设备
(2)右下角图标
(2)查看/dev
ls /dev/sdb
(3)拷贝下载工具imxdownload到Ubuntu工程目录下
修改权限:chmod +777 imxdownload
(4)烧写程序到SD卡
./imxdownload start.bin /dev/sdb
注意烧写速率,如果上M的速度是不成功的,必须拔掉USB读卡器,重启Ubuntu
(8)测试
(1)启动方式选择SD卡
原理图:BOOt模块(USB启动 SD卡启动 板载EMMC启动 nandflash启动 ) -> 通过拨码卡关选择
(2)插入SD卡
查看开发板图找到 TFcard 插入SD卡
(3)开发板上电
保证开关弹起的状态下,插上电源适配器,按下旁边蓝色开关,查看蓝色电源灯
(4)观察红色Led灯
练习:修改汇编代码,添加延时函数完成led灯闪烁
(9)Makefile简化编译过程
(1)Makefile的三要素:目标:start.bin 依赖:start.S 规则:如何产生目标
start.bin : start.S
arm-linux-gnueabihf-gcc -c start.S -o start.o -g
arm-linux-gnueabihf-ld -Ttext 0x87800000 start.o -o start.elf
arm-linux-gnueabihf-objcopy -O binary -S -g start.elf start.bin
arm-linux-gnueabihf-objdump -D start.elf > start.dis
(2)伪目标 clean 不加依赖
rm start.o start.elf start.bin start.dis -f
(3)伪目标 load
./imxdownload start.bin /dev/sdb
(4)优化(存放变量)
COMPLITER = arm-linux-gnueabihf-
CC = $(COMPLITER)gcc
LD = $(COMPLITER)ld
OBJCOPY = $(COMPLITER)objcopy
OBJDUMP = $(COMPLITER)objdump
start.bin : start.S
$(CC) -c start.S -o start.o -g
$(LD) -Ttext 0x87800000 start.o -o start.elf
$(OBJCOPY) -O binary -S -g start.elf start.bin
$(OBJDUMP) -D start.elf > start.dis
clean:
rm start.o start.elf start.bin start.dis -f
load:
./imxdownload start.bin /dev/sdb
.s=====================================================================
.global _start
_start:
ldr pc, =_reset_handler
ldr pc, =_undef_handler
ldr pc, =_software_handler
ldr pc, =_prefect_handler
ldr pc, =_data_handler
nop
ldr pc, =_irq_handler
ldr pc, =_fiq_handler
_undef_handler:
b _undef_handler
_software_handler:
b _software_handler
_prefect_handler:
b _prefect_handler
_data_handler:
b _data_handler
_irq_handler:
b _irq_handler
_fiq_handler:
b _fiq_handler
_reset_handler:
cpsid i //关掉IRQ的中断开关
cpsid f //关掉FIQ的中断开关
cps #0x12 //切换到10010
ldr sp, =0x82000000 //定义栈顶指针
cps #0x1F //切换到11111
ldr sp, =0x84000000 //定义栈顶指针
cpsie i
b main
finish:
b finish
main====================================================
//复用寄存器
#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 (*((volatile unsigned int *)(0x020E0068)))
//电气寄存器
#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 (*((volatile unsigned int *)(0x020E02F4)))
//方向寄存器
#define GPIO1_GDIR (*((volatile unsigned int *)(0x0209C004)))
//输出寄存器
#define GPIO1_DR (*((volatile unsigned int *)(0x0209C000)))
void led_init(void)
{
//初始化复用
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = 0x5;
//初始化电气
IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 = 0x10B0;
//初始化方向
GPIO1_GDIR |= (1 << 3);
return;
}
void led_on(void)
{
GPIO1_DR &= ~(1 << 3);
}
void led_delay(unsigned int t)
{
while(t--);
}
void led_off(void)
{
GPIO1_DR |= (1 << 3);
}
void main(void)
{
led_init();
while(1)
{
led_on();
led_delay(0x3FFFF);
led_off();
led_delay(0x3FFFF);
}
}
======================================================================
- 在LED实验中,在对Soc引脚配置时都做了哪些工作?
首先对LED灯关联的引脚CPIO1_03进行初始化
初始化内容包括
1,将地址为0x020E 0068的SW---MUX---CTL(MUX控制寄存器)的后四位修改为0101
- 将地址为0x020E 02F4的SW---PAD---CTL(电气控制寄存器)后16位修改为10B0
3更改GPIO1_IO03的方向为输入,GP1O1_GDIR寄存器
地址为0x0209 C004,修改3位为1
开灯关灯,修改GPIO1_IO03的电平,寄存器GPIO1_DR地址为0x0209 C000 的第3位0低电平开,1高电平关
- 什么是编译器、连接器、格式转换器和反汇编器?
编译器
属于编译流程的编译阶段(核心阶段)。它实现将预处理后的高级语言源代码(如 C/C++)翻译成特定处理器架构的汇编代码.S文件。其作用是进行语法分析、语义检查、代码优化,并生成底层汇编指令,是连接人类可读代码与机器底层指令的桥梁。
连接器
属于编译流程的链接阶段。它实现将编译器生成的多个目标文件(.o)以及所需的库文件(如标准库)合并、定位并绑定成一个完整的可执行文件。其作用是解决模块间的符号引用(如函数调用、全局变量),分配最终的内存地址,确保程序各个部分能正确拼接并运行。
格式转换器(Format Converter)
通常属于编译流程的后处理阶段(有时也属于构建工具链的一部分)。它实现将连接器生成的通用可执行文件格式(如 ELF)转换为特定目标环境所需的格式(如纯二进制 .bin、Intel Hex 等)。其作用是去除文件头、调试信息等冗余数据,生成可以直接烧录到裸机硬件或特定引导程序中的镜像文件。
反汇编器(Disassembler)
属于编译流程的逆向分析阶段(并非构建流程的必经环节,而是调试与验证工具)。它实现将机器码(目标文件或可执行文件)反向翻译回汇编代码。其作用是在没有源代码的情况下,帮助开发者查看底层指令、分析程序逻辑、定位崩溃原因以及验证编译器生成的代码是否符合预期。
1. 预处理(汇编文件通常不需要,C文件需要)
arm-linux-gnueabihf-gcc -E led.s -o led.i
2. 编译(生成汇编)
arm-linux-gnueabihf-gcc -S led.i -o led.s
3. 汇编(生成目标文件)
arm-linux-gnueabihf-gcc -c led.s -o led.o
4. 链接(生成 ELF 可执行文件,裸机需要 -nostdlib 和链接脚本)
arm-linux-gnueabihf-ld -Ttext 0x87800000 -o led.elf led.o
注意:更完整的裸机链接通常需要指定链接脚本(.lds)
5. 格式转换(生成最终烧录的 .bin 文件)
arm-linux-gnueabihf-objcopy -O binary -S led.elf led.bin
3、arm汇编调用c语言函数以及c语言函数调用汇编编写的函数,函数参数和返回值如何处理?
当ARM汇编调用C语言函数时,C语言函数需要对函数进行外部声明,同时汇编需要对其进行import引用,同时将使用通用寄存器R0-依次向后的值作为函数的参数,返回值默认采用R00000进行接收。
当C语言使用汇编函数时,C语言需要对函数进行外部声明,同时汇编代码需要对函数进行exp0ort导出,C在使用汇编函数时应参考汇编函数的参数数量,传入对应的参数。参数将依次修改R0-的值,返回值默认修改R0
让 S0P 保持 8 字节对齐,核心就一句话:任何改变 SP 的操作,增减量都必须是 8 的倍数。