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

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

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

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

" [( M' ]0 @; t# Q1 L% [- d; [

1. 关于CORDIC

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


/ {4 g% E4 |- b' W  k: _% I9 p# `9 W

640 (7).png 坐标旋转算法示意图9 f+ ?# A, z- J5 X0 y+ b5 ~

3 D. S6 K, e5 T4 ]5 c2. STM32G4中使用CORDIC2.1 初始配置

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


8 {$ G2 {+ n! B( z/ a( U' \8 N

640 (6).png
- E5 l3 p( `" t/ d# M结构体成员变量6 f4 H7 [! h3 W

. P# G: [# b; Q* d6 I

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

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

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

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

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

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

640 (5).png

函数输入与输出) h; @0 k9 \' |( l, N& X


. p8 C* M+ N% G/ \) K

640 (4).png
1 O. q. y4 X. I

CORDIC_CSR寄存器
% u4 U2 S' V8 g* y4 b

0 D7 p! c( y9 i: v
; r* T! A, X; X2 r2.2 CORDIC的读写操作步骤
  • 零开销模式(Zero-overhead mode)

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


    : X2 X; B" w' g8 b9 g
    1 v3 i8 N% |/ l  r) x/ }1 R5 K
  • 配置CORDIC_CSR寄存器,也就是初始化和配置CORDIC;
  • 向CORDIC_WDATA寄存器写入参数,写入完成后CORDIC将会开始第一次计算;
  • 如果需要,为下一次计算重新配置CORDIC_CSR寄存器,此时不论上一个计算是否完成,重新配置CSR寄存器不会对上一次计算结果产生影响;
  • 向CORDIC_WDATA寄存器写入下一次计算所需参数;
  • 从CORDIC_RDATA寄存器读取上一次计算的结果,读取结果的操作完成后会触发下一次计算的开始;一旦开始计算,读取CORDIC_RDATA寄存器的操作都会插入AHB总线等待状态,直到计算结束才返回结果;因此,即使CORDIC未运算出结果,也可以进行读操作,当计算结果返回时读操作完成;
  • 重复第3至第6步骤;
  • 从CORDIC_RDATA寄存器读取最后一个结果,完成计算。0 l3 S% r( s3 r- I3 a- r
/ J. G  O7 y. `
640 (3).png : l& b. W0 u1 h' T
零开销模式示意图7 Y, h6 o2 q( I% g4 H" @( ^8 Q4 Y

, Z* c4 J3 W* g* _8 o
  • 轮询模式(Polling mode)

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

    9 L2 c1 c& y( f. m! H! D
    " u3 [4 k  Q% e& f" J
  • 配置CORDIC_CSR寄存器,也就是初始化和配置CORDIC;
  • 向CORDIC_WDATA寄存器写入参数,写入完成后CORDIC将会开始第一次计算;
  • 如果需要,为下一次计算重新配置CORDIC_CSR寄存器,此时不论上一个计算是否完成,重新配置CSR寄存器不会对上一次计算结果产生影响;
  • 向CORDIC_WDATA寄存器写入下一次计算所需参数;
  • 轮询CORDIC_CSR寄存器的RRDY标志位,直到该位被置1;
  • RRDY标志位置1时,从CORDIC_RDATA寄存器读取上一次计算的结果,读取结果的操作完成后会触发下一次计算的开始;
  • 重复第3至第7步骤;
  • 从CORDIC_RDATA寄存器读取最后一个结果,完成计算。
    6 L: y3 t2 T9 W8 \) W

    ) t' @, T( p4 S9 k$ I$ Z4 x
  • 0 ~& W) \) d7 S+ w* l. \% s' {: E
  • 中断模式(Interrupt mode)

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


      e8 M$ m0 t- O. X8 Q7 V

    ' u- F6 M$ s* P9 h
  • 配置CORDIC_CSR寄存器,也就是初始化和配置CORDIC,并且设置IEN位为1;可以直接在STM32CubeMX中设置为中断模式;
  • 向CORDIC_WDATA寄存器写入参数,写入完成后CORDIC将会开始第一次计算;
  • 如果需要,为下一次计算重新配置CORDIC_CSR寄存器,此时不论上一个计算是否完成,重新配置CSR寄存器不会对上一次计算结果产生影响;
  • 向CORDIC_WDATA寄存器写入下一次计算所需参数;
  • 当计算完成,RRDY位被置1,产生中断信号;在中断服务函数中读取CORDIC_RDATA寄存器上一次计算的结果,读取结果的操作完成后会触发下一次计算的开始;读取CORDIC_RDATA的操作会清除RRDY位和中断信号;;
  • 从CORDIC_RDATA寄存器读取最后一个结果,完成计算。
    $ N( x( f/ b/ i8 b! Z

    0 ?' q8 m9 i, G' l1 Y
  • 5 P6 E  C5 _$ V4 q5 o8 {) q
  • 直接存储器访问模式(DMA mode)

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


    # b; G3 g! b  N5 y! g  \
    8 v8 u5 E3 f& {1 [
  • 配置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阻塞。


    $ z; _# ~0 o& A9 x
5 i. {! z6 p" f3 C5 R
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
9 T8 K( c6 w) c3 [- A4 \
+ g. H( c4 ^4 I% @9 j7 W 6{1P){WKOQU0ABX~1ELO1.png ; S$ B. N4 n: ]0 w/ W

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

5 Y+ K0 j" a7 A9 T0 S$ k

640 (1).png
2 N: @9 w) T$ `" \2 j* S/ Z% C" H$ ^( k  ]8 O2 q
5J~BNAAMTUAV20R%J8213.png * M+ V& z: l, `+ V+ p( x+ A

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

640.png 3 P$ @$ V8 L  w4 C4 C; O' ~, q

# f' t4 g0 p8 Y' R9 r3.2 带符号浮点格式的转换

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


$ t  j! x% D" m& Z+ j9 U$ q

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

  1. /**
    : @* ]2 v6 e+ W/ c* }4 H; X' s& s
  2.   * @brief  将数据转换成CORDIC要求的Q1.31整型数据格式。% y/ I) [6 i6 X* n
  3.   * @param  需要转换的数据,取值可以为负数。6 \# ?! x/ G0 \, l" g+ W
  4.   * @param  比例系数;数据除以比例系数之后再转换格式;
    , {. m, }. K! G! z' U
  5.         *         CORDIC的输入参数数值在[-1,1]之间,故需要先除以一个比例系数。
    ) O/ r& M( N1 q' N
  6.   *            @ref STM32G4 Series advanced Arm-based 32-bit MCUs - Reference Manual( Z9 D. W9 Z0 h9 F: Z. V8 Y
  7.   * @retval Q1.31整型数据
    ; y" V' V! I1 h& |- S$ B
  8.   */- h4 F0 T- N# k% K
  9. int Value_To_CORDIC31(float Value, float Coefficient)
    7 A! x1 L6 N2 \  @8 Q$ ]2 I/ W! n
  10. {- N& R. s4 d9 t, V/ u
  11.         int CORDIC31;
    ( ~$ W+ q9 r3 h
  12.         CORDIC31 = (int)((Value/Coefficient)*0x80000000);
    : A7 S6 {  c1 }
  13.         return CORDIC31;
      }. }/ z' T5 w/ [
  14. }
复制代码

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

  1. /**: ]) J0 e5 Q/ H. o# R
  2.   * @brief  将数据转换成CORDIC要求的Q1.15整型数据格式。
    & s2 U2 _9 O( [, Y
  3.   * @param  需要转换的数据,取值可以为负数;该数据存放在高16位。
    " I( ]* j- K3 w/ T* K* s
  4.   * @param  需要转换的数据,取值可以为负数;该数据存放在低16位。; K* Q3 N& L0 [$ f
  5.   * @param  比例系数;数据除以比例系数之后再转换格式;; X4 Z! g4 s( Y* f1 I; Q) h
  6.         *         CORDIC的输入参数数值在[-1,1]之间,故需要先除以一个比例系数。
    * R; M0 R2 `% m6 O+ H  X1 E
  7.   *            @ref STM32G4 Series advanced Arm-based 32-bit MCUs - Reference Manual- e- k+ b6 r0 J  h
  8.   * @retval Q1.15整型数据7 L/ h& V9 C4 o! ~, ]4 y1 b0 e
  9.   */( \% Q: {. l- z
  10. int Value_To_CORDIC15(float ValueA, float ValueB, float Coefficient)
    " X# t1 m6 a. Y
  11. {
    % T* U* k/ \) X; T+ Y  Q
  12.         int CORDIC15;
    % |- v2 Z# U: R/ a1 c
  13.         CORDIC15 = (int)((ValueA/Coefficient)*0x8000) << 16;
    " z, Z- r! T% m1 J. S4 q
  14.         CORDIC15 = CORDIC15|(int)((ValueB/Coefficient)*0x8000);) h6 b; r) ~1 r
  15.         return CORDIC15;, m7 s" }1 v( a4 _3 L4 `  Y! a
  16. }
复制代码

" i6 F8 [& F* n  U7 W3 K+ D' }& Y6 c

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

  1. /**. [! D' t( }6 H
  2.   * @brief  将CORDIC输出的Q1.31整型数据转换成带符号的浮点数值格式。" E! V6 V  ]0 ~4 }+ `" A
  3.   * @param  需要转换的数据。; x) K2 r# V5 j6 H1 o
  4.   * @param  存放输出数据的地址。
    $ H  J7 s$ W$ ?! c, h
  5.   * @note   转换无精度损失;
    ) a& y; j/ C3 O7 Q1 _7 m+ ~! _2 y" T
  6.   *         精度要求不高时,可以将double类型换成float类型以节约RAM空间;此时精度将下降至1/10000000。
    $ m4 E. B" J$ Q" m5 o
  7.   */8 f" y( z! `# o
  8. void CORDIC31_To_Value(int CORDIC31, double        *RES)
    ( S+ R) o4 S0 e+ {9 t' ]" j  W1 S! g
  9. {- ~3 \5 ~% H3 m0 V6 B6 h
  10.         if (CORDIC31&0x80000000); z* M) v+ U' s) I( R) M( ]
  11.         { /*为负数*/8 u4 v/ R  y' r! {+ {2 u
  12.                 CORDIC31 = CORDIC31&0x7FFFFFFF;
    / D5 Z, a& i5 V: ^' p" a
  13.                 *RES = (((double)(CORDIC31)-0x80000000)/0x80000000);
    6 i0 X7 B5 w# K; }% H: y) f
  14.         }/ r/ |  x0 N) |3 S4 _2 u4 x! D
  15.         else7 d, j) D3 v3 o3 a7 S
  16.         {/*为正数*/- g; D( i( S8 s$ g$ [/ R6 `
  17.                 *RES = (double)(CORDIC31)/0x80000000;
    7 b8 @% z+ }( O% W/ l! S7 ], k
  18.         }
    + W, @7 S% Q* D
  19. <font size="2">}</font>
复制代码

+ n) s, E& a% s5 A
& X5 [2 e7 S7 G  D

- s3 _5 }( F0 n% _# S% `0 G

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

  1. /**1 K7 g/ h+ V5 N/ v6 Q
  2.   * @brief  将CORDIC输出的Q1.15整型数据转换成两个带符号的浮点数值格式。
    * [1 X" F  f7 @/ V9 a  u
  3.   * @param  需要转换的数据。" w8 Q$ b7 U  H0 \; C9 n+ ]
  4.   * @param  存放输出数据的地址;输出高位数据。4 F9 j/ u, C  [: X9 T7 Y, I
  5.   * @param  存放输出数据的地址;输出低位数据。" u% x; V- G. l) |. Z5 C
  6.   */- K$ V9 F' i' A/ x$ a
  7. void CORDIC15_To_Value(int CORDIC15, float *REA, float *REB)
    ' P4 @+ N( N/ T9 x
  8. {
    6 ]; F4 n0 q1 }: q: L4 d
  9.         if (CORDIC15&0x80000000)//处理高16位4 ]& \; j: m+ w2 G: C4 y
  10.         {/*为负数*/& D3 W: i) ?/ h
  11.                 *REA = ((float)((CORDIC15>>16)&0x7FFF)-0x8000)/0x8000;
    * Y0 O. B0 s8 ^# n' w9 J
  12.         }0 B+ T; w& x8 H: t  k/ q
  13.         else) ]5 k& @5 O* r) P
  14.         {/*为正数*/
    + K) e1 A/ x9 [* m# c7 u
  15.                 *REA = (float)((CORDIC15>>16)&0xFFFF)/0x8000;
    1 N' N; ?3 G1 l* l! ?
  16.         }8 C# P' ~' @) K7 w) ]8 v6 }
  17.         if (CORDIC15&0x8000)//处理低16位
    3 M" o# @9 m) {# j. i* B
  18.         {/*为负数*// a( ?& v7 k' w! B" |# o5 P  ~7 |( B
  19.                 *REB = ((float)(CORDIC15&0x7FFF)-0x8000)/0x8000;5 u+ x4 w' q1 o  h4 y
  20.         }4 v/ x5 k  `4 n! |" m
  21.         else
    - |' U2 Z5 R( X; k! I* B1 U/ J
  22.         {/*为正数*/$ j0 P3 L" h" ]- J
  23.                 *REB = (float)(CORDIC15&0xFFFF)/0x8000;' I/ T7 B/ k8 f+ V: d' k
  24.         }
    . u2 S  d' R0 J- c( H; A3 E) I
  25. }
复制代码
9 m0 l6 Y, A" v9 x8 H; g0 |

: [. L6 E3 a; W8 ^
赞 收藏 评论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管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版