C与ARM汇编结合实现mini2440串口uart简单程序
最近学完了ARM的一些基础知识,开始在mini2440上开发一些简单的程序,串口发送程序是一开始涉及多个寄存器的例子,稍有繁多的步骤应该是开发过程中要慢慢适应的境况
下面的程序的目的是实现mini2440串口的发送功能,向超级终端打印简单字符。
设备:mini2440如图,软件为gcc交叉编译工具,minitools与超级终端,主机环境为Windows虚拟机WSL(版本为ubuntu18.04)
首先应该为C语言主程序的运行初始化环境(设定好堆、栈、入口、中断向量表),这部分要用汇编实现,下面是这一部分
start.s:
.text
.global _start
_start:
ldr pc, _reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
nop
ldr pc, _irq
ldr pc, _fiq _reset:
.word reset
_undefined_instruction:
.word undefined_instruction
_software_interrupt:
.word software_interrupt
_prefetch_abort:
.word prefetch_abort
_data_abort:
.word data_abort
_irq:
.word irq
_fiq:
.word fiq reset: @先设置向量表的位置为0x30001000
ldr r0,= 0x30001000
mcr p15, , r0, c12, c0, init_stack: @初始化栈
ldr r0,= sk mov sp, r0 //svc
sub r0, # msr cpsr, #0xd2
mov sp, r0 //irq
sub r0, # msr cpsr, #0xd1
mov sp, r0 //fiq
sub r0, # msr cpsr, #0xd7
mov sp, r0 //abort
sub r0, # msr cpsr, #0xdb
mov sp, r0 //undefine
sub r0, # msr cpsr, #0x10
mov sp, r0 //user b main b main_end undefined_instruction: software_interrupt:
stmfd sp!, {r1 - r3, lr} ldmfd sp!, {r1 - r3, pc}^
prefetch_abort: data_abort: irq:
stmfd sp!, {r1 - r3, lr}
bl main
ldmfd sp!, {r1 - r3, pc}^ fiq: main_end:
b main_end .data
buf:
.space *
sk: .end
不过由于在这个串口程序中没有中断介入,所以这部分最主要的就是初始化栈(buf与ks之间的512*8Byte的栈空间),为之后的C主程序创造环境
之后便是最主要的工作:编写C程序操作串口相关寄存器。首先需要阅读minii2440原理图与S3C2440的芯片手册
从原理图上得知,我们要用的0号串口对应的GPIO引脚是GPH2号与3号引脚
之后去芯片手册找GPIO部分的GPH如下:
显然我们要把GPH的四五位和六七位分别置为10,表示这两个管脚进入uart模式
之后要配置S3C2440的uart控制器,到手册的UART部分
ULCON0寄存器与串口通信方式设置有关,我们只需要修改字长为八位:
UCON0寄存器则涉及收发模式、时钟选择等等,这里我们只需要设置收发为polling模式:
波特率的设置则需要借助UBRDIV0,这里由于前面的时钟默认选择为pclk,也就是50MHZ,而波特率是115200,那么按照下面的公式,得到UBRDIV0的值应该为(50000000 / (115200 * 16)) - 1 约等于26
收发状态寄存器为UTRSTAT0,收发内容寄存器为URXH0和UTXH0,注意,UTRSTAT0的0位为0时,接受寄存器为空,而1位为1时,发送寄存器为空,这一点区别要注意一下
因为之前我们不选择FIFO模式,所以主要通过这一个寄存器来确定当前是否处于可以发送数据的状态以及是否接收到了数据
下一步是编写C程序
main.c
/*
*配置串口传输主程序
*S3C2440
*
*/ #define GPHCON (*(unsigned int *)(0x56000070))
#define ULCON0 (*(unsigned int *)(0x50000000))
#define UCON0 (*(unsigned int *)(0x50000004))
#define UBRDIV0 (*(unsigned int *)(0x50000028))
#define UTXH0 (*(unsigned int *)(0x50000020))
#define URXH0 (*(unsigned int *)(0x50000024))
#define UTRSTAT0 (*(unsigned int *)(0x50000010)) void configGPH(void); void configULC(void); void configUC(void); void configUBR(void); void uart_init(void); void RTX0(void)
{
while ()
{
if (UTRSTAT0 & )
{
break;
}
}
UTXH0 = 'c';
int i;
for (i = ; i <= ; ++i)
{
;
}
} int main(void)
{
uart_init();
while ()
{
RTX0();
}
return ;
} void uart_init(void)
{
configGPH();
configULC();
configUC();
configUBR();
} void configGPH(void) //设置GPH2、3分别为TXD0,RXD0
{
unsigned int GPH23 = GPHCON;
GPH23 |= << ;
GPH23 |= << ;
GPH23 &= ~( << );
GPH23 &= ~( << );
GPHCON = GPH23;
} void configULC(void) //设置传输字长为8bit
{
unsigned int ULC = ULCON0;
ULC |= << ;
ULC |= ;
ULCON0 = ULC;
} void configUC(void) //设置接受与发送为polling模式
{
unsigned int UC = UCON0;
UC |= ( << );
UC |= ;
UC &= ~( << );
UC &= ~( << );
UCON0 = UC;
} /*
* 设置波特率 寄存器设置为(时钟频率50MHZ)/(波特率115200 * 16)-1 最后为26
*/
void configUBR(void)
{
unsigned int UBR = UBRDIV0;
UBR = ;
UBRDIV0 = UBR;
}
这个程序令开发板每隔一定时间通过串口打印一个“c”字符,功能简单但是每个步骤都要正确,特别是地址的设置以及位运算操作
之后我们要编写连接脚本来使汇编程序与C程序按照正常顺序生成组合之后的二进制文件
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x30001000; /*start address*/
. = ALIGN();
.text :
{
start.o(.text)
*(.text)
}
. = ALIGN();
.data :
{
*(data)
}
. = ALIGN();
.bss :
{
*(.bss)
}
}
这个脚本告诉连接器将start.s生成的start.o作为代码的开始,其中入口就是里面的_start标号,同时设置各部分起始地址
补充一点为什么选择程序的起始地址为0x30001000:我的mini2440的RAM是64MB,地址是从0x30000000-0x34000000,不过在高地址运行着superboot,所以选择大于0x30000000的附近地址段0x30001000,当然也可以选择0x30000000,但不能接近上限。
这样make之后,交叉编译、处理出了uart_main.bin文件,用方孔usb和usb转串口线连接mini2440与主机,同时打开超级终端接收串口打印信息,连接mini2440电源,使开发板从Nor Flash启动进入superboot,用配套的minitools工具将uart_main.bin文件写入开发板的目标地址并运行就可以了。
超级终端出现字符,说明程序运行成功:
程序最终顺利实现的关键是正确初始化C程序的运行环境,并且将寄存器地址逐一检查并确认无误,由于所涉及的寄存器在更复杂的程序中会更加繁多,所以对寄存器的准确操作尤为重要
C与ARM汇编结合实现mini2440串口uart简单程序的更多相关文章
- GNU ARM 汇编基础
ARM GNU汇编基础 0 前言 全文补充提醒: 笔者在阅读ARM官方文档及查阅实际的u-boot源码中的汇编代码后,发现了一些不同于ARM官方文档中的汇编语法,查阅相关资料后,才发现主要由于汇编器的 ...
- ARM汇编编程概述
1.为什么需要学些汇编指令 2.ARM汇编指令分类 3.汇编程序框架 4.编程准备 +++++++++++++++++++++++++++++++++++ 1.为什么需要学些汇编指令 bootload ...
- linux驱动系列之arm汇编
在arm平台学习linux时,会遇到arm汇编指令,arm汇编指令与8086汇编指令很多地方都不同,在此记下来以免后面忘了,同时在学习了汇编指令之后分析一些汇编指令编写的代码. 一.相对跳转指令b.b ...
- GNU ARM 汇编指令
第一部分 Linux下ARM汇编语法尽管在Linux下使用C或C++编写程序很方便,但汇编源程序用于系统最基本的初始化,如初始化堆栈指针.设置页表.操作 ARM的协处理器等.初始化完成后就可以跳转到C ...
- 生成ARM汇编
使用ndk即可生成arm汇编 1.首先写好hello.c 2.编写makefile #ndk根目录 NDK_ROOT=E:\Android\android-ndk-r10b #编译器根目录 TOOLC ...
- ARM汇编指令调试方法
学习ARM汇编时,少不了对ARM汇编指令的调试.作为支持多语言的调试器,gdb自然是较好的选择.调试器工作时,一般通过修改代码段的内容构造trap软中断指令,实现程序的暂停和程序执行状态的监控.为了在 ...
- ARM汇编
ARM汇编 ISA ISA即指指令集架构(Instruction Set Architecture)是与程序设计有关的计算机架构的一部分,包括本地数据类型.指令.寄存器.地址模式.内存架构.中断和意外 ...
- 3.1 ARM汇编编程概述
1. 汇编编程 为什么要学习汇编 1). Bootloader初始化 2). Linux kernel 3). 高效 2. ARM汇编分类 1. ARM标准汇编:ARM公司得汇编器适合在Windows ...
- arm汇编进入C函数分析,C函数压栈,出栈,传参,返回值
环境及代码介绍 环境和源码 由于有时候要透彻的理解C里面的一些细节问题,所有有必要看看汇编,首先这一切的开始就是从汇编代码进入C的main函数过程.这里不使用编译器自动生成的这部分汇编代码,因为编译器 ...
随机推荐
- NOIP2000提高组T1 进制转换
https://www.luogu.org/problem/P1017 题目描述 我们可以用这样的方式来表示一个十进制数: 将每个阿拉伯数字乘以一个以该数字所处位置的值减1为指数,以10为底数的幂之和 ...
- ionic3 修改页面切换动画
在app.module.ts中 配置pageTransition属性 [ BrowserModule, IonicModule.forRoot(MyApp, { pageTransition: 'io ...
- day14-单继承
#面向对象的三大特征:继承.多态.封装. #一.单继承: # 1. class Animal: #没有父类,默认继承了顶级父类object类. def __init__(self,name,aggr, ...
- linux 有了源码创建git版本库(coding)
进入目录,比如ewei_shop 执行 git init 瞬间Git就把仓库建好了,而且告诉你是一个空的仓库(empty Git repository),当前目录下多了一个.git的目录,如果没有看到 ...
- mysql查找json格式列的指定字段值
SELECT json_extract(字段名,'$.json结构') FROM 表名;如果json里有双引号,那这样取出来的数据也带双引号,要去掉就使用REPLACE函数 例如t_submit_an ...
- AndroidP推出多项AI功能,会不会引发新的隐私担忧?
让谷歌很"伤心"的是,相比苹果iOS系统的统一,Android系统的碎片化态势实在太严重了.就像已经发布一年多的Android O,其占有率仅有4.6%.主要是因为很多手机厂商都会 ...
- MySQL之数据存储引擎
1.什么是存储引擎: 现实生活中我们用来存储数据的文件有不同的类型,每种文件类型对应各自不同的处理机制:比如处 理文本用txt类型,处理表格用excel,处理图片用png等,数据库中的表也应该有不同的 ...
- cs231n spring 2017 lecture15 Efficient Methods and Hardware for Deep Learning
讲课嘉宾是Song Han,个人主页 Stanford:https://stanford.edu/~songhan/:MIT:https://mtlsites.mit.edu/songhan/. 1. ...
- Jacoco代码覆盖率工具
https://www.cnblogs.com/fnng/p/7923314.html https://my.oschina.net/wangmengjun/blog/974067
- Archlinux安装与出现的问题
arch的安装 arch的安装主要参考官网arch wiki,基本上按照Beginners' guide的步骤就可以安装,不过这里推荐用U盘刻录的方法来安装,我尝试过用硬盘安装的办法,还是感觉U盘刻录 ...