day2(IMX6ULL)<led(c语言版)>

一、volatile关键字

1.基本概念:

volatile 告诉编译器:这个变量可能会被程序以外的因素改变,不要对这个变量进行优化。

2. 主要作用:

防止编译器优化
cpp 复制代码
// 没有 volatile 的情况
int flag = 0;

void wait_for_flag() {
    while (flag == 0) {
        // 编译器可能优化为:if (flag == 0) while(1);
        // 因为编译器认为 flag 在循环中没有改变
    }
}

// 使用 volatile 的情况
volatile int flag = 0;

void wait_for_flag() {
    while (flag == 0) {
        // 每次循环都会重新从内存读取 flag 的值
    }
}

3.使用场景

硬件寄存器
cpp 复制代码
// 硬件寄存器地址映射
#define PORT_A *(volatile unsigned char*)0x1000

void write_to_port() {
    PORT_A = 0xFF;  // 确保写入物理地址
}

unsigned char read_from_port() {
    return PORT_A;  // 确保从物理地址读取
}

二、定义寄存器地址

cpp 复制代码
#include<reg51.h>
	#define P2 *((volatile unsigned char*)0x80)
	
	#define CCM_CCGR0 *((unsigned int *)0x020C4068)
	#define CCM_CCGR1 *((unsigned int *)0x020C406C)
	#define CCM_CCGR2 *((unsigned int *)0x020C4070)
	#define CCM_CCGR3 *((unsigned int *)0x020C4074)
	#define CCM_CCGR4 *((unsigned int *)0x020C4078)
	#define CCM_CCGR5 *((unsigned int *)0x020C407C)
	#define CCM_CCGR6 *((unsigned int *)0x020C4080)

	#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03    *((unsigned int *)0x020E0068)
	#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03    *((unsigned int *)0x020E02F4)
	#define GPIO1_DR                            *((unsigned int *)0x0209C000)
	#define GPIO1_GDIR                          *((unsigned int *)0x0209C004)

三、代码编写

cpp 复制代码
void clock_init(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)
	{
		IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = 0x05;
		IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 = 0x10B0;
		GPIO1_GDIR |= (1 << 3);
	}

	void led_on(void)
	{
		GPIO1_DR &= ~(1 << 3);
	}

	void led_off(void)
	{
		GPIO1_DR |= (1 << 3);
	}

	void led_delay(unsigned int time)
	{
		while (time--);
	}

四、优化Makefile

Matlab 复制代码
COMPLITER = arm-linux-gnueabihf-
	CC = $(COMPLITER)gcc
	LD = $(COMPLITER)ld
	OBJCOPY = $(COMPLITER)objcopy
	OBJDUMP = $(COMPLITER)objdump

	OBJS = start.o main.o
	TARGET = led
	
	%.o : %.S
		$(CC) -c $^ -o $@ -g

	%.o : %.c
		$(CC) -c $^ -o $@ -g
		
	$(TARGET).bin : $(OBJS)
		$(LD) -Ttext 0x87800000 $^ -o $(TARGET).elf
		$(OBJCOPY) -O binary -S -g $(TARGET).elf $@
		$(OBJDUMP) -D $(TARGET).elf  > $(TARGET).dis

	clean:
		rm $(OBJS) $(TARGET).elf $(TARGET).bin $(TARGET).dis -f

	load:
		./imxdownload $(TARGET).bin /dev/sdb

五、优化寄存器

cpp 复制代码
struct GPIO_t
    {
        unsigned int DR;
        unsigned int DGIR;
        unsigned int PSR;
        unsigned int ICR1;
        unsigned int ICR2;
        unsigned int IMR;
        unsigned int ISR;
        unsigned int EDGE_SEL;
    };
    #define GPIO1 (*((struct GPIO_t *)0x0209C000))

六、构建新工程

1.新建文件夹led_sdk

2.拷贝led_c内的start.S main.c Makefile到新工程

  • (1).SDK(Software development tools)移植
  • (2).完整开发工具就是一个IDE, 集代码编写、编译、下载于一体的集成开发环境, 类似于keil这种工具,要是用这个需要额外购买一些设备如下载器、编程器、仿真器
  • (3).所以只用它的头文件。

3.拷贝SDK目录下的所有头文件到新工程

4.介绍头文件

GPIO_Type:

在 i.MX6ULL 中,GPIO 管理分为两个核心层级IOMUXCGPIO 控制器。这比很多单片机(如STM32)的单一GPIO模块要复杂。

在官方 SDK(如 NXP 的 MCUXpresso)中,通常会在 fsl_gpio.h 头文件中定义 GPIO_Type 结构体,用于映射到内存中的GPIO控制器

cpp 复制代码
/* 简化的 GPIO_Type 结构体定义 */
typedef struct {
    __IO uint32_t DR;        /* 数据寄存器 (偏移: 0x00) */
    __IO uint32_t GDIR;      /* 方向寄存器 (偏移: 0x04) */
    __I  uint32_t PSR;       /* 引脚状态寄存器 (偏移: 0x08) */
    __IO uint32_t ICR1;      /* 中断配置寄存器1 (偏移: 0x0C) */
    __IO uint32_t ICR2;      /* 中断配置寄存器2 (偏移: 0x10) */
    __IO uint32_t IMR;       /* 中断屏蔽寄存器 (偏移: 0x14) */
    __IO uint32_t ISR;       /* 中断状态寄存器 (偏移: 0x18) */
    __IO uint32_t EDGE_SEL;  /* 边沿选择寄存器 (偏移: 0x1C) */
} GPIO_Type;

注:__IO__I 是防止编译器优化的宏,通常定义为 volatile,确保直接访问硬件寄存器。

七、利用SDK编写点灯程序

cpp 复制代码
void clock_init(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)
	{
		IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03, 0);
		IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03, 0x10B0);
		GPIO1->GDIR |= (1 << 3);
	}

	void led_on(void)
	{
		GPIO1->DR &= ~(1 << 3);
	}

	void led_off(void)
	{
		GPIO1->DR |= (1 << 3);
	}

	void led_flicker(void)
	{
		GPIO1->DR ^= (1 << 3);
	}

八、工程管理BSP(板级支持包)

  • 1.project :存放必要程序 main.c start.S
  • 2.imx6ull :存放NXP提供的i.mx6ull头文件 cc.h core_ca7.h fsl_common.h fsl_iomuxc.h MCIMX6Y2.h
  • 3.bsp :存放硬件外设相关功能模块 led.c led.h beep.c beep.h
  • 4.Makefile: 需要遍历目录

九、链接脚本

1.链接脚本: imx6ull.lds

2.链接主要在链接阶段,为连接器提供蓝图;

3.启动代码需要在进入C语言第一条指令前,将.bss .COMMON段初始化清0

cpp 复制代码
SECTIONS
	{
		. = 0x87800000;
		.text :
		{
			obj/start.o
			*(.text)
		} 
		.rodata ALIGN(4) : {*(.rodata*)}
		.data ALIGN(4) : {*(.data)}

		__bss_start = .;
		.bss ALIGN(4) : {*(.bss) *(.COMMON)}
		__bss_end = .;
	}
相关推荐
输出输入1 小时前
IJ IDEA支持中文变量名、方法名、类名吗?
java·intellij-idea
计算机毕设指导62 小时前
基于微信小程序的奶茶店点餐系统【源码文末联系】
java·spring boot·微信小程序·小程序·tomcat·maven·intellij-idea
bloglin999992 小时前
hub.docker.com和docker.com
java·docker·eureka
誰能久伴不乏2 小时前
Qt 启动时序与事件循环:为什么监控启动不要放在构造函数里,以及 `QTimer::singleShot(0, ...)` 到底做了什么
c语言·c++·qt
若鱼19192 小时前
SpringBoot4.0新特性-声明式HTTP远程调用客户端
java·spring
信创天地2 小时前
信创环境下数据库与中间件监控实战:指标采集、工具应用与告警体系构建
java·运维·数据库·安全·elk·华为·中间件
无籽西瓜a2 小时前
详解Stream流特性与常用操作
java
H Corey2 小时前
Java抽象类与接口实战指南
java·开发语言·学习·intellij-idea
昊坤说不出的梦2 小时前
互联网大厂Java面试实录:核心技术栈深度解析与业务场景落地
java·大数据·spring boot·微服务·ai·技术栈·互联网面试