极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 12695|回复: 0

pcDuino裸板程序-led

[复制链接]
发表于 2013-6-21 09:00:16 | 显示全部楼层 |阅读模式
本帖最后由 夜聆风 于 2013-6-22 08:26 编辑

最近调驱动时,调试led时遇到了点问题,于是回过头来再写个led裸板程序。在我写的pcDuino第一个裸板程序uart的基础上,再写个led裸板程序还是很轻松的。很多人觉得没有必要写什么pcDuino裸板程序,觉得没啥意义。我觉得可以用来熟悉硬件,特别是想做底层驱动开发,以及系统移植,熟悉底层硬件还是有用的。其实做底层驱动开发,也是跟硬件打交道,硬件相关的操作和裸板程序是一样的。下面介绍怎样在pcDuino上跑一个最简单的led裸板程序。

开发环境:
系统:ubuntu 10.04.4
单板:pcDuino
编译器:arm-2009q3-67-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2


目标:实现pcDuino上的TX_LED闪烁

一、硬件介绍

仔细看pcDuino上的原理图和pcDuino的手册,发现二者不是完全对应的,还是以原理图为准。根据原理图知道TX_LED是接到PH15上,可以当做普通IO口用,不需要连跳线




二、编写源代码

主要是看手册30.Port Controller,根据手册写led初始化程序主要包括设为输出、是能上拉及Multi-Driving寄存器设置。包括start.S、main.c、clock.c、clock.h、Makefile,下面贴出全部代码

文件start.S:


[plain] view plaincopyprint?.global _start  
      
_start:  
    ldr sp, =0x00007f00  
      
    b main  

.global _start
       
_start:
        ldr sp, =0x00007f00
       
        b main
文件main.c:


[plain] view plaincopyprint?#include "clock.h"  
  
#define PH_CFG1             (*(volatile unsigned int *)0x01c20900)   
#define PH_DAT              (*(volatile unsigned int *)0x01c2090C)  
#define PH_DRI              (*(volatile unsigned int *)0x01c20910)  
#define PH_PULL             (*(volatile unsigned int *)0x01c20918)  
void gpio_init()  
{  
/*PCDUINO GPIO4--PH9:  
  *bit[6:4] PH9_SELECT 001:OUTPUT  
  *PCDUINO GPIO5--PH10:  
  *bit[10:8] PH10_SELECT 001:OUTPUT  
  */   
  PH_CFG1 |= ((0x1<<4)|(0x1<<8)|(0X1<<28));  
  PH_DRI   = 0XFFFFFFFF;  
  PH_PULL  = 0X55555555;  
}  
  
void delay()  
{  
    volatile int i = 0x300000;  
    while (i--);  
}  
int main(void)  
{  
    char c;  
    clock_init(); /* 初始化时钟 */  
    gpio_init();  
  
    while (1)  
    {  
        PH_DAT = 0x00;  
        delay();  
        PH_DAT = 0xffff;  
        delay();  
    }  
  
    return 0;  
}  

#include "clock.h"

#define PH_CFG1                  (*(volatile unsigned int *)0x01c20900)       
#define PH_DAT                  (*(volatile unsigned int *)0x01c2090C)
#define PH_DRI                  (*(volatile unsigned int *)0x01c20910)
#define PH_PULL                  (*(volatile unsigned int *)0x01c20918)
void gpio_init()
{
/*PCDUINO GPIO4--PH9:
  *bit[6:4] PH9_SELECT 001:OUTPUT
  *PCDUINO GPIO5--PH10:
  *bit[10:8] PH10_SELECT 001:OUTPUT
  */
  PH_CFG1 |= ((0x1<<4)|(0x1<<8)|(0X1<<28));
  PH_DRI   = 0XFFFFFFFF;
  PH_PULL  = 0X55555555;
}

void delay()
{
        volatile int i = 0x300000;
        while (i--);
}
int main(void)
{
        char c;
        clock_init(); /* 初始化时钟 */
        gpio_init();

        while (1)
        {
                PH_DAT = 0x00;
                delay();
                PH_DAT = 0xffff;
                delay();
        }

        return 0;
}
文件clock.c:


[plain] view plaincopyprint?#define CPU_AHB_APB0_CFG    (*(volatile unsigned int *)0x01c20054)  
#define PLL1_CFG            (*(volatile unsigned int *)0x01c20000)   
#define APB1_CLK_DIV_CFG    (*(volatile unsigned int *)0x01c20058)   
#define APB1_GATE           (*(volatile unsigned int *)0x01c2006C)   
  
void sdelay(unsigned long loops)  
{  
  __asm__ volatile("1:\n" "subs %0, %1, #1\n"  
           "bne 1b":"=r" (loops):"0"(loops));  
}  
void clock_init(void)  
{  
  /*AXI_DIV_1[1:0]  AXI_CLK_DIV_RATIO 00:/1 AXI Clock source is CPU clock  
   *AHB_DIV_2[5:4]  AHP_CLK_DIV_RATIO 01:/2 AHB Clock source is AXI CLOCK  
   *APB0_DIV_1[9:8] APB0_CLK_RATIO    00:/2 APB0 clock source is AHB2 clock  
   *CPU_CLK_SRC_OSC24M[17:16] CPU_CLK_SRC_SEL 01:OSC24M  
   */  
   CPU_AHB_APB0_CFG = ((0<<0)|(0x1<<4)|(0<<8)|(1<<16));  
  
   /*bit31 PLL1_Enable 1:Enable  
    *bit25:EXG_MODE 0x0:Exchange mode  
    *bit[17:16] PLL1_OUT_EXT_DIVP 0x0P=1  
    *bit[12:8]PLL1_FACTOR_N 0x10:Factor=16,N=16  
    *bit[5:4] PLL1_FACTOR_K 0x0:K=1  
    *bit3:SIG_DELT_PAT_IN 0x0  
    *bit2:SIG_DELT_PAT_EN 0x0  
    *bit[1:0]PLL1_FACTOR_M 0x0:M=1  
    *The PLL1 output=(24M*N*K)/(M*P)=(24M*16*1)/(1*1)=384M is for the coreclk  
    */  
   PLL1_CFG = 0xa1005000;  
  
   sdelay(200);  
  
   CPU_AHB_APB0_CFG = ((0<<0)|(0x1<<4)|(0<<8)|(2<<16));//CPU_CLK_SRC_SEL 10PLL1  
  
   /*uart clock source is apb1,config apb1 clock*/  
   /*bit[25:24]:APB1_CLK_SRC_SEL 00:OSC24M  
    *bit[17:16]:CLK_RAT_N 0X0:1 The select clock source is pre-divided by 2^1  
    *bit[4:0]:CLK_RAT_M 0x0:1 The pre-devided clock is divided by(m+1)  
    */  
   APB1_CLK_DIV_CFG = ((0<<5)|(0<<16)|(0<<24));  
   /*open the clock for uart0*/  
   /*bit16:UART0_APB_GATING 1:pass 0:mask*/  
   APB1_GATE = (0x1<<16);  
}  

#define CPU_AHB_APB0_CFG          (*(volatile unsigned int *)0x01c20054)
#define PLL1_CFG                  (*(volatile unsigned int *)0x01c20000)       
#define APB1_CLK_DIV_CFG          (*(volatile unsigned int *)0x01c20058)       
#define APB1_GATE                  (*(volatile unsigned int *)0x01c2006C)       

void sdelay(unsigned long loops)
{
  __asm__ volatile("1:\n" "subs %0, %1, #1\n"
                   "bne 1b":"=r" (loops):"0"(loops));
}
void clock_init(void)
{
  /*AXI_DIV_1[1:0]  AXI_CLK_DIV_RATIO 00:/1 AXI Clock source is CPU clock
   *AHB_DIV_2[5:4]  AHP_CLK_DIV_RATIO 01:/2 AHB Clock source is AXI CLOCK
   *APB0_DIV_1[9:8] APB0_CLK_RATIO    00:/2 APB0 clock source is AHB2 clock
   *CPU_CLK_SRC_OSC24M[17:16] CPU_CLK_SRC_SEL 01:OSC24M
   */
   CPU_AHB_APB0_CFG = ((0<<0)|(0x1<<4)|(0<<8)|(1<<16));

   /*bit31 PLL1_Enable 1:Enable
    *bit25:EXG_MODE 0x0:Exchange mode
    *bit[17:16]PLL1_OUT_EXT_DIVP 0x0 P=1
    *bit[12:8]PLL1_FACTOR_N 0x10:Factor=16,N=16
    *bit[5:4]PLL1_FACTOR_K 0x0:K=1
    *bit3:SIG_DELT_PAT_IN 0x0
    *bit2:SIG_DELT_PAT_EN 0x0
    *bit[1:0]PLL1_FACTOR_M 0x0:M=1
    *The PLL1 output=(24M*N*K)/(M*P)=(24M*16*1)/(1*1)=384M is for the coreclk
    */
   PLL1_CFG = 0xa1005000;

   sdelay(200);

   CPU_AHB_APB0_CFG = ((0<<0)|(0x1<<4)|(0<<8)|(2<<16));//CPU_CLK_SRC_SEL 10PLL1

   /*uart clock source is apb1,config apb1 clock*/
   /*bit[25:24]:APB1_CLK_SRC_SEL 00:OSC24M
    *bit[17:16]:CLK_RAT_N 0X0:1 The select clock source is pre-divided by 2^1
    *bit[4:0]:CLK_RAT_M 0x0:1 The pre-devided clock is divided by(m+1)
    */
   APB1_CLK_DIV_CFG = ((0<<5)|(0<<16)|(0<<24));
   /*open the clock for uart0*/
   /*bit16:UART0_APB_GATING 1 pass 0:mask*/
   APB1_GATE = (0x1<<16);
}
文件·clock.h:


[plain] view plaincopyprint?void clock_init(void);  

void clock_init(void);文件·Makefile:


[plain] view plaincopyprint?led.bin:start.S main.c clock.c  
    arm-none-linux-gnueabi-gcc -nostdlib -c start.S -o start.o  
    arm-none-linux-gnueabi-gcc -nostdlib -c main.c -o main.o  
    arm-none-linux-gnueabi-gcc -nostdlib -c clock.c -o clock.o   
    arm-none-linux-gnueabi-ld -Ttext 0xD0020010 start.o main.o clock.o  -o led_elf  
    arm-none-linux-gnueabi-objcopy -O binary -S led_elf led.bin  
  
clean:  
    rm -rf *.o *.bin led_elf *.dis  

led.bin:start.S main.c clock.c
        arm-none-linux-gnueabi-gcc -nostdlib -c start.S -o start.o
        arm-none-linux-gnueabi-gcc -nostdlib -c main.c -o main.o
        arm-none-linux-gnueabi-gcc -nostdlib -c clock.c -o clock.o       
        arm-none-linux-gnueabi-ld -Ttext 0xD0020010 start.o main.o clock.o  -o led_elf
        arm-none-linux-gnueabi-objcopy -O binary -S led_elf led.bin

clean:
        rm -rf *.o *.bin led_elf *.dis
代码确实很简单,上面也有看手册时留下的注释,就不分析了,有问题留言吧。

三、编译、测试

1.安装交叉编译链,给个链接 http://code.google.com/p/smp-on-qemu/downloads/list 选择arm-2009q3-67-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2并下载。然后在ubuntu下直接解压即可,过程就不说了,还不清楚的看Ubuntu 10.04.4开发环境配置。

2.编译

change@change:~$ cd Si/A10/2_led/
change@change:~/Si/A10/2_led$ ls
clock.c  clock.h  main.c  Makefile  mksunxiboot  start.S
change@change:~/Si/A10/2_led$ make
arm-none-linux-gnueabi-gcc -nostdlib -c start.S -o start.o
arm-none-linux-gnueabi-gcc -nostdlib -c main.c -o main.o
arm-none-linux-gnueabi-gcc -nostdlib -c clock.c -o clock.o
arm-none-linux-gnueabi-ld -Ttext 0xD0020010 start.o main.o clock.o  -o led_elf
arm-none-linux-gnueabi-objcopy -O binary -S led_elf led.bin
change@change:~/Si/A10/2_led$ ./mksunxiboot led.bin leds.bin
File size: 0x154
Load size: 0x154
Read 0x154 bytes
Write 0x200 bytes
change@change:~/Si/A10/2_led$
其中有个./mksunxiboot led.bin leds.bin要注意,不经过mksunxiboot工具 的.bin文件,pcDuino是运行不了的。这个工具在官网上都有下。现在的处理启动都很复杂,内有固化有bl0代码,在跳转到bl1时需要校验程序的合法性,这个工具mksunxiboot简单点少就是给我们程序加了点头部,让处理器能够识别我们写的代码。你可以分析led.bin和leds.bin的反汇编代码,就一目了然了。这部分感兴趣的可以一起讨论。

3.测试

上面生成的leds.bin就可以放到板子上运行了。为了不破会NAND中的系统,直接放到tf卡运行。不用担心那个先启动,看全志手册就知道pcDuino默认先从tf卡启动,只有tf卡没有启动的引导程序才会跳到NAND启动。插上tf卡到PC机

change@change:~/Si/A10/2_led$ sudo dd if=/dev/zero of=/dev/sdb bs=1M count=1
1+0 records in
1+0 records out
1048576 bytes (1.0 MB) copied, 0.425886 s, 2.5 MB/s
change@change:~/Si/A10/2_led$ sudo dd if=leds.bin of=/dev/sdb bs=1024 seek=8
0+1 records in
0+1 records out
512 bytes (512 B) copied, 0.00600667 s, 85.2 kB/s
change@change:~/Si/A10/2_led$


然后取下tf卡,插到pcDino上,RX LED就开始闪烁了。如果你手上有led,接到GPIO4、GPIO5也会闪烁。对底层硬件感兴趣的,一起讨论,有问题的请直接留言。



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-26 00:24 , Processed in 0.069283 second(s), 19 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表