首先,创建nonos/01_led/
文件夹存放裸机点亮LED的代码。
CPU刚启动时没有设置栈,不能运行C语言,所以需要通过汇编来完成C语言的初始化,然后跳转到C语言区执行,一般称之为汇编启动文件,新建start.S
汇编启动文件,内容如下。首先,设置栈指针,因为开发板上的DDR的地址范围为0X80000000~0X9FFFFFFF
,然后我们设置栈首地址为0X80200000,这样其大小为2MB,因为IMX6UL的堆栈是向下增长的!我们需要注意的是,堆栈指针地址一定要是4字节地址对齐的!!!
/* 文件名:start.S
* 描述:启动文件,完成C环境初始化, 然后跳转到C代码运行 */
.text
.global _start /* 全局标号 */
/* 程序从此处开始执行 */
_start:
/* 设置栈,栈首地址为0X80200000,大小为2MB */
ldr sp,=0X80200000
/* 清除BSS段 */
bl clean_bss
/* 跳转到main函数 */
bl main
halt:
b halt
clean_bss:
ldr r1, =__bss_start
ldr r2, =__bss_end
mov r3, #0
cmp r1, r2
bne clean
mov pc, lr
clean:
str r3, [r1]
add r1, r1, #4
cmp r1, r2
bne clean
mov pc, lr
1、新建led.h
文件,填入以下内容
#ifndef __LED_H__
#define __LED_H__
/* 初始化LED引脚 */
void led_init(void);
/* 设置LED状态 */
void led_ctl(int on);
/* ms延时函数 */
void delay_ms(volatile unsigned int n);
#endif
2、新建led.c
文件
首先,宏定义我们需要使用的寄存器,然后实现和LED控制相关的几个函数,代码如下
#define CCM_CCGR1 ((volatile unsigned int *)0X020C406C)
#define SW_MUX_GPIO1_IO03 ((volatile unsigned int *)0X020E0068)
#define GPIO1_DR ((volatile unsigned int *)0X0209C000)
#define GPIO1_GDIR ((volatile unsigned int *)0X0209C004)
/* 描 述:初始化LED引脚,就是把它设置为输出引脚
* 参 数:无
* 返回值:无 */
void led_init(void)
{
unsigned int val;
/* a. 使能GPIO1, bit[27:26] --> gpio1_clock */
*CCM_CCGR1 |= (3<<26);
/* b. 设置GPIO1_IO03用于GPIO */
val = *SW_MUX_GPIO1_IO03;
val &= ~(0xf);
val |= (5);
*SW_MUX_GPIO1_IO03 = val;
/* c. 设置GPIO5_IO03作为output引脚 */
*GPIO1_GDIR |= (1<<3);
}
/* 描 述: 设置LED状态
* 参 数: on : 1-LED点亮, 0-LED熄灭
* 返回值: 无 */
void led_ctl(int on)
{
if (on) /* on: output 0*/
{
/* 将GPIO1_DR的bit3清零,输出低电平 */
*GPIO1_DR &= ~(1<<3);
}
else /* off: output 1*/
{
/* 将GPIO1_DR的bit3置1,输出高电平 */
*GPIO1_DR |= (1<<3);
}
}
/* 描 述: 短时间延时函数
* 参 数: 要延时循环次数(空操作循环次数)
* 返回值: 无 */
void delay_short(volatile unsigned int n)
{
while(n--){}
}
/* 描 述: ms延时函数,在396Mhz的主频下,延时时间大约为1ms
* 参 数: 要延时的ms数
* 返回值: 无 */
void delay_ms(volatile unsigned int n)
{
while(n--)
{
delay_short(0x7ff);
}
}
3、接下来就是编写主函数了,新建main.c
文件
#include "led.h"
int main(void)
{
led_init(); /* 初始化led */
while(1) /* 死循环 */
{
led_ctl(0); /* 关闭LED */
delay_ms(500); /* 延时大约500ms */
led_ctl(1); /* 打开LED */
delay_ms(500); /* 延时大约500ms */
}
return 0;
}
1、编写连接脚本文件 touch imx6ul.lds
SECTIONS {
. = 0x80100000;
. = ALIGN(4);
.text :
{
*(.text)
}
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4);
.data : { *(.data) }
. = ALIGN(4);
__bss_start = .;
.bss : { *(.bss) *(.COMMON) }
__bss_end = .;
}
2、编写Makefile文件 touch Makefile
objs := start.o led.o main.o
led.bin:$(objs)
arm-linux-gnueabihf-ld -Timx6ull.lds -o led.elf $^
arm-linux-gnueabihf-objcopy -O binary -S led.elf $@
arm-linux-gnueabihf-objdump -D -m arm led.elf > led.dis
%.o:%.s
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
%.o:%.S
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
%.o:%.c
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<
clean:
rm -rf *.o led.bin led.elf led.dis
代码编写完成后,使用make
命令对工程进行编译链接
可以看到,生成了led.bin
将正点原子提供的imxdownload
文件复制到工程目录下,并修改其权限chmod 777 imxdownload
然后使用ls /dev/sd*
命令找到sd卡
通过插入SD卡前后的对比,可以看到我们要使用的SD卡为sdb
,然后用imxdownlord将led.bin烧写到sd卡中
./imxdownload led.bin /dev/sdb
烧写后可看到
要注意其烧写速度,如果烧写速度大于几十MB/s,那么就是烧写失败了,可以尝试重启Ubuntu系统。
另外可以看到,烧写完后再当前目录下会生成一个load.imx
的文件,这个文件是软件imxdownlord根据NXP官方启动方式,再ledc.bin文件前面添加了一些数据头生成的,最终写到SD卡里的也是这个load.imx文件。
将SD卡插到开发板的SD卡槽中,并设置拨码开关为SD卡启动
然后上电可以看到LED闪烁
完整代码在:https://gitee.com/william_william/imx6u_alpha.git