本章节接着上一章<IMX6ULL裸机开发学习1-汇编点亮led>进行升级改造代码。
编程环境搭建:
开发板:野火Imx6ull mini板
编程环境:Ubuntu18.04 + VScode
开始进入代码内容:
C语言需要运行起来,少不了汇编准备好运行的环境。
汇编代码start.S如下:
/*******************
*文件名: start.S
*作者 : 桂志威
*邮箱 : motion_gui@126.com
*日期 :2022 - 02 -13
*描述 :裸机实验测试2 C语言点亮led
********************/
.global _start @全局标号
/*****
*描述 : _start函数
*/
_start :
/*****
*1.配置CPU 进入SVC模式
*/
mrs r0, cpsr @拷贝CPSR状态寄存器到R0中
bic r0, r0, #0x1f @清楚CPU模式位BIT4-BIT0
orr r0, r0, #0x13 @配置BIT4-0为SVC模式
msr cpsr, r0 @将寄存器R0数据写回到CPSR中
/*****
*2.设置堆栈指针并跳转C语言main函数
*/
ldr sp, =0x80200000 @设置堆栈0x80200000->0x80000000 2M空间
b main @跳转到C语言main函数
有了上述代码,就能和stm32一样写代码了。
C代码部分来个头文件led.h,将CPU相关寄存器地址指针给定义出来:
/*******************
*文件名: led.h
*作者 : 桂志威
*邮箱 : motion_gui@126.com
*日期 :2022 - 02 -13
*描述 :led灯程序头文件,存放寄存器指针
********************/
#ifndef _H_LED_H
#define _H_LED_H
/**
* CCM时钟相关寄存器地址定义
*/
#define CCM_CCGR0 *((volatile unsigned int *)0x020c4068)
#define CCM_CCGR1 *((volatile unsigned int *)0x020c406C)
#define CCM_CCGR2 *((volatile unsigned int *)0x020c4070)
#define CCM_CCGR3 *((volatile unsigned int *)0x020c4074)
#define CCM_CCGR4 *((volatile unsigned int *)0x020c4078)
#define CCM_CCGR5 *((volatile unsigned int *)0x020c407C)
#define CCM_CCGR6 *((volatile unsigned int *)0x020c4080)
/**
* IOMUX复用相关寄存器地址定义
* IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址229_0014h
* IOMUXC_SNVS_SW_PAD_CTL_PAD_SNVS_TAMPER3 地址 229_0058h
*/
#define SW_MUX_GPIO5_IO3 *((volatile unsigned int *)0x02290014)
#define SW_PAD_GPIO5_IO3 *((volatile unsigned int *)0x02290058)
/**
* GPIO5相关寄存器地址定义
*
*/
#define GPIO5_DR *((volatile unsigned int *)0x020AC000)
#define GPIO5_GDIR *((volatile unsigned int *)0x020AC004)
/**
* GPIO5_IO3相关操作宏
* 开漏输出控制
*/
#define LED_ON() (GPIO5_DR &= ~(1<<3))
#define LED_OFF() (GPIO5_DR |= (1<<3))
#endif // !_H_LED_H
可执行代码片段:
/*******************
*文件名: led.c
*作者 : 桂志威
*邮箱 : motion_gui@126.com
*日期 :2022 - 02 -13
*描述 :led灯程序可执行程序
********************/
#include "led.h"
/**
* 使能所有外设控制时钟
*
*/
void clk_enable(void)
{
CCM_CCGR0 = 0xffffffff ;
CCM_CCGR1 = 0xffffffff ;
CCM_CCGR2 = 0xffffffff ;
CCM_CCGR3 = 0xffffffff ;
CCM_CCGR4 = 0xffffffff ;
CCM_CCGR5 = 0xffffffff ;
CCM_CCGR6 = 0xffffffff ;
}
/**
* Led初始化对应的GPIO
*/
void led_Init(void)
{
/*****
*1.GPIO5_IO03 复用功能配置GPIO
*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址229_0014h
*/
SW_MUX_GPIO5_IO3 = 0x5; //AL5
/*****
*2.GPIO5_IO03 配置IO属性功能
*IOMUXC_SNVS_SW_PAD_CTL_PAD_SNVS_TAMPER3 地址 229_0058h
*BIT0 压摆率 0-慢速
*BIT5-3 驱动能力R0/6 -110
*BIT7-6 速度 100mhz-10
* BIT11 开漏输出使能 1-开启
*BIT12 上下拉功能使能 0-关闭上下拉
*BIT13 保持功能0
*BIT15-14 100K上下拉电阻 -00
*BIT16 hys-0关闭
*设置配置值:8B0-100010110000
*/
SW_PAD_GPIO5_IO3 = 0x08B0;
/*****
*3.设置GPIO5_IO03 为输出
*GPIO5_GDIR 地址20A_C004
*GPIO5_DR 地址20A_C000
*/
GPIO5_GDIR = 0x08;
/*****
*4打开GPIO LED
*/
LED_ON() ;
}
/****
* 延时控制运行程序
* 实现大致1ms的单位延时
*/
void delay_ms(volatile unsigned int nms)
{
unsigned int nus;
while(nms--)
{
//1 ms延时
nus=0x7ff;
while(nus--)
{
}
}
}
/**
* 主main入口程序
*/
int main(void)
{
clk_enable(); //使能时钟
led_Init(); //初始化led灯
//led闪烁循环
while(1)
{
LED_OFF();
delay_ms(500);
LED_ON();
delay_ms(500);
}
return 0;
}
代码部分好了,接下来准备一下链接脚本,用于指定编译程序起始地址和顺序
SECTIONS{
. = 0x87800000;
.text :
{
start.o
led.o
*(.text)
}
.rodata ALIGN(4) : {*(.rodata*)}
.data ALIGN(4) : { *(.data) }
__bss_start = .;
.bss ALIGN(4) : { *(.bss) *(COMMON)}
__bss_end = .;
}
准备Makefile进行起飞编译吧:
objs := start.o led.o
led.bin : $(objs)
arm-linux-gnueabihf-ld -Timxu.lds -o led.elf $^
arm-linux-gnueabihf-objcopy -O binary -S led.elf $@
%.o : %.s
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
%.o : %.S
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
%.o : %.c
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
clean:
rm -rf *.o led.bin led.elf led.dis *.imx
dump:
arm-linux-gnueabihf-objdump -D -m arm led.elf > led.dis
dowmload:
./imxdownload led.bin /dev/sdb
试试编译效果:
motiongui@motiongui-VirtualBox:~/work/imxAss/Ledc$ make
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o start.o start.S
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o led.o led.c
arm-linux-gnueabihf-ld -Timxu.lds -o led.elf start.o led.o
arm-linux-gnueabihf-objcopy -O binary -S led.elf led.bin