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 = .;
	}
相关推荐
侠客行03178 小时前
Mybatis连接池实现及池化模式
java·mybatis·源码阅读
蛇皮划水怪8 小时前
深入浅出LangChain4J
java·langchain·llm
老毛肚10 小时前
MyBatis体系结构与工作原理 上篇
java·mybatis
风流倜傥唐伯虎10 小时前
Spring Boot Jar包生产级启停脚本
java·运维·spring boot
Yvonne爱编码10 小时前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python
Re.不晚10 小时前
JAVA进阶之路——无奖问答挑战1
java·开发语言
你这个代码我看不懂11 小时前
@ConditionalOnProperty不直接使用松绑定规则
java·开发语言
fuquxiaoguang11 小时前
深入浅出:使用MDC构建SpringBoot全链路请求追踪系统
java·spring boot·后端·调用链分析
琹箐11 小时前
最大堆和最小堆 实现思路
java·开发语言·算法
__WanG11 小时前
JavaTuples 库分析
java