1、S5P6818 Boot Header
手册上对Boot Header部分是这么描述的,所有的启动模式都会检查512字节的引导头,引导头假设第一次接收或者从启动设备都是加载到SRAM中,地址为0xFFFF0000。首先,当接收到512字节时,签名值必须是0x4849534E,如果不相等,则会从下一个启动设备重新启动。
意思就是,在你的程序前面必须有512字节的指定数据,这其实是厂家提供的一个文件,你只需把这些数据添加到你的bin文件之前
2、Boot Header中都有什么
在我的这块开发板提供的uboot源码中,找到了这个文件 “nsih.txt”,这个虽然是个txt文件,但里面的有效内容都是机器码,//开头的均为注释,其他的为有效部分。简单来说,你只需要通过文件操作把你的bin文件和这个里面的机器码组合到一个文件即可,事实是可不止这一个文件,这里之所以这么说,是因为这一个文件已经能够满足我们简单的裸机开发,后续的文章会更加详细全面的讲解。下面我们来看一下nsih.txt都描述了什么
//------------------------------------------------------------------------------
// Copyright (C) 2012 Nexell Co., All Rights Reserved
// Nexell Co. Proprietary < Confidential
//
// NEXELL INFORMS THAT THIS CODE AND INFORMATION IS PROVIDED "AS IS" BASE
// AND WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING
// BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS
// FOR A PARTICULAR PURPOSE.
//
// Module : Boot Header
// File : NSIH.txt
// Description : system initialize info
// Author : Firmware Team
// History :
// Hans 2014.01.13 Excel Generator
// Hans 2013.06.23 Create
//------------------------------------------------------------------------------
// Excel sheet version - 0.3.00
//------------------------------------------------------------------------------
// This must be synchronized with SecondBoot.h
//------------------------------------------------------------------------------
// Nexell System Infomation Header
//------------------------------------------------------------------------------
// Vector Code Area
E59FF018 // 0x000 : MOV PC, ResetV
E59FF018 // 0x004 : MOV PC, UndefV
E59FF018 // 0x008 : MOV PC, SWIV
E59FF018 // 0x00C : MOV PC, PAbortV
E59FF018 // 0x010 : MOV PC, DAbortV
E59FF018 // 0x014 : MOV PC, NotUsed
E59FF018 // 0x018 : MOV PC, IRQV
E59FF018 // 0x01C : MOV PC, FIQV
FFFF0200 // 0x020 : SRAMBASE + Header
FFFF0204 // 0x024 : SRAMBASE + Header
FFFF0208 // 0x028 : SRAMBASE + Header
FFFF020C // 0x02C : SRAMBASE + Header
FFFF0210 // 0x030 : SRAMBASE + Header
FFFF0214 // 0x034 : SRAMBASE + Header
FFFF0218 // 0x038 : SRAMBASE + Header
FFFF021C // 0x03C : SRAMBASE + Header
//------------------------------------------------------------------------------
// Main Bootloader Load Info
//------------------------------------------------------------------------------
00008000 // 0x040 : Device Read Address from 2ndboot Device.
00040000 // 0x044 : Load Size for 2ndboot.
FFFF0000 // 0x048 : Load Address for 2ndboot.
FFFF0000 // 0x04C : Launch Address for 2ndboot.
00000000 // 0x050 [7:0] - Channel number
00000000 // 0x054 Boot From SDMMC [31:24] - 0: USB, 1: SPI, 2: NAND, 3:SDMMC, 4: SDFS
00000000 // 0x058
//------------------------------------------------------------------------------
// CLKPWR registers
//------------------------------------------------------------------------------
100CC801 // 0x05C : PLL0 800MHz P:3 M:200 S:1
100CC801 // 0x060 : PLL1 800MHz P:3 M:200 S:1
100CC301 // 0x064 : PLL2 780MHz P:3 M:195 S:1 K:0
100CC801 // 0x068 : PLL3 800MHz P:3 M:200 S:1 K:0
00000104 // 0x06C : PLL2 SPREAD
00000104 // 0x070 : PLL3 SPREAD
00000601 // 0x074 : CPU G0 PLL1 /FCLK:800 /HCLK:200
00000208 // 0x078 : BUS PLL0 /BCLK:400 /PCLK:200
00208003 // 0x07C : MEM PLL3 /MDCLK:800 /MCLK:800 /MBCLK:400 /MPCLK:200
00000208 // 0x080 : GR3D PLL0 /GR3DBCLK:400
00000208 // 0x084 : MPEG PLL0 /MPEGBCLK:400 /MPEGPCLK:200
00000208 // 0x088 : DISP PLL0 /DISPBCLK:400 /DISPPCLK:200
00000028 // 0x08C : HDMI PLL0 /HDMIPCLK:133.333333333333
00000601 // 0x090 : CPU G1 PLL1 /FCLK:800 /HCLK:200
00000208 // 0x094 : CCI4 PLL0 /CCI4BCLK:400 /CCI4PCLK:200
//------------------------------------------------------------------------------
// MCU-D registers
//------------------------------------------------------------------------------
// Mem Controller Configuration
03100301 // 0x098 /Chip Num:1 /Chip Row:15 /Bus Width:16 /Chip Col:10
004007C0 // 0x09C 256MB x 2ea (16bit) x 1CS
06000B08 // 0x0A0 /CWL:8 /CL:11 /MR1_AL:0 /MR0_WR:6
// DDR PHY delay timing Configuration
0C0C0C0C // 0x0A4
04040404 // 0x0A8
// DDR AC Timing Configuration
0000401B // 0x0AC /tPZQ:16411
00620618 // 0x0B0 /Refresh Interval:7.8us
6836650E // 0x0B4 /tRFC:104 /tRRD:3 /tRP:6 /tRCD:6 /tRC:20 /tRAS:14
3630580B // 0x0B8 /tWTR:3 /tWR:6 /tRTP:3
31000A26 // 0x0BC /tFAW:12 /tXSR:256 /tXP:10 /tCKE:2
// DDR3 device - Drive strength value.
00020102 // 0x0C0 [23:16] MR1_RTT_Nom - 001: RZQ/4, 010: RZQ/2, 011: RZQ/6, 100: RZQ/12, 101: RZQ/8, [15:0] MR1_ODS - 0: RZQ/6, 1 : RZQ/7, [7:0] MR2_RTT_WR - 0: ODT disable, 1: RZQ/4, 2: RZQ/2
// DDR PHY Controller - Drive strength value.
06060606 // 0x0C4 [31:24] Byte3, [23:16] Byte2, [15:8] Byte1, [7:0] Byte0 - 240ohm / (n + 1), n = (1 ~ 7)
06060606 // 0x0C8 [31:24] CA, [23:16] CS, [15:8] CKE, [7:0] CK - 240ohm / (n + 1), n = (1 ~ 7)
00000104 // 0x0CC [15:8] ZQ_ODT, [7:0] ZQ_DDS - 240ohm / (n + 1), n = (1 ~ 7)
// Leveling & Training.
00000004 // 0x0D0 WR_CAL[4], RD_CAL[3], GT_LVL[2], CA_CAL[1], WR_LVL[0]
//------------------------------------------------------------------------------
// STUB
//------------------------------------------------------------------------------
00000000 // 0x0D4
00000000 // 0x0D8
00000000 // 0x0DC
00000000 // 0x0E0
00000000 // 0x0E4
00000000 // 0x0E8
00000000 // 0x0EC
00000000 // 0x0F0
00000000 // 0x0F4
00000000 // 0x0F8
00000000 // 0x0FC
00000000 // 0x100
00000000 // 0x104
00000000 // 0x108
00000000 // 0x10C
00000000 // 0x110
00000000 // 0x114
00000000 // 0x118
00000000 // 0x11C
00000000 // 0x120
00000000 // 0x124
00000000 // 0x128
00000000 // 0x12C
00000000 // 0x130
00000000 // 0x134
00000000 // 0x138
00000000 // 0x13C
00000000 // 0x140
00000000 // 0x144
00000000 // 0x148
00000000 // 0x14C
00000000 // 0x150
00000000 // 0x154
00000000 // 0x158
00000000 // 0x15C
00000000 // 0x160
00000000 // 0x164
00000000 // 0x168
00000000 // 0x16C
00000000 // 0x170
00000000 // 0x174
00000000 // 0x178
00000000 // 0x17C
00000000 // 0x180
00000000 // 0x184
00000000 // 0x188
00000000 // 0x18C
00000000 // 0x190
00000000 // 0x194
00000000 // 0x198
00000000 // 0x19C
00000000 // 0x1A0
00000000 // 0x1A4
00000000 // 0x1A8
00000000 // 0x1AC
00000000 // 0x1B0
00000000 // 0x1B4
00000000 // 0x1B8
00000000 // 0x1BC
00000000 // 0x1C0
00000000 // 0x1C4
00000000 // 0x1C8
00000000 // 0x1CC
00000000 // 0x1D0
00000000 // 0x1D4
00000000 // 0x1D8
00000000 // 0x1DC
00000000 // 0x1E0
00000000 // 0x1E4
00000000 // 0x1E8
00000000 // 0x1EC
00000000 // 0x1F0
00000000 // 0x1F4
00000000 // 0x1F8
//------------------------------------------------------------------------------
// Signature
//------------------------------------------------------------------------------
4849534E // 0x1FC """NSIH"""
第一部分:Vector Code Area
这一部分是异常向量表,熟悉ARM架构的都应该清楚,ARM异常共有9种,分别是复位异常、未定义指令异常、软件中断异常、预取指终止异常、读取数据终止异常、保留、中断异常、快中断异常。这几种异常分别位于CPU的0地址起始位置,当发生异常时,就会跳转到对应的位置执行。
例如未定义指令异常 位于CPU地址 0x04处,当CPU读到一个未定义指令时,CPU会自动跳转到0x04处执行该处的指令,从而可以进入我们之前设计好的处理函数。
关于异常向量表,我们会在后期的文章中继续讲述,这里只是做一下简单说明。
第二部分:硬件参数
从异常向量表往下的部分就是配置参数,包括用户程序的起始地址,重定向的地址和大小,CPU的时钟参数,SDRAM的初始化参数等,当然还有一个非常重要的签名值 0x4849534E,这个签名值位于这512字节的最后4个字节,非常重要,当CPU没有检测到这个签名值时,就会自动转向下一个boot device。
3、一个简单的裸机程序编写
硬件:S5P6818开发板 LED引脚:GPIOE13 ,低电平亮
汇编代码:
/*点亮LED
**LED1 GPIOE13
**低电平点亮,高电平熄灭
*/
#define GPIOEOUT 0xC001E000
#define GPIOEOUTENB 0xC001E004
#define GPIOEALTFN0 0xC001E020
.text
.global _start
_start:
b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort: .word data_abort
_not_used: .word not_used
_irq: .word irq
_fiq: .word fiq
reset:
//初始化GPIOE13 为输出引脚
ldr r0,=GPIOEALTFN0
ldr r1,[r0]
mov r2,#(3<<26)
bic r1,r1,r2
str r1,[r0]
ldr r0,=GPIOEOUTENB
ldr r1,[r0]
orr r1,#(1<<13)
str r1,[r0]
//灭灯
ldr r0,=GPIOEOUT
ldr r1,[r0]
orr r1,#(1<<13)
str r1,[r0]
b loop
undefined_instruction:
b .
software_interrupt:
b .
prefetch_abort:
b .
data_abort:
b .
not_used:
b .
irq:
b .
fiq:
b .
loop:
//亮灯
ldr r0,=GPIOEOUT
ldr r1,[r0]
bic r1,#(1<<13)
str r1,[r0]
ldr r0,=9000000 //通过r0传递参数
bl delay //bl:跳转到子程序,并保存返回地址到lr
//灭灯
ldr r0,=GPIOEOUT
ldr r1,[r0]
orr r1,#(1<<13)
str r1,[r0]
ldr r0,=9000000
bl delay
b loop
//延时
delay:
sub r0,#1 //减1
cmp r0,#0 //和0比较
bne delay
moveq pc,lr
.end
Makefile:
all:
arm-linux-gcc led.S -c -march=armv4t -o led.o -nostdlib
arm-linux-ld -Ttext 0x0 led.o -o led.elf
arm-linux-objcopy -O binary led.elf led.bin
arm-linux-objdump -D led.elf > led.dis
clean:
rm *.o *.elf *.bin *.dis
.PHONY:clean
make产生的led.bin文件
提前准备好的boot header:从这个文件bootled.bin中提取了前512字节
用户代码的bin文件和boot header的bin文件都准备好了,这里采用手动拼接的方法,也可以通过编程来实现,因为后面我们还会采用程序的方法来连接boot header和2ndboot,所以这里简单使用手动拼接的方法,bin编辑软件使用Hex Editor或者UltraEdit都可以,这里我使用Hex Editor
1、新建一个空白的bin文件
2、复制boot header部分,粘贴到新建的bin文件中0地址处
3、复制led.bin用户代码,紧接着在0x200位置粘贴
4、保存为led_m.bin到工程目录,就可以使用了
到此,一个简单的裸机程序就好了,要想在6818开发板上运行了,下一步就是烧写到SD卡,这个我们下一篇文章再讲。
本篇中的代码文件:
链接:https://pan.baidu.com/s/1Mm3CL2cMWKZTn45tQAul0w
提取码:x4qk