嵌入式Linux学习历程 — C语言LED灯

C语言LED灯

1、汇编文件:C语言环境构建
2、C语言文件:完成工程需要的功能

一、C语言运行环境构建

一、 设置处理器模式

设置6ULL处于SVC模式下,设置CPSR寄存器的bit4-0,即M[4:0]为10011 = 0X13。
读写状态寄存器需要用到MRS和MSR指令。MRS将CPSR寄存器数据读出到通用寄存器,MSR指令将通用寄存器的数据写入到CPSR寄存器中。

二、 设置 SP 指针

SP指针可以指向内部RAM,也可以指向DDR,我们将其指向DDR。
SP指针设置到哪里?DDR内存 512MB的范围0X80000000~0X9FFFFFFF。栈设置大小,0X200000 = 2MB。处理器栈增长方式,对于A7而言是向下增长的(由高地址指向低地址),所以设置SP指针指向0X80200000。

三、 跳转到C语言

使用b指令,跳转到C语言函数,比如main函数。

二、 程序代码

1、 汇编文件,设置处理器模式以及SP指针
start.S

.global _start      /* 全局标量 */

/*
    描述: _start函数,程序从此函数开始执行,此函数主要功能是设置C运行环境

 */
_start:

        /* 进入SVC模式 */
        mrs r0, cpsr       // 读取cpsr的数据到r0
        bic r0, r0, #0X1F  // 将r0的低五位清零,即cpsr的M0~M4
        orr r0, r0, #0X13  // r0或上0x13,表示使用SVC模式
        msr cpsr, r0       // 将r0的数据写入到cpsr_c中

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

2、 驱动文件
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_IO03   *((volatile unsigned int*)0X020E0068)
#define SW_PAD_GPIO1_IO03   *((volatile unsigned int*)0X020E02F4)

/* 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.c

#include "main.h"

/**********************************
* 函数名称: void clk_enable(void)
* 函数功能: 使能外设时钟
* 输入   : 无
* 输出   : 无
***********************************/
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;
}

/**********************************
* 函数名称: void LED_Init(void)
* 函数功能: 初始化LED
* 输入   : 无
* 输出   : 无
***********************************/
void LED_Init(void)
{
    /* 初始化IO复用,复用为GPIO1_IO3 */
    SW_MUX_GPIO1_IO03 = 0X5;

    /* 设置GPIO1——IO3 电气属性 */
    /***************************
     *bit 16:0 HYS关闭
	 *bit [15:14]: 00 默认下拉
     *bit [13]: 0 kepper功能
     *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_IO03 = 0X10B0;

    /* 初始化GPIO,GPIO1_IO3设置为输出 */
    GPIO1_GDIR = 0X00000008;

    /* 设置GPIO1_IO3输出低电平,打开LED灯 */
    GPIO1_DR = 0X0;
    
}

/**********************************
* 函数名称: void delay_short(volatile unsigned int n)
* 函数功能: 短延时
* 输入   : volatile unsigned int n
* 输出   : 无
***********************************/
void delay_short(volatile unsigned int n)
{
    while(n--);
}

/**********************************
* 函数名称: void delay(volatile unsigned int n)
* 函数功能: 延时,在396Mhz主频下约1ms
* 输入   : volatile unsigned int n
* 输出   : 无
***********************************/
void delay(volatile unsigned int n)
{
    while(n--)
        delay_short(0X7FF);
}

/**********************************
* 函数名称: void LED_On(void)
* 函数功能: 打开LED灯
* 输入   : 无
* 输出   : 无
***********************************/
void LED_On(void)
{
    GPIO1_DR &= ~(1 << 3);  /* bit3清零 */
    /* 1 << 3: 
     *      1左移3位 0000 0001 --> 0000 1000
     * ~(1 << 3):
     *      ~(0000 1000) --> 1111 0111
     * GPIO1_DR &= ~(1 << 3) 即 将bit3清零
     */
}

/**********************************
* 函数名称: void LED_Off(void)
* 函数功能: 关闭LED灯
* 输入   : 无
* 输出   : 无
***********************************/
void LED_Off(void)
{
    GPIO1_DR |= (1 << 3);  /* bit3置1 */
}

int main(void)
{
    clk_enable();    /* 使能外设时钟 */
    LED_Init();      /* 初始化LED */

    while(1) {
        LED_On();
        delay(500);
    
        LED_Off();
        delay(500);
    }

    return 0;
}

3、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 : %.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 

三、 链接脚本

链接脚本描述了要连接的文件,以及链接顺序,和链接首地址。

链接脚本的语法很简单,就说编写一系列的命令,这些命令组成连接脚本 ,每个命令都是一个带有参数的关键字或者一个对符号的赋值,可以使用符号分隔命令。
一般编译出来的代码都包含text、data、bss和rodata这四个段。
假设代码要被链接到0X10000000地址,而数据要被链接到0X30000000地址,下面为完成此功能最简单的链接脚本:

SECTIONS{
	. = 0X10000000;
	.text : {*(.text)}
	. = 0X30000000
	.data ALIGN(4) : { *(.data)}
	.bss ALIGN(4) : { *(.bss)}
}

第1行 为关键字“SECTIONS”
第2行 对特殊符号 “.” 进行赋值,“.”在链接脚本里称为 定位计数器,默认的定位计数器为0。因此给“.”赋值0X10000000,表示以0X10000000开始,后面的文件或者段都会以0X10000000开始链接。
第3行 “.text”为段名,冒号是语法要求,大括号里可以填上要链接到“.text”这个段的所有文件 “ *(.text)”表示所有输入文件的.text段都放到“.text”上 “ * ”是通配符
ALIGN(4)表示4字节对称,用来对“.data”段的起始地址做字节对称,即“.data”的起始地址要能被4整除。常见的有ALIGN(4)、ALIGN(8)
“.bss”就是那些定义了但是没有初始化的变量

imx6ull.lds
与Makefile同目录,用于Makefile的链接

SECTIONS{
	. = 0X87800000;
	.text :
	{
		start.o 
		*(.text)
	}
	.rodata ALIGN(4) : {*(.rodata*)}     
	.data ALIGN(4)   : { *(.data) }    
	__bss_start = .;    
	.bss ALIGN(4)  : { *(.bss)  *(COMMON) }    
	__bss_end = .;
}

其中Makefile也需要修改

objs = start.o main.o 

ledc.bin : $(objs)
	arm-linux-gnueabihf-ld -Timx6ull.lds  $^ -o ledc.elf
	arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@
	arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis

%.o : %.c
	arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<

%.o : %.S
	arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<	

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

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值