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 = .;
	}
相关推荐
云烟成雨TD37 分钟前
Spring AI 1.x 系列【28】基于内存和 MySQL 的多轮对话实现案例
java·人工智能·spring
Lyyaoo.40 分钟前
【JAVA基础面经】String、StringBuffer、StringBuilder
java·开发语言
范纹杉想快点毕业44 分钟前
Zynq开发视角下的C语言能力分级详解
c语言·开发语言
TeamDev1 小时前
JxBrowser 8.18.2 版本发布啦!
java·前端·跨平台·桌面应用·web ui·jxbrowser·浏览器控件
晴天sir1 小时前
Redis 在业务中的几种典型用法
java·数据库·redis
WJX_KOI1 小时前
MemOS —— 为大语言模型 (LLMs) 和智能体打造的记忆操作系统。
java·人工智能·语言模型
_日拱一卒1 小时前
LeetCode:矩阵置零
java·数据结构·线性代数·算法·leetcode·职场和发展·矩阵
weixin_408099671 小时前
【实战教程】懒人精灵如何实现 OCR 文字识别?接口调用完整指南(附可运行示例)
java·前端·人工智能·后端·ocr·api·懒人精灵
花千树-0101 小时前
Java Agent 集成 MCP 工具协议:让 AI 真正驱动企业系统
java·ai·langchain·ai agent·mcp·harness·j-langchain
橘子编程1 小时前
GoF 23 种设计模式完整知识总结与使用教程
java·c语言·开发语言·python·设计模式