博客介绍
硬件:正点原子linux开发板IM6ULL
开发环境:Ubuntu下的VSCode
功能:配置引脚GPIO1_IO03驱动LED的亮灭。
参考:IMX6ULL串口手册.pdf、I.MX6U 嵌入式 Linux 驱动开发指南 V1.3.pdf
使用汇编语言跳转至C语言,使用C语言进行点亮LED。
第一步:编写汇编跳转文件
文件文件:start.S
.global _start
_start: //程序启始
//第一步:设置处理器进入SVC模式
/* 设置CSRP寄存器 设置为特权模式Supervisor(SVC)模式*/
MRS R0, CPSR
BIC R0, R0, #0x1F //清除CPSR的低五位
ORR R0, R0, #0x13 //设置CPSR的低五位为Supervisor(SVC)模式
MSR CPSR, R0 //将R0写入到CPSR
//第二步:设置SP指针
LDR SP, =0x80200000
B main //跳转到C语言main函数
第二步:映射寄存器汇编内存物理地址
创建文件:main.h
#ifndef __MAIN_H
#define __MAIN_H
//映射要使用到的寄存器
#define CCM_CCGR0 *((volatile unsigned int *)0x020C4068) //映射CCM_CCGR0的物理地址
#define CCM_CCGR1 *((volatile unsigned int *)0x020C406C) //映射CCM_CCGR1的物理地址
#define CCM_CCGR2 *((volatile unsigned int *)0x020C4070) //映射CCM_CCGR2的物理地址
#define CCM_CCGR3 *((volatile unsigned int *)0x020C4074) //映射CCM_CCGR3的物理地址
#define CCM_CCGR4 *((volatile unsigned int *)0x020C4078) //映射CCM_CCGR4的物理地址
#define CCM_CCGR5 *((volatile unsigned int *)0x020C407C) //映射CCM_CCGR5的物理地址
#define CCM_CCGR6 *((volatile unsigned int *)0x020C4080) //映射CCM_CCGR6的物理地址
//映射GPIO1_IO03复用和属性寄存器
#define SW_MUX_GPIO1_IO03 *((volatile unsigned int *)0x020E0068) //映射SW_MUX_GPIO1_IO03的物理地址
#define SW_PAD_GPIO1_IO03 *((volatile unsigned int *)0x020E02F4) //映射SW_PAD_GPIO1_IO03的物理地址
//映射数据寄存器
#define GPIO1_DR *((volatile unsigned int *)0x0209C000) //映射GPIO1_DR的物理地址
#define GPIO1_GDIR *((volatile unsigned int *)0x0209C004) //映射GPIO1_DR的物理地址
#define GPIO1_PSR *((volatile unsigned int *)0x0209C008) //映射GPIO1_DR的物理地址
#define GPIO1_ICR1 *((volatile unsigned int *)0x0209C00C) //映射GPIO1_DR的物理地址
#define GPIO1_ICR2 *((volatile unsigned int *)0x0209C010) //映射GPIO1_DR的物理地址
#define GPIO1_IMR *((volatile unsigned int *)0x0209C014) //映射GPIO1_DR的物理地址
#define GPIO1_ISR *((volatile unsigned int *)0x0209C018) //映射GPIO1_DR的物理地址
#define GPIO1_EDGE_SEL *((volatile unsigned int *)0x0209C01C) //映射GPIO1_DR的物理地址
#endif
第三步:调用寄存器初始化引脚功能
创建文件:main.h
LED初始化可以参考:汇编LED功能寄存器
#include "main.h"
//使能外设时钟
void clock_enable()
{
CCM_CCGR0 = 0xFFFFFFFF;
CCM_CCGR1 = 0xFFFFFFFF;
CCM_CCGR2 = 0xFFFFFFFF;
CCM_CCGR3 = 0xFFFFFFFF;
CCM_CCGR4 = 0xFFFFFFFF;
CCM_CCGR5 = 0xFFFFFFFF;
CCM_CCGR6 = 0xFFFFFFFF;
}
//初始化LED设置模式
void LED_Init(void)
{
SW_MUX_GPIO1_IO03 = 0x00000005; //配置GPIO1_IO03的工作模式
SW_PAD_GPIO1_IO03 = 0x000090b0; //配置PGIO1_IO03的电器属性
/* 配置 SW_PAD_GPIO1_IO03 电器属性
bit16: YHS:作为输入有效,迟滞比较器 0 失能
bit14-15: PUS:设置上下拉与电阻大小 10 上拉电阻100K
bit13: PUE:作为输入时使能或禁止上下拉 0 禁止
bit12: PKE:作为输出时使能或禁止下拉 1 使能
bit11: ODE:作用输出时使能开漏输出 0 关闭开漏输出
bit6-7: SPEED:IO作用输出时速度 10 100MHz
bit3-5: DSE:输出时设置驱动能力 110 R0/6
bit0: SRE:设置压摆率 0 低压摆率
*/
GPIO1_GDIR = 0x8; //设置PGIO1_IO03为输出模式
GPIO1_DR = 0x8; //设置PGIO1_IO03默认输出高点平
}
/*使用while循环实现硬件延时*/
//功能:实现短延时
void delay_short(volatile unsigned int n)
{
while(n--);
}
//延时函数,在396MHz时 大约1ms
void delay(volatile unsigned int n)
{
while(n--)
delay_short(0x7FF);
}
//关闭led
void led_off(void)
{
GPIO1_DR |= (1<<3); //操作GPIO1_DR寄存器
}
//打开led
void led_on(void)
{
GPIO1_DR &= ~(1<<3);
}
int main()
{
/*初始换led*/
clock_enable(); //调用时钟使能
LED_Init(); //调用LED初始化函数
while(1)
{
led_on(); //打开LED
delay(500); //粗略延时500ms
led_off(); //关闭LED
delay(500); //粗略延时500ms
}
return 0;
}
#endif
第四步:编写Makefile文件
创建文件:Makefile
objs := start.o main.o #使用变量 文件文件依赖
ledc.bin:$(objs)
arm-linux-gnueabihf-ld -Ttext 0x87800000 -o ledc.elf $^
arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@
arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis
%.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 ledc.bin ledc.elf ledc.dis
第五步:编译连接下载
第六步:插入SD卡上电观察
编写过程中遇到的问题
[https://blog.csdn.net/qq_41906031/article/details/105852723]