前言
有了2440开发板环境搭建、基于韦东山S3C2440开发板搭建arm-linux-gcc交叉编译环境基础,环境已经搭起来了,可以做些逻辑试验了,最经典的是点灯、按键、定时器、中断程序。
那就从点灯开始,我们的重点是linux嵌入式开发,逻辑程序只是热身用的,不要花太多时间。
实验1 汇编点灯
实验内容:点开发板上的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命令
实验2 C代码点灯
同实验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
实验3 汇编传参C点灯
实验内容:循环点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
实验4 按键控制点灯
实验内容:按键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