天天看點

嵌入式Linux學習曆程 — C語言LED燈C語言LED燈一、C語言運作環境建構二、 程式代碼三、 連結腳本

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 
           
嵌入式Linux學習曆程 — C語言LED燈C語言LED燈一、C語言運作環境建構二、 程式代碼三、 連結腳本

繼續閱讀