嵌入式ARM设计编程(四) ARM启动过程控制

这篇具有很好参考价值的文章主要介绍了嵌入式ARM设计编程(四) ARM启动过程控制。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

文章和代码已归档至【Github仓库:hardware-tutorial】,需要的朋友们自取。或者公众号【AIShareLab】回复 嵌入式 也可获取。

一、实验目的

(1) 掌握建立基本完整的ARM 工程,包含启动代码,C语言程序等;

(2) 了解ARM启动过程,学会编写简单的C 语言程序和汇编启动代码并进行调试;

(3) 掌握如何指定代码入口地址与入口点;

(4) 掌握通过memory/register/watch/variable 窗口分析判断结果。

二、实验环境

硬件:PC机。

软件:ADS1.2 集成开发环境

三、实验内容

使用汇编语言编写初始化程序,并引导至C语言main函数,用汇编语言编写延时函数实现毫秒级的延时,在C语言中调用延时函数,实现1s钟定时。

四、实验要求

(1) 在ADS下创建一个工程armasmc,编写3个文件,如下图所示:

arm程序执行过程,ARM,fpga开发,ARM,arm开发

其中一个初始化汇编语言文件Init.s,该文件中主要完成异常矢量表的建立,模式堆栈初始化,并将程序引导至C语言的main函数。

C语言程序保存为armasmc.c。 C语言中调用汇编语言文件delay.s中的毫秒延时程序delayxms,C语言将延时的毫秒数通过参数传递到汇编语言,汇编语言完成延时,然后返回C语言函数。

通过AXD运用单步执行方式调试程序。观察程序执行过程中的寄存器及存储器的变化情况。

(2)实验过程中请记录并思考以下内容:

1)如何建立异常矢量入口表?

2)如何在汇编语言中切换至C语言的main函数?。

3)如何在C语言中调用汇编语言函数,并完成参数传递?

4)汇编语言函数中用到的寄存器如何保护与恢复,为什么要保护参考程序中的R11?

5)将delay.s中的R11改成R4,并将两条R11 的保护与恢复语句stmfd sp!,{r11} 和ldmfd sp!,{r11}删掉,在C语言程序中的语句i–处设置端点,观察运行过程中变量i的变化情况,并解释其中的原因。

五、实验情况:

1、实验源代码(含注释):

Init.s代码:

;************************ entry.s ****************************
 IMPORT Main  ;在汇编程序调用该c程序前要在汇编语言程序中使用IMPORT伪操作来声明该c程序

  area Init,code,readonly   ;定义CODE片段Init 只读 
  entry     ;设置程序入口伪指令
  code32   ;以下为32位的ARM程序
; *********** Setup interrupt/exception vector *******************
start              b Reset_Handler        ;异常矢量表,根据异常矢量表进入不同模式的中断程序      
Undefined_Handler  b Undefined_Handler
SWI_Handler        b SWI_Handler
Prefetch_handler   b Prefetch_handler
Abort_Handler      b Abort_Handler
                   nop   ;Reserved vector
IRQ_Handler        b IRQ_Handler
FIQ_Handler        b FIQ_Handler

Reset_Handler     ;Reset中断,为整个中断的实际入口点        
             bl initstack    ;初始化各模式下的堆栈指针
                             
             ;切换至用户模式堆    
             msr cpsr_c,#0xd0    ;110  10000
                 
             bl Main

halt  b halt

initstack    mov r0,lr   ;r0<--lr,因为各种模式下r0是相同的而各个模式?                            
                                   
             ;设置管理模式堆栈
             msr cpsr_c,#0xd3    ;110  10011  
             ldr sp,stacksvc
               
             ;设置中断模式堆栈
             msr cpsr_c,#0xd2    ;110  10010
             ldr sp,stackirq  
             
             ;设置快速中断模式堆栈
             msr cpsr_c,#0xd1    ;110  10001
             ldr sp,stackfiq
                                
             ;设置中止模式堆栈      
             msr cpsr_c,#0xd7    ;110  10111
             ldr sp,stackabt
                                    
            ;设置未定义模式堆栈   
             msr cpsr_c,#0xdb    ;110  11011
             ldr sp,stackund
   
             ;设置系统模式堆栈    
             msr cpsr_c,#0xdf    ;110  11111
             ldr sp,stackusr
             
             mov pc,r0 ;返回
         
  LTORG      

stackusr     dcd  usrstackspace+128
stacksvc     dcd  svcstackspace+128
stackirq     dcd  irqstackspace+128
stackfiq     dcd  fiqstackspace+128
stackabt     dcd  abtstackspace+128
stackund     dcd  undstackspace+128

  area Interrupt,data,READWRITE  ;分配堆栈空间
usrstackspace space 128
svcstackspace space 128
irqstackspace space 128
fiqstackspace space 128
abtstackspace space 128
undstackspace space 128
     
       end

delay.s代码:

;************************* delay.s *****************************
  EXPORT delayxms ;EXPORT伪指令用于在程序中声明一个全局的标号,该标号可在其他的文件中引用
  area delay,code,readonly  ;定义code片段delay只读
  code32  ;以下为32位的ARM程序
  
;下面是延时若干ms的子程序      
delayxms
     stmfd sp!,{r11} ; 寄存器入栈
     sub r0,r0,#1 ;r0=r0-1
     ldr r11,=1000 ;加载至r11中
loop2
     sub r11,r11,#1 ;每次将r11自减一
     cmp r11,#0x0 ;将r11与0比较
     bne loop2  ;比较的结果不为0,则继续调用loop2  
     cmp r0,#0x0    ;将r0与0比较
     bne delayxms   ;比较的结果不为0,则继续调用delayxms
     ldmfd sp!,{r11};
     mov pc,lr;返回
     
     end

armasmc.c代码:

//*************************armasmc.c******************************
#include <stdio.h>
int Main()
{  
  extern void delayxms(int xms);  //在C程序调用汇编程序之前需要在C语言程序中使用extern关键词来声明该汇编程序
  
  int i=100;
  
  while(1)
  {
     delayxms(1000); // 调用delayxms汇编程序
     i--;
     if(i==0)
       i=100;
  }
  return 0;
}

2、实验过程(含结果截图及相应文字解释):

1.如何建立异常矢量入口表?

答:建立异常矢量入口表需要设置中断类型号,并且要设置中断服务子程序段地址,以根据异常矢量表进入不同模式的中断程序。在实验程序中也有定义:

arm程序执行过程,ARM,fpga开发,ARM,arm开发

2.如何在汇编语言中切换至C语言的main函数?

arm程序执行过程,ARM,fpga开发,ARM,arm开发

答:由上代码可知,为保证程序调用时参数的正确传递,汇编程序设计要遵守ATPCS(ARM-Thumb Produce Call Standard),它是ARM程序和Thumb程序中子程序调用的基本规则,目的是为了使单独编译的C语言程序和汇编程序之间能够相互调用。这些基本规则包括子程序调用过程中寄存器的使用规则、数据栈的使用规则和参数的传递规则。在C程序中不需要任何关键字来声明将被汇编语言调用的C程序,但需要在汇编语言程序之前使用IMPORT伪操作来声明该C程序。在汇编程序中通过BL指令来调用子程序。同时,汇编程序可以通过地址间接访问在C语言程序中声明的全局变量。通过使用IMPORT关键词引入全局变量,并利用LDR和STR指令根据全局变量的地址可以访问它们。

3.如何在C语言中调用汇编语言函数,并完成参数传递?

arm程序执行过程,ARM,fpga开发,ARM,arm开发

arm程序执行过程,ARM,fpga开发,ARM,arm开发

答:为了保证程序调用时参数的正确传递,汇编程序设计要遵守ATPCS。在汇编程序中需要使用EXPORT伪操作来声明,同时,在C程序中调用该汇编程序之前需要在C语言程序中使用extern关键词来声明该汇编程序。

4.汇编语言函数中用到的寄存器如何保护与恢复,为什么要保护参考程序中的R11?

答:汇编语言函数中用到的寄存器通过压栈来保护,出栈来恢复。根据ATPCS规则,R11对应ARM 状态局部变量寄存器8,R11中含有循环次数的重要参量,因此要保护R11避免在程序运行与调用过程中受到影响而导致程序异常。

5.将delay.s中的R11改成R4,并将两条R11 的保护与恢复语句stmfd sp!,{r11} 和ldmfd sp!,{r11}删掉,在C语言程序中的语句i–处设置端点,观察运行过程中变量i的变化情况,并解释其中的原因。

修改程序如下:

arm程序执行过程,ARM,fpga开发,ARM,arm开发

答:由上可知R4对应局部变量寄存器1,即变量i,因此在子程序delay.s中,R4的值减为0,若不进行保护,则返回C程序后自减-1,导致变量i的值变为-1,此时将无法满足0的条件,也就无法执行if,导致i会一直递减下去,最终无法停止。

六、总结

本次有关汇编与C语言相互调用的部分,建立异常矢量入口表的方法,即需要设置中断类型号,并且要设置中断服务子程序段地址,以根据异常矢量表进入不同模式的中断程序。此外,还有ARM程序和Thumb程序中子程序调用的基本规则ATPCS(ARM-Thumb Produce Call Standard),目的是为了使单独编译的C语言程序和汇编程序之间能够相互调用。这些基本规则包括子程序调用过程中寄存器的使用规则、数据栈的使用规则和参数的传递规则,为调用提供了相关的规范。其中汇编程序访问全局C变量的方法是:汇编程序可以通过地址间接访问在C语言程序中声明的全局变量。通过使用IMPORT关键词引入全局变量,并利用LDR和STR指令根据全局变量的地址可以访问它们。在C语言程序中调用汇编程序的方法是:在汇编程序中需要使用EXPORT伪操作来声明,使得本程序可以被其它程序调用。同时,在C程序调用该汇编程序之前需要在C语言程序中使用extern关键词来声明该汇编程序。而在汇编程序中调用C语言程序的方法是:在C程序中不需要使用任何关键字来声明将被汇编语言调用的C程序,但是在汇编程序调用该C程序之前需要在汇编语言程序中使用IMPORT伪操作来声明该C程序。在汇编程序中通过BL指令来调用子程序。文章来源地址https://www.toymoban.com/news/detail-735171.html

到了这里,关于嵌入式ARM设计编程(四) ARM启动过程控制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [ARM 汇编]高级部分—ARM汇编编程实战—3.3.2 嵌入式开发环境搭建

    搭建一个嵌入式开发环境主要包括以下几个部分: 安装交叉编译器 配置集成开发环境(IDE) 安装调试工具 下载和烧录程序 接下来,我们将详细介绍每个部分,并提供相应的实例。 安装交叉编译器 交叉编译器是用于将您编写的ARM汇编代码编译成可执行文件的工具。在本教程

    2024年02月11日
    浏览(54)
  • 【文末送书】Linux/Windows/嵌入式系统的启动过程

    欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。关注公粽号 《机器和智能》 回复 “python项目

    2024年02月20日
    浏览(51)
  • [ARM 汇编]高级部分—ARM汇编编程实战—3.3.1 嵌入式系统的基本概念

    嵌入式系统是一种特殊的计算机系统,通常用于执行特定的任务。它通常包含一个或多个微处理器、存储器和外围设备。与通用计算机系统相比,嵌入式系统具有体积小、功耗低、成本低和实时性强等特点。在这一部分,我们将介绍嵌入式系统的基本概念,并通过实例来展示

    2024年02月11日
    浏览(48)
  • 嵌入式学习笔记(1)ARM的编程模式和7种工作模式

        ARM态-ARM指令集(32-bit)     Thumb态-Thumb指令集(16-bit)     Thumb2态-Thumb2指令集(16 32 bit) Thumb指令集是对ARM指令集的一个子集重新编码得到的,指令长度为16位。通常在处理器执行ARM程式时,称处理器处于ARM状态;当处理器执行Thumb程式时,称处理器处于Thumb状态。

    2024年02月10日
    浏览(48)
  • ARM简单程序设计【嵌入式系统】

    2023-4-6 20:26:54 以下内容源自《【嵌入式系统】》 仅供学习交流使用 Keil 4 安装教程及简单使用【嵌入式系统】 新建工程xxx 芯片:ARM7 (Little Endian) 设置工程属性 Build结果必须是0Error的 如果是下图看配置是否正确 注意这个: 1.每一次修改代码就需要重写Build 2.READWRITE区变量初始

    2023年04月20日
    浏览(69)
  • ARM嵌入式编程优化之在C/C++中栈的使用

    栈在C/C++中使用得非常频繁,比如,栈中可以保存: 在调用函数时,保存函数的返回地址。 保存一些寄存器的值,这取决于ARM 架构:the Procedure Call Standard for the Arm Architecture (AAPCS) or the Procedure Call Standard for the Arm 64-bit Architecture (AAPCS64),比如在进入子程序时,将一些寄存器里

    2024年02月06日
    浏览(51)
  • 嵌入式:ARM汇编语言程序设计基础教程

    ① 合理地分配存储器资源,将前述的目标系统‘数据结构模型’表示到各存储器单元。 ② CPU寄存器数量有限,在程序中,大多数操作都要使用寄存器;并且有的操作使用特定的寄存器(如堆栈操作使用SP/R13等),程序中要合理分配各寄存器的用途。 用计算机语言,对数据结

    2023年04月23日
    浏览(88)
  • C++嵌入式编程:硬件控制与物联网

    C++是一种功能强大的编程语言,被广泛应用于嵌入式系统的开发和物联网(IoT)应用程序的编写。C++具有高性能、灵活性以及强大的硬件控制能力,使其成为嵌入式编程和物联网开发的理想选择。在本文中,我们将讨论C++在硬件控制和物联网应用中的重要性、应用领域以及一

    2024年01月16日
    浏览(60)
  • BL302嵌入式ARM控制器进行SQLite3数据库操作的实例演示

    本文主要讲述了在钡铼技术BL302嵌入式arm控制器上运行 SQLite3 数据库的命令示例。SQLite3 是一个轻型的嵌入式数据库,不需要安装数据库服务器进程,占用资源低且处理速度快。 首先,需要将对应版本的 SQLite3 文件复制到设备的 /usr/ 目录下,并解压缩。然后进入 /usr/lib 目录,

    2024年02月14日
    浏览(48)
  • 嵌入式培训机构四个月实训课程笔记(完整版)-Linux ARM驱动编程第五天-ARM Linux编程之设备节点 (物联技术666)

    链接:https://pan.baidu.com/s/1hOBKyRom-4EZMBpFn1H9kQ?pwd=1688 提取码:1688  Linux设备节点 设备管理是linux中比较基础的东西,但是由于Linux智能程度的越来越高,Udev的使用越来越广泛,使得越来越多的Linux新用户对 /dev 目录下的东西变得不再熟悉。有时候遇见问题就会变得抓狂 本文是我

    2024年02月22日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包