SAM4E单片机之旅——23、在AS6(GCC)中使用FPU

时间:2022-08-26 20:36:18

浮点单元(Floating Point Unit,FPU),是用于处理浮点数运算的单元。

为使用FPU,除了需要启用FPU外,还需要对编译器进行设置,以使其针对浮点运算生成特殊的指令。虽然在Atmel Studio 6中,开发板使用的工程模板中默认就完成了这两部分工作,但这次仍然对设置的方法进行介绍,同时简单测试一下FPU的效率。

一、 编译器设置

AS6.1 SP2中,使用的编译器为arm-none-eabi-gcc.exe,版本为4.7.3。其中“none”表示没有指定操作系统,“eabi”表示使用的二进制文件接口是eabi。

  1. 在ARM GCC中,可以使用-mfloat-abi选项设置浮点数的ABI:

    • soft: 调用软浮点库对浮点运算进行支持。在GCC中采用常用的指令来模拟浮点运算。

    • softfp: 使用FPU进行浮点数运算。但是在函数调用时,仍然使用通用的寄存器传递浮点数参数。这需要额外的类型转换的开销。

    • hard: 使用FPU进行浮点数运算。而且在函数调用时,使用FPU的寄存器传递浮点数参数。

    AS6.1使用的编译器,默认情况下即使用soft选项。而为了使用FPU,这里将使用softfp选项。

  2. 使用-mfpu选项设置FPU硬件的类型。

    SAM4E搭载了Cortex-M4F FPU,它实现了FPv4-SP版本(SP表示单精度)的浮点数扩展。另外,它也搭载了32个32位的单精度寄存器,而这些寄存器也可以被当作16个64位的双精度寄存器以进行load,store和move操作。

    所以需要将-mfpu赋值为fpv4-sp-d16。其中d16表示有16个64位寄存器。

  3. AS6中的设置。

    在解决方案管理器中,右键点击工程,进入属性页面。然后选中“Toolchain”选项卡,再选择“ARM/GUN C Complier”下的“Miscellaneous”选项,就可以看到自定义的编译器的选项了。

    可以看到,默认情况下已经追加了“-mfloat-abi=softfp -mfpu=vfpv4”的选项了。vfpv4默认表示vfpv4-D32,表示实现了完全的FPV4的版本,且配有32个64位寄存器。很明显,这是一个不怎么正确的设置,所以需要更改-mfloat-abi=softfp -mfpu= fpv4-sp-d16

    SAM4E单片机之旅——23、在AS6(GCC)中使用FPU

    注意,Release版本的配置中也需要进行修改

二、 启用FPU

开发板重置时,FPU是禁止访问的。但是AS6中使用的startup文件会根据编译器设置启用FPU。

  1. 启用FPU的方法

    向FPU的CPACR寄存器的CP10和CP11字段写入0b11即可开放FPU的完全访问权限。另外,在特权模式下才能读写该寄存器。

    在CMSIS中该寄存器的地址被定义成了保留地址。但是在fpu.h 中提供了相应的API:

    #include <fpu.h> // 会和sam.h的宏定义冲突,使用board.h即可
    fpu_enable();

    fpu_enable() 的实现如下:

    /** CPACR寄存器 */
    #define ADDR_CPACR 0xE000ED88
    #define REG_CPACR (*((volatile uint32_t *)ADDR_CPACR)) /** 保存CPU当前中断的状态,并屏蔽之 */
    irqflags_t flags;
    flags = cpu_irq_save(); /** 修改CPACR寄存器*/
    REG_CPACR |= (0xFu << 20); __DSB(); /** 等待寄存器修改完成*/
    __ISB(); /** 清空处理器流水线 */ /** 根据设置决定是否重新启用中断 */
    cpu_irq_restore(flags);
  2. AS6中已经完成的工作

    开发板使用的AS6的工程模板中,程序的入口函数是Reset_Handler()

    • 该函数在调用main() 函数之前,会执行以下代码:

      #if __FPU_USED
      fpu_enable();
      #endif
    • __FPU_USED在以下代码中定义:

      //...
      /* 判断使用的编译器是否为GCC */
      #elif defined ( __GNUC__ )
      /* 判断是否启用浮点运算,且运算不是用软件实现的 */
      #if defined (__VFP_FP__) && !defined(__SOFTFP__)
      /* 判断目标平台是否有FPU */
      #if (__FPU_PRESENT == 1)
      #define __FPU_USED 1
      #else
      //...
    • __FPU_PRESENT sam4e16e.h 中定义:

      /**< SAM4E16E does provide a FPU */
      #define __FPU_PRESENT 1

    所以,只需要设置好了编译器的参数,就可以自动启用FPU了。

    PS:__GNUC__ 在GCC编译器预定义的宏,__VFP_FP__ 在GCC启用浮点运算时预定义,__SOFTFP__ 是使用软模拟浮点运算时预定义。GCC可以使用“-dM –E”参数打印出预定义的宏。

三、 测试

在第一次示例教程中,我们使用了空循环来进行延时,来完成LED的闪烁工作。在这里,我们将这个空循环的循环体修改为对一个浮点数的运算。然后观察在是否使用硬件FPU时,LED闪烁的频率的差别。

将延时函数修改如下:

void Delay(int num)
{
volatile float f = 1.0f;
for (volatile int i = 0; i < 1024 * 64 * num; ++i )
f *= 1.1f;
}

然后分别使用“-mfloat-abi=softfp ”和“-mfloat-abi=soft ”选项编译并执行程序,观察LED闪烁的频率。

SAM4E单片机之旅——23、在AS6(GCC)中使用FPU的更多相关文章

  1. SAM4E单片机之旅——24、使用DSP库求向量数量积

    DSP(Digital Signal Processing,数字信号处理)中会使用大量的数学运算.Cortex-M4中,配置了一些强大的部件,以提高DSP能力.同时CMSIS提供了一个DSP库,提供了 ...

  2. SAM4E单片机之旅——3、LED闪烁之定时器中断

    让一个LED灯闪烁不过瘾,我们应该让这块开发板完成一点更高难度的任务:比如让两个LED灯闪烁. …… 当然了,以我们的现在使用的空循环技术,还是可以实现这点的.但是这样显得略为低端.所以我们使用一个高 ...

  3. SAM4E单片机之旅——1、LED闪烁之空循环

    最近因为导师要写一本关于SAME4单片机的书籍,而我也作为一个嵌入式的初学者看了这本书.现在也让我写写几个小的程序,做做示例.既然写了文档之类的,就发到博客上来吧. 目前关于这芯片能参考的书籍大概就只 ...

  4. SAM4E单片机之旅——18、通过AFEC&lpar;ADC&rpar;获取输入的电压

    很多时候,一个电压不仅仅需要定性(高电平或者低电平),而且要定量(了解具体电压的数值).这个时候就可以用到模数转换器(ADC)了.这次的内容是测量开发板搭载的滑动变阻器(VR1)的电压,然后把ADC转 ...

  5. SAM4E单片机之旅——17、通过UART进行标准IO

    交互还是很有必要的,而且使用键盘和显示器的交互效率还是很高的.当然,可以直接使用UART进行字符的输入和输出.但是又何必浪费了C的标准输入输出的格式控制之类的功能呢? 这次内容就是使用scanf() ...

  6. SAM4E单片机之旅——13、LCD之ASF初步

    在Atmel Studio 6中,集成了Atmel Software Framework(ASF框架).通过它提供的库,可以很快速地完成新的项目. 这次的最终目标使用ASF在LCD上显示出文字“Hel ...

  7. SAM4E单片机之旅——2、LED闪烁之轮询定时器

    之前我们使用空循环,达到了延迟的目的,但是这样子的延迟比较不精确.现在就使用实时定时器(RTT)来进行更为精确的计时.RTT虽然不是特别通用,在某些单片机上可能没有,但它较为简单. RTT内部有一个计 ...

  8. SAM4E单片机之旅——22、GMAC和PHY的介绍与初始化

    网络通信的作用不用多说,而这次进行的工作即是对以太网通信过程中,需要用到的硬件部分进行初始化,也介绍了发送和接收数据的方法. 由于较为复杂,所以使用了ASF框架.但是也会对用到的库函数的实现做一个介绍 ...

  9. SAM4E单片机之旅——21、DMAC之USART回显

    DMAC也可以和外设进行数据交互.之前我们曾使用PDC进行USART的数据回显,这次就使用DMAC完成相同的工作.而且由于DMAC有内部的缓冲区,实现起来更为简单. 一. USART设置 因为之前已经 ...

随机推荐

  1. js获取给定月份的N个月后的日期

    1.在讲js获取给定月份的N个月后的日期之前,小颖先给大家讲下getFullYear().getYear()的区别. ①getYear() var d = new Date() console.log ...

  2. AJAX初探&comma;XMLHttpRequest介绍

    AJAX初探,XMLHttpRequest介绍 AJAX      AJAX = Asynchronous JavaScript and XML. 异步的JavaScript和XML.      AJ ...

  3. &period;net core 基本概念

    asp.net core 是基于 .net core的,所以能够跨平台. 目前存在.NET Framework (CLR), .NET Core (CoreCLR) or Mono,可根据项目的具体情 ...

  4. Scala的模式匹配

    1.概述 2.程序示例(普通的示例) 3.模式匹配(Array) 4.程序示例(Array) 5.模式匹配(List) 6.程序示例 7.遍历 8.模式匹配(case class) 9.程序示例(传统 ...

  5. H5调用Android播放视频

    webView.loadUrl("http://10.0.2.2:8080/assets/RealNetJSCallJavaActivity.htm"); js调用的Java文件中 ...

  6. 分布式Java应用与实践 &lpar;一&rpar;

    一) 分布式Java应用 1.1 基于消息方式实现系统间的通信 数据传输 TCP/IP 可靠的网络传输协议,首先给通信双方建立链接之后再进行数据传输,保证链接及数据传输的可靠,因此会牺牲一些性能 UD ...

  7. Go语言极速入门手册&period;go

    Github: https://github.com/coderzh/CodeTips /* gotips_test.go: Golang速学速查速用代码手册 Source: github.com/c ...

  8. 使用MXNet的NDArray来处理数据

    NDArray.ipynb NDArray介绍 机器学习处理的对象是数据,数据一般是由外部传感器(sensors)采集,经过数字化后存储在计算机中,可能是文本.声音,图片.视频等不同形式. 这些数字化 ...

  9. HTML5 Canvas &lpar; 贝塞尔曲线&comma; 一片星空加绿地 &rpar; quadraticCurveTo&comma; bezierCurveTo

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. Java多线程编程之不可变对象模式

           在多线程环境中,为了保证共享数据的一致性,往往需要对共享数据的使用进行加锁,但是加锁操作本身就会带来一定的开销,这里可以使用将共享数据使用不可变对象进行封装,从而避免加锁操作. 1. 模 ...