【STM32F407的DSP教程】第12章 DSP基础函数-相反数,偏移,移位,减法和比例因子

时间:2024-03-23 09:26:29

完整版教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=94547

第12章       DSP基础函数-相反数,偏移,移位,减法和比例因子

本期教程主要讲基本函数中的相反数,偏移,移位,减法和比例因子。

目录

第12章       DSP基础函数-相反数,偏移,移位,减法和比例因子

12.1 初学者重要提示

12.2 DSP基础运算指令

12.3 相反数(Vector Negate)

12.3.1        函数arm_negate_f32

12.3.2        函数arm_negate _q31

12.3.3        函数arm_negate_q15

12.3.4        函数arm_negate_q7

12.3.5        使用举例

12.4 偏移(Vector Offset)

12.4.1        函数arm_offset_f32

12.4.2        函数arm_offset_q31

12.4.3        函数arm_offset_q15

12.4.4        函数arm_offset_q7

12.4.5        使用举例

12.5 移位(Vector Shift)

12.5.1        函数arm_shift_q31

12.5.2        函数arm_shift_q15

12.5.3        函数arm_shift_q7

12.5.4        使用举例

12.6 减法(Vector Sub)

12.6.1        函数arm_sub_f32

12.6.2        函数arm_sub_q31

12.6.3        函数arm_sub_q15

12.6.4        函数arm_sub_q7

12.6.5        使用举例

12.7 比例因子(Vector Scale)

12.7.1        函数arm_scale_f32

12.7.2        函数arm_scale_q31

12.7.3        函数arm_scale_q15

12.7.4        函数arm_scale_q7

12.7.5        使用举例

12.8 实验例程说明(MDK)

12.9 实验例程说明(IAR)

12.10   总结


 

12.1 初学者重要提示

在这里简单的跟大家介绍一下DSP库中函数的通用格式,后面就不再赘述了。

  1.   这些函数基本都是支持重入的。
  2.   基本每个函数都有四种数据类型,F32,Q31,Q15,Q7。
  3.   函数中数值的处理基本都是4个为一组,这么做的原因是F32,Q31,Q15,Q7就可以统一采用一个程序设计架构,便于管理。更重要的是可以在Q15和Q7数据处理中很好的发挥SIMD指令的作用(因为4个为一组的话,可以用SIMD指令正好处理2个Q15数据或者4个Q7数据)。
  4.   部分函数是支持目标指针和源指针指向相同的缓冲区。
  5.   为什么定点DSP运算输出的时候容易出现结果为0的情况:http://www.armbbs.cn/forum.php?mod=viewthread&tid=95194

12.2 DSP基础运算指令

本章用到基础运算指令:

  •   相反数函数用到QSUB,QSUB16和QSUB8。
  •   偏移函数用到QADD,QADD16和QADD8。
  •   移位函数用到PKHBT和SSAT。
  •   减法函数用到QSUB,QSUB16和QSUB8。
  •   比例因子函数用到PKHBT和SSAT。

 

这里特别注意饱和运算问题,在第11章的第2小节有详细说明。

12.3 相反数(Vector Negate)

这部分函数主要用于求相反数,公式描述如下:

pDst[n] = -pSrc[n],   0 <= n < blockSize.  

特别注意,这部分函数支持目标指针和源指针指向相同的缓冲区。

12.3.1        函数arm_negate_f32

函数原型:

 

1.    void arm_negate_f32(
2.      const float32_t * pSrc,
3.            float32_t * pDst,
4.            uint32_t blockSize)
5.    {
6.            uint32_t blkCnt;                               /* Loop counter */
7.    
8.    #if defined(ARM_MATH_NEON_EXPERIMENTAL)
9.        float32x4_t vec1;
10.        float32x4_t res;
11.    
12.        /* Compute 4 outputs at a time */
13.        blkCnt = blockSize >> 2U;
14.    
15.        while (blkCnt > 0U)
16.        {
17.            /* C = -A */
18.    
19.            /* Negate and then store the results in the destination buffer. */
20.            vec1 = vld1q_f32(pSrc);
21.            res = vnegq_f32(vec1);
22.            vst1q_f32(pDst, res);
23.    
24.            /* Increment pointers */
25.            pSrc += 4;
26.            pDst += 4;
27.            
28.            /* Decrement the loop counter */
29.            blkCnt--;
30.        }
31.    
32.        /* Tail */
33.        blkCnt = blockSize & 0x3;
34.    
35.    #else
36.    #if defined (ARM_MATH_LOOPUNROLL)
37.    
38.      /* Loop unrolling: Compute 4 outputs at a time */
39.      blkCnt = blockSize >> 2U;
40.    
41.      while (blkCnt > 0U)
42.      {
43.        /* C = -A */
44.    
45.        /* Negate and store result in destination buffer. */
46.        *pDst++ = -*pSrc++;
47.    
48.        *pDst++ = -*pSrc++;
49.    
50.        *pDst++ = -*pSrc++;
51.    
52.        *pDst++ = -*pSrc++;
53.    
54.        /* Decrement loop counter */
55.        blkCnt--;
56.      }
57.    
58.      /* Loop unrolling: Compute remaining outputs */
59.      blkCnt = blockSize % 0x4U;
60.    
61.    #else
62.    
63.      /* Initialize blkCnt with number of samples */
64.      blkCnt = blockSize;
65.    
66.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
67.    #endif /* #if defined(ARM_MATH_NEON_EXPERIMENTAL) */
68.    
69.      while (blkCnt > 0U)
70.      {
71.        /* C = -A */
72.    
73.        /* Negate and store result in destination buffer. */
74.        *pDst++ = -*pSrc++;
75.    
76.        /* Decrement loop counter */
77.        blkCnt--;
78.      }
79.    
80.    }

 

函数描述:

这个函数用于求32位浮点数的相反数。

函数解析:

  •   第8到35行,用于NEON指令集,当前的CM内核不支持。
  •   第36到61行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
  •   浮点数的相反数求解比较简单,直接在相应的变量前加上负号即可。
  •   第69到78行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。

函数参数:

  •   第1个参数是原数据地址。
  •   第2个参数是求相反数后目的数据地址。
  •   第3个参数转换的数据个数,这里是指的浮点数个数。

12.3.2        函数arm_negate _q31

函数原型:

 

1.    void arm_negate_q31(
2.      const q31_t * pSrc,
3.            q31_t * pDst,
4.            uint32_t blockSize)
5.    {
6.            uint32_t blkCnt;                               /* Loop counter */
7.            q31_t in;                                      /* Temporary input variable */
8.    
9.    #if defined (ARM_MATH_LOOPUNROLL)
10.    
11.      /* Loop unrolling: Compute 4 outputs at a time */
12.      blkCnt = blockSize >> 2U;
13.    
14.      while (blkCnt > 0U)
15.      {
16.        /* C = -A */
17.    
18.        /* Negate and store result in destination buffer. */
19.        in = *pSrc++;
20.    #if defined (ARM_MATH_DSP)
21.        *pDst++ = __QSUB(0, in);
22.    #else
23.        *pDst++ = (in == INT32_MIN) ? INT32_MAX : -in;
24.    #endif
25.    
26.        in = *pSrc++;
27.    #if defined (ARM_MATH_DSP)
28.        *pDst++ = __QSUB(0, in);
29.    #else
30.        *pDst++ = (in == INT32_MIN) ? INT32_MAX : -in;
31.    #endif
32.    
33.        in = *pSrc++;
34.    #if defined (ARM_MATH_DSP)
35.        *pDst++ = __QSUB(0, in);
36.    #else
37.        *pDst++ = (in == INT32_MIN) ? INT32_MAX : -in;
38.    #endif
39.    
40.        in = *pSrc++;
41.    #if defined (ARM_MATH_DSP)
42.        *pDst++ = __QSUB(0, in);
43.    #else
44.        *pDst++ = (in == INT32_MIN) ? INT32_MAX : -in;
45.    #endif
46.    
47.        /* Decrement loop counter */
48.        blkCnt--;
49.      }
50.    
51.      /* Loop unrolling: Compute remaining outputs */
52.      blkCnt = blockSize % 0x4U;
53.    
54.    #else
55.    
56.      /* Initialize blkCnt with number of samples */
57.      blkCnt = blockSize;
58.    
59.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
60.    
61.      while (blkCnt > 0U)
62.      {
63.        /* C = -A */
64.    
65.        /* Negate and store result in destination buffer. */
66.        in = *pSrc++;
67.    #if defined (ARM_MATH_DSP)
68.        *pDst++ = __QSUB(0, in);
69.    #else
70.        *pDst++ = (in == INT32_MIN) ? INT32_MAX : -in;
71.    #endif
72.    
73.        /* Decrement loop counter */
74.        blkCnt--;
75.      }
76.    
77.    }

 

函数描述:

用于求32位定点数的相反数。

函数解析:

  •   第9到54行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
  •   第61到75行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。
  •   对于Q31格式的数据,饱和运算会使得数据0x80000000变成0x7fffffff,因为最小负数0x80000000(对应浮点数-1),求相反数后,是个正的0x80000000(对应浮点数正1),已经超过Q31所能表示的最大值0x7fffffff,因此会被饱和处理为正数最大值0x7fffffff。
  •   这里重点说一下函数__QSUB,其实这个函数算是Cortex-M7,M4/M3的一个指令,用于实现饱和减法。比如函数:__QSUB(0, in1) 的作用就是实现0 – in1并返回结果。这里__QSUB实现的是32位数的饱和减法。还有__QSUB16和__QSUB8实现的是16位和8位数的减法。

函数参数:

  •   第1个参数是原数据地址。
  •   第2个参数是求相反数后目的数据地址。
  •   第3个参数转换的数据个数,这里是指的定点数个数。

12.3.3        函数arm_negate_q15

函数原型:

 

1.    void arm_negate_q15(
2.      const q15_t * pSrc,
3.            q15_t * pDst,
4.            uint32_t blockSize)
5.    {
6.            uint32_t blkCnt;                               /* Loop counter */
7.            q15_t in;                                      /* Temporary input variable */
8.    
9.    #if defined (ARM_MATH_LOOPUNROLL)
10.    
11.    #if defined (ARM_MATH_DSP)
12.      q31_t in1;                                    /* Temporary input variables */
13.    #endif
14.    
15.      /* Loop unrolling: Compute 4 outputs at a time */
16.      blkCnt = blockSize >> 2U;
17.    
18.      while (blkCnt > 0U)
19.      {
20.        /* C = -A */
21.    
22.    #if defined (ARM_MATH_DSP)
23.        /* Negate and store result in destination buffer (2 samples at a time). */
24.        in1 = read_q15x2_ia ((q15_t **) &pSrc);
25.        write_q15x2_ia (&pDst, __QSUB16(0, in1));
26.    
27.        in1 = read_q15x2_ia ((q15_t **) &pSrc);
28.        write_q15x2_ia (&pDst, __QSUB16(0, in1));
29.    #else
30.        in = *pSrc++;
31.        *pDst++ = (in == (q15_t) 0x8000) ? (q15_t) 0x7fff : -in;
32.    
33.        in = *pSrc++;
34.        *pDst++ = (in == (q15_t) 0x8000) ? (q15_t) 0x7fff : -in;
35.    
36.        in = *pSrc++;
37.        *pDst++ = (in == (q15_t) 0x8000) ? (q15_t) 0x7fff : -in;
38.    
39.        in = *pSrc++;
40.        *pDst++ = (in == (q15_t) 0x8000) ? (q15_t) 0x7fff : -in;
41.    #endif
42.    
43.        /* Decrement loop counter */
44.        blkCnt--;
45.      }
46.    
47.      /* Loop unrolling: Compute remaining outputs */
48.      blkCnt = blockSize % 0x4U;
49.    
50.    #else
51.    
52.      /* Initialize blkCnt with number of samples */
53.      blkCnt = blockSize;
54.    
55.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
56.    
57.      while (blkCnt > 0U)
58.      {
59.        /* C = -A */
60.    
61.        /* Negate and store result in destination buffer. */
62.        in = *pSrc++;
63.        *pDst++ = (in == (q15_t) 0x8000) ? (q15_t) 0x7fff : -in;
64.    
65.        /* Decrement loop counter */
66.        blkCnt--;
67.      }
68.    
69.    }

 

函数描述:

用于求16位定点数的绝对值。

函数解析:

  •   第9到50行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
  •   第57到67行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。
  •   对于Q15格式的数据,饱和运算会使得数据0x8000求相反数后饱和为0x7fff。因为最小负数0x8000(对应浮点数-1),求相反数后,是个正的0x8000(对应浮点数正1),已经超过Q15所能表示的最大值0x7fff,因此会被饱和处理为正数最大值0x7fff。
  •   __QSUB16用于实现16位数据的饱和减法。

函数参数:

  •   第1个参数是原数据地址。
  •   第2个参数是求相反数后目的数据地址。
  •   第3个参数转换的数据个数,这里是指的定点数个数。

12.3.4        函数arm_negate_q7

函数原型:

 

1.    void arm_negate_q7(
2.      const q7_t * pSrc,
3.            q7_t * pDst,
4.            uint32_t blockSize)
5.    {
6.            uint32_t blkCnt;                               /* Loop counter */
7.            q7_t in;                                       /* Temporary input variable */
8.    
9.    #if defined (ARM_MATH_LOOPUNROLL)
10.    
11.    #if defined (ARM_MATH_DSP)
12.      q31_t in1;                                    /* Temporary input variable */
13.    #endif
14.    
15.      /* Loop unrolling: Compute 4 outputs at a time */
16.      blkCnt = blockSize >> 2U;
17.    
18.      while (blkCnt > 0U)
19.      {
20.        /* C = -A */
21.    
22.    #if defined (ARM_MATH_DSP)
23.        /* Negate and store result in destination buffer (4 samples at a time). */
24.        in1 = read_q7x4_ia ((q7_t **) &pSrc);
25.        write_q7x4_ia (&pDst, __QSUB8(0, in1));
26.    #else
27.        in = *pSrc++;
28.        *pDst++ = (in == (q7_t) 0x80) ? (q7_t) 0x7f : -in;
29.    
30.        in = *pSrc++;
31.        *pDst++ = (in == (q7_t) 0x80) ? (q7_t) 0x7f : -in;
32.    
33.        in = *pSrc++;
34.        *pDst++ = (in == (q7_t) 0x80) ? (q7_t) 0x7f : -in;
35.    
36.        in = *pSrc++;
37.        *pDst++ = (in == (q7_t) 0x80) ? (q7_t) 0x7f : -in;
38.    #endif
39.    
40.        /* Decrement loop counter */
41.        blkCnt--;
42.      }
43.    
44.      /* Loop unrolling: Compute remaining outputs */
45.      blkCnt = blockSize % 0x4U;
46.    
47.    #else
48.    
49.      /* Initialize blkCnt with number of samples */
50.      blkCnt = blockSize;
51.    
52.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
53.    
54.      while (blkCnt > 0U)
55.      {
56.        /* C = -A */
57.    
58.        /* Negate and store result in destination buffer. */
59.        in = *pSrc++;
60.    
61.    #if defined (ARM_MATH_DSP)
62.        *pDst++ = (q7_t) __QSUB(0, in);
63.    #else
64.        *pDst++ = (in == (q7_t) 0x80) ? (q7_t) 0x7f : -in;
65.    #endif
66.    
67.        /* Decrement loop counter */
68.        blkCnt--;
69.      }
70.    
71.    }

 

函数描述:

用于求8位定点数的相反数。

函数解析:

  •   第9到47行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
  •   第54到69行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。
  •   对于Q7格式的数据,饱和运算会使得数据0x80变成0x7f。因为最小负数0x80(对应浮点数-1),求相反数后,是个正的0x80(对应浮点数正1),已经超过Q7所能表示的最大值0x7f,因此会被饱和处理为正数最大值0x7f。
  •   __QSUB8用于实现8位数据的饱和减法。

函数参数:

  •   第1个参数是原数据地址。
  •   第2个参数是求相反数后目的数据地址。
  •   第3个参数转换的数据个数,这里是指的定点数个数。

12.3.5        使用举例

程序设计:

 

/*
*********************************************************************************************************
*    函 数 名: DSP_Negate
*    功能说明: 求相反数
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void DSP_Negate(void)
{
     float32_t pSrc = 0.0f;
     float32_t pDst;
    
    q31_t pSrc1 = 0;
    q31_t pDst1;
    
    q15_t pSrc2 = 0;
    q15_t pDst2;
    
    q7_t pSrc3 = 0; 
    q7_t pDst3;
    
    /*求相反数*********************************/    
    pSrc -= 1.23f;
    arm_negate_f32(&pSrc, &pDst, 1);
    printf("arm_negate_f32 = %f\r\n", pDst);

    pSrc1 -= 1;
    arm_negate_q31(&pSrc1, &pDst1, 1);
    printf("arm_negate_q31 = %d\r\n", pDst1);

    pSrc2 -= 1;
    arm_negate_q15(&pSrc2, &pDst2, 1);
    printf("arm_negate_q15 = %d\r\n", pDst2);

    pSrc3 += 1; 
    arm_negate_q7(&pSrc3, &pDst3, 1);
    printf("arm_negate_q7 = %d\r\n", pDst3);
    printf("***********************************\r\n");
}

 

实验现象:

【STM32F407的DSP教程】第12章 DSP基础函数-相反数,偏移,移位,减法和比例因子

12.4 偏移(Vector Offset)

这部分函数主要用于求偏移,公式描述如下:

pDst[n] = pSrc[n] + offset,   0 <= n < blockSize.

    注意,这部分函数支持目标指针和源指针指向相同的缓冲区。

12.4.1        函数arm_offset_f32

函数原型:

 

1.    void arm_offset_f32(
2.      const float32_t * pSrc,
3.            float32_t offset,
4.            float32_t * pDst,
5.            uint32_t blockSize)
6.    {
7.            uint32_t blkCnt;                               /* Loop counter */
8.    
9.    #if defined(ARM_MATH_NEON_EXPERIMENTAL)
10.        float32x4_t vec1;
11.        float32x4_t res;
12.    
13.        /* Compute 4 outputs at a time */
14.        blkCnt = blockSize >> 2U;
15.    
16.        while (blkCnt > 0U)
17.        {
18.            /* C = A + offset */
19.     
20.            /* Add offset and then store the results in the destination buffer. */
21.            vec1 = vld1q_f32(pSrc);
22.            res = vaddq_f32(vec1,vdupq_n_f32(offset));
23.            vst1q_f32(pDst, res);
24.    
25.            /* Increment pointers */
26.            pSrc += 4;
27.            pDst += 4;
28.            
29.            /* Decrement the loop counter */
30.            blkCnt--;
31.        }
32.    
33.        /* Tail */
34.        blkCnt = blockSize & 0x3;
35.    
36.    #else
37.    #if defined (ARM_MATH_LOOPUNROLL)
38.    
39.      /* Loop unrolling: Compute 4 outputs at a time */
40.      blkCnt = blockSize >> 2U;
41.    
42.      while (blkCnt > 0U)
43.      {
44.        /* C = A + offset */
45.    
46.        /* Add offset and store result in destination buffer. */
47.        *pDst++ = (*pSrc++) + offset;
48.    
49.        *pDst++ = (*pSrc++) + offset;
50.    
51.        *pDst++ = (*pSrc++) + offset;
52.    
53.        *pDst++ = (*pSrc++) + offset;
54.    
55.        /* Decrement loop counter */
56.        blkCnt--;
57.      }
58.    
59.      /* Loop unrolling: Compute remaining outputs */
60.      blkCnt = blockSize % 0x4U;
61.    
62.    #else
63.    
64.      /* Initialize blkCnt with number of samples */
65.      blkCnt = blockSize;
66.    
67.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
68.    #endif /* #if defined(ARM_MATH_NEON_EXPERIMENTAL) */
69.    
70.      while (blkCnt > 0U)
71.      {
72.        /* C = A + offset */
73.    
74.        /* Add offset and store result in destination buffer. */
75.        *pDst++ = (*pSrc++) + offset;
76.    
77.        /* Decrement loop counter */
78.        blkCnt--;
79.      }
80.    
81.    }

 

函数描述:

这个函数用于求32位浮点数的偏移。

函数解析:

  •   第9到36行,用于NEON指令集,当前的CM内核不支持。
  •   第37到62行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
  •   第70到79行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。

函数参数:

  •   第1个参数是源数据地址。
  •   第2个参数是偏移量。
  •   第3个参数是转换后的目的地址。
  •   第4个参数是浮点数个数,其实就是执行偏移的次数。

12.4.2        函数arm_offset_q31

函数原型:

 

1.    void arm_offset_q31(
2.      const q31_t * pSrc,
3.            q31_t offset,
4.            q31_t * pDst,
5.            uint32_t blockSize)
6.    {
7.            uint32_t blkCnt;                               /* Loop counter */
8.    
9.    #if defined (ARM_MATH_LOOPUNROLL)
10.    
11.      /* Loop unrolling: Compute 4 outputs at a time */
12.      blkCnt = blockSize >> 2U;
13.    
14.      while (blkCnt > 0U)
15.      {
16.        /* C = A + offset */
17.    
18.        /* Add offset and store result in destination buffer. */
19.    #if defined (ARM_MATH_DSP)
20.        *pDst++ = __QADD(*pSrc++, offset);
21.    #else
22.        *pDst++ = (q31_t) clip_q63_to_q31((q63_t) * pSrc++ + offset);
23.    #endif
24.    
25.    #if defined (ARM_MATH_DSP)
26.        *pDst++ = __QADD(*pSrc++, offset);
27.    #else
28.        *pDst++ = (q31_t) clip_q63_to_q31((q63_t) * pSrc++ + offset);
29.    #endif
30.    
31.    #if defined (ARM_MATH_DSP)
32.        *pDst++ = __QADD(*pSrc++, offset);
33.    #else
34.        *pDst++ = (q31_t) clip_q63_to_q31((q63_t) * pSrc++ + offset);
35.    #endif
36.    
37.    #if defined (ARM_MATH_DSP)
38.        *pDst++ = __QADD(*pSrc++, offset);
39.    #else
40.        *pDst++ = (q31_t) clip_q63_to_q31((q63_t) * pSrc++ + offset);
41.    #endif
42.    
43.        /* Decrement loop counter */
44.        blkCnt--;
45.      }
46.    
47.      /* Loop unrolling: Compute remaining outputs */
48.      blkCnt = blockSize % 0x4U;
49.    
50.    #else
51.    
52.      /* Initialize blkCnt with number of samples */
53.      blkCnt = blockSize;
54.    
55.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
56.    
57.      while (blkCnt > 0U)
58.      {
59.        /* C = A + offset */
60.    
61.        /* Add offset and store result in destination buffer. */
62.    #if defined (ARM_MATH_DSP)
63.        *pDst++ = __QADD(*pSrc++, offset);
64.    #else
65.        *pDst++ = (q31_t) clip_q63_to_q31((q63_t) * pSrc++ + offset);
66.    #endif
67.    
68.        /* Decrement loop counter */
69.        blkCnt--;
70.      }
71.    
72.    }

 

函数描述:

这个函数用于求两个32位定点数的偏移。

函数解析:

  •   第9到50行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
  •   第57到70行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。
  •   __QADD实现32位数的加法饱和运算。输出结果的范围[0x80000000 0x7FFFFFFF],超出这个结果将产生饱和结果,负数饱和到0x80000000,正数饱和到0x7FFFFFFF。

函数参数:

  •   第1个参数是源数据地址。
  •   第2个参数是偏移量。
  •   第3个参数是转换后的目的地址。
  •   第4个参数是定点数个数,其实就是执行偏移的次数。

12.4.3        函数arm_offset_q15

函数原型:

 

1.    void arm_offset_q15(
2.      const q15_t * pSrc,
3.            q15_t offset,
4.            q15_t * pDst,
5.            uint32_t blockSize)
6.    {
7.            uint32_t blkCnt;                               /* Loop counter */
8.    
9.    #if defined (ARM_MATH_LOOPUNROLL)
10.    
11.    #if defined (ARM_MATH_DSP)
12.      q31_t offset_packed;                           /* Offset packed to 32 bit */
13.    
14.      /* Offset is packed to 32 bit in order to use SIMD32 for addition */
15.      offset_packed = __PKHBT(offset, offset, 16);
16.    #endif
17.    
18.      /* Loop unrolling: Compute 4 outputs at a time */
19.      blkCnt = blockSize >> 2U;
20.    
21.      while (blkCnt > 0U)
22.      {
23.        /* C = A + offset */
24.    
25.    #if defined (ARM_MATH_DSP)
26.        /* Add offset and store result in destination buffer (2 samples at a time). */
27.        write_q15x2_ia (&pDst, __QADD16(read_q15x2_ia ((q15_t **) &pSrc), offset_packed));
28.        write_q15x2_ia (&pDst, __QADD16(read_q15x2_ia ((q15_t **) &pSrc), offset_packed));
29.    #else
30.        *pDst++ = (q15_t) __SSAT(((q31_t) *pSrc++ + offset), 16);
31.        *pDst++ = (q15_t) __SSAT(((q31_t) *pSrc++ + offset), 16);
32.        *pDst++ = (q15_t) __SSAT(((q31_t) *pSrc++ + offset), 16);
33.        *pDst++ = (q15_t) __SSAT(((q31_t) *pSrc++ + offset), 16);
34.    #endif
35.    
36.        /* Decrement loop counter */
37.        blkCnt--;
38.      }
39.    
40.      /* Loop unrolling: Compute remaining outputs */
41.      blkCnt = blockSize % 0x4U;
42.    
43.    #else
44.    
45.      /* Initialize blkCnt with number of samples */
46.      blkCnt = blockSize;
47.    
48.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
49.    
50.      while (blkCnt > 0U)
51.      {
52.        /* C = A + offset */
53.    
54.        /* Add offset and store result in destination buffer. */
55.    #if defined (ARM_MATH_DSP)
56.        *pDst++ = (q15_t) __QADD16(*pSrc++, offset);
57.    #else
58.        *pDst++ = (q15_t) __SSAT(((q31_t) *pSrc++ + offset), 16);
59.    #endif
60.    
61.        /* Decrement loop counter */
62.        blkCnt--;
63.      }
64.    
65.    }

 

函数描述:

这个函数用于求16位定点数的偏移。

函数解析:

  •   第9到43行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
  •   第50到63行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。
  •   函数__PKHBT也是SIMD指令,作用是将将两个16位的数据合并成32位数据。用C实现的话,如下:
  #define __PKHBT(ARG1, ARG2, ARG3) ( (((int32_t)(ARG1) <<    0) & (int32_t)0x0000FFFF) | \
                                      (((int32_t)(ARG2) << ARG3) & (int32_t)0xFFFF0000)  )
  •   函数read_q15x2_ia的原型如下:
__STATIC_FORCEINLINE q31_t read_q15x2_ia (
  q15_t ** pQ15)
{
  q31_t val;

  memcpy (&val, *pQ15, 4);
  *pQ15 += 2;

  return (val);
}

作用是读取两次16位数据,返回一个32位数据,并将数据地址递增,方便下次读取。

  •   __QADD16实现两次16位数的加法饱和运算。输出结果的范围[0x8000 0x7FFF],超出这个结果将产生饱和结果,负数饱和到0x8000,正数饱和到0x7FFF。
  •   __SSAT也是SIMD指令,这里是将结果饱和到16位精度。

函数参数:

  •   第1个参数是源数据地址。
  •   第2个参数是偏移量。
  •   第3个参数是转换后的目的地址。
  •   第4个参数是定点数个数,其实就是执行偏移的次数。

12.4.4        函数arm_offset_q7

函数原型:

 

1.    void arm_offset_q7(
2.      const q7_t * pSrc,
3.            q7_t offset,
4.            q7_t * pDst,
5.            uint32_t blockSize)
6.    {
7.            uint32_t blkCnt;                               /* Loop counter */
8.    
9.    #if defined (ARM_MATH_LOOPUNROLL)
10.    
11.    #if defined (ARM_MATH_DSP)
12.      q31_t offset_packed;                           /* Offset packed to 32 bit */
13.    
14.      /* Offset is packed to 32 bit in order to use SIMD32 for addition */
15.      offset_packed = __PACKq7(offset, offset, offset, offset);
16.    #endif
17.    
18.      /* Loop unrolling: Compute 4 outputs at a time */
19.      blkCnt = blockSize >> 2U;
20.    
21.      while (blkCnt > 0U)
22.      {
23.        /* C = A + offset */
24.    
25.    #if defined (ARM_MATH_DSP)
26.        /* Add offset and store result in destination buffer (4 samples at a time). */
27.        write_q7x4_ia (&pDst, __QADD8(read_q7x4_ia ((q7_t **) &pSrc), offset_packed));
28.    #else
29.        *pDst++ = (q7_t) __SSAT(*pSrc++ + offset, 8);
30.        *pDst++ = (q7_t) __SSAT(*pSrc++ + offset, 8);
31.        *pDst++ = (q7_t) __SSAT(*pSrc++ + offset, 8);
32.        *pDst++ = (q7_t) __SSAT(*pSrc++ + offset, 8);
33.    #endif
34.    
35.        /* Decrement loop counter */
36.        blkCnt--;
37.      }
38.    
39.      /* Loop unrolling: Compute remaining outputs */
40.      blkCnt = blockSize % 0x4U;
41.    
42.    #else
43.    
44.      /* Initialize blkCnt with number of samples */
45.      blkCnt = blockSize;
46.    
47.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
48.    
49.      while (blkCnt > 0U)
50.      {
51.        /* C = A + offset */
52.    
53.        /* Add offset and store result in destination buffer. */
54.        *pDst++ = (q7_t) __SSAT((q15_t) *pSrc++ + offset, 8);
55.    
56.        /* Decrement loop counter */
57.        blkCnt--;
58.      }
59.    
60.    }

 

函数描述:

这个函数用于求两个8位定点数的偏移。

函数解析:

  •   第9到42行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
  •   第49到58行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。
  •   函数write_q7x4_ia的原型如下:
__STATIC_FORCEINLINE void write_q7x4_ia (
  q7_t ** pQ7,
  q31_t   value)
{
  q31_t val = value;

  memcpy (*pQ7, &val, 4);
  *pQ7 += 4;
}

作用是写4次8位数据,并将数据地址递增,方便下次继续写。

  •   __QADD8实现四次8位数的加法饱和运算。输出结果的范围[0x80 0x7F],超出这个结果将产生饱和结果,负数饱和到0x80,正数饱和到0x7F。

函数参数:

  •   第1个参数是源数据地址。
  •   第2个参数是偏移量。
  •   第3个参数是转换后的目的地址。
  •   第4个参数是定点数个数,其实就是执行偏移的次数。

12.4.5        使用举例

程序设计:

 

/*
*********************************************************************************************************
*    函 数 名: DSP_Offset
*    功能说明: 偏移
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void DSP_Offset(void)
{
    float32_t   pSrcA = 0.0f;
    float32_t   Offset = 0.0f;  
    float32_t   pDst;  
    
    q31_t  pSrcA1 = 0;  
    q31_t  Offset1 = 0;  
    q31_t  pDst1;  

    q15_t  pSrcA2 = 0;  
    q15_t  Offset2 = 0;  
    q15_t  pDst2; 

    q7_t  pSrcA3 = 0; 
    q7_t  Offset3 = 0;  
    q7_t  pDst3;  

    /*求偏移*********************************/        
    Offset--;
    arm_offset_f32(&pSrcA, Offset, &pDst, 1);
    printf("arm_offset_f32 = %f\r\n", pDst);

    Offset1--;
    arm_offset_q31(&pSrcA1, Offset1, &pDst1, 1);
    printf("arm_offset_q31 = %d\r\n", pDst1);

    Offset2--;
    arm_offset_q15(&pSrcA2, Offset2, &pDst2, 1);
    printf("arm_offset_q15 = %d\r\n", pDst2);

    Offset3--;
    arm_offset_q7(&pSrcA3, Offset3, &pDst3, 1);
    printf("arm_offset_q7 = %d\r\n", pDst3);
    printf("***********************************\r\n");
}

 

实验现象:

【STM32F407的DSP教程】第12章 DSP基础函数-相反数,偏移,移位,减法和比例因子

12.5 移位(Vector Shift)

这部分函数主要用于实现移位,公式描述如下:

pDst[n] = pSrc[n] << shift,   0 <= n < blockSize. 

注意,这部分函数支持目标指针和源指针指向相同的缓冲区

12.5.1        函数arm_shift_q31

函数原型:

 

1.    void arm_shift_q31(
2.      const q31_t * pSrc,
3.            int8_t shiftBits,
4.            q31_t * pDst,
5.            uint32_t blockSize)
6.    {
7.            uint32_t blkCnt;                               /* Loop counter */
8.            uint8_t sign = (shiftBits & 0x80);             /* Sign of shiftBits */
9.    
10.    #if defined (ARM_MATH_LOOPUNROLL)
11.    
12.      q31_t in, out;                                 /* Temporary variables */
13.    
14.      /* Loop unrolling: Compute 4 outputs at a time */
15.      blkCnt = blockSize >> 2U;
16.    
17.      /* If the shift value is positive then do right shift else left shift */
18.      if (sign == 0U)
19.      {
20.        while (blkCnt > 0U)
21.        {
22.          /* C = A << shiftBits */
23.    
24.          /* Shift input and store result in destination buffer. */
25.          in = *pSrc++;
26.          out = in << shiftBits;
27.          if (in != (out >> shiftBits))
28.            out = 0x7FFFFFFF ^ (in >> 31);
29.          *pDst++ = out;
30.    
31.          in = *pSrc++;
32.          out = in << shiftBits;
33.          if (in != (out >> shiftBits))
34.            out = 0x7FFFFFFF ^ (in >> 31);
35.          *pDst++ = out;
36.    
37.          in = *pSrc++;
38.          out = in << shiftBits;
39.          if (in != (out >> shiftBits))
40.            out = 0x7FFFFFFF ^ (in >> 31);
41.          *pDst++ = out;
42.    
43.          in = *pSrc++;
44.          out = in << shiftBits;
45.          if (in != (out >> shiftBits))
46.            out = 0x7FFFFFFF ^ (in >> 31);
47.          *pDst++ = out;
48.    
49.          /* Decrement loop counter */
50.          blkCnt--;
51.        }
52.      }
53.      else
54.      {
55.        while (blkCnt > 0U)
56.        {
57.          /* C = A >> shiftBits */
58.    
59.          /* Shift input and store results in destination buffer. */
60.          *pDst++ = (*pSrc++ >> -shiftBits);
61.          *pDst++ = (*pSrc++ >> -shiftBits);
62.          *pDst++ = (*pSrc++ >> -shiftBits);
63.          *pDst++ = (*pSrc++ >> -shiftBits);
64.    
65.          /* Decrement loop counter */
66.          blkCnt--;
67.        }
68.      }
69.    
70.      /* Loop unrolling: Compute remaining outputs */
71.      blkCnt = blockSize % 0x4U;
72.    
73.    #else
74.    
75.      /* Initialize blkCnt with number of samples */
76.      blkCnt = blockSize;
77.    
78.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
79.    
80.      /* If the shift value is positive then do right shift else left shift */
81.      if (sign == 0U)
82.      {
83.        while (blkCnt > 0U)
84.        {
85.          /* C = A << shiftBits */
86.    
87.          /* Shift input and store result in destination buffer. */
88.          *pDst++ = clip_q63_to_q31((q63_t) *pSrc++ << shiftBits);
89.    
90.          /* Decrement loop counter */
91.          blkCnt--;
92.        }
93.      }
94.      else
95.      {
96.        while (blkCnt > 0U)
97.        {
98.          /* C = A >> shiftBits */
99.    
100.          /* Shift input and store result in destination buffer. */
101.          *pDst++ = (*pSrc++ >> -shiftBits);
102.    
103.          /* Decrement loop counter */
104.          blkCnt--;
105.        }
106.      }
107.    
108.    }

 

函数描述:

这个函数用于求32位定点数的左移或者右移。

函数解析:

  •   第10到73行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
    •   第18到52行,如果参数shiftBits是正数,执行左移。
    •   第53到68行,如果蚕食shiftBits是负数,执行右移。
    •   第28行,数值的左移仅支持将其左移后再右移相应的位数后数值不变的情况,如果不满足这个条件,那么要对输出结果做饱和运算,这里分两种情况:

out = 0x7FFFFFFF ^ (in >> 31)   (in是正数)

= 0x7FFFFFFF ^ 0x00000000

= 0x7FFFFFFF

 out = 0x7FFFFFFF ^ (in >> 31)   (in是负数)

= 0x7FFFFFFF ^ 0xFFFFFFFF

= 0x80000000

  •   第81到106行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。
    •  第88行,函数clip_q63_to_q31的原型如下:
 __STATIC_FORCEINLINE 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;
  }

函数参数:

  •   第1个参数是源数据地址。
  •   第2个参数是左移或者右移位数,正数是左移,负数是右移。
  •   第3个参数是移位后数据地址。
  •   第4个参数是定点数个数,其实就是执行左移或者右移的次数。

12.5.2        函数arm_shift_q15

函数原型:

 

1.    void arm_shift_q15(
2.      const q15_t * pSrc,
3.            int8_t shiftBits,
4.            q15_t * pDst,
5.            uint32_t blockSize)
6.    {
7.            uint32_t blkCnt;                               /* Loop counter */
8.            uint8_t sign = (shiftBits & 0x80);             /* Sign of shiftBits */
9.    
10.    #if defined (ARM_MATH_LOOPUNROLL)
11.    
12.    #if defined (ARM_MATH_DSP)
13.      q15_t in1, in2;                                /* Temporary input variables */
14.    #endif
15.    
16.      /* Loop unrolling: Compute 4 outputs at a time */
17.      blkCnt = blockSize >> 2U;
18.    
19.      /* If the shift value is positive then do right shift else left shift */
20.      if (sign == 0U)
21.      {
22.        while (blkCnt > 0U)
23.        {
24.          /* C = A << shiftBits */
25.    
26.    #if defined (ARM_MATH_DSP)
27.          /* read 2 samples from source */
28.          in1 = *pSrc++;
29.          in2 = *pSrc++;
30.    
31.          /* Shift the inputs and then store the results in the destination buffer. */
32.    #ifndef ARM_MATH_BIG_ENDIAN
33.          write_q15x2_ia (&pDst, __PKHBT(__SSAT((in1 << shiftBits), 16),
34.                                         __SSAT((in2 << shiftBits), 16), 16));
35.    #else
36.          write_q15x2_ia (&pDst, __PKHBT(__SSAT((in2 << shiftBits), 16),
37.                                          __SSAT((in1 << shiftBits), 16), 16));
38.    #endif /* #ifndef ARM_MATH_BIG_ENDIAN */
39.    
40.          /* read 2 samples from source */
41.          in1 = *pSrc++;
42.          in2 = *pSrc++;
43.    
44.    #ifndef ARM_MATH_BIG_ENDIAN
45.          write_q15x2_ia (&pDst, __PKHBT(__SSAT((in1 << shiftBits), 16),
46.                                         __SSAT((in2 << shiftBits), 16), 16));
47.    #else
48.          write_q15x2_ia (&pDst, __PKHBT(__SSAT((in2 << shiftBits), 16),
49.                                         __SSAT((in1 << shiftBits), 16), 16));
50.    #endif /* #ifndef ARM_MATH_BIG_ENDIAN */
51.    
52.    #else
53.          *pDst++ = __SSAT(((q31_t) *pSrc++ << shiftBits), 16);
54.          *pDst++ = __SSAT(((q31_t) *pSrc++ << shiftBits), 16);
55.          *pDst++ = __SSAT(((q31_t) *pSrc++ << shiftBits), 16);
56.          *pDst++ = __SSAT(((q31_t) *pSrc++ << shiftBits), 16);
57.    #endif
58.    
59.          /* Decrement loop counter */
60.          blkCnt--;
61.        }
62.      }
63.      else
64.      {
65.        while (blkCnt > 0U)
66.        {
67.          /* C = A >> shiftBits */
68.    
69.    #if defined (ARM_MATH_DSP)
70.          /* read 2 samples from source */
71.          in1 = *pSrc++;
72.          in2 = *pSrc++;
73.    
74.          /* Shift the inputs and then store the results in the destination buffer. */
75.    #ifndef ARM_MATH_BIG_ENDIAN
76.          write_q15x2_ia (&pDst, __PKHBT((in1 >> -shiftBits),
77.                                         (in2 >> -shiftBits), 16));
78.    #else
79.          write_q15x2_ia (&pDst, __PKHBT((in2 >> -shiftBits),
80.                                         (in1 >> -shiftBits), 16));
81.    #endif /* #ifndef ARM_MATH_BIG_ENDIAN */
82.    
83.          /* read 2 samples from source */
84.          in1 = *pSrc++;
85.          in2 = *pSrc++;
86.    
87.    #ifndef ARM_MATH_BIG_ENDIAN
88.          write_q15x2_ia (&pDst, __PKHBT((in1 >> -shiftBits),
89.                                         (in2 >> -shiftBits), 16));
90.    #else
91.          write_q15x2_ia (&pDst, __PKHBT((in2 >> -shiftBits),
92.                                         (in1 >> -shiftBits), 16));
93.    #endif /* #ifndef ARM_MATH_BIG_ENDIAN */
94.    
95.    #else
96.          *pDst++ = (*pSrc++ >> -shiftBits);
97.          *pDst++ = (*pSrc++ >> -shiftBits);
98.          *pDst++ = (*pSrc++ >> -shiftBits);
99.          *pDst++ = (*pSrc++ >> -shiftBits);
100.    #endif
101.    
102.          /* Decrement loop counter */
103.          blkCnt--;
104.        }
105.      }
106.    
107.      /* Loop unrolling: Compute remaining outputs */
108.      blkCnt = blockSize % 0x4U;
109.    
110.    #else
111.    
112.      /* Initialize blkCnt with number of samples */
113.      blkCnt = blockSize;
114.    
115.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
116.    
117.      /* If the shift value is positive then do right shift else left shift */
118.      if (sign == 0U)
119.      {
120.        while (blkCnt > 0U)
121.        {
122.          /* C = A << shiftBits */
123.    
124.          /* Shift input and store result in destination buffer. */
125.          *pDst++ = __SSAT(((q31_t) *pSrc++ << shiftBits), 16);
126.    
127.          /* Decrement loop counter */
128.          blkCnt--;
129.        }
130.      }
131.      else
132.      {
133.        while (blkCnt > 0U)
134.        {
135.          /* C = A >> shiftBits */
136.    
137.          /* Shift input and store result in destination buffer. */
138.          *pDst++ = (*pSrc++ >> -shiftBits);
139.    
140.          /* Decrement loop counter */
141.          blkCnt--;
142.        }
143.      }
144.    
145.    }

 

函数描述:

这个函数用于求16位定点数的左移或者右移。

函数解析:

  •   第10到115行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
    •   第20到62行,如果参数shiftBits是正数,执行左移。
    •   第63到105行,如果蚕食shiftBits是负数,执行右移。
    •   第79行,函数write_q15x2_ia的原型如下,用于实现将两个Q15组成合并成一个Q31。
__STATIC_FORCEINLINE void write_q15x2_ia (
  q15_t ** pQ15,
  q31_t    value)
{
  q31_t val = value;

  memcpy (*pQ15, &val, 4);
  *pQ15 += 2;
}

函数__PKHBT也是SIMD指令,作用是将将两个16位的数据合并成32位数据。用C实现的话,如下:

  #define __PKHBT(ARG1, ARG2, ARG3) ( (((int32_t)(ARG1) <<    0) & (int32_t)0x0000FFFF) | \
                                      (((int32_t)(ARG2) << ARG3) & (int32_t)0xFFFF0000)  )
  •   第118到143行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。

函数参数:

  •   第1个参数是源数据地址。
  •   第2个参数是左移或者右移位数,正数是左移,负数是右移。
  •   第3个参数是移位后数据地址。
  •   第4个参数是定点数个数,其实就是执行左移或者右移的次数。

12.5.3        函数arm_shift_q7

函数原型:

 

1.    void arm_shift_q7(
2.      const q7_t * pSrc,
3.            int8_t shiftBits,
4.            q7_t * pDst,
5.            uint32_t blockSize)
6.    {
7.            uint32_t blkCnt;                               /* Loop counter */
8.            uint8_t sign = (shiftBits & 0x80);             /* Sign of shiftBits */
9.    
10.    #if defined (ARM_MATH_LOOPUNROLL)
11.    
12.    #if defined (ARM_MATH_DSP)
13.      q7_t in1,  in2,  in3,  in4;                    /* Temporary input variables */
14.    #endif
15.    
16.      /* Loop unrolling: Compute 4 outputs at a time */
17.      blkCnt = blockSize >> 2U;
18.    
19.      /* If the shift value is positive then do right shift else left shift */
20.      if (sign == 0U)
21.      {
22.        while (blkCnt > 0U)
23.        {
24.          /* C = A << shiftBits */
25.    
26.    #if defined (ARM_MATH_DSP)
27.          /* Read 4 inputs */
28.          in1 = *pSrc++;
29.          in2 = *pSrc++;
30.          in3 = *pSrc++;
31.          in4 = *pSrc++;
32.    
33.        /* Pack and store result in destination buffer (in single write) */
34.          write_q7x4_ia (&pDst, __PACKq7(__SSAT((in1 << shiftBits), 8),
35.                                         __SSAT((in2 << shiftBits), 8),
36.                                         __SSAT((in3 << shiftBits), 8),
37.                                         __SSAT((in4 << shiftBits), 8) ));
38.    #else
39.          *pDst++ = (q7_t) __SSAT(((q15_t) *pSrc++ << shiftBits), 8);
40.          *pDst++ = (q7_t) __SSAT(((q15_t) *pSrc++ << shiftBits), 8);
41.          *pDst++ = (q7_t) __SSAT(((q15_t) *pSrc++ << shiftBits), 8);
42.          *pDst++ = (q7_t) __SSAT(((q15_t) *pSrc++ << shiftBits), 8);
43.    #endif
44.    
45.          /* Decrement loop counter */
46.          blkCnt--;
47.        }
48.      }
49.      else
50.      {
51.        while (blkCnt > 0U)
52.        {
53.          /* C = A >> shiftBits */
54.    
55.    #if defined (ARM_MATH_DSP)
56.          /* Read 4 inputs */
57.          in1 = *pSrc++;
58.          in2 = *pSrc++;
59.          in3 = *pSrc++;
60.          in4 = *pSrc++;
61.    
62.        /* Pack and store result in destination buffer (in single write) */
63.          write_q7x4_ia (&pDst, __PACKq7((in1 >> -shiftBits),
64.                                         (in2 >> -shiftBits),
65.                                         (in3 >> -shiftBits),
66.                                         (in4 >> -shiftBits) ));
67.    #else
68.          *pDst++ = (*pSrc++ >> -shiftBits);
69.          *pDst++ = (*pSrc++ >> -shiftBits);
70.          *pDst++ = (*pSrc++ >> -shiftBits);
71.          *pDst++ = (*pSrc++ >> -shiftBits);
72.    #endif
73.    
74.          /* Decrement loop counter */
75.          blkCnt--;
76.        }
77.      }
78.    
79.      /* Loop unrolling: Compute remaining outputs */
80.      blkCnt = blockSize % 0x4U;
81.    
82.    #else
83.    
84.      /* Initialize blkCnt with number of samples */
85.      blkCnt = blockSize;
86.    
87.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
88.    
89.      /* If the shift value is positive then do right shift else left shift */
90.      if (sign == 0U)
91.      {
92.        while (blkCnt > 0U)
93.        {
94.          /* C = A << shiftBits */
95.    
96.          /* Shift input and store result in destination buffer. */
97.          *pDst++ = (q7_t) __SSAT(((q15_t) *pSrc++ << shiftBits), 8);
98.    
99.          /* Decrement loop counter */
100.          blkCnt--;
101.        }
102.      }
103.      else
104.      {
105.        while (blkCnt > 0U)
106.        {
107.          /* C = A >> shiftBits */
108.    
109.          /* Shift input and store result in destination buffer. */
110.          *pDst++ = (*pSrc++ >> -shiftBits);
111.    
112.          /* Decrement loop counter */
113.          blkCnt--;
114.        }
115.      }
116.    
117.    }

 

函数描述:

这个函数用于求8位定点数的左移或者右移。

函数解析:

  •   第10到87行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
    •   第20到48行,如果参数shiftBits是正数,执行左移。
    •   第49到77行,如果蚕食shiftBits是负数,执行右移。
    •   第79行,函数write_q7x4_ia的原型如下,作用是写入4次8位数据,并将数据地址递增,方便下次写入。
__STATIC_FORCEINLINE void write_q7x4_ia (
  q7_t ** pQ7,
  q31_t   value)
{
  q31_t val = value;

  memcpy (*pQ7, &val, 4);
  *pQ7 += 4;
}

函数__PACKq7作用是将将4个8位的数据合并成32位数据,实现代码如下:

  #define __PACKq7(v0,v1,v2,v3) ( (((int32_t)(v0) <<  0) & (int32_t)0x000000FF) | \
                                  (((int32_t)(v1) <<  8) & (int32_t)0x0000FF00) | \
                                  (((int32_t)(v2) << 16) & (int32_t)0x00FF0000) | \
                                  (((int32_t)(v3) << 24) & (int32_t)0xFF000000)  )
  •   第90到115行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。

函数参数:

  •   第1个参数是源数据地址。
  •   第2个参数是左移或者右移位数,正数是左移,负数是右移。
  •   第3个参数是移位后数据地址。
  •   第4个参数是定点数个数,其实就是执行左移或者右移的次数

12.5.4        使用举例

程序设计:

 

/*
*********************************************************************************************************
*    函 数 名: DSP_Shift
*    功能说明: 移位
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void DSP_Shift(void)
{
    q31_t  pSrcA1 = 0x88886666;  
    q31_t  pDst1;  

    q15_t  pSrcA2 = 0x8866;  
    q15_t  pDst2; 

    q7_t  pSrcA3 = 0x86; 
    q7_t  pDst3;  


    /*求移位*********************************/    
    arm_shift_q31(&pSrcA1, 3, &pDst1, 1);
    printf("arm_shift_q31 = %8x\r\n", pDst1);

    arm_shift_q15(&pSrcA2, -3, &pDst2, 1);
    printf("arm_shift_q15 = %4x\r\n", pDst2);

    arm_shift_q7(&pSrcA3, 3, &pDst3, 1);
    printf("arm_shift_q7 = %2x\r\n", pDst3);
    printf("***********************************\r\n");
}

 

实验现象:

【STM32F407的DSP教程】第12章 DSP基础函数-相反数,偏移,移位,减法和比例因子

这里特别注意Q31和Q7的计算结果,表示负数已经饱和到了最小值。另外注意,对于负数来说,右移时,右侧补1,左移时,左侧补0。

12.6 减法(Vector Sub)

这部分函数主要用于实现减法,公式描述如下:

pDst[n] = pSrcA[n] - pSrcB[n],   0 <= n < blockSize。

12.6.1        函数arm_sub_f32

函数原型:

 

1.    void arm_sub_f32(
2.      const float32_t * pSrcA,
3.      const float32_t * pSrcB,
4.            float32_t * pDst,
5.            uint32_t blockSize)
6.    {
7.            uint32_t blkCnt;                               /* Loop counter */
8.    
9.    #if defined(ARM_MATH_NEON)
10.        float32x4_t vec1;
11.        float32x4_t vec2;
12.        float32x4_t res;
13.    
14.        /* Compute 4 outputs at a time */
15.        blkCnt = blockSize >> 2U;
16.    
17.        while (blkCnt > 0U)
18.        {
19.            /* C = A - B */
20.    
21.            /* Subtract and then store the results in the destination buffer. */
22.            vec1 = vld1q_f32(pSrcA);
23.            vec2 = vld1q_f32(pSrcB);
24.            res = vsubq_f32(vec1, vec2);
25.            vst1q_f32(pDst, res);
26.    
27.            /* Increment pointers */
28.            pSrcA += 4;
29.            pSrcB += 4; 
30.            pDst += 4;
31.            
32.            /* Decrement the loop counter */
33.            blkCnt--;
34.        }
35.    
36.        /* Tail */
37.        blkCnt = blockSize & 0x3;
38.    
39.    #else
40.    #if defined (ARM_MATH_LOOPUNROLL)
41.    
42.      /* Loop unrolling: Compute 4 outputs at a time */
43.      blkCnt = blockSize >> 2U;
44.    
45.      while (blkCnt > 0U)
46.      {
47.        /* C = A - B */
48.    
49.        /* Subtract and store result in destination buffer. */
50.        *pDst++ = (*pSrcA++) - (*pSrcB++);
51.    
52.        *pDst++ = (*pSrcA++) - (*pSrcB++);
53.    
54.        *pDst++ = (*pSrcA++) - (*pSrcB++);
55.    
56.        *pDst++ = (*pSrcA++) - (*pSrcB++);
57.    
58.        /* Decrement loop counter */
59.        blkCnt--;
60.      }
61.    
62.      /* Loop unrolling: Compute remaining outputs */
63.      blkCnt = blockSize % 0x4U;
64.    
65.    #else
66.    
67.      /* Initialize blkCnt with number of samples */
68.      blkCnt = blockSize;
69.    
70.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
71.    #endif /* #if defined(ARM_MATH_NEON) */
72.    
73.      while (blkCnt > 0U)
74.      {
75.        /* C = A - B */
76.    
77.        /* Subtract and store result in destination buffer. */
78.        *pDst++ = (*pSrcA++) - (*pSrcB++);
79.    
80.        /* Decrement loop counter */
81.        blkCnt--;
82.      }
83.    
84.    }

 

函数描述:

这个函数用于求32位浮点数的减法。

函数解析:

  •   第9到39行,用于NEON指令集,当前的CM内核不支持。
  •   第40到65行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
  •   第73到82行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。

函数参数:

  •   第1个参数是减数地址。
  •   第2个参数是被减数地址。
  •   第3个参数是结果地址。
  •   第4个参数是数据块大小,其实就是执行加法的次数。

12.6.2        函数arm_sub_q31

函数原型:

 

1.    void arm_sub_q31(
2.      const q31_t * pSrcA,
3.      const q31_t * pSrcB,
4.            q31_t * pDst,
5.            uint32_t blockSize)
6.    {
7.            uint32_t blkCnt;                               /* Loop counter */
8.    
9.    #if defined (ARM_MATH_LOOPUNROLL)
10.    
11.      /* Loop unrolling: Compute 4 outputs at a time */
12.      blkCnt = blockSize >> 2U;
13.    
14.      while (blkCnt > 0U)
15.      {
16.        /* C = A - B */
17.    
18.        /* Subtract and store result in destination buffer. */
19.        *pDst++ = __QSUB(*pSrcA++, *pSrcB++);
20.    
21.        *pDst++ = __QSUB(*pSrcA++, *pSrcB++);
22.    
23.        *pDst++ = __QSUB(*pSrcA++, *pSrcB++);
24.    
25.        *pDst++ = __QSUB(*pSrcA++, *pSrcB++);
26.    
27.        /* Decrement loop counter */
28.        blkCnt--;
29.      }
30.    
31.      /* Loop unrolling: Compute remaining outputs */
32.      blkCnt = blockSize % 0x4U;
33.    
34.    #else
35.    
36.      /* Initialize blkCnt with number of samples */
37.      blkCnt = blockSize;
38.    
39.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
40.    
41.      while (blkCnt > 0U)
42.      {
43.        /* C = A - B */
44.    
45.        /* Subtract and store result in destination buffer. */
46.        *pDst++ = __QSUB(*pSrcA++, *pSrcB++);
47.    
48.        /* Decrement loop counter */
49.        blkCnt--;
50.      }
51.    
52.    }

 

函数描述:

这个函数用于求32位定点数的减法。

函数解析:

  •   这个函数使用了饱和减法__QSUB,所得结果是Q31格式,范围[0x80000000 0x7FFFFFFF]。
  •   第9到34行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
  •   第41到50行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。

函数参数:

  •   第1个参数是减数地址。
  •   第2个参数是被减数地址。
  •   第3个参数是结果地址。
  •   第4个参数是数据块大小,其实就是执行加法的次数。

12.6.3        函数arm_sub_q15

函数原型:

 

1.    void arm_sub_q15(
2.      const q15_t * pSrcA,
3.      const q15_t * pSrcB,
4.            q15_t * pDst,
5.            uint32_t blockSize)
6.    {
7.            uint32_t blkCnt;                               /* Loop counter */
8.    
9.    #if defined (ARM_MATH_LOOPUNROLL)
10.    
11.    #if defined (ARM_MATH_DSP)
12.      q31_t inA1, inA2;
13.      q31_t inB1, inB2;
14.    #endif
15.    
16.      /* Loop unrolling: Compute 4 outputs at a time */
17.      blkCnt = blockSize >> 2U;
18.    
19.      while (blkCnt > 0U)
20.      {
21.        /* C = A - B */
22.    
23.    #if defined (ARM_MATH_DSP)
24.        /* read 2 times 2 samples at a time from sourceA */
25.        inA1 = read_q15x2_ia ((q15_t **) &pSrcA);
26.        inA2 = read_q15x2_ia ((q15_t **) &pSrcA);
27.        /* read 2 times 2 samples at a time from sourceB */
28.        inB1 = read_q15x2_ia ((q15_t **) &pSrcB);
29.        inB2 = read_q15x2_ia ((q15_t **) &pSrcB);
30.    
31.        /* Subtract and store 2 times 2 samples at a time */
32.        write_q15x2_ia (&pDst, __QSUB16(inA1, inB1));
33.        write_q15x2_ia (&pDst, __QSUB16(inA2, inB2));
34.    #else
35.        *pDst++ = (q15_t) __SSAT(((q31_t) *pSrcA++ - *pSrcB++), 16);
36.        *pDst++ = (q15_t) __SSAT(((q31_t) *pSrcA++ - *pSrcB++), 16);
37.        *pDst++ = (q15_t) __SSAT(((q31_t) *pSrcA++ - *pSrcB++), 16);
38.        *pDst++ = (q15_t) __SSAT(((q31_t) *pSrcA++ - *pSrcB++), 16);
39.    #endif
40.    
41.        /* Decrement loop counter */
42.        blkCnt--;
43.      }
44.    
45.      /* Loop unrolling: Compute remaining outputs */
46.      blkCnt = blockSize % 0x4U;
47.    
48.    #else
49.    
50.      /* Initialize blkCnt with number of samples */
51.      blkCnt = blockSize;
52.    
53.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
54.    
55.      while (blkCnt > 0U)
56.      {
57.        /* C = A - B */
58.    
59.        /* Subtract and store result in destination buffer. */
60.    #if defined (ARM_MATH_DSP)
61.        *pDst++ = (q15_t) __QSUB16(*pSrcA++, *pSrcB++);
62.    #else
63.        *pDst++ = (q15_t) __SSAT(((q31_t) *pSrcA++ - *pSrcB++), 16);
64.    #endif
65.    
66.        /* Decrement loop counter */
67.        blkCnt--;
68.      }
69.    
70.    }

 

函数描述:

这个函数用于求16位定点数的减法。

函数解析:

  •   第9到48行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
    •   第25行,函数read_q15x2_ia一次读取两个Q15格式的数据,组成一个Q31格式。
    •   第32行,函数write_q15x2_ia一次写入两个Q15格式的数据,获得一个Q31格式数据。
    •   第32行,函数__QSUB16实现两次16bit的饱和减法。
  •   第55到68行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。

函数参数:

  •   第1个参数是减数地址。
  •   第2个参数是被减数地址。
  •   第3个参数是结果地址。
  •   第4个参数是数据块大小,其实就是执行加法的次数。

12.6.4        函数arm_sub_q7

函数原型:

 

1.    void arm_sub_q7(
2.      const q7_t * pSrcA,
3.      const q7_t * pSrcB,
4.            q7_t * pDst,
5.            uint32_t blockSize)
6.    {
7.            uint32_t blkCnt;                               /* Loop counter */
8.    
9.    #if defined (ARM_MATH_LOOPUNROLL)
10.    
11.      /* Loop unrolling: Compute 4 outputs at a time */
12.      blkCnt = blockSize >> 2U;
13.    
14.      while (blkCnt > 0U)
15.      {
16.        /* C = A - B */
17.    
18.    #if defined (ARM_MATH_DSP)
19.        /* Subtract and store result in destination buffer (4 samples at a time). */
20.        write_q7x4_ia (&pDst, __QSUB8(read_q7x4_ia ((q7_t **) &pSrcA), read_q7x4_ia ((q7_t **) &pSrcB)));
21.    #else
22.        *pDst++ = (q7_t) __SSAT((q15_t) *pSrcA++ - *pSrcB++, 8);
23.        *pDst++ = (q7_t) __SSAT((q15_t) *pSrcA++ - *pSrcB++, 8);
24.        *pDst++ = (q7_t) __SSAT((q15_t) *pSrcA++ - *pSrcB++, 8);
25.        *pDst++ = (q7_t) __SSAT((q15_t) *pSrcA++ - *pSrcB++, 8);
26.    #endif
27.    
28.        /* Decrement loop counter */
29.        blkCnt--;
30.      }
31.    
32.      /* Loop unrolling: Compute remaining outputs */
33.      blkCnt = blockSize % 0x4U;
34.    
35.    #else
36.    
37.      /* Initialize blkCnt with number of samples */
38.      blkCnt = blockSize;
39.    
40.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
41.    
42.      while (blkCnt > 0U)
43.      {
44.        /* C = A - B */
45.    
46.        /* Subtract and store result in destination buffer. */
47.        *pDst++ = (q7_t) __SSAT((q15_t) *pSrcA++ - *pSrcB++, 8);
48.    
49.        /* Decrement loop counter */
50.        blkCnt--;
51.      }
52.    
53.    }

 

函数描述:

这个函数用于求8位定点数的乘法。

函数解析:

  •   第9到35行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
    •   第20行,函数write_q7x4_ia实现一次写入4个Q7格式数据到Q31各种中。

函数__QSUB8实现一次计算4个Q7格式减法。

  •  第42到51行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。

函数参数:

  •   第1个参数是减数地址。
  •   第2个参数是被减数地址。
  •   第3个参数是结果地址。
  •   第4个参数是数据块大小,其实就是执行加法的次数。

12.6.5        使用举例

程序设计:

 

/*
*********************************************************************************************************
*    函 数 名: DSP_Sub
*    功能说明: 减法
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void DSP_Sub(void)
{
    float32_t   pSrcA[5] = {1.0f,1.0f,1.0f,1.0f,1.0f};
    float32_t   pSrcB[5] = {1.0f,1.0f,1.0f,1.0f,1.0f};  
    float32_t   pDst[5];  
    
    q31_t  pSrcA1[5] = {1,1,1,1,1};  
    q31_t  pSrcB1[5] = {1,1,1,1,1};  
    q31_t  pDst1[5];   

    q15_t  pSrcA2[5] = {1,1,1,1,1};  
    q15_t  pSrcB2[5] = {1,1,1,1,1};  
    q15_t  pDst2[5];   

    q7_t  pSrcA3[5] = {0x70,1,1,1,1}; 
    q7_t  pSrcB3[5] = {0x7f,1,1,1,1};  
    q7_t  pDst3[5];  


    /*求减法*********************************/    
    pSrcA[0] += 1.1f;
    arm_sub_f32(pSrcA, pSrcB, pDst, 5);
    printf("arm_sub_f32 = %f\r\n", pDst[0]);
    
    pSrcA1[0] += 1;
    arm_sub_q31(pSrcA1, pSrcB1, pDst1, 5);
    printf("arm_sub_q31 = %d\r\n", pDst1[0]);

    pSrcA2[0] += 1;
    arm_sub_q15(pSrcA2, pSrcB2, pDst2, 5);
    printf("arm_sub_q15 = %d\r\n", pDst2[0]);

    pSrcA3[0] += 1;
    arm_sub_q7(pSrcA3, pSrcB3, pDst3, 5);
    printf("arm_sub_q7 = %d\r\n", pDst3[0]);
    printf("***********************************\r\n");
}

 

实验现象:

【STM32F407的DSP教程】第12章 DSP基础函数-相反数,偏移,移位,减法和比例因子

12.7 比例因子(Vector Scale)

这部分函数主要用于实现数据的比例放大和缩小,浮点数据公式描述如下:

pDst[n] = pSrc[n] * scale,   0 <= n < blockSize.        

如果是Q31,Q15,Q7格式的数据,公式描述如下:

pDst[n] = (pSrc[n] * scaleFract) << shift,   0 <= n < blockSize.  

这种情况下,比例因子就是:

scale = scaleFract * 2^shift.      

      注意,这部分函数支持目标指针和源指针指向相同的缓冲区

12.7.1        函数arm_scale_f32

函数原型:

 

1.    void arm_scale_f32(
2.      const float32_t *pSrc,
3.            float32_t scale,
4.            float32_t *pDst,
5.            uint32_t blockSize)
6.    {
7.      uint32_t blkCnt;                               /* Loop counter */
8.    #if defined(ARM_MATH_NEON_EXPERIMENTAL)
9.        float32x4_t vec1;
10.        float32x4_t res;
11.    
12.        /* Compute 4 outputs at a time */
13.        blkCnt = blockSize >> 2U;
14.    
15.        while (blkCnt > 0U)
16.        {
17.            /* C = A * scale */
18.    
19.            /* Scale the input and then store the results in the destination buffer. */
20.            vec1 = vld1q_f32(pSrc);
21.            res = vmulq_f32(vec1, vdupq_n_f32(scale));
22.            vst1q_f32(pDst, res);
23.    
24.            /* Increment pointers */
25.            pSrc += 4; 
26.            pDst += 4;
27.            
28.            /* Decrement the loop counter */
29.            blkCnt--;
30.        }
31.    
32.        /* Tail */
33.        blkCnt = blockSize & 0x3;
34.    
35.    #else
36.    #if defined (ARM_MATH_LOOPUNROLL)
37.    
38.      /* Loop unrolling: Compute 4 outputs at a time */
39.      blkCnt = blockSize >> 2U;
40.    
41.      while (blkCnt > 0U)
42.      {
43.        /* C = A * scale */
44.    
45.        /* Scale input and store result in destination buffer. */
46.        *pDst++ = (*pSrc++) * scale;
47.    
48.        *pDst++ = (*pSrc++) * scale;
49.    
50.        *pDst++ = (*pSrc++) * scale;
51.    
52.        *pDst++ = (*pSrc++) * scale;
53.    
54.        /* Decrement loop counter */
55.        blkCnt--;
56.      }
57.    
58.      /* Loop unrolling: Compute remaining outputs */
59.      blkCnt = blockSize % 0x4U;
60.    
61.    #else
62.    
63.      /* Initialize blkCnt with number of samples */
64.      blkCnt = blockSize;
65.    
66.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
67.    #endif /* #if defined(ARM_MATH_NEON_EXPERIMENTAL) */
68.    
69.      while (blkCnt > 0U)
70.      {
71.        /* C = A * scale */
72.    
73.        /* Scale input and store result in destination buffer. */
74.        *pDst++ = (*pSrc++) * scale;
75.    
76.        /* Decrement loop counter */
77.        blkCnt--;
78.      }
79.    
80.    }

 

函数描述:

这个函数用于求32位浮点数的比例因子计算。

函数解析:

  •   第8到35行,用于NEON指令集,当前的CM内核不支持。
  •   第36到61行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
  •   第69到78行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。

函数参数:

  •   第1个参数是数据源地址。
  •   第2个参数是比例因子
  •   第3个参数是结果地址。
  •   第4个参数是数据块大小,其实就是执行比例因子计算的次数。

12.7.2        函数arm_scale_q31

函数原型:

 

1.    void arm_scale_q31(
2.      const q31_t *pSrc,
3.            q31_t scaleFract,
4.            int8_t shift,
5.            q31_t *pDst,
6.            uint32_t blockSize)
7.    {
8.            uint32_t blkCnt;                               /* Loop counter */
9.            q31_t in, out;                                 /* Temporary variables */
10.            int8_t kShift = shift + 1;                     /* Shift to apply after scaling */
11.            int8_t sign = (kShift & 0x80);
12.    
13.    #if defined (ARM_MATH_LOOPUNROLL)
14.    
15.      /* Loop unrolling: Compute 4 outputs at a time */
16.      blkCnt = blockSize >> 2U;
17.    
18.      if (sign == 0U)
19.      {
20.        while (blkCnt > 0U)
21.        {
22.          /* C = A * scale */
23.    
24.          /* Scale input and store result in destination buffer. */
25.          in = *pSrc++;                                /* read input from source */
26.          in = ((q63_t) in * scaleFract) >> 32;        /* multiply input with scaler value */
27.          out = in << kShift;                          /* apply shifting */
28.          if (in != (out >> kShift))                   /* saturate the result */
29.            out = 0x7FFFFFFF ^ (in >> 31);
30.          *pDst++ = out;                               /* Store result destination */
31.    
32.          in = *pSrc++;
33.          in = ((q63_t) in * scaleFract) >> 32;
34.          out = in << kShift;
35.          if (in != (out >> kShift))
36.            out = 0x7FFFFFFF ^ (in >> 31);
37.          *pDst++ = out;
38.    
39.          in = *pSrc++;
40.          in = ((q63_t) in * scaleFract) >> 32;
41.          out = in << kShift;
42.          if (in != (out >> kShift))
43.            out = 0x7FFFFFFF ^ (in >> 31);
44.          *pDst++ = out;
45.    
46.          in = *pSrc++;
47.          in = ((q63_t) in * scaleFract) >> 32;
48.          out = in << kShift;
49.          if (in != (out >> kShift))
50.            out = 0x7FFFFFFF ^ (in >> 31);
51.          *pDst++ = out;
52.    
53.          /* Decrement loop counter */
54.          blkCnt--;
55.        }
56.      }
57.      else
58.      {
59.        while (blkCnt > 0U)
60.        {
61.          /* C = A * scale */
62.    
63.          /* Scale input and store result in destination buffer. */
64.          in = *pSrc++;                                /* read four inputs from source */
65.          in = ((q63_t) in * scaleFract) >> 32;        /* multiply input with scaler value */
66.          out = in >> -kShift;                         /* apply shifting */
67.          *pDst++ = out;                               /* Store result destination */
68.    
69.          in = *pSrc++;
70.          in = ((q63_t) in * scaleFract) >> 32;
71.          out = in >> -kShift;
72.          *pDst++ = out;
73.    
74.          in = *pSrc++;
75.          in = ((q63_t) in * scaleFract) >> 32;
76.          out = in >> -kShift;
77.          *pDst++ = out;
78.    
79.          in = *pSrc++;
80.          in = ((q63_t) in * scaleFract) >> 32;
81.          out = in >> -kShift;
82.          *pDst++ = out;
83.    
84.          /* Decrement loop counter */
85.          blkCnt--;
86.        }
87.      }
88.    
89.      /* Loop unrolling: Compute remaining outputs */
90.      blkCnt = blockSize % 0x4U;
91.    
92.    #else
93.    
94.      /* Initialize blkCnt with number of samples */
95.      blkCnt = blockSize;
96.    
97.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
98.    
99.      if (sign == 0U)
100.      {
101.        while (blkCnt > 0U)
102.        {
103.          /* C = A * scale */
104.    
105.          /* Scale input and store result in destination buffer. */
106.          in = *pSrc++;
107.          in = ((q63_t) in * scaleFract) >> 32;
108.          out = in << kShift;
109.          if (in != (out >> kShift))
110.              out = 0x7FFFFFFF ^ (in >> 31);
111.          *pDst++ = out;
112.    
113.          /* Decrement loop counter */
114.          blkCnt--;
115.        }
116.      }
117.      else
118.      {
119.        while (blkCnt > 0U)
120.        {
121.          /* C = A * scale */
122.    
123.          /* Scale input and store result in destination buffer. */
124.          in = *pSrc++;
125.          in = ((q63_t) in * scaleFract) >> 32;
126.          out = in >> -kShift;
127.          *pDst++ = out;
128.    
129.          /* Decrement loop counter */
130.          blkCnt--;
131.        }
132.      }
133.    
134.    }

 

函数描述:

这个函数用于求32位定点数的比例因子计算。

函数解析:

  •   第13到92行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
    •   第18行到56行,如果函数的移位形参shift是正数,那么执行左移。
    •   第57行到87行,如果函数的移位形参shift是负数,那么执行右移。
    •   这里特别注意一点,两个Q31函数相乘是2.62格式,而函数的结果要是Q31格式的,所以程序里面做了专门处理。

第26行,左移32位,那么结果就是2.30格式。

第27行,kShift = shift + 1,也就是out = in <<(shift + 1)多执行了一次左移操作。

相当于2.30格式,转换为2.31格式。

    •   第28到29行,做了一个Q31的饱和处理,也就是将2.31格式转换为1.31。

数值的左移仅支持将其左移后再右移相应的位数后数值不变的情况,如果不满足这个条件,那么要对输出结果做饱和运算,这里分两种情况:

out = 0x7FFFFFFF ^ (in >> 31)   (in是正数)

      = 0x7FFFFFFF ^ 0x00000000

      = 0x7FFFFFFF

 out = 0x7FFFFFFF ^ (in >> 31)   (in是负数)

      = 0x7FFFFFFF ^ 0xFFFFFFFF

      = 0x80000000

  •   第99到132行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。

函数参数:

  •   第1个参数是数据源地址。
  •   第2个参数是比例因子。
  •   第3个参数是移位参数,正数表示右移,负数表示左移。
  •   第4参数是结果地址。
  •   第5参数是数据块大小,其实就是执行比例因子计算的次数。

12.7.3        函数arm_scale_q15

函数原型:

 

1.    void arm_shift_q15(
2.      const q15_t * pSrc,
3.            int8_t shiftBits,
4.            q15_t * pDst,
5.            uint32_t blockSize)
6.    {
7.            uint32_t blkCnt;                               /* Loop counter */
8.            uint8_t sign = (shiftBits & 0x80);             /* Sign of shiftBits */
9.    
10.    #if defined (ARM_MATH_LOOPUNROLL)
11.    
12.    #if defined (ARM_MATH_DSP)
13.      q15_t in1, in2;                                /* Temporary input variables */
14.    #endif
15.    
16.      /* Loop unrolling: Compute 4 outputs at a time */
17.      blkCnt = blockSize >> 2U;
18.    
19.      /* If the shift value is positive then do right shift else left shift */
20.      if (sign == 0U)
21.      {
22.        while (blkCnt > 0U)
23.        {
24.          /* C = A << shiftBits */
25.    
26.    #if defined (ARM_MATH_DSP)
27.          /* read 2 samples from source */
28.          in1 = *pSrc++;
29.          in2 = *pSrc++;
30.    
31.          /* Shift the inputs and then store the results in the destination buffer. */
32.    #ifndef ARM_MATH_BIG_ENDIAN
33.          write_q15x2_ia (&pDst, __PKHBT(__SSAT((in1 << shiftBits), 16),
34.                                         __SSAT((in2 << shiftBits), 16), 16));
35.    #else
36.          write_q15x2_ia (&pDst, __PKHBT(__SSAT((in2 << shiftBits), 16),
37.                                          __SSAT((in1 << shiftBits), 16), 16));
38.    #endif /* #ifndef ARM_MATH_BIG_ENDIAN */
39.    
40.          /* read 2 samples from source */
41.          in1 = *pSrc++;
42.          in2 = *pSrc++;
43.    
44.    #ifndef ARM_MATH_BIG_ENDIAN
45.          write_q15x2_ia (&pDst, __PKHBT(__SSAT((in1 << shiftBits), 16),
46.                                         __SSAT((in2 << shiftBits), 16), 16));
47.    #else
48.          write_q15x2_ia (&pDst, __PKHBT(__SSAT((in2 << shiftBits), 16),
49.                                         __SSAT((in1 << shiftBits), 16), 16));
50.    #endif /* #ifndef ARM_MATH_BIG_ENDIAN */
51.    
52.    #else
53.          *pDst++ = __SSAT(((q31_t) *pSrc++ << shiftBits), 16);
54.          *pDst++ = __SSAT(((q31_t) *pSrc++ << shiftBits), 16);
55.          *pDst++ = __SSAT(((q31_t) *pSrc++ << shiftBits), 16);
56.          *pDst++ = __SSAT(((q31_t) *pSrc++ << shiftBits), 16);
57.    #endif
58.    
59.          /* Decrement loop counter */
60.          blkCnt--;
61.        }
62.      }
63.      else
64.      {
65.        while (blkCnt > 0U)
66.        {
67.          /* C = A >> shiftBits */
68.    
69.    #if defined (ARM_MATH_DSP)
70.          /* read 2 samples from source */
71.          in1 = *pSrc++;
72.          in2 = *pSrc++;
73.    
74.          /* Shift the inputs and then store the results in the destination buffer. */
75.    #ifndef ARM_MATH_BIG_ENDIAN
76.          write_q15x2_ia (&pDst, __PKHBT((in1 >> -shiftBits),
77.                                         (in2 >> -shiftBits), 16));
78.    #else
79.          write_q15x2_ia (&pDst, __PKHBT((in2 >> -shiftBits),
80.                                         (in1 >> -shiftBits), 16));
81.    #endif /* #ifndef ARM_MATH_BIG_ENDIAN */
82.    
83.          /* read 2 samples from source */
84.          in1 = *pSrc++;
85.          in2 = *pSrc++;
86.    
87.    #ifndef ARM_MATH_BIG_ENDIAN
88.          write_q15x2_ia (&pDst, __PKHBT((in1 >> -shiftBits),
89.                                         (in2 >> -shiftBits), 16));
90.    #else
91.          write_q15x2_ia (&pDst, __PKHBT((in2 >> -shiftBits),
92.                                         (in1 >> -shiftBits), 16));
93.    #endif /* #ifndef ARM_MATH_BIG_ENDIAN */
94.    
95.    #else
96.          *pDst++ = (*pSrc++ >> -shiftBits);
97.          *pDst++ = (*pSrc++ >> -shiftBits);
98.          *pDst++ = (*pSrc++ >> -shiftBits);
99.          *pDst++ = (*pSrc++ >> -shiftBits);
100.    #endif
101.    
102.          /* Decrement loop counter */
103.          blkCnt--;
104.        }
105.      }
106.    
107.      /* Loop unrolling: Compute remaining outputs */
108.      blkCnt = blockSize % 0x4U;
109.    
110.    #else
111.    
112.      /* Initialize blkCnt with number of samples */
113.      blkCnt = blockSize;
114.    
115.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
116.    
117.      /* If the shift value is positive then do right shift else left shift */
118.      if (sign == 0U)
119.      {
120.        while (blkCnt > 0U)
121.        {
122.          /* C = A << shiftBits */
123.    
124.          /* Shift input and store result in destination buffer. */
125.          *pDst++ = __SSAT(((q31_t) *pSrc++ << shiftBits), 16);
126.    
127.          /* Decrement loop counter */
128.          blkCnt--;
129.        }
130.      }
131.      else
132.      {
133.        while (blkCnt > 0U)
134.        {
135.          /* C = A >> shiftBits */
136.    
137.          /* Shift input and store result in destination buffer. */
138.          *pDst++ = (*pSrc++ >> -shiftBits);
139.    
140.          /* Decrement loop counter */
141.          blkCnt--;
142.        }
143.      }
144.    
145.    }

 

函数描述:

这个函数用于求16位定点数的比例因子计算。

函数解析:

  •   第10到110行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
    •   第20到62行,如果函数的移位形参shiftBits是正数,执行左移。
    •   第63到105行,如果函数的移位形参shiftBits是负数,执行右移。
    •   第33行,函数__PKHBT也是SIMD指令,作用是将将两个16位的数据合并成32位数据。用C实现的话,如下:
  #define __PKHBT(ARG1, ARG2, ARG3) ( (((int32_t)(ARG1) <<    0) & (int32_t)0x0000FFFF) | \
                                      (((int32_t)(ARG2) << ARG3) & (int32_t)0xFFFF0000)  )

函数write_q15x2_ia的原型如下:

__STATIC_FORCEINLINE void write_q15x2_ia (
  q15_t ** pQ15,
  q31_t    value)
{
  q31_t val = value;

  memcpy (*pQ15, &val, 4);
  *pQ15 += 2;
}

作用是写入两次Q15格式数据,组成一个Q31格式数据,并将数据地址递增,方便下次写入。

  •   第118到143行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理

函数参数:

  •   第1个参数是数据源地址。
  •   第2个参数是比例因子。
  •   第3个参数是移位参数,正数表示右移,负数表示左移。
  •   第4参数是结果地址。
  •   第5参数是数据块大小,其实就是执行比例因子计算的次数。

12.7.4        函数arm_scale_q7

函数原型:

 

1.    void arm_scale_q7(
2.      const q7_t * pSrc,
3.            q7_t scaleFract,
4.            int8_t shift,
5.            q7_t * pDst,
6.            uint32_t blockSize)
7.    {
8.            uint32_t blkCnt;                               /* Loop counter */
9.            int8_t kShift = 7 - shift;                     /* Shift to apply after scaling */
10.    
11.    #if defined (ARM_MATH_LOOPUNROLL)
12.    
13.    #if defined (ARM_MATH_DSP)
14.      q7_t in1,  in2,  in3,  in4;                    /* Temporary input variables */
15.      q7_t out1, out2, out3, out4;                   /* Temporary output variables */
16.    #endif
17.    
18.      /* Loop unrolling: Compute 4 outputs at a time */
19.      blkCnt = blockSize >> 2U;
20.    
21.      while (blkCnt > 0U)
22.      {
23.        /* C = A * scale */
24.    
25.    #if defined (ARM_MATH_DSP)
26.        /* Reading 4 inputs from memory */
27.        in1 = *pSrc++;
28.        in2 = *pSrc++;
29.        in3 = *pSrc++;
30.        in4 = *pSrc++;
31.    
32.        /* Scale inputs and store result in the temporary variable. */
33.        out1 = (q7_t) (__SSAT(((in1) * scaleFract) >> kShift, 8));
34.        out2 = (q7_t) (__SSAT(((in2) * scaleFract) >> kShift, 8));
35.        out3 = (q7_t) (__SSAT(((in3) * scaleFract) >> kShift, 8));
36.        out4 = (q7_t) (__SSAT(((in4) * scaleFract) >> kShift, 8));
37.    
38.        /* Pack and store result in destination buffer (in single write) */
39.        write_q7x4_ia (&pDst, __PACKq7(out1, out2, out3, out4));
40.    #else
41.        *pDst++ = (q7_t) (__SSAT((((q15_t) *pSrc++ * scaleFract) >> kShift), 8));
42.        *pDst++ = (q7_t) (__SSAT((((q15_t) *pSrc++ * scaleFract) >> kShift), 8));
43.        *pDst++ = (q7_t) (__SSAT((((q15_t) *pSrc++ * scaleFract) >> kShift), 8));
44.        *pDst++ = (q7_t) (__SSAT((((q15_t) *pSrc++ * scaleFract) >> kShift), 8));
45.    #endif
46.    
47.        /* Decrement loop counter */
48.        blkCnt--;
49.      }
50.    
51.      /* Loop unrolling: Compute remaining outputs */
52.      blkCnt = blockSize % 0x4U;
53.    
54.    #else
55.    
56.      /* Initialize blkCnt with number of samples */
57.      blkCnt = blockSize;
58.    
59.    #endif /* #if defined (ARM_MATH_LOOPUNROLL) */
60.    
61.      while (blkCnt > 0U)
62.      {
63.        /* C = A * scale */
64.    
65.        /* Scale input and store result in destination buffer. */
66.        *pDst++ = (q7_t) (__SSAT((((q15_t) *pSrc++ * scaleFract) >> kShift), 8));
67.    
68.        /* Decrement loop counter */
69.        blkCnt--;
70.      }
71.    
72.    }

 

函数描述:

这个函数用于求8位定点数的比例因子计算。

函数解析:

  •   第9行,这个变量设计很巧妙,这样下面处理正数左移和负数右移就很方面了,可以直接使用一个右移就可以实现。
  •   第11到54行,实现四个为一组进行计数,好处是加快执行速度,降低while循环占用时间。
    •   33到36行,对输入的数据做8位的饱和处理。比如:

  (in1 * scaleFract) >> kShift

= (in1 * scaleFract) * 2^(shift - 7)

= ((in1 * scaleFract) >>7)*(2^shift)

源数据in1格式Q7乘以比例因子scaleFract格式Q7,也就是2.14格式,再右移7bit就是2.7格式,

此时如果shift正数,那么就是当前结果左移shitf位,如果shift是负数,那么就是当前结果右移shift位。最终结果通过__SSAT做个饱和运算。

  •   第61到70行,四个为一组剩余数据的处理或者不采用四个为一组时数据处理。

函数参数:

  •   第1个参数是数据源地址。
  •   第2个参数是比例因子。
  •   第3个参数是移位参数,正数表示右移,负数表示左移。
  •   第4参数是结果地址。
  •   第5参数是数据块大小,其实就是执行比例因子计算的次数。

12.7.5        使用举例

程序设计:

 

/*
*********************************************************************************************************
*    函 数 名: DSP_Scale
*    功能说明: 比例因子
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static void DSP_Scale(void)
{
    float32_t   pSrcA[5] = {1.0f,1.0f,1.0f,1.0f,1.0f};
    float32_t   scale = 0.0f;  
    float32_t   pDst[5];  
    
    q31_t  pSrcA1[5] = {0x6fffffff,1,1,1,1};  
    q31_t  scale1 = 0x6fffffff;  
    q31_t  pDst1[5];   

    q15_t  pSrcA2[5] = {0x6fff,1,1,1,1};  
    q15_t  scale2 = 0x6fff;  
    q15_t  pDst2[5];   

    q7_t  pSrcA3[5] = {0x70,1,1,1,1}; 
    q7_t  scale3 = 0x6f;  
    q7_t pDst3[5];  

    /*求比例因子计算*********************************/    
    scale += 0.1f;
    arm_scale_f32(pSrcA, scale, pDst, 5);
    printf("arm_scale_f32 = %f\r\n", pDst[0]);
    
    scale1 += 1;
    arm_scale_q31(pSrcA1, scale1, 0, pDst1, 5);
    printf("arm_scale_q31 = %x\r\n", pDst1[0]);

    scale2 += 1;
    arm_scale_q15(pSrcA2, scale2, 0, pDst2, 5);
    printf("arm_scale_q15 = %x\r\n", pDst2[0]);

    scale3 += 1;
    arm_scale_q7(pSrcA3, scale3, 0, pDst3, 5);
    printf("arm_scale_q7 = %x\r\n", pDst3[0]);
    printf("***********************************\r\n");
}

 

实验现象:

【STM32F407的DSP教程】第12章 DSP基础函数-相反数,偏移,移位,减法和比例因子

12.8 实验例程说明(MDK)

配套例子:

V5-207_DSP基础运算(相反数,偏移,移位,减法和比例因子)

实验目的:

  1. 学习基础运算(相反数,偏移,移位,减法和比例因子)

实验内容:

  1. 启动一个自动重装软件定时器,每100ms翻转一次LED2。
  2. 按下按键K1, DSP求相反数运算。
  3. 按下按键K2, DSP求偏移运算。
  4. 按下按键K3, DSP求移位运算。
  5. 按下摇杆OK键, DSP求减法运算。
  6. 按下摇杆上键, DSP比例因子运算。

使用AC6注意事项

特别注意附件章节C的问题

上电后串口打印的信息:

波特率 115200,数据位 8,奇偶校验位无,停止位 1。

详见本章的3.5,4.5,5.4和6.5小节。

程序设计:

  系统栈大小分配:

【STM32F407的DSP教程】第12章 DSP基础函数-相反数,偏移,移位,减法和比例因子

  硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

 

/*
*********************************************************************************************************
*    函 数 名: bsp_Init
*    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
    /* 
       STM32F407 HAL 库初始化,此时系统用的还是F407自带的16MHz,HSI时钟:
       - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
       - 设置NVIV优先级分组为4。
     */
    HAL_Init();

    /* 
       配置系统时钟到168MHz
       - 切换使用HSE。
       - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    */
    SystemClock_Config();

    /* 
       Event Recorder:
       - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
       - 默认不开启,如果要使能此选项,务必看V5开发板用户手册第8章
    */    
#if Enable_EventRecorder == 1  
    /* 初始化EventRecorder并开启 */
    EventRecorderInitialize(EventRecordAll, 1U);
    EventRecorderStart();
#endif
    
    bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
    bsp_InitTimer();      /* 初始化滴答定时器 */
    bsp_InitUart();    /* 初始化串口 */
    bsp_InitLed();        /* 初始化LED */        

    bsp_InitESP8266();    /* 配置ESP8266模块相关的资源 */
}

 

  主功能:

主程序实现如下操作:

  •   启动一个自动重装软件定时器,每100ms翻转一次LED2。
  •   按下按键K1, DSP求相反数运算。
  •   按下按键K2, DSP求偏移运算。
  •   按下按键K3, DSP求移位运算。
  •   按下摇杆OK键, DSP求减法运算。
  •   按下摇杆上键, DSP比例因子运算。  

 

/*
*********************************************************************************************************
*    函 数 名: main
*    功能说明: c程序入口
*    形    参:无
*    返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{
    uint8_t ucKeyCode;        /* 按键代码 */
    

    bsp_Init();        /* 硬件初始化 */
    PrintfLogo();    /* 打印例程信息到串口1 */

    PrintfHelp();    /* 打印操作提示信息 */
    

    bsp_StartAutoTimer(0, 100);    /* 启动1个100ms的自动重装的定时器 */

    /* 进入主程序循环体 */
    while (1)
    {
        bsp_Idle();        /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */

        /* 判断定时器超时时间 */
        if (bsp_CheckTimer(0))    
        {
            /* 每隔100ms 进来一次 */  
            bsp_LedToggle(2);
        }

        ucKeyCode = bsp_GetKey();    /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
        if (ucKeyCode != KEY_NONE)
        {
            switch (ucKeyCode)
            {
                case KEY_DOWN_K1:            /* K1键按下,求相反数 */
                    DSP_Negate();
                    break;

                case KEY_DOWN_K2:            /* K2键按下, 求偏移 */
                    DSP_Offset();
                    break;

                case KEY_DOWN_K3:            /* K3键按下,求移位 */
                    DSP_Shift();
                    break;
    
                case JOY_DOWN_OK:            /* 摇杆OK键按下,求减法 */
                    DSP_Sub();
                    break;
                
                case JOY_DOWN_U:            /* 摇杆上键按下,求比例因子计算 */
                    DSP_Scale();
                    break;

                default:
                    /* 其他的键值不处理 */
                    break;
            }
        }
    }
}

 

12.9 实验例程说明(IAR)

配套例子:

V5-207_DSP基础运算(相反数,偏移,移位,减法和比例因子)

实验目的:

  1. 学习基础运算(相反数,偏移,移位,减法和比例因子)

实验内容:

  1. 启动一个自动重装软件定时器,每100ms翻转一次LED2。
  2. 按下按键K1, DSP求相反数运算。
  3. 按下按键K2, DSP求偏移运算。
  4. 按下按键K3, DSP求移位运算。
  5. 按下摇杆OK键, DSP求减法运算。
  6. 按下摇杆上键, DSP比例因子运算。

使用AC6注意事项

特别注意附件章节C的问题

上电后串口打印的信息:

波特率 115200,数据位 8,奇偶校验位无,停止位 1。

详见本章的3.5,4.5,5.4和6.5小节。

程序设计:

  系统栈大小分配:

【STM32F407的DSP教程】第12章 DSP基础函数-相反数,偏移,移位,减法和比例因子

  硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

 

/*
*********************************************************************************************************
*    函 数 名: bsp_Init
*    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
    /* 
       STM32F407 HAL 库初始化,此时系统用的还是F407自带的16MHz,HSI时钟:
       - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
       - 设置NVIV优先级分组为4。
     */
    HAL_Init();

    /* 
       配置系统时钟到168MHz
       - 切换使用HSE。
       - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    */
    SystemClock_Config();

    /* 
       Event Recorder:
       - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
       - 默认不开启,如果要使能此选项,务必看V5开发板用户手册第8章
    */    
#if Enable_EventRecorder == 1  
    /* 初始化EventRecorder并开启 */
    EventRecorderInitialize(EventRecordAll, 1U);
    EventRecorderStart();
#endif
    
    bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
    bsp_InitTimer();      /* 初始化滴答定时器 */
    bsp_InitUart();    /* 初始化串口 */
    bsp_InitExtIO();   /* 初始化扩展IO */
    bsp_InitLed();        /* 初始化LED */        
}

 

  主功能:

主程序实现如下操作:

  •   启动一个自动重装软件定时器,每100ms翻转一次LED2。
  •   按下按键K1, DSP求相反数运算。
  •   按下按键K2, DSP求偏移运算。
  •   按下按键K3, DSP求移位运算。
  •   按下摇杆OK键, DSP求减法运算。
  •   按下摇杆上键, DSP比例因子运算。  

 

/*
*********************************************************************************************************
*    函 数 名: main
*    功能说明: c程序入口
*    形    参:无
*    返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{
    uint8_t ucKeyCode;        /* 按键代码 */
    

    bsp_Init();        /* 硬件初始化 */
    PrintfLogo();    /* 打印例程信息到串口1 */

    PrintfHelp();    /* 打印操作提示信息 */
    

    bsp_StartAutoTimer(0, 100);    /* 启动1个100ms的自动重装的定时器 */

    /* 进入主程序循环体 */
    while (1)
    {
        bsp_Idle();        /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */

        /* 判断定时器超时时间 */
        if (bsp_CheckTimer(0))    
        {
            /* 每隔100ms 进来一次 */  
            bsp_LedToggle(2);
        }

        ucKeyCode = bsp_GetKey();    /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
        if (ucKeyCode != KEY_NONE)
        {
            switch (ucKeyCode)
            {
                case KEY_DOWN_K1:            /* K1键按下,求相反数 */
                    DSP_Negate();
                    break;

                case KEY_DOWN_K2:            /* K2键按下, 求偏移 */
                    DSP_Offset();
                    break;

                case KEY_DOWN_K3:            /* K3键按下,求移位 */
                    DSP_Shift();
                    break;
    
                case JOY_DOWN_OK:            /* 摇杆OK键按下,求减法 */
                    DSP_Sub();
                    break;
                
                case JOY_DOWN_U:            /* 摇杆上键按下,求比例因子计算 */
                    DSP_Scale();
                    break;

                default:
                    /* 其他的键值不处理 */
                    break;
            }
        }
    }
}

 

12.10   总结

DSP基础函数就跟大家讲这么多,希望初学的同学多多的练习,并在自己以后的项目中多多使用,效果必将事半功倍。