历史上的今天
返回首页

历史上的今天

今天是:2024年12月27日(星期五)

正在发生

2019年12月27日 | arm裸板驱动总结(makefile+lds链接脚本+裸板调试)

2019-12-27 来源:eefocus

在裸板2440中,当我们使用nand启动时,2440会自动将前4k字节复制到内部sram中,如下图所示:

然而此时的SDRAM、nandflash的控制时序等都还没初始化,所以我们就只能使用前0~4095地址,在前4k地址里来初始化SDRAM,nandflash,初始化完成后,才能将nandflash的4096至后面的地址内容存放到SDRAM里去.


而裸板驱动的步骤如下所示:

  • 1.写makefile

  • 2.写lds链接脚本 (供makefile调用)

  • 3.写真正要执行的文件代码,比如初始化nand,sdram,串口等

为什么要写lds链接脚本?

首先lds链接脚本的作用就是将多个*.o文件的各个段链接在一起,告诉链接器这些各个段存放的地址先后顺序,它的好处就是,确保裸板2440的前4k地址里存放的是初始化SDRAM,nandflash的内容


 

1.写makefile

(参考makefile初步制作:http://www.cnblogs.com/lifexy/p/7065175.html)

在写裸板之前首先要来写Makefile,如下所示:


objs := head.o init.o nand.o main.o   

//定义objs变量,表示obj文件,包含生成boot.bin目标文件需要的依赖文件, 使用$(objs)就可以使用这个变量了

//‘:=’:有关位置的等于(比如:”x:=a  y:=$(x)  x:=b”,那么y的值取决于当时位置的a,而不是b) 

//‘=’:无关位置的等于(比如:”x=a  y=$(x)  x=b”,那么y的值永远等于最后的b ,而不是a)                                                     


 


nand.bin : $(objs)   //冒号前面的是表示目标文件, 冒号后面的是依赖文件,这里是将所有*.o文件编译出nand.bin可执行文件

arm-linux-ld -Tnand.lds    -o nand_elf $^   //将*.o文件生成nand_elf链接文件

//-T:指向链接脚本, $^:指向所有依赖文件,


arm-linux-objcopy -O binary -S nand_elf $@ //将nand_elf链接文件生成nand.bin文件

//$@:指向目标文件:nand.bin

//-O :选项,其中binary就是表示生成的文件为.bin文件


arm-linux-objdump -D -m arm  nand_elf > nand.dis //将nand.bin文件反汇编出nand.dis文件

//-D :反汇编nand.bin里面所有的段, -m arm:指定反汇编文件的架构体系,这里arm架构


 


%.o:%.c            //冒号前面的是目标文件,冒号后面的是依赖文件,%.o表示所有.o文件,


arm-linux-gcc -Wall -c -O2 -o $@ $<         //将*.c文件生成*.o文件

//$<:指向第一个依赖文件, 也就是.c文件

//$@:指向目标文件,也就是.o文件

//-Wall:编译若有错,便打印警告信息     -O2:编译优化程度为2级


 


%.o:%.S                       

    arm-linux-gcc -Wall -c -O2 -o $@ $<    //将*.S文件生成*.o文件


 


clean:                           //输入make clean,即进入该项,来删除所有生成的文件

    rm -f  nand.dis nand.bin nand_elf *.o   //通过rm命令来删除


2.写lds链接脚本

(参考lds脚本解析: http://www.cnblogs.com/lifexy/p/7089873.html)


 SECTIONS {

    . = 0x30000000;             //指定当前的链接地址=0x30000000


.text          :   {

head.o(.text)    //添加第一个目标文件,里面会调用这些函数

init.o(.text)      //添加第二个目标文件,里面存放关看门狗,初始化SDRAM等函数

nand.o(.text)   //添加第三个目标文件,里面存放初始化nand函数

*(.text)    // *(.text) 表示添加剩下的全部文件的.text代码段

}


.rodata ALIGN(4) : {*(.rodata)}       //指定只读数据段


.data ALIGN(4) : { *(.data) }     //指定读写数据段,     *(data):添加所有文件的数据段


__bss_start = .;     //把__bss_start赋值为当前地址位置,即bss段的开始位置


.bss ALIGN(4)  : { *(.bss)  *(COMMON) }     //指定bss段,里面存放未被使用的变量


__bss_end = .;        //把_end赋值为当前地址位置,即bss段的结束位置


}


上面的链接地址=0x30000000,表示程序运行的地方应该位于0x30000000处,0x30000000就是我们的SDRAM基地址,而一上电后,nand的前4k地址会被2440自动装载到内部ram中,所以我们初始化了sdram和nand后,就需要把程序所有内容都复制到链接地址0x30000000上才行

2.1为什么要在bss段的前后设置两个符号__bss_start, __bss_end?

定义__bss_start和__bss_end符号,是用来程序开始之前将这些未定义的变量清0,节省内存
且__bss_start -0x30000000就等于该bin文件的字节大小,实现动态复制

2.3为什么链接地址在0x30000000处,为什么在初始化sdram和nand之前,还能运行前4k地址的内容?

我们先来看看head.S第一个目标文件,就知道了:


.text                                                           @设置代码段


           @函数disable_watch_dog, memsetup, init_nand, nand_read_ll在init.c中定义

            ldr     sp, =4096               @设置堆栈

            bl      disable_watch_dog       @关WATCH DOG

            bl      memsetup                @初始化SDRAM

            bl      nand_init               @初始化NAND Flash


            ldr sp,=0x34000000              @64Msdram,所以设置栈SP=0x34000000,避免堆栈溢出

                                            

                           @nand_read_ll函数需要3个参数:

            ldr     r0,     =0x30000000     @1. 目标地址=0x30000000,这是SDRAM的起始地址

            mov     r1,     #0              @2.  源地址   = 0         

            ldr     r2,     =__bss_start         

            sub           r2,r2,r0          @3.  复制长度= __bss_start-0x30000000

            bl      nand_read               @调用C函数nand_read,将nand的内容复制到SDRAM中


            ldr     lr, =halt_loop          @设置返回地址


            ldr     pc, =main                @使用ldr命令 绝对跳转到SDRAM地址上

halt_loop:                                   @若main函数跳出后,便进入死循环,避免程序跑飞

            b       halt_loop


(参考位置无关码(bl)与绝对位置码(ldr): http://www.cnblogs.com/lifexy/p/7117345.html)

从上面代码来看,可以发现在复制数据到sdram之前,都是使用的相对跳转命令bl,bl是一个位置无关码,也就是说无论该代码放在内存的哪个地址,都能正确运行.


而ldr就是绝对跳转命令,是一个绝对位置码,当一上电时,我们的链接地址0x30000000上是没有程序的,因为程序都存在nand flash上,也就是0地址上,而如果在复制数据到sdram之前,使用ldr去执行的话,就会直接跳转到0x30000000上,就会运行出错.


而且在复制数据到sdram之前,执行的代码里都不能用静态变量、全局变量、以及数组,因为这些初始值量的地址与位置有关的,必须将nand的内容复制到sdram地址中,才能用.

 

2.4比如,下面memsetup ()函数,就是个会出错的函数

其中的mem_cfg_val[]数组的内存是存在链接地址0x30000000上,就是与位置有关,在未复制内容之前使用将会出错


#define   MEM_CTL_BASE            0x48000000           //SDRAM寄存器基地址

void memsetup()

{

   int   i = 0;

   unsigned long *p = (unsigned long *)MEM_CTL_BASE;


 


    /* SDRAM 13个寄存器的值 */


    unsigned long  const    mem_cfg_val[]={ 0x22011110,     //BWSCON


                                            0x00000700,     //BANKCON0


                                            0x00000700,     //BANKCON1


                                            0x00000700,     //BANKCON2


                                            0x00000700,     //BANKCON3 


                                            0x00000700,     //BANKCON4


                                            0x00000700,     //BANKCON5


                                            0x00018005,     //BANKCON6


                                            0x00018005,     //BANKCON7


                                            0x008C07A3,     //REFRESH


                                            0x000000B1,     //BANKSIZE


                                            0x00000030,     //MRSRB6


                                            0x00000030,     //MRSRB7


                                    };


 


       for(; i < 13; i++)


              p[i] = mem_cfg_val[i];


}


如下3个图所示,通过反汇编来看,上面的数组内容都是存在SDRAM的链接地址上面的rodata段0x300005d0里,在我们没有初始化SDRAM,复制数据到SDRAM之前,这些数据是无法读取到的

图1,使用bl跳到相对地址0x30000094处:

 

图2,使用ldr,使ip跳到绝对地址0x300005d0:

 

图3,0x300005d0里保存的.redata只读数据段,也就是 mem_cfg_val[]的内容:

 

2.5所以要修改memsetup ()函数为以下才行:


#define   MEM_CTL_BASE            0x48000000           //SDRAM寄存器基地址

void memsetup()

{

       unsigned long *p = (unsigned long *)MEM_CTL_BASE;


    /* 设置SDRAM 13个寄存器的值 */

   p[0]  =0x22011110,     //BWSCON

   p[1]  =0x00000700,     //BANKCON0

   p[2]  =0x00000700,     //BANKCON1

   p[3]  =0x00000700,     //BANKCON2

推荐阅读

史海拾趣

Condor公司的发展小趣事

关于Condor公司在电子行业的发展,以下是五个相关故事:

  1. Condor的创始与早期发展

Condor公司成立于1893年,起初主要涉及离心机、挤奶机以及泵的生产。随着技术的不断进步和市场需求的变化,公司逐渐转型,开始专注于压力和液位控制组件及系统解决方案的研发与生产。这一转变使得Condor在电子行业中崭露头角,为其后续的发展奠定了坚实的基础。

  1. 专利技术的突破

1935年,Condor取得了世界上的泵压力开关上的第一个专利,这一创新性的技术突破为公司的快速发展注入了新的动力。随着这项专利技术的应用,Condor的产品开始在各种工业领域中得到广泛应用,特别是在需要精确控制压力和液位的场景中,如汽车、冶金、水火核风电等行业。

  1. 国际市场的拓展与合作

随着全球化进程的加速,Condor开始积极拓展国际市场。公司与多个国家的合作伙伴建立了长期稳定的合作关系,共同开发新产品,拓展新的应用领域。这一战略举措不仅提升了Condor在全球电子行业中的影响力,也为其带来了更多的商业机会。

  1. 产品质量的持续提升

Condor一直坚持以最高的质量要求来生产每一款产品。为了确保产品质量,公司在生产过程中严格把控每一个环节,从原材料采购到最终的产品测试,都遵循严格的标准和流程。这种对质量的执着追求,使得Condor的产品在市场上赢得了良好的口碑和客户的信赖。

  1. 技术创新的持续推进

作为家族企业,Condor始终保持着对技术创新的热情和投入。公司不断引进新的技术和设备,优化生产流程,提高产品的性能和可靠性。同时,Condor还积极与科研机构和高校合作,共同研发新的技术和产品,以满足市场不断变化的需求。这种持续的技术创新为Condor在电子行业中保持领先地位提供了有力支持。

以上五个故事展示了Condor公司在电子行业中的发展历程和关键转折点,体现了其对技术、质量和市场的敏锐洞察力和持续创新精神。如需更多信息,建议查阅Condor公司官网或相关新闻报道。

Gravitech公司的发展小趣事

对于电子猜数玩具电路的网友可能提出的问题,我整理了一些常见问题及其回答:

一、电路设计相关问题

  1. 问题:电子猜数玩具电路的基本组成部分有哪些?
    回答:电子猜数玩具电路通常由触摸控制器、多谐振荡器、LED驱动电路和受控声、光电路等部分组成。具体来说,包括时基集成电路(如NE555)、非门集成电路(如CD4069)、计数分配器集成电路(如CD4017)、音乐集成电路、继电器、二极管、发光二极管、电阻器、电容器等元器件。

  2. 问题:如何设计电路以确保游戏能够正确运行?
    回答:设计电路时,需要确保各个部分能够协调工作。例如,触摸控制器负责检测玩家的输入,多谐振荡器产生计数脉冲,LED驱动电路控制LED的显示,受控声、光电路则在玩家猜中数字时发出声音和光信号。设计时还需要注意电路的稳定性和可靠性,避免信号干扰和元件损坏。

  3. 问题:电路中的LED如何布局以实现数字显示?
    回答:LED的布局通常根据要显示的数字范围进行设计。例如,如果要显示0-9的数字,可以使用7段LED数码管或分散的LED灯。7段LED数码管内部含有8个LED小灯(7个用于显示数字段,1个用于小数点或原点),通过控制这些LED的亮灭来显示不同的数字。如果是分散的LED灯,则需要根据数字的形状来布置LED,并通过编程控制它们的亮灭。

二、元件选择与参数设置问题

  1. 问题:如何选择适合的集成电路和元器件?
    回答:选择集成电路和元器件时,需要考虑电路的需求、元器件的性能参数以及成本等因素。例如,时基集成电路可以选择NE555,因为它具有成本低、易于获取和使用的优点;非门集成电路可以选择CD4069,因为它提供了多个非门输出,方便电路设计;发光二极管则需要选择高亮度的型号以确保显示效果良好。

  2. 问题:电阻器和电容器的参数如何设置?
    回答:电阻器和电容器的参数设置需要根据电路的具体需求来确定。电阻器的阻值会影响电流的大小和LED的亮度,因此需要根据LED的电流需求和驱动电压来选择合适的阻值。电容器的容量则会影响多谐振荡器的振荡频率和电路的响应时间,需要根据实际需要进行调整。

三、调试与故障排除问题

  1. 问题:如何调试电子猜数玩具电路?
    回答:调试电路时,可以按照以下步骤进行:首先检查电路连接是否正确,包括电源连接、信号连接和地线连接等;然后使用万用表等工具测试电路中的电压和电流是否正常;最后观察LED的显示和声音输出是否符合预期。如果出现问题,可以逐步排查各个部分,找出故障点并进行修复。

  2. 问题:电路中出现LED不亮或声音不响的故障怎么办?
    回答:如果LED不亮或声音不响,首先需要检查电源是否正常供电;然后检查相关元器件是否损坏或接触不良;最后检查控制信号是否正确传输。如果以上都正常,可能是程序设计或电路布局存在问题,需要进一步检查和调整。

四、拓展与改进问题

  1. 问题:如何增加电子猜数玩具的趣味性和挑战性?
    回答:可以通过增加游戏难度、丰富游戏模式或添加互动元素等方式来增加电子猜数玩具的趣味性和挑战性。例如,可以设置不同的难度等级、增加倒计时功能、设置奖励机制或添加与手机等设备的互动功能等。

  2. 问题:如何对电子猜数玩具电路进行改进以降低成本或提高性能?
    回答:降低成本可以通过选择性价比更高的元器件、优化电路设计、减少不必要的元器件数量等方式实现;提高性能则可以通过升级元器件、改进电路设计、优化算法等方式实现。具体改进方案需要根据实际情况和需求进行制定。

Bel Fuse公司的发展小趣事

Bel Fuse公司的创立可以追溯到XXXX年,当时它由几位富有远见的工程师在新泽西州创立。起初,公司专注于保险丝的研发和生产,致力于提供高质量的电气保护产品。凭借卓越的技术和可靠的产品质量,Bel Fuse逐渐在市场上获得了认可,并开始扩展其产品线。

Formosa MS公司的发展小趣事

进入XXXX年代,电子行业经历了深刻的变革,新兴技术的涌现给传统企业带来了挑战。Bel Fuse也面临着市场需求的变化和竞争压力的增加。为了应对这些变革,公司进行了战略调整,将重点放在了连接器、电源、磁性元件和电路保护产品等领域。通过加大研发力度和市场推广,Bel Fuse成功实现了产品升级和市场拓展。

GISMA Steckverbinder GmbH公司的发展小趣事

自1983年成立以来,GISMA Steckverbinder GmbH便专注于水下连接器的开发、设计和生产。作为一家由所有者直接管理的独立公司,GISMA从一开始就确立了为海洋工业、船舶及海洋技术提供高质量电气和光纤连接器的目标。这一明确的市场定位使得GISMA能够迅速在竞争激烈的电子行业中脱颖而出,逐步建立起自己的市场地位。

远阳(FLYOUNG)公司的发展小趣事

人才是企业发展的根本。国光新业深知这一点,因此始终注重人才的引进与培养。公司推出了“国新力”人才计划专项,构建了一支优秀人才梯队。目前,企业的技术团队中科技人员占比超过30%,其中拥有工程师以上职称的比例更是超过六成。这些高素质的人才为公司的技术创新与产品研发提供了源源不断的动力。

问答坊 | AI 解惑

日本常用三极管

这是在我的硬盘里的资料,拿出来共享一下。希望能对大家有参考价值。…

查看全部问答>

iar avr twi 多从机源码

来源于AVR网站 /***************************************************************************** * * Atmel Corporation * * File         : main.c * Compiler       : IAR EWAAVR 2 ...…

查看全部问答>

99SE中写PCB中文字体

1、解压后将此文件放入C盘   2、在放入C盘后,在FONT.EXE文件中编辑你所要放的汉字   3、编辑好汉字后,在PROTEL99SE的PCB状态下,找到你放入PROTELHZ文件夹的路径,导入PCBHZ.LIB文件      采用以上步 ...…

查看全部问答>

网卡驱动

网卡驱动是不是在Linux下编写TCP通讯协议?…

查看全部问答>

飞行体验项目——看看这样的项目谁能作

项目:飞行体验项目 说明:         飞行体验装置由现时屏幕和控制器两部分组成,控制器为飞鸟外形,小朋友们可以俯卧在控制器上操作飞行器,电脑模拟的飞行场景以及小朋友的操作结果会在显示屏幕上显示  &n ...…

查看全部问答>

求智能电源监控管理软件方案(有偿服务)

本方案包括PWM 3路;A/D输入6路;双向I/O口 7路;D/A输出1路。要求用PIC、瑞萨或ATMEL 的八位单片机,如有兴趣请联系18923776056 或QQ1538444360 [ 本帖最后由 vpgpu 于 2011-1-2 19:50 编辑 ]…

查看全部问答>

关于NE555的问题。当输入高电平,输出低电平不够低怎么办?量出来2.7。

做单稳电路。高电平3.7,低电平2.7。 [ 本帖最后由 huang91 于 2011-11-10 15:49 编辑 ]…

查看全部问答>

TI Stellais SSI

Master or slave Master runs up to sys_clk/2 (25Mb @ 50MHz) Slave runs up to sys_clk/12 (4.1667Mb @ 50MHz)  …

查看全部问答>

帮忙看下为什么不产生PWM波啊

我用的芯片是LM3S2B93,Keil4工程,调试PWM时怎么也产生不了PWM,其他功能正常,大家帮忙看下是怎么回事啊~急急!! unsigned long gSysClock = 12000000UL; #define PWM_FREQ    6000           & ...…

查看全部问答>