Linux開發板C語言實現LED閃爍
阿新 • • 發佈:2021-01-07
一、處理器模式的設定
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=.;
}
完成以上工作後即可按照之前的步驟進行燒寫驗證。