当前位置: 首页 > article >正文

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

一,启动文件

.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文件

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

三,链接脚本文件

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文件

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 编译器,打开所有警告,不链接标准库,只编译不链接,输出文件名为当前规则的目标文件名,源代码文件为当前规则的第一个依赖文件。这通常用于编译单个源文件到目标文件的过程。


http://www.kler.cn/a/463627.html

相关文章:

  • 微服务实战——购物车模块实战
  • Ungoogled Chromium127 编译指南 MacOS 篇(一)- 项目介绍
  • 【前端系列】Pinia状态管理库
  • aardio —— 虚表 —— 模拟属性框
  • kubelet状态错误报错
  • AE RFG 1251 Generator User Manual
  • 基础的基础之 pillow与opencv相比的特点与优缺点比较
  • 【从零开始入门unity游戏开发之——C#篇39】C#反射使用——Type 类、Assembly 类、Activator 类操作程序集
  • 如何利用java爬虫获得AMAZON商品详情
  • 基于 Python 的人脸识别景区票务识别系统
  • 使用Qt中的模型视图框架
  • 【Rust自学】9.1. 不可恢复的错误以及panic!
  • 180天Java项目学习路线指引
  • 计算机毕设-基于springboot的花店管理系统的设计与实现(附源码+lw+ppt+开题报告)
  • 低精度只适用于未充分训练的LLM?腾讯提出LLM量化的scaling laws
  • JVMTI 笔记
  • 单元测试入门和mockup
  • ruoyi 分页 查询超出后还有数据; Mybatis-Plus 分页 超出后还有数据
  • 常见CMS漏洞(wordpress,DedeCms,ASPCMS,PHPMyAdmin)
  • MATLAB 中打印某些变量的值到文本文件中,使用diary和 fprintf
  • 人工智能:变革时代的核心驱动力
  • 阿里云redis内存优化——PCP数据清理
  • 华为开源自研AI框架昇思MindSpore应用案例:ICNet用于实时的语义分割
  • C# 将图片转换为PDF文档
  • 虹安信息技术有限公司数据泄露防护平台pushSetup存在SQL注入漏洞
  • 【Elasticsearch入门到落地】5、安装IK分词器