arm-linux-gcc裸机程序开发(三)

发布者:daasddla最新更新时间:2022-10-12 来源: csdn关键字:arm-linux-gcc  裸机程序  开发 手机看文章 扫描二维码
随时随地手机看文章

一. 中断问题

       中断对编写程序非常的重要,所以程序对中断处理的好坏将直接影响程序的优劣,对实时性要求较高的系统更是如此。对于ADS2.0,在编写中断处理程序的时候,只需要在程序前面加上"_irq"这个关键字,ADS就会自动为我们保存中断现场,等程序返回的时候自动恢复现场,细节无须我们关心。当然,也可以不加这个关键字,如果这样就得自己保存与恢复中断现场,考虑的问题就多了。arm-linux-gcc开发环境下,目前我还没有发现类似“_irq”这样的关键字可以通知编译器自动处理中断过程。因此,如果使用arm-linux-gcc编译带有中断的程序,就必须自己处理中断现场。除了保护中断现场外,程序还需要做的就是设置正确的中断向量表,使得每个中断发生时都能找到合适的跳转地址。这里我主要参考了2440init.S中的方法。有如下几步:

(1)首先定义宏

.macro Handler Addr

sub     sp, sp, #4      

stmfd   sp!, {r0}    

ldr     r0, =Addr    

ldr     r0, [r0]          

str     r0, [sp,#4]    

ldmfd   sp!, {r0,pc}    

.endm

    这个宏的名称是Handler,作用是取地址Addr处存放的值,赋值给PC。


(2)宏展开

HandlerUndef:

Handler HandleUndef

HandlerSWI:

Handler HandleSWI

HandlerPabort:

Handler HandlePabort

HandlerDabort:

Handler HandleDabort

HandlerIRQ:

Handler HandleIRQ

HandlerFIQ:

Handler HandleFIQ

    这样一来,发生中断后,PC就会跳转到HandleIRQ存放的地址处执行(假设是普通中断)


(3)在HandlerIRQ处有这样的代码

HandleIRQ:

.word IsrIRQ

    HandleIRQ处存放的地址是IsrIRQ,所以发生中断后,PC跳转到IsrIRQ处执行


(4) IsrIRQ 是interrupt.S中的标号

.globl IsrIRQ

IsrIRQ:

        @ Fix the return address

sub lr,lr,#4

        stmfd sp!,{r0-r3,r12,lr}  

#define rINTOFFSET 0x4a000014

LDR     R0, =rINTOFFSET

        LDR     R0, [R0]

       

        LDR     R1, =HandleEINT0

        MOV     LR, PC                          @ Save LR befor jump to the C function we need return back

        LDR     PC, [R1, R0, LSL #2]               

    

ldmfd sp!,{r0-r3,r12,pc}^


这段程序就是中断处理的核心代码:保存中断现场,然后跳转到相应的中断服务程序中,返回后恢复中断现场。这是一种最简单的中断处理方式。程序的开始修正了程序返回地址,我们知道由于流水线的问题,arm体系结构中pc不是指向正在执行的指令,而是指向正在取址的指令,因为中断而保存在lLR寄存器中的就是正在执行的指令的后两个指令,比如正在执行第n条指令,而cpu为我们保存的是第n+2条指令,中断返回后我们要执行第n+1条指令。一个指令四个字节,所以这里LR减4正好是程序应该返回的地址。把这个地址压入栈才是正确的。修正完返回地址,就可以保存寄存器了。这里保存的寄存器有r0-r3,r12,还有返回地址LR。这些寄存器的保存我是参考一些书上介绍的,这样保存事实上也可以正常工作。但是我一直有一个疑问:在arm不同的模式下共用的寄存器不止r0-r3,r0-r7都是各个模式共用的寄存器。那么为什么就保存r0-r3就可以了呢。保存完现场,然后通过rINTOFFSET寄存器找到究竟发生了哪个中断。rINTOFFSET是中断控制器的寄存器,发生中断后,这里记录了具体中断的偏移。所有的中断都是有号码的,我们可以利用这个号码来实现中断服务程序的跳转。这里读出中断号,左移2位也就是乘以4,加上HandleEINT0的值,最后将这个地址处存放的值赋值个pc,从而完成了中断的跳转。


rINTOFFSET 是start.S中的标号,在start.S的最后有这么一段代码:

.equ ISR_BADDR, 0x33ffff00        


HandleReset:

  .word (ISR_BADDR+4*0)

HandleUndef:

.word (ISR_BADDR+4*1)

HandleSWI:

.word (ISR_BADDR+4*2)

HandlePabort:

.word (ISR_BADDR+4*3)

HandleDabort:

.word (ISR_BADDR+4*4)

HandleReserved:

.word (ISR_BADDR+4*5)

HandleIRQ:

.word IsrIRQ

HandleFIQ:

.word (ISR_BADDR+4*7)



.globl HandleEINT0 

.equ HandleEINT0, (ISR_BADDR+4*8)

.equ HandleEINT1, (ISR_BADDR+4*9)

.equ HandleEINT2, (ISR_BADDR+4*10)

.equ HandleEINT3, (ISR_BADDR+4*11)

       ........


HandleEINT0等于ISR_BADDR+4*8,也就是0x33ffff00+4×8,这个地址处就是0号中断(也就是外部中断0)服务程序入口地址。其他中断入口地址都是在此基础上加上相应的偏移值。在应用程序中我们只需要将相应的中断服务程序入口地址保存在这里,发生中断的时候就会实现正确跳转。


在2440addr.h中,定义了一些宏,方便我们赋值。比如

#define _ISR_STARTADDRESS 0x33ffff0



#define pISR_EINT0 (*(unsigned *)(_ISR_STARTADDRESS+0x20))

#define pISR_EINT1 (*(unsigned *)(_ISR_STARTADDRESS+0x24))

#define pISR_EINT2 (*(unsigned *)(_ISR_STARTADDRESS+0x28))

#define pISR_EINT3 (*(unsigned *)(_ISR_STARTADDRESS+0x2c))

#define pISR_EINT4_7         (*(unsigned *)(_ISR_STARTADDRESS+0x30))


注意_ISR_STARTADDRESS 与 ISR_BADDR是相同的,这就保证了跳转的一致性。假如我们中断服务程序为irq_int0,在应用程序中我们只需要一条赋值语句就实现了中断程序的装载

pISR_EINT0 = irq_int0


以上的中断处理,在Nandflash启动下是正常工作的,但是在Norflash启动的情况下,用supervivi的D功能下载程序到内存中运行,程序是不能正确响应中断的,在串口终端输出奇怪的信息。原因是当中断发生时,cpu默认去0x00地址处取得中断向量表,而我们的程序的中断向量表在0x30000000处,地址0x00是norfalsh的地址空间,而这里存放的是supervivi的代码,所以发生找不到中断向量的错误。但是在Nandflash启动的情况下,cpu自动将我们代码前4k拷贝到SRAM里,当然也包括中断向量表。在这种情况下,0x00处是SRAM地址空间,正确存放着中断向量。


对于下载到内存中运行这种情况,为了实现正确的中断跳转。解决的办法有两种:第一种是将内存中的中断向量表拷贝到0x00处,但是这种方法是不可行的。原因一:麻烦,我们知道在norflash启动下,0x00是norflash的地址空间,虽然norflash读时序很简单,只需要普通的赋值就可以了。但是写时序很复杂,需要复杂的时序操作。这样一来就需要额外的代码。原因二:有副作用,在norflash里我们存放了supervivi,如果重写norflash就会破坏supervivi,导致下一次norflash不能正确启动。所以这种方法不可取,另一种方法就是通过mmu重映射的方式,将物理地址0x30000000开始处的一小段代码,映射到0x00处,cpu取地址取的是虚拟地址,所以当中断发生的时候,cpu照常到0x00出取中断向量,但是却是取到0x30000000的内容,而这里就是正确的中断向量。我就是用这种方式实现的内存中中断正常跳转的。


验证代码在我的资源里: http://download.csdn.net/detail/yaozhenguo2006/3845811


程序验证的是按键中断,每按下一个按键,串口终端都会提示按下的按键号


二. 完整工程验证

至此arm-linux-gcc编译裸机程序的所有问题都解决了,但是真正能否用于工程还是个未知数。所以得找一个完整的工程验证一下。因为在ADS下我曾经移植过ucosii,如果将ucosii编译通过,并且能够正确运行,那么就表明方法确实可以用。所以我进行了ucosii的移植,有了上面的基础,移植就简单多了,无非就是将arm汇编转换成gnu汇编,c代码基本上不用动,最后编写合适的makefile就可以了。


编译完成的代码在我的资源里: http://download.csdn.net/detail/yaozhenguo2006/3845817


将ucosii_mini2440.bin下载到mini2440中运行,会看到串口终端交替输出hello world 和my friend,同时led灯在闪烁。这说明程序能正确运行,两个任务互不影响的运行。如果要重新编译只需要根据自己系统的情况将链接选项修改一下就可以了。


关键字:arm-linux-gcc  裸机程序  开发 引用地址:arm-linux-gcc裸机程序开发(三)

上一篇:mini2440开发板FTP上传文件的问题
下一篇:arm-linux-gcc 裸机程序开发(二)

推荐阅读最新更新时间:2024-11-12 21:21

如何在TI SimpleLink CC1352P上快速开发AI原型?
德州仪器(TI)的CC1352P器件是一款多协议低于1GHz和2.4GHz无线MCU,面向无线M-Bus、IEEE802.15.4g、支持IPv6的智能对象(6LoWPAN)、Thread、Zigbee®、KNXRF、Wi-SUN®、低功耗Bluetooth®5以及专有系统,包括TI15.4-Stack。该器件包含具有一流效率的+20dBm集成高功率放大器,适用于远距离应用。 CC1352P器件是具有成本效益、超低功耗、2.4GHz和低于1GHz射频器件SimpleLink MCU平台中的一员。非常低的有源射频和微控制器(MCU)电流以及低于1μA的睡眠电流和高达80KB并受奇偶校验保护的RAM保持能力可提供卓越的电池寿命,并
[嵌入式]
如何在TI SimpleLink CC1352P上快速<font color='red'>开发</font>AI原型?
基于氧化锌原料的光发电技术开发
前言 现在HEMS、BEMS※1能源管理系统正在开发当中。这是一种建筑物中用来管理使用器械、设备运转的系统,其目的是为了减少建筑物中的能源消耗。目前,HEMS/BEMS主要致力于将能源消耗量可视化,今后将会结合传感器网络,用来检测室内人体活动,门窗打开或关闭等状态,在必要的场合使用能源,而不必要的场合能自动节约能源,实现舒适和节能的目标。 在传感器网络的实际使用中,电源是挑战课题之一。通过用来减少能耗的传感器节点达到节能的效果,为了更舒适的生活,我们从未放弃对节点自由安装的研究。村田制作所考虑到环境发电技术不适用于这种传感器节点的电源中,利用压电效应的振动发电、将温度差转换成电能的热电转换元件,还有本章介绍的光发电技术的多种
[嵌入式]
谷歌母公司终止旗下机器人公司Schaft开发计划
据外媒报道,Google母公司Alphabet最近终止了人型机器人开发公司Schaft的研发计划,Alphabet向外媒证实并表示,目前正在协助Schaft的员工找到新角色和外部的工作。不过,目前具体终止研发计划的原因还不确定。 Schaft成立于2012年,由东京大学教授Yuto Nakanishi带领团队,专注于开发工业用及任务型的人型双脚机器人。去年6月,日本软银计划买下Alphabet手中两家机器人公司Boston Dynamics与Schaft,但疑似合约有些问题并没有完成交易。因此,Schaft还是Alphabet旗下公司。 而Alphabet旗下另一家Boston Dynamics主要的产品为机器狗,该大型机器狗的设
[机器人]
卡巴斯基实验室与AVL合作 开发安全的自动驾驶控制器
据外媒报道,日前,卡巴斯基实验室(Kaspersky)宣布首次成功将其新的汽车KasperskyOS集成到由AVL Software and Functions 开发的ADAS电子控制单元(ECU)中。 (图片来源:www.newmobility.global) 该控制器是一个开放的和可定制的开发平台,用于原型和系列产品开发,并且运行在KasperskyOS上,具有安全的设计。在此应用中,安全操作系统旨在保护ADAS组件之间的通信,并保护自动驾驶汽车的所有功能。作为安全特性的一部分,KasperskyOS保证无论是在发布时未被注意到的,还是通过系统更新插入的未申明功能,都不会被利用,也不会影响自动驾驶汽车的性能。 汽
[汽车电子]
卡巴斯基实验室与AVL合作 <font color='red'>开发</font>安全的自动驾驶控制器
Mini2440裸机开发之keil开发环境的搭建
Mini2440裸机开发之keil开发环境的搭建 之前搞过一段时间的STM32,也搞过uboot和Linux驱动,但是感觉这些搞得都不系统,不成体系,感觉学的东西很杂,而且没有纪录,所以决定从今天起把写博客这件事给坚持下去 硬件环境:jlink,mini2440开发板 软件环境下载: 首先需要到keil官网下载MDK(因为对keil的版本认识一直很模糊,有明白的小伙伴还请赐教)。 之前曾经开发过STM32,所以,我的电脑上是有keil的,但是在建工程选择器件的时候却没有s3c2440,如下图1,然后到keil的官网查看,找到MDK-Arm的下载目录,keil是支持cotex内核和arm内核的,继续找发现有支持Arm
[单片机]
Mini2440<font color='red'>裸机</font><font color='red'>开发</font>之keil<font color='red'>开发</font>环境的搭建
STM32WB55开发(6)----FUS更新
概述 在 STM32WB 微控制器中,FUS(Firmware Upgrade Services)是用于固件升级的一种服务。这项服务可以让你更新设备上的无线栈固件(如蓝牙、Zigbee或 Thread 栈),以及无线 MCU (microcontroller unit) 的系统服务。 FUS 实质上是设备的一部分固件,它可以独立于主应用程序运行,主要负责安全地处理设备固件的升级。这包括检查新固件的有效性,确保新固件被正确地写入设备,以及在出现问题时回滚到旧版本的固件。 总的来说,FUS 是 STM32WB 和其他 STM32 无线微控制器中一个非常重要的组件,可以确保设备固件的安全更新。 最近在弄ST和瑞萨RA的课程,需要样片的可
[单片机]
STM32WB55<font color='red'>开发</font>(6)----FUS更新
STM32开发 -- 低功耗模式详解(1)
很多单片机都有低功耗模式,STM32 也不例外。当 CPU 不需继续运行时,可以利用多个低功耗模式来节省功耗。 这部分不是我负责,但是也是有必要看一下的。 参看: STM32F1开发指南-库函数版本_V3.2.pdf STM32中文参考手册_V10.pdf 一、低功耗模式 在系统或电源复位以后,微控制器处于运行状态。当CPU不需继续运行时,可以利用多种低功耗模式来节省功耗,例如等待某个外部事件时。用户需要根据最低电源消耗、最快速启动时间和可用的唤醒源等条件,选定一个最佳的低功耗模式。 STM32有三种低功耗模式: ● 睡眠模式(Cortex™-M3内核停止,所有外设包括Cortex-M3核心的外设,如NVIC、系统时钟
[单片机]
STM32<font color='red'>开发</font> -- 低功耗模式详解(1)
Beken博通集成推麻雀一号:Wi-Fi音视频SoC软硬件开发
日前,Beken博通集成资深软件工程师王凡在B站直播麻雀一号开发板开发指南,2个小时的直播中互动频繁,在线活跃,参与人数一度达5000人,反映业界对智能音视频开发平台的高度关注。 麻雀一号是性价比超高的集成音视频的Wi-Fi开发板平台,内置RT_Thread操作系统,主打Wi-Fi音频、摄像头和拍照功能,配合丰富的组件及例程,降低了多媒体应用的开发门槛。 麻雀一号的其主要技术特点包括 • 采用双层板设计,布局合理; • BK7252 SOC ,主频180MHz; • 搭载PSRAM、TF卡座、五项按键,丰富的外设; • 支持音频/ Wi-Fi/BLE,自带喇叭和麦克风; • 摄像头分辨率:640*480(最大600*800
[手机便携]
Beken博通集成推麻雀一号:Wi-Fi音视频SoC软硬件<font color='red'>开发</font>板
小广播
设计资源 培训 开发板 精华推荐

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

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

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved