IMX6ULL學(xué)習(xí)筆記(15)——GPIO輸出接口使用(官方SDK方式)

一、GPIO簡(jiǎn)介

i.MX6ULL 芯片的 GPIO 被分成 5 組,并且每組 GPIO 的數(shù)量不盡相同,例如 GPIO1 擁有 32 個(gè)引腳, GPIO2 擁有 22 個(gè)引腳, 其他 GPIO 分組的數(shù)量以及每個(gè) GPIO 的功能請(qǐng)參考 《i.MX 6UltraLite Applications Processor Reference Manual》 第26章General Purpose Input/Output (GPIO)(P1133)。


通過(guò) GPIO 硬件結(jié)構(gòu)框圖,就可以從整體上深入了解 GPIO 外設(shè)及它的各種應(yīng)用模式。

1.1 IO命名

打開 i.MX6ULL 參考手冊(cè)的第 32 章“Chapter 32: IOMUX Controller(IOMUXC)”


i.MX6ULL 的 IO 分為兩類:SNVS 域的和通用的,這兩類 IO 本質(zhì)上都是一樣的。

“IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00”的就是 GPIO 命名,命名形式就是“IOMUXC_SW_MUC_CTL_PAD_XX_XX”,后面的“XX_XX”就是 GPIO 命名,比如:GPIO1_IO01、UART1_TX_DATA、JTAG_MOD 等等。他是 根據(jù)某個(gè) IO 所擁有的功能來(lái)命名的。比如我們一看到 GPIO1_IO01 就知道這個(gè)肯定能做 GPIO,看到 UART1_TX_DATA 肯定就知道這個(gè) IO 肯定能做為 UART1 的發(fā)送引腳。

IO 復(fù)用功能。 i.MX6ULL 除了 GPIO1_IO00~GPIO1_IO09 引腳外,其它 IO 也是可以復(fù)用為 GPIO 功能。同樣的,GPIO1_IO00~GPIO_IO09 也是可以復(fù)用為其它外設(shè)引腳。

1.2 IO復(fù)用

IOMUX 譯為 IO 復(fù)用選擇器。i.MX6ULL 的芯片每個(gè) GPIO 都通過(guò) IOMUX 支持多種功能, 例如一個(gè) IO 可用于網(wǎng)絡(luò)外設(shè) ENET 的數(shù)據(jù)接收引腳,也可以被配置成 PWM 外設(shè)的輸出引腳, 這樣的設(shè)計(jì)大大增加了芯片的適用性,這樣可選的功能就是由 IOMUX 實(shí)現(xiàn)的。IOMUX 相當(dāng)于增加了多根內(nèi)部信號(hào)線與 IO 引腳相連,最多有 8 根,也就是說(shuō)一個(gè) IO 最多可支持 8 種可選的功能

以“IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00”這個(gè) IO 為例,打開參考手冊(cè)的 1568 頁(yè)。



可以看到有個(gè)名為:IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00 的寄存器,寄存器地址為 0X020E005C,這個(gè)寄存器是 32 位的,但是只用到了最低 5 位,其中 bit0~bit3(MUX_MODE) 就是設(shè)置 GPIO1_IO00 的復(fù)用功能的。GPIO1_IO00 一共可以復(fù)用為 9 種功能 IO,分別對(duì)應(yīng) ALT0~ALT8,其中 ALT5 就是作為 GPIO1_IO00。GPIO1_IO00 還可以作為 I2C2_SCL、GPT1_CAPTURE1、ANATOP_OTG1_ID 等。

1.3 IO配置

IOMUX 由其左側(cè)的 IOMUXC 控制(C表示Controler),IOMUXC 提供寄存器給用戶進(jìn)行配置, 它又分成 MUX Mode(IO模式控制) 以及 Pad Settings(Pad配置) 兩個(gè)部分:

在 IOMUXC 外設(shè)中關(guān)于 MUX Mode 和 Pad Settings 寄存器命名格式如下:

IOMUXC控制類型 寄存器名稱
MUX Mode IOMUXC_SW_MUX_CTL_PAD_XXXX
Pad Settings IOMUXC_SW_PAD_CTL_PAD_XXXX

每個(gè)引腳都包含這兩個(gè)寄存器,表中的XXXX表示引腳的名字

1.3.1 MUX Mode配置

MUX Mode 就是用來(lái)配置引腳的復(fù)用功能,即選擇引腳具體是用于網(wǎng)絡(luò)外設(shè) ENET 的數(shù)據(jù)接收, 還是用于 PWM 外設(shè)的輸出引腳,當(dāng)然,也可以配置成普通的 IO 口,僅用于控制輸出高低電平。

以 GPIO1_IO04 引腳為例對(duì) MUX 寄存器進(jìn)行說(shuō)明,該引腳相應(yīng)的 MUX 寄存器在參考手冊(cè)中的描述如下:

該寄存器主要有兩個(gè)配置域,分別是 SIONMUX_MODE

  • SION: 用于設(shè)置引腳在輸出模式下同時(shí)開啟輸入通道。
  • MUX_MODE: 使用 4 個(gè)寄存器位表示可選的 ALT0~ALT7 這 8 個(gè)模式。
    • 如 ALT2 模式就是用于 USB 外設(shè)的 USB_OTG1_PWR 信號(hào);
    • 若配置為 ALT5 則引腳會(huì)用作普通的 GPIO 功能, 用于輸出高、低電平。

1.3.2 Pad Settings配置

Pad Settings 用于配置引腳的屬性,例如驅(qū)動(dòng)能力,是否使用上下拉電阻, 是否使用保持器,是否使用開漏模式以及使用施密特模式還是CMOS模式等。

以 GPIO1_IO04 引腳中 PAD 寄存器在參考手冊(cè)中的描述如下:

相對(duì)來(lái)說(shuō) PAD 寄存器的配置項(xiàng)就更豐富了,而且圖中僅是該寄存器的部分說(shuō)明,如 HYS 設(shè)置使用施密特模式的滯后功能,PUS 配置上下拉電阻的阻值, 其它的還包含PUE、PKE、ODE、SPEED、DSE 及 SRE 的配置。

1.3.3 PAD(可跳過(guò)不看)

PAD 代表了一個(gè) i.MX6ULL 的 GPIO 引腳。在它的左側(cè)是一系列信號(hào)通道及控制線,如 input_on 控制輸入開關(guān),Dir 控制引腳的輸入輸出方向,Data_out 控制引腳輸出高低電平,Data_in 作為信號(hào)輸入,這些信號(hào)都經(jīng)過(guò)一個(gè) IOMUX 的器件連接到左側(cè)的寄存器。

①PAD引腳
代表一個(gè)i.MX6ULL的引腳。
②輸出緩沖區(qū)
當(dāng)輸出緩沖區(qū)使能時(shí),引腳被配置為輸出模式。在輸出緩沖區(qū)中,又包含了如下的屬性配置:

  • DSE驅(qū)動(dòng)能力
    當(dāng)IO用作輸出的時(shí)候用來(lái)設(shè)置IO的驅(qū)動(dòng)能力。DSE可以調(diào)整芯片內(nèi)部與引腳串聯(lián)電阻R0的大小,從而改變引腳的驅(qū)動(dòng)能力。例如,R0的初始值為260歐姆,在3.3V電壓下其電流驅(qū)動(dòng)能力為12.69mA,通過(guò)DSE可以把R0的值配置為原值的1/2、1/3…1/7等。

    位設(shè)置 速度
    000 輸出驅(qū)動(dòng)關(guān)閉
    001 R0(3.3V 下 R0 是 260Ω,1.8V 下 R0 是 150Ω,接 DDR 的時(shí)候是 240Ω)
    010 R0/2
    011 R0/3
    100 R0/4
    101 R0/5
    110 R0/6
    111 R0/7
  • SRE壓擺率配置
    設(shè)置壓擺率。壓擺率是指電壓轉(zhuǎn)換速率,可理解為電壓由波谷升到波峰的時(shí)間。增大壓擺率可減少輸出電壓的上升時(shí)間。i.MX6ULL的引腳通過(guò)SRE支持低速和高速壓擺率這兩種配置。當(dāng)此位為0的時(shí)候是低壓擺率,當(dāng)為1的時(shí)候是高壓擺率。壓擺率是大信號(hào)特性,下面的帶寬是小信號(hào)特性。

  • SPEED帶寬配置
    設(shè)置IO的帶寬。分別可設(shè)置為50MHz、100MHz以及200MHz。帶寬的意思是能通過(guò)這個(gè)IO口最高的信號(hào)頻率,通俗點(diǎn)講就是方波不失真,如果超過(guò)這個(gè)頻率方波就變正弦波。但是這個(gè)帶寬要區(qū)別于IO的翻轉(zhuǎn)速率,IO的翻轉(zhuǎn)速率的信號(hào)來(lái)自于GPIO這個(gè)外設(shè),而IO的帶寬只是限制了IO口引腳的物理特性,IO口的信號(hào)可以來(lái)自于內(nèi)部定時(shí)器輸出的PWM信號(hào),也可以來(lái)自于GPIO翻轉(zhuǎn)輸出的信號(hào),兩者相比之下,PWM信號(hào)的頻率是遠(yuǎn)遠(yuǎn)高于GPIO翻轉(zhuǎn)輸出的信號(hào)頻率。

    位設(shè)置 速度
    00 低速 50M
    01 中速 100M
    10 中速 100M
    11 最大速度 200M
  • ODE開漏輸出配置
    設(shè)置引腳是否工作在開漏輸出模式。在該模式時(shí)引腳可以輸出高阻態(tài)和低電平,此位為0的時(shí)候禁止開路輸出,當(dāng)此位為1的時(shí)候就使能開路輸出功能。輸出高阻態(tài)時(shí)可由外部上拉電阻拉至高電平。開漏輸出模式常用在一些通訊總線中,如I2C。

③輸入緩沖區(qū)
當(dāng)輸入緩沖區(qū)使能時(shí),引腳被配置為輸入模式。在輸入緩沖區(qū)中,又包含了如下的屬性配置:

  • HYS滯后使能
    用來(lái)使能遲滯比較器。i.MX6ULL的輸入檢測(cè)可以使用普通的CMOS檢測(cè)或施密特觸發(fā)器模式(滯后模式)。施密特觸發(fā)器具有滯后效應(yīng),對(duì)正向和負(fù)向變化的輸入信有不同的閾值電壓。如果需要對(duì)輸入波形進(jìn)行整形的話可以使能此位。此位為0的時(shí)候禁止遲滯比較器,為1的時(shí)候使能遲滯比較器。常被用于電子開關(guān)、波形變換等場(chǎng)合,其轉(zhuǎn)換特性和對(duì)比如下,如檢測(cè)按鍵時(shí),使用施密特模式即可起到消抖的功能。

④Pull/Keeper上下拉、保持器
引腳的控制邏輯中還包含了上下拉、保持器的功能。芯片內(nèi)部的上拉和下拉電阻可以將不確定的信號(hào)鉗位在高、低電平,或小幅提高的電流輸出能力,上拉提供輸出電流,下拉提供輸入電流。注意這些上下拉配置只是弱拉,對(duì)于類似I2C之類的總線,還是必須使用外部上拉電阻。i.MX6ULL芯片的電源模塊中包含轉(zhuǎn)換器,當(dāng)轉(zhuǎn)換器停止工作時(shí),保持器會(huì)保持輸入輸出電壓。

上下拉、保持器可以通過(guò)如下屬性配置:

  • PUS上下拉配置
    設(shè)置上下拉電阻。PUS可配置項(xiàng)可選為100K歐下拉以及22K歐、47K歐及100K歐上拉。
    位設(shè)置 含義
    00 100K 下拉
    01 47K 上拉
    10 100K 上拉
    11 22K 上拉
  • PUE上下拉、保持器選擇
    上下拉功能和保持器功能是二選一的,可以通過(guò)PUE來(lái)選擇。當(dāng)IO作為輸入的時(shí)候,這個(gè)位用來(lái)設(shè)置 IO 使用上下拉還是狀態(tài)保持器。當(dāng)為0的時(shí)候使用狀態(tài)保持器,當(dāng)為1的時(shí)候使用上下拉。狀態(tài)保持器在IO作為輸入的時(shí)候才有用,顧名思義,就是當(dāng)外部電路斷電以后此IO口可以保持住以前的狀態(tài)。
  • PKE上下拉、保持器配置
    用來(lái)使能或者禁止上下拉/狀態(tài)保持器功能。為0時(shí)禁止上下拉/狀態(tài)保持器,為1時(shí)使能上下拉和狀態(tài)保持器。

注意,當(dāng)引腳被配置為輸出模式時(shí),不管上下拉、保持器是什么配置,它們都會(huì)被關(guān)閉。

1.4 GPIO配置

GPIO 模塊是每個(gè) IO 都具有的外設(shè),它具有 IO 控制最基本的功能,如輸出高低電平、檢測(cè)電平輸入等。 它也占用 IOMUX 分配的復(fù)用信號(hào),也就是說(shuō)使用 GPIO 模塊功能時(shí)同樣需要使用 IOMUX 選中 GPIO 外設(shè),對(duì)其 GPIO 的功能進(jìn)行配置。


1.4.1 GDIR方向寄存器

設(shè)置某個(gè) IO 的工作方向。控制一個(gè) GPIO 引腳時(shí),要先用 GDIR 方向寄存器配置該引腳用于輸出電平信號(hào)還是用作輸入檢測(cè)。 典型的例子是使用輸出模式可以控制LED燈的亮滅,輸入模式時(shí)可以用來(lái)檢測(cè)按鍵是否按下。

GDIR 寄存器的每一個(gè)數(shù)據(jù)位代表一個(gè)引腳的方向,對(duì)應(yīng)的位被設(shè)置為0時(shí)該引腳為輸入模式,被設(shè)置為1時(shí)該引腳為輸出模式。

例如,對(duì) GPIO1 的 GDIR 寄存器的 bit3 位被寫入為 1,那么 GPIO1.3 引腳的模式即為輸出。

1.4.2 DR數(shù)據(jù)寄存器

DR 數(shù)據(jù)寄存器直接代表了引腳的電平狀態(tài),它也使用 1 個(gè)數(shù)據(jù)位表示 1 個(gè)引腳的電平,每位用 1 表示高電平,用 0 表示低電平。

當(dāng) GDIR 方向寄存器設(shè)置引腳為輸出模式時(shí),寫入 DR 數(shù)據(jù)寄存器對(duì)應(yīng)的位即可控制該引腳輸出的電平狀態(tài), 如這時(shí) GPIO1 的 DR 寄存器的 bit4 被寫入為 1,則引腳為輸出高電平。

當(dāng) GDIR 方向寄存器設(shè)置引腳為輸入模式時(shí),讀取 DR 數(shù)據(jù)寄存器對(duì)應(yīng)的位即可獲取該引腳當(dāng)前的輸入電平狀態(tài),例如這里讀取 GPIO1 的DR寄存器的 bit4,得到該位的值為 0,表示當(dāng)前引腳的輸入狀態(tài)為低電平。


1.4.3 PSR引腳狀態(tài)寄存器

讀取相應(yīng)的位即可獲取對(duì)應(yīng)的 GPIO 的狀態(tài),也就是 GPIO 的高低電平值。PSR 引腳狀態(tài)寄存器相當(dāng)于 DR 寄存器的簡(jiǎn)化版,它僅在 GDIR 方向寄存器設(shè)置為輸入模式時(shí)有效,它的每個(gè)位表示一個(gè)引腳當(dāng)前的輸入電平狀態(tài)。PSR 寄存器的權(quán)限是只讀的,對(duì)它進(jìn)行寫操作是無(wú)效的。

特別地,當(dāng)引腳被配置成輸出模式時(shí),若 IOMUXC 中的 MUX 寄存器使能了 SION 功能(輸出通道回環(huán)至輸入), 可以通過(guò) PSR 寄存器讀取回引腳的狀態(tài)值。

二、引腳確定

我使用的是 野火_EBF6ULL S1 Pro 開發(fā)板


從原理圖可看到 RGB 燈的三個(gè)陰極 R、G、B 連接分別連接至標(biāo)號(hào) GPIO_4、CSI_HSYNCCSI_VSYNC, 這些標(biāo)號(hào)實(shí)際上與配套核心板上 i.MX6ULL 芯片的引腳相連。由于引腳功能眾多, 繪制原理圖時(shí)不可避免地?zé)o法完全表示引腳信息的所有信息。而無(wú)論是具體的引腳名還是復(fù)用功能, 我們都無(wú)法直接得知這些具體是 i.MX6ULL 芯片的哪個(gè)引腳。我們需要知道這些引腳是對(duì)應(yīng)的具體 GPIO,這樣我們才能編寫程序進(jìn)行控制。

由于還不清楚標(biāo)號(hào) GPIO_4CSI_HSYNC、CSI_VSYNC 的具體引腳名,我們首先要在核心板原理圖中查看它與 i.MX6ULL 芯片的關(guān)系。打開 《野火_EBF6ULL S1 郵票孔核心板V1.0原理圖》,在PDF閱讀器的搜索框輸入前面的 GPIO_4CSI_HSYNC、CSI_VSYNC 標(biāo)號(hào)。


查找到了 GPIO_4 信號(hào)的具體引腳名為 GPIO1_IO04。 但是當(dāng)我們使用同樣的方法查找時(shí)發(fā)現(xiàn)只能找到 CSI_HSYNC、CSI_VSYNC, 并沒有我們熟悉的 GPIOx_IOx 標(biāo)注的引腳名。這兩個(gè)引腳默認(rèn)情況下不用作 GPIO,而是用作攝像頭的某一功能引腳,但是它可以復(fù)用為 GPIO,我們?cè)趺凑业綄?duì)應(yīng)的 GPIO 呢?

  • 方法一:
    《i.MX 6UltraLite Applications Processor Reference Manual》的第4章 External Signals and Pin Multiplexing 搜索引腳名

  • 方法二:
    在官方寫好的文件 fsl_iomuxc.h(路徑:SDK文件夾/devices/MCIMX6Y2/drivers/fsl_iomuxc.h) 中搜索引腳名

經(jīng)查閱,我們把以上連接 LED 燈的各個(gè) i.MX6ULL 芯片引腳總結(jié)出如表:

LED燈 原理圖的標(biāo)號(hào) 具體引腳名 GPIO端口及引腳編號(hào)
R燈 GPIO_4 GPIO1_IO04 GPIO1_IO04
G燈 CSI_HSYNC CSI_HSYNC GPIO4_IO20
B燈 CSI_VSYNC CSI_VSYNC GPIO4_IO19

三、編程流程

1. 移植官方寄存器定義文件
2. 移植官方SDK引腳復(fù)用和引腳屬性定義文件
3. 移植野火PAD屬性配置文件
4. 編寫啟動(dòng)文件
5. 編寫鏈接文件
6. 編寫makefile文件
7. 編寫C語(yǔ)言代碼
(1) 開啟GPIO時(shí)鐘
(2) 設(shè)置引腳的復(fù)用功能以及引腳屬性
(3) 設(shè)置引腳方向以及輸出電平
(4) 查詢按鍵輸入控制LED

四、移植官方SDK寄存器定義文件

使用匯編語(yǔ)言和C語(yǔ)言實(shí)現(xiàn)點(diǎn)亮LED燈。需要自己查找、定義那么多寄存器。這樣做的缺點(diǎn)很明顯,易錯(cuò)、費(fèi)時(shí)、代碼可讀性差。NXP官方SDK中已經(jīng)將所有的寄存器以及所有可用引腳的復(fù)用功能定義好了。

添加官方SDK寄存器定義文件 MCIMX6Y2.h,位于 SDK_2.2_MCIM6ULL_EBF6ULL/devices/MCIMX6Y2 目錄下。

在官方SDK頭文件 MCIMX6Y2.h 文件多達(dá)4萬(wàn)多行,包含了i.MX6U芯片幾乎所有的寄存器定義以及中斷編號(hào)的定義。

這里只列 GPIO1相關(guān)寄存器 的部分代碼。其他寄存器定義與此類似。 添加這些定義之后我們就可以 直接使用 “GPIO1->DR” 語(yǔ)句操作GPIO1的DR寄存器。操作方法與STM32非常相似。

typedef struct {
   __IO uint32_t DR;     /**< GPIO data register, offset: 0x0 */
   __IO uint32_t GDIR;   /**< GPIO direction register, offset: 0x4 */
   __I  uint32_t PSR;    /**< GPIO pad status register, offset: 0x8 */
   __IO uint32_t ICR1;   /**< GPIO interrupt configuration register1,*/
   __IO uint32_t ICR2;   /**< GPIO interrupt configuration register2, */
   __IO uint32_t IMR;   /**< GPIO interrupt mask register, offset: 0x14 */
   __IO uint32_t ISR; /**< GPIO interrupt status register, offset: 0x18 */
   __IO uint32_t EDGE_SEL;/**< GPIO edge select register, offset: 0x1C */
} GPIO_Type;

/*********************以下代碼省略***************************8*/
/** Peripheral GPIO1 base address */
#define GPIO1_BASE                               (0x209C000u)
/** Peripheral GPIO1 base pointer */
#define GPIO1                                    ((GPIO_Type *)GPIO1_BASE)

五、移植官方SDK引腳復(fù)用和引腳屬性定義文件

添加官方SDK引腳復(fù)用和引腳屬性定義文件 fsl_iomuxc.h,位于 SDK_2.2_MCIM6ULL_EBF6ULL/devices/MCIMX6Y2/drivers 目錄下。

使用每一個(gè)引腳之前我們都要選擇引腳的復(fù)用功能以及引腳的pad屬性。在官方SDK的頭文件 fsl_iomuxc.h中定義了所有可用引腳以及這些引腳的所有復(fù)用功能,我們需要哪種復(fù)用功能只需要選擇即可,并且官方SDK中提供了初始化函數(shù)。

  • 定義引腳的復(fù)用功能
    這里只列出了“GPIO1_IO00”引腳的復(fù)用功能,其他引腳類似。每個(gè)引腳對(duì)應(yīng)多個(gè)宏定義代表引腳的不同的復(fù)用功能,以宏“IOMUXC_GPIO1_IO00_I2C2_SCL”為例,它表示“GPIO1_IO00”引腳復(fù)用為“I2C2”的“SCL”引腳。這些宏定義將會(huì)用作某些函數(shù)的入口參數(shù)。
#define IOMUXC_GPIO1_IO00_I2C2_SCL \
                        0x020E005CU, 0x0U, 0x020E05ACU, 0x1U, 0x020E02E8U
#define IOMUXC_GPIO1_IO00_GPT1_CAPTURE1L \
                        0x020E005CU, 0x1U, 0x020E058CU, 0x0U, 0x020E02E8U
#define IOMUXC_GPIO1_IO00_ANATOP_OTG1_IDL   \
                        0x020E005CU, 0x2U, 0x020E04B8U, 0x0U, 0x020E02E8U
#define IOMUXC_GPIO1_IO00_ENET1_REF_CLK1L  \
                        0x020E005CU, 0x3U, 0x020E0574U, 0x0U, 0x020E02E8U
#define IOMUXC_GPIO1_IO00_MQS_RIGHTL  \
                        0x020E005CU, 0x4U, 0x00000000U, 0x0U, 0x020E02E8U
#define IOMUXC_GPIO1_IO00_GPIO1_IO00L  \
                        0x020E005CU, 0x5U, 0x00000000U, 0x0U, 0x020E02E8U
#define IOMUXC_GPIO1_IO00_ENET1_1588_EVENT0_INL \
                        0x020E005CU, 0x6U, 0x00000000U, 0x0U, 0x020E02E8U
#define IOMUXC_GPIO1_IO00_SRC_SYSTEM_RESETL  \
                        0x020E005CU, 0x7U, 0x00000000U, 0x0U, 0x020E02E8U
#define IOMUXC_GPIO1_IO00_WDOG3_WDOG_BL   \
                        0x020E005CU, 0x8U, 0x00000000U, 0x0U, 0x020E02E8U
#define IOMUXC_GPIO1_IO01_I2C2_SDAL    \
                        0x020E0060U, 0x0U, 0x020E05B0U, 0x1U, 0x020E02ECU
#define IOMUXC_GPIO1_IO01_GPT1_COMPARE1L  \
                        0x020E0060U, 0x1U, 0x00000000U, 0x0U, 0x020E02ECU
#define IOMUXC_GPIO1_IO01_USB_OTG1_OCL    \
                        0x020E0060U, 0x2U, 0x020E0664U, 0x0U, 0x020E02ECU
  • 引腳復(fù)用功能設(shè)置函數(shù)
    IOMUXC_SetPinMux() 擁有6個(gè)入口參數(shù), 但是前五個(gè)是通過(guò)上面的宏定義自動(dòng)完成設(shè)置的。而第6個(gè)入口參數(shù)“inputOnfiled”用于設(shè)置是否開啟讀回引腳電平功能。
static inline void IOMUXC_SetPinMux(uint32_t muxRegister,
                                    uint32_t muxMode,
                                    uint32_t inputRegister,
                                    uint32_t inputDaisy,
                                    uint32_t configRegister,
                                    uint32_t inputOnfield)
{
   *((volatile uint32_t *)muxRegister) =
                  IOMUXC_SW_MUX_CTL_PAD_MUX_MODE(muxMode) |\
                  IOMUXC_SW_MUX_CTL_PAD_SION(inputOnfield);

   if (inputRegister)
   {
      *((volatile uint32_t *)inputRegister) = \
      IOMUXC_SELECT_INPUT_DAISY(inputDaisy);
   }
}
  • 引腳PAD屬性設(shè)置函數(shù)
    IOMUXC_SetPinConfig() 函數(shù)共有6個(gè)入口參數(shù),其中前五個(gè)是通過(guò)上面的宏定義自動(dòng)完成設(shè)置的。而第6個(gè)參數(shù)用于設(shè)置PAD屬性,根據(jù)每個(gè)引腳擁有一個(gè)32位PAD屬性寄存器。第六個(gè)參數(shù)就是設(shè)置要填入PAD屬性寄存器的值。
static inline void IOMUXC_SetPinConfig(uint32_t muxRegister,
                                       uint32_t muxMode,
                                       uint32_t inputRegister,
                                       uint32_t inputDaisy,
                                       uint32_t configRegister,
                                       uint32_t configValue)
{
   if (configRegister)
   {
      *((volatile uint32_t *)configRegister) = configValue;
   }
}

代碼屏蔽 #include "fsl_common.h"

六、移植野火PAD屬性配置文件

添加 pad_config.h。

通常情況下一個(gè)引腳要設(shè)置8種PAD屬性,而這些屬性只能通過(guò)數(shù)字指定。為簡(jiǎn)化PAD屬性設(shè)置野火編寫了一個(gè)PAD屬性配置文件 pad_config.h (embed_linux_driver_tutorial_imx6_code/bare_metal/led_rgb_c/pad_config.h)【源碼下載:https://gitee.com/Embedfire/embed_linux_driver_tutorial_imx6_code.git】,這里使用宏定義了引腳可選的PAD屬性值,并且通過(guò)宏定義的名字很容易知道宏代表的屬性值:

/* SPEED 帶寬配置 */
#define SPEED_0_LOW_50MHz       IOMUXC_SW_PAD_CTL_PAD_SPEED(0)
#define SPEED_1_MEDIUM_100MHz   IOMUXC_SW_PAD_CTL_PAD_SPEED(1)
#define SPEED_2_MEDIUM_100MHz   IOMUXC_SW_PAD_CTL_PAD_SPEED(2)
#define SPEED_3_MAX_200MHz      IOMUXC_SW_PAD_CTL_PAD_SPEED(3)


/* PUE 選擇使用保持器還是上下拉 */
#define PUE_0_KEEPER_SELECTED       IOMUXC_SW_PAD_CTL_PAD_PUE(0)
#define PUE_1_PULL_SELECTED         IOMUXC_SW_PAD_CTL_PAD_PUE(1)


/* PUS 上下拉配置 */
#define PUS_0_100K_OHM_PULL_DOWN  IOMUXC_SW_PAD_CTL_PAD_PUS(0)
#define PUS_1_47K_OHM_PULL_UP     IOMUXC_SW_PAD_CTL_PAD_PUS(1)
#define PUS_2_100K_OHM_PULL_UP    IOMUXC_SW_PAD_CTL_PAD_PUS(2)
#define PUS_3_22K_OHM_PULL_UP     IOMUXC_SW_PAD_CTL_PAD_PUS(3)

完整的代碼請(qǐng)閱讀源文件,這里只列出了文件“pad_config.h”部分代碼(embed_linux_driver_tutorial_imx6_code/bare_metal/led_rgb_c/pad_config.h)【源碼下載:https://gitee.com/Embedfire/embed_linux_driver_tutorial_imx6_code.git】。

七、編寫啟動(dòng)文件

在 Ubuntu 下創(chuàng)建 start.S 文件用于編寫啟動(dòng)文件。
在匯編文件中設(shè)置“棧地址”并執(zhí)行跳轉(zhuǎn)命令跳轉(zhuǎn)到main函數(shù)執(zhí)行C代碼。

7.1 完整代碼

/***********************第一部分*********************/
  .text            //代碼段
  .align 2         //設(shè)置2字節(jié)對(duì)齊
  .global _start   //定義一個(gè)全局標(biāo)號(hào)

/*************************第二部分*************************/
  _start:          //程序的開始
    b reset      //跳轉(zhuǎn)到reset標(biāo)號(hào)處

/*************************第三部分*************************/
reset:
   mrc     p15, 0, r0, c1, c0, 0     /*  將 CP15 協(xié)處理器中的寄存器數(shù)據(jù)讀到 ARM 寄存器中   */
   bic     r0,  r0, #(0x1 << 12)     /*  清除第12位(I位)禁用 I Cache  */
   bic     r0,  r0, #(0x1 <<  2)     /*  清除第 2位(C位)禁用 D Cache  */
   bic     r0,  r0, #0x2             /*  清除第 1位(A位)禁止嚴(yán)格對(duì)齊   */
   bic     r0,  r0, #(0x1 << 11)     /*  清除第11位(Z位)分支預(yù)測(cè)   */
   bic     r0,  r0, #0x1             /*  清除第 0位(M位)禁用 MMU   */
   mcr     p15, 0, r0, c1, c0, 0     /*  將 ARM 寄存器的數(shù)據(jù)寫入到 CP15 協(xié)處理器寄存器中   */

/***********************第四部分*********************/
      ldr sp, =0x84000000   //設(shè)置棧地址64M
      b main                //跳轉(zhuǎn)到main函數(shù)

/***********************第五部分*******************/
    /*進(jìn)入死循環(huán)*/
  loop:
      b loop

7.2 分析代碼

  • 第一部分
    .text 定義代碼段。
    .align 2 設(shè)置字節(jié)對(duì)齊。
    .global _start 生命全局標(biāo)號(hào)_start。
/*************************第一部分*************************/
.text            //代碼段
.align 2         //設(shè)置2字節(jié)對(duì)齊
.global _start   //定義一個(gè)全局標(biāo)號(hào)
  • 第二部分
    _start: 定義標(biāo)號(hào)_start: ,它位于匯編的最前面,說(shuō)以會(huì)首先被執(zhí)行。
    b reset 使用b指令將程序跳轉(zhuǎn)到reset標(biāo)號(hào)處。
/*************************第二部分*************************/
_start:          //程序的開始
   b reset      //跳轉(zhuǎn)到reset標(biāo)號(hào)處
  • 第三部分
    通過(guò)修改CP15寄存器(系統(tǒng)控制寄存器) 關(guān)閉 I Cache 、D Cache、MMU 等等。
    我們暫時(shí)用不到的功能,如果開啟可能會(huì)影響我們裸機(jī)運(yùn)行,為避免不必要的麻煩暫時(shí)關(guān)閉這些功能。
/*************************第三部分*************************/
reset:
   mrc     p15, 0, r0, c1, c0, 0     /*  將 CP15 協(xié)處理器中的寄存器數(shù)據(jù)讀到 ARM 寄存器中   */
   bic     r0,  r0, #(0x1 << 12)     /*  清除第12位(I位)禁用 I Cache  */
   bic     r0,  r0, #(0x1 <<  2)     /*  清除第 2位(C位)禁用 D Cache  */
   bic     r0,  r0, #0x2             /*  清除第 1位(A位)禁止嚴(yán)格對(duì)齊   */
   bic     r0,  r0, #(0x1 << 11)     /*  清除第11位(Z位)分支預(yù)測(cè)   */
   bic     r0,  r0, #0x1             /*  清除第 0位(M位)禁用 MMU   */
   mcr     p15, 0, r0, c1, c0, 0     /*  將 ARM 寄存器的數(shù)據(jù)寫入到 CP15 協(xié)處理器寄存器中   */
  • 第四部分
    ldr sp, =0x84000000 用于設(shè)置棧指針。野火i.MX6ULL開發(fā)板標(biāo)配512M的DDR內(nèi)存,裸機(jī)開發(fā)用不了這么多。程序中我們將棧地址設(shè)置到DDR的64M地址處。 這個(gè)值也可以根據(jù)需要自行定義。
    b main 只用跳轉(zhuǎn)指令跳轉(zhuǎn)到main函數(shù)中執(zhí)行。
/***********************第四部分*********************/
      ldr sp, =0x84000000   //設(shè)置棧地址64M
      b main                //跳轉(zhuǎn)到main函數(shù)
  • 第五部分
    b loop 是“無(wú)返回”的跳轉(zhuǎn)指令。正常情況下,不會(huì)執(zhí)行第五部分代碼。
/***********************第五部分*******************/
  /*進(jìn)入死循環(huán)*/
  loop:
      b loop

八、編寫鏈接腳本

寫好的代碼(無(wú)論是匯編還是C語(yǔ)言)都要經(jīng)過(guò)編譯、匯編、鏈接等步驟生成二進(jìn)制文件或者可供下載的文件。在編譯階編譯器會(huì)對(duì)每個(gè)源文件進(jìn)行語(yǔ)法檢查并生成對(duì)應(yīng)的匯編語(yǔ)言,匯編是將匯編文件轉(zhuǎn)化為機(jī)器碼。

使用 arm-none-eabi-gcc -g -c led.S -o led.o 命令完成源碼的編譯、匯編工作,生成了 .o文件。編譯和匯編是針對(duì)單個(gè)源文件,也就編譯完成后一個(gè)源文件(.c,.S.s)對(duì)應(yīng)一個(gè) .o 文件。程序鏈接階段就會(huì)將這些 .o 鏈接成一個(gè)文件。

鏈接腳本的作用就是告訴編譯器怎么鏈接這些文件,比如那個(gè)文件放在最前面,程序的代碼段、數(shù)據(jù)段、bss段分別放在什么位置等等。

在 Ubuntu 下創(chuàng)建 led.lds 鏈接腳本。

8.1 完整代碼

 ENTRY(_start)
 SECTIONS {
   . = 0x80000000;

   . = ALIGN(4);
   .text :
   {
   start.o (.text)
   *(.text)
   }

   . = ALIGN(4);
   .data :
   {
   *(.data)
   }

   . = ALIGN(4);
   .bss :
   {
   *(.bss)
   }
 }

8.2 分析代碼

  • 指定程序的入口
    ENTRY(_start) 用于指定程序的入口,ENTRY() 是設(shè)置入口地址的命令, “_start” 是程序的入口,led程序的入口地址位于 start.S“_start” 標(biāo)號(hào)處。
 ENTRY(_start)
  • 定義SECTIONS
    SECTIONS 可以理解為是一塊區(qū)域,我們?cè)谶@塊區(qū)域排布我們的代碼,鏈接時(shí)鏈接器就會(huì)按照這里的指示鏈接我們的代碼。
 SECTIONS {
···
···
}
  • 定義鏈接起始地址
    “.” 運(yùn)算符代表當(dāng)前位置。 我們?cè)赟ECTION的最開始使用 “.= 0x80000000” 就是將鏈接起始地址設(shè)置為0x80000000。
. = 0x80000000;
  • 設(shè)置字節(jié)對(duì)齊
    “. = ALIGN(4);” 它表示從當(dāng)前位置開始執(zhí)行四字節(jié)對(duì)齊。假設(shè)當(dāng)前位置為0x80000001,執(zhí)行該命令后當(dāng)前地址將會(huì)空出三個(gè)字節(jié)轉(zhuǎn)到0x80000004地址處。

  • 設(shè)置代碼段
    “.text :” 用于定義代碼段,固定的語(yǔ)法要求,我們按照要求寫即可。在“{}”中指定那些內(nèi)容放在代碼段。
    start.o 中的代碼放到代碼段的最前面。start.S是啟動(dòng)代碼應(yīng)當(dāng)首先被執(zhí)行,所以通常情況下要把它放到代碼段的最前面,其他源文件的代碼按照系統(tǒng)默認(rèn)的排放順序即可,通配符 “*” 在這里表示其他剩余所有的 .o文件。

   . = ALIGN(4);
   .text :
   {
   start.o (.text)
   *(.text)
   }
  • 設(shè)置數(shù)據(jù)段
    同設(shè)置代碼段類似,首先設(shè)置字節(jié)對(duì)齊,然后定義代碼段。在數(shù)據(jù)段里使用 “*” 通配符, 將所有源文件中的代碼添加到這個(gè)數(shù)據(jù)段中。
   . = ALIGN(4);
   .data :
   {
   *(.data)
   }
  • 設(shè)置BSS段
    設(shè)置方法與設(shè)置數(shù)據(jù)段完全相同。
. = ALIGN(4);
   .bss :
   {
   *(.bss)
   }

九、編寫makefile文件

程序編寫完成后需要依次輸入編譯、鏈接、格式轉(zhuǎn)換命令才能最終生成二進(jìn)制文件。這種編譯方式效率低、容易出錯(cuò)。

使用makefile只需要在所在文件夾下執(zhí)行make命令,makefile工具便會(huì)自動(dòng)完成程序的編譯、鏈接、格式轉(zhuǎn)換等工作。正常情況下我們可以在當(dāng)前目錄看到生成的一些中間文件以及我們期待的.bin文件。

在 Ubuntu 下創(chuàng)建 makefile 文件。

9.1 完整代碼

 all: start.o led.o
    arm-none-eabi-ld -Tled.lds  $^ -o led.elf
    arm-none-eabi-objcopy -O binary -S -g led.elf led.bin

  %.o : %.S
    arm-none-eabi-gcc -g -c $^ -o start.o
  %.o : %.c
    arm-none-eabi-gcc -g -c $^ -o led.o


  .PHONY: clean
  clean:
    rm *.o *.elf *.bin

9.2 分析代碼

  • 添加最終目標(biāo)以及依賴文件
 all: start.o led.o
  • 添加鏈接命令
    “-Tled.lds” 表示使用led.lds鏈接腳本鏈接程序。
    “$^” 代表所有的依賴文件。
    “-o” 指定輸出文件名。
    arm-none-eabi-ld -Tled.lds  $^ -o led.elf
  • 添加格式轉(zhuǎn)換命令
    “-O binary” 指定輸出二進(jìn)制文件。
    “-S” 不從源文件中復(fù)制重定位信息和符號(hào)信息。
    “-g” 不從源文件中復(fù)制可調(diào)試信息。
    arm-none-eabi-objcopy -O binary -S -g led.elf led.bin
  • 添加匯編文件編譯命令
    “$^” 替代要編譯的源文件。
  %.o : %.S
    arm-none-eabi-gcc -g -c $^ -o start.o
  • 添加編譯C文件的命令
    “$^” 替代要編譯的源文件。
  %.o : %.c
    arm-none-eabi-gcc -g -c $^ -o led.o
  • 添加清理命令
    “.PHONY” 定義了偽目標(biāo)“clean”。偽目標(biāo)一般沒有依賴,并且 “clean” 偽目標(biāo)一般放在Makefile文件的末尾。
    “clean” 為目標(biāo)用于刪除make生成的文件。
  .PHONY: clean
  clean:
    rm *.o *.elf *.bin

十、編寫C語(yǔ)言代碼

在 Ubuntu 下創(chuàng)建 led.c 文件用于驅(qū)動(dòng) RGB 燈。

10.1 完整代碼

 /*************************第一部分************************/
  #include "MCIMX6Y2.h"
  #include "fsl_iomuxc.h"
  #include "pad_config.h"

  /*************************第二部分************************/
  /*LED GPIO端口、引腳號(hào)及IOMUXC復(fù)用宏定義*/
  #define RGB_RED_LED_GPIO                GPIO1
  #define RGB_RED_LED_GPIO_PIN            (4U)
  #define RGB_RED_LED_IOMUXC              IOMUXC_GPIO1_IO04_GPIO1_IO04

  #define RGB_GREEN_LED_GPIO              GPIO4
  #define RGB_GREEN_LED_GPIO_PIN          (20U)
  #define RGB_GREEN_LED_IOMUXC            IOMUXC_CSI_HSYNC_GPIO4_IO20

  #define RGB_BLUE_LED_GPIO               GPIO4
  #define RGB_BLUE_LED_GPIO_PIN           (19U)
  #define RGB_BLUE_LED_IOMUXC             IOMUXC_CSI_VSYNC_GPIO4_IO19


  /*************************第三部分************************/
  /* 所有引腳均使用同樣的PAD配置 */
  #define LED_PAD_CONFIG_DATA            (SRE_0_SLOW_SLEW_RATE| \
                                          DSE_6_R0_6| \
                                          SPEED_2_MEDIUM_100MHz| \
                                          ODE_0_OPEN_DRAIN_DISABLED| \
                                          PKE_0_PULL_KEEPER_DISABLED| \
                                          PUE_0_KEEPER_SELECTED| \
                                          PUS_0_100K_OHM_PULL_DOWN| \
                                          HYS_0_HYSTERESIS_DISABLED)
      /* 配置說(shuō)明 : */
      /* 轉(zhuǎn)換速率: 轉(zhuǎn)換速率慢
        驅(qū)動(dòng)強(qiáng)度: R0/6
        帶寬配置 : medium(100MHz)
        開漏配置: 關(guān)閉
        拉/保持器配置: 關(guān)閉
        拉/保持器選擇: 保持器(上面已關(guān)閉,配置無(wú)效)
        上拉/下拉選擇: 100K歐姆下拉(上面已關(guān)閉,配置無(wú)效)
        滯回器配置: 關(guān)閉 */

  /*************************第四部分************************/
  /*簡(jiǎn)單延時(shí)函數(shù)*/
  void delay(uint32_t count)
  {
      volatile uint32_t i = 0;
      for (i = 0; i < count; ++i)
      {
          __asm("NOP"); /* 調(diào)用nop空指令 */
      }
  }


  int main()
  {
      /*************************第五部分************************/
      CCM->CCGR1 |= CCM_CCGR1_CG13(0x3);//開啟GPIO1的時(shí)鐘
      CCM->CCGR3 |= CCM_CCGR3_CG6(0x3); //開啟GPIO4的時(shí)鐘

      /*************************第六部分************************/
      /*設(shè)置 紅燈 引腳的復(fù)用功能以及PAD屬性*/
      IOMUXC_SetPinMux(RGB_RED_LED_IOMUXC,0);
      IOMUXC_SetPinConfig(RGB_RED_LED_IOMUXC, LED_PAD_CONFIG_DATA);

      /*設(shè)置 綠燈 引腳的復(fù)用功能以及PAD屬性*/
      IOMUXC_SetPinMux(RGB_GREEN_LED_IOMUXC,0);
      IOMUXC_SetPinConfig(RGB_GREEN_LED_IOMUXC, LED_PAD_CONFIG_DATA);

      /*設(shè)置 藍(lán)燈 引腳的復(fù)用功能以及PAD屬性*/
      IOMUXC_SetPinMux(RGB_BLUE_LED_IOMUXC,0);
      IOMUXC_SetPinConfig(RGB_BLUE_LED_IOMUXC, LED_PAD_CONFIG_DATA);

      /*************************第七部分************************/
      GPIO1->GDIR |= (1<<4);  //設(shè)置GPIO1_04為輸出模式
      GPIO1->DR |= (1<<4);    //設(shè)置GPIO1_04輸出電平為高電平

      GPIO4->GDIR |= (1<<20);  //設(shè)置GPIO4_20為輸出模式
      GPIO4->DR |= (1<<20);    //設(shè)置GPIO4_20輸出電平為高電平

      GPIO4->GDIR |= (1<<19);  //設(shè)置GPIO4_19為輸出模式
      GPIO4->DR |= (1<<19);    //設(shè)置GPIO4_19輸出電平為高電平

      /*************************第八部分************************/
      while(1)
      {
           GPIO1->DR &= ~(1<<4); //紅燈亮
           delay(0xFFFFF);
           GPIO1->DR |= (1<<4); //紅燈滅

           GPIO4->DR &= ~(1<<20); //綠燈亮
           delay(0xFFFFF);
           GPIO4->DR |= (1<<20); //綠燈滅

           GPIO4->DR &= ~(1<<19); //藍(lán)燈亮
           delay(0xFFFFF);
           GPIO4->DR |= (1<<19); //藍(lán)燈滅
      }
      return 0;
  }

10.2 分析代碼

  • 第一部分:添加頭文件
    文件 “MCIMX6Y2.h”“fsl_iomuxc.h” 來(lái)自SDK。 文件 “pad_config.h” 是野火編寫的文件,在其他工程中可直接使用。
 /*************************第一部分************************/
  #include "MCIMX6Y2.h"
  #include "fsl_iomuxc.h"
  #include "pad_config.h"
  • 第二部分:定義GPIO相關(guān)引腳以及復(fù)用功能
  /*************************第二部分************************/
  /*LED GPIO端口、引腳號(hào)及IOMUXC復(fù)用宏定義*/
  #define RGB_RED_LED_GPIO                GPIO1
  #define RGB_RED_LED_GPIO_PIN            (4U)
  #define RGB_RED_LED_IOMUXC              IOMUXC_GPIO1_IO04_GPIO1_IO04

  #define RGB_GREEN_LED_GPIO              GPIO4
  #define RGB_GREEN_LED_GPIO_PIN          (20U)
  #define RGB_GREEN_LED_IOMUXC            IOMUXC_CSI_HSYNC_GPIO4_IO20

  #define RGB_BLUE_LED_GPIO               GPIO4
  #define RGB_BLUE_LED_GPIO_PIN           (19U)
  #define RGB_BLUE_LED_IOMUXC             IOMUXC_CSI_VSYNC_GPIO4_IO19
  • 第三部分:定義引腳的PAD屬性
    PAD屬性宏定義保存在 “pad_config.h” 文件中,這里使用 “|” 運(yùn)算符將所有屬性設(shè)置“合并”在一起,后面將作為函數(shù)參數(shù)。
  /*************************第三部分************************/
  /* 所有引腳均使用同樣的PAD配置 */
  #define LED_PAD_CONFIG_DATA            (SRE_0_SLOW_SLEW_RATE| \
                                          DSE_6_R0_6| \
                                          SPEED_2_MEDIUM_100MHz| \
                                          ODE_0_OPEN_DRAIN_DISABLED| \
                                          PKE_0_PULL_KEEPER_DISABLED| \
                                          PUE_0_KEEPER_SELECTED| \
                                          PUS_0_100K_OHM_PULL_DOWN| \
                                          HYS_0_HYSTERESIS_DISABLED)
      /* 配置說(shuō)明 : */
      /* 轉(zhuǎn)換速率: 轉(zhuǎn)換速率慢
        驅(qū)動(dòng)強(qiáng)度: R0/6
        帶寬配置 : medium(100MHz)
        開漏配置: 關(guān)閉
        拉/保持器配置: 關(guān)閉
        拉/保持器選擇: 保持器(上面已關(guān)閉,配置無(wú)效)
        上拉/下拉選擇: 100K歐姆下拉(上面已關(guān)閉,配置無(wú)效)
        滯回器配置: 關(guān)閉 */
  • 第四部分:簡(jiǎn)單的延時(shí)函數(shù)
 /*************************第四部分************************/
  /*簡(jiǎn)單延時(shí)函數(shù)*/
  void delay(uint32_t count)
  {
      volatile uint32_t i = 0;
      for (i = 0; i < count; ++i)
      {
          __asm("NOP"); /* 調(diào)用nop空指令 */
      }
  }
  • 第五部分:開啟GPIO時(shí)鐘
/*************************第五部分************************/
CCM->CCGR1 |= CCM_CCGR1_CG13(0x3);//開啟GPIO1的時(shí)鐘
CCM->CCGR3 |= CCM_CCGR3_CG6(0x3); //開啟GPIO4的時(shí)鐘
  • 第六部分:設(shè)置引腳的復(fù)用功能以及引腳PAD屬性
/*************************第六部分************************/
/*設(shè)置 紅燈 引腳的復(fù)用功能以及PAD屬性*/
IOMUXC_SetPinMux(RGB_RED_LED_IOMUXC,0);
IOMUXC_SetPinConfig(RGB_RED_LED_IOMUXC, LED_PAD_CONFIG_DATA);

/*設(shè)置 綠燈 引腳的復(fù)用功能以及PAD屬性*/
IOMUXC_SetPinMux(RGB_GREEN_LED_IOMUXC,0);
IOMUXC_SetPinConfig(RGB_GREEN_LED_IOMUXC, LED_PAD_CONFIG_DATA);

/*設(shè)置 藍(lán)燈 引腳的復(fù)用功能以及PAD屬性*/
IOMUXC_SetPinMux(RGB_BLUE_LED_IOMUXC,0);
IOMUXC_SetPinConfig(RGB_BLUE_LED_IOMUXC, LED_PAD_CONFIG_DATA);
  • 第七部分:設(shè)置GPIO為輸出并設(shè)置初始電平為高電平
/*************************第七部分************************/
GPIO1->GDIR |= (1<<4);  //設(shè)置GPIO1_04為輸出模式
GPIO1->DR |= (1<<4);    //設(shè)置GPIO1_04輸出電平為高電平

GPIO4->GDIR |= (1<<20);  //設(shè)置GPIO4_20為輸出模式
GPIO4->DR |= (1<<20);    //設(shè)置GPIO4_20輸出電平為高電平

GPIO4->GDIR |= (1<<19);  //設(shè)置GPIO4_19為輸出模式
GPIO4->DR |= (1<<19);    //設(shè)置GPIO4_19輸出電平為高電平
  • 第八部分:在while(1)中依次點(diǎn)亮紅燈、綠燈和藍(lán)燈
/*************************第八部分************************/
while(1)
{
  GPIO1->DR &= ~(1<<4); //紅燈亮
  delay(0xFFFFF);
  GPIO1->DR |= (1<<4); //紅燈滅

  GPIO4->DR &= ~(1<<20); //綠燈亮
  delay(0xFFFFF);
  GPIO4->DR |= (1<<20); //綠燈滅

  GPIO4->DR &= ~(1<<19); //藍(lán)燈亮
  delay(0xFFFFF);
  GPIO4->DR |= (1<<19); //藍(lán)燈滅
}

十一、編譯下載驗(yàn)證

11.1 編譯代碼

make

執(zhí)行make命令,生成led.bin文件。

11.2 代碼燒寫

編譯成功后會(huì)在當(dāng)前文件夾下生成.bin文件,這個(gè).bin文件也不能直接放到開發(fā)板上運(yùn)行, 這次是因?yàn)樾枰?bin文件缺少啟動(dòng)相關(guān)信息。

為二進(jìn)制文件添加頭部信息并燒寫到SD卡。查看 IMX6ULL學(xué)習(xí)筆記(12)——通過(guò)SD卡啟動(dòng)官方SDK程序

進(jìn)入燒寫工具目錄,執(zhí)行 ./mkimage.sh <燒寫文件路徑> 命令,例如要燒寫的 led.bin 位于 home 目錄下,則燒寫命令為 ./mkimage.sh /home/led.bin。

執(zhí)行上一步后會(huì)列出linux下可燒寫的磁盤,選擇你插入的SD卡即可。這一步 非常危險(xiǎn)?。?!一定要確定選擇的是你插入的SD卡??!,如果選錯(cuò)很可能破壞你電腦磁盤內(nèi)容,造成數(shù)據(jù)損壞?。。?確定磁盤后SD卡以“sd”開頭,選擇“sd”后面的字符即可。例如要燒寫的sd卡是“sdb”則輸入“b”即可。

11.3 實(shí)驗(yàn)現(xiàn)象

將開發(fā)板設(shè)置為SD卡啟動(dòng),接入SD卡,開發(fā)板上電,可以看到開發(fā)板上RGB紅、綠、藍(lán)三種顏色輪流閃爍。


? 由 Leung 寫于 2022 年 12 月 25 日

? 參考:6. 完善LED程序

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容