你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32G4_CORDIC与定点带符号整数数据格式

[复制链接]
STMCU小助手 发布时间:2022-5-27 19:47
STM32G4_CORDIC与定点带符号整数数据格式

2019年ST推出的G4系列芯片是STM32系列第一款带有CORDIC协同处理器的芯片。CORDIC协同处理器提供某些数学函数的硬件加速,尤其是三角函数。它能加快这些函数的运算,释放处理器以执行其他任务。通常用于电机控制、测量、信号处理和许多其他应用。

: g( B# q2 l. o

1. 关于CORDIC

CORDIC(coordinate rotation digital computer坐标旋转数字计算机)是一种用于计算三角函数和双曲线函数的低成本逐次逼近算法。最初由Jack Volder在1959年提出,它被广泛用于早期计算器当中。CORDIC算法通过基本的加和移位运算代替乘法运算,具体原理不在此赘述。

# y# p0 k( d+ n( @" d

640 (7).png 坐标旋转算法示意图+ X7 B0 |9 r" @- q; g
7 V9 A% |4 T3 F' s, p9 }5 V
2. STM32G4中使用CORDIC2.1 初始配置

使用STM32CubeMX激活CORDIC,再按需选择配置NVIC或者DMA。生成代码支持HAL库和LL库。此时代码包含了CORDIC的初始化(CORDIC_Initialize),不包括CORDIC的配置(CORDIC_Configure)。需要用户自行实例化结构体CORDIC_ConfigTypeDef:

+ g* X/ ^( T4 d7 z# [1 }; R

640 (6).png
. O( y1 Z$ Z; K( @/ t9 y- t结构体成员变量5 `0 @5 x! E' j4 N
' V2 i- O; t' Z' P6 C( I

Function包含共10种函数:余弦、正弦、方位角、取模、反正切、双曲余弦、双曲正弦、双曲反正切、自然对数、开平方。

Scale指缩放因子;CORDIC要求输入数值在[-1,1]区间内;设输入值为x,缩放因子为n,则会先对输入数值做运算x=x·2^-n,CORDIC计算完成后输出结果y再做运算y=y·2^n;缩放因子取值范围视所选函数规定,在[0,7]区间内;缩放因子可能会导致运算精度的丢失。(可查阅ST官方文档:RM0440)

InSizeOutSize:提供两种输入输出数据格式Q1.31和Q1.15;每次向CORDIC输入数据时,会发送一个32位的数据,当选择Q1.31数据格式时,CORDIC一次运算一个数据;当选择Q1.15数据格式时,将两个数据封装在一个32位数据中,CORDIC一次运算两个数据;选择Q1.15数据格式能提高运算速度,但牺牲了运算精度;有关Q1.31和Q1.15数据格式的内容下文会讲到。

NbWriteNbRead:写入写出的参数数量;有些函数,比如求方位角、取模,需要输入x,y两个参数才能进行运算;有些函数,比如余弦、正弦,CORDIC运算后可以输出两个结果,例如进行余弦函数运算时,可以输出一个余弦结果和一个正弦结果;两个数据以交替的形式进行输入输出;输入时若次要参数一直保持不变,可在第一次计算开始后将NbWrite设置为1个参数输入模式。(可查阅ST官方文档:RM0440)

Precision指迭代周期;取值范围为1到13;迭代周期越多,运算精度越高,运算速度越低;当运算精度到达数据格式所能表达的精度极限时,继续增加迭代周期毫无意义,例如迭代6周期运算已经达到Q1.31数据格式正弦函数运算所能表达的精度极限,继续增加迭代周期的运算结果与迭代6周期的运算结果无异;对于大多数函数,迭代周期推荐3到6周期。

配置完结构体变量,后使用CORDIC_Configure函数将数据写入CORDIC_CSR寄存器,CORDIC的初始化和配置完成。

640 (5).png

函数输入与输出
) W# D1 \+ B" I, g

; Q" g1 H7 X6 A3 g1 n5 X

640 (4).png

9 x( F2 @1 y+ q- H- {

CORDIC_CSR寄存器
- J& w$ y  x* k  @: w; @: R: k' ~" q" S
8 q* I" s+ Z) a7 v+ l6 l& x. @

# ?  E# `1 v9 P- o2 N2.2 CORDIC的读写操作步骤
  • 零开销模式(Zero-overhead mode)

    该模式下CORDIC运算效率最高,上一个结果被读取后即刻开始下一次运算,期间没有空闲时间;该模式中CPU的占用率为100%。

    , [) o. L. ^1 n8 k! Q3 U

    1 w$ e  I  W. [; J) g
  • 配置CORDIC_CSR寄存器,也就是初始化和配置CORDIC;
  • 向CORDIC_WDATA寄存器写入参数,写入完成后CORDIC将会开始第一次计算;
  • 如果需要,为下一次计算重新配置CORDIC_CSR寄存器,此时不论上一个计算是否完成,重新配置CSR寄存器不会对上一次计算结果产生影响;
  • 向CORDIC_WDATA寄存器写入下一次计算所需参数;
  • 从CORDIC_RDATA寄存器读取上一次计算的结果,读取结果的操作完成后会触发下一次计算的开始;一旦开始计算,读取CORDIC_RDATA寄存器的操作都会插入AHB总线等待状态,直到计算结束才返回结果;因此,即使CORDIC未运算出结果,也可以进行读操作,当计算结果返回时读操作完成;
  • 重复第3至第6步骤;
  • 从CORDIC_RDATA寄存器读取最后一个结果,完成计算。1 d; @! d0 a2 w$ K7 P
4 G9 j' `4 e9 S9 J8 g7 F/ R4 V4 F
640 (3).png
& f0 T( \8 p) ?4 ]% ^零开销模式示意图
0 X5 `! l# T4 Q; ~& w5 p, @2 |. |+ J# ^7 B9 n
  • 轮询模式(Polling mode)

    该模式会轮询CORDIC_CSR寄存器的RRDY标志位以判断运算完成;该模式不会使CPU处于100%的占用率,使CPU可以处理其他任务;轮询模式会比零开销模式消耗稍长时间,因为计算完成后结果不会立即被读取,需要等待下一个轮询周期到来,且读取RRDY标志位后再读取结果会产生延迟。


    1 Y" j7 c) {. Z6 y) R9 E

    8 T! e1 X' P# i0 e7 X, S1 X
  • 配置CORDIC_CSR寄存器,也就是初始化和配置CORDIC;
  • 向CORDIC_WDATA寄存器写入参数,写入完成后CORDIC将会开始第一次计算;
  • 如果需要,为下一次计算重新配置CORDIC_CSR寄存器,此时不论上一个计算是否完成,重新配置CSR寄存器不会对上一次计算结果产生影响;
  • 向CORDIC_WDATA寄存器写入下一次计算所需参数;
  • 轮询CORDIC_CSR寄存器的RRDY标志位,直到该位被置1;
  • RRDY标志位置1时,从CORDIC_RDATA寄存器读取上一次计算的结果,读取结果的操作完成后会触发下一次计算的开始;
  • 重复第3至第7步骤;
  • 从CORDIC_RDATA寄存器读取最后一个结果,完成计算。
    % a4 N6 O1 I4 q" Y3 C7 ]2 j6 r6 F' P

    9 K9 t+ ]$ ?  k* g/ p  b

  • 2 A$ U+ A% d' E5 }* q
  • 中断模式(Interrupt mode)

    当RRDY标志位被置1时产生中断信号,该位被置0时会清除中断标志位;该模式下使得结果的读取具有优先级;因此会比零开销模式和轮询模式消耗更长时间。

    ! c6 [, @1 ~, q8 V' V2 C

    % q6 a! Z8 Z) F
  • 配置CORDIC_CSR寄存器,也就是初始化和配置CORDIC,并且设置IEN位为1;可以直接在STM32CubeMX中设置为中断模式;
  • 向CORDIC_WDATA寄存器写入参数,写入完成后CORDIC将会开始第一次计算;
  • 如果需要,为下一次计算重新配置CORDIC_CSR寄存器,此时不论上一个计算是否完成,重新配置CSR寄存器不会对上一次计算结果产生影响;
  • 向CORDIC_WDATA寄存器写入下一次计算所需参数;
  • 当计算完成,RRDY位被置1,产生中断信号;在中断服务函数中读取CORDIC_RDATA寄存器上一次计算的结果,读取结果的操作完成后会触发下一次计算的开始;读取CORDIC_RDATA的操作会清除RRDY位和中断信号;;
  • 从CORDIC_RDATA寄存器读取最后一个结果,完成计算。
    $ ^% K. P! ^% g

    5 O3 y! I7 g5 k6 a! N
  • $ ^/ r, N3 a6 a
  • 直接存储器访问模式(DMA mode)

    该模式下CPU占用率为0%;DMA请求不能对CORDIC_CSR寄存器进行读写操作,因此DMA模式只适用于相同模式下的运算,比如使用相同的函数、相同的缩放因子、相同的迭代周期等;DMA模式下,数据的来源与输出目的地不一定是片上内存,可以是其他外设,比如DAC和ADC;

    8 M% x& I6 z  q+ m

    ' J9 G- H/ `/ I: Y
  • 配置CORDIC_CSR寄存器,也就是初始化和配置CORDIC;在STM32CubeMX中设置DMA模式;

  • 使用CORDIC_Calculate_DMA函数启动DMA运算,入口参数中配置数据源的地址以及输出地址,并且设置DMAWEN位和DMAREN位;

    注意事项:当DMAWEN置1时会产生DMA写请求,当DMAREN置1且RRDY置1时会产生DMA读请求,因此要暂停DMA读写只需将DMAWEN和DMAREN置0即可;在DMA模式运行中应避免对CORDIC_WDATA寄存器做写操作和CORDIC_RDATA寄存器做读操作,否则可能会产生DMA阻塞。


    1 v/ L3 @1 m, L; n
! I/ G8 m6 a0 I3 A$ a! G" C8 t" U
3. 定点带符号整数数据格式(Q1.31,Q1.15)3.1 定义

在q1.31格式中,数字由一个符号位和31个小数位(二进制位)表示;数值范围是-1(0x80000000)到1 - 2^-31(0x7fffffff);精度是2^-31(大约5 x 10^-10)。

640 (2).png
" ~6 Y2 v( u& [% R' p: U1 _* Z/ M
- Q1 K8 X2 {# X* d% P8 z, V8 C7 I 6{1P){WKOQU0ABX~1ELO1.png
) y9 @# ?# @' n

在q1.15格式中,数字由一个符号位和15个小数位(二进制位)表示;数值范围是-1(0x8000)到1 - 2^-15(0x7fff);

! C, I! m. ^: Z% Y! y

640 (1).png $ z% B" i0 {0 E+ A
# ]. h$ `$ e1 t& Z' p
5J~BNAAMTUAV20R%J8213.png ; |8 }. ]6 X" t/ N# j! y. P

这种格式的优点是可以将两个输入参数打包到一个32位的数据中,并且可以在一个32位的读操作中获取两个结果;但精度降低到2^-15(大约3 × 10^-5)。

640.png
9 M, m; b. W+ S& n6 Z9 H/ D( x4 [
3.2 带符号浮点格式的转换

Q1.31或Q1.15格式对开发者而言不够直观,以下提供四条函数,可将Q1.31和Q1.15格式转换成带符号浮点数。

0 ^1 r" L3 ~; f0 C) {9 Y

将带符号浮点数转换成Q1.31格式:

  1. /**
    ' n1 b, o3 a2 X/ ]
  2.   * @brief  将数据转换成CORDIC要求的Q1.31整型数据格式。
    ' ]# \. \( {7 ?8 E1 w
  3.   * @param  需要转换的数据,取值可以为负数。2 \4 H/ M' t: O. u' O! G, v
  4.   * @param  比例系数;数据除以比例系数之后再转换格式;
    . a! U; S- O. |
  5.         *         CORDIC的输入参数数值在[-1,1]之间,故需要先除以一个比例系数。
    6 `4 E. q/ z! D3 R4 L* d+ G6 _5 B
  6.   *            @ref STM32G4 Series advanced Arm-based 32-bit MCUs - Reference Manual
    0 B5 _$ R$ p8 t% P$ S" R# C
  7.   * @retval Q1.31整型数据
    & i1 p- r+ n# C: [
  8.   */8 ?& b+ @! [7 W8 {
  9. int Value_To_CORDIC31(float Value, float Coefficient)# S9 C; k1 [* U; |, ]  T  O1 O
  10. {
    % d  s$ S7 n# ], ~) V
  11.         int CORDIC31;# |( g" P  x! w
  12.         CORDIC31 = (int)((Value/Coefficient)*0x80000000);
    - S0 T' g8 y+ h  Q% }* k
  13.         return CORDIC31;" D. e" [, Y2 Z3 O" `6 v
  14. }
复制代码

将带符号浮点数转换成Q1.15格式:

  1. /**+ i: [+ N7 R9 F# ?. W6 U& _& g
  2.   * @brief  将数据转换成CORDIC要求的Q1.15整型数据格式。
    . ]; T& f- x1 a
  3.   * @param  需要转换的数据,取值可以为负数;该数据存放在高16位。
    # A8 }3 O5 }8 r' X8 d4 s# p
  4.   * @param  需要转换的数据,取值可以为负数;该数据存放在低16位。
    ; Q+ l' F2 `7 ^/ C
  5.   * @param  比例系数;数据除以比例系数之后再转换格式;
    ( p7 a2 |( w8 E9 e) ?
  6.         *         CORDIC的输入参数数值在[-1,1]之间,故需要先除以一个比例系数。
    . {3 O6 K0 X5 N5 ?
  7.   *            @ref STM32G4 Series advanced Arm-based 32-bit MCUs - Reference Manual
    , b4 M1 h6 [0 x$ q. F5 g
  8.   * @retval Q1.15整型数据
    ; U, t8 S9 p0 B  h" E% n
  9.   */
    & I5 @; D: c. ^. y% ]9 G
  10. int Value_To_CORDIC15(float ValueA, float ValueB, float Coefficient)# a0 D! K. A; e+ c3 s2 h
  11. {9 ?- z, Y; L/ {* B7 P, p
  12.         int CORDIC15;/ `! s* d, S/ z
  13.         CORDIC15 = (int)((ValueA/Coefficient)*0x8000) << 16;
    & U6 f8 g8 |3 r: S# z9 K6 k1 N+ f2 I
  14.         CORDIC15 = CORDIC15|(int)((ValueB/Coefficient)*0x8000);
    6 Y: j- ]! ^2 z3 [4 A
  15.         return CORDIC15;' u/ `- x- D' J0 ]
  16. }
复制代码
  K5 g$ m) p" e0 Y. B/ f; u3 {
( c" g- U, J# P2 v0 f. n. K

将Q1.31格式转换成带符号浮点数:

  1. /**
    : ~0 E: E" Z- j% A. c3 V
  2.   * @brief  将CORDIC输出的Q1.31整型数据转换成带符号的浮点数值格式。5 T2 i. i. J7 _% u- I
  3.   * @param  需要转换的数据。# n( g$ N; }" g! t- f! t: z! _; c
  4.   * @param  存放输出数据的地址。0 ^$ w, Q! ~% D1 L
  5.   * @note   转换无精度损失;
    " F; ^! u. K- [- V& X2 r) m  P
  6.   *         精度要求不高时,可以将double类型换成float类型以节约RAM空间;此时精度将下降至1/10000000。
    % I( ?; p. _5 A) K, B
  7.   */
    3 @' e5 G% K! z+ U; c" l
  8. void CORDIC31_To_Value(int CORDIC31, double        *RES)
    $ e% u* y1 d. B( z: {' Y
  9. {* O# G1 l* V6 J6 _
  10.         if (CORDIC31&0x80000000)
    ' Z. }& J! |9 c  p
  11.         { /*为负数*/
    9 ]9 Z) h! V2 W+ K. N( T2 h' l0 D
  12.                 CORDIC31 = CORDIC31&0x7FFFFFFF;. z  ?% l7 z; @' h5 g3 O
  13.                 *RES = (((double)(CORDIC31)-0x80000000)/0x80000000);. f# x2 R& d. A# j% @
  14.         }+ L2 v$ M6 R  \+ g& c! v
  15.         else
    ; b4 }* |, _' A9 a8 V
  16.         {/*为正数*/
    , u7 w. Q  B8 M) ^/ D/ i: Q9 N
  17.                 *RES = (double)(CORDIC31)/0x80000000;
    + v( F& \9 g& u/ T
  18.         }& r# h# U0 i/ M7 n5 K
  19. <font size="2">}</font>
复制代码

: |+ c( |7 ^' k/ _9 @$ g; ~

) l$ Z0 J  C/ b) v
; Q* G4 B0 \3 l6 V

将Q1.15格式转换成带符号浮点数:

  1. /**3 a" `/ u0 A, H* R, P7 K
  2.   * @brief  将CORDIC输出的Q1.15整型数据转换成两个带符号的浮点数值格式。+ @% G4 Z" R0 k- l* U6 x! r: e
  3.   * @param  需要转换的数据。
    . P2 h% ^& z* k& b4 a
  4.   * @param  存放输出数据的地址;输出高位数据。) Y5 K4 R" ^# a. M/ q
  5.   * @param  存放输出数据的地址;输出低位数据。& f( O, {" {5 l6 C" {  i
  6.   */% Q/ V' g) l2 J- L7 s1 J
  7. void CORDIC15_To_Value(int CORDIC15, float *REA, float *REB), K- d  ]+ r) z* Y- k
  8. {
    2 o  c( p2 _' ^- T
  9.         if (CORDIC15&0x80000000)//处理高16位
    3 T/ B& N8 B3 _! {9 d
  10.         {/*为负数*/
    ' h$ c/ Q. ~* F: B3 m
  11.                 *REA = ((float)((CORDIC15>>16)&0x7FFF)-0x8000)/0x8000;4 i( s6 Z: g3 D3 d+ x& y; f
  12.         }. F8 W) x+ F# s& ?! _/ T
  13.         else( I/ Y1 g3 ?# @: s( u/ L
  14.         {/*为正数*/
    2 v1 l" t2 A! o/ `/ b
  15.                 *REA = (float)((CORDIC15>>16)&0xFFFF)/0x8000;7 Z8 ^; z2 l9 X1 U
  16.         }
    / M8 l1 p7 K( i+ ]* X
  17.         if (CORDIC15&0x8000)//处理低16位! U1 Z5 ^* S; P4 L5 t  ?4 C9 P
  18.         {/*为负数*/
    6 N# V  U$ d4 L6 ?
  19.                 *REB = ((float)(CORDIC15&0x7FFF)-0x8000)/0x8000;
    + `$ ^- Z. a1 U, d. h6 j" o
  20.         }
    : D- t8 k2 y8 L! \" z
  21.         else& R7 ]. T/ a3 [* v  ^/ O
  22.         {/*为正数*/
    # X& r9 j9 A1 ?  F/ K2 G
  23.                 *REB = (float)(CORDIC15&0xFFFF)/0x8000;. N0 X& i! k( \( ]8 U3 b2 K2 ~+ c
  24.         }; f6 x: Y' O: T3 q2 N3 l( C
  25. }
复制代码
. |* Q8 g2 m4 V% V+ `( \

% ~: G$ A7 h  A8 @
收藏 评论2 发布时间:2022-5-27 19:47

举报

2个回答
1316096865@qq.c 回答时间:2024-3-20 16:47:57

关于迭代次数有些问题,原文中“对于大多数函数,迭代周期推荐3到6周期。”,实际cordic精度在迭代20次左右时q1.15的误差才趋于稳定(来源RM0440 16.3.5图)。

1316096865@qq.c 回答时间:2024-3-20 18:16:58

1316096865@qq.c 发表于 2024-3-20 16:47
关于迭代次数有些问题,原文中“对于大多数函数,迭代周期推荐3到6周期。”,实际cordic精度在迭代20次 ...

[md]补充一下,CSR寄存器的PRECISION位表示的是“迭代次数/4”,因此原文中应该是配置PRECISION为3-6,对应迭代次数为12-24次

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版