ucos在s3c2410上运行过程整体剖析-从加电到执行main函数

发布者:平和的心情最新更新时间:2017-01-19 来源: eefocus关键字:ucos  s3c2410  main函数 手机看文章 扫描二维码
随时随地手机看文章

先说明一下在加电之前的这个软硬件情况,这个三星公司根据ARM920T软核生产的这个s3c2410集成了64M的sdram和64M的nandflash存储器。Vivi和UCOS都存储在这个nandflash中,因为nandflash断电后不会丢失信息。这个VIVI是三星公公司为ARM系列芯片书写的bootloader,用于开发阶段,做系统的引导程序。

VIVI存放在flash 0x00000000地址开始的地方,UCOS存放在flash 0x03f30000地址开始的地方。ARM920T开机从flash启动,启动时把flash前4K (即vivi的前4K)COPY到SDRAM(这种启动方式是利用Nandflash启动,COPY前4K到sdram中是硬件自动实现的),vivi的前4K 代码中有用于COPY剩余VIVI的代码。执行完这些代码之后,VIVI就控制了FLASH的读取,串口的控制以及用户shell接口,当然它还有其他一些功能。当用户执行bootucos命令时,VIVI会把ucos相关代码从flash  0x03f30000  COPY到SDRAM  0x30008000的地方。当然也可以设置VIVI自动引导ucos执行。当代码copy完毕后,vivi会把PC值改成0x30008000去执行。

我们先说一下为什么我们非要说具体的那个地址那,咱们前面说了,编译好的程序有一个load地址,一个真正运行的地址,0x30008000这个地址就是咱们说的程序的装载地址,这个地址是我们用编译器指定的地址,也就是通过在ads工程里后缀名是scf的文件配置的。在这个文件里我们配置了程序的装载地址和程序运行的地址,我们为什么要指定这两个地址那?我们整个工程的程序是最后链接时一次性固定的绝对地址,也就是说最终链接出来的程序地址和真正运行的地址是一致的。只不过我们一般不会把这些代码直接放到相应的部位去罢了,其中一个原因就是,我们为了在不加电时保存程序会把程序放到非易失的存储设备里去,而我们运行时会把程序copy到运行速度比较快的sdram中去。也就是说,本来这些静态链接的程序的执行地址都是固定的了,我们要在这些程序运行之前要把这些程序放对位置。我们必须知道我们的程序装载到什么地址和真正在什么地址运行。这样我们才能知道那些装载地址和运行地址不一样的程序段应该怎么搬运。至于搬运的工作,你可以自己手工实现,也可以用ADS提供的库函数实现。

跳转到这个0x30008000去执行这个地址处的指令,我们这个工程编译出来后谁是第一条指令那?我们平时写的程序都是从main()函数开始执行,但我们这个嵌入式的开发可不是哦,在分析完启动代码后你就知道了,在执行的所谓的main()函数之前要做很多工作的。

arm映像文件的入口点有两种类型:一种是映像文件运行时的入口点,称为初始入口点(initial entry point),另一种是普通入口点(entry point).
初始入口点是映像文件运行时的入口点,每个映像文件只有一个唯一的初始入口点,它保存在ELF头文件中。假如映像文件是被操作系统加载的,操作系统是通过跳转到该初始入口点处来加载该映像文件。
普通的入口点是在汇编中用ENTRY伪操作定义。他通常用于标志该段代码是通过异常中断处理程序进入的。这样连接器删除无用的段时不会将该段代码删除。一个映像文件中可以定义多个普通入口点。
应该注重的是,初始入口点可以使普通入口点,但也可以不是普通入口点.

初始入口点必须满足下面两个条件:
1.初始入口点必须位于映像文件的运行时域内。
1.1饱含初始入口点的运行时域不能被覆盖,他的加载地址和运行地址必须是相同的。
可以使用连接选项-entry address来指定映像文件的初始入口点。这时,address指定了映像文件的初始入口点的地址值。对于地址0x0处为rom的嵌入式应用系统,可以使用-entry 0x0来指定映像文件的初始入口点。这样当系统复位后,自动跳转到该入口开始执行。假如映像文件是被一个加载器加载的,该映像文件该映像文件必须包含一个初始化入口点。这种映像文件通常还包含了其他普通入口点,这些普通入口点一般为异常中断处理程序的入口地址。
当用户没有指定-entry address时,连接器根据下面的规则决定映像文件的初始入口点。
假如输入的目标文件中只有一个普通入口点,该普通入口点被连接器当成映像文件的初始入口点。
假如输入的目标文件中没有一个普通入口点,或者其中的普通入口点多于一个,则连接器生成的映像文。

我们编译好的可执行文件时去除了头格式的映像文件,我们讲的本来就是操作系统,所以这个程序不是通过初始入口点执行的第一条指令,应该是通过普通入口点来执行的,通常是中断向量表。也就是程序中用伪指令entry指定的指令段的第一条指令。我们用ADS1.2打开ucos的学习资料的工程中的第十个实验(ucos系统移植实验)。在startup文件夹中有一个startup.s 的汇编程序,这个就是ucos的启动代码了。由ENTRY伪指令指定的第一条指令是b     ColdReset,所以第一条指令就是它了。

咱先不管这个第一条指令的问题,我的目的是把我学习的UCOS讲述给你听,但这需要一定的讲述规范,希望我说的你能听懂,愿意看下去,我想这样做:

先从整体描述一下整个过程,然后在分阶段概括这一阶段整个硬件和软件系统干了什么?为什么会有这些顺序?为什么要这么干?在这个过程中可能思维随即发散到任何有关系的知识点。最后我将逐一分析源代码,在分析源代码时遇到的问题,都将解决,当然包括那些精华和美。还可能阐述一下我的理解和方法,以及我对学习的一些认识。我是想按照一定的规范去写这个东东,但是我又不想完全按照一种思路去写,毕竟我是随意书写的。我的整体思路就是针对硬件和软件在整个时间流里都干了什么?为什么要这么干为主要线路。在这个线路中涉及到的所有疑问和知识点都将一一展开阐述。我尽量做到自然,而不是强加给你一些生硬的概念,因为人不喜欢被。被学习,被干活,被记忆。

理解UCOS最好的方式是阅读其源代码,一本很好的参考书是嵌入式实时操作系统ucos-ii,邵贝贝译

 

声明:在写这个文档时,我还有很多地方没有真正弄明白,所以有些地方可能我也说不清楚,但我会把我的疑问写出来,我什么时候想明白了,我会把它写出来,如果你知道请你告诉我,我会很高兴的。

 

在说明一下现在的情况:现在ucos的所有代码(包括启动的bootloader)都被vivi copy到0x30008000的内存地址开始的地方了,然后PC值改为0x30008000,取出这个地址放的arm指令就开始执行这条指令了。前面已经分析完整个工程编译出来的可执行程序的第一条指令了。

好了,下面开始说整个班子以及UCOS的整体启动过程,只是大概的说明流程,至于会为什么这样的问题等到具体详解的时候在具体解释。

硬件初始化,主要是让硬件平台处于一个可知的状态,重要的一点就是初始化C语言运行环境。

UCOS初始化

UCOS运行并执行应用程序

 

哎 ,这样看的话,整个过程还真挺简单的,哈。

 

下面具体讲解硬件初始化阶段,这个就真的比较麻烦了,但没关系,咱们慢慢说。

从具体代码上看,它主要干了这些活:

关闭看门狗,(一个用于开发阶段的硬件,到代码讲解时具体说明)

屏蔽中断掩码寄存器(现在整个硬件平台的控制权都在UCOS,在初始化的时候,我们不希望被打扰,具体原因我们以后说)

初始化各个模式堆栈空间(堆栈空间很重要哦)

COPY中断向量表(关于为什么要copy,我们在后面说)

初始化c库环境

然后跳转到主应用程序(即我们平时说的main()函数)

下面这些代码是用汇编写的代码,其中分号后面的是注释。

 

下面就以具体代码为例,详细讲解启动代码。

 

每个代码块做一个说明,对于特别重要的代码,我在代码后面做详细注释。注释写在//后面,如果此处有很重要知识点的话,单独起一段进行说明。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;

;;; Copyright (c) 2004-2007 threewater@up-tech.com, All  rights reserved.

;;;

;;; Startup Code for

;;;       S3C2410 : Startup.s

;;;; by      threewater      2005.2.22

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 

       GET 2410addr.s //引入2410addr.s文件里的内容,作用像是c语言里的#include一样。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;; Some ARM920   CPSR bit discriptions

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;Pre-defined constants

USERMODE    EQU   0x10

FIQMODE         EQU       0x11

IRQMODE         EQU       0x12

SVCMODE         EQU       0x13

ABORTMODE   EQU  0x17

UNDEFMODE   EQU  0x1b

MODEMASK    EQU  0x1f

NOINT       EQU       0xc0

 

I_Bit                     *     0x80

F_Bit                     *     0x40

//以上代码是定义一些常量,都是关于arm的CPSR寄存器的,我们对这方面的知识是知道的,不知道的请参考datasheet的program model 章节相关内容。书写的代码是用于程序员之间交流用的,所以要尽量的可读,不要使用数字。使用数字的时候像上面一样,把他们定义成另一个可读的符号,这样就能读名知意了。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;; Start here

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 

                     AREA     Init,CODE,READONLY // 定义一个段,并指明属性,这些都是给编译器说的。具体怎么回事请参考编译器相关知识部分。

                     IMPORT __use_no_semihosting_swi //禁止使用semihosting机制,现在说一下什么是semihosting机制,这是ADS提供的一种开发调试机制,就是说你的程序运行在目标平台上,你可以利用主机的硬件资源进行对程序的调试,比如你可以利用宿主机的屏幕和键盘。Semihosted环境(semihosting是针对ARM目标机的一种机制,它能够根据应用程序代码的输入/输出请求,与运行有调试功能的主机通讯。这种技术允许主机为通常没有输入和输出功能的目标硬件提供主机资源)在semlhosted环境下用来实现C库函数与目标相关的函数。可以在你的Application Code中使用printf等stand IO Function in C Library! 方便调试!更多的你可以参考ARM DUI 0058D(Debug Target Guide!)ARM公司对Semihosting的中文解释是半主机机制。为什么叫半主机呢?主要是指应用程序的代码运行在目标系统上,当需要类似PC平台下的控制台输入输出时,会调用Semihosting去利用PC上的控制台输入输出设备:如打开关闭文件,PC显示器输出,键盘输入等等。更详细的内容请参见Semihosting.pdf

 

而此处,我们做的系统是独自运行在硬件平台上的,即不需要使用Semihosting机制。IMPORT __use_no_semihosting_swi就是声明我们不使用这种机制,如果程序里有使用这种机制的地方编译器就会报错。在c语言中我们用#pragma import(__use_no_semihosting_swi)这句话禁用。

                     IMPORT Enter_UNDEF

                     IMPORT Enter_SWI

                     IMPORT Enter_PABORT

                     IMPORT Enter_DABORT

                     IMPORT Enter_FIQ  //以上就是引用全局标号,就是说明这些标号在其他地方已经声明,而且是全局的。在汇编语言里声明全局变量用关键字EXPORT,在C语言中用extern ,当然c语言中的函数本身就是全局的标号。

                     ;IMPORT       main

                     ENTRY         //指定程序普通入口点,以下代码都是一些跳转指令,ENTRY伪指令就是告诉编译器以下这些代码是有用的,不要优化掉。编译器可能认为这是一堆没有的代码。

 

                     b     ColdReset  //第一条是跳转指令,跳转到ColdReset处去执行

                     b     Enter_UNDEF ;UndefinedInstruction

                     b     Enter_SWI     ;syscall_handler or SWI

                     b     Enter_PABORT      ;PrefetchAbort

                     b     Enter_DABORT     ;DataAbort

                     b     .             ;ReservedHandler

                     b     IRQ_Handler   ;IRQHandler

                     b     Enter_FIQ      ;FIQHandler

 

;deal with IRQ interrupt

       EXPORT IRQ_Handler

IRQ_Handler

       IMPORT ISR_IrqHandler

       ;SUBS      LR, LR, #4                   ;事先修正返回地址

       STMFD  sp!, {r0-r12, lr}

      

       BL   ISR_IrqHandler

       ;mrs      r10, SPSR                ; get the PSR

       ;MSR     CPSR_cxsf,r10                   ;恢复cpsr

       ; LDMFD       sp!, {r0-r12,pc}^

      

      

       ;bic        r10,r10,#0xc0                      ;开中断

      

        LDMFD       sp!, {r0-r12,lr}

         ;mrs      r10, spsr                ; get the PSR

        ; MSR     CPSR_cxsf,r10                   ;恢复cpsr

       ;mov pc,lr

       SUBS      pc, lr,      #4                                ;s表示对cpsr有影响

       ;mrs      r10, SPSR                ; get the PSR

       ;MSR     CPSR_cxsf,r10                   ;恢复cpsr

 

;=======

; ENTRY

;=======

       EXPORT ColdReset

ColdReset

       ldr   r0,=WTCON  ;watch dog disable

       ldr   r1,=0x0         

       str   r1,[r0]  //关闭看门狗,有关看门狗的相关知识查看datasheet的第十八章watchdog

 

       ldr   r0,=INTMSK

       ldr   r1,=0xffffffff  ;all interrupt disable

       str   r1,[r0]    

 

       ldr   r0,=INTSUBMSK

       ldr   r1,=0x7ff              ;all sub interrupt disable, 2002/04/10

       str   r1,[r0]

//以上代码用于屏蔽所有外部中断,用的方法是屏蔽外部中断掩码寄存器。具体原理查看datasheet的第十四章interrupt controllor或者查看前面写的基础知识篇之ARM芯片的相关知识。

 

;****************************************************

;*    Initialize stacks                         *

;****************************************************

                     bl     InitStacks       ; Stack    Setup for each MODE //跳转指令,跳转到InitStacks去执行

现在已经初始化好了各个模式下的系统堆栈空间了,总结一下现在处理器的情况:处理器现处于SVC模式,并且cpsr的irq和fiq位禁止中断。还有看门狗被屏蔽(整个系统不用看门狗),外部中断的中断控制器的屏蔽寄存器被屏蔽。也就是说现在外部中断的申请不能到cpu,就算外部的请求到了cpu,cpu也不会搭理,因为irq和fiq位都被屏蔽。所谓双重保障就是这么回事。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;; copy excption table to sram at 0x0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

              IMPORT |Load

EXCEPTIONEXEC

Base|   //装载时的地址


              IMPORT |Image

EXCEPTIONEXEC

Base|  //运行时的地址


              IMPORT |Image

EXCEPTIONEXEC

Length|//exception段的长度


                    

              ldr   r0,   =|Load

EXCEPTIONEXEC

Base|  ;source    data


              ldr   r1,   =|Image

EXCEPTIONEXEC

Base| ;place exception talbe at 0x0


              ldr   r2,   =|Image

EXCEPTIONEXEC

Length|


             

 

exception_cploop

              sub  r2,   r2,   #4   //把r2(即exception的长度值减去4,因为arm的通用寄存器是32位的,即每次移动4个字节)

              ldmia       r0!,  {r3}   //借助把源地址处的前四个字节放到r3中去,然后r0的地址自动加4,这是!的作用。具体参考arm指令集。

              stmia       r1!,  {r3}   //利用r3装到目的地址

              cmp r2, #0         //判断是否移动完毕,未移动完毕,则继续移动

              bge exception_cploop

//以上代码是copy中断向量表,这里的中断向量表是工程中exception.s里定义的中断向量,不是startup.s中开始的那几个跳转指令。至于为什么要copy中断向量表呢,原因是这样的,咱们现在的ucos在sdram地址0x30008000的地方,我们还知道ucos要管理整个硬件,当然要管理中断,ARM的中断向量表规定要在内存地址的0开始的地方,而现在sdram 的0地址处是vivi的代码,我想一定也是一个中断向量表(不过他是vivi的),现在我们要把ucos自己的中断向量表copy到sdram的0地址处。一,这样就为ucos管理中断提供了前提条件,二,这也废除了vivi的中断机制,所谓一箭双雕。

对了,还有一个事要说,和那个叫分散加载文件有关的,具体分散加载文件的作用和使用请参见ARM开发工具ADS原理与应用.pdf第十章的相关章节。简单说一下,这个分散加载文件是用于告诉编译器怎么链接输入的文件,以及连接成什么样子,把链接的文件装载到什么地方,真正运行时在什么地方。而这个从装载地址到运行地址的一个转化可以自己用代码实现,也可以利用ADS提供的功能来实现,那就是下面的__main()函数可以帮助你做这个工作。__main()这个是ads提供的库函数,是根据你写的分散加载文件自动生成搬运代码的。

至于这个__main()函数的具体使命,我们下面再说。

下面我们就看一下这个分散加载文件的内容(我们用的是scat_ram.scf这个文件):

LOAD 0x30008000              ;load region

{

       RAM_EXEC +0            ;PC

       {

              startup.o (init, +FIRST)

              * (+RO)

    }

 

 

    STACKS +0x100000 UNINIT      ;64KByte under L0 pagetable

    {

        stack.o (+ZI)

    }

 

       RAM +0

       {

              * (+RW,+ZI)

       }

 

       HEAP +0 UNINIT

       {

              heap.o (+ZI)

       }

      

       EXCEPTION_EXEC 0 OVERLAY ;exception region

       {

              exception.o (+RO)

       }

 

}

 

关于这个分散加载文件的语法和具体含义,我就不一一解说了,这是一个格式文件,资料里有它的规范,看懂它很容易的。分析完我们发现这样一个问题,exception.o(即中断向量表这一段)其加载地址和运行地址是不同的,按理说应该由__main函数自动生成代码,因为我们下面用到了__main函数,但EXCEPTION_EXEC这个执行域的属性是OVERLAY,这个属性的代码段__main函数是不管的喽,只能自己去实现这些搬运代码的功能。我们现在就回过头去看搬运代码是怎么实现搬运的。

首先,引入了几个变量,这几个变量是编译器提供的,也就是你通过那个叫分散加载文件指定的装载地址和运行地址。本来就是,你想搬家,你得有原来的家的地址和目的地址吧。具体过程参考我在程序后写的注释。  

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;; start main function in C language

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

                     IMPORT __main 

 

                     BL   __main    ;Don't use main() because ......

//跳转到__main()函数执行,看好了,这里是__main()哦,并不是平常我们所说的main()函数,为什么呢,下面说明原因:

__main()函数是ads1.2开发环境提供的库函数,这个库函数主要的作用有以下几点:

1,根据你写的分散加载文件来生成自动搬运的代码

2,负责库函数的初始化

如果你用的存储结构比较复杂,那__main()函数提供的这个功能就很给力了,不用自己去实现搬运代码的工作了。

另外__main()函数还初始化库函数,这个也很重要,库函数初始化好了后,在你编程时就可以使用标准的c库函数进行编程了,比如printf()函数等,当然了,要在固定硬件平台上实现这些库函数,还要进行库函数的移植工作。关于库的移植你可以参考《使用ARM标准C库进行嵌入式应用程序开发.doc》。关于__main()函数的具体细节问题请参考《main  __main.doc》

关于__main()的问题,其中有一个库的初始化函数_rt_lib_init()到底做了什么初始化,不是很清楚,用AXD调试,都是汇编,又没看明白什么意思,有时间慢慢调试,再总结说明。

__main()函数最终要跳转到main()函数(即用户写的那个普通的main函数)

如果你写的程序里有main()函数的话,编译器就会默认的链接__main()函数和main()函数。

                     B     .    //跳转到本条指令,也即死循环,一般程序不会跑到这里的。

 

;****************************************************

;*    The function for initializing stack      *

;****************************************************

       IMPORT UserStack

       IMPORT SVCStack

       IMPORT UndefStack

       IMPORT IRQStack

       IMPORT AbortStack

       IMPORT FIQStack

//以下代码实现ARM芯片的各种模式下的堆栈空间的初始化,就是把分配的空间的地址分配给各个模式下的SP指针,至为什么要分配这个空间,我想你看了基础知识里的c语言和堆栈后应该很清楚了,另外当处理器模式更改时也要用到堆栈。记住了,现在分配的是系统堆栈空间哦。

InitStacks

       ;Don't use DRAM,such as     stmfd,ldmfd......

       ;SVCstack is initialized before

       ;Under toolkit ver 2.50, 'msr cpsr,r1' can be used instead of 'msr cpsr_cxsf,r1'

 

       mrs  r0,cpsr          //读取cpsr的值,在特权模式下才能修改cpsr的值,在特权模式下你可以用mrs和msr修改cpsr的后五位的值来实现模式的更改。

       bic   r0,r0,#MODEMASK

       orr   r1,r0,#UNDEFMODE|NOINT

       msr  cpsr_cxsf,r1          ;UndefMode

       ldr   sp,=UndefStack   //更改为undefined模式,然后把分配空间的高地址付给这个模式的sp指针。定义这些空间是在stack.s这个文件中的,你可以看看哦。

                           

       orr   r1,r0,#ABORTMODE|NOINT

       msr  cpsr_cxsf,r1          ;AbortMode

       ldr   sp,=AbortStack

                    

       orr   r1,r0,#IRQMODE|NOINT

       msr  cpsr_cxsf,r1          ;IRQMode

       ldr   sp,=IRQStack

                           

       orr   r1,r0,#FIQMODE|NOINT

       msr  cpsr_cxsf,r1          ;FIQMode

       ldr   sp,=FIQStack

                    

       ;bic  r0,r0,#MODEMASK|NOINT

       orr   r1,r0,#SVCMODE|NOINT

       msr  cpsr_cxsf,r1          ;SVCMode

       ldr   sp,=SVCStack

       //其他模式的设置方法和第一个模式是一样的,最后ARM芯片运行在SVC模式下,芯片启动后默认的模式就是SVC,现在改来改去又回到了SVC模式下,而且cpsr的irq和fiq位是禁止中断的哦。

       ;USER mode is not initialized.

       mov pc,lr ;The LR register may be not valid for   the mode changes.//返回,当执行bl   InitStacks       时把返回地址保存在了lr寄存器了。准确的说是保存到SVC模式下的lr寄存器了,所以最后切换的模式是SVC才保证了用mov pc,lr指令能正常返回。

 

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;; End of Startup.c

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

 

                     END

 

好了,现在总结一下现在的情况,硬件基本的初始化完成,c语言的执行环境已经初始化完成,现在跳转到main()函数去了,哎 终于见到了可爱的c语言。理解起来就简单喽。呵呵。我们进入下一阶段了。重要提醒:现在处于关中断状态。


关键字:ucos  s3c2410  main函数 引用地址:ucos在s3c2410上运行过程整体剖析-从加电到执行main函数

上一篇:ucos在s3c2410上运行过程整体剖析之基础知识
下一篇:ucos在s3c2410上运行过程整体剖析之基础知识- ARM9芯片知识

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

C语言程序执行的第一条指令,并不在 main 函数
C语言程序执行的第一条指令,并不在 main 函数中。当我们生成一个C程序的可执行文件时,编译器总是在我们的代码前加一段固定的代码 crt0.o,它是编译器自带的一个文件。此段代码设置 C 程序的堆栈等,然后调用 main 函数。很可惜,在我们的裸板上,这段代码无法执行,所以我们得自己写一个。这段代码很简单,只有 3条指令。crt0.s 代码: 1 .text 2 .global _start 3 _start: 4 ldr sp, =1024*4 @设置堆栈,注意:不能大于 4k(栈区是向下增长的) @nand flash 中的代码在复位后会自动
[单片机]
s3c2410开发板的VGA调试
光买开发板没有LCD,穷啊,只能用VGA的显示器代替。带的资料也没说怎么就支持VGA,只好上网查,还好解决了,虽然不知道linux驱动的原理,但改改寄存器还是会的。下面说说整个过程。 VGA的接口定义如图所示: 板子上的AD芯片是TI的TL5632,该芯片的三个输出引脚与VGA的RED GREEN BLUE相连,它的24个输入引脚与2410的vd 相连,2410的VSYNC和HSYNC直接连到VGA的对应引脚,其他的该接地接地, MONITOR ID这三个编码引脚用不上。 上面是分辨率为640×480、刷新频率为60 Hz、16位彩色显示模式的VGA接口时序图,LCD寄存器中的一些值就由它们决定: *LCDCON1寄存
[单片机]
<font color='red'>s3c2410</font>开发板的VGA调试
stm32+ucos+ucgui 中edit框读取AD值以十进制显示
初始化 case WM_INIT_DIALOG: hEdit0 = WM_GetDialogItem(hDlg, GUI_ID_EDIT0); //创建Dialog hRadio = WM_GetDialogItem(hDlg, GUI_ID_RADIO0); //创建Dialog //EDIT_SetDecMode(hEdit0, 0, 0, 5000, 0, 0); /* Select decimal mode */ EDIT_SetMaxLen(hEdit0,4); //此句要进行设置edit 默认显示3位数 //WM_DisableWindow(hItem); RADIO_SetVa
[单片机]
ARM S3C2410硬件手册重点
简介:S3C2410提供了外接ROM、SRAM、SDRAM、NOR Flash、NAND Flash的接口。S3C2410外接存储器的空间被分为8 BANKS,每BANK容量为128M:当访问BANKx(x从0到7)所对应的地址范围x*128M到(x+1)*128M-1 SDRAM使用BANK6,它的物理起始地址为6*128M=0x30000000。 a.Memory Controller b.Nand Flash c.UART d.Interrupt e.Timer Memory Controller SDRAM: S3C2410提供了外接ROM、SRAM、SDRAM、NOR Flash、NAND Flash的接口。S3
[单片机]
关于S3C2410的电源管理
一、S3C2410支持4种供电模式 (1)NORMAL MODE 耗电最大、可以通过关闭具体控制器的时钟来节电 (2)SLOW MODE 在此模式下可以没有内部PLL,耗电情况依赖于外部时钟的频率 (3)IDLE MODE FCLK被关断,主要由于CPU core节电。可以任何通过外部中断唤醒 (4)Power_OFF MODE 除了处理器唤醒逻辑单元外,处理器不损耗任何电量。可以通过EINT 或 RTC alarm interrupt唤醒系统 二、S3C2410各种节电模式的进入 (1)慢速模式(SLOW) CLKSLOW的SLOW_BIT置1进入 (2)空闲模式(IDLE) CLKCON 被置1则进入 (3)掉电模式(Powe
[单片机]
关于<font color='red'>S3C2410</font>的电源管理
UART-中断模式
init.c /* * init.c: 进行一些初始化 */ #include s3c24xx.h void disable_watch_dog(void); void clock_init(void); void memsetup(void); void copy_steppingstone_to_sdram(void); /* * 关闭WATCHDOG,否则CPU会不断重启 */ void disable_watch_dog(void) { WTCON = 0; // 关闭WATCHDOG很简单,往这个寄存器写0即可 } #define S3C2410_MPLL_200MHZ ((0x5c
[单片机]
AVR128单片机最小系统串口,外部中断,跑马灯,uCOS-II移植
实验名称:串口通信实验 功能描述:计算机通过串口向开发板发送数据,开发板将数据原样送回。 实验目的:学习串口通信 实验说明:MCU--M128 内部8M晶振 连接方式:利用串口线将开发板和计算机相连。 单片机源程序如下: /************************************************ 文件:sio.c 用途:结构化串口通信程序 ************************************************/ #include config.h #if USEUART0 siocirqueue RTbuf_UART0; #endif #if USEUART1
[单片机]
基于嵌入式触摸屏驱动程序的研究与开
0 引言 Windows CE.NET是一个抢先式多任务并具有强大通信能力的Windows 32位嵌入式操作系统,是微软专门为信息设备、移动应用、消费类电子产品、嵌入式应用等非PC领域而从头设计的战略性操作系统产品。可以看出 Windows CE并不是Windows桌面操作系统的一部分或缩减版本。CE系统与其它操作系统一样,也提供了设备驱动程序,以驱动内部或者外围硬件设备。驱动程序将操作系统和设备链接起来,使得操作系统能够识别设备,并为应用程序提供相应的服务 。要想真正了解驱动程序必须结合一些驱动程序的实际开发,本文以基于ARM9核心硬件平台的触摸屏驱动程序为例,讲解如何在不同的硬件设备上实现Windows CE的驱动开发。
[单片机]
基于嵌入式触摸屏驱动程序的研究与开
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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