• 03. C语言编写LED


    C语言环境搭配

    1. 设置处理器模式
      设置6ULL处于SVC模式下。设置CPSR寄存器的bit4-0,也就是M[4:0]为10011=0x13。读写状态寄存器需要用到MRS和MSR指令。MRS将CPSR寄存器数据读出到通用寄存器里面,MSR指令将通用寄存器的值写入到CPSR寄存器里
    2. 设置SP指针
      sp指针可以指向内部RAM,也可以指向DDR。我们将其指向DDR。512MB的范围是0x80000000~0x9FFFFFFF。栈大小,0x200000=2M。处理器栈增长方式,对于A7,是向下增长的。设置sp指向0x80200000。
    3. 跳转到C语言
      使用b指令跳转到C语言函数,比如main函数

    编写程序

    配置环境start.s

    .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
    
    	/* 设置sp指针 */
    	ldr sp, =0x80200000
    	b main
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    头文件led.h

    #pragma once
    /* 定义要使用的寄存器 */
    /* CCM相关的寄存器 */
    #define CCM_CCGR0 				*((volatile ssize_t int*)0x020c4068)
    #define CCM_CCGR1 				*((volatile ssize_t int*)0x020c406c)
    #define CCM_CCGR2 				*((volatile ssize_t int*)0x020c4070)
    #define CCM_CCGR3 				*((volatile ssize_t int*)0x020c4074)
    #define CCM_CCGR4 				*((volatile ssize_t int*)0x020c4078)
    #define CCM_CCGR5 				*((volatile ssize_t int*)0x020c407c)
    #define CCM_CCGR6 				*((volatile ssize_t int*)0x020c4080)
    
    /* IOMUX相关的寄存器 */
    #define SW_MUX_GPIO1_IO03 		*((volatile ssize_t int*)0x020e0068)
    #define SW_PAD_GPIO1_IO03 		*((volatile ssize_t int*)0x020e02f4)
    
    /* GPIO1相关的寄存器 */
    #define GPIO1_DR 				*((volatile ssize_t int*)0x0209c0000)
    #define GPIO1_GDIR 				*((volatile ssize_t int*)0x0209c0004)
    #define GPIO1_PSR 				*((volatile ssize_t int*)0x0209c0008)
    #define GPIO1_ICR1 				*((volatile ssize_t int*)0x0209c000C)
    #define GPIO1_ICR2 				*((volatile ssize_t int*)0x0209c0010)
    #define GPIO1_IMR 				*((volatile ssize_t int*)0x0209c0014)
    #define GPIO1_ISR 				*((volatile ssize_t int*)0x0209c0018)
    #define GPIO1_GPIO_EDGE_SEL 	*((volatile ssize_t int*)0x0209c001C)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    源文件led.c

    #include "led.h"
    /* 使能外设时钟 */
    void clk_enable()
    {
    	CCM_CCGR0 = 0xFFFFFFFF;
    	CCM_CCGR1 = 0xFFFFFFFF;
    	CCM_CCGR2 = 0xFFFFFFFF;
    	CCM_CCGR3 = 0xFFFFFFFF;
    	CCM_CCGR4 = 0xFFFFFFFF;
    	CCM_CCGR5 = 0xFFFFFFFF;
    	CCM_CCGR6 = 0xFFFFFFFF;
    }
    
    /* 初始化LED */
    void led_init()
    {
    	SW_MUX_GPIO1_IO03 = 0x5;    // 复用
    	SW_PAD_GPIO1_IO03 = 0x10b0;  // 设置电器属性
    
    	GPIO1_GDIR=0x8; //设置为输出
    	GPIO1_DR = 0x0; //打开LED灯
    }
    void delay_short(volatile ssize_t int n)
    {
    	while(n--){}
    }
    void delay(volatile ssize_t int n)
    {
    	while(n--)
    	{
    		delay_short(0x7ff);// 396MHz下,一次循环大概是1ms
    	}
    }	
    void led_on()
    {
    	GPIO1_DR &= ~(1<<3); // 将第三位清零
    }
    void led_off()
    {
    	GPIO1_DR |= (1<<3); // 将第三位置1
    }
    void main()
    {
    	clk_enable();
    	led_init();
    	while(1){
    		led_on();
    		delay(500);
    		led_off();
    		delay(500);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    makefile文件

    # -Wall 表示显示编译的时候所有警告,-nostdlib表示不链接系统标准启动文件和库文件,否则编译可能会出错。-o2表示优化等级。imx6UL.lds是链接脚本
    objs := start.o main.o	# 定义了一个变量objs,包含要生成ledc.bin的两个文件
    
    led.bin:$(objs) # 如果当前工程没有这两个文件,就去相应的规则中生成
    	arm-linux-gnueabihf-ld -Timx6ul.lds -o led.elf $^  # $^ 所有依赖文件的集合,这一行是链接文件
    	arm-linux-gnueabihf-objcopy -O binary -S led.elf $@  # $@ 所有目标的集合,这一行生成bin文件
    	arm-linux-gnueabihf-objdump -D -m arm led.elf > led.dis # 这一行是生成反汇编dis文件
    
    # 针对不同的文件类型编译为对应的 .o 文件	
    %.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 $@ $<
    
    .PHONY:clean	
    clean:
    	rm -rf *.o ledc.bin ledc.elf ledc.dis
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    链接脚本

    链接脚本主要用于链接,描述文件应该如何被链接在一起形成最终的可执行文件。用来描述输入文件中的段如何被映射到输出文件中,并且控制输出文件中的内存排布。
    链接脚本就是编写一系列的命令,每个命令是一个带有参数的关键字或者对一个符号的赋值。我们一般编译出来的代码都包含在text、data、bss和rodata这四个段内

    SECTIONS{
    	. = 0x87800000  /* 以该地址为起始地址开始链接 */
    	.text: /* 段名,块内写要链接到这个段的所有文件 */
    	{
    		start.o   /* start.o 要链接到最开始的地方,因为包含第一个要执行的命令 */
    		*(.text)  /* *是通配符,表示所有输入文件的.text段都放到.text中 */
    	}
    	.rodata ALIGN(4) : {*(.rodata*)}  /* ALIGN(4)表示.rodata 的起始地址要能被4整除,也就是内存对齐 */
    	.data ALIGN(4) : {*(.data)}
    	__bss_start=.; /* .bss段是定义了,但是没有被初始化,需要手动清零 */
    	.bss ALIGN(4) : {*(.bss) *(COMMON)}
    	__bss_end=.; /* 直接将.bss这段内存赋0,就完成了清零 */
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    然后将上述的makefile文件的链接脚本由-Ttext 0x87800000改为了-Timx6ul.lds

  • 相关阅读:
    电脑微软账户登录一直转圈怎么解决问题
    生成代理:人类行为的交互模拟(Generative Agents: Interactive Simulacra of Human Behavior)
    MySQL 连接查询和存储过程
    dbeaver 连接HANA数据库不同租户模式
    Go — 相关依赖对应的exe
    iOS渲染卡死应该如何解决
    Spark 弹性分布式数据集 RDD
    Maven编程环境搭建以及VS code Maven设置
    基于python的智慧城市社区服务平台及养老服务子系统的设计与实现
    qt Android中使用opencv处理视频
  • 原文地址:https://blog.csdn.net/m0_63667883/article/details/133881443