• Home
  • pcDuino
  • WiKi
  • Store
  • Distributors
  • Home
  • pcDuino
  • WiKi
  • Store
  • Distributors
HomepcDuinoBare metal coding of pcDuino
Previous Next

Bare metal coding of pcDuino

Posted by: Alvin Jin , March 12, 2014

[vc_row][vc_column][vc_column_text]This project shows how to code a bare metal program for pcDuino.

Development Environment:
System: ubuntu 10.04.4
Hardware: pcDuino
Compiler: arm-2009q3-67-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2

Objective: To blink TX_LED of pcDuino.

First, hardware description

Look carefully at the schematic of pcDuino and pcDuino manual. According to the schematic ,TX_LED is connected to PH15, can be used as general IO port.

jump


Second,  write LED  led initialization it includes files start.S, main.c, clock.c, clock.h, Makefile and all the following code:


File start.S:

view plaincopyprint?.global _start

_start:
ldr sp, =0x00007f00

b main

.global _start

_start:
ldr sp, =0x00007f00

b main
file main.c:

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 |= ((0×1<<4)|(0×1<<8)|(0X1<<28));
PH_DRI   = 0XFFFFFFFF;
PH_PULL  = 0X55555555;
}

void delay()
{
volatile int i = 0×300000;
while (i–);
}
int main(void)
{
char c;
clock_init(); /* Initialize the clock */
gpio_init();

while (1)
{
PH_DAT = 0×00;
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 |= ((0×1<<4)|(0×1<<8)|(0X1<<28));
PH_DRI   = 0XFFFFFFFF;
PH_PULL  = 0X55555555;
}

void delay()
{
volatile int i = 0×300000;
while (i–);
}
int main(void)
{
char c;
clock_init(); /*Initialize the clock*/
gpio_init();

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

return 0;
}
file clock.c:

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&lt;&lt;0)|(0×1&lt;&lt;4)|(0&lt;&lt;8)|(1&lt;&lt;16));

/*bit31 PLL1_Enable 1:Enable
*bit25:EXG_MODE 0×0:Exchange mode
*bit[17:16] PLL1_OUT_EXT_DIVP 0x0P=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;

sdelay(200);

CPU_AHB_APB0_CFG = ((0&lt;&lt;0)|(0×1&lt;&lt;4)|(0&lt;&lt;8)|(2&lt;&lt;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 0×0:1 The pre-devided clock is divided by(m+1)
*/
APB1_CLK_DIV_CFG = ((0&lt;&lt;5)|(0&lt;&lt;16)|(0&lt;&lt;24));
/*open the clock for uart0*/
/*bit16:UART0_APB_GATING 1:pass 0:mask*/
APB1_GATE = (0×1&lt;&lt;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&lt;&lt;0)|(0×1&lt;&lt;4)|(0&lt;&lt;8)|(1&lt;&lt;16));

/*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;

sdelay(200);

CPU_AHB_APB0_CFG = ((0&lt;&lt;0)|(0×1&lt;&lt;4)|(0&lt;&lt;8)|(2&lt;&lt;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 0×0:1 The pre-devided clock is divided by(m+1)
*/
APB1_CLK_DIV_CFG = ((0&lt;&lt;5)|(0&lt;&lt;16)|(0&lt;&lt;24));
/*open the clock for uart0*/
/*bit16:UART0_APB_GATING 1 pass 0:mask*/
APB1_GATE = (0×1&lt;&lt;16);
}
file·clock.h:

view plaincopyprint?void clock_init(void);

void clock_init(void);文件·Makefile:

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

Third, compile and  test

1.Install the cross compiler chain, click link http://code.google.com/p/smp-on-qemu/downloads/list”> http://code.google.com/p/smp-on-qemu/downloads/list choose arm-2009q3-67-arm-none-linux-gnueabi-i686-pc- linux-gnu.tar.bz2 and download. Then extract it under ubuntu.If you do not know, you can refer to the Ubuntu 10.04.4 development environment configuration.

2. Compile

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: 0×154
Load size: 0×154
Read 0×154 bytes
Write 0×200 bytes
change@change:~/Si/A10/2_led$

3.Test

Above the generated leds.bin can running on the board. In order not to break the system of NAND, directly put  into the TF Card to operate. Don’t worry about the start, look at the  allwinner  allwinner manual, we can know pcDuino default to boot from the TF card. It will only boot from NAND if it failed to boot from SD card.

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$

Then remove the TF card ,insert into the pcDuino, and reboot.  RX, LED begin to blink.  If you have leds  connected to GPIO4, GPIO5, they will also blink.[/vc_column_text][/vc_column][/vc_row]

Tags: pcDuino, pcDuino Hardware Experiments

Share!
Tweet

Alvin Jin

About the author

Leave a Reply Cancel reply

You must be logged in to post a comment.

Category

  • Home
  • pcDuino
  • WiKi
  • Store
  • Distributors