C與彙編
現在很少用匯編去編寫嵌入式驅動,常用C。彙編作用只是用來完成C語言環境搭建。C語言去實現具體功能裸機。
程序編寫
工程文件
新建2.ledc文件夾,談價start.S,main.c,main.h文件。
彙編部分程序start.S
.global _start /* 全局標號 */
/*
* 描述: _start 函數,程序從此函數開始執行,此函數主要功能是設置 C 5 * 運行環境。
*/
_start:
/* 進入 SVC 模式 */
mrs r0, cpsr
bic r0, r0, #0x1f /* 將 r0 的低 5 位清零,也就是 cpsr 的 M0~M4 */
orr r0, r0, #0x13 /* r0 或上 0x13,表示使用 SVC 模式 */
msr cpsr, r0 /* 將 r0 的數據寫入到 cpsr_c 中 */
ldr sp, =0X80200000 /* 設置棧指針 */
b main /* 跳轉到 main 函數 */
C程序main.c,main.h
- 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_IO04 *((volatile unsigned int*)0x020E006C)
#define SW_PAD_GPIO1_IO04 *((volatile unsigned int*)0x020E02F8)
/*
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_H
- main.c
#include "main.h"
/* 使能所有時鐘 */
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;
}
/* 初始化LED對應的GPIO */
void led_init(void)
{
/* 1.初始化IO複用,複用GPIO1_IO04 */
SW_MUX_GPIO1_IO04 = 0x05;
/* 2.配置GPIO1_IO04的IO屬性
*bit 16:0 HYS關閉
*bit [15:14] 00 默認下拉
*bit [13]:0 keeper功能
*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_IO04 = 0X10B0;
/* 3.初始化GPIO,GPIO1_IO04設置爲輸出 */
GPIO1_GDIR = 0X00000010;
/* 4.設置GPIO1_IO04輸出低電平,打開LED0 */
GPIO1_DR = 0x0;
}
/* 打開LED */
void led_on(void)
{
/*
將GPIO1_DR的bit4清零
*/
GPIO1_DR &= ~(1<<4);
}
/* 關閉LED */
void led_off(void)
{
/*
講GPIO1_DR的bit4置1
*/
GPIO1_DR |= (1<<4);
}
/* 短時間延時函數 */
void delay_short(volatile unsigned int n)
{
while(n--){}
}
/* 延時函數,在396Mhz主頻下延時月1ms */
void delay(volatile unsigned int n)
{
while(n--)
{
delay_short(0x7ff);
}
}
/* 主函數 */
int main(void)
{
clk_enable();/* 使能所有時鐘 */
led_init(); /* 初始化led */
while (1)/* 死循環 */
{
led_off(); /* 關閉LED */
delay(500);
led_on();/* 打開led */
delay(500);
}
return 0;
}
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 $@
arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis
%.o:%.s
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
%.o:%.S
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
%.o:%.c
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
%.o:%.s
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $<
clean:
rm -rf *.o ledc.bin ledc.elf ledc.dis
Makefile使用到的語法知識:變量和自動變量。
- 變量定義:objs := start.o main.o
賦值符號除了:=還有= ,?=。使用“=”在給變量的賦值的時候,不一定要用已經定義好的值,也可以使用後面定義的值。賦值符“:=”不會使用後面定義的變量,只能使用前面已經定義好的。賦值符“?=”會判斷前面沒有被賦值,那麼此變量就會賦值符賦值,如果前面已經賦過值了,那麼就使用前面賦的值。 - 自動變量
目標和依賴都是一系列的文件,每一次對模式規則進行解析的時候都會是不同的目標和依賴文件,而命令只有一行,如何通過一行命令來從不同的依賴文件中生成對應的目標?自動化變量就是完成這個功能的!所謂自動化變量就是這種變量會把模式中所定義的一系列的文件自動的挨個取出,直至所有的符合模式的文件都取完,自動化變量只應該出現在規則的命令中。
$@
:規則中的目標集合,在模式規則中,如果有多個目標的話,“$@”表示匹配模式中定義的目標集合。
$%
當目標是函數庫的時候表示規則中的目標成員名,如果目標不是函數庫文件,那麼其值爲空。
$<
依賴文件集合中的第一個文件,如果依賴文件是以模式(即“%”)定義的,那麼“$<”就是符合模式的一系列的文件集合。
$?
所有比目標新的依賴目標集合,以空格分開。
$^
所有依賴文件的集合,使用空格分開,如果在依賴文件中有多個重複的文件,“$^”會去除重複的依賴文件,值保留一份。
$+
和“$^”類似,但是當依賴文件存在重複的話不會去除重複的依賴文件。
$*
這個變量表示目標模式中"%"及其之前的部分,如果目標是 test/a.test.c,目標模式爲 a.%.c,那麼“$*”就是 test/a.test。