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

【安富莱——DSP教程】第8章 BasicMathFunctions的使用(一)

[复制链接]
baiyongbin2009 发布时间:2015-3-18 11:33
特别说明:完整45期数字信号处理教程,原创高性能示波器代码全开源地址:链接
: u. Q( B/ P& [! ~$ E( I
第8章 BasicMathFunctions的使用(一)

0 _$ z$ W, ^  V& K, X
    本期教程开始学习ARM官方的DSP库,这里我们先从基本数学函数开始。本期教程主要讲绝对值,加法,点乘和乘法四种运算。
    8.1 绝对值(Vector Absolute Value)
    8.2 求和(Vector Addition)
    8.3 点乘(Vector Dot Product)
    8.4 乘法(Vector Multiplication)
5 q6 u/ S- I. Z
8.1 绝对值(Vector Absolute Value)
    这部分函数主要用于求绝对值,公式描述如下:
    pDst[n] = abs(pSrc[n]),   0 <= n < blockSize.
    特别注意,这部分函数支持目标指针和源指针指向相同的缓冲区。
8.1.1 arm_abs_f32
    这个函数用于求32位浮点数的绝对值,源代码分析如下:
  1. /**        / c+ V* t5 X! p, W+ C( m; }
  2. * @brief Floating-point vector absolute value.                                                    (1)" j1 {; `; y  k2 T4 t
  3. * @param[in]       *pSrc points to the input buffer        
    2 l( p( ?3 t4 O) c- S" c
  4. * @param[out]      *pDst points to the output buffer        9 z) A& ~5 K, ?4 I0 g9 A2 k& C
  5. * @param[in]       blockSize number of samples in each vector        ( f* F5 Z6 Q! ^% M' a2 b. m; [0 X
  6. * @return none.        " Y: T" C+ K! Z0 \  X3 H! w+ L
  7. */" s& Y1 W7 X9 f' N' @0 Z

  8. 0 p/ Y& D/ p: K& j: F. H" o
  9. void arm_abs_f32(                                                                                  (2)$ S( r# }9 V( `' P
  10.   float32_t * pSrc,0 J! K' J, a1 k/ M4 y# E0 Y
  11.   float32_t * pDst,, |- v! s9 Q( |: B% V( ]7 Y
  12.   uint32_t blockSize)' K+ }  }; s/ I% v
  13. {
    ' R* i% i  O% |6 b8 R3 v( u
  14.   uint32_t blkCnt;                               /* loop counter */( Q% Z4 R/ Y0 E# x4 g
  15. ) Q0 g, K$ G2 ~8 r
  16. #ifndef ARM_MATH_CM0_FAMILY                                                                        (3). D3 e1 x( r. N

  17. 5 A, `% N! g$ }3 Y: |
  18.   /* Run the below code for Cortex-M4 and Cortex-M3 */
    # g/ d$ p% B+ {0 ~2 f; V
  19.   float32_t in1, in2, in3, in4;                  /* temporary variables */: `1 v9 S. d( P" y* a# o$ n
  20. ; H* D$ Z  y0 A1 a# U
  21.   /*loop Unrolling */9 O+ L! |' a( h( e9 w2 O" G+ `
  22.   blkCnt = blockSize >> 2u;                                                                        (4)/ q, I. Q7 f& C, N2 h# I; y1 m# f  }6 u

  23. # k  |* X: C6 _0 z: I8 M2 E
  24.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.    4 C7 F$ j9 U! X
  25.    ** a second loop below computes the remaining 1 to 3 samples. */0 P- J4 ]5 _$ ?/ v6 I* y
  26.   while(blkCnt > 0u)3 H; a' e) p! b  o# ^* Q
  27.   {
    4 ]7 m2 j7 h% q5 _. `7 s/ r
  28.     /* C = |A| */
    6 o- \. A+ H1 @) ~4 Q
  29.     /* Calculate absolute and then store the results in the destination buffer. */% P1 ?6 d1 [( Y
  30.     /* read sample from source */
    0 W( U; P0 a1 r6 v" ?- X
  31.     in1 = *pSrc;/ A% K+ c  P1 j+ w6 T0 l7 P
  32.     in2 = *(pSrc + 1);
    3 k' X7 F0 m1 g6 C7 x, V
  33.     in3 = *(pSrc + 2);6 \0 F+ T. j) q* K+ M' p9 N. N
  34. 1 q5 ~+ [* e* a0 [' l
  35.     /* find absolute value */1 f8 B% }$ p3 l0 ?6 q, I
  36.     in1 = fabsf(in1);                                                                             (5)1 k2 ]; z' ?2 [0 l/ e

  37. # ^! E) d' D+ J. F  D) K" K
  38.     /* read sample from source */
    & o$ U. T: X! V7 p7 y
  39.     in4 = *(pSrc + 3);' I. D5 \9 V5 f8 y
  40. 4 d2 X* `  e2 W) _8 R& q
  41.     /* find absolute value */( F' [. v, @0 D1 d! J" t+ K/ U
  42.     in2 = fabsf(in2);2 b0 {& ]5 [; G$ z2 ?2 o4 X/ j
  43. $ a3 @9 K8 c: r- A- J, p2 Q8 c
  44.     /* read sample from source */. h# ?; y2 z2 q* i
  45.     *pDst = in1;- ]  _) v# v( [5 k0 I$ w$ F/ o! D
  46. 4 a' L9 N! z) G' ^
  47.     /* find absolute value */) U4 B% [0 [  {4 j; W
  48.     in3 = fabsf(in3);
    4 H' g  ~* I6 i- K

  49. % @' l5 }$ G' B9 H
  50.     /* find absolute value */
    $ o2 \/ F/ _9 x! b# K
  51.     in4 = fabsf(in4);
    ' j7 l; v4 Z1 T. X# _

  52. 5 S* z0 Q1 G$ h% d) u
  53.     /* store result to destination */8 r* ~/ {  L* R" p" P
  54.     *(pDst + 1) = in2;9 k1 K/ t5 ?6 Z" B  {

  55. 2 f4 D0 U( u( o1 n% h1 E
  56.     /* store result to destination */; q. `- x' Y8 Z. H
  57.     *(pDst + 2) = in3;! V4 u- {" L8 ?- B
  58. / P, P1 [( X# \+ P* ?
  59.     /* store result to destination */! G& C0 s1 t# f6 z
  60.     *(pDst + 3) = in4;
    8 g0 s7 l$ ~: U7 U. A( t/ s; k

  61. 8 V; n8 k, Z1 V& o3 d
  62. 0 W% Z- T9 m3 l! w! w) j
  63.     /* Update source pointer to process next sampels */                                            (6)$ `1 e/ h. J( v# l2 U, [
  64.     pSrc += 4u;" H+ e! B; F. \
  65. / P5 q* H, h6 e! S  N
  66.     /* Update destination pointer to process next sampels */
    * q2 o. _' W* p+ Q
  67.     pDst += 4u;
    7 P' ?1 `/ _1 S- U8 p
  68. & q6 c, h  _! ^
  69.     /* Decrement the loop counter */
    ' ]7 H, ?. t1 y4 p
  70.     blkCnt--;" t. i0 i: n  O5 x, @
  71.   }
    ! A9 R. i/ X& `0 o: c2 K1 ^
  72. 1 u6 x- K0 ^; _
  73.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.    ' j3 B% Q) P* c7 ]' g$ ~! w
  74.    ** No loop unrolling is used. */
    * r1 [: T8 r5 M9 q) D5 f
  75.   blkCnt = blockSize % 0x4u;
    ! |; U7 ?5 h9 Z: v! A

  76. " n9 m& J4 U& U2 D! b- H0 Y3 A
  77. #else                                                                                             (7)
    8 ?* q: Q, _( k& Y4 s: j

  78. 1 R7 S! K5 ^- N9 \" M" V* G4 L1 b
  79.   /* Run the below code for Cortex-M0 */
    5 n) E1 a+ S4 {# S; I6 Y
  80. 5 i/ ]- g% r) e3 o
  81.   /* Initialize blkCnt with number of samples */
    0 [/ X8 a& j- F3 b1 N8 e/ t8 k. K6 G
  82.   blkCnt = blockSize;
    0 \. o5 E0 I, y! \! _8 B  S: m
  83. 2 z0 p% S" T$ g
  84. #endif /*   #ifndef ARM_MATH_CM0_FAMILY   */
    0 Y# [2 D- o6 t

  85. + q" q# m. R$ v
  86.   while(blkCnt > 0u)                                                                              (8)
    - C) x* |1 L0 J5 i4 a
  87.   {
    + e* S' z( r4 u7 O/ v
  88.     /* C = |A| */5 V' @# W( `* X# x) r# t
  89.     /* Calculate absolute and then store the results in the destination buffer. */
    . b  N2 @# q4 C( z6 P! a% }
  90.     *pDst++ = fabsf(*pSrc++);/ h; O$ `. }9 |# o# N

  91. : v6 ?+ q. y* y) Y7 i/ H
  92.     /* Decrement the loop counter */
    ) H5 e. c0 v1 C- _) M
  93.     blkCnt--;
    ) Z, a( Q1 y- J4 a5 b" C6 q7 S) ~5 O
  94.   }1 |# o* W% d3 M0 E& O
  95. }
复制代码
1. 在这里简单的跟大家介绍一下DSP库中函数的通用格式,后面就不再赘述了。
    (1) 基本所有的函数都是可重入的。
    (2) 大部分函数都支持一组数的计算,比如这个函数arm_abs_f32就可以计算一组数的绝对值。所以如果只是就几个数的绝对值,用这个库函数就没有什么优势了。
    (3) 库函数基本是CM0,CM3和CM4都支持的(最新的DSP库已经添加CM7的支持)。
    (4) 每组数据基本上都是以4个数为一个单位进行计算,不够四个再单独计算。
    (5) 大部分函数都是配有f32,Q31,Q15和Q7四种格式。
2. 函数参数,支持输入一个数组进行计算绝对值。
3. 这部分代码是用于CM3和CM4内核。
4. 左移两位从而实现每4个数据为一组进行计算。
5. fabsf:这个函数不是用Cortex-M4F支持的DSP指令实现的,而是用C语言实现的,这个函数是被MDK封装起来的。
6. 切换到下一组数据。
7. 这部分代码用于CM0.
8. 用于不够4个数据的计算或者CM0内核。
8.1.2 arm_abs_q31
    这个函数用于求32位定点数的绝对值,源代码分析如下:
  1. /**   
    : F1 w6 j$ ]' P: ^, L
  2. * @brief Q31 vector absolute value.   
    ) ~2 ?! Q" ?- h8 p+ X/ y
  3. * @param[in]       *pSrc points to the input buffer    . S, F; m8 Z9 U9 X/ V
  4. * @param[out]      *pDst points to the output buffer    1 S0 g& H7 t; b$ r
  5. * @param[in]       blockSize number of samples in each vector   
    / R5 l. Y! e' G. ^. ]! u9 r0 ]
  6. * @return none.    6 @% i$ j" ^/ W; ^" u& N8 w" ~. U2 `2 a
  7. *   
    8 q" s( X' I! u. l1 [- O3 f+ @
  8. * <b>Scaling and Overflow Behavior:</b>                                                              (1)/ h. x) I+ a6 o: j2 Q  [
  9. * \par   
    : ]' \8 T5 p/ H
  10. * The function uses saturating arithmetic.   
    / G5 P4 @# V2 r' |* K( i
  11. * The Q31 value -1 (0x80000000) will be saturated to the maximum allowable positive value 0x7FFFFFFF.   
    4 ]$ O1 n. F$ O, ?6 w4 U% @& ?
  12. */3 C. m* N3 [7 r5 f% {: K9 q
  13. ; v2 ~4 G) [- j9 F
  14. void arm_abs_q31(
    ' o, U) Q  f9 l& x) K/ ?
  15.   q31_t * pSrc,; Q6 v! @' t# H
  16.   q31_t * pDst,
    # k, S' r  m7 D7 ^% V
  17.   uint32_t blockSize)
    8 g  W* F1 M7 [( h3 p0 O
  18. {
    ; O# r& R0 X; B5 }" a- f  i% L
  19.   uint32_t blkCnt;                               /* loop counter */  f) l) U# Y. x2 W4 w
  20.   q31_t in;                                      /* Input value */
    " o: {% q) ^" C4 l/ u& s' h; g6 x4 w

  21. : D* R9 w( t: R* A3 o, Q
  22. #ifndef ARM_MATH_CM0_FAMILY
    - Z  T' ]2 |0 i2 ]+ t
  23. + K  |1 A/ L  v! C
  24.   /* Run the below code for Cortex-M4 and Cortex-M3 */: m$ J/ q3 R5 h+ C
  25.   q31_t in1, in2, in3, in4;- T" A: I7 x; g& C

  26. 1 h) E# N. E* f& X6 n2 o4 t
  27.   /*loop Unrolling */+ K3 M5 d$ ~' b, {/ \. f; Y1 w
  28.   blkCnt = blockSize >> 2u;
    2 `' z& B. R, X2 c/ H; o

  29. ( {; e" M7 j( ^! u
  30.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.    6 J6 b/ W$ K, f# A2 `, S# e
  31.    ** a second loop below computes the remaining 1 to 3 samples. */
      y; c6 s. a9 p2 q( n
  32.   while(blkCnt > 0u); P. J; N3 l. h7 h" g3 t$ S
  33.   {( a# D2 t7 ?$ v1 d/ {- A  Y. ~4 c
  34.     /* C = |A| */3 F% ?/ c, y6 |2 a- b
  35.     /* Calculate absolute of input (if -1 then saturated to 0x7fffffff) and then store the results in the destination buffer. */" |5 V0 n# E9 g% ~  {: S( @
  36.     in1 = *pSrc++;0 ^& m  b! Y  d- m
  37.     in2 = *pSrc++;
    ; `" L9 z  `6 }1 L7 T; u, ~
  38.     in3 = *pSrc++;/ U. Z" {" [9 V
  39.     in4 = *pSrc++;) g0 l. c8 ^+ \3 n, ?

  40. + W  h( k& q% @0 W/ i4 `; _( I0 c
  41.     *pDst++ = (in1 > 0) ? in1 : (q31_t)__QSUB(0, in1);                                              (2)
    1 W/ K6 S9 Y: c! Z2 Y
  42.     *pDst++ = (in2 > 0) ? in2 : (q31_t)__QSUB(0, in2);1 @6 K  A1 a' r3 @; Y5 T: A1 P
  43.     *pDst++ = (in3 > 0) ? in3 : (q31_t)__QSUB(0, in3);
    : d/ F2 J2 v# m) J0 ?/ i
  44.     *pDst++ = (in4 > 0) ? in4 : (q31_t)__QSUB(0, in4);& Q5 j- j# y, }. C  S; m
  45. . M  O2 M. X6 R( P
  46.     /* Decrement the loop counter */
    1 `" Q# [- C" U1 y
  47.     blkCnt--;
    + Z% P: b. e+ |+ V- n  `* ~" K
  48.   }; u3 ?; c1 y1 ^" A

  49. 7 P6 T8 l# d) p- i$ x
  50.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.    * H6 ?% J% i2 H0 J/ ]/ Z3 p7 T
  51.    ** No loop unrolling is used. */
    # {. G0 \7 v6 Y# U6 y
  52.   blkCnt = blockSize % 0x4u;4 E4 _9 O% \* u0 `6 f+ _

  53. , U4 O; ?3 J& B
  54. #else( U9 E, e* S. x7 d
  55. / F  Q: ?, q0 h# D4 _
  56.   /* Run the below code for Cortex-M0 */
    & a& M: i0 W6 O  y3 l; I# Y3 Y
  57. " o, n( c3 _# O0 O7 a8 ~3 k. @1 U
  58.   /* Initialize blkCnt with number of samples */7 u  e9 Y0 @2 R( W/ Z& [
  59.   blkCnt = blockSize;3 ?& z5 P; `) ^! G* e$ d& q! H

  60. ( w8 e$ L5 ^8 o# H- \6 l4 W( f5 U
  61. #endif /*   #ifndef ARM_MATH_CM0_FAMILY   */8 u# e4 q. u# U
  62. & c1 l" \" f' @- {
  63.   while(blkCnt > 0u)
    & g4 K$ K. u& Y# v- ~
  64.   {; I/ H3 k$ Q8 T; M! E( O6 D
  65.     /* C = |A| */
    $ J! W. q2 y/ n. `7 v/ j
  66.     /* Calculate absolute value of the input (if -1 then saturated to 0x7fffffff) and then store the results in the destination buffer. */
    7 [2 m. l2 ^( ]' e; b% J
  67.     in = *pSrc++;
    9 B) m# T5 ~7 e+ r4 o/ O
  68.     *pDst++ = (in > 0) ? in : ((in == INT32_MIN) ? INT32_MAX : -in);$ }% t; y" e( O" |+ X
  69. ! a  A! i: u# U/ R
  70.     /* Decrement the loop counter */" G0 x) A% z* g) u7 B
  71.     blkCnt--;; V8 c0 V9 j  O1 K( i1 ~1 }1 L
  72.   }
    + H2 I/ b0 ~0 h% B' ]  y
  73. : R( i1 Z6 N6 l1 p) h* C
  74. }
复制代码
1. 这个函数使用了饱和运算,其实不光这个函数,后面很多函数都是使用了饱和运算的,关于什么是饱和运算,大家看Cortex-M3权威指南中文版的4.3.6 小节:汇编语言:饱和运算即可。
    对于Q31格式的数据,饱和运算会使得数据0x80000000变成0x7fffffff(这个数比较特殊,算是特殊处理,记住即可)。
2. 这里重点说一下函数__QSUB,其实这个函数算是Cortex-M4/M3的一个指令,用于实现饱和减法。
    比如函数:__QSUB(0, in1) 的作用就是实现0 – in1并返回结果。这里__QSUB实现的是32位数的饱和减法。还有__QSUB16和__QSUB8实现的是16位和8位数的减法。
8.1.3 arm_abs_q15
    这个函数用于求15位定点数的绝对值,源代码分析如下:
  1. /**    + ?- W- h$ W3 V7 [
  2. * @brief Q15 vector absolute value.   
    + e! K% N6 z; @. E
  3. * @param[in]       *pSrc points to the input buffer   
    0 g4 V1 c, X  E3 D
  4. * @param[out]      *pDst points to the output buffer   
    * p( P6 Q* A# H  ~! T
  5. * @param[in]       blockSize number of samples in each vector   
    ( |: N- Z, c' {+ r% b
  6. * @return none.   
    3 c( v9 ]" J- a* Q
  7. *    4 G" o' u: w8 e5 X" c6 R) A
  8. * <b>Scaling and Overflow Behavior:</b>   
      M) U! q% L# K' F# s9 Q$ Q9 Y
  9. * \par    5 F2 Q0 D- m; T' C
  10. * The function uses saturating arithmetic.   
    # z  ~2 S; e; y: i( l8 n
  11. * The Q15 value -1 (0x8000) will be saturated to the maximum allowable positive value 0x7FFF.       (1)9 |" L( a2 S! X- w: H& d0 I( ^
  12. */
    8 ~6 M& A, \- V5 P
  13. : j7 U. a- v6 o5 t6 s# t- l
  14. void arm_abs_q15(
    & p" D8 N5 i  ^: y
  15.   q15_t * pSrc,
    8 J' Y: G- t( ]% z, W& i3 n$ I
  16.   q15_t * pDst,
    ! Q. x9 `, ?6 |5 A
  17.   uint32_t blockSize)  q( a  |6 L, y- p
  18. {. B# `8 h; V9 `) `% @9 k9 P9 p6 u& e
  19.   uint32_t blkCnt;                               /* loop counter */8 h/ x3 E' V5 ]+ C! ]( U, g6 M1 n

  20. % Y/ W5 w. E3 I' S" K( |
  21. #ifndef ARM_MATH_CM0_FAMILY! s: o- ], u6 I# T/ e. R* o
  22.   __SIMD32_TYPE *simd;                                                                               (2)
    : ^7 x- O3 \- \, R
  23. " M- Z4 T( N2 W% B) q+ q' @, F
  24. /* Run the below code for Cortex-M4 and Cortex-M3 */+ x3 z2 f9 ]% Z, b8 o+ j

  25. + v6 v& |* V2 E/ @# X' H
  26.   q15_t in1;                                     /* Input value1 */
    3 U9 L) w3 Z& Z( T1 g8 Q1 o
  27.   q15_t in2;                                     /* Input value2 */
    4 A# ]% V0 x( ~# f
  28. ) y/ l9 b0 ^/ \8 O3 v

  29. ; i) i, ^: z1 {2 j6 Q
  30.   /*loop Unrolling */
    9 t+ ^( T( B% X- ?
  31.   blkCnt = blockSize >> 2u;' S) [+ R. K$ N9 Q- I- H) h

  32. 5 Z6 [5 v) }3 C5 N) _' ?/ ]& G2 J3 C+ n
  33.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.    0 b- W9 k2 o$ y- L( H' E7 ^3 y
  34.    ** a second loop below computes the remaining 1 to 3 samples. */3 j1 G6 H# c; K# m. |* j
  35.   simd = __SIMD32_CONST(pDst);                                                                       (3)! V6 Z1 @0 H- d7 J( b
  36.   while(blkCnt > 0u)) v6 n8 k' t7 V/ @* i
  37.   {& {1 G; P$ s# D6 a  a
  38.     /* C = |A| */
    ( D+ g% H& }- e+ G: U8 r7 J. }
  39.     /* Read two inputs */
    4 C' I- f3 m' a2 \) H5 `0 ~! o
  40.     in1 = *pSrc++;
    9 [1 U1 ]- [- {6 @8 |8 c8 A% E
  41.     in2 = *pSrc++;) |0 z  A1 T# y" J& v2 B

  42. 3 |4 Q) b1 D9 \. n
  43. 5 O- X3 _5 i9 ?4 k* C+ l# f
  44.     /* Store the Absolute result in the destination buffer by packing the two values, in a single cycle */
    4 {" C0 J) }' ^' b% R0 a
  45. #ifndef  ARM_MATH_BIG_ENDIAN" H2 o0 G: o% a
  46.     *simd++ =
    - F0 w1 l, N. X& Z7 ^  p
  47.       __PKHBT(((in1 > 0) ? in1 : (q15_t)__QSUB16(0, in1)),                                           (4), P: K* {/ J8 U5 }' N: L
  48.               ((in2 > 0) ? in2 : (q15_t)__QSUB16(0, in2)), 16);9 p9 O; I. J  Q- u: R

  49. 4 j% Z) w  O  u6 E
  50. #else; V% t' e* s3 P6 n! F
  51. ; e- I/ ^; s. \; j% X
  52. 4 h1 _2 n/ @" L! _) j8 d2 f  R( y8 w
  53.     *simd++ =
    ! c/ O$ y# b1 z2 T% U8 d
  54.       __PKHBT(((in2 > 0) ? in2 : (q15_t)__QSUB16(0, in2)),& _  ~. g! e, P- R$ n' b6 [5 v
  55.               ((in1 > 0) ? in1 : (q15_t)__QSUB16(0, in1)), 16);( D: W5 a3 S! W% M9 L1 w; [  F

  56. + g5 o% G; P  ?% U# \
  57. #endif /* #ifndef  ARM_MATH_BIG_ENDIAN    */+ S1 D) z$ e/ y/ f9 R& `

  58. $ Y  U, n4 t) n% h# E) d% f
  59.     in1 = *pSrc++;
      E  C) O7 U; O& j4 Z% {8 t
  60.     in2 = *pSrc++;' k4 @" [' U" E+ c0 }: d

  61. ! i6 \  ]5 R, o2 [2 S( J' S; b

  62. ) W) j, p+ B, P% X9 w# a
  63. #ifndef  ARM_MATH_BIG_ENDIAN5 U* q4 [2 m5 y) u

  64. 1 `. [  r3 J5 K2 N
  65.     *simd++ =
    % V1 E; W% w4 z1 k0 A8 Q+ Z
  66.       __PKHBT(((in1 > 0) ? in1 : (q15_t)__QSUB16(0, in1)),# c+ n" ~. k! D3 T! h
  67.               ((in2 > 0) ? in2 : (q15_t)__QSUB16(0, in2)), 16);
    9 A" V! ?- _+ V9 r9 Z

  68. ; t; W$ I# P& ~/ p/ E
  69. #else# z5 L8 Y7 N/ f, c
  70. & A  D( [/ k3 L6 s4 e0 y( A
  71. 6 Y* O0 z4 F/ K3 B. ]0 @
  72.     *simd++ =# r/ Q! B2 h+ ~
  73.       __PKHBT(((in2 > 0) ? in2 : (q15_t)__QSUB16(0, in2)),
    / U4 a) F+ g5 R9 r+ h, _
  74.               ((in1 > 0) ? in1 : (q15_t)__QSUB16(0, in1)), 16);
    # \& z9 I% v6 W7 j% `. z4 E

  75. 6 H0 R# G: k8 J4 {: ]! j
  76. #endif /* #ifndef  ARM_MATH_BIG_ENDIAN    */* j2 R9 y( Y% s$ L8 R; O" T
  77. . v4 N3 {( p  o! `- [8 g. u, N
  78.     /* Decrement the loop counter */
    1 t6 {& S; Z  n" U
  79.     blkCnt--;' O$ _  ~: w3 {3 M. y2 I0 e
  80.   }6 q  R+ F) I! v# D
  81.   pDst = (q15_t *)simd;
      k7 D$ I4 _+ f& I1 e
  82.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
    / m) M  i9 H2 i4 Q; J/ O4 c% k
  83.    ** No loop unrolling is used. */
    4 v5 \8 b. N" t" B7 m, d
  84.   blkCnt = blockSize % 0x4u;
    3 T+ t' m! B' |: B* J  k7 v
  85. , t! u, }# ^) d0 f5 ^+ W
  86.   while(blkCnt > 0u)2 R" H0 O2 M5 I
  87.   {# S: Q* n* n! `, J" ?8 o: A
  88.     /* C = |A| */
      i0 k* B  O- W+ y
  89.     /* Read the input */
    0 r' L( }, A: o; C( s5 `
  90.     in1 = *pSrc++;8 h9 g# R' w0 X
  91. % Q( |- x# ~' k4 ~* }# z
  92.     /* Calculate absolute value of input and then store the result in the destination buffer. */1 D) M/ L' o& X2 X+ }* X0 b, g$ k
  93.     *pDst++ = (in1 > 0) ? in1 : (q15_t)__QSUB16(0, in1);
    6 _5 [0 k3 ^' U: V* j, O% h

  94. : _8 N  X1 K* l: R4 _; E/ ^" b
  95.     /* Decrement the loop counter */- Q$ T) f) f4 h0 r
  96.     blkCnt--;
    # ^. G* {  o& P6 l" [2 L- {. x
  97.   }% K. K# D- W- o( p4 W( X
  98. $ w& W; m4 D+ P6 O: ^( _5 E
  99. #else! \6 J1 U) w# Z; ?/ Q
  100. & R( _4 l( @9 ?
  101.   /* Run the below code for Cortex-M0 */
    3 |: h; K+ U3 {. ^8 [" o# N
  102. $ v, o3 T' u1 w: X# V# d
  103.   q15_t in;                                      /* Temporary input variable */
    ) W  r5 }  n: k$ z
  104. ' s; R" p; R% T/ ?1 ?; |4 Z# ^
  105.   /* Initialize blkCnt with number of samples */- F" i# ?/ d! z+ |# g+ q
  106.   blkCnt = blockSize;
    * K: T! s' g# j7 V- y

  107. " I* o5 \9 E8 `. i9 p& f, ]
  108.   while(blkCnt > 0u)6 N- S0 e% K' R
  109.   {
    0 g  w  i+ o$ }5 W4 I
  110.     /* C = |A| */. U; H( H( \0 J" D* N" r/ i0 U
  111.     /* Read the input */
    1 v4 R* M* F+ z9 C( t2 V) o
  112.     in = *pSrc++;( a1 D: |% {$ _
  113. ; o" h) H. X  e% Y1 j0 \
  114.     /* Calculate absolute value of input and then store the result in the destination buffer. */
    # J* V7 n; y# e& i5 c  S8 q
  115.     *pDst++ = (in > 0) ? in : ((in == (q15_t) 0x8000) ? 0x7fff : -in);
    ' _3 W& {. t' M% U
  116. 0 {8 _+ ^3 }; ?3 {# G4 E
  117.     /* Decrement the loop counter *// ]4 V8 v4 q; N: O
  118.     blkCnt--;$ q1 `9 V! x% Y0 k5 N( x1 D
  119.   }
    & x/ v4 K0 h( ?  U  F4 J

  120. , K- a2 K0 k4 e0 r
  121. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
    ! a- N: S2 r7 n' \  h, }

  122. # L, M5 T8 b  L+ B
  123. }
复制代码
1. 对于Q15格式的数据,饱和运算会使得数据0x8000变成0x7fff。
2. __SIMD32_TYPE的定义在文件arm_math.h中,具体定义如下:
        #define __SIMD32_TYPE int32_t __packed
    SIMD就是咱们上期教程所将的单指令多数据流。简单的理解就是__SIMD32_TYPE就是定义了一个int32_t类型的数据,__packed的含义就是实现字节的对齐功能,方便两个16位数据的都存入到这个数据类型中。
3. 函数__SIMD32_CONST的定义如下:
    #define __SIMD32_CONST(addr)  ((__SIMD32_TYPE *)(addr))
4. 函数__PKHBT的定义在文件core_cm4_simd.h,定义如下:
    #define __PKHBT(ARG1,ARG2,ARG3)   ( ((((uint32_t)(ARG1)) ) & 0x0000FFFFUL) |  \
                                                          ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL) )
        这个宏定义的作用就是将将两个16位的数据合并成32位数据。但是有一点要特别说明__PKHBT也是CM4内核支持的SIMD指令,上面的宏定义的C函数会被MDK自动识别并调用相应的PKHBT指令。
        __QSUB16用于实现16位数据的饱和减法。
8.1.4 arm_abs_q7
    这个函数用于求8位定点数的绝对值,源代码分析如下:
  1. /**        8 t0 ~' l# W6 s( B& d# M3 U& q  l9 y
  2. * @brief Q7 vector absolute value.        
    0 i+ D3 c  c  l5 ?
  3. * @param[in]       *pSrc points to the input buffer        + g0 j' r: E9 X/ J" k. ~
  4. * @param[out]      *pDst points to the output buffer        
    " ?/ d& ^' R" q9 r2 }0 p4 p
  5. * @param[in]       blockSize number of samples in each vector          n" @/ F3 }  c& f" k
  6. * @return none.        
    & V+ V- j+ b1 ?# F# [; x* G
  7. *   
    , \% d& b6 w, |7 Z) G
  8. * \par Conditions for optimum performance    6 q* L0 _+ ?/ m. Y/ u3 X6 h
  9. *  Input and output buffers should be aligned by 32-bit   
    ) i; J5 S* L+ |. {
  10. *      Q* x% j+ |3 g/ r9 s
  11. *        
    ( [2 G' T0 `: a$ ]. S# d9 r
  12. * <b>Scaling and Overflow Behavior:</b>                                                             (1)
    " f$ N& G8 l, \8 Q
  13. * \par        8 f) O9 O+ D- K; _" Z
  14. * The function uses saturating arithmetic.        $ a3 G' @+ V4 |5 W. N- i
  15. * The Q7 value -1 (0x80) will be saturated to the maximum allowable positive value 0x7F.        
    " L8 |! \3 C7 B& \) J
  16. */
    ( t5 b* l3 |" _+ U9 X8 P3 A

  17. * f; w0 L4 `5 l& z3 {+ c. E
  18. void arm_abs_q7(
    , ?( s3 D2 q0 r' r
  19.   q7_t * pSrc,. W& ]- S- c0 _& E8 L! J2 g4 M, T
  20.   q7_t * pDst,
    : o; \. t' h( D% n0 c
  21.   uint32_t blockSize)
    " a' y3 ?; _. O7 Z2 L5 j5 ~
  22. {2 |- P5 v1 o3 G$ X' @/ h
  23.   uint32_t blkCnt;                               /* loop counter */! X$ _$ s5 g; c
  24.   q7_t in;                                       /* Input value1 */0 O! N& C: C0 p: \8 x8 Z

  25. - ~" w0 q0 a! ^% p& u+ j
  26. #ifndef ARM_MATH_CM0_FAMILY
    0 C+ T+ `) Y% E4 S

  27. 9 {6 R9 p5 Z: x3 P
  28.   /* Run the below code for Cortex-M4 and Cortex-M3 */: d* B: v' k+ d* h4 K9 H- ^" C4 v0 y: a
  29.   q31_t in1, in2, in3, in4;                      /* temporary input variables */+ n4 D/ J3 W5 \  t- T' d- V  s, Q* H
  30.   q31_t out1, out2, out3, out4;                  /* temporary output variables */
    6 p& ]6 I$ s- h% j# j
  31. - H+ I% E0 F4 a/ M3 r9 h& K/ |6 _" _7 X
  32.   /*loop Unrolling */" f0 v, N& p3 [0 F, E% N2 b
  33.   blkCnt = blockSize >> 2u;
      B& F6 W" ~+ S+ x

  34. 3 e! l; N/ K0 X, V5 k
  35.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.    5 a0 J4 A8 h- P, v
  36.    ** a second loop below computes the remaining 1 to 3 samples. */
    / q+ Z# e4 e9 J6 A5 B, G9 [6 F9 `
  37.   while(blkCnt > 0u)* I' R( V; {$ R- Y! i& }% Z
  38.   {
    ( {3 @+ C* N0 t% q" {
  39.     /* C = |A| */  i8 D5 h! f( S5 D
  40.     /* Read inputs */: J3 d& H; e, i/ T
  41.     in1 = (q31_t) * pSrc;
    + `7 p$ H* ?1 ]- ^! g1 H; r
  42.     in2 = (q31_t) * (pSrc + 1);' q! |+ Z/ |; H1 z
  43.     in3 = (q31_t) * (pSrc + 2);% V- N) y/ s- T% b" ~

  44. 5 w$ ?9 ?. T) z" F) O! O: S
  45.     /* find absolute value */
    + o. x7 T$ y2 m0 s4 J/ U6 x
  46.     out1 = (in1 > 0) ? in1 : (q31_t)__QSUB8(0, in1);                                                  (2)
    : Z: {+ E2 B) r+ J* l

  47. 9 u& X  s# _2 w) ]
  48.     /* read input */& U: |3 L# x3 i/ C& N1 @5 d
  49.     in4 = (q31_t) * (pSrc + 3);* k) z: g/ H$ O, G5 D

  50. ) p" K$ N& c$ V! o5 U+ }
  51.     /* find absolute value */+ T# i# M1 _7 m/ h3 d/ o
  52.     out2 = (in2 > 0) ? in2 : (q31_t)__QSUB8(0, in2);# M$ `/ S( Y& a( R; c
  53. : ~! {1 I; G" j! ^1 p  I
  54.     /* store result to destination */* W5 [" g: z& S: }5 E& l
  55.     *pDst = (q7_t) out1;' C" o$ u# @- o0 f' H
  56. 1 t2 Y+ q# j* [6 p, d+ F' s
  57.     /* find absolute value */
      B  ?! e8 r- j$ l$ S3 L
  58.     out3 = (in3 > 0) ? in3 : (q31_t)__QSUB8(0, in3);$ O  R% v+ _* g* Y( g3 f4 H5 _
  59. ! e) \7 D+ i8 {( ^; v: u# p
  60.     /* find absolute value */: L. J7 e3 q' ^# {
  61.     out4 = (in4 > 0) ? in4 : (q31_t)__QSUB8(0, in4);# }% y8 B; v7 {5 ^) _. x! B

  62. 0 d8 X% j7 Z# f! t  @: [
  63.     /* store result to destination */
    7 H' h) q' I! a. h
  64.     *(pDst + 1) = (q7_t) out2;) [0 i  C+ H7 I, b* k) \
  65. / y+ f( Z* A9 x5 V/ ^2 @- O2 G( C
  66.     /* store result to destination */8 d0 T+ C& f2 }# t3 o
  67.     *(pDst + 2) = (q7_t) out3;5 M9 n1 f) t, |1 N  L$ X, |
  68. 8 C/ G6 C7 r, e" f% K
  69.     /* store result to destination */
    # G2 ]( j* D# N& _
  70.     *(pDst + 3) = (q7_t) out4;" b. J; k/ _9 v9 ~
  71. : |: L. u: N9 E- R% D3 h
  72.     /* update pointers to process next samples */! M4 r* e0 e- \: ^5 p0 R) `! b; Z
  73.     pSrc += 4u;' n1 ?+ {/ ^! d0 ?4 h
  74.     pDst += 4u;4 R# `/ |: R: u1 ~3 y: [* x/ k

  75. - j% M( y2 d1 k$ w( {' |/ {1 y- _
  76.     /* Decrement the loop counter */( P# ?" ~. @- r( ?
  77.     blkCnt--;
    $ }2 {( K) J2 y; [% E
  78.   }
    5 H  l! e7 @0 {
  79. ; A) r  l. E1 P1 c* W( I! k1 {4 j
  80.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.    & K; k3 f; y. p7 @# |- n
  81.    ** No loop unrolling is used. */
    1 I1 C  t" ^+ B3 ], R
  82.   blkCnt = blockSize % 0x4u;
    6 u: W4 t1 ]6 e8 N8 s% |
  83. #else. v$ _. @4 {8 f- }% l

  84. 4 B9 v' W9 d3 K5 D+ T  J2 v
  85.   /* Run the below code for Cortex-M0 */: Z) D+ n; X4 h/ X! f7 Q
  86.   blkCnt = blockSize;
    ' e9 _$ `. p% _: s
  87. $ p# i1 l3 f+ m( ?  A! b- S: W& v
  88. #endif //      #define ARM_MATH_CM0_FAMILY/ A3 ^/ s6 x  K

  89. % e2 G8 M9 d. m( p
  90.   while(blkCnt > 0u)
    3 L  ^, B* _* i. a* n: F- q
  91.   {" e3 F( ~, v0 K( i' x% c( v% ~) W
  92.     /* C = |A| */' S/ N; z' d1 n! Y0 n( ?4 I% C2 y
  93.     /* Read the input */
    * W* F  L/ f) @# y, }1 [1 w! Y
  94.     in = *pSrc++;
    ! }+ U! b0 z7 @8 t- t( k6 M. F

  95. 0 H% H$ Y2 z: Y- B" J: u- m
  96.     /* Store the Absolute result in the destination buffer */
    ! ~% G3 M; h5 r  L' I9 f7 [
  97.     *pDst++ = (in > 0) ? in : ((in == (q7_t) 0x80) ? 0x7f : -in);
    3 Q4 I  {$ @8 H

  98. 8 F# f) @2 g' g( O7 ^
  99.     /* Decrement the loop counter */* J( d3 A/ d# ~$ d0 O! _; k
  100.     blkCnt--;
    , u2 w4 Y1 b* t. M6 X* n) H3 o6 m
  101.   }) Q( S/ B7 B; X2 Q
  102. }
复制代码
1. 由于饱和运算,0x80求绝对值将变成数据0x7F。
2. __QSUB8用以实现8位数的饱和减法运算。
8.1.5 实例讲解
实验目的:
    1. 四种数据类型数据绝对值求解
实验内容:
    1. 按下按键K1, 串口打印输出结果
实验现象:
        通过窗口上位机软件SecureCRT(V5光盘里面有此软件)查看打印信息现象如下:
8.1.png
程序设计:
  1. /*
    # \8 H2 K. K" {3 S" a, [/ V
  2. *********************************************************************************************************$ r+ J' Q# s+ B+ H1 a! Y1 h- S+ a% r
  3. *        函 数 名: DSP_ABS6 O/ S. v: Z, B; [
  4. *        功能说明: 求绝对值* _% j) G+ ]; q# v: c
  5. *        形    参:无. M- P  h' d. z1 |# z
  6. *        返 回 值: 无
    ! c) V& w$ g* ~2 a3 r( N
  7. *********************************************************************************************************
    $ j" U  U- a9 M) ^! |
  8. */, V* f& d0 p$ E* Q
  9. static void DSP_ABS(void)
    2 c3 B! b  {1 u* a' i
  10. {
    , d7 c! l8 W( K* |9 g! ~( t
  11. static float32_t pSrc;) |$ Q& ^( p3 w  _3 J0 b
  12.     static float32_t pDst;
    * z$ v' t: J$ }& M% N6 T
  13. static q31_t pSrc1;5 H% D+ K% r, F, e& |7 |/ w" e2 j
  14. static q31_t pDst1;% s" q. L7 L- a1 @
  15. static q15_t pSrc2;
    6 Q: R/ L! T4 A2 s) g
  16. static q15_t pDst2;
    6 \" k% M, r& J7 O" b1 T
  17. static q7_t pSrc3 = 127; /* 为了说明问题,在这里设置初始值为127,然后查看0x80是否饱和为0x7F */0 C) v0 Z: T6 Q, Y+ _( h
  18. static q7_t pDst3;% @0 r+ Q) U/ t, X
  19. pSrc -= 1.23f;( Q% j; P0 G; y+ ~
  20. arm_abs_f32(&pSrc, &pDst, 1);                                                                    (1)  Z. G7 J( @& ~" T* n. i$ w
  21. printf("arm_abs_f32 = %f\r\n", pDst);
    9 W9 M( m- I4 B' H
  22. 6 `3 x: g+ A2 M* G& F7 n
  23. pSrc1 -= 1;  Y0 G7 `; Z! Q' k! G' f
  24. arm_abs_q31(&pSrc1, &pDst1, 1);                                                                  (2)
    7 j7 L9 t4 o) M$ S6 @
  25. printf("arm_abs_q31 = %d\r\n", pDst1);" Z; N  h  ]' A# p
  26. % [( Q- k- W* Q, J
  27. pSrc2 -= 1;9 C# |2 e1 k$ l. h0 a* W2 \
  28. arm_abs_q15(&pSrc2, &pDst2, 1);                                                                  (3)
      ~, [7 i# O8 M. x4 n, D
  29. printf("arm_abs_q15 = %d\r\n", pDst2);( q* U+ x. P# c5 ]+ @

  30. 7 }9 u( K# ]* @. L5 u( K& ?
  31. pSrc3 += 1;
    / s3 Z) z# y/ b/ B
  32. printf("pSrc3 = %d\r\n", pSrc3);
    + @  f4 X- J8 x% u
  33. arm_abs_q7(&pSrc3, &pDst3, 1);                                                                   (4)$ L" c1 W! g. I2 n1 A
  34. printf("arm_abs_q7 = %d\r\n", pDst3);
    $ p8 [- e. x9 @7 L% M9 k
  35. printf("***********************************\r\n");
    " s5 a; {) o' ~7 W; @4 x
  36. }
复制代码
(1)到(4)实现相应格式下绝对值的求解。这里只求了一个数,大家可以尝试求解一个数组的绝对值。
( \8 I/ E9 c) q' Q5 Q3 t8 U+ q" W
赞 收藏 评论5 发布时间:2015-3-18 11:33

举报

5个回答
baiyongbin2009 回答时间:2015-3-18 11:42:14
8.3 点乘(Vector Dot Product)
    这部分函数主要用于点乘,公式描述如下:
     sum = pSrcA[0]*pSrcB[0] + pSrcA[1]*pSrcB[1] + ... + pSrcA[blockSize-1]*pSrcB[blockSize-1]
8.3.1 arm_dot_prod_f32
    这个函数用于求32位浮点数的点乘,源代码分析如下:
  1. /**1 J! H9 [' _, y/ ?
  2. * @defgroup dot_prod Vector Dot Product! F4 L9 t; A* w! p8 A; p/ \
  3. *  v3 w3 K6 J: c
  4. * Computes the dot product of two vectors.
    6 \) H5 m7 A1 e3 y! |( Y& ^: j
  5. * The vectors are multiplied element-by-element and then summed.
    & m2 V7 F5 ^1 B3 D/ |7 A
  6. *$ Z1 O" g; E! J
  7. * <pre>
    3 J# q" e0 a; @
  8. *     sum = pSrcA[0]*pSrcB[0] + pSrcA[1]*pSrcB[1] + ... + pSrcA[blockSize-1]*pSrcB[blockSize-1]
    + @/ @" h0 @8 [* D8 l7 Y! d
  9. * </pre>     
    & g. e0 a8 ]& N# }# I$ R. k
  10. *
    / Y* n6 \' @- \. J
  11. * There are separate functions for floating-point, Q7, Q15, and Q31 data types.    0 k1 q; M  R" a' X. I5 h
  12. */) r; j: O2 j6 w( s" z

  13. " H" ]7 k# {0 F: f. B% U" {- p
  14. /**    + Q& m, C, P' A. `4 A/ z
  15. * @addtogroup dot_prod   
    4 L+ `% W+ ^5 [; N! y
  16. * @{   
    . Z! o4 V& y. d2 k) S: ]1 a, Q
  17. */2 p9 M  O4 S9 I) L9 q. u

  18. 0 v9 c/ x( @# J( G3 j
  19. /**    1 C% F) J. F0 L* {, k
  20. * @brief Dot product of floating-point vectors.   
    1 ~4 ]" {8 r2 v
  21. * @param[in]       *pSrcA points to the first input vector    1 P6 L1 t( d$ }5 i
  22. * @param[in]       *pSrcB points to the second input vector   
    * R! O& q3 q  |. B+ W
  23. * @param[in]       blockSize number of samples in each vector    / B9 F, U, w9 o$ g* Y' q
  24. * @param[out]      *result output result returned here    3 u' I2 h4 C  S; s( D* u
  25. * @return none.    8 S6 D8 L2 t# B* J  y2 x
  26. */' G/ U  A5 J  b* C% D% p
  27. . M( y" B7 F; k$ O+ Y5 f4 A

  28. ( n8 ^/ K1 |2 I8 e1 s: T" v5 G7 Z
  29. void arm_dot_prod_f32(
    : Y# A. b- C/ y1 t6 \
  30.   float32_t * pSrcA,
    6 C9 w# b; \+ M) a7 ?3 I, q
  31.   float32_t * pSrcB,
    * z6 Q7 s0 H' d4 v$ m- z0 {: ^% ^& K
  32.   uint32_t blockSize,
    # [( |. b6 l8 [6 D. l
  33.   float32_t * result)
      U: X; X/ {+ J& Z% g( W5 Y
  34. {3 J6 j, W. s! _" J
  35.   float32_t sum = 0.0f;                          /* Temporary result storage */                      (1)2 r8 o3 r9 y3 t; N' F+ J
  36.   uint32_t blkCnt;                               /* loop counter */
    , ?; g3 N" ?1 L
  37. 3 l* g& H& [. H, I2 \3 z( ~
  38. , k; ?3 @' E: A: `/ B0 a9 p* p
  39. #ifndef ARM_MATH_CM0_FAMILY
    4 g* Y$ t5 b" @8 e
  40. & q# ?1 ^2 R" Y& E4 n: @! O
  41. /* Run the below code for Cortex-M4 and Cortex-M3 */; S2 l+ q4 J& a7 ^
  42.   /*loop Unrolling */% N  P9 {" F! D! p1 l- i0 Q
  43.   blkCnt = blockSize >> 2u;8 j  _6 C  t, [7 V

  44.   j0 d/ P* y- u! e
  45.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
    / W. [0 u) E) J9 W; g
  46.    ** a second loop below computes the remaining 1 to 3 samples. */
    : ~. P- W$ L- j' U, G
  47.   while(blkCnt > 0u)9 R' B5 X- w' \/ |; Q# s
  48.   {
    & ?* h5 x6 X. b3 G; ~0 [  Q# x( P
  49.     /* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */) j$ ]7 \; q# M
  50.     /* Calculate dot product and then store the result in a temporary buffer */
    " j3 p$ F. f: @
  51.     sum += (*pSrcA++) * (*pSrcB++);                                                                  (2)8 U+ C8 S# E3 `) v) P7 b) c1 |4 L2 |% q
  52.     sum += (*pSrcA++) * (*pSrcB++);
    : r8 b5 a4 {; _) ?: s/ }+ L
  53.     sum += (*pSrcA++) * (*pSrcB++);1 I, G" O  H  h' ?2 J
  54.     sum += (*pSrcA++) * (*pSrcB++);
    ( ^3 R5 v3 {. V6 w# J4 R
  55. 5 w8 i5 L) j" O9 i
  56.     /* Decrement the loop counter */! f& _& v, H% l, [$ e6 U* [& Z! y; G! |
  57.     blkCnt--;- `. I2 ~9 f4 b
  58.   }3 B1 `* V3 i- s
  59. 2 s4 B* T8 s- L
  60.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
    9 ^, A9 _  }% {
  61.    ** No loop unrolling is used. */
    ' {$ k: M4 Q8 U" |1 R' s2 C
  62.   blkCnt = blockSize % 0x4u;
    3 l0 y  Z$ R+ h( @5 b; S( S% n
  63. . d' h% D) s0 B& x+ V6 K9 P2 O
  64. #else
    2 j! s& T6 c! L/ w% Z

  65. : H9 g) u, \3 o. ]; T
  66.   /* Run the below code for Cortex-M0 */
    9 Y/ F, ]+ ?& q- i& g1 ^+ c4 x

  67. 8 `# L4 o! d! g, N6 P
  68.   /* Initialize blkCnt with number of samples */
    4 y. p. ?3 Q, Z  ~% l
  69.   blkCnt = blockSize;
    / T" _3 p* h1 J4 _3 s. k1 z% m# {
  70. " [$ o' B  i& Q( _$ ?
  71. #endif /* #ifndef ARM_MATH_CM0_FAMILY */7 B: \4 U& f( ~2 j! |
  72. ! h8 j, c, k, p+ o7 H: X

  73. 2 @3 G: x$ e; V+ ?- W% u5 C8 `6 G
  74.   while(blkCnt > 0u)6 r4 H" A2 t; m/ m! D0 n- c
  75.   {4 [) ^3 U6 ]4 \- O8 k4 n/ s$ c
  76.     /* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */6 n* G2 M$ q) d
  77.     /* Calculate dot product and then store the result in a temporary buffer. */8 M. c* Y, ]* N  O- |
  78.     sum += (*pSrcA++) * (*pSrcB++);
    5 s1 Y2 N6 v( m# V- s" h
  79. , K* d' a& s" ]2 N* [+ t; @* m
  80.     /* Decrement the loop counter *// ~3 {% Q  I$ T% x2 x- u7 v
  81.     blkCnt--;
    9 q+ Y& }7 T6 f9 P5 d
  82.   }( i! W! ?, L$ T9 P
  83.   /* Store the result back in the destination buffer */) [# `, O; X) x2 I; l3 m9 F
  84.   *result = sum;
      u& }# ^/ S0 v
  85. }
复制代码
1. 由于CM4上带的FPU是单精度的,所以初始化float32_t类型的浮点数时需要在数据的末尾加上f。
2. 类似函数sum += (*pSrcA++) * (*pSrcB++)最终会通过浮点的MAC(乘累加)实现,从而加快执行时间。
8.3.2 arm_dot_prod_q31
    这个函数用于求32位定点数的点乘,源代码分析如下:
  1. /**    * `4 [4 R1 t/ ?3 T; D6 I- a
  2. * @brief Dot product of Q31 vectors.      E; T1 l3 y4 b# b- ]6 N
  3. * @param[in]       *pSrcA points to the first input vector   
    0 F0 E8 [; l" C+ t3 n, r
  4. * @param[in]       *pSrcB points to the second input vector   
    . G5 |8 Y6 K9 Q& L, ^) R9 i$ I7 l
  5. * @param[in]       blockSize number of samples in each vector    8 N  m5 q2 h0 W8 r; ^2 N
  6. * @param[out]      *result output result returned here    + s8 L% q/ }; r" C6 \# G
  7. * @return none.   
    : v: d8 M7 m3 p; k: q( b  M
  8. *   
    7 v. e; N1 A7 `* ]
  9. * <b>Scaling and Overflow Behavior:</b>                                                              (1)1 I# V  i8 f$ n% s3 `, R
  10. * \par   
    4 _# ?, I- u; J
  11. * The intermediate multiplications are in 1.31 x 1.31 = 2.62 format and these   
    5 _/ W# ^! H  ?9 `9 M$ X, c) Y
  12. * are truncated to 2.48 format by discarding the lower 14 bits.    : b/ a0 s, Z; Q# ?0 B
  13. * The 2.48 result is then added without saturation to a 64-bit accumulator in 16.48 format.   
      z& W; ^0 l( X' w. y$ c+ ~/ [2 J
  14. * There are 15 guard bits in the accumulator and there is no risk of overflow as long as   
    / {, X5 U' M' c) v1 ^) [% r
  15. * the length of the vectors is less than 2^16 elements.    / S6 h' ], I4 q9 o- b1 x
  16. * The return result is in 16.48 format.   
    - N/ d% }5 K$ L2 m. p; ?1 [2 f
  17. */; B7 o/ \6 r8 o. S) L- T
  18. 2 P' X- ?9 z$ f  f
  19. void arm_dot_prod_q31(
    5 F) A/ Q* k( F. Z( s
  20.   q31_t * pSrcA,
    2 q( h4 i7 R- m; o$ j3 ]3 T
  21.   q31_t * pSrcB,
    , Y- N6 Y8 d$ _- {
  22.   uint32_t blockSize,
    " Q) _! G5 ^% C7 L  Y
  23.   q63_t * result)4 C9 W2 Q& k) k0 R  C1 X! o+ i
  24. {
    7 n+ i, {+ G5 a( ?! z4 B
  25.   q63_t sum = 0;                                 /* Temporary result storage */" o5 Z% H5 n- l* D5 o
  26.   uint32_t blkCnt;                               /* loop counter */9 Q: I, R1 d6 a% \5 T* d
  27. ' X/ R2 {1 u* w& j# T8 q$ t
  28. : X/ Z) E3 Z7 R. e
  29. #ifndef ARM_MATH_CM0_FAMILY
    $ p# a9 f# v  `: r7 B

  30. 1 N( w5 Z3 _8 K0 o& t) |
  31. /* Run the below code for Cortex-M4 and Cortex-M3 */
    $ R* [$ Q) }& x0 T! f' S' T
  32.   q31_t inA1, inA2, inA3, inA4;3 u0 }0 _, B" H- d3 v6 R; c9 W
  33.   q31_t inB1, inB2, inB3, inB4;5 I" n7 Z4 M! K' k- c

  34. 4 T$ ~  e4 ?! u& ~4 V8 k) ?
  35.   /*loop Unrolling */; @/ F5 ^9 q9 S: K3 a2 x3 h
  36.   blkCnt = blockSize >> 2u;
    & L5 o3 v+ e8 U
  37. : x+ l, x5 [5 V( o* A
  38.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
    & u2 c  p' y) U2 A+ {
  39.    ** a second loop below computes the remaining 1 to 3 samples. */6 Z( ]# Q. |7 l' m$ y* w. G
  40.   while(blkCnt > 0u)
    + b4 ^/ `; c9 ?( F4 }
  41.   {
    - E; q5 m( ~6 _/ H9 a% u
  42.     /* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */
    2 I  q$ q% v! k( Q0 M
  43.     /* Calculate dot product and then store the result in a temporary buffer. */
    " [$ V, O. L  V* e+ _( P
  44.     inA1 = *pSrcA++;: x) k$ M! V8 i! f# @- M: \) [
  45.     inA2 = *pSrcA++;
    . N* ~' e+ v. q! C
  46.     inA3 = *pSrcA++;4 R4 i- K) ], _2 U. v$ C
  47.     inA4 = *pSrcA++;
    6 g$ Z$ T# T8 \" p1 U& y0 y' F
  48.     inB1 = *pSrcB++;  \, k. ?, H: V
  49.     inB2 = *pSrcB++;# \" b2 r. q) I0 B- w
  50.     inB3 = *pSrcB++;) U7 q5 ~1 u  h
  51.     inB4 = *pSrcB++;" _- Y4 J7 o* [. k  n" x
  52. 2 Y% o/ ~$ Q2 M& z0 F7 r
  53.     sum += ((q63_t) inA1 * inB1) >> 14u;                                                               (2)8 D' i+ ]- Q2 t# I0 a3 i9 F& Q
  54.     sum += ((q63_t) inA2 * inB2) >> 14u;
    & M) J7 u- R/ I. L# M9 y* K
  55.     sum += ((q63_t) inA3 * inB3) >> 14u;
    4 v. i8 s1 {; P# r+ \( }  X1 q
  56.     sum += ((q63_t) inA4 * inB4) >> 14u;4 U5 `; m. H6 k( y# M
  57. 4 k  U  Q1 c% v. {( p0 H+ W
  58.     /* Decrement the loop counter */3 p2 U& b: k; Z8 Z% o
  59.     blkCnt--;- B9 D' t) h0 R' ]/ O
  60.   }; @* T/ G* P( j) S) R# V7 T- O

  61. 7 z* q& a* Y$ `5 r
  62.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
    # E7 s8 |$ @. ?' \/ ~) p. Y
  63.    ** No loop unrolling is used. */
    8 A+ ~  A8 s# A
  64.   blkCnt = blockSize % 0x4u;
    . b$ M+ u( b6 Y/ Q/ S$ {6 L  }

  65. * X/ J0 r" A. G, h& S" u& M7 ~* ]
  66. #else" t) u8 n4 n  v7 {+ ^& w
  67. $ P7 A. Z* ^1 I9 m( Z" Y, \* [
  68.   /* Run the below code for Cortex-M0 */
    - Q/ W5 L) R0 r/ ^/ w
  69. " q3 X' e) n4 u8 K% F9 m
  70.   /* Initialize blkCnt with number of samples */0 D* a3 I; t/ w5 h0 U  G: I
  71.   blkCnt = blockSize;  a1 W9 Y7 H% \. H# p% u& O

  72. . M4 N, i1 E8 r4 g7 d: Z
  73. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
    8 g5 |2 x) t. p# W

  74. ) r5 G- w9 s/ m& Q+ v; U3 d

  75. 9 J/ \5 D( Y. |/ r" l# e6 H
  76.   while(blkCnt > 0u), X) u5 c- ?6 t
  77.   {
    % H: n1 J/ a9 {" q
  78.     /* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */4 k( y/ w: X8 y! K/ A2 U
  79.     /* Calculate dot product and then store the result in a temporary buffer. */) x$ Z( A$ h- e; m# N
  80.     sum += ((q63_t) * pSrcA++ * *pSrcB++) >> 14u;" P8 C. r, O# V- x: D, ?

  81. : d- k! Z9 T1 e) h
  82.     /* Decrement the loop counter */  H; L$ e0 K2 t3 O" G$ h
  83.     blkCnt--;6 P8 W! @0 h( R, Z! I, a6 d; `8 w
  84.   }
    , C9 V2 Q2 E. v+ G6 H  s2 U3 h

  85. 5 R0 }$ x2 R9 X: f$ V4 ]* I/ ]+ H
  86.   /* Store the result in the destination buffer in 16.48 format */
    6 p  j4 `0 q3 `% Q1 O, d0 m
  87.   *result = sum;2 O% q! F# H" M; O
  88. }
复制代码
1. 两个Q31格式的32位数相乘,那么输出结果的格式是1.31*1.31 = 2.62。实际应用中基本不需要这么高的精度,这个函数将低14位的数据截取掉,反应在函数中就是两个数的乘积左移14位,也就是定点数的小数点也左移14位,那么最终的结果的格式是16.48。所以只要乘累加的个数小于2^16就没有输出结果溢出的危险(不知道这里为什么不是2^14,留作以后解决)。
2. 将获取的结果左移14位。
8.3.3 arm_dot_prod_q15
    这个函数用于求16位定点数的点乘,源代码分析如下:
  1. /**    # B/ Y/ l' ^+ ~  U
  2. * @brief Dot product of Q15 vectors.   
    " k8 S- w, t$ y, `% L; f) j* N
  3. * @param[in]       *pSrcA points to the first input vector    8 d8 I+ ?, f3 p9 p
  4. * @param[in]       *pSrcB points to the second input vector   
    7 W. M1 k* {1 i# q1 H; ^; c- n
  5. * @param[in]       blockSize number of samples in each vector    ! ~8 \) M; g% o4 a% h% V, Q
  6. * @param[out]      *result output result returned here   
    0 s( o0 _$ a5 D# P+ V4 o
  7. * @return none.   
    # x% r& X' p0 V
  8. *    - G* S- b+ z; L
  9. * <b>Scaling and Overflow Behavior:</b>                                                             (1)
    2 J9 L4 q( d+ }& O
  10. * \par    " u/ |2 R! ^' O# G! R
  11. * The intermediate multiplications are in 1.15 x 1.15 = 2.30 format and these   
    ' M: C% X6 g2 v
  12. * results are added to a 64-bit accumulator in 34.30 format.   
      K: e. m) M- f. o  |8 `6 L
  13. * Nonsaturating additions are used and given that there are 33 guard bits in the accumulator    - v0 r% a& V- b$ U( T
  14. * there is no risk of overflow.   
    " x$ O4 m- l, ^' K4 l; Q" ?! b
  15. * The return result is in 34.30 format.    , F- v1 K, a( g7 ]' R; u. ?
  16. */
    3 ]! {- W4 Z7 f/ R! T* E
  17. - ^8 k& Y( c% h. R
  18. void arm_dot_prod_q15(
    : ~" T& v, f$ [! j2 G' T$ @
  19.   q15_t * pSrcA,7 l" P6 n" J, n% b! `' a% p" W
  20.   q15_t * pSrcB,9 h( P4 m) {9 f9 p
  21.   uint32_t blockSize," g: }: I$ A, T0 d
  22.   q63_t * result)
    ( X$ [( S$ E8 ]
  23. {
    % n, l, j( \  S& x9 j$ E4 C
  24.   q63_t sum = 0;                                 /* Temporary result storage */( Q( m# V3 x6 ~+ e3 N' v$ U) V
  25.   uint32_t blkCnt;                               /* loop counter */
    6 K6 d- _3 F7 w! _
  26. 0 Z% I$ I/ U% e$ J7 z. f5 {
  27. #ifndef ARM_MATH_CM0_FAMILY! s3 M8 w. F3 Z4 |

  28.   |5 M* h6 I5 L8 t" N% [* m# C6 |
  29. /* Run the below code for Cortex-M4 and Cortex-M3 */$ {, a+ C, z; e+ H* r- }5 @( |
  30. 5 H7 F3 X% U8 L9 o4 w
  31. 5 `1 d7 _. B4 d, l5 a" B
  32.   /*loop Unrolling */( y5 v/ h+ j: @7 y! O
  33.   blkCnt = blockSize >> 2u;+ G8 [+ M; a; r0 X# o+ \1 F
  34. + N& a3 m$ e, e% N9 X
  35.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
    5 [- N7 C6 w9 e, l
  36.    ** a second loop below computes the remaining 1 to 3 samples. */
    3 I% w* K. n; J' e
  37.   while(blkCnt > 0u)
    5 x: S" h7 C" s9 B& V; g9 u9 f& b& i, E
  38.   {
    . q+ e- t8 Y* M1 ~4 D" W
  39.     /* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */           (2)2 A+ z1 \: Z+ w; V% z1 n
  40.     /* Calculate dot product and then store the result in a temporary buffer. */
    5 C: u( U& s* y' P. V
  41.     sum = __SMLALD(*__SIMD32(pSrcA)++, *__SIMD32(pSrcB)++, sum);( \6 J$ A, \- D9 g5 a; S
  42.     sum = __SMLALD(*__SIMD32(pSrcA)++, *__SIMD32(pSrcB)++, sum);( I6 V2 f" ^; H0 ]! h  V

  43. % g( K' ]# w* B1 ^) T* c
  44.     /* Decrement the loop counter */# |* L2 {4 [- Q3 w$ h
  45.     blkCnt--;1 E2 H$ \5 m! ]3 L: a6 z# M* u
  46.   }$ r( h9 x% Z7 M0 m# }+ ^2 f
  47. # z5 G" n8 c2 J' F
  48.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
    1 H! ^( @: n7 u0 ~' a
  49.    ** No loop unrolling is used. */
    ' B  u( g- g. l) t
  50.   blkCnt = blockSize % 0x4u;
    % T$ p+ w7 N1 |% _% e
  51. : U. L  b4 |1 I! B3 n
  52.   while(blkCnt > 0u)
    2 g/ `" F+ S* T" m6 ~
  53.   {
    4 Z8 u4 x2 B9 A" H' R7 v
  54.     /* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */8 |, n$ C9 A* S
  55.     /* Calculate dot product and then store the results in a temporary buffer. */* S' h5 f. ~3 k
  56.     sum = __SMLALD(*pSrcA++, *pSrcB++, sum);! D! K9 o, x+ q2 T
  57. # k$ V$ `1 R: X: l$ l
  58.     /* Decrement the loop counter */( c: \) K" O2 a( W8 a
  59.     blkCnt--;% b& U( f$ m  D+ b0 n
  60.   }1 @* w6 w- ^) N

  61. / o6 G7 @% U" C  a$ A3 ^- `) j
  62. / A9 u; W/ ^0 A" C# l  S
  63. #else- G+ i% u( m& Q$ ^3 u4 G- ?
  64.   J7 d  \& m+ U
  65.   /* Run the below code for Cortex-M0 */
    " @. f$ E7 @7 t5 A. z

  66. % ]2 N9 {- l; O5 K1 H' J9 l- `3 o
  67.   /* Initialize blkCnt with number of samples */
    . P9 E  `9 z4 @# s% J( v
  68.   blkCnt = blockSize;
    . K! M: K7 I# ^( z( _6 A; e5 I+ Y

  69. ' J; f5 f; v( w* A6 m
  70.   while(blkCnt > 0u)0 Q3 E' L' ^' X6 Z
  71.   {
    6 h5 }; d. E9 M1 n- d$ p/ D
  72.     /* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */
    ) M, i/ E8 y% y9 r2 c) V1 R# ]3 [
  73.     /* Calculate dot product and then store the results in a temporary buffer. */
    6 D  N' c  R/ X, r  k& p
  74.     sum += (q63_t) ((q31_t) * pSrcA++ * *pSrcB++);7 R) O# t8 [4 e5 k2 J7 r
  75. ) X) F% c; a8 y. e( A3 x0 ?
  76.     /* Decrement the loop counter */; c$ c# k; X4 L; x0 u
  77.     blkCnt--;2 ~( A2 z+ g& X! i" t( V- ]
  78.   }) D- x% L$ j9 I$ E1 S/ F* O7 A" O

  79. , D& w0 o. p/ r- F8 R! Y
  80. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
    ' r* Y- T; W- M

  81. # ^% i9 M5 l' ^* C
  82.   /* Store the result in the destination buffer in 34.30 format */
    7 D$ n1 X, N' u" Z  ^) \7 ]
  83.   *result = sum;4 f2 x: y7 E. G; V
  84. 3 F% y( J8 G  S' X1 j0 z, Z
  85. }
复制代码
1. 两个Q15格式的数据相乘,那么输出结果的格式是1.15*1.15 = 2.30,这个函数将输出结果赋值给了64位变量,那么输出结果就是34.30格式。所以基本没有溢出的危险。
2. __SMLALD也是SIMD指令,实现两个16位数相乘,并把结果累加给64位变量。
8.3.4 arm_dot_prod_q7
    这个函数用于求8位定点数的点乘,源代码分析如下:
  1. /**   
    ( m$ d  g( H% z& m, s
  2. * @brief Dot product of Q7 vectors.    . t5 e" U: F" F
  3. * @param[in]       *pSrcA points to the first input vector    + `0 }% n4 [- k! ]) U# n. u( c( M2 i
  4. * @param[in]       *pSrcB points to the second input vector   
    : X+ S# A, M& S: t9 L
  5. * @param[in]       blockSize number of samples in each vector    / N$ S0 l# G" b8 b' G+ _
  6. * @param[out]      *result output result returned here   
    7 q% J0 z0 ^1 T! y# e
  7. * @return none.    7 Z5 G% g4 {+ n% Q9 I. r
  8. *    * M% u" y  |2 r5 k$ [7 n, b8 ^' T
  9. * <b>Scaling and Overflow Behavior:</b>                                                              (1)
    ' p$ p8 o4 ]! M
  10. * \par   
    ( q% _* A: W9 R, f7 _5 @/ x
  11. * The intermediate multiplications are in 1.7 x 1.7 = 2.14 format and these   
    ) w# G1 K/ B/ b3 N
  12. * results are added to an accumulator in 18.14 format.   
    - T% M5 x0 b" F# u
  13. * Nonsaturating additions are used and there is no danger of wrap around as long as    + n) O" ^& H3 a) m
  14. * the vectors are less than 2^18 elements long.    " I. |4 k5 J& ~8 R) L. \
  15. * The return result is in 18.14 format.    6 T" A' ?# g" K3 ^' z2 w
  16. */% z* P0 T+ \; a: l0 Z

  17. ( c$ M( F6 a- h, K+ L% t
  18. void arm_dot_prod_q7(7 O% \# o9 H) d# A: j9 I
  19.   q7_t * pSrcA,4 w4 G0 s' W  k" o9 Z
  20.   q7_t * pSrcB,6 n1 f5 N5 \4 {) Q) D# U
  21.   uint32_t blockSize,
    * m  i  [' U# _& ]) P0 I. |" g
  22.   q31_t * result)! [3 z; |' \! V# k- Z. i0 n/ `
  23. {/ }7 Q) E! b. b3 A. L7 V
  24.   uint32_t blkCnt;                               /* loop counter */
    % A0 T' J+ C0 o( y2 Q: b! y/ j

  25. / U5 r* ~/ o$ p5 R4 C! O: w
  26.   q31_t sum = 0;                                 /* Temporary variables to store output */+ Z# x& Q4 z! T9 L( P
  27. 7 a  D. c+ k; c+ Q
  28. #ifndef ARM_MATH_CM0_FAMILY
    4 D8 T  S( b% j2 I

  29. 0 w+ Y4 [7 ~( u/ o
  30. /* Run the below code for Cortex-M4 and Cortex-M3 */
    ; A% [$ R/ m' T5 p8 ?! _

  31. 3 X) ~$ ]: i1 i  e7 B
  32.   q31_t input1, input2;                          /* Temporary variables to store input */
    : S# g# M5 @  A! _) Z  @7 ~
  33.   q31_t inA1, inA2, inB1, inB2;                  /* Temporary variables to store input */
    1 C# K: t1 P4 R3 n# s
  34. / h2 [7 Z. b3 N7 w% x- [5 Q

  35. 3 D" {$ S, y$ T1 D. k0 G
  36. 3 D: C- F5 d$ e7 S  L
  37.   /*loop Unrolling */
    5 w: f! V3 p: T
  38.   blkCnt = blockSize >> 2u;
    7 p5 X* Z6 K  l$ L; L

  39. ) n$ r; |0 a8 v+ {# r3 Q
  40.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.    , |$ b) P, e' s5 X4 h7 A3 Y9 I4 z- a
  41.    ** a second loop below computes the remaining 1 to 3 samples. */
    8 `$ k! U, n9 K3 T! x
  42.   while(blkCnt > 0u)% I0 u- ~/ j8 n! y
  43.   {* x4 N" w9 _1 j8 Q, ], |: ^
  44.     /* read 4 samples at a time from sourceA */                                                       (2)# C: }6 I+ F. s/ y7 x
  45.     input1 = *__SIMD32(pSrcA)++;  j$ g( B3 H' \8 W4 k
  46.     /* read 4 samples at a time from sourceB */
    8 A, t6 W- t* V, T& ^
  47.     input2 = *__SIMD32(pSrcB)++;
    % U  H" I  W0 L9 S" I( h
  48. 0 o7 c9 l9 }9 u4 ?5 y& G
  49.     /* extract two q7_t samples to q15_t samples */* U! k5 {! z" A
  50.     inA1 = __SXTB16(__ROR(input1, 8));                                                                (3)
    8 U. n" M9 k4 H" S- Z7 I6 W5 {
  51.     /* extract reminaing two samples */
    & e1 C  A" q) D7 P& h3 z
  52.     inA2 = __SXTB16(input1);/ ?$ q* L% d2 ?1 Z/ L$ n8 D8 h% p
  53.     /* extract two q7_t samples to q15_t samples */. j' V% u& b' m8 Y% E' d! y/ {
  54.     inB1 = __SXTB16(__ROR(input2, 8));
    + z# \% I/ i# f
  55.     /* extract reminaing two samples */
    % R8 w' r! H& r& Z1 B3 ?% f
  56.     inB2 = __SXTB16(input2);9 J6 _* K" \- i- n

  57. $ S& M" I3 c5 l; B9 z- t$ ]6 p% v+ E2 \
  58.     /* multiply and accumulate two samples at a time */+ M; ?) t0 _+ G9 L+ y
  59.     sum = __SMLAD(inA1, inB1, sum);                                                                   (4)1 D6 n  n  g* D# T7 |; N" m$ k# A( z' `  B
  60.     sum = __SMLAD(inA2, inB2, sum);
    - C+ ]# l$ P3 x  M7 o# G- }

  61. 4 n: r# ?6 e( U) c
  62.     /* Decrement the loop counter */
    ' E/ I1 m% E0 Q& q  v- z+ x
  63.     blkCnt--;
    / H6 f1 z0 o) g) m2 K
  64.   }
    " j! C! n) v$ C- X

  65. * b2 r" p- u- ]) u5 J3 |1 N1 C& l5 N
  66.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.    , S4 m7 X1 P8 c
  67.    ** No loop unrolling is used. */' n# X5 L, w3 D9 ?3 j$ I8 o- U
  68.   blkCnt = blockSize % 0x4u;
    & X+ o6 A4 |- V4 R0 @) c
  69. - S9 Q6 J- _  N; u
  70.   while(blkCnt > 0u)' ~; F: }- A4 }+ V' L
  71.   {" `; U2 y8 r5 T5 z
  72.     /* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */. H( T' K/ A5 E" x" e/ f4 ?7 K! x
  73.     /* Dot product and then store the results in a temporary buffer. */& b% h; o" E" h0 n$ }- s
  74.     sum = __SMLAD(*pSrcA++, *pSrcB++, sum);7 {& b- i2 P3 H1 G
  75. 7 Z1 f6 j( ~& }3 g) F8 [
  76.     /* Decrement the loop counter */
    ( N2 t2 N2 T2 f5 K8 J  r, \
  77.     blkCnt--;
    9 s; W) F7 b! f/ v, p  u
  78.   }* N' a* z/ B: z' ^* @2 M

  79. + u# }) ]2 h$ g7 o7 c7 B
  80. #else' j7 u$ S; ?6 `0 v: z$ z6 R

  81. 2 ]$ q  P' m$ d, F6 N1 a) g
  82.   /* Run the below code for Cortex-M0 */
    ) _8 L  B* _; G- L; G- \1 f" g

  83. 3 N* _! n7 p  M) R. Y3 N
  84. . Q3 h7 i6 B6 B3 B' e' T' }

  85. " J4 B# B; p' u: ~
  86.   /* Initialize blkCnt with number of samples */. c2 v  G7 s; ?9 e7 I5 J2 E7 ]
  87.   blkCnt = blockSize;8 ^3 V: t: t; C1 m2 ^
  88. ( @6 p; d& P3 Y- \
  89.   while(blkCnt > 0u)% B7 ^; k9 |9 c2 V1 b
  90.   {$ `  @4 j+ [  I1 Q* O- C
  91.     /* C = A[0]* B[0] + A[1]* B[1] + A[2]* B[2] + .....+ A[blockSize-1]* B[blockSize-1] */6 p7 O" W7 g" ?% H2 z
  92.     /* Dot product and then store the results in a temporary buffer. */
    ! Y- x7 p: `/ B- D
  93.     sum += (q31_t) ((q15_t) * pSrcA++ * *pSrcB++);5 w# \0 g% N" I

  94. + A! h$ ]: j$ p$ V+ T
  95.     /* Decrement the loop counter */
    9 L7 B. b& S( m
  96.     blkCnt--;4 v4 ?: h& T* |/ C
  97.   }$ r1 ~6 i$ V( r  Z% P* a
  98. 9 f- q/ x/ C' A+ e& Q4 y
  99. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
    , ^0 u$ h  K1 e: M: q7 w+ g
  100. * v; _: l8 t! P# f$ }+ r& ]
  101. 1 K9 \$ c6 n; g
  102.   /* Store the result in the destination buffer in 18.14 format */5 c# }! |1 e6 N) ~; B
  103.   *result = sum;
    4 M2 \5 V- u! `* U  M' g; M
  104. }
复制代码
1. 两个Q8格式的数据相乘,那么输出结果就是1.7*1.7 = 2.14格式。这里将最终结果赋值给了32位的变量,那么最终的格式就是18.14。如果乘累加的个数小于2^18那么就不会有溢出的危险(感觉这里应该是2^16)。
2. 一次读取4个8位的数据。
3. __SXTB16也是SIMD指令,用于将两个8位的有符号数扩展成16位。__ROR用于实现数据的循环右移。
4. __SMLAD也是SIMD指令,用于实现如下功能:
    sum = __SMLAD(x, y, z)
    sum = z + ((short)(x>>16) * (short)(y>>16)) + ((short)x * (short)y)
8.3.5 实例讲解
实验目的:
    1. 四种类型数据的点乘。
实验内容:
    1. 按下按键K3, 串口打印输出结果
实验现象:
        通过窗口上位机软件SecureCRT(V5光盘里面有此软件)查看打印信息现象如下:
8.3.png
程序设计:
  1. /*0 j! }0 D: j0 E) M- f# d
  2. *********************************************************************************************************8 a' y9 v0 g& U
  3. *        函 数 名: DSP_DotProduct$ l# f; m% \9 w; B/ W$ E
  4. *        功能说明: 乘积
    ; a' t! Y7 q* g9 `5 i/ W. }6 V. h
  5. *        形    参:无
    " i8 k. C% r- b0 c& r
  6. *        返 回 值: 无/ W1 q: y' S5 R' f% A# [4 }6 C, v
  7. *********************************************************************************************************
    ) n0 b$ G6 D: O5 L& X* }/ I  O: k
  8. */3 q+ G4 [  x0 ]0 A5 }+ _/ d
  9. static void DSP_DotProduct(void)
    & L: H7 p! q: _0 _
  10. {
    % k7 D3 V* B7 L8 Z
  11. static float32_t   pSrcA[5] = {1.0f,1.0f,1.0f,1.0f,1.0f};0 \3 x3 M) J" L- T) k& `/ U7 H) b
  12. static float32_t   pSrcB[5] = {1.0f,1.0f,1.0f,1.0f,1.0f};  # B. r1 I. g0 T8 s
  13. static float32_t   result;  2 C( v2 e# M- `
  14. static q31_t  pSrcA1[5] = {0x7ffffff0,1,1,1,1};  % P7 R6 y9 n5 E  U% R& K1 h% T( E
  15. static q31_t  pSrcB1[5] = {1,1,1,1,1};  
    # h6 y/ s3 l1 p$ i
  16. static q63_t   result1;   * O/ H8 J7 @* G/ m3 ]+ U  t6 B
  17. : k8 z# u6 y+ ^4 t* d3 [7 |, B7 [* t
  18. static q15_t  pSrcA2[5] = {1,1,1,1,1};  * j7 U1 V" J& O# j2 C* X" n& U
  19. static q15_t  pSrcB2[5] = {1,1,1,1,1};  
    3 N3 R- b# i& G
  20. static q63_t  result2;   
    0 D( B3 w9 u7 u9 t9 c: z; V8 p

  21. 7 P% o3 n/ `0 d2 G; h
  22. static q7_t  pSrcA3[5] = {1,1,1,1,1};
    ' b; H- K: g: B" t2 Z
  23. static q7_t  pSrcB3[5] = {1,1,1,1,1};  
    % }  {; u  g" o' H/ L; p
  24. static q31_t result3;  
    # O2 {$ f$ {. R7 ~+ I* r9 S
  25. # I! |( T' }/ h1 h0 l9 o
  26. pSrcA[0] -= 1.1f;% C4 }% [- g- F
  27. arm_dot_prod_f32(pSrcA, pSrcB, 5, &result);% d. B6 x. U( L( {" W
  28. printf("arm_dot_prod_f32 = %f\r\n", result);* Q/ _5 O1 r) E6 V- I
  29. pSrcA1[0] -= 0xffff;
    . y% o. ^4 b8 m. B( Y6 Y) f
  30. arm_dot_prod_q31(pSrcA1, pSrcB1, 5, &result1);
    / B' v" U. _  |! W
  31. printf("arm_dot_prod_q31 = %lld\r\n", result1);
    . m: Z9 J3 W" v+ ^/ m3 s4 j$ O
  32. , x/ f/ i& E3 s. Q1 e) Z
  33. pSrcA2[0] -= 1;; |3 s# K. t8 Z/ U/ I$ f
  34. arm_dot_prod_q15(pSrcA2, pSrcB2, 5, &result2);
    . J% e$ y0 c$ X; z/ x
  35. printf("arm_dot_prod_q15 = %lld\r\n", result2);
    ; U8 a$ @+ J6 I( C0 p

  36. 3 i( v& K% W, [* M( n  I
  37. pSrcA3[0] -= 1;
    1 ?2 D$ n- b) b* R8 o, \3 Z9 F
  38. arm_dot_prod_q7(pSrcA3, pSrcB3, 5, &result3);- g5 d- E/ z5 F! [( `, G' b1 Y
  39. printf("arm_dot_prod_q7 = %d\r\n", result3);4 S% g* `4 n* f% R* T9 n' b: f
  40. printf("***********************************\r\n");
    & m/ b- o9 `: U2 p  W1 s7 J8 A) Z! ~
  41. }
复制代码

$ |& [3 E' q- J9 \2 }) M; K

) j$ M- M" p( }+ O
baiyongbin2009 回答时间:2015-3-18 11:38:01
8.2 求和(Vector Addition)
    这部分函数主要用于求和,公式描述如下:
    pDst[n] = pSrcA[n] + pSrcB[n],   0 <= n < blockSize.
8.2.1 arm_add_f32
    这个函数用于求32位浮点数的和,源代码分析如下:
  1. /**        / ^8 c) V& Q$ b- j! U4 m- J
  2. * @brief Floating-point vector addition.        
    : ~. Q$ k5 s& h. h/ D1 _
  3. * @param[in]       *pSrcA points to the first input vector        + [# t. s$ n, Z4 D
  4. * @param[in]       *pSrcB points to the second input vector        
    2 p6 Z2 _# p- U: E
  5. * @param[out]      *pDst points to the output vector        
    & U, ?5 V$ k% ^- L; w3 ~
  6. * @param[in]       blockSize number of samples in each vector        / d$ R5 u+ I& ?( q
  7. * @return none.          L0 o9 l9 p  S! n7 _5 @
  8. */2 Q* g9 a7 L" d, K8 h- V

  9.   W1 j4 ^1 M  h  e8 `4 R5 l. Q5 W
  10. void arm_add_f32(0 D& `4 O/ N( t4 H
  11.   float32_t * pSrcA,. P; h) `! b- F2 b' P$ F  s# ?
  12.   float32_t * pSrcB,/ `! T. \8 X" N
  13.   float32_t * pDst,) ^4 W& @" V# q6 Z
  14.   uint32_t blockSize)
    / }2 M( n" r1 {1 j& N
  15. {* I5 `2 m2 C5 d7 _1 |
  16.   uint32_t blkCnt;                               /* loop counter */
    # g# I4 N, v7 e+ ^+ ?7 r
  17. & m! I# j& C$ z0 t8 A
  18. #ifndef ARM_MATH_CM0_FAMILY
    & p; `3 ~1 Y# S/ p9 N

  19. 8 y, G- }5 @! Y/ M' }
  20. /* Run the below code for Cortex-M4 and Cortex-M3 */. h1 a8 ~5 G0 N6 t* S/ ]
  21.   float32_t inA1, inA2, inA3, inA4;              /* temporary input variabels */
    - Z9 k1 q4 e. r* K- i- [. \
  22.   float32_t inB1, inB2, inB3, inB4;              /* temporary input variables */# H& u  u' J$ O  m' i$ j) Y8 L
  23. ) M4 ~0 a( M" Y6 V0 V2 G
  24.   /*loop Unrolling */# T6 n0 Q" q+ X' L. U
  25.   blkCnt = blockSize >> 2u;  Y% I. A$ L* c7 C' t) k
  26. 7 z) g% d0 }. o  Z& m% c6 y6 L& o" ^2 R
  27.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.        
    5 F, p2 h6 a) o2 m* \7 n& x- I. W
  28.    ** a second loop below computes the remaining 1 to 3 samples. */  b; @% B! y- C' l5 u. r& m3 o
  29.   while(blkCnt > 0u)
    . r9 J) y3 [8 G- e9 c' s0 j  O
  30.   {) T7 h6 `9 q* x* R7 |
  31.     /* C = A + B */1 R' t, h" u$ r. P+ h) t8 _
  32.     /* Add and then store the results in the destination buffer. */
    . v0 p( [: j2 m7 V/ [

  33. 2 g+ M- a, Y/ {4 K
  34.     /* read four inputs from sourceA and four inputs from sourceB */
    ) y5 I! G' B8 a. l' D8 @* \1 F  |
  35.     inA1 = *pSrcA;3 H* M0 S9 I- I2 t1 _' [% I5 c
  36.     inB1 = *pSrcB;
    ) r7 `6 P: r9 Z- d2 I8 v7 V8 E9 {
  37.     inA2 = *(pSrcA + 1);. ^: q- y2 x, O& K* H: |/ u, @
  38.     inB2 = *(pSrcB + 1);
    9 e+ R( f- N% e' a
  39.     inA3 = *(pSrcA + 2);
    8 o' l. p: w$ \3 Y  q
  40.     inB3 = *(pSrcB + 2);) K2 I- i5 L& ^6 O& t9 ~7 `8 ^
  41.     inA4 = *(pSrcA + 3);: A5 O, k. u- U% K. C0 }
  42.     inB4 = *(pSrcB + 3);
    ; p7 `% }0 A4 W( W9 v
  43. 0 h2 b" Z, e9 `% v7 e
  44.     /* C = A + B */                                                                                  (1)
    3 v$ k3 G  l& g+ D
  45.     /* add and store result to destination */3 u) j% C2 c- n
  46.     *pDst = inA1 + inB1;7 [  h  y  ~' q) b, Q
  47.     *(pDst + 1) = inA2 + inB2;
    % O" t: U& a7 R/ P& I1 q
  48.     *(pDst + 2) = inA3 + inB3;5 m/ m( E& Y* d6 ~8 |4 T, Z+ Y9 ?
  49.     *(pDst + 3) = inA4 + inB4;- U" W8 g# m  m5 E, b

  50. % t, L# k& R5 ?7 @! s" ?
  51.     /* update pointers to process next samples */
    ) }' _( Y$ V; I" G; ]) k0 h3 f4 T
  52.     pSrcA += 4u;
    , y( c6 s+ u, R  v1 M7 p
  53.     pSrcB += 4u;- y4 V1 \- w: k- {7 W8 m5 n
  54.     pDst += 4u;
    , o, x5 Q$ s+ Z9 [2 t
  55. & A3 ~4 h2 h" i# R! T) ~
  56. 0 e5 s5 M+ g" Z+ B. H
  57.     /* Decrement the loop counter */7 Q5 a; A- j4 [  U3 J7 j, U
  58.     blkCnt--;$ x8 U8 Z. W5 S$ L: W& p' g% r$ l
  59.   }
    1 G# k; p# Y* L6 R* B

  60. % G- O; Z/ S% p9 i+ s+ x
  61.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.        ; _* t# z, ^; o  g
  62.    ** No loop unrolling is used. */. m  I, }$ r2 B3 m4 _2 i
  63.   blkCnt = blockSize % 0x4u;
    1 v+ L$ M* G+ @
  64. 7 q. o- q/ Z' Q. i, Y
  65. #else
    - t; ~, u  @6 q, E. ^9 d

  66.   H5 S) u6 d; j0 Z
  67.   /* Run the below code for Cortex-M0 */
    ; Z, ^! t2 h: i8 @8 |" q- x

  68. ) [6 \  q' I+ d" c# J6 B8 p
  69.   /* Initialize blkCnt with number of samples */4 x! X5 C3 Q4 P- S
  70.   blkCnt = blockSize;
    ! {1 c- h' v* H

  71. - O" A0 E2 U8 N+ i6 Q/ p1 }
  72. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
    - ], t9 [5 z" G0 q
  73. 0 c/ f1 b  \0 C! `! n3 r9 {
  74.   while(blkCnt > 0u)
    ) z( S0 x0 @: C- o
  75.   {. E9 u: y7 r) k- W: r9 |
  76.     /* C = A + B */! F! }0 Y; i4 [4 G# R- b
  77.     /* Add and then store the results in the destination buffer. */: f9 m; Q) o! i: L, B: `2 M( e9 g3 W
  78.     *pDst++ = (*pSrcA++) + (*pSrcB++);
    % l9 f/ ~$ G4 o+ h4 e3 g! A

  79. 5 Y& O) |; n2 \/ R6 N, s. _
  80.     /* Decrement the loop counter */
    9 U3 i+ |) m; K# g7 Y
  81.     blkCnt--;4 b8 s' I, i. d, y; K& q
  82.   }6 C* S: L- f0 [7 ]4 x- _
  83. }
复制代码
1. 这部分的代码比较简单,只是求解两个数的和。
8.2.2 arm_add_q31
    这个函数用于求32位定点数的和,源代码分析如下:
  1. /**   
    * H% q+ w. ?1 h: Z
  2. * @brief Q31 vector addition.   
    , ]: H& `, v7 v8 R5 X" ^, {
  3. * @param[in]       *pSrcA points to the first input vector      d! y/ i# V2 y8 N/ \/ u- x
  4. * @param[in]       *pSrcB points to the second input vector   
    2 c* i2 P- x! K1 A1 s
  5. * @param[out]      *pDst points to the output vector    & d1 j* t' O- a7 S
  6. * @param[in]       blockSize number of samples in each vector   
    4 b! A- H; c* L2 A, [3 o
  7. * @return none.   
    ' z4 B* Z" Z$ n) n/ j$ \
  8. *   
    + `6 g+ \. _2 s% M2 q1 o+ T9 @
  9. * <b>Scaling and Overflow Behavior:</b>                                                             (1)
    # y) Q" U  C6 m/ G' M
  10. * \par   
    ' c. v3 J( J7 O! R
  11. * The function uses saturating arithmetic.      k: l2 w3 G  ^+ b- ~% [, d
  12. * Results outside of the allowable Q31 range[0x80000000 0x7FFFFFFF] will be saturated.   
    # b  ^9 h2 r, b2 I. p. C- F
  13. */9 D5 K8 s6 s# |' u2 H

  14. ) m, L) a0 O( L/ b; e
  15. void arm_add_q31(' m- i2 D4 ?- |1 L5 m# c# P0 d
  16.   q31_t * pSrcA,
    1 B6 o; S, @) H, l
  17.   q31_t * pSrcB,  O$ V( ]; \' h  E& u
  18.   q31_t * pDst,
    3 [- L9 j% G- [- p+ }, [! {
  19.   uint32_t blockSize)& Q% t: K8 r; D/ j' s, g
  20. {
    4 v5 o# |" y3 X; w- x9 i! N7 ~
  21.   uint32_t blkCnt;                               /* loop counter */7 x( I6 k  S) F. f
  22. 6 g, [- S! d2 r4 e3 J8 K9 _
  23. #ifndef ARM_MATH_CM0_FAMILY& }. a' n6 I; t+ }% k" p
  24. # ]% b2 }; Q8 ~; Q' F6 v6 C9 |
  25. /* Run the below code for Cortex-M4 and Cortex-M3 */  U) Y; r! h+ t# ^+ o
  26.   q31_t inA1, inA2, inA3, inA4;
    : o# O& L5 h! c: g
  27.   q31_t inB1, inB2, inB3, inB4;  ]( O9 T0 E( @% g

  28.   |6 Y9 o' y  e1 V+ x
  29.   /*loop Unrolling */
    3 o3 Q- f9 N9 u2 D
  30.   blkCnt = blockSize >> 2u;
    * \7 q. T: S$ ~& D: _4 u- ]7 s$ Q1 X

  31. 9 G( R, e) i+ }
  32.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
    ( t9 N* X: R* G: n+ i" r
  33.    ** a second loop below computes the remaining 1 to 3 samples. */) u1 G* q# g8 O, i( x
  34.   while(blkCnt > 0u)
    # \8 @7 N6 b0 t+ v! \$ s, C
  35.   {
    / c: A7 ^! e+ e& j% ?9 Z
  36.     /* C = A + B */
    0 i) x% @, k. j2 x4 @9 s6 T
  37.     /* Add and then store the results in the destination buffer. */
    5 H! _; m6 o1 d
  38.     inA1 = *pSrcA++;/ o  L! V' O. P0 }5 F
  39.     inA2 = *pSrcA++;
    7 G. _9 ~' Z4 u; I( q4 n. J
  40.     inB1 = *pSrcB++;
    6 [6 K: ^' j" V& A* x# r
  41.     inB2 = *pSrcB++;
    9 I! _: z' x1 N) E

  42. $ }: d* c) I% `% S) z
  43.     inA3 = *pSrcA++;+ D: E! ]. c' w$ b  Q
  44.     inA4 = *pSrcA++;
    $ Z, L% J1 }# s# b4 r+ w0 t6 B
  45.     inB3 = *pSrcB++;1 q) \' o7 ]7 ?( }, h: h0 @% h
  46.     inB4 = *pSrcB++;
    + K* B% F3 ~  J! J! j& M1 t# |" H
  47. ; r+ m; l, n9 j9 @
  48.     *pDst++ = __QADD(inA1, inB1);                                                                   (2)# n! z! p) m# d+ r6 [
  49.     *pDst++ = __QADD(inA2, inB2);
    & A" x$ z. D. J" t0 e( r7 M  M
  50.     *pDst++ = __QADD(inA3, inB3);6 C* D3 u% L% \1 k
  51.     *pDst++ = __QADD(inA4, inB4);
    $ m" B7 ~3 n, n

  52. 0 V9 o+ \8 w( j% C
  53.     /* Decrement the loop counter */
    : J; r4 G% q2 ^% c8 M# s- k+ n
  54.     blkCnt--;  x" a% t6 g4 n+ }( x& r9 w: M, C
  55.   }
    5 U# y1 ]$ R4 ^
  56. + y+ m. P+ r) e
  57.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
    ) m4 k8 F& E# L' N; a* T6 {4 K
  58.    ** No loop unrolling is used. */  `% ?7 u2 m5 F: K7 W
  59.   blkCnt = blockSize % 0x4u;
    ( O/ _# X6 {1 [4 N

  60. ) C5 Q6 D7 C) A0 ^  a2 C
  61.   while(blkCnt > 0u)
    " _; U9 O' n9 E6 J8 Q4 C9 X
  62.   {
    # M5 M& |" h* }
  63.     /* C = A + B */
    8 S7 f' [; j+ e( ^
  64.     /* Add and then store the results in the destination buffer. */1 x% P1 z. d) t5 K& v3 g
  65.     *pDst++ = __QADD(*pSrcA++, *pSrcB++);3 F6 x8 u! h+ X  Q5 o+ D* o

  66. + m/ C7 i, }1 k7 X. x9 V
  67.     /* Decrement the loop counter */  w0 c$ o5 K9 J. V5 K
  68.     blkCnt--;; {2 |# j% F- y5 X% }% G- H
  69.   }3 P7 `* N! X+ F8 B+ Q( o3 D. [5 y
  70. ! P" ^) T/ m: i% j
  71. #else8 Q7 M9 a; Z$ w$ \
  72. % j1 x1 R9 F/ w! Z6 \
  73.   /* Run the below code for Cortex-M0 */& p2 h3 G! W: S+ a! ~* r
  74. - ^! k( M) ?) b3 ~  t  \( R' p7 _

  75. ! ~3 }/ q5 H6 G% H, q' c
  76. 6 g5 d' i3 O$ m) \2 B1 W
  77.   /* Initialize blkCnt with number of samples */
    8 N* C( u# J# L) J; i7 z3 w' V& T% g
  78.   blkCnt = blockSize;( U/ g: ]" C! Y9 G& A* v

  79. 9 O  b1 j9 U9 b8 c7 R7 e! R
  80.   while(blkCnt > 0u)( I0 w- m' {2 D7 g
  81.   {- `/ R- M6 Z! I# g- H
  82.     /* C = A + B */
    9 y5 ]5 \/ ~. M
  83.     /* Add and then store the results in the destination buffer. */' m% E- E* h, a) }
  84.     *pDst++ = (q31_t) clip_q63_to_q31((q63_t) * pSrcA++ + *pSrcB++);                                  (3)0 S- r% T, [3 N' |" A. r; y# v

  85. 7 H6 N- [( q5 E) I$ @) Y
  86.     /* Decrement the loop counter */
    * ]2 k" E2 Y9 ^' n: Y
  87.     blkCnt--;( b1 N$ i2 f6 b
  88.   }
    $ x0 L6 D* m0 R! d
  89. 7 S& T: A2 Z, h8 J% V
  90. #endif /* #ifndef ARM_MATH_CM0_FAMILY */9 H: J4 z4 O/ O! [4 J* R
  91. 5 M/ U# Q8 g0 M6 H- F7 V' L
  92. }
复制代码
1. 这个函数也是饱和运算,输出结果的范围[0x80000000 0x7FFFFFFF],超出这个结果将产生饱和结果。
2. __QADD实现32位数的加法。
3. 函数clip_q63_to_q31的定义在文件arm_math.h里面
      static __INLINE q31_t clip_q63_to_q31(
      q63_t x)
      {
           return ((q31_t) (x >> 32) != ((q31_t) x >> 31)) ?
             ((0x7FFFFFFF ^ ((q31_t) (x >> 63)))) : (q31_t) x;
          }
    这个函数的作用是实现饱和结果。
8.2.3 arm_add_q15
    这个函数用于求16位定点数的和,源代码分析如下:
  1. /**   
    9 g/ Y" k3 j. m+ B2 d
  2. * @brief Q15 vector addition.    - s# `  r; }! m
  3. * @param[in]       *pSrcA points to the first input vector    0 ]$ Q4 I6 p3 A! x7 J: i- R
  4. * @param[in]       *pSrcB points to the second input vector   
    $ M. E5 B) V$ a2 C6 x2 I2 g
  5. * @param[out]      *pDst points to the output vector   
    0 f. G- [- s* b/ Z% y
  6. * @param[in]       blockSize number of samples in each vector   
    + J6 K6 H- |, p9 `- y7 M
  7. * @return none.   
    0 Y1 q' `% C7 Z$ Y' F4 e# C
  8. *    . o2 M' N6 ]$ D' ?6 X
  9. * <b>Scaling and Overflow Behavior:</b>                                                               (1)
    4 R+ V. L$ d+ e8 |
  10. * \par   
    2 D; U2 p' w6 ?/ r; p
  11. * The function uses saturating arithmetic.    ( d+ O. D) a6 q# U* V, Q4 ?
  12. * Results outside of the allowable Q15 range [0x8000 0x7FFF] will be saturated.   
    1 m1 z1 b* T) z0 @" S
  13. */- p9 ^) K; y- A$ G

  14. $ u4 X8 D% G3 n) f* {
  15. void arm_add_q15(
    / c2 q( c+ H5 J5 _; g* n
  16.   q15_t * pSrcA,1 `$ m+ f; t. m7 C: W
  17.   q15_t * pSrcB,
    0 l/ \/ e4 \8 U. m8 r9 W( x
  18.   q15_t * pDst,! c0 k# }: |: v$ _3 x
  19.   uint32_t blockSize)
      d! Z8 `0 L! H6 [
  20. {
    , o# V1 \' p; Y3 G  i# G
  21.   uint32_t blkCnt;                               /* loop counter */
    " o- s2 s$ t/ Z

  22. 3 d7 r; k$ [! R
  23. #ifndef ARM_MATH_CM0_FAMILY3 L  f$ H9 z# @0 l( ?! P& D. W

  24. 8 i, w2 O8 r! z% h9 G! y$ O! e
  25. /* Run the below code for Cortex-M4 and Cortex-M3 */
    7 z+ G" u; s& X8 S4 Z0 d" p# X
  26.   q31_t inA1, inA2, inB1, inB2;/ u4 F/ d4 W2 l8 z
  27. & n! @/ g, ], U, \( a; d
  28.   /*loop Unrolling */0 J! P; |, ~9 B+ f. J0 @1 Q
  29.   blkCnt = blockSize >> 2u;
    ! G7 O' K+ Y6 j9 Z8 h( f
  30. + D. Y7 y+ x  E2 q" \' S  R
  31.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.    ' w) }4 z$ W. p$ J+ G, E
  32.    ** a second loop below computes the remaining 1 to 3 samples. */7 @7 l0 _3 i1 R7 |' z7 {: A( h
  33.   while(blkCnt > 0u)2 N7 \$ M6 @* x5 X
  34.   {
    0 R. X: }! u, j
  35.     /* C = A + B */                                                                                    (2)3 G6 M! F, r0 {/ K( J) ?% }2 `) N
  36.     /* Add and then store the results in the destination buffer. */  u+ {: M' }' M9 M
  37.     inA1 = *__SIMD32(pSrcA)++;  l& I( U5 K: J
  38.     inA2 = *__SIMD32(pSrcA)++;: R9 ]* x" O3 a& c3 e0 `6 S
  39.     inB1 = *__SIMD32(pSrcB)++;# R' G4 b( o1 q7 h  \
  40.     inB2 = *__SIMD32(pSrcB)++;9 w$ @# @6 l8 j/ o
  41. ; [& p$ _9 X) O/ N; \5 P
  42.     *__SIMD32(pDst)++ = __QADD16(inA1, inB1);
    6 m' w" x# H& c7 }3 D/ O: C
  43.     *__SIMD32(pDst)++ = __QADD16(inA2, inB2);# \2 ]9 k, A8 w% o: r% J

  44.   t( n& G% v) c' b) m0 v. X( x
  45.     /* Decrement the loop counter */
    ' r7 u3 P! {% P
  46.     blkCnt--;# Y) s) c- G. O7 r$ Q* Q
  47.   }
    4 R# D2 ~1 z3 {8 d1 Q
  48. 2 {0 T, w" B; W# R
  49.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.    ; r2 N: e* G( _) A; m, W, \
  50.    ** No loop unrolling is used. */! u% {1 u8 Y! A6 p' B/ X  a
  51.   blkCnt = blockSize % 0x4u;6 S3 s. M) e" L8 y& X$ z6 H  M/ K8 w( W
  52. & w- Y# g& g9 E( `/ R. j4 N
  53.   while(blkCnt > 0u)
    3 _6 E% E1 i3 x* w4 V' Z2 M
  54.   {  s: a$ q0 T  _
  55.     /* C = A + B */
    % i# [8 R' O# ?* O
  56.     /* Add and then store the results in the destination buffer. */0 B4 t% E; ~! Q4 v1 U
  57.     *pDst++ = (q15_t) __QADD16(*pSrcA++, *pSrcB++);, T8 n( n( W  X; e8 _
  58. 0 M5 e( O+ ^7 ^+ u
  59.     /* Decrement the loop counter */
    0 y% s) t7 ^# [" H! ^. H
  60.     blkCnt--;
    3 W) @! ?! v2 `4 c
  61.   }$ z0 S1 J" S+ k
  62. % I' e4 M1 {2 X
  63. #else/ o8 C+ g9 O. g1 B# E2 J1 v; ]

  64. ; l% G9 d! u& _& U' m8 P
  65.   /* Run the below code for Cortex-M0 */' ^8 S7 B( U5 O* U

  66. 7 P$ L, ~9 [- o4 r
  67. 9 z# D8 @2 F: M# j, ~/ ]9 J3 S

  68. $ o* N: c8 j1 X+ A  \/ P) X
  69.   /* Initialize blkCnt with number of samples */
    ' i! C& {, Q! L+ x0 g
  70.   blkCnt = blockSize;
    7 i- p8 K0 w) H, W5 ]

  71. # O& j7 u3 A4 u  M* c3 U
  72.   while(blkCnt > 0u)5 V9 `8 J. R/ U
  73.   {& g' m1 q, }3 a1 Z! ^( \. A
  74.     /* C = A + B */
    5 D4 O6 y( L2 k" W0 ?' S1 M
  75.     /* Add and then store the results in the destination buffer. */
    / H2 S  U" \) M
  76.     *pDst++ = (q15_t) __SSAT(((q31_t) * pSrcA++ + *pSrcB++), 16);                                      (3)' U) _$ H9 M: G  F$ u' r- E

  77. ; [' w# A" q" m) Y
  78.     /* Decrement the loop counter */
    6 h' J! v. @& c1 I  k8 W' M5 z; k
  79.     blkCnt--;5 o) @' @/ k/ w# P0 y" Y
  80.   }
    0 w' L0 r. Z$ D4 L
  81. 0 ?% m  n1 P& C) M4 h
  82. #endif /* #ifndef ARM_MATH_CM0_FAMILY */! o! \1 w) g3 e4 Z) f4 m

  83. 5 {% m6 W, Y9 m" u) A

  84. ; B8 d+ b. l$ X( P
  85. }
复制代码
1. 这个函数也是饱和运算,输出结果的范围[0x8000 0x7FFF],超出这个结果将产生饱和结果。
2. 函数inA1 = *__SIMD32(pSrcA)++仅需要一条SIMD指令即可完成将两个16位数存到32位的变量inA1中。
3. __SSAT也是SIMD指令,这里是将结果饱和到16位精度。
8.2.4 arm_add_q7
    这个函数用于求8位定点数的绝对值,源代码分析如下:
  1. /**   
    3 j9 @4 Z! P% e
  2. * @brief Q7 vector addition.    $ p* y0 P+ m2 N: z6 G  Y+ g6 D- d
  3. * @param[in]       *pSrcA points to the first input vector    ! Q4 c6 Y( l- Q, s
  4. * @param[in]       *pSrcB points to the second input vector    1 X; N. @9 h% g  U, R
  5. * @param[out]      *pDst points to the output vector   
    3 W! i) X; n; ]7 B6 T6 A9 M
  6. * @param[in]       blockSize number of samples in each vector   
    9 P- H) V+ s# S( s. Y9 F# S, V; N  N  t
  7. * @return none.    5 M1 `8 ?7 Y, `* F+ B! D" D
  8. *   
    1 ]1 P7 Y8 v; N; f( n
  9. * <b>Scaling and Overflow Behavior:</b>                                                              (1)
    % \/ ~7 @0 I2 ], M$ S" t4 @8 ~' a
  10. * \par    4 W, p( t! t0 _7 G6 G4 J! T
  11. * The function uses saturating arithmetic.    # _+ @0 ^' q5 j2 W+ P/ I6 h
  12. * Results outside of the allowable Q7 range [0x80 0x7F] will be saturated.    - Y. m! q. u; J9 L: A4 I% E+ A
  13. */: K2 T1 I  p9 u2 O% ^/ V

  14. 8 k) i8 m' I' f& I5 A! @
  15. void arm_add_q7(; o! ]8 [- r2 L9 d( J/ N
  16.   q7_t * pSrcA,
    6 [9 W0 B% |2 \7 O: t+ X, C
  17.   q7_t * pSrcB,* G5 g( _, L1 z& I" K# W. X/ Y
  18.   q7_t * pDst,7 ~3 f4 h2 O% G6 @
  19.   uint32_t blockSize)1 ?; T% p7 y* L) B% g  m, C
  20. {
    $ |( _: C9 _" C5 W4 G+ K
  21.   uint32_t blkCnt;                               /* loop counter */
    1 v! Z4 U$ y1 B( M) _2 _& H" l( x
  22. 3 W) O9 ^8 ~$ d5 |
  23. #ifndef ARM_MATH_CM0_FAMILY! F0 d# p$ n+ v8 G2 i. u& Q! ~( H
  24. : E1 s4 G( z0 `) h' ~$ r; I
  25. /* Run the below code for Cortex-M4 and Cortex-M3 */
    5 H7 v' w6 `8 a
  26.   d9 L' I5 Q# T- F0 o5 v
  27. # `$ w2 ?. B( S3 z. v& `3 [) h
  28.   /*loop Unrolling */
    1 k1 k; M, u* K" l% u6 z
  29.   blkCnt = blockSize >> 2u;
    ' X* i4 c1 h0 S# X; a( i
  30. ) E  Q; `6 n7 P
  31.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.    ' f0 s: T' i$ f5 U$ n1 Y+ G
  32.    ** a second loop below computes the remaining 1 to 3 samples. */
    ( x5 m) Q: Z7 W5 [6 {
  33.   while(blkCnt > 0u)7 s/ X4 ^( `! P
  34.   {* T% w. v) C0 j3 ^$ h+ U
  35.     /* C = A + B */: \0 \4 q1 A, C  |* f  w8 X
  36.     /* Add and then store the results in the destination buffer. */                                 (2)
    6 l  a% @6 \- r
  37.     *__SIMD32(pDst)++ = __QADD8(*__SIMD32(pSrcA)++, *__SIMD32(pSrcB)++);9 ^+ v- U! x  S! o) g
  38. 1 ?6 L! o9 T' Z/ b8 l
  39.     /* Decrement the loop counter */
    0 H3 M+ {  ~; }5 P6 Z' b' m, F8 c$ K
  40.     blkCnt--;
    ' P1 u/ g$ f8 h& ~1 `. k
  41.   }) |5 R8 g3 p# n7 ^
  42. # @2 k$ s  o8 h' P
  43.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.    ! J4 l8 u5 D1 c: o2 m# ~( S
  44.    ** No loop unrolling is used. */4 @4 T# I- V' C% V8 C
  45.   blkCnt = blockSize % 0x4u;
    ) T; I  ]; l  u" v/ g

  46. + T* r5 Q4 ^1 B( E2 M
  47.   while(blkCnt > 0u)
    : l4 Q5 L# s3 N) _: S
  48.   {1 M% W8 B% h" N" g6 V4 R& d
  49.     /* C = A + B */, m7 i, V0 ]) P' v7 j
  50.     /* Add and then store the results in the destination buffer. */
    2 U4 o8 ?* X7 d& \8 q. q1 W
  51.     *pDst++ = (q7_t) __SSAT(*pSrcA++ + *pSrcB++, 8);& P  M- ]+ `  t9 Y! t3 w2 K, g

  52. 6 ~) a% ~: z* f. h
  53.     /* Decrement the loop counter */
    ' K3 O4 D; P) Y" z9 G
  54.     blkCnt--;
    # x- H# K/ H7 I2 L
  55.   }5 a4 j: k: u: Q( ^: H- r
  56. 6 E5 T; F" Z  I/ b
  57. #else
    + T( b5 y" y9 P3 J& L1 b1 O  b

  58. 5 A0 p& G" b: ^; a+ i$ ^* u
  59.   /* Run the below code for Cortex-M0 */3 d+ h  c; q  v. L$ M
  60. ( H0 t, t8 ^6 x  z8 ?

  61. , D; q7 ?, t' n; C5 p9 w7 U5 \
  62. 6 N+ T, {; f2 X( K
  63.   /* Initialize blkCnt with number of samples */
    ( L; D# w7 [( g3 _- Z" v
  64.   blkCnt = blockSize;3 i* c- O$ I! I: V

  65. 9 u, w; C, ^, D
  66.   while(blkCnt > 0u)( U4 e5 E, J9 g3 o% c; `' Z
  67.   {- ~3 t6 P+ X: ?
  68.     /* C = A + B */
    * P0 [0 B! i1 F; i  `3 r
  69.     /* Add and then store the results in the destination buffer. */, V! k# |* P6 m; z3 }
  70.     *pDst++ = (q7_t) __SSAT((q15_t) * pSrcA++ + *pSrcB++, 8);
    2 D! g; g" H( I7 p
  71. : c. p* q. @" {- v3 y# t0 ~. q; ~
  72.     /* Decrement the loop counter */& v4 A7 w, p, }! M
  73.     blkCnt--;  s  R+ v% M0 a/ s' v/ X" S# Y/ b
  74.   }
    ( }; Y5 N; F# ?/ \$ F" [4 v; E

  75. " N' A8 v& L* E2 T$ D" k5 O
  76. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
    ' q- c" G* ^. e- p) g, J. H# e
  77. : B" y( u! ~8 t: P0 j- a2 B" w+ K
  78. % P' n9 Q! t6 D! S
  79. }
复制代码
1. 这个函数也是饱和运算,输出结果的范围[0x80 0x7F],超出这个结果将产生饱和。
2. 这里通过SIMD指令实现4组8位数的加法。
8.2.5 实例讲解
实验目的:
    1. 四种类似数据的求和
实验内容:
    1. 按下按键K2, 串口打印输出结果
实验现象:
    通过窗口上位机软件SecureCRT(V5光盘里面有此软件)查看打印信息现象如下:
8.2.png
程序设计:
  1. /*2 w# {) j9 q2 X6 m
  2. *********************************************************************************************************
    / A* N1 `* M. X4 _3 y% M; j* b$ ]
  3. *        函 数 名: DSP_ABS, Z8 c: m& Q  g3 N5 T$ a# [# D
  4. *        功能说明: 加法5 z1 [  z1 q7 v+ R* B
  5. *        形    参:无% b3 H, }5 h5 \, V7 ]
  6. *        返 回 值: 无
    1 a* m) T- K% S8 y8 L' r( c2 G6 {3 C
  7. *********************************************************************************************************
    ' L( H4 ~/ r) f& L! M3 y4 v
  8. */6 R7 H* I& S/ A" n, e/ e
  9. static void DSP_Add(void)
    ; X/ a9 h2 q% w+ B) P+ H- y
  10. {( n; `, O+ U. q  L
  11. static float32_t   pSrcA;$ u2 W: ^; w8 C
  12. static float32_t   pSrcB;  
    & c+ w! J" `) w: c: ?4 e3 g; v# u) w
  13. static float32_t   pDst;  , y  L2 v" I& K% Q1 b! [  R8 ^
  14. static q31_t  pSrcA1;  
    ' r7 I( n2 d5 [; `" a3 d& N1 k3 p
  15. static q31_t  pSrcB1;  + y3 k3 e5 }+ ]; C& h
  16. static q31_t  pDst1;  
    3 m! a& P$ Q2 Z' c/ n; i9 e

  17. & \8 B9 i/ C" p  ~. f  U9 V1 |
  18. static q15_t  pSrcA2;  
    + I8 {. h9 x; m
  19. static q15_t  pSrcB2;  
    & U( c2 q- T0 z& t8 G. y
  20. static q15_t  pDst2;
    " c( b9 ]2 m( N2 e0 W

  21. $ N# t( a' f! y" a% @& y+ }
  22. static q7_t  pSrcA3; 3 d  Z& N9 Q" T, H' J
  23. static q7_t  pSrcB3;  * k) N7 Q- u2 w8 O
  24. static q7_t  pDst3;  * B, s% y8 l; S+ \

  25. , Y$ r7 _' b% v$ X# o  U# ~
  26. pSrcA--;# \5 b* K, i7 e2 h
  27. arm_add_f32(&pSrcA, &pSrcB, &pDst, 1);
    * B1 l5 i8 [, Q% E, d* H& C
  28. printf("arm_add_f32 = %f\r\n", pDst);
    ) l( I% B; c# E) ~& E. a

  29. ! e( j, t# Z4 q! `" l
  30. pSrcA1--;
    . m( n1 U, V8 u# Z
  31. arm_add_q31(&pSrcA1, &pSrcB1, &pDst1, 1);# m. Q4 i, M/ l
  32. printf("arm_add_q31 = %d\r\n", pDst1);
    . Z  F" T+ _' ]4 z6 D/ }0 K

  33. $ z0 {/ e- s) N! @. a; C: n
  34. pSrcA2--;
    3 I  U) {! s3 z) s+ K
  35. arm_add_q15(&pSrcA2, &pSrcB2, &pDst2, 1);9 t3 R/ e' ?: Y* @
  36. printf("arm_add_q15 = %d\r\n", pDst2);- J6 P0 k8 s5 K8 U. ]

  37. & ]+ ]  w% U8 |+ M/ s
  38. pSrcA3--;
    # S* S* z5 P; ~1 b  I
  39. arm_add_q7(&pSrcA3, &pSrcB3, &pDst3, 1);$ W: W. G1 g8 U2 n: Y% J
  40. printf("arm_add_q7 = %d\r\n", pDst3);
    3 L+ `  G7 `$ M* [/ [) ]! I4 F$ _
  41. printf("***********************************\r\n");( m" d: e; j$ }, J$ ^$ f
  42. }
复制代码
' v  @' f5 k/ X
baiyongbin2009 回答时间:2015-3-18 11:45:34
8.4 乘法(Vector Multiplication)
    这部分函数主要用于乘法,公式描述如下:
     pDst[n] = pSrcA[n] * pSrcB[n],   0 <= n < blockSize.   
8.4.1 arm_mult_f32
     这个函数用于求32位浮点数的乘法,源代码分析如下:
  1. /**        3 J7 T# }/ E, W+ Q; y+ ]5 x
  2. * @brief Floating-point vector multiplication.        ' w$ E& q( o" f% L+ ?$ d
  3. * @param[in]       *pSrcA points to the first input vector        + \0 v0 Q7 F# X) l
  4. * @param[in]       *pSrcB points to the second input vector        
    ! z! {$ Y/ u0 l+ M$ f& F8 e
  5. * @param[out]      *pDst points to the output vector        % ^4 u4 V& r# b' M; j6 v
  6. * @param[in]       blockSize number of samples in each vector        
    : r% X3 f- U4 l
  7. * @return none.        
    ) ^# p% G5 v- U% o* X2 d' r0 d
  8. */
    ' X; `, M7 V& v' R2 a) R, W
  9. ( o0 [" z1 U. N# `
  10. void arm_mult_f32(
    5 @( k1 \3 w6 ]# i/ `! p/ B
  11.   float32_t * pSrcA,# v+ X( \! I8 f3 l. t) ]# N, C1 N6 q2 W
  12.   float32_t * pSrcB,
    $ s, A4 I: _# m) I4 N5 [
  13.   float32_t * pDst,
    9 t# L0 g4 c3 q% l; ]. w7 Z
  14.   uint32_t blockSize)
    : H! R/ T& G: r' U: R. a
  15. {  R$ ]6 b8 }- x8 Q: P* _: j9 }* A5 z
  16.   uint32_t blkCnt;                               /* loop counters */9 G- n. E+ N7 X
  17. #ifndef ARM_MATH_CM0_FAMILY
    " U5 F# M) p- K/ X
  18. 8 X8 e4 ?! Z7 ~2 r6 B
  19.   /* Run the below code for Cortex-M4 and Cortex-M3 */9 o( [- W- |2 f& K* q$ O* U, I' t" p
  20.   float32_t inA1, inA2, inA3, inA4;              /* temporary input variables *// M; G' R4 \2 _7 g( Z5 P) z3 z
  21.   float32_t inB1, inB2, inB3, inB4;              /* temporary input variables */
      M9 s8 J  n- H/ c4 S$ Y% K  ?
  22.   float32_t out1, out2, out3, out4;              /* temporary output variables */
    + r) O1 V4 N1 V& k) B
  23. * p" m3 Y: S5 `4 A' x2 m0 i/ `! E
  24.   /* loop Unrolling */
    ( E/ m1 y  z7 f5 S/ O8 Z
  25.   blkCnt = blockSize >> 2u;
    8 u2 d. B$ g( W9 O
  26. / M! R% A* h' [) |8 Y- L5 u
  27.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.        : o8 U1 C/ X; ?5 |
  28.    ** a second loop below computes the remaining 1 to 3 samples. */8 n- H1 K/ p7 ~/ [& `. |
  29.   while(blkCnt > 0u)0 I; Q5 A6 M6 L, L4 a
  30.   {
    # q" g& M$ x. b4 \
  31.     /* C = A * B */. Q7 C0 K: i, F
  32.     /* Multiply the inputs and store the results in output buffer */                                 (1)& b, T; y2 @5 {1 ?" x$ z& a
  33.     /* read sample from sourceA */. j- i+ u, G( `8 l* F7 j
  34.     inA1 = *pSrcA;
    ) C# Z6 m8 s" [8 D
  35.     /* read sample from sourceB */
    . p$ G; ]  b, n1 f5 k
  36.     inB1 = *pSrcB;
    " v( B+ L5 B: v) c9 `  t
  37.     /* read sample from sourceA */
    ! \5 C; d) S3 E  m0 j5 s# J- m
  38.     inA2 = *(pSrcA + 1);
    , k3 `9 @6 A' P1 _& [( H! I
  39.     /* read sample from sourceB */+ f6 M8 O8 M1 F3 B: J; t! @5 V
  40.     inB2 = *(pSrcB + 1);
    ; i0 J2 J; j( Z& J4 d) a7 o: c- q9 _

  41. 1 v+ p% S# F5 S1 g
  42.     /* out = sourceA * sourceB */" o, S7 [( M5 J/ R
  43.     out1 = inA1 * inB1;! p4 c8 K/ E# _4 V

  44. 8 f& J4 o$ H# W% x& a! F: t
  45.     /* read sample from sourceA */
    & P5 b# Q$ ~9 a' Y- s
  46.     inA3 = *(pSrcA + 2);$ |: O7 V: G5 r; }( V
  47.     /* read sample from sourceB */( c! M0 s- a5 ^- }1 I2 y* E
  48.     inB3 = *(pSrcB + 2);
    ) J# p& Y0 f" ^2 v, W" v9 D
  49. 9 F4 e6 {# o9 i, o! N
  50.     /* out = sourceA * sourceB */
    ' ?* s# f& _: h5 T
  51.     out2 = inA2 * inB2;& F7 V( I- Z) m% |2 t+ V% X

  52. 0 E: [! V. m  |
  53.     /* read sample from sourceA */7 a8 D& _& A) a% u0 O% A7 O
  54.     inA4 = *(pSrcA + 3);
    3 g' Y4 U/ D9 N# Q! ~, ]

  55. 7 A; i$ j4 M2 C4 r( }3 N
  56.     /* store result to destination buffer */
    1 P+ A1 w# _1 Y! [. t
  57.     *pDst = out1;
    1 |9 p' B7 _9 P$ I/ D. H) M
  58. 6 N0 \- t5 u1 h8 G
  59.     /* read sample from sourceB */3 c! q% C$ {+ B0 }+ K
  60.     inB4 = *(pSrcB + 3);# R2 A. R5 r; E. e. v/ C' q  S
  61. 4 j% x4 w1 K4 k2 a# s5 `
  62.     /* out = sourceA * sourceB */
      b2 d) M  }! f. V. w
  63.     out3 = inA3 * inB3;
    ! V, d1 H2 h+ @. S; _9 s8 p5 P

  64. 0 ?9 }0 F0 I7 }% L
  65.     /* store result to destination buffer */  [! A# [/ l0 O
  66.     *(pDst + 1) = out2;
    * H9 q* y( {& f( p" J# ^0 [0 V% \
  67. 7 b' _3 n! o3 \* X' T9 W
  68.     /* out = sourceA * sourceB */
    4 _. f# s, M) r$ m2 C, [
  69.     out4 = inA4 * inB4;
    6 U4 D2 c; u4 b$ f& c
  70.     /* store result to destination buffer */
    & P+ m# t+ w# o- J$ M
  71.     *(pDst + 2) = out3;
    % ?0 y( A, M# m6 }* L' s
  72.     /* store result to destination buffer */& m- G  J) g4 t1 d, C3 u* d
  73.     *(pDst + 3) = out4;4 k  H: A6 P! }7 p: T

  74. ; F0 z' b' X: @% G% a) C+ T
  75. + |5 x. t5 S+ n' U1 T! z% s1 R# i
  76.     /* update pointers to process next samples */
    % }$ S: n! g/ i" U1 \( `! ?3 {9 ~
  77.     pSrcA += 4u;" L. J; K  t7 I; B4 C
  78.     pSrcB += 4u;' T+ d& Y' y+ C) F$ |
  79.     pDst += 4u;
    , j. s6 f  [1 K

  80.   ]2 U. v- @1 m: R
  81.     /* Decrement the blockSize loop counter */& J( t- i8 U8 M% N4 l. o
  82.     blkCnt--;
    $ c5 P* T% c* N6 j7 ]) `1 D& X
  83.   }4 C/ X$ O$ ~; w
  84. ) j( W0 P$ B+ h/ c" k) H! M
  85.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.        ! x  S0 o: O# b+ Q# w
  86.    ** No loop unrolling is used. */; m3 c  p9 Z: S2 `5 n( Z3 F
  87.   blkCnt = blockSize % 0x4u;
    . Y6 ~1 a* c. T2 c( [$ M) q$ t( U  _

  88. & ~8 L- a$ m/ p0 s+ Y
  89. #else5 q0 V: f$ T( F
  90. , J9 b7 s5 A, E- S7 _! F
  91.   /* Run the below code for Cortex-M0 */
    # z& Y) r3 M' T4 Y- z& m% f) o

  92. * S* S' |) r1 b
  93.   /* Initialize blkCnt with number of samples */' j0 w1 |; S% s$ S+ k
  94.   blkCnt = blockSize;0 A' _7 H) f0 l$ ]
  95. 6 T: c6 Q- @9 Q* b
  96. #endif /* #ifndef ARM_MATH_CM0_FAMILY */1 |) e4 j( l* s

  97. ) v$ H% f2 {$ g+ F, D9 E
  98.   while(blkCnt > 0u)
    ( B( r; L3 C8 U( G! U+ D
  99.   {
    : S' U! q4 P* s7 ^! ^- w7 q! H
  100.     /* C = A * B *// M3 Z" I/ F$ `; F! K& n
  101.     /* Multiply the inputs and store the results in output buffer */
      }& ^; p$ j) k( @' t
  102.     *pDst++ = (*pSrcA++) * (*pSrcB++);+ o8 Q1 ^  V: O
  103. + l% u  C- x" Y0 b/ J2 Y* x" Y
  104.     /* Decrement the blockSize loop counter */- m7 ~8 ^! U- \0 a. }5 l- E3 d
  105.     blkCnt--;
      U, q9 F" @4 t* t7 {8 T- Q
  106.   }% [& s" W9 y3 F% s4 _8 M8 r" N1 j$ r- c
  107. }
复制代码
1. 浮点的32位乘法比较简单,这里依然是以4次的计算为一组。
8.4.2 arm_mult_q31
    这个函数用于求32位定点数的乘法,源代码分析如下:
  1. /**   
    ) t, y  `0 D% n1 k5 o2 Z* C; f7 U
  2. * @brief Q31 vector multiplication.    5 X7 T+ e" Z4 |# h1 _- p
  3. * @param[in]       *pSrcA points to the first input vector   
    9 v+ Q4 D  V6 |5 f6 x" B7 N
  4. * @param[in]       *pSrcB points to the second input vector   
    / t) v" Q; H- e$ r  Y9 ~$ M
  5. * @param[out]      *pDst points to the output vector    0 G# r/ g! d; c
  6. * @param[in]       blockSize number of samples in each vector   
    . L' b6 p& L$ E: P
  7. * @return none.    4 d5 M0 r; G: E# D6 O; }
  8. *    ; [) z) _7 L5 e% L. f0 g( V
  9. * <b>Scaling and Overflow Behavior:</b>                                                             (1)
    % a6 V% `6 ]9 }, Z: r, J( X
  10. * \par    / e/ X& E8 y  P- ^9 n* `3 J
  11. * The function uses saturating arithmetic.    / ]; Y- I  ]8 S& O
  12. * Results outside of the allowable Q31 range[0x80000000 0x7FFFFFFF] will be saturated.   
    ) Z& x; E# o  u- W/ L6 z
  13. */5 d( M5 W% I5 |- Q- I' F4 g3 h8 ~: u

  14. $ T* l) s1 G1 d& t' Z5 [
  15. void arm_mult_q31(
    ' ]' r0 Y  N- {
  16.   q31_t * pSrcA,
    1 f+ X3 K. N- H5 K9 g4 }- z7 C
  17.   q31_t * pSrcB,
    + l  s& L2 x: C% e& L& {- f
  18.   q31_t * pDst,( r, b  s8 p8 N" N7 A1 A3 @
  19.   uint32_t blockSize)2 \. Z3 c/ {4 q7 o' d1 k0 N
  20. {
    . ~2 ]& e7 j& ]8 ]7 v+ Z
  21.   uint32_t blkCnt;                               /* loop counters */6 a3 W# ^% P. Z" q6 ]7 V: C7 Y  i

  22. : A6 s6 O& P8 B- S& ~# v& u/ k
  23. #ifndef ARM_MATH_CM0_FAMILY) G" B8 B  V! A- i, x
  24. & d, T4 I, v' y
  25. /* Run the below code for Cortex-M4 and Cortex-M3 */; t2 @- ], [3 n
  26.   q31_t inA1, inA2, inA3, inA4;                  /* temporary input variables */
    / o2 i9 C3 [( Y3 q- t1 q) y; g
  27.   q31_t inB1, inB2, inB3, inB4;                  /* temporary input variables */
    7 Z( n1 C$ Z( t4 G( k
  28.   q31_t out1, out2, out3, out4;                  /* temporary output variables */) k/ L) d6 a1 ^1 |

  29. 4 N* S% B' h/ F$ s- H& P; F
  30.   /* loop Unrolling */2 M7 d9 M$ L; K* a0 J
  31.   blkCnt = blockSize >> 2u;  m, O6 p. Q2 Q- a& T* k

  32. - j" `1 r* ]/ m: c, f. \0 W& O4 D
  33.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.    % g; b5 c& Q& ^; Y+ }7 v% V" b4 h+ g. L
  34.    ** a second loop below computes the remaining 1 to 3 samples. */( E; J) s- B2 V
  35.   while(blkCnt > 0u)6 x$ b$ g/ ^; ^9 r, h4 m& h
  36.   {* {5 Y3 w, b. S- t5 t
  37.     /* C = A * B */1 ]' P' s( g+ t1 C' J
  38.     /* Multiply the inputs and then store the results in the destination buffer. */
    # l4 N. ?6 W7 j' _" p# z: s7 \
  39.     inA1 = *pSrcA++;# L" z: e5 d: L: o4 n. H# }% `
  40.     inA2 = *pSrcA++;
    2 W9 N$ C8 L! Z* _
  41.     inA3 = *pSrcA++;
    9 y1 w8 f0 \' C! t4 I
  42.     inA4 = *pSrcA++;
    # G8 V* @3 g8 \- @# J
  43.     inB1 = *pSrcB++;
    4 Q1 d: y9 I* E3 U0 ]& V
  44.     inB2 = *pSrcB++;1 r/ N' E$ b1 o$ N" e; X
  45.     inB3 = *pSrcB++;
    8 i2 c2 K. d& P0 Q
  46.     inB4 = *pSrcB++;
    * K8 k  C7 A0 h9 t2 E- s' k2 f% k( B! ~
  47. $ |" H( I: w! d: B
  48.     out1 = ((q63_t) inA1 * inB1) >> 32;                                                              (2), |$ T* ?0 x& L: S
  49.     out2 = ((q63_t) inA2 * inB2) >> 32;, Z" q% \% {9 X; U
  50.     out3 = ((q63_t) inA3 * inB3) >> 32;
    ' }& n) U) ~, v
  51.     out4 = ((q63_t) inA4 * inB4) >> 32;
    , R1 H' x* ^" I/ y2 I
  52. 7 y9 B: y# ~6 R( k
  53.     out1 = __SSAT(out1, 31);                                                                         (3)
    9 Q, t" L0 T2 s  Y" t( i' V
  54.     out2 = __SSAT(out2, 31);# q4 ~/ u8 q: U4 l* a
  55.     out3 = __SSAT(out3, 31);
    - k  V& G$ @. H# K# D8 c0 ~
  56.     out4 = __SSAT(out4, 31);; f" v8 `& |; P/ b$ }7 i

  57. 3 Y, G, ^5 b4 f% c
  58.     *pDst++ = out1 << 1u;                                                                            (4)
    2 q5 _, l- d# ]2 K6 I$ D. c: u
  59.     *pDst++ = out2 << 1u;0 U/ N7 ]- i5 p1 m$ y$ C% ]2 n% `& Q
  60.     *pDst++ = out3 << 1u;
    / n4 u9 u. Z* p) t
  61.     *pDst++ = out4 << 1u;
    3 M5 C* m1 z4 {6 S
  62. % I% V; @- a9 @! f& _
  63.     /* Decrement the blockSize loop counter */% |5 p1 A1 D7 E: ^( Z
  64.     blkCnt--;
    6 B+ J4 a& P! G7 l
  65.   }' V* `. l: e4 L
  66. % C7 H6 a" a" b( I, ?2 W( L* |
  67.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
    + j8 P7 `0 N) R) D/ f9 L) Z
  68.    ** No loop unrolling is used. */
    & V- y) ^7 X* ]$ Y, D+ Z2 T
  69.   blkCnt = blockSize % 0x4u;
    + X; b% D7 R1 |7 j' ^! t) W+ H
  70. : I4 [) @- D' T# x
  71. #else/ E3 e' |( I( |1 E
  72. 0 @+ M* d6 [- K
  73.   /* Run the below code for Cortex-M0 */) m" ?' M0 Z" ~) j; j& ^; d
  74. 5 q) A% r; P9 z  J& h
  75.   /* Initialize blkCnt with number of samples */# u4 L( d: H& B$ M- a
  76.   blkCnt = blockSize;
    / I: j. V6 q0 k& u) A" a3 ^
  77. - g2 |1 ?* u. T/ G- C  p. H
  78. #endif /* #ifndef ARM_MATH_CM0_FAMILY */
    # W" D# A0 w' P
  79. ( M1 D7 N# u8 |8 i) w$ Y1 K
  80.   while(blkCnt > 0u)# q- U6 U  S, ]. b& p3 Y4 Q$ ]
  81.   {3 d  y& s% @+ w2 c
  82.     /* C = A * B */0 V6 F+ \; O4 l8 i" z+ N& r. X9 |) J
  83.     /* Multiply the inputs and then store the results in the destination buffer. */* G4 M# J7 K! C7 e/ y7 f7 S8 ]
  84.     *pDst++ =& s  f! z: V8 G% o- V" H
  85.       (q31_t) clip_q63_to_q31(((q63_t) (*pSrcA++) * (*pSrcB++)) >> 31);+ X5 ^6 V: d- `  h
  86. ( p( w9 `: ~: h! y8 v# {# M
  87.     /* Decrement the blockSize loop counter */
    % H5 d+ m) @5 }- t( v) Y
  88.     blkCnt--;: h/ N1 v4 A; q- ^% O7 X8 C
  89.   }
    , I- N# h- L! Q  r. R
  90. }
复制代码
1. 这个函数使用了饱和算法。
     所得结果是Q31格式,范围Q31 range[0x80000000 0x7FFFFFFF]。
2. 所得乘积左移32位。
3. 实现31位精度的饱和运算。
4. 右移一位,保证所得结果是Q31格式。
8.4.3 arm_mult_q15
    这个函数用于求16位定点数的乘法,源代码分析如下:
  1. /**   
    / e% F& p: Z- R, I; {- L5 L
  2. * @brief           Q15 vector multiplication   
    ! P- o4 C# ]! a- ~) F
  3. * @param[in]       *pSrcA points to the first input vector   
    7 `% S0 d# l, A: D+ \8 `+ [% t+ Z
  4. * @param[in]       *pSrcB points to the second input vector    " J* n0 N. n9 Q2 I6 E, [$ ]% ~7 g
  5. * @param[out]      *pDst points to the output vector   
    ) I/ @+ C/ f" @' N
  6. * @param[in]       blockSize number of samples in each vector    ! X' O. p4 ~: x, P! e4 C% v
  7. * @return none.   
    5 W1 T4 W3 l: w% M( E* D
  8. *    9 {$ F9 v7 {6 B! H
  9. * <b>Scaling and Overflow Behavior:</b>                                                              (1)
    + e) a( `2 G. P% U, r
  10. * \par    6 d6 W% @# d- R, H) B6 r1 q
  11. * The function uses saturating arithmetic.    % X2 C8 H9 a# D- t
  12. * Results outside of the allowable Q15 range [0x8000 0x7FFF] will be saturated.    2 }% a* D1 v4 ]$ l5 J/ P9 |6 U' o4 X6 z$ }
  13. */
    * E/ Z0 A1 ^4 d! g4 c  D
  14. ) d* D4 W+ W3 E/ V+ F, e2 C6 `
  15. void arm_mult_q15(
    ( r+ j/ a! z! q
  16.   q15_t * pSrcA,4 U0 q( ]+ x' Q% `! ]$ {- N0 B/ ^
  17.   q15_t * pSrcB,. i0 G: }3 K( \4 l6 W0 K
  18.   q15_t * pDst,
    8 `8 u/ F  s# L  e+ \7 ~
  19.   uint32_t blockSize)
    % u; Q) g2 S* u" E+ ]2 E
  20. {
    5 ?0 ]. c6 d# |7 }
  21.   uint32_t blkCnt;                               /* loop counters */1 \" X- c1 i2 N  K4 V# ^
  22. ' F! x+ V2 N) O. A5 ^: O: D: j
  23. #ifndef ARM_MATH_CM0_FAMILY2 V( F# ~3 B* x; Q$ N8 S

  24. * f- j/ O/ I# O' L) i7 w0 T
  25. /* Run the below code for Cortex-M4 and Cortex-M3 */
    ; ]) \, \$ K  k$ |8 g6 [% k$ t8 }
  26.   q31_t inA1, inA2, inB1, inB2;                  /* temporary input variables */
    " d3 F; e6 L; R4 D
  27.   q15_t out1, out2, out3, out4;                  /* temporary output variables */4 ~1 e7 K2 K8 T" G9 w+ Q$ p
  28.   q31_t mul1, mul2, mul3, mul4;                  /* temporary variables */
    + E% X: j8 s& O+ l4 G/ v+ n# C
  29. ( n8 `8 l* I3 ~2 S
  30.   /* loop Unrolling */4 u; P" ^& S/ f
  31.   blkCnt = blockSize >> 2u;
    ( H1 O& Q+ _, `2 s
  32. 0 a9 H2 V, r4 N+ M
  33.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.        
    . t- Q- F- N% l4 h
  34.    ** a second loop below computes the remaining 1 to 3 samples. */
    6 C# I) N5 a/ w6 l/ h0 E8 g& @
  35.   while(blkCnt > 0u)0 R  j7 o$ X; k
  36.   {" E5 x, a1 l2 Y: f
  37.     /* read two samples at a time from sourceA */
    $ R' l' ~# D( }+ @2 L$ c; a
  38.     inA1 = *__SIMD32(pSrcA)++;                                                                     (2)' y1 V) h) c7 T8 W+ i( Q: p
  39.     /* read two samples at a time from sourceB */
    4 l" u  ?- x3 V5 s8 i+ O( x3 k
  40.     inB1 = *__SIMD32(pSrcB)++;' N6 @* H2 W2 ]! W' {
  41.     /* read two samples at a time from sourceA */1 S3 x- Q; g- Q  G7 e& E0 F
  42.     inA2 = *__SIMD32(pSrcA)++;
    5 O7 q- ~4 ?+ C2 _5 @/ A5 d
  43.     /* read two samples at a time from sourceB */
    ; R! x* y  W$ E4 B9 r6 X# S0 t4 G2 _
  44.     inB2 = *__SIMD32(pSrcB)++;& z/ |1 B* t- v- u
  45. ( f8 L# c+ n! k: K
  46.     /* multiply mul = sourceA * sourceB */) B, w5 S, M2 b  L
  47.     mul1 = (q31_t) ((q15_t) (inA1 >> 16) * (q15_t) (inB1 >> 16));                                  (3)
    1 \5 r4 X+ X" J( t' {# e
  48.     mul2 = (q31_t) ((q15_t) inA1 * (q15_t) inB1);
    # Q5 I- d5 Q0 w' D# |2 Y9 X
  49.     mul3 = (q31_t) ((q15_t) (inA2 >> 16) * (q15_t) (inB2 >> 16));0 \4 V7 V5 d, S& g6 _! s* m6 L) }0 F
  50.     mul4 = (q31_t) ((q15_t) inA2 * (q15_t) inB2);
    - o% K3 P) J* f8 f" `6 Q
  51. ' l' F2 ?  c% S
  52.     /* saturate result to 16 bit */9 P- [( S0 v; F: E2 N7 ?8 }6 m
  53.     out1 = (q15_t) __SSAT(mul1 >> 15, 16);                                                         (4)9 @4 z8 Q* y. P
  54.     out2 = (q15_t) __SSAT(mul2 >> 15, 16);5 x& s8 L* \5 H, r/ O" B
  55.     out3 = (q15_t) __SSAT(mul3 >> 15, 16);+ ?  q: T6 F, C6 i; s
  56.     out4 = (q15_t) __SSAT(mul4 >> 15, 16);! [/ Z1 Z2 [; b+ [7 b/ N) e
  57. ; _& H4 g) \$ t# B
  58.     /* store the result */. q0 y* f0 ^6 x2 X0 m; G: p
  59. #ifndef ARM_MATH_BIG_ENDIAN
    9 d: X+ B5 J0 s# {$ J! Z
  60. " E  a; w/ m& |6 A1 h# _9 Q
  61.     *__SIMD32(pDst)++ = __PKHBT(out2, out1, 16);                                                   (5)0 R# q( ~' t" ~) U7 I& Z! E
  62.     *__SIMD32(pDst)++ = __PKHBT(out4, out3, 16);
    1 ]8 u+ u1 U8 k. K2 }
  63. ) U$ S0 K( ~2 N. K6 j0 o7 ~
  64. #else$ f5 `. U$ l# p% w  D) f+ T2 x+ @5 H
  65. & y( l" X9 \8 ?7 S2 {
  66.     *__SIMD32(pDst)++ = __PKHBT(out2, out1, 16);0 h* S" w/ R6 O2 ~/ I& ^
  67.     *__SIMD32(pDst)++ = __PKHBT(out4, out3, 16);
    $ ?( J/ j1 y& ]+ G1 L8 Q. A
  68. 3 z3 F# _  K- {: p  e
  69. #endif //      #ifndef ARM_MATH_BIG_ENDIAN) m* b  `& R! g0 e  ^
  70. , d( H* ~, ]( W6 Y! e& a
  71.     /* Decrement the blockSize loop counter */
      T' f. W9 N/ f' u" k' s4 {' T) r! s
  72.     blkCnt--;) p3 k  l% }' v" A" D
  73.   }
    ' x9 B$ @0 {5 O8 {- g) ^/ A0 t
  74. 5 q8 f! f- p6 J: J
  75.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
    ) b6 O; W# q! h' e' Z7 q: q( v
  76.    ** No loop unrolling is used. */+ w0 m+ Z$ G1 |" P3 B
  77.   blkCnt = blockSize % 0x4u;' E, m9 Z- R0 V( J" v, e
  78. 2 D' D0 o9 k; c7 n) [* l$ c7 q  ?
  79. #else" \. q) G" c. v- q. S
  80. 2 a" a+ q" ]1 [! k4 A. H
  81.   /* Run the below code for Cortex-M0 */
    7 E. D. D& z& |. @5 Z5 ~
  82. # {- w: W4 O/ t' [: |, z1 f9 `
  83.   /* Initialize blkCnt with number of samples */5 ]- z& ?/ g0 o. z
  84.   blkCnt = blockSize;
    / P( @' J) t" V4 p9 Z6 z( r* K, F) b
  85. 8 x: F6 D5 T+ S0 }( E
  86. #endif /* #ifndef ARM_MATH_CM0_FAMILY */" J! X1 C- a+ _5 r. Y9 x2 a

  87. + s7 \$ K5 A- c; R( i

  88. 8 \. ?. T% o; b
  89.   while(blkCnt > 0u)/ t. ^" j8 u) N$ x0 r
  90.   {
    4 t+ ~& ]9 _+ |0 B) P
  91.     /* C = A * B */, S. _3 k" p$ L6 X6 h) ^2 K
  92.     /* Multiply the inputs and store the result in the destination buffer */
    6 v0 o/ O7 L/ ?$ d- e- s% ]5 h$ K
  93.     *pDst++ = (q15_t) __SSAT((((q31_t) (*pSrcA++) * (*pSrcB++)) >> 15), 16);" N" A: [8 i  \/ A3 |6 Z, P( R
  94.   L+ n6 ?+ m$ d1 I5 i
  95.     /* Decrement the blockSize loop counter */
    ) c) k' G3 N% A% L" ]
  96.     blkCnt--;
    ) q6 u4 f$ ]& e2 w5 n1 x
  97.   }! `' Q- M' V6 {: M0 V. f' T1 x& ^/ a" C
  98. }
复制代码
1. 这个函数使用了饱和算法。
    所得结果是Q15格式,范围 [0x8000  0x7FFF]。
2. 一次读取两个Q15格式的数据。
3. 将四组数的乘积保存到Q31格式的变量mul1,mul2,mul3,mul4。
4. 丢弃32位数据的低15位,并把最终结果饱和到16位精度。
5. 通过SIMD指令__PKHBT将两个Q15格式的数据保存的结果数组中,从而一个指令周期就能完成两个数据的存储。
8.4.4 arm_mult_q7
    这个函数用于求8位定点数的乘法,源代码分析如下:
  1. /**    4 [' X0 Z; k# E  w* P' h# d
  2. * @brief           Q7 vector multiplication   
    & U6 S3 f& D& b' t2 {1 P9 p
  3. * @param[in]       *pSrcA points to the first input vector   
    9 R7 c" v. E, ~8 [# o. @
  4. * @param[in]       *pSrcB points to the second input vector   
    8 l  k7 p1 E, X
  5. * @param[out]      *pDst points to the output vector   
      Q7 {+ Z( i: B0 P* J3 ?9 D
  6. * @param[in]       blockSize number of samples in each vector    . V# v7 [. s" X( Z- C. Q
  7. * @return none.   
    ! A& s" M: H( R0 p( T  x3 F
  8. *   
    . F* U4 A  u, i5 C
  9. * <b>Scaling and Overflow Behavior:</b>                                                             (1)0 C: M7 P" S# L  z. p+ q
  10. * \par    4 _' J  C- Y/ a# i; J; s$ \
  11. * The function uses saturating arithmetic.   
    ! _5 m1 h3 b9 T" \, ?
  12. * Results outside of the allowable Q7 range [0x80 0x7F] will be saturated.   
    % ^+ N1 {7 \# m
  13. */
    : H; L" M- [: S. c0 e

  14. 4 X1 _( L' w- v- H) n2 _+ S
  15. void arm_mult_q7(2 z9 ]' u8 u, z( P, a/ P1 S1 z0 F; S# k
  16.   q7_t * pSrcA,5 [2 ~0 A' v' _: M
  17.   q7_t * pSrcB,# |: m$ t. [2 b# m' c
  18.   q7_t * pDst,
    9 \% I! N. P1 F3 F( D5 b- |9 F
  19.   uint32_t blockSize)6 v) ^. O  |4 M. U! N# N
  20. {
    5 q9 O1 W7 c7 {. t. K
  21.   uint32_t blkCnt;                               /* loop counters */
    ( U+ M) t1 l+ e; M% n; P6 S* v3 u/ i

  22. 9 K) e: ]: U2 T0 J
  23. #ifndef ARM_MATH_CM0_FAMILY
    1 R8 A5 Y6 K6 E! J) b' ?
  24. ( J( p) _9 ~& n) R" U1 z. P: J
  25. /* Run the below code for Cortex-M4 and Cortex-M3 */
    8 r, ~! h. b# q% {
  26.   q7_t out1, out2, out3, out4;                   /* Temporary variables to store the product */
    $ x1 B' v+ \/ o2 u; \, F
  27. : x  Z- E5 e7 m: [* w/ M6 F- z
  28.   /* loop Unrolling */0 [9 C: y$ I; A. h8 P- }7 A
  29.   blkCnt = blockSize >> 2u;* R) ~+ V, g+ k# ]' Q# U4 _
  30. * }( p2 ?+ t3 L' ?" T. {/ m, g# L
  31.   /* First part of the processing with loop unrolling.  Compute 4 outputs at a time.   
    + z# u/ H0 D! r* j  M4 P& A
  32.    ** a second loop below computes the remaining 1 to 3 samples. */
    - j/ {( R. b! }8 G/ g4 E( p
  33.   while(blkCnt > 0u)8 z) A1 a! Y$ w, D
  34.   {& p6 n) o, S, w" D4 h6 ]  A* D: N
  35.     /* C = A * B */
    8 v  a( k- ], ~, S: A; G& f
  36.     /* Multiply the inputs and store the results in temporary variables */                          (2)
    2 }9 N8 F& y, b- v/ c- o; X6 }
  37.     out1 = (q7_t) __SSAT((((q15_t) (*pSrcA++) * (*pSrcB++)) >> 7), 8);" ?! U% G1 ~! K! @4 t, V
  38.     out2 = (q7_t) __SSAT((((q15_t) (*pSrcA++) * (*pSrcB++)) >> 7), 8);
    ; N5 z2 S2 j$ `+ s
  39.     out3 = (q7_t) __SSAT((((q15_t) (*pSrcA++) * (*pSrcB++)) >> 7), 8);
    - W; |+ N* R$ k! O/ C: X5 n
  40.     out4 = (q7_t) __SSAT((((q15_t) (*pSrcA++) * (*pSrcB++)) >> 7), 8);
    3 ?5 V* z& T/ C$ i
  41. 5 T5 a2 c$ }, N* I8 m% }
  42.     /* Store the results of 4 inputs in the destination buffer in single cycle by packing */% P9 L5 N1 X# O0 [, H  o
  43.     *__SIMD32(pDst)++ = __PACKq7(out1, out2, out3, out4);                                          (3)4 i! I& r5 E" Y/ R4 j% z

  44. + B5 a4 O* b4 f
  45.     /* Decrement the blockSize loop counter */
    0 B+ p* S! G0 p7 a5 I
  46.     blkCnt--;
    $ W2 E9 @; K. l  J5 w/ O. c/ c. g) ?  P
  47.   }
    ( T+ b% ~' l/ a

  48. " m: [7 @+ v# ^* {" }0 U+ b
  49.   /* If the blockSize is not a multiple of 4, compute any remaining output samples here.   
    * q0 l: `# D3 r& |* n
  50.    ** No loop unrolling is used. */" S: C  G' I: z+ @: D
  51.   blkCnt = blockSize % 0x4u;
    " ?7 `9 W, e6 v3 [6 |. D5 w0 ]( k
  52. 8 ~& N9 D1 ~: I, P# {4 ~
  53. #else
    2 J. l5 s, x. _
  54. 1 A6 t' {5 g& [& E
  55.   /* Run the below code for Cortex-M0 */
    $ i# \5 K+ L/ f7 `4 e. h' k

  56. ; {8 q( i5 ?7 B2 K( K
  57.   /* Initialize blkCnt with number of samples *// C3 U! Z- Z5 r# e. {
  58.   blkCnt = blockSize;1 N* c$ i# [3 f: Y8 p1 w
  59. / X2 g1 A% s7 D4 J1 q" `. ~8 \' b$ u# R
  60. #endif /* #ifndef ARM_MATH_CM0_FAMILY */5 b: [( s" V8 S  h( n) R  [2 b

  61. & m: T% z8 G4 G1 L/ W# Y/ Q
  62. $ l6 M" n" B1 [$ I
  63.   while(blkCnt > 0u)
    8 p* s& b+ j. F7 }& i8 I+ ]
  64.   {8 W0 R) _5 f8 ?1 Q/ P9 ]1 p
  65.     /* C = A * B */
    * a, G7 P% E/ T5 n
  66.     /* Multiply the inputs and store the result in the destination buffer */  G8 K3 T, \4 z
  67.     *pDst++ = (q7_t) __SSAT((((q15_t) (*pSrcA++) * (*pSrcB++)) >> 7), 8);( H8 i4 e  p* d0 U6 ^3 t

  68. 9 K" ^9 z' H3 O
  69.     /* Decrement the blockSize loop counter */9 o1 @* c# x! a5 Q
  70.     blkCnt--;7 A) H% q9 H( H) t
  71.   }3 Z& E% O  z/ O# c' A; e! x
  72. }
复制代码
1. 这个函数使用了饱和算法。
    所得结果是Q7格式,范围 [0x80  0x7F]。
2. 将两个Q7格式的数据乘积左移7位,也就是丢掉低7位的数据,并将所得结果饱和到8位精度。
3. __PACKq7函数可以在一个时钟周期就能完成相应操作。
8.4.5 实例讲解
实验目的:
1. 四种类型数据的乘法。
实验内容:
1. 按下摇杆的UP键, 串口打印输出结果
实验现象:
        通过窗口上位机软件SecureCRT(V5光盘里面有此软件)查看打印信息现象如下:
8.4.png
程序设计:
  1. /*8 M0 X& i, x# l8 P( i
  2. *********************************************************************************************************
    % ?! Y" I7 ^; n
  3. *        函 数 名: DSP_Multiplication
    5 ]- @; f0 H2 F; L) n% j
  4. *        功能说明: 乘法0 i& G/ x5 b) c1 l2 o
  5. *        形    参:无- C1 I+ P' ?) g$ L5 N. m
  6. *        返 回 值: 无  @+ P/ r1 k4 t# @) {
  7. *********************************************************************************************************9 {2 T! O+ g% ]% u! l( t4 m. y6 c5 ?
  8. */) o1 z" u9 ]' V5 m
  9. static void DSP_Multiplication(void)
    ! h* k8 v. ~! u) s5 d
  10. {
    + \  a9 E! B; e( D3 l
  11. static float32_t   pSrcA[5] = {1.0f,1.0f,1.0f,1.0f,1.0f};
    / W" e$ Q! v$ g7 M
  12. static float32_t   pSrcB[5] = {1.0f,1.0f,1.0f,1.0f,1.0f};  
    ' C( d9 T! |# _
  13. static float32_t   pDst[5];  
    % W- S, y: t( I/ M' x/ t7 w7 r: Y( P
  14. static q31_t  pSrcA1[5] = {1,1,1,1,1};  
    # _& u5 C  z8 i4 j; e- {8 n
  15. static q31_t  pSrcB1[5] = {1,1,1,1,1};  
    8 t0 k7 Q  \& Q! n. i( r+ f
  16. static q31_t  pDst1[5];   . H( E( q" y& D: {9 k

  17. 8 c1 F( y+ k; K- _4 z+ U0 i* q
  18. static q15_t  pSrcA2[5] = {1,1,1,1,1};  
    5 |2 l6 H. M5 t6 |5 t, X
  19. static q15_t  pSrcB2[5] = {1,1,1,1,1};  ( {3 R% d/ k) z" O
  20. static q15_t  pDst2[5];   
    : M( I  n( X9 k
  21. & k$ c0 E, g4 Q+ L+ w# W; c
  22. static q7_t  pSrcA3[5] = {0x70,1,1,1,1}; , m  j+ n7 x  M* T( m
  23. static q7_t  pSrcB3[5] = {0x7f,1,1,1,1};  
    7 C. s( p7 q& \# Y
  24. static q7_t pDst3[5];  
    # o6 {# N1 ^1 }( G

  25. , C  b# g+ O6 ?
  26. pSrcA[0] += 1.1f;
    , t9 I1 h- |' H* [7 u6 a% {
  27. arm_mult_f32(pSrcA, pSrcB, pDst, 5);
    4 U' G0 L* t5 ?! W% x4 ~: @
  28. printf("arm_mult_f32 = %f\r\n", pDst[0]);2 D% y* F2 K; C$ ?! L3 Z
  29. pSrcA1[0] += 1;
    , o4 U8 }; w. G& w" L
  30. arm_mult_q31(pSrcA1, pSrcB1, pDst1, 5);
    9 G+ \5 z. T: K$ \" d: O! C% k
  31. printf("arm_mult_q31 = %d\r\n", pDst1[0]);* r" e) Y  C  F. _- _2 H  e$ K

  32.   n0 y) ^/ \5 O: ~5 ^2 `$ p) ^4 P4 }
  33. pSrcA2[0] += 1;
    , Y4 `. m& S0 W' p/ Y5 q
  34. arm_mult_q15(pSrcA2, pSrcB2, pDst2, 5);0 K' u, I: ?! p0 \* e) m1 q+ j
  35. printf("arm_mult_q15 = %d\r\n", pDst2[0]);
    0 l, E$ v* y; T& |' _* Q+ B+ R

  36. 3 Z, ^. N, P$ i; x( V8 }- m
  37. pSrcA3[0] += 1;
    8 x5 m7 H  i. _4 U6 u, s
  38. arm_mult_q7(pSrcA3, pSrcB3, pDst3, 5);
    " S8 I) a5 x$ n4 P3 k- I
  39. printf("arm_mult_q7 = %d\r\n", pDst3[0]);
    * j4 ?  T% l8 ^* j2 c3 x, G
  40. printf("***********************************\r\n");+ a0 w1 z/ Q" {+ M+ V% P
  41. }
复制代码
! d5 m/ W* j3 m/ z$ m$ u1 T8 h
8.5 总结
    本期教程就跟大家讲这么多,还是那句话,可以自己写些代码调用本期教程中讲的这几个函数,如果可以的话,可以自己尝试直接调用这些DSP指令。
9 f1 _4 j2 U' z. f/ T
MouseCat 回答时间:2015-3-18 11:48:26
沙发,收藏
kqh1120 回答时间:2015-3-18 13:48:34
谢谢分享啊 3.gif
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版