S3C2440逻辑程序--从点灯开始

前言

有了2440开发板环境搭建基于韦东山S3C2440开发板搭建arm-linux-gcc交叉编译环境基础,环境已经搭起来了,可以做些逻辑试验了,最经典的是点灯、按键、定时器、中断程序。

那就从点灯开始,我们的重点是linux嵌入式开发,逻辑程序只是热身用的,不要花太多时间。

实验1 汇编点灯

实验内容:点开发板上的LED1。

硬件原理图:

S3C2440逻辑程序--从点灯开始

S3C2440逻辑程序--从点灯开始

 

S3C2440芯片手册:

配置GPF4为输出模式(GPFCON),设置输出电平为0(GPFDAT).

S3C2440逻辑程序--从点灯开始

 

 

汇编文件

/*
 * 点亮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逻辑程序--从点灯开始S3C2440逻辑程序--从点灯开始

S3C2440逻辑程序--从点灯开始

 

 S3C2440芯片手册:

GPF的前面已经截图了,这里只截图K3用到的GPG寄存器

S3C2440逻辑程序--从点灯开始

 

 

汇编代码:

这里关闭了看门狗;判断了是从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

上一篇:C#分页


下一篇:linux – 使用ELF文件的“.init_array”部分