S3C2410 bootloader ----VIVI阅读笔记

发布者:RadiantSerenity最新更新时间:2016-11-27 来源: eefocus关键字:S3C2410  bootloader  阅读笔记 手机看文章 扫描二维码
随时随地手机看文章

建议读一读《嵌入式系统Boot Loader技术内幕》(詹荣开著),google一下就会找到一片。什么是Bootloader就不再这里废话了,看看上面的文章就明了了。 Bootloader有很多种,如本文将要阅读的vivi,除此之外还有uboot,redboot,lilo等等。Vivi 是韩国mizi公司专门为三星s3c2410芯片设计的Bootloader。

先来看看vivi的源码树:

vivi-+-arch-+-s3c2410

|-Documentation

|-drivers-+-serial

| ‘-mtd-+-maps

| |-nor

| ‘-nand

|-include-+-platform

| |-mtd

| ‘-proc

|-init

|-lib-+-priv_data

|-scripts-+-lxdialog

|-test

|-util

可以google一下,搜到源码vivi.tar.gz。

前面提到的文件已经系统的分析了bootloader的,这里就按源代码来具体说事。vivi也可以分为2个阶段,阶段1的代码在arch/s3c2410/head.S中,阶段2的代码从init/main.c的main函数开始。

阶段1

阶段1从程序arch/s3c2410/head.S开始,按照head.S的代码执行顺序,一次完成了下面几个任务:

1、关WATCH DOG (disable watch dog timer)

上电后,WATCH DOG默认是开着的

2、禁止所有中断 (disable all interrupts)

vivi中不会用到中断,中断是系统的事,bootloader可不能去干这事的(不过这段代码实在多余,上电后中断默认是关闭的)

3、初始化系统时钟(initialise system clocks)

启动MPLL,FCLK=200MHz,HCLK=100MHz,PCLK=50MHz,“CPU bus mode”改为“Asynchronous bus mode”。

4、初始化内存控制寄存器(memsetup)

S3c2410共有15个寄存器,在此开始初始化13个寄存器。

5、检查是否从掉电模式唤醒(Check if this is a wake-up from sleep)

若是,则调用WakeupStart函数进行处理。

6、点亮所有LED (All LED on)

点一下灯,通知外面的同志,告诉他们有情况发生。

7、初始化UART0 (set GPIO for UART & InitUART)

a.设置GPIO,选择UART0使用的引脚

b.初始化UART0,设置工作方式(使用FIFO)、波特率115200 8N1、无流控等。这可是使用串口与s3c2410通信的条件啊,在终端也要如此设置。

8、跳到内存测试函数(simple memory test to find some DRAM flaults)

当然要定义了CONFIG_BOOTUP_MEMTEST这个参数才会跳到内存测试。

9、如果定义了以Nand flash方式启动(#ifdef CONFIG_S3C2410_NAND_BOOT),则此时要将vivi所有代码(包括阶段1和阶段2)从Nand flash复制到SDRAM中(因为在Nand flash中是不能执行程序的,它只能做为程序和数据的存储器,而Nor flash可就不同了,Nor flash可以执行程序,但贵是它发展得瓶颈):

a.设置nand flash控制寄存器

b.设置堆栈指针

c.设置即将调用的函数nand_read_ll的参数:r0=目的地址(SDRAM的地址),r1=源地址(nand flash的地址),r2=复制的长度(以字节为单位)

d.调用nand_read_ll进行复制

  10、跳到bootloader的阶段2运行,亦即调用init/main.c中的main函数(get read to call C functions)

a.重新设置堆栈

b.设置main函数的参数

c.调用main函数

head.S有900多行,都是些arm汇编,看的云山雾罩,汇编看来是忘的差不多了,所以这部分代码也看的相当糙,只知道大概在干什么,至于个中缘由就不是很了解。先学学arm汇编再回来看。

阶段2

从init/main.c中的main函数开始,终于步入C语言的世界了。Main函数总共有8步(8 steps),先看看源代码:

int main(int argc, char *argv[])

{

int ret;

/*

* Step 1:

*/

putstr("\r\n");

putstr(vivi_banner); //vivi_banner是vivi执行开始的显示信息,vivi_banner在文件version.c中定义

reset_handler();

/*

* Step 2:

*/

ret = board_init();

if (ret) {

putstr("Failed a board_init() procedure\r\n");

error();

}

/*

* Step 3:

*/

mem_map_init();

mmu_init();

putstr("Succeed memory mapping.\r\n");

/*

* Now, vivi is running on the ram. MMU is enabled.

* Step 4:

*/

/* initialize the heap area*/

ret = heap_init();

if (ret) {

putstr("Failed initailizing heap region\r\n");

error();

}

/* Step 5:

* MTD

*/

ret = mtd_dev_init();

/* Step 6:

*/

init_priv_data();

/* Step 7:

*/

misc();

init_builtin_cmds();

/* Step 8:

*/

boot_or_vivi();

return 0;

}

下面按照上面的步骤逐步来分析一下。

1、Step 1:reset_handler()

reset_handler用于将内存清零,代码在lib/reset_handle.c中。

1 void

2 reset_handler(void)

3 {

4 int pressed;

5 pressed = is_pressed_pw_btn(); /*判断是硬件复位还是软件复位*/

6 if (pressed == PWBT_PRESS_LEVEL) {

7 DPRINTK("HARD RESET\r\n");

8 hard_reset_handle(); /*调用clear_mem对SDRAM清0*/

9 } else {

10 DPRINTK("SOFT RESET\r\n");

11 soft_reset_handle(); /*此函数为空*/

12 }

13 }

在上电后,reset_handler调用第8行的hard_reset_handle(),此函数在lib/reset_handle.c中:

[main(int argc, char *argv[]) -> reset_handler() -> hard_reset_handle()]

1 static void

2 hard_reset_handle(void)

3 {

4 #if 0

5 clear_mem((unsigned long)(DRAM_BASE + VIVI_RAM_ABS_POS), \

6 (unsigned long)(DRAM_SIZE - VIVI_RAM_ABS_POS));

7 #endif

/*lib/memory.c,将起始地址为USER_RAM_BASE,长度为USER_RAM_SIZE的内存清0*/

8 clear_mem((unsigned long)USER_RAM_BASE, (unsigned long) USER_RAM_SIZE);

9 }

先写到这儿吧。

(未完待续)

S3C2410 bootloader ----VIVI阅读笔记2(续笔记1)

2、Step 2:board_init()

board_init调用2个函数用于初始化定时器和设置各GPIO引脚功能,代码在arch/s3c2410/smdk.c中:

[main(int argc, char *argv[]) > board_init()]

1 int board_init(void)

2 {

3 init_time(); /*arch/s3c2410/proc.c*/

4 set_gpios(); /*arch/s3c2410/smdk.c */

5 return 0;

6 }

init_time() 这个函数对寄存器进行了简单的操作:

void init_time(void)

{

TCFG0 = (TCFG0_DZONE(0) | TCFG0_PRE1(15) | TCFG0_PRE0(0));

/*s3c2410 data sheet P298*/

/*TCFG0 = 0 | 0xf00 | 0 */

}

寄存器TCFG0由三部分组成,prescaler0,prescaler1,deadzone和reserve四部分,前三部分分别对应 TCFG0_PRE0、TCFG0_PRE1、TCFG0_DZONE,TCFG0_PRE0(0)实际值为0x00,TCFG0_PRE1(15)实际值为0x0f00,而TCFG0_DZONE(0)实际值为 0x000000。实际中,vivi并未使用定时器,这个函数就可以忽略。set_gpios()用于选择GPA至GPH端口各引脚的功能及是否使用各引脚的内部上拉电阻,并设置外部中断源寄存器EXTINT0-2(vivi中未使用外部中断)。

1 void set_gpios(void)

2 {

3 GPACON = vGPACON;

4 GPBCON = vGPBCON;

5 GPBUP = vGPBUP;

6 GPCCON = vGPCCON;

7 GPCUP = vGPCUP;

8 GPDCON = vGPDCON;

9 GPDUP = vGPDUP;

10 GPECON = vGPECON;

11 GPEUP = vGPEUP;

12 GPFCON = vGPFCON;

13 GPFUP = vGPFUP;

14 GPGCON = vGPGCON;

15 GPGUP = vGPGUP;

16 GPHCON = vGPHCON;

17 GPHUP = vGPHUP;

18 EXTINT0 = vEXTINT0;

19 EXTINT1 = vEXTINT1;

20 EXTINT2 = vEXTINT2;

21 }

以第三行为例,vGPACON的值为0x007fffff,查找s3c2410用户手册可知,该参数将GPACON的23位全部置1。各位功能需察看s3c2410用户手册

3、Step 3:建立页表和启动MMU

mem_map_init();

mmu_init();

mem_map_init函数用于建立页表,vivi使用段式页表,只需要一级页表。它调用3个函数,代码在arch/s3c2410/mmu.c中:

[main(int argc, char *argv[]) > mem_map_init(void)]

1 void mem_map_init(void)

2 {

3 #ifdef CONFIG_S3C2410_NAND_BOOT

/*CONFIG_S3C2410_NAND_BOOT = y ,在文件include/autoconf.h中定义*/

4 mem_map_nand_boot();

/* 最终调用mem_mepping_linear, 建立页表 */

5 #else

6 mem_map_nor();

7 #endif

8 cache_clean_invalidate();/* 清空cache,使无效cache */

9 tlb_invalidate(); /* 使无效快表TLB */

10 }

第9、 10行的两个函数可以不用管它,他们做的事情在下面的mmu_init函数里又重复了一遍。对于本开发板,在.config中定义了 CONFIG_S3C2410_NAND_BOOT。mem_map_nand_boot()函数调用mem_mapping_linear()函数来最终完成建立页表的工作。页表存放在SDRAM物理地址0x33dfc000开始处,共16K:一个页表项4字节,共有4096个页表项;每个页表项对应 1M地址空间,共4G。mem_map_init先将4G虚拟地址映射到相同的物理地址上,NCNB(不使用cache,不使用write buffer)――这样,对寄存器的操作跟未启动MMU时是一样的;再将SDRAM对应的64M空间的页表项修改为使用cache。 mem_mapping_linear函数的代码在arch/s3c2410/mmu.c中:

[main(int argc, char *argv[]) > mem_map_init(void) > mem_map_nand_boot( ) > mem_mapping_linear(void)]

1 static inline void mem_mapping_linear(void)

2 {

3 unsigned long pageoffset, sectionNumber;

4 putstr_hex("MMU table base address = 0x", (unsigned long)

mmu_tlb_base);

5 /* 4G 虚拟地址映射到相同的物理地址. not cacacheable, not bufferable */

6 /* mmu_tlb_base = 0x33dfc000*/

7 for (sectionNumber = 0; sectionNumber < 4096; sectionNumber++) {

8 pageoffset = (sectionNumber << 20);

9 *(mmu_tlb_base + (pageoffset >> 20)) = pageoffset |

MMU_SECDESC;

10 }

11 /* make dram cacheable */

12 /* SDRAM物理地址0x3000000-0x33ffffff,

13 DRAM_BASE=0x30000000,DRAM_SIZE=64M

14 */

15 for (pageoffset = DRAM_BASE; pageoffset < (DRAM_BASE+DRAM_SIZE); \

16 pageoffset += SZ_1M) {

17 //DPRINTK(3, "Make DRAM section cacheable: 0x%08lx\n", pageoffset);

18 *(mmu_tlb_base + (pageoffset >> 20)) = \

pageoffset | MMU_SECDESC | MMU_CACHEABLE;

19 }

20 }

mmu_init()函数用于启动MMU,它直接调用arm920_setup()函数。arm920_setup()的代码在arch/s3c2410/mmu.c中:

[main(int argc, char *argv[]) > mmu_init( ) > arm920_setup( )]

1 static inline void arm920_setup(void)

2 {

3 unsigned long ttb = MMU_TABLE_BASE;

/* MMU_TABLE_BASE = 0x33dfc000 */

4 __asm__(

5 /* Invalidate caches */

6 "mov r0, #0\n"

7 "mcr p15, 0, r0, c7, c7, 0\n" /* invalidate I,D caches on v4 */

8 "mcr p15, 0, r0, c7, c10, 4\n" /* drain write buffer on v4 */

9 "mcr p15, 0, r0, c8, c7, 0\n" /* invalidate I,D TLBs on v4 */

10 /* Load page table pointer */

11 "mov r4, %0\n"

12 "mcr p15, 0, r4, c2, c0, 0\n" /* load page table pointer */

13 /* Write domain id (cp15_r3) */

14 "mvn r0, #0\n" /* Domains 0b01 = client, 0b11=Manager*/

15 "mcr p15, 0, r0, c3, c0, 0\n"

/* load domain access register,write domain 15:0, 用户手册P548(access permissions)*/

16 /* Set control register v4 */

17 "mrc p15, 0, r0, c1, c0, 0\n" /* get control register v4 */

/*数据手册P545:read control register */

18 /* Clear out 'unwanted' bits (then put them in if we need them) */

19 /* ..VI ..RS B... .CAM */ /*这些位的含义在数据手册P546*/

20 "bic r0, r0, #0x3000\n" /* ..11 .... .... .... */

/*I(bit[12])=0 = Instruction cache disabled*/

21 /*V[bit[13]](Base location of exception registers)=0 = Low addresses = 0x0000 0000*/

22 "bic r0, r0, #0x0300\n" /* .... ..11 .... .... */

23 /*R(ROM protection bit[9])=0*/

/*S(System protection bit[8])=0*/

/*由于TTB中AP=0b11(line141),所以RS位不使用(P579)*/

24 "bic r0, r0, #0x0087\n" /* 0x0000000010000111 */

/*M(bit[0])=0 = MMU disabled*/

/*A(bit[1])=0 =Data address alignment fault checking disable*/

/*C(bit[2])=0 = Data cache disabled*/

/*B(bit[7])=0= Little-endian operation*/

25 /* Turn on what we want */

26 /* Fault checking enabled */

27 "orr r0, r0, #0x0002\n" /* .... .... .... ..10 */

/*A(bit[1])=1 = Data address alignment fault checking enable*/

28 #ifdef CONFIG_CPU_D_CACHE_ON /*is not set*/

29 "orr r0, r0, #0x0004\n" /* .... .... .... .100 */

/*C(bit[2])=1 = Data cache enabled*/

30 #endif

31 #ifdef CONFIG_CPU_I_CACHE_ON /*is not set*/

32 "orr r0, r0, #0x1000\n" /* ...1 .... .... .... */

/*I(bit[12])=1 = Instruction cache enabled*/

33 #endif

34 /* MMU enabled */

35 "orr r0, r0, #0x0001\n" /* .... .... .... ...1 */

/*M(bit[0])=1 = MMU enabled*/

36 "mcr p15, 0, r0, c1, c0, 0\n" /* write control register */

/*数据手册P545*/

37 : /* no outputs */

38 : "r" (ttb) );

39 }

[未完]

S3C2410 bootloader ----VIVI阅读笔记3

4、Step 4:heap_init()

第4步调用了heap_init(void)函数,并返回值。该值是函数heap_init()调用的mmalloc_init()函数的返回值。其实,这步就是申请一块内存区域。

[lib/heap.c->heap_init(void)]

1 int heap_init(void)

2 {

3 return mmalloc_init((unsigned char *)(HEAP_BASE), HEAP_SIZE);

4 }

内存动态分配函数mmalloc就是从heap(堆)中划出一块空闲内存。相应的mfree函数则将动态分配的某块内存释放回heap中。

heap_init 函数在SDRAM中指定了一块1M大小的内存作为heap(起始地址HEAP_BASE = 0x33e00000),并在heap的开头定义了一个数据结构blockhead。事实上,heap就是使用一系列的blockhead数据结构来描述和操作的。每个blockhead数据结构对应着一块heap内存,假设一个blockhead数据结构的存放位置为A,则它对应的可分配内存地址为“A + sizeof(blockhead)”到“A + sizeof(blockhead) + size - 1”。blockhead数据结构在lib/heap.c中定义:

1 typedef struct blockhead_t {

2 int32 signature; //固定为BLOCKHEAD_SIGNATURE

3 bool allocated; //此区域是否已经分配出去:0-N,1-Y

4 unsigned long size; //此区域大小

5 struct blockhead_t *next; //链表指针

6 struct blockhead_t *prev; //链表指针

7 } blockhead;

现在来看看heap是如何运作的(如果您不关心heap实现的细节,这段可以跳过)。vivi对heap的操作比较简单,vivi中有一个全局变量 static blockhead *gHeapBase,它是heap的链表头指针,通过它可以遍历所有blockhead数据结构。假设需要动态申请一块sizeA大小的内存,则 mmalloc函数从gHeapBase开始搜索blockhead数据结构,如果发现某个blockhead满足:

(1) allocated = 0 //表示未分配

(2) size > sizeA,则找到了合适的blockhead,

满足上述条件后,进行如下操作:

a.allocated设为1

b.如果size ?C sizeA > sizeof(blockhead),则将剩下的内存组织成一个新的blockhead,放入链表中

c.返回分配的内存的首地址释放内存的操作更简单,直接将要释放的内存对应的blockhead数据结构的allocated设为0即可。

heap_init函数直接调用mmalloc_init函数进行初始化,此函数代码在lib/heap.c中,比较简单,初始化gHeapBase即可:

[main(int argc, char *argv[]) > heap_init(void) > mmalloc_init(unsigned char *heap, unsigned long size)]

1 static inline int mmalloc_init(unsigned char *heap, unsigned long size)

2 {

3 if (gHeapBase != NULL) return -1;

4 DPRINTK("malloc_init(): initialize heap area at 0x%08lx, size = 0x%08lx\n", heap, size);

5 gHeapBase = (blockhead *)(heap);

6 gHeapBase->allocated=FALSE;

7 gHeapBase->signature=BLOCKHEAD_SIGNATURE;

8 gHeapBase->next=NULL;

9 gHeapBase->prev=NULL;

10 gHeapBase->size = size - sizeof(blockhead);

11 return 0;

12 }

static blockhead *gHeapBase = NULL; 这个就是上面称赞的全局变量了,定义在lib/heap.c中。上面就是个链表操作,数据结构,看来搞这个也得好好学数据结构啊,不然内存搞的溢出、浪费可就哭都来不及了。

5、Step 5:mtd_dev_init()

所谓MTD(Memory Technology Device)相关的技术。在linux系统中,我们通常会用到不同的存储设备,特别是FLASH设备。为了在使用新的存储设备时,我们能更简便地提供它的驱动程序,在上层应用和硬件驱动的中间,抽象出MTD设备层。驱动层不必关心存储的数据格式如何,比如是FAT32、ETX2还是FFS2或其它。它仅仅提供一些简单的接口,比如读写、擦除及查询。如何组织数据,则是上层应用的事情。MTD层将驱动层提供的函数封装起来,向上层提供统一的接口。这样,上层即可专注于文件系统的实现,而不必关心存储设备的具体操作。这段乱七八糟的话也许比较让人晕,也可以这样理解在设备驱动(此处指存储设备)和上层应用之间还存在着一层,共三层,这个中间层就是MTD技术的产物。通常可以将它视为驱动的一部分,叫做上层驱动,而那些实现设备的读、写操作的驱动称为下层驱动,上层驱动将下层驱动封装,并且留给其上层应用一些更加容易简单的接口。

在我们即将看到的代码中,使用mtd_info数据结构表示一个MTD 设备,使用nand_chip数据结构表示一个nand flash芯片。在mtd_info结构中,对nand_flash结构作了封装,向上层提供统一的接口。比如,它根据nand_flash提供的 read_data(读一个字节)、read_addr(发送要读的扇区的地址)等函数,构造了一个通用的读函数read,将此函数的指针作为自己的一个成员。而上层要读写flash时,执行mtd_info中的read、write函数即可。

mtd_dev_init()用来扫描所使用的 NAND Flash的型号,构造MTD设备,即构造一个mtd_info的数据结构。对于S3C2410来说,它直接调用mtd_init(),mtd_init 又调用smc_init(),此函数在drivers/mtd/maps/s3c2410_flash.c中:

[main(int argc,char *argv[])>mtd_dev_init()>mtd_init()]

1 int mtd_init(void)

2 {

3 int ret;

4 #ifdef CONFIG_MTD_CFI /*is not set*/

5 ret = cfi_init();

6 #endif

7 #ifdef CONFIG_MTD_SMC9 /* =y */

8 ret = smc_init();

9 #endif

10 #ifdef CONFIG_S3C2410_AMD_BOOT /*is not set*/

11 ret = amd_init();

12 #endif

13 if (ret) {

14 mymtd = NULL;

15 return ret;

16 }

17 return 0;

18 }

显而易见,该函数应取第二项,这项在autoconf.h中定义了。

[main(int argc, char *argv[]) > mtd_dev_init() > mtd_init() > smc_init()]

1 static int

2 smc_init(void)

3 {

/*struct mtd_info *mymtd,数据类型在include/mtd/mtd.h*/

/*strcut nand_chip在include/mtd/nand.h中定义*/

4 struct nand_chip *this;

5 u_int16_t nfconf;

/* Allocate memory for MTD device structure and private data */

6 mymtd = mmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip));

7 if (!mymtd) {

8 printk("Unable to allocate S3C2410 NAND MTD device structure.\n");

9 return -ENOMEM;

10 }

/* Get pointer to private data */

11 this = (struct nand_chip *)(&mymtd[1]);

/* Initialize structures */

12 memset((char *)mymtd, 0, sizeof(struct mtd_info));

13 memset((char *)this, 0, sizeof(struct nand_chip));

/* Link the private data with the MTD structure */

14 mymtd->priv = this;

/* set NAND Flash controller */

15 nfconf = NFCONF;

/* NAND Flash controller enable */

16 nfconf |= NFCONF_FCTRL_EN;

/* Set flash memory timing */

17 nfconf &= ~NFCONF_TWRPH1; /* 0x0 */

18 nfconf |= NFCONF_TWRPH0_3; /* 0x3 */

19 nfconf &= ~NFCONF_TACLS; /* 0x0 */

20 NFCONF = nfconf;

/* Set address of NAND IO lines */

21 this->hwcontrol = smc_hwcontrol;

22 this->write_cmd = write_cmd;

23 this->write_addr = write_addr;

24 this->read_data = read_data;

25 this->write_data = write_data;

26 this->wait_for_ready = wait_for_ready;

/* Chip Enable -> RESET -> Wait for Ready -> Chip Disable */

27 this->hwcontrol(NAND_CTL_SETNCE);

28 this->write_cmd(NAND_CMD_RESET);

29 this->wait_for_ready();

30 this->hwcontrol(NAND_CTL_CLRNCE);

31 smc_insert(this);

32 return 0;

33 }

6 -14行构造了一个mtd_info结构和nand_flash结构,前者对应MTD设备,后者对应nand flash芯片(如果您用的是其他类型的存储器件,比如nor flash,这里的nand_flash结构应该换为其他类型的数据结构)。MTD设备是具体存储器件的抽象,那么在这些代码中这种关系如何体现呢――第 14行的代码把两者连结在一起了。事实上,mtd_info结构中各成员的实现(比如read、write函数),正是由priv变量所指向的 nand_flash的各类操作函数(比如read_addr、read_data等)来实现的。

15-20行是初始化S3C2410上的 NAND FLASH控制器。前面分配的nand_flash结构还是空的,现在当然就是填满它的各类成员了,这正是21-26行做的事情。27-30行对这块 nand flash作了一下复位操作。最后,也是最复杂的部分,根据刚才填充的nand_flash结构,构造mtd_info结构,这由31行的 smc_insert函数调用smc_scan完成。

这才是VIVI启动的第5步,还有三步就完成了启动了,同时我的这篇阅读笔记也就O了。


关键字:S3C2410  bootloader  阅读笔记 引用地址:S3C2410 bootloader ----VIVI阅读笔记

上一篇:ARM汇编常用伪操作总结
下一篇:NandFlash读写过程

推荐阅读最新更新时间:2024-03-16 15:22

s3c2410时钟信号:FCLK、HCLK和PCLK;clk_get_rate()
s3c2410 有三个时钟FLCK 、HCLK 和PCLK (这3个时针都是核心时针) s3c2410 芯片有这么一段话: FCLK is used by ARM920T ,内核时钟,主频。 HCLK is used for AHB bus, which is used by the ARM920T, the memory controller, the interrupt controller, the LCD controller, the DMA and USB host block. 也就是为AHB总线上的外设提供时钟信号,包括USB时钟。 AHB总线用于连接高速外设。 PCLK is used for APB bus,
[单片机]
<font color='red'>s3c2410</font>时钟信号:FCLK、HCLK和PCLK;clk_get_rate()
AVR BOOTLOADER 实例开发笔记
写了一个基于Atmega8 的Bootloader应用实例,其间遇到了一些问题,下面把过程和问题叙述如下,供朋友们参考。工程实例的代码在http://download.csdn.net/detail/knowmuch/7712209,也包含了一个C#的配套烧录程序,欢迎有兴趣的朋友们下载。 1、准备一个目标程序(被加载的应用程序),一般环境编译生成的结果是Hex文件,而写进Flash的是Bin文件。二者转换其实很简单,去掉Hex中的类型、长度、校验等,只留下数据依次排列就好了。 a)Hex文件格式:以ASCII格式记录,“:”表示一行开始,第1、2个字符表示此行数据长度。第3-6字符表示数据存储的起始地址,第7、8字符表示
[单片机]
AVR <font color='red'>BOOTLOADER</font> 实例开发<font color='red'>笔记</font>
ARM9 Bootloader的启动流程
Bootloader启动大多数都分为两个阶段.第一个阶段主要包含依赖于CPU的体系结构硬件初始化的代码,通常都用汇编语言来实现。这个阶段的任务有: 1、基本的硬件设备初始化(屏蔽所有的中断、关闭处理器内部指令/数据cache等)。 2、为第二阶段准备RAM空间。 3、如果是从某个固态存储煤质中,则复制Bootloader的第二阶段代码到RAM。 4、设置堆栈。 5、跳转到第二阶段的c程序入口点。 特别注意的地方: 在第一阶段中为什么要关闭cache?通常使用cache以及写缓冲是为了提高系统性能。但由于cache的使用可能改变访问主存的数量、类型和时间,因此Bootloader通常是不需要的
[单片机]
s3c2410/2440(armv4t) 移植Android
ARMv4移植简单 教程 : 相信国内很多朋友手上都有s3c2410/2440的片子,基于armv4t(arm920t)的指令架构。在之前,因为android的一些底层代码含 有armv5t的指令, 所以以前无法移植到这样的平台。 在这里也放出移植教程和已经编译好的image。 让更多的朋友可以在自己的开发板上亲身体验android。教程基于勤研qt2410以及扬创utu2440完成。 注意,移植是到armv4而不是armv4t, 原因应该是不开thumb支持会比较好移植一些(改动未涉及的库依然会用thumb代码,所以kernel依然要开thumb支持)。 kernel移植及nfs配置的详细部分等请自行查阅相关
[单片机]
S3C2410之NAND Flash MTD配置
1 ./drivers/mtd/nand/s3c2410.c static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, struct s3c2410_nand_mtd *nmtd, struct s3c2410_nand_set *set) 将NAND_ECC_SOFT改为NAND_ECC_NONE 2 ./arch/arm/plat-s3c24xx/common-smdk.c static struct mtd_partition smdk_default_nand_
[单片机]
MCU_S3C2410之ADC分析
基本概念: 1.采样定理,又称香农采样定理,奈奎斯特采样定理:即采样频率要大于模拟信号最高频率的两倍 2.A/D的位数,即A/D的分辨率,决定量化误差的大小(LSB)1LSB=1/2的N次方 3.转换速率:指一次A/D转换所需的时间,从接收转换开始控制信号到输出数字信号所花费的时间 A/D是高速还是低速皆以此为依据 4.量化误差(分辨率) 为了减小量化误差,通常输入端会加入0.5LSB的偏移量。 5.A/D的精度(DNL和INL) 用直尺来形象的描述,平常用的直尺,其最小刻度是1 毫米,然而,由于工艺等因素,使得直尺上的每个刻度并非都是精确的1 毫米,可能偏大,也可能偏小,DNL
[单片机]
MCU_<font color='red'>S3C2410</font>之ADC分析
嵌入式Linux下基于MiniGUI的GIS实现
1 引言 随着软硬件资源的成熟与完善,嵌入式技术的应用越来越广泛,而开放源码的Linux操作系统成为开发嵌入式产品的首选。MiniGUI是一个适用于嵌入式系统的、功能强大的、轻量级的图形用户界面支持系统,它具有占用资源少、高性能、高可靠性及可配置的特点,已经成功移植到多种硬件和操作系统平台上。我们利用MiniGUI在Linux上实现了一个嵌入式GIS,它能实现地图的显示、放大、缩小、漫游等基本功能。 2、MiniGUI的特点和体系结构 2.1 MiniGUI的特点 与其它针对嵌入式产品的图形系统相比,MiniGUI具有以下一些技术优势: 1)遵循GPL条款的纯自由软件。 2)多字符集和多字体支持
[单片机]
嵌入式Linux下基于MiniGUI的GIS实现
S3C2410 的拓展
接口设计: 对SDRAM初始化 对内存控制器初始化 memsetup: mov r1,#MEM_CTL_BASE adrl r2,mem_cfg_val add r3,r1,#52 ldr r4, ,#4 str r4, ,#4 cmp r1,r3 bne 1b mov pc,lr 复制代码到SDRAM,将SRAM中的4K数据全部复制到SDRAM, SRAM起始地址为0x00000000,SDRAM的起始地址为0x30000000 copy_steppingstone_to_sdram: mov r1,#0 ldr r2,=SDRAM_
[单片机]
<font color='red'>S3C2410</font> 的拓展
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved