浮点单元(Floating Point Unit,FPU),是用于处理浮点数运算的单元。
为运用FPU,除了需求启用FPU外,还需求对编译器进行设置,以使其针对浮点运算生成特别的指令。虽然在Atmel Studio 6中,开发板运用的工程模板中默许就完结了这两部分作业,但这次依然对设置的办法进行介绍,一起简略测验一下FPU的功率。
一、 编译器设置
AS6.1 SP2中,运用的编译器为arm-none-eabi-gcc.exe,版别为4.7.3。其间“none”表明没有指定操作系统,“eabi”表明运用的二进制文件接口是eabi。
在ARM GCC中,能够运用-mfloat-abi选项设置浮点数的ABI:
soft: 调用软浮点库对浮点运算进行支撑。在GCC中选用常用的指令来模仿浮点运算。
softfp: 运用FPU进行浮点数运算。可是在函数调用时,依然运用通用的寄存器传递浮点数参数。这需求额定的类型转化的开支。
hard: 运用FPU进行浮点数运算。并且在函数调用时,运用FPU的寄存器传递浮点数参数。
AS6.1运用的编译器,默许情况下即运用soft选项。而为了运用FPU,这儿将运用softfp选项。
运用-mfpu选项设置FPU硬件的类型。
SAM4E搭载了Cortex-M4F FPU,它完结了FPv4-SP版别(SP表明单精度)的浮点数扩展。别的,它也搭载了32个32位的单精度寄存器,而这些寄存器也能够被当作16个64位的双精度寄存器以进行load,store和move操作。
所以需求将-mfpu赋值为fpv4-sp-d16。其间d16表明有16个64位寄存器。
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”:
留意,在Release版别的装备中也需求进行修正。
二、 启用FPU
开发板重置时,FPU是制止拜访的。可是AS6中运用的startup文件会依据编译器设置启用FPU。
启用FPU的办法
向FPU的CPACR寄存器的CP10和CP11字段写入0b11即可敞开FPU的彻底拜访权限。别的,在特权形式下才干读写该寄存器。
在CMSIS中该寄存器的地址被界说成了保存地址。可是在fpu.h 中供给了相应的API:
#include
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);
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闪耀的频率。