C語言LED燈
1、彙編檔案:C語言環境建構
2、C語言檔案:完成工程需要的功能
一、C語言運作環境建構
一、 設定處理器模式
設定6ULL處于SVC模式下,設定CPSR寄存器的bit4-0,即M[4:0]為10011 = 0X13。
讀寫狀态寄存器需要用到MRS和MSR指令。MRS将CPSR寄存器資料讀出到通用寄存器,MSR指令将通用寄存器的資料寫入到CPSR寄存器中。
二、 設定 SP 指針
SP指針可以指向内部RAM,也可以指向DDR,我們将其指向DDR。
SP指針設定到哪裡?DDR記憶體 512MB的範圍0X80000000~0X9FFFFFFF。棧設定大小,0X200000 = 2MB。處理器棧增長方式,對于A7而言是向下增長的(由高位址指向低位址),是以設定SP指針指向0X80200000。
三、 跳轉到C語言
使用b指令,跳轉到C語言函數,比如main函數。
二、 程式代碼
1、 彙編檔案,設定處理器模式以及SP指針
start.S
.global _start /* 全局标量 */
/*
描述: _start函數,程式從此函數開始執行,此函數主要功能是設定C運作環境
*/
_start:
/* 進入SVC模式 */
mrs r0, cpsr // 讀取cpsr的資料到r0
bic r0, r0, #0X1F // 将r0的低五位清零,即cpsr的M0~M4
orr r0, r0, #0X13 // r0或上0x13,表示使用SVC模式
msr cpsr, r0 // 将r0的資料寫入到cpsr_c中
ldr sp, = 0X80200000 // 設定棧指針
b main // 跳轉到C語言main函數
2、 驅動檔案
main.h
#ifndef __MAIN_H
#define __MAIN_H
/*
* 描述:
* 定義要使用的寄存器
*/
/* CCM 相關的寄存器位址 */
#define CCM_CCGR0 *((volatile unsigned int*)0X020C4068)
#define CCM_CCGR1 *((volatile unsigned int*)0X020C406C)
#define CCM_CCGR2 *((volatile unsigned int*)0X020C4070)
#define CCM_CCGR3 *((volatile unsigned int*)0X020C4074)
#define CCM_CCGR4 *((volatile unsigned int*)0X020C4078)
#define CCM_CCGR5 *((volatile unsigned int*)0X020C407C)
#define CCM_CCGR6 *((volatile unsigned int*)0X020C4080)
/* IOMUX 相關寄存器位址 */
#define SW_MUX_GPIO1_IO03 *((volatile unsigned int*)0X020E0068)
#define SW_PAD_GPIO1_IO03 *((volatile unsigned int*)0X020E02F4)
/* GPIO1 相關寄存器位址 */
#define GPIO1_DR *((volatile unsigned int*)0X0209C000)
#define GPIO1_GDIR *((volatile unsigned int*)0X0209C004)
#define GPIO1_PSR *((volatile unsigned int*)0X0209C008)
#define GPIO1_ICR1 *((volatile unsigned int*)0X0209C00C)
#define GPIO1_ICR2 *((volatile unsigned int*)0X0209C010)
#define GPIO1_IMR *((volatile unsigned int*)0X0209C014)
#define GPIO1_ISR *((volatile unsigned int*)0X0209C018)
#define GPIO1_EDGE_SEL *((volatile unsigned int*)0X0209C01C)
#endif
main.c
#include "main.h"
/**********************************
* 函數名稱: void clk_enable(void)
* 函數功能: 使能外設時鐘
* 輸入 : 無
* 輸出 : 無
***********************************/
void clk_enable(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)
* 函數功能: 初始化LED
* 輸入 : 無
* 輸出 : 無
***********************************/
void LED_Init(void)
{
/* 初始化IO複用,複用為GPIO1_IO3 */
SW_MUX_GPIO1_IO03 = 0X5;
/* 設定GPIO1——IO3 電氣屬性 */
/***************************
*bit 16:0 HYS關閉
*bit [15:14]: 00 預設下拉
*bit [13]: 0 kepper功能
*bit [12]: 1 pull/keeper使能
*bit [11]: 0 關閉開路輸出
*bit [7:6]: 10 速度100Mhz
*bit [5:3]: 110 R0/6驅動能力
*bit [0]: 0 低轉換率
****************************/
SW_PAD_GPIO1_IO03 = 0X10B0;
/* 初始化GPIO,GPIO1_IO3設定為輸出 */
GPIO1_GDIR = 0X00000008;
/* 設定GPIO1_IO3輸出低電平,打開LED燈 */
GPIO1_DR = 0X0;
}
/**********************************
* 函數名稱: void delay_short(volatile unsigned int n)
* 函數功能: 短延時
* 輸入 : volatile unsigned int n
* 輸出 : 無
***********************************/
void delay_short(volatile unsigned int n)
{
while(n--);
}
/**********************************
* 函數名稱: void delay(volatile unsigned int n)
* 函數功能: 延時,在396Mhz主頻下約1ms
* 輸入 : volatile unsigned int n
* 輸出 : 無
***********************************/
void delay(volatile unsigned int n)
{
while(n--)
delay_short(0X7FF);
}
/**********************************
* 函數名稱: void LED_On(void)
* 函數功能: 打開LED燈
* 輸入 : 無
* 輸出 : 無
***********************************/
void LED_On(void)
{
GPIO1_DR &= ~(1 << 3); /* bit3清零 */
/* 1 << 3:
* 1左移3位 0000 0001 --> 0000 1000
* ~(1 << 3):
* ~(0000 1000) --> 1111 0111
* GPIO1_DR &= ~(1 << 3) 即 将bit3清零
*/
}
/**********************************
* 函數名稱: void LED_Off(void)
* 函數功能: 關閉LED燈
* 輸入 : 無
* 輸出 : 無
***********************************/
void LED_Off(void)
{
GPIO1_DR |= (1 << 3); /* bit3置1 */
}
int main(void)
{
clk_enable(); /* 使能外設時鐘 */
LED_Init(); /* 初始化LED */
while(1) {
LED_On();
delay(500);
LED_Off();
delay(500);
}
return 0;
}
3、Makefile
objs = start.o main.o
ledc.bin : $(objs)
arm-linux-gnueabihf-ld -Ttext 0X87800000 $^ -o ledc.elf
arm-linux-gnueabihf-objcopy -O binary -S ledc.elf [email protected]
arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis
%.o : %.c
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o [email protected] $<
%.o : %.S
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o [email protected] $<
clean:
rm -rf *.o ledc.bin ledc.elf ledc.dis
三、 連結腳本
連結腳本描述了要連接配接的檔案,以及連結順序,和連結首位址。
連結腳本的文法很簡單,就說編寫一系列的指令,這些指令組成連接配接腳本 ,每個指令都是一個帶有參數的關鍵字或者一個對符号的指派,可以使用符号分隔指令。
一般編譯出來的代碼都包含text、data、bss和rodata這四個段。
假設代碼要被連結到0X10000000位址,而資料要被連結到0X30000000位址,下面為完成此功能最簡單的連結腳本:
SECTIONS{
. = 0X10000000;
.text : {*(.text)}
. = 0X30000000
.data ALIGN(4) : { *(.data)}
.bss ALIGN(4) : { *(.bss)}
}
第1行 為關鍵字“SECTIONS”
第2行 對特殊符号 “.” 進行指派,“.”在連結腳本裡稱為 定位計數器,預設的定位計數器為0。是以給“.”指派0X10000000,表示以0X10000000開始,後面的檔案或者段都會以0X10000000開始連結。
第3行 “.text”為段名,冒号是文法要求,大括号裡可以填上要連結到“.text”這個段的所有檔案 “ *(.text)”表示所有輸入檔案的.text段都放到“.text”上 “ * ”是通配符
ALIGN(4)表示4位元組對稱,用來對“.data”段的起始位址做位元組對稱,即“.data”的起始位址要能被4整除。常見的有ALIGN(4)、ALIGN(8)
“.bss”就是那些定義了但是沒有初始化的變量
imx6ull.lds
與Makefile同目錄,用于Makefile的連結
SECTIONS{
. = 0X87800000;
.text :
{
start.o
*(.text)
}
.rodata ALIGN(4) : {*(.rodata*)}
.data ALIGN(4) : { *(.data) }
__bss_start = .;
.bss ALIGN(4) : { *(.bss) *(COMMON) }
__bss_end = .;
}
其中Makefile也需要修改
objs = start.o main.o
ledc.bin : $(objs)
arm-linux-gnueabihf-ld -Timx6ull.lds $^ -o ledc.elf
arm-linux-gnueabihf-objcopy -O binary -S ledc.elf [email protected]
arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis
%.o : %.c
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o [email protected] $<
%.o : %.S
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o [email protected] $<
clean:
rm -rf *.o ledc.bin ledc.elf ledc.dis
