ARM_Linux NOTE_3
Vine Farer
2016.08.10
3、ARM汇编、C混合编程
1)LED实验
汇编
.text .globl _start _start: nop bl main #跳进main函数 nop _stop: b _stop
main.c中的main函数
volatile:
1、修饰代码块,屏蔽编译器优化
2、修饰变量,等式两边对同一变量都读一次int main(int argc, char *argc[]) { (*((volatile unsigned int *)(0x11400000 + 0x01e0))) = ((*((volatile unsigned int *)(0x11400000 + 0x01e0))) & (0x0fffff)) | (0x100000); (*((volatile unsigned int *)(0x11400000 + 0x01e4))) |= (0b100000); return 0; }
Makefile
SHELL=C:\WINDOWS\system32\cmd.exe all: arm-none-eabi-gcc -c -g asm.s -o asm.o arm-none-eabi-gcc -c -g main.c -o main.o arm-none-eabi-ld -Ttext 0x40008000 asm.o main.o -o asm.elf arm-none-eabi-objdump -D asm.elf > asm.dis clean: rm -rf *.elf *.o
2)C语言的传参
asm:
.text .globl _start _start: nop bl main nop _stop: b _stop .globl _fun #全局调用_fun函数,要先用.globl声明 _fun: mov r3,#1 mov r4,#2 mov pc,lr
main:
int _fun(); int fun(int a, int b, int c, int d) { return 300; } int main(int argc, char *argv[]) { int a = 100; a = fun(6,7,8,9); a = _fun(); return 250; }
3)内联汇编
如果全局调用汇编函数,则pc不断跳转很浪费时间
所以,内联汇编使C中内嵌汇编,省去跳转时间,提高效率
输出列表中的变量,内联结束后,变量会得到寄存器返回的值
int main(int argc, char *argv[])
{
int a = 100;
int b, c, d;
//内联汇编
asm volatile( /*也可__asm__ __volatile__*/
/*volatile用来关闭编译器优化*/
"mov r0,#123\n\r"
"mov %0,#45\n\r" /* \n是回车,\r是行首 */
"str r1,%1\n\r"
"mov r2,%2\n\r"
"ldr r3,%3\n\r"
:"+r"(a),"=m"(b) /*输出列表output table*/
:"r"(c),"m"(d) /*输入列表input table*/
:"r0","r1","r2","r3" /*异变列表change table*/
); /*r是寄存器传输、m是内存传输*/
/*+是可读可写、=是只写、*/
/*输出列表的元素默认只读*/
a = fun(6,7,8,9);
a = _fun();
return 250;
}
4)C代码实现片外模块功能
先包含exynos_4412.h头文件,里面包含了所有的片外寄存器声明
LED闪烁
#include "exynos_4412.h" void mydelay_ms(int ms) { int i, j; while(ms--) { for (i = 0; i < 5; i++) for (j = 0; j < 514; j++); } } int main(int argc, char *argv[]) { int i; GPF3.CON = (GPF3.CON & (~(0xf << 20))) | (0x1 << 20); for(i = 0; i < 100; i ++) { GPF3.DAT ^= (0b1 << 5); //异或取反 mydelay_ms(500); } return 0; }
蜂鸣器驱动
#include "exynos_4412.h" void mydelay_ms(int ms) { int i, j; while(ms--) { for (i = 0; i < 5; i++) for (j = 0; j < 514; j++); } } void mydelay_10us(int us) { int i, j; while(us--) { for (i = 0; i < 5; i++) for (j = 0; j < 5; j++); } } int main(int argc, char *argv[]) { int i; GPD0.CON = (GPD0.CON & ~(0xf << 0)) | (0x1 << 0); while(1) { GPD0.DAT ^= (0x1 << 0); // mydelay_ms(1); mydelay_10us(1); } return 0; }
按键
/*beep GPD0_0*/ GPD0.CON = (GPD0.CON & (~(0xf << 0))) | (0x1 << 0); /*led5 GPX3_5*/ GPF3.CON = (GPF3.CON & (~(0xf << 20))) | (0x1 << 20); /*key4 GPX3_5*/ GPX3.CON &= ~(0xf << 8); while(1) { if(0 == (GPX3.DAT & (1 << 2))){ mydelay_ms(50); if(0 == (GPX3.DAT & (1 << 2))){ GPF3.DAT ^= (1 << 5); while(0 == (GPX3.DAT & (1 << 2))) ; } } }