自己学驱动11——简单GPIO操作

来源:互联网 发布:软件开发逻辑测试 编辑:程序博客网 时间:2024/06/07 18:17
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中,所以小实验程序可以借助此性质比较方便的完成。
0 0