从代码開始(先写一个像普通单片机一样的代码):

/********led.c************************/

#define GPFCON  (*(volatile unsigned long *)0x56000050)

#define GPFDAT  (*(volatile unsigned long *)0x56000054)

/*后面的数字是引脚的寄存器的地址,(volatile unsignedlong *)这是强制转换,就是吧后面的数字强制转换成volatile unsigned long 的指针类型。最前面的“*”是代表该地址存储的数据*/

static voidpin_init(void)

{

/*首先看原理图led链接的那个引脚,然后在datasheet找到该引脚寄存器地址*/

GPFCON&=~(3<<8); //GPF4相应控制位清0

GPFCON&=~(3<<10); //GPF5相应控制位清0

GPFCON&=~(3<<12); //GPF6相应控制位清0

GPFCON |=1<<8;   //GPF4相应控制位设置为输出

GPFCON |=1<<10;

GPFCON |=1<<12;

GPFDAT&=~(1<<4);//GPF4设置输出0

GPFDAT&=~(1<<5);//GPF5设置输出0

GPFDAT&=~(1<<6);//GPF6设置输出0

}

static voiddelay(volatile unsigned int a)

{

int k;

k=30000;

while(--k>0)

for(;a>0;a--);

}

int main ()

{

int temp=1; //用了反转的标志位

pin_init();

while(1)

{

if (temp>0)

{

GPFDAT |=1<<4;

delay(6000);

GPFDAT |=1<<5;

delay(6000);

GPFDAT |=1<<6;

delay(6000);

temp=-1;

}

else

{

GPFDAT &=~(1<<4);

delay(6000);

GPFDAT &=~(1<<5);

delay(6000);

GPFDAT &=~(1<<6);

delay(6000);

temp=1;

}

}

return 0;

}

c代码比較简单,接下来就要用启动文件了。

启动文件就是包括一些初始化信息相关的初始化的工作包括:



(1)建立异常向量表、设置栈以及硬件初始化

硬件相关的初始化的工作包含:

①关闭看门狗  

②初始化时钟

③初始化SDRAM

(2)设置main函数的返回地址

(3)调用main函数

(4)完毕一些清理工作

简要说明:

首先,异常向量表不是必须的,起作用是将用户程序与启动代码之间及其启动代码之间建立关系。由一系列的跳转指令完毕。当系统发生异常的时候,处理器将把PC指针由硬件强制指向异常向量表的相应的异常处理函数中,开发板为了上电后能够进入复位异常处理函数中(该函数完毕以下个步骤的初始化工作),所以异常向量表要写在启动代码的最前面。

然后设置栈是必须的

对于关闭看门狗,这个是必须的。不然芯片处于不断重新启动的过程。

初始化时钟就是设置时钟频率,默认的系统时钟12M,依据自己实际设置。

假如要用到SDRAM就要进行SDRAM的初始化。

因为本次程序比較简单,代码编译出来肯定小于4k。因此能够对于启动文件的书写能够分两次实验:

⑴执行程序直接在SRAM( Steppingstone)执行,不在将nand
flash的内容复制到SDRAM中。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;裸机的启动文件   init.s

.text

.global _start

_start:

 ldr    r0, =0x53000000     ; WATCHDOG寄存器地址

           mov     r1,#0x0                     

           str   r1,[r0]             ;赋值WATCHDOG为0。关闭看狗            

           ldr     sp, =4096       ;设置堆栈,sram是4k

bl     main               ; 调用C程序中的main函数

loop:

           b       loop

上面没有初始化sdran,使用的默认时钟12M。此时的执行地址在makefile中就要设置-Ttext为0

⑵按键控制led

这里仅仅是改动写led.c文件就能够

对于本人使用的开发板来说。开发板的3个按键分别连接2440的GPF0   GPF2  GPG3引脚,因此在这里改动led.c文件例如以下:

/*****************************************************

按键控制led

原理图得知3个按键分别连接2440的GPF0   GPF2  GPG3

三个led 分别相应 GPF4GPF5   GPF6

*************************************************/

#defineGPFCON  (*(volatile unsigned long*)0x56000050)

#defineGPFDAT  (*(volatile unsigned long*)0x56000054)

#defineGPGCON  (*(volatile unsigned long*)0x56000060)

#defineGPGDAT  (*(volatile unsigned long*)0x56000064)

static voidpin_init(void)

{

/*led*/

GPFCON&=~(3<<8);

GPFCON&=~(3<<10); //GPF5相应控制位清0

GPFCON&=~(3<<12); //GPF6相应控制位清0

GPFCON |=1<<8;   //GPF4相应控制位设置为输出

GPFCON |=1<<10;

GPFCON |=1<<12;

GPFDAT&=~(1<<4);//GPF4设置输出0

GPFDAT&=~(1<<5);//GPF5设置输出0

GPFDAT&=~(1<<6);//GPF6设置输出0

/*key*/

GPFCON&=~(3<<0);

GPFCON&=~(3<<(2*2)); //GPF2相应控制位清0

GPGCON&=~(3<<(2*3)); //GPG3相应控制位清0

/*清零的同一时候也把按键相应的引脚设置成输入*/

}

int main ()

{

unsigned long key_state; //记录按键的状态

pin_init();

while(1)

{

/*当有按键按下led亮,松开按键led灭*/

key_state=GPFDAT;

if(key_state&(1<<0))

GPFDAT|=(1<<4);//GPF4设置输出1

else

GPFDAT&=~(1<<4);//GPF4设置输出0

if(key_state&(1<<2))

GPFDAT|=(1<<5);//GPF5设置输出1

else

GPFDAT&=~(1<<5);//GPF5设置输出0

key_state=GPGDAT;

if(key_state&(1<<3))

GPFDAT|=(1<<6);//GPF6设置输出1

else

GPFDAT&=~(1<<6);//GPF6设置输出0

}

return 0;

}

改动后,又一次make 。下载到开发板中有现象,当有按键按下时led亮。松开按键。led灭。

⑶执行程序在SDRAM执行,须要将SRAM的内容复制到SDRAM中。

以下给出一个完整的启动代码,代码的解释參考《mini启动代码的编写(第三版)》代码的编写大都參考了ads1.2库文件的启动代码。这里下载的是百问网的。

详细的代码文件见附录的裸机代码部分须要的文件有:startup.S   init.c   nand .c s3c24xx.h

此时编译的时候须要设置执行地址为:-Ttext为0x30000000

这样。代码的启动流程就是把程序下载到nand flash中,然后硬件自己主动吧nand的前4k代码(主要是初始化代码)复制到SRAM中,然后代码開始在SRAM的0地址处開始运行,然后通过代码将sram中的代码复制到SDRAM中,然后有程序控制跳转到SDRAM中去运行。

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

; File:init.S

; 功能:设置SDRAM,将程序拷贝到SDRAM,然后跳到SDRAM继续运行

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

.equ        MEM_CTL_BASE,       0x48000000

.equ        SDRAM_BASE,         0x30000000

.text

.global _start

_start:

bl disable_watch_dog               ; 关闭WATCHDOG。否则CPU会不断重新启动

bl memsetup                        ; 设置存储控制器

bl copy_steppingstone_to_sdram     ; 复制代码到SDRAM中

ldr pc, =on_sdram                   ; 跳到SDRAM中继续运行

on_sdram:

ldr sp, =0x34000000                 ; 设置堆栈

bl main

halt_loop:

b  halt_loop

disable_watch_dog:

; 往WATCHDOG寄存器写0就可以

mov r1,    #0x53000000

mov r2,    #0x0

str r2,    [r1]

mov pc,    lr      ; 返回

copy_steppingstone_to_sdram:

; 将Steppingstone的4K数据所有拷贝到SDRAM中去

; Steppingstone起始地址为0x00000000。SDRAM中起始地址为0x30000000

mov r1, #0

ldr r2, =SDRAM_BASE

mov r3, #4*1024

1:

ldr r4, [r1],#4     ; 从Steppingstone读取4字节的数据,并让源地址加4

str r4, [r2],#4     ; 将此4字节的数据拷贝到SDRAM中,并让目地地址加4

cmp r1, r3          ; 推断是否完毕:源地址等于Steppingstone的未地址?

bne 1b              ; 若没有复制完,继续

mov pc,    lr      ; 返回

memsetup:

; 设置存储控制器以便使用SDRAM等外设

mov r1,    #MEM_CTL_BASE       ; 存储控制器的13个寄存器的開始地址

adrl   r2, mem_cfg_val         ; 这13个值的起始存储地址

add r3,    r1, #52             ; 13*4 = 54

1:

ldr r4,    [r2], #4            ; 读取设置值。并让r2加4

str r4,    [r1], #4            ; 将此值写入寄存器,并让r1加4

cmp r1,    r3                  ; 推断是否设置全然部13个寄存器

bne 1b                          ; 若没有写成。继续

mov pc,    lr                  ; 返回

.align 4

mem_cfg_val:

; 存储控制器13个寄存器的设置值

.long  0x22011110      ; BWSCON

.long  0x00000700      ; BANKCON0

.long  0x00000700      ; BANKCON1

.long  0x00000700      ; BANKCON2

.long  0x00000700      ; BANKCON3

.long  0x00000700      ; BANKCON4

.long  0x00000700      ; BANKCON5

.long  0x00018005      ; BANKCON6

.long  0x00018005      ; BANKCON7

.long  0x008C07A3      ; REFRESH

.long  0x000000B1      ; BANKSIZE

.long  0x00000030      ; MRSRB6

.long  0x00000030      ; MRSRB7

接下来開始写makefile,在写makefile文件之前,首先须要了解一下gcc的编译过程:

程序编译过程可分为四步:

预处理(Preproceessing):主要是.c和.h文件生成一个文件 (处理一写头文件、宏定义、预编译指令等)

编译(Compilation):上步生成文件生成.s文件 (包含语法分析、优化等等)

汇编(Assembly):.s文件生成.o文件(把汇编语言代码翻译成目标机器指令)

链接(Linking):.o和.a等连接成可运行文件默觉得a.out(将有关的目标文件彼此相连接)

以下写代码来说明各个过程:

/*hello.c*/

#include<stdio.h>

int main ()

{

printf(“hello\n”)

return 0;

}

首先进行预处理:

gcc –E hello.c

-E參数就是让gcc仅仅是预处理,不进行编译、汇编和链接。

运行的时候会在终端打印出好多信息。

这就是预处理后生成的文件。

然后运行 gcc –S  hello.c

-S參数就是让gcc仅仅进行编译。不进行汇编和链接

运行该命令后会得到一个.s的汇编文件。内容为:

.file   "hello.c"

.section        .rodata

.LC0:

.string "hello"

.text

.globl  main

.type   main, @function

main:

.LFB0:

.cfi_startproc

pushl   %ebp

.cfi_def_cfa_offset 8

.cfi_offset 5, -8

movl   %esp, %ebp

.cfi_def_cfa_register5

andl    $-16, %esp

subl    $16, %esp

movl    $.LC0, (%esp)

call    puts

movl    $0, %eax

leave

.cfi_restore 5

.cfi_def_cfa 4, 4

ret

.cfi_endproc

.LFE0:

.size   main, .-main

.ident  "GCC: (Ubuntu 4.8.2-19ubuntu1)4.8.2"

.section        .note.GNU-stack,"",@progbits

再者执行:

gcc -c hello.c

得到hello.o, hello.o的内容为机器码,不能以普通文本形式的查看

最后执行进行链接,链接要用到ld命令,这里直接使用:

gcc hello.c

能够完毕全部的步骤,这是默认的生成.out文件

接下来些makefile文件

Makefile文件:

对于将在sram运行时候可为:

CFLAGS  := -Wall -Wstrict-prototypes -O2  -nostdlib

led.bin :init.S led.c

arm-linux-gcc $(CFLAGS) -c -o init.oinit.S

arm-linux-gcc $(CFLAGS) -c -o led.o led.c

arm-linux-ld -Ttext 0  init.o led.o -o led_elf

arm-linux-objcopy -O binary -S  led_elf led.bin

#arm-linux-objdump -D -m arm  led_elf >  led.dis

clean:

rm -rf *.o *elf  *bin *.dis

对于CFAGS,也就是gcc的选项解释例如以下:

-Wall生成全部警告信息。

-Wstrict-prototypes 假设一个函数定义或者声明没有指定參数类型发出警告。

-O设置一共同拥有五种:-O0、-O1、-O2、-O3和-Os

O0:这个等级(字母“O”后面跟个零)关闭全部优化选项,也是CFLAGS或CXXFLAGS中没有设置-O等级时的默认等级。这样就不会优化代码,这通常不是我们想要的。

-O1:这是最主要的优化等级。编译器会在不花费太多编译时间的同一时候试图生成更快更小的代码。这些优化是很基础的。但一般这些任务肯定能顺利完毕。 

-O2:-O1的进阶。这是推荐的优化等级,除非你有特殊的需求。-O2会比-O1启用多一些标记。设置了-O2后。编译器会试图提高代码性能而不会增大体积和大量占用的编译时间。

-O3:这是最高最危急的优化等级。

用这个选项会延长编译代码的时间,而且在使用gcc4.x的系统里不应全局启用。

自从3.x版本号以来gcc的行为已经有了极大地改变。在3.x。-O3生成的代码也仅仅是比-O2快一点点而已,而gcc4.x中还未必更快。用-O3来编译全部的软件包将产生更大体积更耗内存的二进制文件。大大添加编译失败的机会或不可预知的程序行为(包含错误)。这样做将得不偿失,记住过犹不及。在gcc 4.x.中使用-O3是不推荐的。

-Os:这个等级用来优化代码尺寸。当中启用了-O2中不会添加磁盘空间占用的代码生成选项。这对于磁盘空间极其紧张或者CPU缓存较小的机器很实用。但也可能产生些许问题,因此软件树中的大部分ebuild都过滤掉这个等级的优化。

使用-Os是不推荐的。

(全部的參数能够在man gcc 查看)

接下来两行是分别汇编成.o文件

对于这一句: arm-linux-ld -Ttext 0 init.o led.o -o led_elf  当中-Ttext的功能就是指定程度段的起始地址。这里不过指定了一下代码段的执行地址,后面的数据段并不会在后面接着存放。

也即是程序是跳转到0处(sran的起始地址)去执行的。

另一点就是链接init.0和led.o生成可elf的可执行文件,ELF(excutable
and linking format
)是一种可运行可链接格式的二进制文件,它能够用来表示relocatablefile、executablefile或者sharedobject file,这三者都是目标文件(objectfile)。所谓“可运行”指能够被调入内存供CPU直接运行;“可链接”指多个ELF格式的目标文件能够被链接在一起形成一个可运行文件。

arm-linux-objcopy被用来复制一个目标文件的内容到还有一个文件里.此选项能够进行格式的转换.这里就是将elf格式的文件转化为.bin二进制文件。对于 arm-linux-objcopy -Obinary -S  led_elf  led.bin –O后面的是输出的问价类型,-S 是说不要从输入文件复制重定位信息和符号信息到目标文件里。

至于led.c文件,仍使用上面的那个按键点灯的程序。

一切就绪后。就能够编译然后将终于生成的led.bin/文件下载到开发板中就能够,假如成功的话,当有按键按下的时候等就会亮。松开按键等就会灭。

http://blog.csdn.net/jmppok/article/details/17121971

http://blog.csdn.net/laoniu_c/article/details/17218289

http://www.cnblogs.com/brianhxh/archive/2009/07/04/1517020.html

http://blog.csdn.net/tang_jin_chan/article/details/8675269

http://blog.csdn.net/happinux/article/details/5800996

http://blog.chinaunix.net/uid-26833883-id-3746968.html

http://www.cnblogs.com/brianhxh/archive/2009/07/04/1517020.html

一、2440裸机点亮led的更多相关文章

  1. Raspberry PI 系列 —— 裸机点亮LED灯

    Raspberry PI 系列 -- 裸机点亮LED灯 背景 近期刚买了Raspberry PI B+,配置执行了官方提供的Raspbian系统,折腾了一周Linux系统,感觉没啥意思,于是就试着想了 ...

  2. Tiny6410 裸机开发--裸机点亮LED

    环境搭建 由于我不喜欢使用虚拟机,双系统无法同时烧程序.最近才折腾好Windows10下编译和下载程序,使用的是韦东山做的easy open jtag,资料十分齐全,之前使用jlink搭建环境碰到了一 ...

  3. JZ2440裸机点亮LED【学习笔记】

    平台:jz2440 作者:庄泽彬(欢迎转载,请注明作者) 说明:韦东山一期视频学习笔记 一.我们首先来做第一个实验,用汇编语言点亮板子上的LED. 1.1 LED的原理图 从下面的原理图可知LED1是 ...

  4. S3C2440—3.用点亮LED来熟悉裸机开发的详细流程

    文章目录 一.硬件知识 1.LED原理图 2.芯片手册 Ⅰ.找LED原理图 Ⅱ.找对应引脚 Ⅲ.在芯片手册中查找引脚信息 Ⅳ.查看寄存器说明 Ⅴ.配置寄存器 二.S3C2440框架与启动过程 三.要用 ...

  5. JZ2440开发笔记(5)——通过按键点亮LED

    在JZ2440中,点亮LED就是给LED的控制位设置为输出,数据位设置为低电平,而通过按键点亮LED,就需要将按键对应的控制位设置为输出. 下面是JZ2440的3个LED电路图: 下面是JZ2440的 ...

  6. 第8课.第一个ARM裸板程序(点亮led)及申引

    1.原理图 2.芯片手册 3.几条汇编代码 1.ldr:读内存 ldr R0, [R1] 假设R1的值是x,读取地址x上的数据(4字节),保存到R0中 ldr R0, =0x12345678 (4字节 ...

  7. Mini2440上的第一个程序——点亮Led

    手头的Mini2440搁置了两年半之后,我再次决定拿出它,重新尝试嵌入式Linux的学习. 我使用的是友善之臂的Mini2440开发板.韦东山的<嵌入式Linux应用开发完成手册>及其视频 ...

  8. Arduino 极速入门系列–1 点亮 LED

    本篇内容为,使用 Arduino 点亮 LED 的做法示范.很简单的一个入门示范.我们让 LED 闪. 本篇使用到的工具和材料 Arduino Mini Pro 1 PCS Mini USB 数据线 ...

  9. STM32学习笔记——点亮LED

    STM32学习笔记——点亮LED 本人学习STM32是直接通过操作stm32的寄存器,使用的开发板是野火ISO-V2版本: 先简单的介绍一下stm32的GPIO: stm32的GPIO有多种模式: 1 ...

随机推荐

  1. C语言学习笔记(三) 输入输出函数的基本用法以及运算符

    printf() ——将内容输出到显示器上 四种用法 1.printf("字符串");   直接输出字符串 2.printf("输出控制符",输出参数); 3. ...

  2. PHP--关于模板的原理和解析(php模板原理)

    此内容用作笔记,以备日后查看,此内容为学习李炎恢课程而来,并非自己所创,如有问题请私信~ 将PHP代码和静态HTML代码进行分离,使代码的可读性和维护性得到显著提高. 使用模板引擎: 我们所说的模板是 ...

  3. bullet, iOS真机编译错误error: identifier or immediate expression expected解决方法

    刚才发现c3dEngine2(http://git.oschina.net/wantnon2/c3dEngine2 或 https://github.com/wantnon2/c3dEngine2)的 ...

  4. [ci]项目规划-后续

      几个方面来写   1,搭建gitlab 配邮箱 域名等使之好用 2,搭建jenkins –yum,安装常见插件 3,搭建sonar,汉化 4,安装sonar-scanner   0,实现sonar ...

  5. UML类图详解_关联关系_多对一

    首先先来明确一个概念,即多重性.什么是多重性呢?多重性是指两个对象之间的链接数目,表示法是“下限...上限”,最小数据为零(0),最大数目为没有设限(*),如果仅标示一个数目级上下限相同. 实际在UM ...

  6. [转]jsonp详解

    jsonp详解 json相信大家都用的多,jsonp我就一直没有机会用到,但也经常看到,只知道是“用来跨域的”,一直不知道具体是个什么东西.今天总算搞明白了.下面一步步来搞清楚jsonp是个什么玩意. ...

  7. MFC 控件RadioButton和CheckBox区别

    1. 单个RadioButton在选中后,通过点击无法变为未选中 单个CheckBox在选中后,通过点击可以变为未选中 2. 一组RadioButton,只能同时选中一个 一组CheckBox,能同时 ...

  8. SUSE10 SP4源码升级Python到2.6.6

    1.安装依赖包(CentOS可采用yum) zypper in gcc gcc-c++ openssl-devel-32bit openssl-devel readline-devel readlin ...

  9. poj 2117(割点的应用)

    题目链接:http://poj.org/problem?id=2117 思路:题目的意思是要求对于给定的无向图,删除某个顶点后,求最大的连通分量数.显然我们只有删掉割点后,连通分支数才会增加,因此我们 ...

  10. Java基础教程笔记

    第一部分——java基础程序设计 一:java语言特色 1:语言有点:“一次编写,到处运行” 2:相对于C++A:提供了对内存的自动管理:B:去除了C++语言中的“指针”:C:避免了赋值语句(如a=3 ...