1.对于GPIO的操作
对于GPIO的操作,通常是通过读写其相应的寄存器来实现的,S3C2440也是如此。比如,S3C2440的GPBCON和GPBDAT寄存器的地址分别是0x56000010和0x56000014,可以通过如下的指令让GPB5输出低电平。
#define GPBCON (*(volatile unsigned long *)0x56000010)
#define GPBDAT (*(volatile unsigned long *)0x56000014)
GPBCON = (1<<(5*2)); //GPB5设置为输出
GPBDAT &= ~(1<<5); //GPB5输出低电平
对于寄存器的读与此类此,不举例说明。
2.NOR Flash操作注意点
假设开发板上NOR Flash的片选信号使用2440的nGCS0,当CPU发出的地址信号处于0x00000000~0x07ffffff之间时,nGCS0信号有效,NOR Flash被选中。需要注意的是NOR Flash在实际使用中多数以16位为单位读写,即2440的ADDR1~ADDR20与NOR Flash的A0~A19对应相连。
注意以下几种操作:
(1)地址对齐的16位读操作。
unsigned short pwAddr = (unsigned short *)0x2;
unsigned short wVal;
wVal = *pwAddr;
这段代码2440将0x2传送给NOR Flash时会读取到NOR Flash中的0x1处16位的数据(NOR Flash设置为word模式,每个地址对应的数据为16位),所以当2440要读取0x0~0x1均读取的是NOR Flash中0x0的数据,而当2440要读取0x2~0x3的数据时实际读取的是NOR Flash中0x1地址的数据。
(2)地址不对齐的16位读操作。
当2440传入的地址为0x1类似的地址时,由于地址不是按2对齐的,所以会导致异常。一般可以通过设置异常处理函数来处理这种情况,在异常函数中,使用0x0和0x2发起两次读操作,然后将两个结果各取一字节组合起来得到需要的数据。
(3)8位读操作。
unsigned char pwAddr = (unsigned char *)0x2;
unsigned char wVal;
wVal = *pwAddr;
CPU读取数据之后会自动丢弃D1,假设读到的数据为D0和D1。
(4)32位读操作。
unsigned int pwAddr = (unsigned int *)0x2;
unsigned int wVal;
wVal = *pwAddr;
CPU会首先使用地址0x2对NOR Flash发起一次读操作,然后使用0x4对NOR Flash发起一次读操作,最后将两次读取到的数据合并并且赋值给wVal,这个过程完全由处理器硬件机制完成对于程序员来说是不可见的。
(5)16位写操作。
由于NOR Flash的特性,使得对NOR Flash的写操作比较复杂——比如要先发出特定的地址信号通知NOR Flash准备接收数据,然后才能发出数据等。不过,其总线上的电信号与软件指令的关系与读操作类似,只是数据的传输方向相反。
unsigned short *pwAddr = (unsigned shrot *)0x6;
*pwAddr = 0x1234;
3.最简单的点灯程序(程序均烧写到Nand Flash中)
(1)汇编版
led.S源码:
.text
.global _start
_start:
LDR R0, =0x56000010
MOV R1, #0x00000400
STR R1, [R0]
LDR R0, =0x56000014
MOV R1, #0x00000000
STR R1, [R0]
MAIN_LOOP:
B MAIN_LOOP
可以看出,程序中所做的工作就是将GPB5设置为输出,然后再输出0,最后是一个死循环。
以上汇编代码对应的Makefile(编译连接等命令放于其中)为:
led.bin:led.S
arm-linux-gcc -g -c -o led.o led.S
arm-linux-ld -Ttext 0x0000000 -g led.o -o led_elf
arm-linux-objcopy -O binary -S led_elf led.bin
clean:
rm -f led.bin led_elf *.o
注:其中arm-linux-gcc指令中的-g选项表示生成本地调试信息,而-c选项表示只完成预处理、编译和汇编,不做连接。
(2)C语言版
C语言版的LED操作需要从汇编代码跳转到C语言中去完成,首先是一段必要的汇编代码完成关闭看门狗、设置堆栈以及跳转到C入口代码等操作。对应的汇编代码源文件内容如下(crt0.S):
.text
.global _start
_start:
ldr r0, =0x560000XX @0x560000XX代表具体的看门狗寄存器地址
mov r1, #0x0
str r1, [r0] @禁止看门狗
ldr sp, =1024*4 @设置堆栈,不能大于4KB
bl main @调用C程序中的main函数
halt_loop:
b halt_loop
而还有一个相应的C语言源代码文件如下(led.c):
#define GPBCON (*(volatile unsigned long *)0x56000010)
#define GPBDAT (*(volatile unsigned long *)0x56000014)
int main()
{
GPBCON = 0x00000400;
GPBDAT = 0x00000000;
return 0;
}
这两段代码所对应的Makefile文件内容为:
led.bin:crt0.S led.c
arm-linux-gcc -g -c -o crt0.o crt0.S
arm-linux-gcc -g -c -o led.o led.c
arm-linux-ld -Ttext 0x0000000 -g crt0.o led.o -o led_elf
arm-linux-objcopy -O binary -S led_elf led.bin
arm-linux-objdump -D -m arm led_elf > led.dis
clean:
rm -f led.dis led.bin led_elf *.o
注意:arm-linux-objdump指令将结果转换为汇编代码以供查看。2440的OM1和OM0引脚用于设置启动位置。NOR Flash可以像内存一样进行读操作,却不可以像内存一样进行写操作,所以从NOR Flash启动时,一般先在代码的开始部分使用汇编指令初始化外接的内存,然后将代码复制到外存中,最后跳转到外存中继续执行。NAND Flash中前4KB的内容会自动的被复制到2440内部RAM中,所以小实验程序可以借助此性质比较方便的完成。
对于GPIO的操作,通常是通过读写其相应的寄存器来实现的,S3C2440也是如此。比如,S3C2440的GPBCON和GPBDAT寄存器的地址分别是0x56000010和0x56000014,可以通过如下的指令让GPB5输出低电平。
#define GPBCON (*(volatile unsigned long *)0x56000010)
#define GPBDAT (*(volatile unsigned long *)0x56000014)
GPBCON = (1<<(5*2)); //GPB5设置为输出
GPBDAT &= ~(1<<5); //GPB5输出低电平
对于寄存器的读与此类此,不举例说明。
2.NOR Flash操作注意点
假设开发板上NOR Flash的片选信号使用2440的nGCS0,当CPU发出的地址信号处于0x00000000~0x07ffffff之间时,nGCS0信号有效,NOR Flash被选中。需要注意的是NOR Flash在实际使用中多数以16位为单位读写,即2440的ADDR1~ADDR20与NOR Flash的A0~A19对应相连。
注意以下几种操作:
(1)地址对齐的16位读操作。
unsigned short pwAddr = (unsigned short *)0x2;
unsigned short wVal;
wVal = *pwAddr;
这段代码2440将0x2传送给NOR Flash时会读取到NOR Flash中的0x1处16位的数据(NOR Flash设置为word模式,每个地址对应的数据为16位),所以当2440要读取0x0~0x1均读取的是NOR Flash中0x0的数据,而当2440要读取0x2~0x3的数据时实际读取的是NOR Flash中0x1地址的数据。
(2)地址不对齐的16位读操作。
当2440传入的地址为0x1类似的地址时,由于地址不是按2对齐的,所以会导致异常。一般可以通过设置异常处理函数来处理这种情况,在异常函数中,使用0x0和0x2发起两次读操作,然后将两个结果各取一字节组合起来得到需要的数据。
(3)8位读操作。
unsigned char pwAddr = (unsigned char *)0x2;
unsigned char wVal;
wVal = *pwAddr;
CPU读取数据之后会自动丢弃D1,假设读到的数据为D0和D1。
(4)32位读操作。
unsigned int pwAddr = (unsigned int *)0x2;
unsigned int wVal;
wVal = *pwAddr;
CPU会首先使用地址0x2对NOR Flash发起一次读操作,然后使用0x4对NOR Flash发起一次读操作,最后将两次读取到的数据合并并且赋值给wVal,这个过程完全由处理器硬件机制完成对于程序员来说是不可见的。
(5)16位写操作。
由于NOR Flash的特性,使得对NOR Flash的写操作比较复杂——比如要先发出特定的地址信号通知NOR Flash准备接收数据,然后才能发出数据等。不过,其总线上的电信号与软件指令的关系与读操作类似,只是数据的传输方向相反。
unsigned short *pwAddr = (unsigned shrot *)0x6;
*pwAddr = 0x1234;
3.最简单的点灯程序(程序均烧写到Nand Flash中)
(1)汇编版
led.S源码:
.text
.global _start
_start:
LDR R0, =0x56000010
MOV R1, #0x00000400
STR R1, [R0]
LDR R0, =0x56000014
MOV R1, #0x00000000
STR R1, [R0]
MAIN_LOOP:
B MAIN_LOOP
可以看出,程序中所做的工作就是将GPB5设置为输出,然后再输出0,最后是一个死循环。
以上汇编代码对应的Makefile(编译连接等命令放于其中)为:
led.bin:led.S
arm-linux-gcc -g -c -o led.o led.S
arm-linux-ld -Ttext 0x0000000 -g led.o -o led_elf
arm-linux-objcopy -O binary -S led_elf led.bin
clean:
rm -f led.bin led_elf *.o
注:其中arm-linux-gcc指令中的-g选项表示生成本地调试信息,而-c选项表示只完成预处理、编译和汇编,不做连接。
(2)C语言版
C语言版的LED操作需要从汇编代码跳转到C语言中去完成,首先是一段必要的汇编代码完成关闭看门狗、设置堆栈以及跳转到C入口代码等操作。对应的汇编代码源文件内容如下(crt0.S):
.text
.global _start
_start:
ldr r0, =0x560000XX @0x560000XX代表具体的看门狗寄存器地址
mov r1, #0x0
str r1, [r0] @禁止看门狗
ldr sp, =1024*4 @设置堆栈,不能大于4KB
bl main @调用C程序中的main函数
halt_loop:
b halt_loop
而还有一个相应的C语言源代码文件如下(led.c):
#define GPBCON (*(volatile unsigned long *)0x56000010)
#define GPBDAT (*(volatile unsigned long *)0x56000014)
int main()
{
GPBCON = 0x00000400;
GPBDAT = 0x00000000;
return 0;
}
这两段代码所对应的Makefile文件内容为:
led.bin:crt0.S led.c
arm-linux-gcc -g -c -o crt0.o crt0.S
arm-linux-gcc -g -c -o led.o led.c
arm-linux-ld -Ttext 0x0000000 -g crt0.o led.o -o led_elf
arm-linux-objcopy -O binary -S led_elf led.bin
arm-linux-objdump -D -m arm led_elf > led.dis
clean:
rm -f led.dis led.bin led_elf *.o
注意:arm-linux-objdump指令将结果转换为汇编代码以供查看。2440的OM1和OM0引脚用于设置启动位置。NOR Flash可以像内存一样进行读操作,却不可以像内存一样进行写操作,所以从NOR Flash启动时,一般先在代码的开始部分使用汇编指令初始化外接的内存,然后将代码复制到外存中,最后跳转到外存中继续执行。NAND Flash中前4KB的内容会自动的被复制到2440内部RAM中,所以小实验程序可以借助此性质比较方便的完成。