C 語言實現 I.MX6ULL 點燈(續上一篇)、SDK、deep及bsp工程管理

目錄

一、匯編點燈轉 C 語言實現

1. 關鍵字:volatile

2. 寄存器地址定義(兩種方式)

(1)直接宏定義地址

(2)結構體封裝寄存器(優化訪問)

3. 核心功能代碼

(1)時鐘初始化:打開所有時鐘門

(2)LED 初始化:引腳復用 + GPIO 方向配置

(3)LED 控制:亮、滅、閃爍

二、SDK 庫文件

1. SDK文件選擇

2. 基于 SDK 的點燈程序優化

三、BSP 工程管理與構建

1. 工程目錄結構(模塊化管理)

2. 蜂鳴器裸機驅動(S8550 PNP 三極管)

3. Makefile 優化(多目錄編譯)

4. 鏈接腳本(imx6ull.lds)

1.鏈接腳本的作用

2.各段及存儲數據類型

一、匯編點燈轉 C 語言實現

1. 關鍵字:volatile

  • 作用:告訴編譯器,被修飾的變量值可能會被程序之外的因素(如硬件寄存器、中斷服務函數)意外修改,禁止編譯器對該變量進行優化

在訪問硬件寄存器時必須使用,確保每次對寄存器的讀寫都是直接操作物理地址,而非操作緩存值

2. 寄存器地址定義(兩種方式)

(1)直接宏定義地址

通過#define將寄存器物理地址強制轉換為對應類型的指針,直接訪問寄存器:

(2)結構體封裝寄存器(優化訪問)

將同組寄存器(如 GPIO1 的 DR、GDIR、PSR 等)封裝為結構體,通過結構體指針映射到基地址:

3. 核心功能代碼

(1)時鐘初始化:打開所有時鐘門

I.MX6ULL 外設默認時鐘關閉,需通過 CCM 寄存器開啟對應外設時鐘,此處為簡化操作,直接打開所有時鐘門:

(2)LED 初始化:引腳復用 + GPIO 方向配置
  • 引腳復用:將GPIO1_IO03配置為 GPIO 功能(復用值 0x05)
  • 電氣屬性:配置引腳驅動能力、上下拉等(0x10B0 為常用配置)
  • GPIO 方向:將GPIO1_IO03設為輸出模式(GDIR 寄存器對應位寫 1)
void led_init(void)
{// 方式1:直接操作寄存器(無SDK)IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = 0x05;    // 引腳復用為GPIOIOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 = 0x10B0;  // 配置引腳電氣屬性GPIO1_GDIR |= (1 << 3);                     // GPIO1_IO03設為輸出(第3位寫1)// 方式2:結構體訪問(優化后)// IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = 0x05;// IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 = 0x10B0;// GPIO1->GDIR |= (1 << 3);
}
(3)LED 控制:亮、滅、閃爍

通過操作 GPIO1 的 DR 寄存器(數據寄存器)控制引腳電平:

  • LED燈亮:對應位寫 0(拉低電平,假設 LED 為共陽極)
  • LED燈滅:對應位寫 1(拉高電平)
  • LED燈閃爍:對應位異或(電平翻轉)
// LED點亮
void led_on(void)
{GPIO1->DR &= ~(1 << 3);  // 第3位清0(拉低電平)
}// LED熄滅
void led_off(void)
{GPIO1->DR |= (1 << 3);   // 第3位置1(拉高電平)
}// LED閃爍(電平翻轉)
void led_flicker(void)
{GPIO1->DR ^= (1 << 3);   // 第3位異或(0變1,1變0)
}// 延時函數(軟件延時,時間與參數time相關)
void led_delay(unsigned int time)
{while (time--);
}

二、SDK 庫文件

1. SDK文件選擇

  • SDK(Software Development Kit):NXP 提供的 I.MX6ULL 開發工具包,包含完整 IDE(需額外設備:下載器、仿真器)和底層驅動頭文件;
  • 移植核心:僅使用 SDK 中的頭文件(無需完整 IDE),路徑為IMAX6ULL/SDK/,關鍵頭文件包括:
    • cc.h:時鐘相關定義;
    • core_ca7.h:ARM Cortex-A7 內核相關定義;
    • fsl_common.h:通用工具函數定義;
    • fsl_iomuxc.h:引腳復用配置函數定義;
    • MCIMX6Y2.h:I.MX6ULL 寄存器映射結構體定義。

2. 基于 SDK 的點燈程序優化

SDK 提供了封裝好的引腳配置函數(如IOMUXC_SetPinMuxIOMUXC_SetPinConfig),簡化寄存器操作:

// 時鐘初始化(SDK中CCM已封裝為結構體,可通過CCM->CCGRx訪問)
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;
}// LED初始化(有SDK)
void led_init(void)
{// 1. 引腳復用:將GPIO1_IO03配置為GPIO功能,第2個參數為ALT引腳(0表示無ALT)IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03, 0);// 2. 引腳電氣屬性配置:驅動能力、上下拉等(0x10B0為標準配置)IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03, 0x10B0);// 3. GPIO方向配置:設為輸出GPIO1->GDIR |= (1 << 3);
}

注意:

時鐘使能:I.MX6ULL外設時鐘默認關閉,初始化外設前必須開啟對應時鐘門;

三、BSP 工程管理與構建

1. 工程目錄結構(模塊化管理)

將代碼按功能拆分到不同目錄,提高可維護性,目錄結構如下:

2. 蜂鳴器實現(S8550 PNP 三極管)

  • 原理:S8550 為 PNP 型三極管,基極高電平時導通,控制蜂鳴器發聲;
  • 核心代碼:與 LED 驅動邏輯類似,僅需修改對應引腳:
//beep.h#ifndef _BEEP_H_
#define _BEEP_H_extern void beep_init(void);
extern void beep_on(void);
extern void beep_off(void);
extern void beep_nor(void);#endif//beep.c#include "beep.h"
#include "fsl_iomuxc.h"
#include "MCIMX6Y2.h"void beep_init(void)
{IOMUXC_SetPinMux(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01 , 0);   //復用功能IOMUXC_SetPinConfig(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01 , 0x10B0);     //電氣特性       GPIO5->GDIR |= (1 << 1);         //引腳方向配置beep_off();
}void beep_on(void)    //蜂鳴器發聲
{GPIO5->DR &= ~(1 << 1);    //置0
}void beep_off(void)   //蜂鳴器停止發聲
{GPIO5->DR |= (1 << 1);     //置1
}void beep_nor(void)   //蜂鳴器交替發聲
{GPIO5->DR ^= (1 << 1);
}//main.c                         實現LED燈和蜂鳴器的共同操作#include "fsl_iomuxc.h"
#include "MCIMX6Y2.h"
#include "led.h"
#include "beep.h"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_delay(unsigned int t)
{while(t--);
}int main(void)
{clock_init();led_init();beep_init();while (1){led_nor();beep_nor();led_delay(0x7FFFF);}
}

3. Makefile 優化(多目錄編譯)

支持多目錄(project、bsp/led、bsp/beep)編譯,自動生成目標文件(obj 目錄),并通過鏈接腳本生成 bin、elf、dis 文件:

target = led// 定義交叉編譯器前綴
cross_compiler = arm-linux-gnueabihf-// 定義編譯工具
cc = $(cross_compiler)gcc       // 編譯器
ld = $(cross_compiler)ld        // 鏈接器
objcopy = $(cross_compiler)objcopy  // 格式轉換工具
objdump = $(cross_compiler)objdump  // 反匯編工具// 頭文件和源文件目錄
incdirs = bsp imx6ull           // 頭文件搜索目錄
srcdirs = bsp project           // 源文件搜索目錄// 生成頭文件包含參數
include = $(patsubst %, -I%, $(incdirs))// 查找所有C和匯編源文件
cfiles = $(foreach dir, $(srcdirs), $(wildcard $(dir)/*.c))
sfiles = $(foreach dir, $(srcdirs), $(wildcard $(dir)/*.S))// 處理文件名(去路徑)
cfilenodir = $(notdir $(cfiles))
sfilenodir = $(notdir $(sfiles))// 生成目標文件路徑
cobjs = $(patsubst %, obj/%, $(cfilenodir:.c=.o))  // C文件對應的.o
sobjs = $(patsubst %, obj/%, $(sfilenodir:.S=.o))  // 匯編文件對應的.o
objs = $(cobjs) $(sobjs)                           // 所有目標文件// 源文件搜索路徑
VPATH = $(srcdirs)// 生成bin文件(依賴所有目標文件)
$(target).bin : $(objs)$(ld) -Timx6ull.lds -o$(target).elf $^       // 鏈接生成elf$(objcopy) -O binary -S -g $(target).elf $@  // 轉換為bin$(objdump) -D $(target).elf > $(target).dis  // 生成反匯編// 匯編文件編譯規則
$(sobjs) : obj/%.o : %.S@mkdir -p obj$(cc) -Wall -nostdlib -c $(include) -o $@ $<// C文件編譯規則
$(cobjs) : obj/%.o : %.c@mkdir -p obj		$(cc) -Wall -nostdlib -c $(include) -o $@ $<// 清理編譯產物
.PHONY : clean
clean:rm -rf $(objs) $(target).elf $(target).bin $(target).dis// 下載程序到SD卡
load:../imxdownload $(target).bin /dev/sdb

總結:

工具(前綴為arm-linux-gnueabihf-作用
gcc(編譯器)將源代碼(.c/.S)編譯為目標文件(.o):預處理→編譯→匯編,生成機器碼
ld(鏈接器)按鏈接腳本,將多個目標文件(.o)合并為可執行文件(.elf)
objcopy(目標文件拷貝工具)將.elf 文件轉換為二進制文件(.bin),便于燒寫至開發板 Flash/RAM
objdump(目標文件反匯編工具)對.elf 文件反匯編,生成.dis 文件,用于調試(查看指令與地址對應關系)
輔助工具(如imxdownload專用燒寫工具,將.bin 文件燒寫到開發板存儲設備(如 SD 卡 /dev/sdb)

4. 鏈接腳本(imx6ull.lds)

指定代碼加載地址(I.MX6ULL 常用 0x87800000),定義各段(text、rodata、data、bss)的排列順序,并標記 BSS 段起始 / 結束地址(用于啟動文件初始化 BSS 段)

SECTIONS
{. = 0x87800000;  // 代碼加載基地址(I.MX6ULL DDR起始地址)// 代碼段(text):存放啟動文件、主程序代碼.text :{obj/start.o  // 啟動文件優先加載(需先初始化棧、BSS段)*(._text)    // 所有文件的text段} // 只讀數據段(rodata):存放常量,4字節對齊.rodata ALIGN(4) : {*(.rodata*)}// 已初始化數據段(data):存放初始化過的全局變量,4字節對齊.data ALIGN(4) : {*(.data)}// 未初始化數據段(bss):存放未初始化的全局變量,需在啟動文件中清0__bss_start = .;  // BSS段起始地址.bss ALIGN(4) : {*(.bss) *(COMMON)}  // 所有bss段和COMMON段__bss_end = .;    // BSS段結束地址
}

注意:

需要在啟動代碼中加入跳轉鏈接

BSS 段初始化:啟動文件(start.S)需在跳轉到 main 前,將__bss_start到__bss_end的內存清0

1.鏈接腳本的作用

鏈接腳本(上文中的imx6ull.lds)的核心作用是定義程序的內存布局使鏈接器將多個目標文件(.o)合并為可執行文件(.elf)?的配置文件,核心是定義 “內存布局” 和 “段的排列規則”(不同段對應程序中不同類型的數據),確保代碼和數據加載到芯片指定的內存地址(如上文中的-Ttext 0x87800000),達成硬件成功運行的要求

2.各段及存儲數據類型
常見段名存儲數據類型
.text代碼段:存放可執行指令(如 C 函數、匯編指令),只讀
.data數據段:存放已初始化且非零的全局變量 / 靜態變量,可讀可寫
.bss未初始化數據段:存放未初始化或初始化為零的全局變量 / 靜態變量,運行時由系統清零
.rodata只讀數據段:存放只讀常量(如字符串常量、const修飾的全局變量)
.stack棧區:用于函數調用時保存局部變量、函數參數、返回地址,由編譯器自動管理
.heap堆區:用于動態內存分配(如malloc申請的內存),需手動管理

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/922455.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/922455.shtml
英文地址,請注明出處:http://en.pswp.cn/news/922455.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

DevOps實戰(7) - 使用Arbess+GitPuk+sourcefare實現Node.js項目自動化部署

Arbess 是一款國產開源免費的 CI/CD 工具&#xff0c;工具支持一鍵部署&#xff0c;頁面簡潔易用。本文將詳細介紹如何安裝配置使用GitPuk、sourcefare、Arbess系統&#xff0c;使用流水線拉取GitPuk源碼、使用sourcefare代碼掃描、構建安裝包并進行主機部署。 1、GitPuk 安裝…

算法,蒜鳥蒜鳥-P1-理解“雙指針”

歡迎來到啾啾的博客&#x1f431;。 記錄學習點滴。分享工作思考和實用技巧&#xff0c;偶爾也分享一些雜談&#x1f4ac;。 有很多很多不足的地方&#xff0c;歡迎評論交流&#xff0c;感謝您的閱讀和評論&#x1f604;。 目錄引言1 雙指針&#xff1a;Two Pointers1.1 左右指…

使用cookiecutter創建python項目

一、關于Python項目結構Python 項目并沒有完全統一的 “固定結構”&#xff0c;但行業內有一些廣泛遵循的約定俗成的目錄結構&#xff08;尤其針對可分發的包或大型項目&#xff09;。同時&#xff0c;確實有工具可以快速生成這些標準化結構&#xff0c;提高開發效率&#xff0…

臺積電生態工程深度解析:從晶圓廠到蜂巢的系統架構遷移

當半導體巨頭將工廠視為生態系統&#xff0c;用工程思維解決環境問題概述&#xff1a;生態系統的工程化再造臺積電近日開展的"積蜜"項目絕非簡單的企業CSR行為&#xff0c;而是一場將生態系統視為復雜系統進行工程化改造的技術實踐。本文將從系統架構、數據監控、循環…

從零實現一個簡易計算器

最近在刷算法題時&#xff0c;遇到了實現計算器的問題。一開始覺得很簡單&#xff0c;但真正動手實現時才發現其中有很多細節需要考慮。今天就來分享一下我的實現思路和學到的經驗。問題分析我們需要實現一個能夠處理加減乘除四則運算的計算器&#xff0c;要正確處理運算符的優…

Actix-webRust Web框架入門教程

文章目錄引言Actix-web是什么&#xff1f;準備工作你的第一個Actix-web應用理解代碼結構處理請求和響應接收請求數據返回響應中間件 - 增強你的應用狀態管理和依賴注入實用示例&#xff1a;構建RESTful API測試你的Actix-web應用部署Actix-web應用結語額外資源引言 嘿&#xf…

若依框架前端通過 nginx docker 鏡像本地運行

1. 前言 項目運行過程圖&#xff1a;對于前端項目通過命令 npm run build 打包后&#xff0c;無法直接運行。存在如下錯誤&#xff1a;可以通過配置 nginx 服務器運行前端項目解決如上問題。 2. Nginx 運行 采用 docker 鏡像的方式運行&#xff0c;docker-compose.yml 文件內容…

淺聊一下HTTP協議

在日常上網瀏覽網頁、刷視頻時&#xff0c;背后都離不開 HTTP 協議的支持。作為 Web 世界的 “交通規則”&#xff0c;它負責服務器和客戶端瀏覽器之間的數據傳輸。這篇文章就帶大家全面了解 HTTP 協議&#xff0c;從基本概念到通信細節&#xff0c;再到安全相關的 HTTPS&#…

機器人控制器開發(定位——cartographer ros2 使用2)

文章總覽 1 純定位模式 當完成建圖后&#xff0c;會生成pbstream格式的地圖文件 配置純定位模式的lua腳本 backpack_2d_localization.lua include "backpack_2d.lua"TRAJECTORY_BUILDER.pure_localization_trimmer {max_submaps_to_keep 3, } POSE_GRAPH.optimi…

《大數據之路1》筆記3:數據管理

一 元數據 1.1 元數據概述 定義&#xff1a; 元數據是關于數據的數據&#xff0c;元數據打通了源數據、數據倉庫、數據應用&#xff0c;記錄了數據從生產到消費的全部過程。元數據主要記錄數據倉庫中模型的定義、各層級間的映射關系、監控數據倉庫的數據狀態和ETL的任務運行狀態…

排序實現java

排序算法概述Java中實現排序可以通過多種方式&#xff0c;包括內置方法、自定義算法或使用第三方庫。常見的排序算法有冒泡排序、選擇排序、插入排序、快速排序、歸并排序等。使用Arrays.sort()方法對于數組排序&#xff0c;Java提供了Arrays.sort()方法&#xff0c;支持對基本…

51c大模型~合集182

我自己的原文哦~ https://blog.51cto.com/whaosoft/14174587 #LaV-CoT 超越GPT-4o&#xff0c;螞蟻集團與南洋理工大學提出&#xff1a;首個語言感知的視覺思維鏈 隨著大型視覺語言模型&#xff08;VLM&#xff09;的飛速發展&#xff0c;它們在處理復雜的視…

C++ STL之deque的使用和模擬實現

目錄 deque 核心本質與定位 與stack和queue的關系: deque的使用 deque的底層實現 deque的原理介紹 deque的缺陷 總結: deque deque文檔 : deque 翻譯: 雙端隊列 deque&#xff08;通常發音類似“deck”&#xff09;是“double-ended queue”&#xff08;雙端隊列&…

布草洗滌廠設備租賃押金原路退回系統—東方仙盟

設備租賃狀態設備管理添加設備設備收押金設備退押金在布草洗滌行業的運營版圖中&#xff0c;設備租賃是連接廠商與客戶的重要紐帶&#xff0c;而押金的收取與退還則是這一環節中關乎信任與效率的關鍵節點。未來之窗布草洗滌廠深諳此道&#xff0c;專為設備租賃業務打造的 “押金…

換源rocklinux和centos

一、Rockylinux換源&#xff0c;國外的源換成國內的源#nmcli connection modify ens33 ipv4.addresses 192.168.121.11 ipv4.gateway 192.168.121.2 ipv4.method manual ipv4.dns 114.114.114.114 connection.autoconnect yes修改地址#systemctl stop firewalld#systemctl diab…

第一部分:服務器硬件配置

目錄1.1 服務器上架與連線1.2 啟用CPU虛擬化功能&#xff08;BIOS設置&#xff09;1.3 配置RAID存儲步驟1&#xff1a;進入RAID配置界面步驟2&#xff1a;確認RAID控制器信息步驟3&#xff1a;創建系統RAID&#xff08;用于安裝ESXi&#xff09;步驟4&#xff1a;創建數據RAID&…

手搓一個 DELL EMC Unity存儲系統健康檢查清單

寫在前面對于DELL EMC存儲系統Unity的一些深度的健康檢查通過Web的Unisphere圖形化界面是做不到的&#xff0c;圖形化界面只能看到是否有告警&#xff0c;物理的東西是否有問題的&#xff0c;邏輯的Pool和LUN等是否ready&#xff0c;再深入的潛在的問題是查不到的。另外&#x…

【數據結構】二叉樹的概念

01 概念定義&#xff1a;二叉樹既然叫二叉樹&#xff0c;顧名思義即度最大為2的樹稱為二叉樹。 它的度可以為 1 也可以為 0&#xff0c;但是度最大為 2 。 一顆二叉樹是節點的一個有限集合&#xff0c;該集合&#xff1a;① 由一個根節點加上兩棵被稱為左子樹和右子樹的二叉樹組…

【RK3576】【Android14】如何在Android14下單獨編譯kernel-6.1?

單獨編譯kernel依賴如下幾個源碼&#xff1a;【交叉編譯工具鏈】prebuilts/clang/host/linux-x86/clang-r487747c【內核源碼】kernel-6.1為什么Android下編譯內核使用clang作為交叉編譯工具鏈而不是GCC&#xff1f;Android 14 選擇使用預置的 Clang 工具鏈&#xff08;如 clang…

什么是Redis的Pipeline

介紹Redis的Pipeline是一種網絡優化技術&#xff0c;在沒有Pipeline的時候&#xff0c;客戶端往redis發送請求&#xff0c;客戶端需要等到redis響應之后才能發送下一個請求。而Pipeline&#xff0c;使redis可以一次性接收多個請求。減少了通信次數&#xff0c;顯著的提高了性能…