基于JZ2440开发板编写bootloader总结(一)

凡走过必留下痕迹,学点什么都会有用的。

本系列博文总结了自己在学习嵌入式Linux编程过程中的收获,若有错误,恳请指正,谢谢!

——参考教材韦东山系列教材



bootloader 是一个用于启动linux内核的C程序,为了达到最终启动内核的目的需要完成以下几个步骤:

step1:硬件相关初始化,为启动内核准备硬件平台;

step2:将内核从NAND FLASH读取到SDRAM;

step3:设置需要传递给内核的启动参数;

step4:跳转到SDRAM,运行内核;

下面将详细讲述各个步骤细节:



第一步:硬件相关初始化,为启动内核准备硬件平台

基本流程见下图1

(1)禁看门狗

1     ldr r0, =0x53000000  //WTCON : WATCHDOG TIMER CONTROL REGISTER  Address = 0x53000000
2     mov r1, #0           //bit 0 = 0 : Disable the reset function of the watchdog timer.
3     str r1, [r0]         //将r1中的值存到r0所指定的地址中

(2)设置系统时钟

配置时钟之前先参考下芯片手册  S3C2440A_UserManual_Rev13,需要操作两个寄存器:

  1. MPLLCON 设置MPLL锁相环倍频因子;

MPLL计算公式 : Mpll = (2 * m * Fin) / (p * 2S)   ;   m = (MDIV + 8), p = (PDIV + 2), s = SDIV ;Fin取决于外部晶振频率,JZ2440开发板的 [OM2:OM3] 设置为 [0:0] ,因此

main clock和USB clock 依赖外部12MHZ 晶振。

2. CLKDIVN 设置 HCLK , FCLK,PCLK比例关系;

FCLK, HCLK, and PCLK
         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.
         PCLK is used for APB bus, which is used by the peripherals such as WDT, IIS, I2C, PWM timer, MMC interface,ADC, UART, GPIO, RTC and SPI.

    #define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02))

/* 2. 设置时钟 */     //先设置各个时钟的比例对CLKDIVN赋值,之后设置系统时钟对MPLLCON赋值
    ldr r0, =0x4c000014  //CLKDIVN : CLOCK DIVIDER CONTROL REGISTER  Address = 0x4c000014
    mov r1, #0x03        //FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1   FCLK=200MHZ HCLK=100MHZ PCLK=50MHZ
    str r1, [r0]         //将r1中的值存到r0所指定的地址中

    /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
    mrc    p15, 0, r1, c1, c0, 0        /* 读出控制寄存器 */
    orr    r1, r1, #0xc0000000          /* 设置为“asynchronous bus mode” */
    mcr    p15, 0, r1, c1, c0, 0        /* 写入控制寄存器 */

    /* MPLLCON = S3C2440_MPLL_200MHZ */
    ldr r0, =0x4c000004                      //MPLLCON Address = 0x4c000004
    ldr r1, =S3C2440_MPLL_200MHZ             // S3C2440_MPLL_200MHZ值比较复杂,使用ldr伪汇编
    str r1, [r0]

(3)初始化SDRAM

在使用SDRAM之前,有必要了解下什么是SDRAM。请参阅《高手进阶_终极内存技术指南——完整》,这篇文章解释了SDRAM的基本原理。系统上电需要对SDRAM进行初始化,完成对模式寄存器(MR,Mode Register)的配置。主要设置操作模式、CAS潜伏期时间、突发传输方式和突发长度,完成配置后可以根据地址读写SDRAM。本文操作的SDRAM型号是K4S561632N,S3C2440提供标准的总线接口(BANK6),用于操作SDRAM,因此建立了硬件连接之后,操作S3C2440相应的控制寄存器即可完成对SDRAM的配置和读写,具体操作参阅《[嵌入式Linux应用开发完全手册]》第6章 存储控制器。

1 /* 3. 初始化SDRAM */
2     ldr r0, =MEM_CTL_BASE //SDRAM控制器寄存器首地址,总计需要对13个寄存器配置完成SDRAM的初始化工作
3     adr r1, sdram_config  //读取sdram_config的当前地址到r1,此地址取决于当前PC值,是相对跳转
4     add r3, r0, #(13*4)   //r3=r0+52  r3值代表了全部控制寄存器所占地址空间大小,总计52字节
5 1:
6     ldr r2, [r1], #4      //从r1所指的地方加载指存入r2,之后r1=r1+4,地址加4字节,32位
7     str r2, [r0], #4      //将r2的值存入r0所指的地方,之后r0=r0+4
8     cmp r0, r3
9     bne 1b                //b表示back
 1 sdram_config:
 2     .long 0x22011110     //BWSCON
 3     .long 0x00000700     //BANKCON0
 4     .long 0x00000700     //BANKCON1
 5     .long 0x00000700     //BANKCON2
 6     .long 0x00000700     //BANKCON3
 7     .long 0x00000700     //BANKCON4
 8     .long 0x00000700     //BANKCON5
 9     .long 0x00018005     //BANKCON6
10     .long 0x00018005     //BANKCON7
11     .long 0x008C04F4     //REFRESH
12     .long 0x000000B1     //BANKSIZE
13     .long 0x00000030     //MRSRB6
14     .long 0x00000030     //MRSRB7

  下图是SDRAM的原理图,由两片32M的SDRAM级联成64M,访问一次传递4字节数据。

SDRAM 原理图

SDRAM由BANK6控制,bank6地址空间为0x30000000~0x38000000,共计128MB。上图所示SDRAM存储空间为64M,因此SDRAM地址空间为0X30000000~0X33FFFFFF。

(4)重定位代码

将启动代码从片内SRAM复制到SDRAM中,使用C代码编写。调用C代码需要设置栈,至于为什么要设置栈请参阅http://www.cnblogs.com/xmphoenix/archive/2012/04/28/2475399.html。这里涉及到三个参数:从哪去读取启动代码,将代码复制到哪去,启动代码多大。

  • 从哪去读取启动代码(源地址)

启动代码烧写在NAND,待系统上电后,片内SRAM会加载NAND的起始4K内容。因此启动代码起始地址为:0x00000000

  • 读到哪去(目的地址)

在链接文件中指定了启动代码在SDRAM的中存放地址:0x33f80000,启动代码存到SDRAM顶端512k的地址空间中。

  • 读多少(大小)

启动代码大小 = 代码段+只读数据段+数据段。BSS段不包含在启动代码中,bss段存放没有初始化的全局变量,或者初始化为0的全局变量,程序运行前将bss段清零。

 1 /* 4. 重定位 : 把bootloader本身的代码从flash复制到它的链接地址去 */
 2     ldr sp, =0x34000000    //设置栈,copy函数使用C语言写,调用C代码之前需要设置栈
 3     bl nand_init
 4
 5     mov r0, #0              //传递参数给 copy_code_to_sdram, 对于NOR 启动
 6     ldr r1, =_start         //链接地址即为代码存储区的首地址 _start = 0x33f80000;
 7     ldr r2, =__bss_start    //代码段不包括bss段
 8     sub r2, r2, r1          //除去BSS段外的所有代码的空间大小
 9
10     bl copy_code_to_sdram   //参数依次为r0,r1,r2
11     bl clear_bss

完成以上4个步骤后,CPU会转到SDRAM中取指令执行。

时间: 2024-12-28 23:11:55

基于JZ2440开发板编写bootloader总结(一)的相关文章

JZ2440开发板

2014年12月14日 刚拿到JZ2440开发板,视频第0课第一节: (1) 要给开发板烧系统,就要用到JTAG,(JTAG一般是与电脑的并口相连的),但是现在电脑都没有并口,所以出现了:OpenJTAG和J-Link.我用的是J-Link. 视频上讲的 offlash 程序,用于烧写系统,但是它只适用于 并口的JTAG 和 OpenJTAG ,不可以用于J-Link. 如果是 J-Link ,则只能使用J-Link烧写 Nor Flash .可以向Nor Flash中烧写 u-boot.bin

Jz2440开发板熟悉

title: Jz2440开发板熟悉 tags: ARM date: 2018-10-14 15:05:56 --- 概述 外部晶振为12M Nand Flash 256M,Nor Flash 2M,SDRAM 32*2=64M 分区 内容 Nand flash地址分配 bootloader分区 Uboot分区 0---256k 环境变量分区 环境变量(参数) 256k---256k+128k kernel 分区 Linux内核 256k+128k-256k+128k+2M Rootfs分区 根

Linux学习 :移植U-boot_2016.09到JZ2440开发板

一.下载源码:ftp://ftp.denx.de/pub/u-boot/ 二.初始化编译: ①make smdk2410_defconfig #首先使用默认配置,减少后续的配置工作 ②make menuconfig      #根据自身需求进一步配置 ③修改Makefile ,开头只能架构和编译器: ARCH=arm CROSS_COMPILE=arm-linux-      ④修改uboot代码:    1. 设置PLL的时钟的函数在_main中的board_init_f中初始化函数列表中的 

emWin 移植 - 基于红牛开发板

一直想利用所学的东西自己设计一个精致一些的作品,手头正好有一块红牛开发板,就先用它来写一些软件,熟悉一下过程和一些想法的可行性.首先当然是选择一个操作系统了,对比了几种之后选择了emWin.那就移植一下吧. 这里首先要感谢一下http://www.openedv.com/posts/list/0/27697.htm 这篇帖子.我的思路基本是照着这个帖子做的.感谢楼主把辛苦的研究成果贡献出来,让我这个菜鸟能够快些入门. STemWin下载地址: http://www.st.com/web/en/c

基于Nucleo开发板STM32F4XX模版的建立与ST-Link的配置

本文将建立一个基于Nucleo开发板和KEIL5.14的工程模版,由一下几个部分组成: 1.工程模版的建立 2.STlink的设置与永远的流水灯 1.工程模版的建立 1)在建立工程之前,首先建立一个存放模版文件的文件夹,我们把它叫做template.然后在建立6个子文件夹:Doc,Libraries,Listing,Output,Project,USER,在Libraries里建立CMSIS和FWlib文件夹,在CMSIS中建立startup,这些文件夹的名字可以任意取的,这样命名只是为了方便识

JZ2440开发板Uboot烧写

最近买了一块韦东山的JZ2440开发板,在学习的过程中,发现根据书上提供的Jflash烧写Uboot总是失败,最后定位问题原因: 1.文件路径名称含有中文字符 2.在Options->Program Settings->flash中选择正确的flash芯片 两项选择都正确后,即可正确烧写Uboot.

基于Tiny210开发板视频显示

基于Tiny210开发板视频显示 1.写基于V4L2编程 ========videodevice.h文件========= #ifndef VIDEODEVICE_H #define VIDEODEVICE_H #include <string.h> #include <stdlib.h> #include <errno.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/m

基于uFUN开发板的心率计(三)Qt上位机的实现

前言 上两周利用周末的时间,分别写了基于uFUN开发板的心率计(一)DMA方式获取传感器数据和基于uFUN开发板的心率计(二)动态阈值算法获取心率值,介绍了AD采集传感器数据和数据的滤波处理获取心率值.这篇文章主要是介绍Qt上位机如何实现波形的显示,串口数据的解析,以及一些小细节实现.这篇文章写完,uFUN心率计这个小项目就算结束了,最近又做了个uFUN开发板的扩展板,在微信群里的朋友都已经看到了,后面会做一些好玩的东西,大家要保持关注哈! 关于Qt Qt是一个1991年由Qt Company开

移植u-boot-2015.10到JZ2440开发板(五)——设置nand分区,环境变量保存地址和其它默认参数

在下载内核或文件系统时,我们可以直接在命令中写明烧到nandflash的具体地址,但较麻烦,我们可以给nandflash分区,这样就可直接写烧到那个分区就行了,较为方便.如何设置呢?首先我们在uboot中输入mtdparts命令,看看默认的分区,结果提示mtdids not defined, no default present.搜索"mtdids not defined",定位到common/cmd_mtdparts.c的mtdparts_init函数中,分析发现是mtdids_de