1. 程式人生 > 其它 >Linux開發板C語言實現LED閃爍

Linux開發板C語言實現LED閃爍

技術標籤:正點原子開發板嵌入式嵌入式

一、處理器模式的設定

Cortex-A 處理器有6種執行模式,當前實驗需要將模式設定為SVC超級管理員模式,從暫存器設定中可以看到CPSR的M【4:0】控制著處理器的執行模式。因此可以將CPSR【4:0】設定為10011即為SVC模式。

二、SP指標的設定

Sp可以指向內部RAM,也可以指向DDR,在此實驗中我們將指向DDR。I.MX6U-ALPHA 開發板上的 DDR3 地 址 範 圍 是0X80000000~0XA0000000(512MB),也有可能是256MB的,但是其 DDR3 起始地址是 0X80000000。由於 Cortex-A7 的堆疊是向下增長的,所以將 SP 指標設定為 0X80200000。因此 SVC 模式的棧大小 0X80200000-0X80000000=0X200000=2MB,2MB 的棧空間已經很大了。最後就是跳轉到main函式。

三、start.S檔案程式碼如下

.global _start

_start:
    /*設定處理器進入SVC模式 */
    mrs r0, cpsr   /*讀取cpsr到r0 */
    bic r0, r0, #0x1f  /*清除cpsr的bit4:0*/
    orr r0, r0, #0x13  /*使用SVC模式 */
    msr cpsr, r0       /*將r0寫入到cpsr */

    /*設定SP指標 */
    ldr sp, =0x80200000
    b main             /*跳轉到C語言main函式 */

四、C語言程式碼的編寫

C程式碼主要由main.c和main.h兩部分組成,main.h主要定義暫存器地址,程式碼如下:
#ifndef __MAIN_H
#define __MAIN_H

/*定義要使用的暫存器*/
#define CCCM_CCGR0 *((volatile unsigned int*)0x020c4068)
#define CCCM_CCGR1 *((volatile unsigned int*)0x020c406c)
#define CCCM_CCGR2 *((volatile unsigned int*)0x020c4070)
#define CCCM_CCGR3 *((volatile unsigned int*)0x020c4074)
#define CCCM_CCGR4 *((volatile unsigned int*)0x020c4078)
#define CCCM_CCGR5 *((volatile unsigned int*)0x020c407c) #define CCCM_CCGR6 *((volatile unsigned int*)0x020c4080) #define SW_MUX_GPIO1_IO03 *((volatile unsigned int*)0x020e0068) #define SW_PAD_GPIO1_IO03 *((volatile unsigned int*)0x020e02f4) #define GPIO1_GDIR *((volatile unsigned int*)0x0209c004) #define GPIO1_DR *((volatile unsigned int*)0x0209c000) #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_H
接下來就是main.c檔案的編寫,該檔案是正式實現LED燈的閃爍,其程式碼如下:
#include "main.h"

/*使能外設時鐘*/
void clk_enable(void)
{
    CCCM_CCGR0 = 0xffffffff;
    CCCM_CCGR1 = 0xffffffff;
    CCCM_CCGR2 = 0xffffffff;
    CCCM_CCGR3 = 0xffffffff;
    CCCM_CCGR4 = 0xffffffff;
    CCCM_CCGR5 = 0xffffffff;
    CCCM_CCGR6 = 0xffffffff;
}

/*初始化LED*/
void led_init(void)
{
    SW_MUX_GPIO1_IO03 = 0x5;
    SW_PAD_GPIO1_IO03 = 0x10b0;

    /*GPIO初始化*/
    GPIO1_GDIR = 0x8; /*設定為輸出*/
    GPIO1_DR = 0x0;   /*開啟led燈*/
}

void delayshort(volatile unsigned int n)
{
    while(n--){}
}

/*延時,一次迴圈大概是1ms 在主頻396Mhz
 *n:延時ms數
 */
void delay(volatile unsigned int n)
{
    while(n--){
        delayshort(0x7ff);
    }
}

/*開啟led燈*/
void led_on(void)
{
    GPIO1_DR &= ~(1<<3); /*bit3清0*/
}

/*關閉led燈*/
void led_off(void)
{
    GPIO1_DR |= (1<<3); /*bit3置1*/
}

int main(void)
{
    clk_enable();
    led_init();
    /*初始化LED*/

    /*設定LED閃爍*/
    while(1){
        led_on();
        delay(1000);
        led_off();
        delay(1000);
    }
    return 0;
}

五、編寫Makefile

objs = main.o start.o

ledc.bin : $(objs)
	arm-linux-gnueabihf-ld -Timx6u.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 -O2 -c -o [email protected] $<

%.o : %.S
	arm-linux-gnueabihf-gcc -Wall -nostdlib -O2 -c -o [email protected] $<

clean:
	rm -rf *.o ledc.bin ledc,elf ledc.dis
連結指令碼的編寫,主要是將我們編譯出來的程式碼塊連結到指定的地址,一般編譯的程式碼塊包含 text、data、bss 和 rodata 這四個段。其程式碼如下:
SECTIONS{
    . = 0x87800000;
    .text :
    {
        start.o
        *(.text)
    }
    .rodate ALIGN(4) : {*(.rodate*)}
    .date ALIGN(4) : {*(.date)}
    __bss_start=.;
    .bss ALIGN(4) : {*(.bss) *(COMMON)}
    __bss_end=.;
}
完成以上工作後即可按照之前的步驟進行燒寫驗證。