一、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 管理分为两个核心层级 :IOMUXC 和 GPIO 控制器。这比很多单片机(如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 = .;
}