目录
启动模式(8引脚设置启动模式)
对应原理图
boot ROM程序
空偏移
映像向量表(Image vector table,IVT)
IVT结构体
Boot data
DCD(外设寄存器配置信息,初始化关键外设)
NXP官方I.MX 6ULL开发SDK
三大模式:
熔丝:烧录一次,发布产品。
外部:USB、串口等。
内部:SD卡、EMMC、NAND。
设置方法:BOOT_MODE0、BOOT_MODE1。
内部介质设置方法:BT_CFG1[4:7]
接口编号设置方法:BT_CFG2[3]
介质属性设置方法:如SD、EMMC,位宽(BT_CFG2[5])
选择内部启动方式,启动boot ROM程序
初始化时钟、外部DDR3
从外部存储介质加载代码
镜像空偏移,由芯片厂商设定。
Image vector table(IVT),关键数据位置。
Boot data,启动数据。镜像加载地址、大小。
Device configuration data(DCD),关键外设的寄存器配置信息(时钟、DDR3相关)。
bin文件,真正程序文件。
镜像不是从存储介质头部开始存储的,不同介质分别对应一段偏移地址。
映像向量表是ROM从提供程序映像的引导设备中读取的数据结构,该程序映像包含成功启动所需的数据组件。
IVT包含程序映像入口点、指向设备配置数据(DCD)的指针和ROM在引导过程中使用的其他指针。
Boot data记录“镜像”在内存中的加载地址和大小。
复位后,芯片使用系统中所有外设的默认寄存器值。但是,这些默认值对于实现最佳系统性能来说并不理想,深圳有些外设在使用之前必须进行配置。DCD是包含在程序镜像中的配置信息,ROM对其解释以配置芯片上的各种外设。
例如,EIM默认配置允许核心在复位后立即连接到NOR闪存设备。这允许芯片与任何NOR闪存设备接口,但缺点是性能慢。此外,一些组件(如DDR)在准备使用之前需要一些寄存器编程作为配置的一部分。DCD可用于将EIM寄存器和MMDC寄存器编程到最佳配置。
ROM根据IVT的信息可确定DCD的位置。
NXP官网 I.MX 6ULL SDK
下载SDK2.2_iMX6ULL_LINUX。下载完成后名字为:SDK_2.2_MCIM6ULL_RFP_Linux.run
虚拟机通过共享文件夹得到。并运行。
./SDK_2.2_MCIM6ULL_RFP_Linux.run
运行完成,会在\opt\生成SDK_2.2_MCIM6ULL文件夹。
在\opt\SDK_2.2_MCIM6ULL\tools\imgutil\readme.txt附有说明文档。
1、复制.bin文件到imgutil\evkmcimx6ull文件下,并重命名为sdk20-app.bin。
2、在imgutil\evkmcimx6ull文件下,终端中运行mkimage.sh命令,获取可启动的镜像文件sdk20-app.imag。
如果镜像是用RAM链接文件构成的,使用“mkimage.sh ram”命令制作可启动镜像。
如果镜像是用Flash链接文件构成的,使用“mkimage.sh flash”命令制作可启动的XIP镜像。
如果镜像是用RAM链接文件构成的,并希望从MicroSD卡启动,使用“mkimage.sh sd”命令制作可启动镜像。
根据mkimage.sh和dcd.config文件,dcdgen.bin生成DCD表,imgutil.bin生成img可烧录镜像。
VSCode官网
下载deb_x64文件,存于虚拟机linux中。
安装:sudo dpkg -i xxx.deb
启动:code
使用特点:
无需新建项目,直接打开文件夹。
不同目录下的文件夹,可保存在工作区。
默认预览模式。不需要可在Setting中输入“preview”,取消勾选:Workbench > Editor:Enable Preview
推荐插件:
c/c++:函数跳转、自动补全。
Chinese:中文。
material theme:UI。
CodeSpell Checker:拼写检查。
rainbow-highlighter:变量彩虹高光。
shift+alt+z:变量彩虹高光。
shift+alt+a:取消变量彩虹高光。
ARM:汇编插件。
高效工作:
移动光标到行首:home
移动光标到行尾:end
跳转文档头部:ctrl+home
跳转文档尾部:ctrl+end
花括号跳转:ctrl+shift+\
文件跳转:ctrl+p
行跳转:ctrl+g
批量修改:F2
数量:五组GPIO(GPIO1~GPIO5),每组最多32个,共124个。
GPIO1_IO0~GPIO1_IO31
GPIO2_IO0~GPIO2_IO21
GPIO3_IO0~GPIO3_IO28
GPIO4_IO0~GPIO4_IO28
GPIO5_IO0~GPIO5_IO11
clock controller module(CCM模块)用于配置芯片的各种外设时钟。跟GPIO相关的时钟主要有CCM_CCGR(0~3)寄存器。
//经典汇编led.s
.global _start
_start:
@使能GPIO时钟
ldr r0,=0x20c406c @将0x20c406c加载到寄存器r0
ldr r1,=0xffffffff @将0xffffffff加载到寄存器r1
str r1,[r0] @将寄存器r1的值存储到r0寄存器指向的地址
@设置引脚复用为GPIO
ldr r0,=0x20e006c
ldr r1,=5
str r1,[r0]
@设置引脚属性(上下拉、速率、驱动能力)
ldr r0,=0x20e02f8
ldr r1,=0x10b0
str r1,[r0]
@控制GPIO引脚输出高低电平
ldr r0,=0x209c004
ldr r1,=16
str r1,[r0]
ldr r0,=0x209c000
ldr r1,=0
str r1,[r0]
1、下载裸机的gcc编译器:sudo apt-get install gcc-arm-none-eabi
2、编译汇编文件为可重定位文件led.o:arm-none-eabi-gcc -c led.s -o led.o
3、把重定位文件链接起来,得到可执行程序(elf文件):arm-none-eabi-ld -Ttext 0x80000000 led.o -o led.elf
4、把elf文件去掉冗余的段和elf头,得到纯净的bin文件:arm-none-eabi-objcopy -O binary led.elf led.bin
5、给bin文件添加6ull特殊的头部信息(IVT + boot data + DCD),并烧录到sd卡:./mkimage.sh xxx.bin
引入SDK头文件目的:解决寄存器地址难查、难设置。
devices/MCIMX6Y2/MCIMX6Y2.h:记录外设寄存器及其相关操作。
devices/MCIMX6Y2/drivers/fsl_iomuxc.h:记录引脚复用及其相关操作。
devices/MCIMX6Y2/MCIMX6Y2.h:
注释:
#include "core_ca7.h"
#include "system_MCIMX6Y2.h"
添加:
#define __O volatile
#define __IO volatile
#define __I volatile const
#define uint32_t unsigned int
#define uint16_t unsigned short
#define uint8_t unsigned char
bin文件组成(段是程序的基本组成元素):
.text段:代码文本
.rodata段:只读变量,如const修饰的变量
.data段:非零的全局变量、静态变量。
.bss段:值为0的全局变量、静态变量。
.comment段:存放注释。
链接脚本引入
目的:指定链接地址、起始代码在text段的位置,其他段的位置。
SECTIONS{
. = xxx //链接起始地址
.段名
{
xxx
*(.段名)
}
...
}
led.s
.global _start
_start:
@设置栈地址为64M,0x80000000~0xA0000000,512MB
ldr sp,=0x84000000
@跳转main函数
b main
led.c
#include "../include/MCIMX6Y2.h"
#include "../include/fsl_iomuxc.h"
/* 简单延时函数 */
void delay(uint32_t count)
{
volatile uint32_t i=0;
for(i=0; iCCGR1 = 0Xffffffff;
/* 设置 红灯引脚的复用以及属性 */
IOMUXC_SetPinMux(IOMUXC_GPIO1_IO04, 0);
IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO04, 0x10b0);
/* 设置 GPIO1_04为输出模式 */
GPIO1->GDIR |= (1<<4);
/* 设置 GPIO1_04输出电平为高电平 */
GPIO1->DR |= (1<<4);
while(1)
{
GPIO1->DR &= ~(1<<4); //红灯亮
delay(0xfffff);
GPIO1->DR |= 1<<4; //红灯灭
delay(0xfffff);
}
return 0;
}
script.lds
SECTIONS{
.=0x80000000;
.text ALIGN(4):
{
build/start.o
*(.text)
}
.rodata ALIGN(4):
{
*(.rodata)
}
.data ALIGN(4):
{
*(.data)
}
__bss_start=.;
.bss ALIGN(4):
{
*(.bss)
*(COMMON)
}
__bss_end=.;
}
Makefile
ifeq ($(ARCH),x86)
CC=gcc
else
CC=arm-none-eabi-gcc
LD=arm-none-eabi-ld
OBJCOPY=arm-none-eabi-objcopy
endif
TARGET=led
BUILD_DIR=build
SRC_DIR=sources
INC_DIR=include
CFLAGS=$(patsubst %,-I %,$(INC_DIR))
INCLUDES=$(foreach dir,$(INC_DIR),$(wildcard $(dir)/*.h))
SOURCE_c=$(foreach dir,$(SRC_DIR),$(wildcard $(dir)/*.c))
SOURCE_s=$(foreach dir,$(SRC_DIR),$(wildcard $(dir)/*.s))
OBJS=$(patsubst %.c,$(BUILD_DIR)/%.o,$(notdir $(SOURCE_c)))
OBJS+=$(patsubst %.s,$(BUILD_DIR)/%.o,$(notdir $(SOURCE_s)))
VPATH=$(SRC_DIR)
$(BUILD_DIR)/$(TARGET).bin:$(OBJS)
$(LD) -Tscript.lds -o $(BUILD_DIR)/$(TARGET).elf $^
$(OBJCOPY) -O binary $(BUILD_DIR)/$(TARGET).elf $@
$(BUILD_DIR)/%.o:%.c $(INCLUDE) | create_build
$(CC) -c $< -o $@ $(CFLAGS)
$(BUILD_DIR)/%.o:%.s $(INCLUDE) | create_build
$(CC) -c $< -o $@ $(CFLAGS)
.PHONY:clean create_build burn
clean:
rm -r $(BUILD_DIR)
create_build:
mkdir -p $(BUILD_DIR)
burn:
cp $(BUILD_DIR)/$(TARGET).bin /home/couvrir/make_testfile1
cd /home/couvrir/make_testfile1 && ./mkimage.sh $(TARGET).bin