|
在STM32的应用开发过程中,我们有时可能涉及到DSP应用,需要使用到相关DSP函数。这里基于STM32H743芯片的Nucleo开发板,做个有关矩阵运算应用的演示,简单的演示下两个矩阵相乘的实现过程。, G& @) H' ]+ r4 { 开发环境选择的是ARM MDK,当然你也可以选其它的,比方IAR, STM32CubeIDE等。 我们要用到ARM提供的DSP函数库,该库在STM32的Cube库或标准库里都可以找到。+ ^+ V* }- _/ |1 W2 G2 U1 m ) z7 g+ Y, Z1 P/ n# | 以STM32CubeH7的库为例,相应的DSP函数库一般在下面位置: 2 {+ Q2 H: g C! t7 |6 g) @
7 C4 p" g1 o1 `/ K; g6 Z* ~ 上图中绿色方框内的函数即为跟矩阵相关的函数库文件。, P/ Z4 b$ I4 L6 |5 W. B # U8 L& m1 F. F8 A+ Z3 [) U+ u 具体使用时,我们直接添加相应的lib库进来即可,不过,添加该lib库文件时要注意两点: " O; t- B' p, n ]5 U: v: I# e ' y1 j6 ~- y2 {% F% {, H* ~ 你选择的库文件要跟你芯片类型一致,内核类型、大小端模式、是否支持浮点运算。5 X! f* D5 {9 o) w $ j' X, _" `& l C9 ]. @+ |# y' N) E 你选择的库文件还要跟你所使用的编译器匹配,即IDE是MDK还是IAR等。# Z% e& f1 _ f 基于上面两点我们添加arm_cortexM7lfdp_math.lib文件【corex M7、小端模式、支持硬件浮点单元】。8 ~4 h1 l3 K9 k+ o$ f 8 M+ p& L9 x X2 R4 u
Q& u, R f$ s$ Q 在我们的main()文件里添加arm_math.h头文件。记得在IDE环境的配置里添加相应的搜索路径。启用硬件浮点运算单元。开启有关宏定义。【宏开关不用特别去记,缺少的话编译时会报错】. q* y( i$ K' _$ ?2 t- f
/ w8 X& Z+ {: V2 q 下面构造三个矩阵,A矩阵的数据表示某家芯片代理商为他的8个客户分别提供四种不同规格的芯片,数据以包为单位。不同型号的包装规格不一样。A矩阵为8X4矩阵。+ E' z/ u H# D2 c $ z) ?& I- X' z# | B矩阵表示A矩阵中各类包装每包的数量、价格、运费、重量,为4X4矩阵。. X5 @$ f( d$ x+ V3 V 二者的矩阵乘积表示各个收货方收到芯片的总数、应付货款、运费、以及货物总重量,将构成8X4矩阵。矩阵里的数据使用浮点数,数据随意设计的。 3 b. | D' S! @( ` 我们知道,两个矩阵可乘有个前提,比方A*B,矩阵A的列数应该等于矩阵B的行数,相乘后所得的乘积矩阵的行数等于矩阵A的行数,其列数等于矩阵B的列数。) q* H1 g) L' Y7 s6 d % i7 i+ N1 s6 I( s 具体到这里,矩阵A的行数为8,列数为4,矩阵B的行数、列数均为4。A*B所得矩阵的行数为8,列数为4. - A5 `" [6 z `! k
/ ^! p6 v6 q- C4 I: j {! |7 Z# w# K$ V' i) m
; {5 v0 s0 E2 m 下面做相关代码的准备。0 W& d( ]0 a* a- w0 P K& r - h1 x1 a# m8 Y& { 定义三个数组,pDataA[32]数组对应矩阵A, pDataB[16]数组对应矩阵B,第3个数组pDataC[32]对应矩阵AB乘积所得的新矩阵。$ T- c; {1 r( h" w8 j; J, t , c# K+ _" c4 R3 M& _ n
基于上面的3个数组定义3个如下矩阵变量:+ E9 E/ P+ P* G% G& `( F7 `
关于结构体arm_matrix_instance_f32的定义和说明,可以在arm_math.h中看到。 ( o' H F" I8 ~( ]( O 8 x6 r# _& K! O" k
2 W+ C8 j5 U) c7 x' ]- F" {( [: G7 E 接下来对3个矩阵进行初始化,注意行、列数别给错了。# }* t9 ?0 ^' _. N, m: K
7 C/ ^$ P! l7 X, ` 2 A+ c! U- O+ v7 y: V( D/ k W8 o" }( F 一切都准备好了,就可以进行矩阵乘法计算了,调用库函数中arm_mat_mult_f32()函数。/ h) p6 P2 Z% u 6 F0 C' [- l( b( @ 1 ~( C$ O$ ]0 l* Z6 C( D
E' R+ z- d: Q3 ^ l" @7 M ) F4 D$ Z5 H. o" c6 m 矩阵相乘后的运算结果存放在数组pDataC[32]里面,按8*4的矩阵摆放。; ~8 }, h; U& a7 Q' `/ m6 q' J# {: L
: B1 h* M& s1 m( c 上述运算结果跟使用MATLAB数学工具通过矩阵乘法得到的结果整体上非常一致。数据会稍有些小出入,毕竟是基于浮点运算所得结果。; `9 x- o- h# [4 Z5 o( w, ^ Z ( X+ i" `2 G9 J 我们知道,STM32H7是带Cache和FPU的。不妨基于该矩阵乘法应用比较不同情况下的运行时间。以定时器的计数时钟为单位。根据Cache和FPU的开启与关闭的不同组合进行测试,可以做些相对比较,让我们有些直观的感受。测试时ARM MDK的优化等级为-o3。顺便提醒下,如果不开启硬件FPU,调用的DSP库函数应选择另外一个不支持硬件浮点单元的函数库。 7 _: U' D6 p( @' w/ S 1 \0 b5 R# ]% q
+ T3 X5 v4 C& g& j+ r7 k 下面数据是基于上面测试代码所得到的,其中红色数据为十进制数据。 ^8 @/ w p$ \ h: b* c% |
从这里我们可以看出,同时开启硬件FPU和Cache与同时关闭二者,运行时间相差将近40倍;开启Cache与关闭Cache运行时间上相差4倍左右;使用FPU和不用FPU,运行时间相差8倍左右。当然,或许基于不同的应用,上述数据可能存在些差异,但可以肯定,开与不开Cache、启不启用硬件FPU,运行速度上的差别还是很明显的。 . Y' J! N0 ]4 F0 y % y5 M# T8 q" k+ Z& ?$ i4 _ 好,关于利用STM32及相关DSP函数库进行矩阵运算的演示就介绍到这里,请留意上文中谈到的那些提醒。其它更多细节,有兴趣的话可以进一步阅读和研究相关资料。) w8 ^) Y0 V5 j9 {1 J. c, h& ~ % [+ g2 |) _* |: C( i- i |
【 逢7发帖赢大礼】1、利用CubeMX生成正点原子H7R7开发板的STM32CubeIDE工程
【STM32H735G-DK测评】ADC3+TIMER1+DMA 采样模拟信号
【STM32H735DK测评】Ethernet+lwip DHCP获取IP地址
STM32H743基于CubeMx5.0配置手册
【STM32H735G-DK测评】lvgl移植
【STM32H735G-DK 测评】STM32H735G-DK External Loder 编译和测试
【福利三:逢7发帖赢大礼】使用MPU6050模块、img_dsc、img_btn机制实现一些简单有趣的动画效果
【福利三:逢7发帖赢大礼】使用arc弧形拉条控件控制PWM舵机及使用SPI3接口操作NRF24L01模块进行无线通信
【福利三:逢7发帖赢大礼】调试nucleo-WBA65RI工程测试样板的一些心得
【福利三:逢7发帖赢大礼】lv_timer和BME680实现温度、湿度、气压数据读取
微信公众号
手机版