IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 基于ARM-Cortex M3/4的GNU汇编的嵌入式程序设计之三 —— STM32F407G-DISC1的FPU操作 -> 正文阅读

[嵌入式]基于ARM-Cortex M3/4的GNU汇编的嵌入式程序设计之三 —— STM32F407G-DISC1的FPU操作

一、简介

最近那块陪了我8年的STM32F407-DISC板子烧了。好在公司买了块新的给我,心情大好。打算再鼓捣一下。
在这里插入图片描述
Cortex-m4是有FPU的。但是好像很多人都搞不清楚要怎样设置才能使能。有的说在Keil的IDE设置里面怎么弄的,还有的说要定义什么宏的。那么,就要探索一下看看官方要求是怎么做的。

为保证操作合规,我们要先查阅技术文档,了解清楚技术参数和初始化的方法。再看看指令集,用指令集做一点测试。最后看看C语言下面生成的语句是否合理。

二、文档说明 - 技术参数和初始化要求

首先要说明一点,那就是CM3和CM4的区别就在cm4有浮点运算单元,也就是FPU。内核其他的都是一样的。至于外设,ST的407和103的寄存器设计还是有很大的区别的。比如,407的GPIO设置寄存器就和103的差别非常大。当然,这些外设对于我们操作内核来说是没有影响的。

先看看文档上我们CM4的FPU是怎样的。所谓的使用浮点运算,其实就是用到2个东西:

  1. 硬件乘法器对应的浮点运算指令集。换句话说就是那一堆带V的指令集,如vmov,vdiv等等
  2. 浮点寄存器。就是d0-d15,s0-s31。

技术参数 - CM4的FPU是32位单精度的

根据Arm? Cortex?-M4 Processor Technical Reference Manual第22页,写得很清楚
在这里插入图片描述
这个就是个32位的,只能处理float类型的浮点数。根据后面的实验你会知道,double的是处理不了的。

初始化方法 - 使能CPACR的CP10和CP11

根据上面那个文档的第71页,只要保证CPACR的CP10和CP11是使能的就好。这里如果你去查这个CPACR,你会发现并没有CP8和CP9,看来这个序号用的是8进制。可能是笔者见识少,我感觉现在计算机上用8进制的其实并没有那么多。

在这里插入图片描述
参考这个文档,我们了解到,我们需要在特权模式下将这CP10和CP11设置成3就行了。如果没有操作系统,那么上电复位以后就是处于这个状态的。所以我们用这部分代码试一下。

三、建立工程

笔者是在STM32CUBEIDE下建立的工程。方法如下:
在这里插入图片描述
这里直接选中开发板的407芯片就好。

在这里插入图片描述
文件名无所谓,但是要创建一个Empty的工程。这样我们就有了一个这样的工程。
在这里插入图片描述

四、测试工程

这里,我们做个实验。看看FPU能不能工作。建立Source Folder,名字叫User。User下面建立文件夹Inc和Src。然后将Inc加入到工程的头文件列表里。将main.c的函数写成下面的样子。

#include <stdint.h>

#if !defined(__SOFT_FP__) && defined(__ARM_FP)
  #warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif

int main(void)
{
	float v0 = 0.32, v1 = 1.35;
    /* Loop forever */
	for(;;){
		v0 = v0 * v1;
	}
}

编译,会有那么个警告。我们先不去管他。直接Debug。然后发生了下面的事情。
在这里插入图片描述
直接跳到了Default_Handler里面了。就是说系统已经崩溃了。查看一下右面的寄存器,发现CP10和CP11都是0。
到底是不是他俩的问题呢?很简单我们在主循环之前下断。用调试器修改CP10和CP11为3,再运行看看。
在这里插入图片描述
看,这次就能正常运行,还把值算了出来。
所以说,就是要初始化的时候设置一下CP10和CP11就可以了。

五、做FPU的初始化函数

那就按照手册上说的那样,如下操作
**第一步:**我们在User/Inc下创建fpu.h。

/*
 * fpu.h
 *
 *  Created on: Jul 10, 2022
 *      Author: swp19
 */

#ifndef INC_FPU_H_
#define INC_FPU_H_

void fpu_init(void);

#endif /* INC_FPU_H_ */

第二步我们在User/Src下创建fpu.s。注意是汇编文件哟,不要写成.c了。

/*
 * fpu.s
 *
 *  Created on: Jul 10, 2022
 *      Author: swp19
 */

.syntax unified
.cpu cortex-m4

.global fpu_init

.section .text.fpu_init
.type fpu_init, %function
fpu_init:
	//; CPACR is located at address 0xE000ED88
	LDR.W R0, =0xE000ED88
	/*
	; or for execute only code, the instruction pair
	; MOVW R0, 0xED88
	; MOVT R0, 0xE000
	; Read CPACR
	*/
	LDR R1, [R0]
	//Set bits 20-23 to enable CP10 and CP11 coprocessors
	ORR R1, R1, #0xF<<20
	//; Write back the modified value to the CPACR
	STR R1, [R0]

	bx lr
.size fpu_init, .-fpu_init

这里要按照以前的文章说的那样,建立平板汇编函数,再把技术手册里的代码抄过来,修改一下语法格式。

最后修改main.c文件

#include <stdint.h>
#include "fpu.h"
#if !defined(__SOFT_FP__) && defined(__ARM_FP)
  #warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif

int main(void)
{
	float v0 = 0.32, v1 = 1.35;
	fpu_init();
    /* Loop forever */
	for(;;){
		v0 = v0 * v1;
	}
}

测试一下。
在这里插入图片描述

可以确认,数值计算正常。
这里还可以从左面的反汇编窗口确认,C语言的浮点数被编译成了FPU指令(即那些V开头的指令)。FPU的初始化函数实现成功。

六、CM4的FPU对双精度的测试

正如手册上说的,CM4是不具备处理双精度浮点,即double的能力的。
这里还可以再测试一下,将float改成double,你会发现虽然得数是对的,但是反汇编那里有些不一样了。
在这里插入图片描述
看,再也没有FPU的指令了。对于double类型,CM4的编译器是不会调用FPU指令的。
那么是不是CM4就不支持64位的指令呢?我们来写一个测试void fpu_test(void)

.section .data.user_data
.type user_data, %object

.align 8
user_data:
.double	12e4
.size user_data, .-user_data

.section .text.fpu_test
.type fpu_test, %function
fpu_test:
	ldr r0, =user_data
	vldr.64 d0, [r0,#0]
	vsqrt.f64 d0, d0
	bx lr
.size fpu_test, .-fpu_test
#include <stdint.h>
#include "fpu.h"
#if !defined(__SOFT_FP__) && defined(__ARM_FP)
  #warning "FPU is not initialized, but the project is compiling for an FPU. Please initialize the FPU before use."
#endif

int main(void)
{
	double v0 = 0.32, v1 = 1.35;
	fpu_init();
    /* Loop forever */
	for(;;){
		v0 = v0 * v1;
		fpu_test();
	}
}

直接编译,发现根本过不去,系统提示:

…/User/Src/fpu.s:47: Error: selected FPU does not support instruction – `vsqrt.f64 d0,d0’
make: *** [User/Src/subdir.mk:19: User/Src/fpu.o] Error 1

所以,我们强行调用64位指令运算是不能成功的。但是这里有个例外,那就是vldr.64 d0, [r0,#0]这句其实是能运行的。例如下图
在这里插入图片描述
可以看出,那个double数字还是可以加载的。但是就是不能使用运算指令。改成单精度以后就可以用了。
在这里插入图片描述
这里把12e4这个数字给开平方了。

七、总结

CM4的FPU:
1、去特权模式下设置CPACR的CP10和CP11为3就可以使能FPU。
2、只能处理float,可以对double进行搬运,但是不能处理double
3、在CM4的C语言程序中使用double将调用C语言的整型算法解决,效率相比float要低一些。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-07-17 16:39:38  更:2022-07-17 16:41:43 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 22:57:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码