本文共 10371 字,大约阅读时间需要 34 分钟。
最近调驱动时,调试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: - <p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">[plain] view plaincopyprint?.global _start</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">_start:
- ldr sp, =0x00007f00</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">b main</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">.global _start</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">_start:
- ldr sp, =0x00007f00</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">b main</p>
复制代码 文件main.c: - <p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">[plain] view plaincopyprint?#include “clock.h”</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">#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 |= ((0×1<<4)|(0×1<<8)|(0X1<<28));
- PH_DRI = 0XFFFFFFFF;
- PH_PULL = 0X55555555;
- }</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">void delay()
- {
- volatile int i = 0×300000;
- while (i–);
- }
- int main(void)
- {
- char c;
- clock_init(); /* 初始化时钟 */
- gpio_init();</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">while (1)
- {
- PH_DAT = 0×00;
- delay();
- PH_DAT = 0xffff;
- delay();
- }</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">return 0;
- }</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">#include "clock.h"</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">#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 |= ((0×1<<4)|(0×1<<8)|(0X1<<28));
- PH_DRI = 0XFFFFFFFF;
- PH_PULL = 0X55555555;
- }</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">void delay()
- {
- volatile int i = 0×300000;
- while (i–);
- }
- int main(void)
- {
- char c;
- clock_init(); /* 初始化时钟 */
- gpio_init();</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">while (1)
- {
- PH_DAT = 0×00;
- delay();
- PH_DAT = 0xffff;
- delay();
- }</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">return 0;
- }
- 文件clock.c:</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">[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)</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">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)|(0×1<<4)|(0<<8)|(1<<16));</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">/*bit31:PLL1_Enable 1:Enable
- *bit25:EXG_MODE 0×0:Exchange mode
- *bit[17:16]:PLL1_OUT_EXT_DIVP 0×0:P=1
- *bit[12:8]:PLL1_FACTOR_N 0×10:Factor=16,N=16
- *bit[5:4]:PLL1_FACTOR_K 0×0:K=1
- *bit3:SIG_DELT_PAT_IN 0×0
- *bit2:SIG_DELT_PAT_EN 0×0
- *bit[1:0]PLL1_FACTOR_M 0×0:M=1
- *The PLL1 output=(24M*N*K)/(M*P)=(24M*16*1)/(1*1)=384M is for the coreclk
- */
- PLL1_CFG = 0xa1005000;</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">sdelay(200);</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">CPU_AHB_APB0_CFG = ((0<<0)|(0×1<<4)|(0<<8)|(2<<16));//CPU_CLK_SRC_SEL 10:PLL1</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">/*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 0×0: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 = (0×1<<16);
- }</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">#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)</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">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)|(0×1<<4)|(0<<8)|(1<<16));</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">/*bit31:PLL1_Enable 1:Enable
- *bit25:EXG_MODE 0×0:Exchange mode
- *bit[17:16]:PLL1_OUT_EXT_DIVP 0×0:P=1
- *bit[12:8]:PLL1_FACTOR_N 0×10:Factor=16,N=16
- *bit[5:4]:PLL1_FACTOR_K 0×0:K=1
- *bit3:SIG_DELT_PAT_IN 0×0
- *bit2:SIG_DELT_PAT_EN 0×0
- *bit[1:0]PLL1_FACTOR_M 0×0:M=1
- *The PLL1 output=(24M*N*K)/(M*P)=(24M*16*1)/(1*1)=384M is for the coreclk
- */
- PLL1_CFG = 0xa1005000;</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">sdelay(200);</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">CPU_AHB_APB0_CFG = ((0<<0)|(0×1<<4)|(0<<8)|(2<<16));//CPU_CLK_SRC_SEL 10:PLL1</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">/*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 0×0: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 = (0×1<<16);
- }</p>
复制代码 文件·clock.h: - [plain] view plaincopyprint?void clock_init(void);
复制代码 void clock_init(void);文件·Makefile: - <p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">[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</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">clean:
- rm -rf *.o *.bin led_elf *.dis</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">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</p><p style="margin-bottom: 1.714285714rem; border: 0px; vertical-align: baseline; ">clean:
- rm -rf *.o *.bin led_elf *.dis</p>
复制代码 代码确实很简单,上面也有看手册时留下的注释,就不分析了,有问题留言吧。 三、编译、测试 1.安装交叉编译链,给个链接 选择arm-2009q3-67-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2并下载。然后在ubuntu下直接解压即可,过程就不说了,还不清楚的看Ubuntu 10.04.4开发环境配置。 2.编译 - change :~$ cd Si/A10/2_led/
- change :~/Si/A10/2_led$ ls
- clock.c clock.h main.c Makefile mksunxiboot start.S
- 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 :~/Si/A10/2_led$ ./mksunxiboot led.bin leds.bin
- File size: 0×154
- Load size: 0×154
- Read 0×154 bytes
- Write 0×200 bytes
- 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卡,插到pcDuino上,RX LED就开始闪烁了。如果你手上有led,接到GPIO4、GPIO5也会闪烁。 |
转载于:https://my.oschina.net/u/1777508/blog/339753