Linux之ARM(MX6U)裸机篇----4.C语言LED驱动实验

一,启动文件

cpp 复制代码
.global _start

_start:
    @设置处理器进入SVC模式
    mrs r0, cpsr        @读取cpsr到r0
    bic r0, r0, #0x1f   @清除cpsr的bit4-0
    orr r0, r0, #0x13   @使用svc模式
    msr cpsr, r0        @将r0写入到cpsr

    ldr sp, =0x80200000 @设置sp指针起始地址,此处已初始化ddr,若开发板未初始化ddr,则要手动初始化
    b main              @跳转到C语言main函数

汇编位运算

设置CPSR寄存器,看M[4:0] 设置为1001100XB ,时6ULL处于SVC模式,读写状态寄存器需要用MRS(特殊寄存器读写到普通寄存器中)MSR(普通寄存器读写到特殊寄存器中)指令

设置SP来控制出栈和入栈,可以指向内部RAM,也可以DDR,这里指向DDR,设置栈大小为0x200000=2MB,栈是向上增长。

二,main文件

cpp 复制代码
main.c

#include "main.h"
/* 使能外设时钟 */
void clk_enable(void)
{
    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 = 0X5;       /* 复用为GPIO1-IO03 */
    SW_PAD_GPIO1_IO03 = 0X10B0;    /* 设置GPIO01_IO03电气属性*/

    /* GPIO初始化 */
    GPIO1_GDIR = 0X8;              /* 设置未输出 */
    GPIO1_DR = 0X0;                /* 打开LED灯 */
}

/* 短延时一个循环1ms */
void delay_short(volatile unsigned int n)
{
    while(n--){}
}

/* 延时 */
void delay(volatile unsigned int n)
{
    while(n--)
    {
        delay_short(0x7ff);
    }
}

/* 打开led灯 */
void led_on(void)
{
    GPIO1_DR &= ~(1<<3); /* bit3清零 */
}

/* 关闭led灯 */
void led_off(void)
{
    GPIO1_DR |= (1<<3); /* bit3置1 */
}
int main(void)
{
    /* 初始化时钟 */
    clk_enable();
    /* 初始化LED */
    led_init();
    /* 设置LED闪烁 */
    while(1){
        led_on();
        delay(500);
        led_off();
        delay(500);
    };
    return 0;
}

main.h
#ifndef _MAIN_H
#define _MAIN_H

/*定义要使用的寄存器,根据操作手册看寄存器地址进行配置*/
#define CCM_CCGR0           *((volatile unsigned int *)0x020C4068)  //volatile是防止被更改,此处对宏读写操作就是直接读写该地址寄存器
#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

三,链接脚本文件

cpp 复制代码
SECTIONS{
    . = 0x87800000;                         /* 链接起始地址 */
    .text :                                 /* 程序段存放所有程序 */
    {
        start.o
        *(.text)
    }       
    .rodata ALIGN(4) : {*(.rodata*)}      /* rodata段存放所有rodata */
    .data ALIGN(4) : {*(.data*)}          /* data段存放所有data */
    _bss_start=.;                         /* .bss的起始地址 */
    .bss ALIGN(4) : {*(.bss) *(COMMON)}   /* 存放.bss数据,定义但未初始化的变量 */
    _bss_end=.;                           /* .bss的终止地址 */
}
/* 这段代码是一个连接脚本文件的片段,将文件分为不同的段,用于描述将各个输入目标文件(object file)的不同部分如.text、.rodata、.data和.bss等合并到最终的可执行文件中的内存布局。 */

四,makefile文件

cpp 复制代码
objs = main.0 start.o
ledc.bin : $(objs)
	arm-linux-gnueabihf-ld -Timx6ull.lds $^ -o ledc.elf
#arm-linux-gnueabihf-ld -Ttext 0X87800000 $^ -o ledc.elf
#这条命令的意思是:使用 arm-linux-gnueabihf-ld 链接器将所有依赖的目标文件($^ 展开后的目标文件列表)链接成一个名为 ledc.elf 的 ELF 文件,并且指定程序的文本段从内存地址 0x87800000 开始。
	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 $@ $<
#Wall表示显示编译时所有警告 -nostdlib表示不链接系统标准启动文件和库文件 -O2表示优化等级
%.o : %.s
	arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $<

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

#-c:这个选项告诉编译器只执行编译步骤,不进行链接。编译器将源代码编译成目标文件(通常是 .o 文件)。
#-o $@:-o 是一个链接器选项,用于指定输出文件的名称。$@ 是一个 Makefile 特殊变量,代表当前规则的 target 名称。在这个上下文中,它将被替换为当前规则的目标文件名,例如 start.o。
#$<:这是另一个 Makefile 特殊变量,代表当前规则依赖的第一个文件。在这个上下文中,它通常指向源代码文件,例如 start.s。
#这串指令的意思是:使用 arm-linux-gnueabihf-gcc 编译器,打开所有警告,不链接标准库,只编译不链接,输出文件名为当前规则的目标文件名,源代码文件为当前规则的第一个依赖文件。这通常用于编译单个源文件到目标文件的过程。
相关推荐
最后一个bug12 小时前
详细说明嵌入式linux中bootcmd与bootargs差异
linux·服务器·c语言·arm开发·嵌入式硬件
qq762118221 天前
arm rk3588 升级glibc2.31到2.33
arm开发
深圳市青牛科技实业有限公司1 天前
一文详解串行、并行、同步、异步
arm开发·科技·单片机·嵌入式硬件·音视频·游戏机
憧憬一下2 天前
RK3399 PCIe 中断处理与映射分析(INTx中断机制源码分析)
arm开发·嵌入式硬件·嵌入式·linux驱动开发·pci/pcie
码农不屈的一生2 天前
ARM架构服务器安装部署KVM虚拟化环境
运维·服务器·arm开发·架构
qq_243309112 天前
qt+Linux+arm多核CPU 亲和性
linux·arm开发·qt
娶不到胡一菲的汪大东2 天前
Linux之ARM(MX6U)裸机篇----5.仿stm32的LED驱动实验
arm开发·stm32·嵌入式硬件
limingade2 天前
手机实时提取SIM卡打电话的信令声音-智能拨号器的SIP线路-双卡双待单通方案
android·arm开发·智能手机·蓝牙电话·电脑打电话
亿道电子Emdoor3 天前
【ARM】PK51关于内存模式的解析与区别
arm开发·stm32·单片机
luoyayun3613 天前
Linux arm 编译安装glibc-2.29
linux·arm开发·glibc安装