有了2440开发板环境搭建、基于韦东山S3C2440开发板搭建arm-linux-gcc交叉编译环境基础,环境已经搭起来了,可以做些逻辑试验了,最经典的是点灯、按键、定时器、中断程序。
那就从点灯开始,我们的重点是linux嵌入式开发,逻辑程序只是热身用的,不要花太多时间。
实验内容:点开发板上的LED1。
硬件原理图:
S3C2440芯片手册:
配置GPF4为输出模式(GPFCON),设置输出电平为0(GPFDAT).
汇编文件
/* * 点亮LED1: gpf4 */ .text .global _start _start: /* 配置GPF4为输出引脚 * 把0x100写到地址0x56000050 */ ldr r1, =0x56000050 ldr r0, =0x100 /* mov r0, #0x100 */ str r0, [r1] /* 设置GPF4输出高电平 * 把0写到地址0x56000054 */ ldr r1, =0x56000054 ldr r0, =0 /* mov r0, #0 */ str r0, [r1] /* 死循环 */ halt: b halt
记录: ldr A, B //A = B str A, B //B = A
Makefiel文件
all: arm-linux-gcc -c -o led_on.o led_on.S arm-linux-ld -Ttext 0 led_on.o -o led_on.elf arm-linux-objcopy -O binary -S led_on.elf led_on.bin arm-linux-objdump -D led_on.elf > led_on.dis clean: rm *.bin *.o *.elf
arm-linux-ld -Ttext 0 led_on.o -o led_on.elf设置程序从地址0处存放代码段,递增存放数据段、bss段
arm-linux-objcopy常用于文件格式转换,这里将elf格式文件转化为bin文件。
参考:arm-linux-objcopy; arm-linux-ld命令
同实验1.
汇编码:
注意: C代码必须设置堆栈大小(SP)
.text .global _start _start: /* 设置内存: sp 栈 */ ldr sp, =4096 /* nand启动 */ // ldr sp, =0x40000000+4096 /* nor启动 */ /* 调用main */ bl main halt: b halt
C代码:
int main() { unsigned int *pGPFCON = (unsigned int *)0x56000050; unsigned int *pGPFDAT = (unsigned int *)0x56000054; /* 配置GPF4为输出引脚 */ //*pGPFCON = 0x100; *pGPFCON = 0x400; /* 设置GPF4输出0 */ *pGPFDAT = 0; return 0; }
Makefile脚本
这里比汇编点灯多了一行:将.c转化为.o
all: arm-linux-gcc -c -o led.o led.c arm-linux-gcc -c -o start.o start.S arm-linux-ld -Ttext 0 start.o led.o -o led.elf arm-linux-objcopy -O binary -S led.elf led.bin arm-linux-objdump -D led.elf > led.dis clean: rm *.bin *.o *.elf *.dis
实验内容:循环点LED0、LED1,中间延时一段时间。
原理图、S3C3440手册:参考实验1
汇编码:
.text .global _start _start: /* 设置内存: sp 栈 */ ldr sp, =4096 /* nand启动 */ // ldr sp, =0x40000000+4096 /* nor启动 */ mov r0, #4 bl led_on ldr r0, =100000 bl delay mov r0, #5 bl led_on halt: b halt
C代码:
注意: 这里没有main函数,在汇编码中直接跳转到led_on,汇编码中在函数跳转前,将参数保存在r0中.
void delay(volatile int d) { while (d--); } int led_on(int which) { unsigned int *pGPFCON = (unsigned int *)0x56000050; unsigned int *pGPFDAT = (unsigned int *)0x56000054; if (which == 4) { /* 配置GPF4为输出引脚 */ *pGPFCON = 0x100; } else if (which == 5) { /* 配置GPF5为输出引脚 */ *pGPFCON = 0x400; } /* 设置GPF4/5输出0 */ *pGPFDAT = 0; return 0; }
Makefile文件:同实验2
实验内容:按键1、2、3控制LED1、2、3亮灭。按键按下,灯亮;按键释放,灯灭。
硬件原理图(按键):
S3C2440芯片手册:
GPF的前面已经截图了,这里只截图K3用到的GPG寄存器
汇编代码:
这里关闭了看门狗;判断了是从Nand/Nor启动,从而设置堆栈起始地址,可以不用关心。
.text .global _start _start: /* 关闭看门狗 */ ldr r0, =0x53000000 ldr r1, =0 str r1, [r0] /* 设置内存: sp 栈 */ /* 分辨是nor/nand启动 * 写0到0地址, 再读出来 * 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动 * 否则就是nor启动 */ mov r1, #0 ldr r0, [r1] /* 读出原来的值备份 */ str r1, [r1] /* 0->[0] */ ldr r2, [r1] /* r2=[0] */ cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */ ldr sp, =0x40000000+4096 /* 先假设是nor启动 */ moveq sp, #4096 /* nand启动 */ streq r0, [r1] /* 恢复原来的值 */ bl main halt: b halt
C代码:
#include "s3c2440_soc.h" void delay(volatile int d) { while (d--); } int main(void) { int val1, val2; /* 设置GPFCON让GPF4/5/6配置为输出引脚 */ GPFCON &= ~((3<<8) | (3<<10) | (3<<12)); GPFCON |= ((1<<8) | (1<<10) | (1<<12)); /* 配置3个按键引脚为输入引脚: * GPF0(S2),GPF2(S3),GPG3(S4) */ GPFCON &= ~((3<<0) | (3<<4)); /* gpf0,2 */ GPGCON &= ~((3<<6)); /* gpg3 */ /* 循环点亮 */ while (1) { val1 = GPFDAT; val2 = GPGDAT; if (val1 & (1<<0)) /* s2 --> gpf6 */ { /* 松开 */ GPFDAT |= (1<<6); } else { /* 按下 */ GPFDAT &= ~(1<<6); } if (val1 & (1<<2)) /* s3 --> gpf5 */ { /* 松开 */ GPFDAT |= (1<<5); } else { /* 按下 */ GPFDAT &= ~(1<<5); } if (val2 & (1<<3)) /* s4 --> gpf4 */ { /* 松开 */ GPFDAT |= (1<<4); } else { /* 按下 */ GPFDAT &= ~(1<<4); } } return 0; }
头文件s3c2440_soc.h:
这里将芯片寄存器封装了一下。
#ifndef __S3C2440_SOC_H #define __S3C2440_SOC_H #define __REG(x) (*(volatile unsigned int *)(x)) /*I/O port*/ #define GPFCON __REG(0x56000050) //Port F control #define GPFDAT __REG(0x56000054) //Port F data #define GPFUP __REG(0x56000058) //Pull-up control F #define GPGCON __REG(0x56000060) //Port G control #define GPGDAT __REG(0x56000064) //Port G data #define GPGUP __REG(0x56000068) //Pull-up control G #define GPHCON __REG(0x56000070) //Port H control #define GPHDAT __REG(0x56000074) //Port H data #endif
Makefile代码:
all: arm-linux-gcc -c -o key_led.o key_led.c arm-linux-gcc -c -o start.o start.S arm-linux-ld -Ttext 0 start.o key_led.o -o key_led.elf arm-linux-objcopy -O binary -S key_led.elf key_led.bin arm-linux-objdump -D key_led.elf > key_led.dis clean: rm *.bin *.o *.elf *.dis