一、2440裸机点亮led
从代码開始(先写一个像普通单片机一样的代码):
/********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的更多相关文章
- Raspberry PI 系列 —— 裸机点亮LED灯
Raspberry PI 系列 -- 裸机点亮LED灯 背景 近期刚买了Raspberry PI B+,配置执行了官方提供的Raspbian系统,折腾了一周Linux系统,感觉没啥意思,于是就试着想了 ...
- Tiny6410 裸机开发--裸机点亮LED
环境搭建 由于我不喜欢使用虚拟机,双系统无法同时烧程序.最近才折腾好Windows10下编译和下载程序,使用的是韦东山做的easy open jtag,资料十分齐全,之前使用jlink搭建环境碰到了一 ...
- JZ2440裸机点亮LED【学习笔记】
平台:jz2440 作者:庄泽彬(欢迎转载,请注明作者) 说明:韦东山一期视频学习笔记 一.我们首先来做第一个实验,用汇编语言点亮板子上的LED. 1.1 LED的原理图 从下面的原理图可知LED1是 ...
- S3C2440—3.用点亮LED来熟悉裸机开发的详细流程
文章目录 一.硬件知识 1.LED原理图 2.芯片手册 Ⅰ.找LED原理图 Ⅱ.找对应引脚 Ⅲ.在芯片手册中查找引脚信息 Ⅳ.查看寄存器说明 Ⅴ.配置寄存器 二.S3C2440框架与启动过程 三.要用 ...
- JZ2440开发笔记(5)——通过按键点亮LED
在JZ2440中,点亮LED就是给LED的控制位设置为输出,数据位设置为低电平,而通过按键点亮LED,就需要将按键对应的控制位设置为输出. 下面是JZ2440的3个LED电路图: 下面是JZ2440的 ...
- 第8课.第一个ARM裸板程序(点亮led)及申引
1.原理图 2.芯片手册 3.几条汇编代码 1.ldr:读内存 ldr R0, [R1] 假设R1的值是x,读取地址x上的数据(4字节),保存到R0中 ldr R0, =0x12345678 (4字节 ...
- Mini2440上的第一个程序——点亮Led
手头的Mini2440搁置了两年半之后,我再次决定拿出它,重新尝试嵌入式Linux的学习. 我使用的是友善之臂的Mini2440开发板.韦东山的<嵌入式Linux应用开发完成手册>及其视频 ...
- Arduino 极速入门系列–1 点亮 LED
本篇内容为,使用 Arduino 点亮 LED 的做法示范.很简单的一个入门示范.我们让 LED 闪. 本篇使用到的工具和材料 Arduino Mini Pro 1 PCS Mini USB 数据线 ...
- STM32学习笔记——点亮LED
STM32学习笔记——点亮LED 本人学习STM32是直接通过操作stm32的寄存器,使用的开发板是野火ISO-V2版本: 先简单的介绍一下stm32的GPIO: stm32的GPIO有多种模式: 1 ...
随机推荐
- android动画具体解释二 属性动画原理
property动画是一个强大的框架,它差点儿能使你动画不论什么东西. 你能够定义一个动画来改变对象的不论什么属性,不论其是否被绘制于屏幕之上. 一个属性动画在一定时间内多次改变一个属性(对象的一个字 ...
- atitit.groovy 语法特性
atitit.groovy 语法特性 1. Groovy 1.6概览1 1.1. 多路赋值2 2. 新发布的Groovy2.0为这门语言带来了关键的静态特性:静态类型检查和静态编译:2 3. 参考3 ...
- Atitit.播放系统规划新版本 and 最近版本回顾 v3 pbf.doc
Atitit.播放系统规划新版本 and 最近版本回顾 v3 pbf.doc 1 版本11 (ing)4 1.1 规划h5本地缓存系列 4 1.2 Android版本app4 1.3 双类别系统, ...
- 解决带fusionCharts的页面多次点击后不显示的问题
问题: 假设不使用公司封装的fusioncharts.使用自己定义的.建议不要使用例如以下方法 使用$(document).ready( 页面载入完之后再载入,会导致多次点击带有fusionchart ...
- waterfall.js
jq-waterfall是一款仿Pinterest网站的响应式无限动态加载图片瀑布流特效jQuery插件.该瀑布流特效使用ajax调用来动态加载图片,达到无限加载的效果.它使用简单,兼容性好,值得推荐 ...
- js基础系列框架:JS重要知识点(转载)
这里列出了一些JS重要知识点(不全面,但自己感觉很重要).彻底理解并掌握这些知识点,对于每个想要深入学习JS的朋友应该都是必须的. 讲解还是以示例代码搭配注释的形式,这里做个小目录: JS代码预解析原 ...
- FreeBSD编译安装emacs,不要用ports
1. 解压emacs 2. 进入解压之后的目录,执行configure命令,大体配置如下: ./configure --with-x-toolkit=no --with-xpm=no --with-j ...
- Yarn源码分析之MRAppMaster上MapReduce作业处理总流程(一)
我们知道,如果想要在Yarn上运行MapReduce作业,仅需实现一个ApplicationMaster组件即可,而MRAppMaster正是MapReduce在Yarn上ApplicationMas ...
- Elasticsearch5.X IN Windows 10 系列文章(2)
ElasticSearch版本: 5.5.1 (最新稳定版为5.5.2),由于用到IK中文分词插件,最新版本没有5.5.2 ,所以使用5.5.1 日期:2017-08-29 第二章:安装Kibana ...
- Linux快速计算MD5和Sha1命令
Linux计算MD5和Sha1的命令 MD5 MD5即Message-Digest Algorithm 5(信息-摘要算法 5),用于确保信息传输完整一致.是计算机广泛使用的杂凑算法之一(又译摘要算法 ...