Tiny6410裸机开发笔记(一)汇编点亮LED

2023-11-05 03:10

本文主要是介绍Tiny6410裸机开发笔记(一)汇编点亮LED,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

开发版信息

CPU: S3C6410
RAM:128MB
NAND: 256MB(SLC) ID:ECDA1095
Touch Device: 1-wire
LCD Type: S70

1. 查阅原理图

Tiny6410 板上提供了 4 个可编程用户 LED,原理图如下:
LEDS
GPIO
LED1,2,3,4 分别使用的 CPU 端口资源为GPK_4,5,6,7

2. 程序编写

2.1 Start.S

2.1.1 代码编写

由原理图可知,点亮Tiny6410 的4 个LED 需如下2 个步骤:
把外设的基地址告诉CPU;对于6410 来说,内存的地址范围为0x00000000~0x60000000,外设的地址范围为0x70000000-0x7fffffff。
关闭看门狗,防止程序不断重启;
设置寄存器GPKCON0,使GPK_4/5/6/7 四个引脚为输出功能;
往寄存器GPKDAT 写0,使GPK_4/5/6/7 四个引脚输出低电平,4 个LED 会亮;相反,
往寄存器GPKDAT 写1,使GPK_4/5/6/7 四个引脚输出高电平,4 个LED 会灭;
Address Map

S3C6410X支持32位物理地址字段,该地址字段可以分为两部分,一部分是内存,另一部分是外设。主存通过SPINE总线访问,其地址范围为0x0000_0000到0x6FFF_FFFF。这个主存部分分为四个区域,启动映像区、内存区、静态内存区和动态内存区。启动映像区的地址范围是从0x0000_0000到0x07FF_FFFF,但是没有真正的映射内存。启动映像区具有镜像映像,镜像映像指向内部内存区或静态内存区的部分区域。启动映像的起始地址固定为0x0000_0000。内部存储器区用于访问内部ROM和内部SRAM,用于引导加载程序,也称为Stepping Stone。每个内存的起始地址是固定的。内部ROM的地址范围是0x0800_0000到0x0BFF_FFFF,但实际存储空间只有32KB。此区域是只读的,当选择内部ROM引导时,可以映射到引导映像区。内部SRAM的地址范围是从0x0C00_0000到0x0FFF_FFFF,但实际存储空间只有4KB。静态存储区的地址范围是从0x1000_0000到0x3FFF_FFFF。SROM、SRAM或闪存,异步NOR接口设备、OneNAND Flash和Steppingstone可以通过这个地址区访问。每个区域代表一个芯片选择,例如,地址范围从0x1000_0000到0x17FF_FFFF代表Xm0CSn[0]。每个芯片选择的起始地址是固定的。NAND闪存和CF/ATA不能通过静态内存区域访问,所以如果Xm0CSn[5:2]中的任何一个映射到NFCON或CFCON,则相关的地址区域不应该被访问。一个例外是,如果Xm0CSn[2]用于NAND闪存,则Steppingstone地址将从0x2000_0000镜像到27FF_FFFF。动态存储区的地址范围是从0x4000_0000到0x6FFF_FFFF。DMC1有权使用地址范围0x5000_0000到0x6FFF_FFFF。每个芯片选择的起始地址是可配置的。外设通过PERI总线访问,其地址范围为0x7000_ 00000x7FFF_ FFFF。所有SFR可以在此地址范围内访问。此外,如果需要从NFCON或CFCON传输数据,这些数据应该通过外围总线传输。

.global _start
_start: //外设基地址及大小告诉CPUldr r0, =0x70000000		//ldr: loadorr r0, r0, #0x13 		//0x13=b10011=256M, 参见arm1176jzfs内核参考手册Page3-130mcr p15,0,r0,c15,c2,4       	//把r0的值(包括了外设基地址+外设大小)告诉cpu//关看门狗ldr r0, =0x7E004000		//watch dog timer base addressmov r1, #0str r1, [r0]			//disable watch dog.  str: Store//设置GPKCON0ldr r0, =0x7F008800		//GPKCON0 addressldr r1, =0x11110000		//GPK_4,5,6,7设置为输出, GPKn设置为0001时,GPKn引脚设置为输出str r1, [r0]mov r2, #0x1000			//LED循环计数
led_blink:ldr r0, =0x7F008808		//GPKDAT addressmov r1, #0xF0			//设置GPK_4,5,6,7为高电平,Led熄灭str r1, [r0]bl  delayldr r0, =0x7F008808mov r1, #0x00			//设置GPK_4,5,6,7为低电平,Led点亮str r1, [r0]bl  delaysub r2, r2, #1			//r2=r2-1cmp r2, #0bne led_blink			//如果r2!=0,则跳转至led_blink处执行。bne:Branch Not Equalhalt:b   halt			//b: Branchdelay:mov r0, #0x1000000	
delay_loop:		sub r0, r0, #1cmp r0, #0bne delay_loopmov pc, lr			//从delay子程序返回

2.1.2 汇编指令学习

1. 跳转语句 B,BL
程序流程的跳转,在 ARM 程序中有两种方法可以实现程序流程的跳转指令用于实现l  使用专门的跳转指令 Bl  直接向程序计数器PC 写入跳转地址值n  这是几乎是任何一种CPU必备的机器,PC表示CPU当前执行语句位置,改变PC的值,相当于实现程序跳转n  如实现类似C语言的Return 语句,就是用MOV PC,LRn  这里可以在任意4G的空间进行跳转B指令(Branch)表示无条件跳转.B main ;跳转到标号为main地代码处BL指令(Branch with Link)表示带返回值的跳转.BL比B多做一步,在跳转前,BL会把当前位置保存在R14(即LR寄存器),当跳转代码结束后,用MOV PC,LR指令跳回来,这实际上就是C语言执行函数的用法,汇编里调子程序都用BL,执行完子函数后,可以用MOV PC,LR跳回来.BL delay ;执行子函数或代码段delay ,delay可以为C函数.与MOV PC,XXX能在4G空间跳转不同,B语句只能32M空间跳转,(因为偏移量是一个有符号26bit的数值=32M)2. 传输数据指令MOV,MVN
n  MOV(MOVE)指令可完成从另一个寄存器、被移位的寄存器或将一个立即数加载到目的寄存器MOV R0,R1 ; 把R1的值传到R0MOV R3,#3 ;把常数3传给R3,MOV中用#表示常数,这个值不能超过n  MVN( MOVE Negative)取反后再传值,比MOV多了一步取反MVN R0, #0 ;0取反(即-1)传给R0MVN R1,R2  ;把R2的值取反传给R13. 加载/存储指令,LDR,STR
n  LDR,STR是用于寄存器和外部存储器交换数据指令,注意与MOV的区别,后面只在寄存器或常数交换.u  LDR/STR可以采用多种寻址方式,以下只举出使用频率最高几种用法n  LDR(load)用于把一个32Bit的WORD数据从外部存储空间装入到寄存器中LDR R0,[R1]; R1的值当成地址,再从这个地址装入数据到R0 (R0=*R1)LDR R1,=0x30008000 ; 把地址0x30008000的值装入到R1中,LDR中用常数要用=打头.(注意跟MOV的区别,MOV是#)ldr  r0, =(0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0)用位与的方法赋值n  STR(Store) 用于把一个寄存器的值存入外部存储空间,是LDR的逆操作.STR R0,[R1] ; 把R0的值,存入到R1对应地址空间上(*R1 = R0)STR R0,=0x30008000 ;把R0中值存入到地址0x30008000

2.2 Makefile

2.2.1 代码编写

led.bin: start.oarm-linux-ld -Ttext 0x50000000 -o led.elf $^arm-linux-objcopy -O binary led.elf led.binarm-linux-objdump -D led.elf > led_elf.dis
%.o : %.Sarm-linux-gcc -o $@ $< -c%.o : %.carm-linux-gcc -o $@ $< -c clean:rm *.o *.elf *.bin *.dis  -rf

2.2.2 Makefile学习

1. 主要功能
Make工具最主要也是最基本的功能就是通过makefile文件来描述源程序之间的相互关系并自动维护编译工作。而makefile 文件需要按照某种语法进行编写,文件中需要说明如何编译各个源文件并连接生成可执行文件,并要求定义源文件之间的依赖关系。makefile 文件是许多编译器--包括 Windows NT 下的编译器--维护编译信息的常用方法,只是在集成开发环境中,用户通过友好的界面修改 makefile 文件而已。2. 规则target ... : prerequisites ...
command
...
...目标:依赖
执行指令 ...target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label)
 prerequisites就是,要生成那个target所需要的文件或是目标。
 command也就是make需要执行的命令。(任意的Shell命令)这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行(command一定要以Tab键开始,否则编译器无法识别command),减少重复编译,提高了其软件工程管理效率。3. 自动化变量
在上述的模式规则中,目标和依赖文件都是一系例的文件,那么我们如何书写一个命令来完成从不同的依赖文件生成相应的目标?因为在每一次的对模式规则的解析时,都会是不同的目标和依赖文件。
自动化变量就是完成这个功能的。在前面,我们已经对自动化变量有所提涉,相信你看到这里已对它有一个感性认识了。所谓自动化变量,就是这种变量会把模式中所定义的一系列的文件自动地挨个取出,直至所有的符合模式的文件都取完了。这种自动化变量只应出现在规则的命令中。
下面是所有的自动化变量及其说明:
$@
表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。
$%
仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么,"$%"就是"bar.o""$@"就是"foo.a"。如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。
$<
依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
$?
所有比目标新的依赖目标的集合。以空格分隔。
$^
所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
$+
这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。
$*
这个变量表示目标模式中"%"及其之前的部分。如果目标是"dir/a.foo.b",并且目标的模式是"a.%.b",那么,"$*"的值就是"dir/a.foo"。这个变量对于构造有关联的文件名是比较有较。如果目标中没有模式的定义,那么"$*"也就不能被推导出,但是,如果目标文件的后缀是make所识别的,那么"$*"就是除了后缀的那一部分。例如:如果目标是"foo.c",因为".c"是make所能识别的后缀名,所以,"$*"的值就是"foo"。这个特性是GNU make的,很有可能不兼容于其它版本的make,所以,你应该尽量避免使用"$*",除非是在隐含规则或是静态模式中。如果目标中的后缀是make所不能识别的,那么"$*"就是空值。
当你希望只对更新过的依赖文件进行操作时,"$?"在显式规则中很有用,例如,假设有一个函数库文件叫"lib",其由其它几个object文件更新。那么把object文件打包的比较有效率的Makefile规则是:
lib : foo.o bar.o lose.o win.o
ar r lib $?
在上述所列出来的自动量变量中。四个变量($@、$<、$%、$*)在扩展时只会有一个文件,而另三个的值是一个文件列表。这七个自动化变量还可以取得文件的目录名或是在当前目录下的符合模式的文件名,只需要搭配上"D""F"字样。这是GNU make中老版本的特性,在新版本中,我们使用函数"dir""notdir"就可以做到了。"D"的含义就是Directory,就是目录,"F"的含义就是File,就是文件。
下面是对于上面的七个变量分别加上"D"或是"F"的含义:
$(@D)
表示"$@"的目录部分(不以斜杠作为结尾),如果"$@"值是"dir/foo.o",那么"$(@D)"就是"dir",而如果"$@"中没有包含斜杠的话,其值就是"."(当前目录)。
$(@F)
表示"$@"的文件部分,如果"$@"值是"dir/foo.o",那么"$(@F)"就是"foo.o""$(@F)"相当于函数"$(notdir $@)"
"$(*D)"
"$(*F)"
和上面所述的同理,也是取文件的目录部分和文件部分。对于上面的那个例子,"$(*D)"返回"dir",而"$(*F)"返回"foo"
"$(%D)"
"$(%F)"
分别表示了函数包文件成员的目录部分和文件部分。这对于形同"archive(member)"形式的目标中的"member"中包含了不同的目录很有用。
"$(<D)"
"$(<F)"
分别表示依赖文件的目录部分和文件部分。
"$(^D)"
"$(^F)"
分别表示所有依赖文件的目录部分和文件部分。(无相同的)
"$(+D)"
"$(+F)"
分别表示所有依赖文件的目录部分和文件部分。(可以有相同的)
"$(?D)"
"$(?F)"
分别表示被更新的依赖文件的目录部分和文件部分。
最后想提醒一下的是,对于"$<",为了避免产生不必要的麻烦,我们最好给$后面的那个特定字符都加上圆括号,比如,"$(<)"就要比"$<"要好一些。
还得要注意的是,这些变量只使用在规则的命令中,而且一般都是"显式规则""静态模式规则"(参见前面"书写规则"一章)。其在隐含规则中并没有意义。

这篇关于Tiny6410裸机开发笔记(一)汇编点亮LED的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/347005

相关文章

基于Python开发电脑定时关机工具

《基于Python开发电脑定时关机工具》这篇文章主要为大家详细介绍了如何基于Python开发一个电脑定时关机工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 简介2. 运行效果3. 相关源码1. 简介这个程序就像一个“忠实的管家”,帮你按时关掉电脑,而且全程不需要你多做

Java中的Opencv简介与开发环境部署方法

《Java中的Opencv简介与开发环境部署方法》OpenCV是一个开源的计算机视觉和图像处理库,提供了丰富的图像处理算法和工具,它支持多种图像处理和计算机视觉算法,可以用于物体识别与跟踪、图像分割与... 目录1.Opencv简介Opencv的应用2.Java使用OpenCV进行图像操作opencv安装j

基于Qt开发一个简单的OFD阅读器

《基于Qt开发一个简单的OFD阅读器》这篇文章主要为大家详细介绍了如何使用Qt框架开发一个功能强大且性能优异的OFD阅读器,文中的示例代码讲解详细,有需要的小伙伴可以参考一下... 目录摘要引言一、OFD文件格式解析二、文档结构解析三、页面渲染四、用户交互五、性能优化六、示例代码七、未来发展方向八、结论摘要

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo

C#图表开发之Chart详解

《C#图表开发之Chart详解》C#中的Chart控件用于开发图表功能,具有Series和ChartArea两个重要属性,Series属性是SeriesCollection类型,包含多个Series对... 目录OverviChina编程ewSeries类总结OverviewC#中,开发图表功能的控件是Char

鸿蒙开发搭建flutter适配的开发环境

《鸿蒙开发搭建flutter适配的开发环境》文章详细介绍了在Windows系统上如何创建和运行鸿蒙Flutter项目,包括使用flutterdoctor检测环境、创建项目、编译HAP包以及在真机上运... 目录环境搭建创建运行项目打包项目总结环境搭建1.安装 DevEco Studio NEXT IDE

Python开发围棋游戏的实例代码(实现全部功能)

《Python开发围棋游戏的实例代码(实现全部功能)》围棋是一种古老而复杂的策略棋类游戏,起源于中国,已有超过2500年的历史,本文介绍了如何用Python开发一个简单的围棋游戏,实例代码涵盖了游戏的... 目录1. 围棋游戏概述1.1 游戏规则1.2 游戏设计思路2. 环境准备3. 创建棋盘3.1 棋盘类

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD