IMX6ULL裸机程序--2.C语言点亮LED

C与汇编

现在很少用汇编去编写嵌入式驱动,常用C。汇编作用只是用来完成C语言环境搭建。C语言去实现具体功能裸机。

程序编写

工程文件

新建2.ledc文件夹,谈价start.S,main.c,main.h文件。

汇编部分程序start.S

.global _start /* 全局标号 */
 
/*
* 描述: _start 函数,程序从此函数开始执行,此函数主要功能是设置 C 5 * 运行环境。
*/
_start: 
/* 进入 SVC 模式 */
mrs r0, cpsr
bic r0, r0, #0x1f /* 将 r0 的低 5 位清零,也就是 cpsr 的 M0~M4 */
orr r0, r0, #0x13 /* r0 或上 0x13,表示使用 SVC 模式 */
msr cpsr, r0 /* 将 r0 的数据写入到 cpsr_c 中 */

ldr sp, =0X80200000 /* 设置栈指针 */
b main /* 跳转到 main 函数 */

C程序main.c,main.h

  • main.h
#ifndef   __MAIN_H
#define __MAIN_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相关寄存器地址 */
#define SW_MUX_GPIO1_IO04  *((volatile unsigned int*)0x020E006C)
#define SW_PAD_GPIO1_IO04  *((volatile unsigned int*)0x020E02F8)


/*
GPIO1相关寄存器地址
*/
#define GPIO1_DR    *((volatile unsigned int*)0x0209C000)
#define GPIO1_GDIR  *((volatile unsigned int*)0x0209C004)
#define GPIO1_PSR   *((volatile unsigned int*)0x0209C008)
#define GPIO1_ICR1  *((volatile unsigned int*)0x0209C00C)
#define GPIO1_ICR2  *((volatile unsigned int*)0x0209C010)
#define GPIO1_IMR   *((volatile unsigned int*)0x0209C014)
#define GPIO1_ISR   *((volatile unsigned int*)0x0209C018)
#define GPIO1_EDGE_SEL  *((volatile unsigned int*)0x0209C01C)



#endif // !  __MAIN_H

  • main.c
#include "main.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.初始化IO复用,复用GPIO1_IO04 */
    SW_MUX_GPIO1_IO04 = 0x05;

    /*   2.配置GPIO1_IO04的IO属性
        *bit 16:0 HYS关闭
        *bit [15:14] 00 默认下拉
        *bit [13]:0 keeper功能
        *bit [12]:1 pull/keeper使能
        *bit [11]:0 关闭开路输出
        *bit [7:6]: 10 速度100MHz
        *bit [5:3]: 110 R0/6驱动能力
        *bit [0]: 0 低转换率
       */
      SW_PAD_GPIO1_IO04 = 0X10B0;

      /*   3.初始化GPIO,GPIO1_IO04设置为输出  */
      GPIO1_GDIR = 0X00000010;

      /*  4.设置GPIO1_IO04输出低电平,打开LED0  */
      GPIO1_DR = 0x0;

}
/* 打开LED */
void led_on(void)
{
    /*
        将GPIO1_DR的bit4清零
    */
   GPIO1_DR &= ~(1<<4);

}


/* 关闭LED */
void led_off(void)
{
    /*
    讲GPIO1_DR的bit4置1
    */
   GPIO1_DR |= (1<<4);
}

/* 短时间延时函数 */
void delay_short(volatile unsigned int n)
{
    while(n--){}
}

/* 延时函数,在396Mhz主频下延时月1ms */
void delay(volatile unsigned int n)
{
    while(n--)
    {
        delay_short(0x7ff);
    }
}
/* 主函数 */
int main(void)
{
    clk_enable();/*   使能所有时钟  */
    led_init();   /*  初始化led  */

    while (1)/*   死循环  */
    {
        led_off();  /* 关闭LED */
        delay(500);

        led_on();/*   打开led  */
        delay(500);
    }

    return 0;
    
}

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  $@ $<
%.o:%.s
	arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o  $@ $<

clean:
	rm -rf *.o ledc.bin ledc.elf ledc.dis

Makefile使用到的语法知识:变量和自动变量。

  • 变量定义:objs := start.o main.o
    赋值符号除了:=还有= ,?=。使用“=”在给变量的赋值的时候,不一定要用已经定义好的值,也可以使用后面定义的值。赋值符“:=”不会使用后面定义的变量,只能使用前面已经定义好的。赋值符“?=”会判断前面没有被赋值,那么此变量就会赋值符赋值,如果前面已经赋过值了,那么就使用前面赋的值。
  • 自动变量
    目标和依赖都是一系列的文件,每一次对模式规则进行解析的时候都会是不同的目标和依赖文件,而命令只有一行,如何通过一行命令来从不同的依赖文件中生成对应的目标?自动化变量就是完成这个功能的!所谓自动化变量就是这种变量会把模式中所定义的一系列的文件自动的挨个取出,直至所有的符合模式的文件都取完,自动化变量只应该出现在规则的命令中。
    $@:规则中的目标集合,在模式规则中,如果有多个目标的话,“$@”表示匹配模式中定义的目标集合。
    $%当目标是函数库的时候表示规则中的目标成员名,如果目标不是函数库文件,那么其值为空。
    $<依赖文件集合中的第一个文件,如果依赖文件是以模式(即“%”)定义的,那么“$<”就是符合模式的一系列的文件集合。
    $? 所有比目标新的依赖目标集合,以空格分开。
    $^所有依赖文件的集合,使用空格分开,如果在依赖文件中有多个重复的文件,“$^”会去除重复的依赖文件,值保留一份。
    $+ 和“$^”类似,但是当依赖文件存在重复的话不会去除重复的依赖文件。
    $*这个变量表示目标模式中"%"及其之前的部分,如果目标是 test/a.test.c,目标模式为 a.%.c,那么“$*”就是 test/a.test。
发布了24 篇原创文章 · 获赞 6 · 访问量 3974

猜你喜欢

转载自blog.csdn.net/weixin_43482414/article/details/104556618