U-Boot 在ARM开发板上的移植以及代码分析.doc_第1页
U-Boot 在ARM开发板上的移植以及代码分析.doc_第2页
U-Boot 在ARM开发板上的移植以及代码分析.doc_第3页
U-Boot 在ARM开发板上的移植以及代码分析.doc_第4页
U-Boot 在ARM开发板上的移植以及代码分析.doc_第5页
免费预览已结束,剩余13页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

U-Boot 在44B0X 开发板上的移植以及代码分析1. u-boot 介绍 u-boot 是一个open source 的bootloader,目前版本是1.1.2。u-boot 是在ppcboot 以及armboot 的基础上发展而来,相当的成熟和稳定,已经在许多嵌入式系统开发过程中被采用。由于其开发源代码,其支持的开发板众多。 为什么我们需要u-boot?显然可以将uClinux 直接烧入flash,从而不需要额外的引导装载程序(bootloader)。但是从软件升级的角度以及程序修补的来说,软件的自动更新非常重要。事实上,引导装载程序(bootloader)的用途不仅如此,但仅从软件的自动更新的需要就说明我们的开发是必要的。同时,u-boot 移植的过程也是一个对嵌入式系统包括软硬件以及操作系统加深理解的一个过程。2. u-boot 移植的框架移植u-boot 到新的开发板上仅需要修改和硬件相关的部分。在代码结构上:1) 在board 目录下创建gold44b 目录,创建gold44b.c 以及flash.c,memsetup.S,u-boot.lds等。不需要从零开始,可选择一个相似的目录,直接复制过来,修改文件名以及内容。我在移植u-boot 过程中,选择的是Dave/B2目录。由于u-boot 已经包含基于s3c24b0 的开发板目录,作为参考,也可以复制相应的目录。2) 在cpu 目录下创建s3c44b0x 目录,主要包含start.S,interrupts.c 以及cpu.c,serial.c几个文件。同样不需要从零开始建立文件,直接从arm720t 复制,然后修改相应内容。3) 在include/configs 目录下添加gold44b.h,在这里放上全局的宏定义等。4) 找到u-boot 根目录下Makefile 修改加入gold44b_config : unconfig./mkconfig $(:_config=) arm s3c44b0 gold44b5) 运行make ev44bii_config,如果没有错误就可以开始硬件相关代码移植的工作3. u-boot 的体系结构1) 总体结构u-boot 是一个层次式结构。做移植工作的软件人员应当提供串口驱动(UART Driver),以太网驱动(Ethernet Driver),Flash 驱动(Flash 驱动),USB 驱动(USB Driver)。目前,通过USB 口下载程序显得不是十分必要,而且开发板上也没有USB接口,所以暂时没有移植USB 驱动。驱动层之上是u-boot 的应用,command 通过串口提供人机界面。我们可以使用一些命令做一些常用的工作,比如内存查看命令md。Kermit 应用主要用来支持使用串口通过超级终端下载应用程序。TFTP 则是通过网络方式来下载应用程序,例如uClinux 操作系统。2) 内存分布gold44b 的flash 大小2M(8bits),现在将0-40000 共256k 作为u-boot 的存储空间。由于u-boot 中有一些环境变量,例如ip 地址,引导文件名等,可在命令行通过setenv 配置好,通过saveenv 保存在40000-50000(共64k)这段空间里。如果存在保存好的环境变量,u-boot 引导将直接使用这些环境变量。正如从代码分析中可以看到,我们会把flash 引导代码搬移到DRAM 中运行。u-boot 的代码在DRAM中的位置在u-boot-1.1.2/board/gold44b/config.mk配置如下:TEXT_BASE = 0x0C700000。这样,引导代码u-boot将从0x0000 0000 处搬移到0x0C700000 处。特别注意的由于gold44b uClinux 中断向量程序地址在0x0c000 0000 处,所以不能将程序下载到0x0c000 0000 出,通常下载到0x0c008 0000 处。4. start.S 代码结构1) 定义入口一个可执行的Image 必须有一个入口点并且只能有一个唯一的全局入口,通常这个入口放在Rom(flash)的0x0 地址。例如start.S 中的.globl _start_start:值得注意的是你必须告诉编译器知道这个入口,这个工作主要是修改连接器脚本文件(lds)。开发板上的u-boot.lds如下:OUTPUT_FORMAT(elf32-littlearm, elf32-littlearm, elf32-littlearm)OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS. = 0x00000000;. = ALIGN(4);.text :cpu/s3c44b0/start.o (.text)*(.text). = ALIGN(4);.rodata : *(.rodata) . = ALIGN(4);.data : *(.data) . = ALIGN(4);.got : *(.got) _u_boot_cmd_start = .;.u_boot_cmd : *(.u_boot_cmd) _u_boot_cmd_end = .;armboot_end_data = .;. = ALIGN(4);_bss_start = .;.bss : *(.bss) _end = .;2) 设置异常向量(Exception Vector)异常中断矢量表(Exception Vector Table)是u-boot与uClinux内核发生联系关键的地方之一。即使uClinux内核已经得到处理器的控制权运行,一旦发生中断,处理器还是会自动跳转到从0x0地址开始的第一级异常中断矢量表中的某个表项(依据于中断类型)处读取指令运行。异常中断矢量表必须是从0 地址开始,连续的存放。如下面的就包括了复位(reset),未定义处理(undef),软件中断(SWI),预去指令错误(Pabort),数据错误 (Dabort),保留,以及IRQ,FIQ 等。注意这里的值必须与uClinux 的vector_base 一致。这就是说如果uClinux 中vector_base(include/armnommu/proc-armv/system.h)定义为0x0c00 0000,则HandleUndef 应该在0x0c00 0004。.globl _start_start: b reset/*Modfied by zl 2005-2-21 */* add pc, pc, #0x0c000000add pc, pc, #0x0c000000add pc, pc, #0x0c000000add pc, pc, #0x0c000000add pc, pc, #0x0c000000add pc, pc, #0x0c000000add pc, pc, #0x0c000000 */ldr pc, =0x0c000004ldr pc, =0x0c000008ldr pc, =0x0c00000cldr pc, =0x0c000010ldr pc, =0x0c000014ldr pc, =0x0c000018ldr pc, =0x0c00001c.balignl 16,0xdeadbeef这里,地址0x0处的一级异常中断矢量表只简单地包含向二级异常中断矢量表的跳转指令就可以。这样,就能够正确地将发生的事件交给uClinux的中断处理程序来处理。这样设计是因为在本u-boot移植里不使用中断,8019和Timer都是轮询中断的,如果u-boot要使用中断(如要用到USB设备),就需要建立二级异常中断矢量表了。代码如下(没有调试通过):.globl _start_start: b resetadd pc, pc, #0x0c000000add pc, pc, #0x0c000000add pc, pc, #0x0c000000add pc, pc, #0x0c000000add pc, pc, #0x0c000000add pc, pc, #0x0c000000add pc, pc, #0x0c000000 .balignl 16,0xdeadbeef .在Reset是复制中断矢量表/*now copy to sram the interrupt vector*/adr r0, real_vectorsadd r2, r0, #1024ldr r1, =0x0c000000add r1, r1, #0x08vector_copy_loop:ldmia r0!, r3-r10stmia r1!, r3-r10cmp r0, r2ble vector_copy_loop .建立三级中断跳转/*/* interrupt vectors */*/*real_vectors:b resetb undefined_instructionb software_interruptb prefetch_abortb data_abortb not_usedb irqb fiq */*/undefined_instruction:mov r6, #3b resetsoftware_interrupt:mov r6, #4b resetprefetch_abort:mov r6, #5b resetdata_abort:mov r6, #6b resetnot_used:/* we *should* never reach this */mov r6, #7b resetirq:mov r6, #8b resetfiq:mov r6, #9b reset3) 初始化CPU 相关的pll,clock,中断控制寄存器依次为关闭watch dog timer,关闭中断,设置LockTime,PLL(phase lock loop),以及时钟。这些值(除了LOCKTIME)都可从Samsung 44b0 的手册中查到。/* CPU_init_critical registers* setup important registers* setup memory timing*/#define INTCON (0x01c00000+0x200000)#define INTMSK (0x01c00000+0x20000c)#define LOCKTIME (0x01c00000+0x18000c)#define PLLCON (0x01c00000+0x180000)#define CLKCON (0x01c00000+0x180004)#define WTCON (0x01c00000+0x130000)cpu_init_crit:/* disable watch dog */ldr r0, =WTCONldr r1, =0x0str r1, r0/* mask all IRQs by clearing all bits in the INTMRs*/ldr r1,=INTMSKldr r0, =0x03fffeffstr r0, r1ldr r1, =INTCONldr r0, =0x05str r0, r1/* Set Clock Control Register */ldr r1, =LOCKTIMEldrb r0, =800strb r0, r1ldr r1, =PLLCON#if CONFIG_S3C44B0_CLOCK_SPEED=64ldr r0, =0x38021 /* smdk4110: Xtal=8MHz Fclk=64MHz */#elif CONFIG_S3C44B0_CLOCK_SPEED=66ldr r0, =0x34031 /* 66MHz (Quartz=11MHz) */#elif CONFIG_S3C44B0_CLOCK_SPEED=75ldr r0, =0x610c1 /*B2: Xtal=20mhz Fclk=75MHz */#else# error CONFIG_S3C44B0_CLOCK_SPEED undefined#endifstr r0, r1ldr r1,=CLKCONldr r0, =0x7ff8str r0, r1mov pc, lr4) 初始化SDRAM控制器内存控制器(主要是SDRAM控制器),主要通过设置13 个从1c80000 开始的寄存器来设置,包括总线宽度,8 个内存bank,bank 大小,sclk,以及两个bank mode。#ifdef CONFIG_INIT_CRITICALbl cpu_init_crit/* before relocating, we have to setup RAM timing* because memory timing is board-dependend, you will* find a memsetup.S in your board directory.*/bl memsetup#endif初始化内存控制器的代码存放在u-boot-1.1.2/board/gold44b/memsetup.S中与ADS或者SDT下的boot代码(memcfg.s和44binit.s)一致,只是汇编格式有点不一样。5) 将rom 中的程序复制到RAM 中首先利用PC 取得bootloader 在flash 的起始地址,再通过标号之差计算出这个程序代码的大小。这些标号,编译器会在连接(link)的时候生成正确的分布的值。取得正确信息后,通过寄存器(r3 到r10)做为复制的中间媒介,将代码复制到RAM 中。relocate: /* relocate U-Boot to RAM */adr r0, _start /* r0 - current position of code */ldr r1, _TEXT_BASE /* test if we run from flash or RAM */cmp r0, r1 /* dont reloc during debug */beq stack_setupldr r2, _armboot_startldr r3, _bss_startsub r2, r3, r2 /* r2 - size of armboot */add r2, r0, r2 /* r2 baudrate) + 0.5) -1 )计算得出。这可以在手册中查到。由于u-boot支持可变的波特率,所以采用宏定义设置默认波特率(64Mhz,115200bps)和其他波特率。代码如下:void serial_setbrg (void)DECLARE_GLOBAL_DATA_PTR;u32 divisor = 0;/* get correct divisor */switch(gd-baudrate) case 1200:#if CONFIG_S3C44B0_CLOCK_SPEED=66divisor = 3124;#elif CONFIG_S3C44B0_CLOCK_SPEED=75divisor = 3905;#elif CONFIG_S3C44B0_CLOCK_SPEED=64 /默认divisor = 3332;#else# error CONFIG_S3C44B0_CLOCK_SPEED undefined#endifbreak;case 9600:#if CONFIG_S3C44B0_CLOCK_SPEED=66divisor = 390;#elif CONFIG_S3C44B0_CLOCK_SPEED=75divisor = 487;#elif CONFIG_S3C44B0_CLOCK_SPEED=64 /默认divisor = 416;#else# error CONFIG_S3C44B0_CLOCK_SPEED undefined#endifbreak;case 19200:#if CONFIG_S3C44B0_CLOCK_SPEED=66divisor = 194;#elif CONFIG_S3C44B0_CLOCK_SPEED=75divisor = 243;#elif CONFIG_S3C44B0_CLOCK_SPEED=64 /默认divisor = 207;#else# error CONFIG_S3C44B0_CLOCK_SPEED undefined#endifbreak;case 38400:#if CONFIG_S3C44B0_CLOCK_SPEED=66divisor = 97;#elif CONFIG_S3C44B0_CLOCK_SPEED=75divisor = 121;#elif CONFIG_S3C44B0_CLOCK_SPEED=64 /默认divisor = 103;#else# error CONFIG_S3C44B0_CLOCK_SPEED undefined#endif break;case 57600:#if CONFIG_S3C44B0_CLOCK_SPEED=66divisor = 64;#elif CONFIG_S3C44B0_CLOCK_SPEED=75divisor = 80;#elif CONFIG_S3C44B0_CLOCK_SPEED=64 /默认divisor = 68;#else# error CONFIG_S3C44B0_CLOCK_SPEED undefined#endif break;case 115200:#if CONFIG_S3C44B0_CLOCK_SPEED=66divisor = 32;#elif CONFIG_S3C44B0_CLOCK_SPEED=64divisor = 34;#elif CONFIG_S3C44B0_CLOCK_SPEED=75 /默认divisor = 40;#else# error CONFIG_S3C44B0_CLOCK_SPEED undefined#endif break;serial_flush_output();serial_flush_input();UFCON0 = 0x0;ULCON0 = 0x03;UCON0 = 0x05;UBRDIV0 = divisor;UFCON1 = 0x0;ULCON1 = 0x03;UCON1 = 0x05;UBRDIV1 = divisor;for(divisor=0; divisor100; divisor+) /* NOP */其他的函数包括发送,接收。这个时候没有中断,是通过循环等待来判断是否动作完成。例如,接收函数:static int serial_flush_input(void)volatile u32 tmp;/* keep on reading as long as the receiver is not empty */while(UTRSTAT0&0x01) tmp = REGB(URXH0);return 0;2) 时钟部分(u-boot-1.1.2/cpu/s3c44b0/interrupt.c)实现了延时函数udelay。这里的get_timer 由于没有使用中断,是使用全局变量来累加的。void udelay (unsigned long usec)ulong tmo;tmo = usec / 1000;tmo *= CFG_HZ;tmo /= 8;tmo += get_timer (0);while (get_timer_masked () tmo)/*NOP*/;3) flash 部分(u-boot-1.1.2/board/gold44b.c)flash 作为内存的一部分,读肯定没有问题,关键是flash 的写部分。Flash 的写必须先擦除,然后再写。flash_init 完成初始化部分,这里的主要目的是检验flash 的型号是否正确。unsigned long flash_init (void)#ifdef _DEBUG_START_FROM_SRAM_return CFG_DUMMY_FLASH_SIZE;#elseunsigned long size_b0;int i;/* Init: no FLASHes known */for (i=0; iCFG_MAX_FLASH_BANKS; +i) flash_infoi.flash_id = FLASH_UNKNOWN;/* Static FLASH Bank configuration here - FIXME XXX */size_b0 = flash_get_size(vu_long *)CFG_FLASH_BASE, &flash_info0);if (flash_info0.flash_id = FLASH_UNKNOWN) printf (# Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MBn,size_b0, size_b0start0);volatile CFG_FLASH_WORD_SIZE *addr2;int flag, prot, sect, l_sect;ulong start, now, last;int i;if (s_first s_last) if (info-flash_id = FLASH_UNKNOWN) printf (- missingn); else printf (- no sectors to erasen);return 1;if (info-flash_id = FLASH_UNKNOWN) printf (Cant erase unknown flash type - abortedn);return 1;prot = 0;for (sect=s_first; sectprotectsect) prot+;if (prot) printf (- Warning: %d protected sectors will not be erased!n,prot); else printf (n);l_sect = -1;/* Disable interrupts which might cause a timeout here */flag = disable_interrupts();/* Start erase on unprotected sectors */for (sect = s_first; sectprotectsect = 0) /* not protected */addr2 = (CFG_FLASH_WORD_SIZE *)(info-startsect);if (info-flash_id & FLASH_VENDMASK) = FLASH_MAN_SST) addrCFG_FLASH_ADDR0 = (CFG_FLASH_WORD_SIZE)0x00AA00AA;addrCFG_FLASH_ADDR1 = (CFG_FLASH_WORD_SIZE)0x00550055;addrCFG_FLASH_ADDR0 = (CFG_FLASH_WORD_SIZE)0x00800080;addrCFG_FLASH_ADDR0 = (CFG_FLASH_WORD_SIZE)0x00AA00AA;addrCFG_FLASH_ADDR1 = (CFG_FLASH_WORD_SIZE)0x00550055;addr20 = (CFG_FLASH_WORD_SIZE)0x00500050; /* block erase */for (i=0; i50; i+)udelay(1000); /* wait 1 ms */ else if (sect = s_first) addrCFG_FLASH_ADDR0 = (CFG_FLASH_WORD_SIZE)0x00AA00AA;addrCFG_FLASH_ADDR1 = (CFG_FLASH_WORD_SIZE)0x00550055;addrCFG_FLASH_ADDR0 = (CFG_FLASH_WORD_SIZE)0x00800080;addrCFG_FLASH_ADDR0 = (CFG_FLASH_WORD_SIZE)0x00AA00AA;addrCFG_FLASH_ADDR1 = (CFG_FLASH_WORD_SIZE)0x00550055;addr20 = (CFG_FLASH_WORD_SIZE)0x00300030; /* sector erase */l_sect = sect;/* re-enable interrupts if necessary */if (flag)enable_interrupts();/* wait at least 80us - lets wait 1 ms */udelay (1000);/* We wait for the la

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论