zoukankan      html  css  js  c++  java
  • 【STM32H7的DSP教程】第21章 DSP矩阵运算-加法,减法和逆矩阵

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

    第21章       DSP矩阵运算-加法,减法和逆矩阵

    本期教程主要讲解矩阵运算中的初始化,加法,逆矩阵和减法。

    21.1 初学者重要提示

    21.2 DSP基础运算指令

    21.3 矩阵初始化(MatInit)

    21.4 矩阵加法(MatAdd)

    21.5 矩阵减法(MatSub)

    21.6 逆矩阵(MatInverse)

    21.7 实验例程说明(MDK)

    21.8 实验例程说明(IAR)

    21.9 总结

     

    21.1 初学者重要提示

    1.   复数运算比较重要,后面FFT章节要用到,如果印象不深的话,需要温习下高数知识了。
    2.   ARM提供的DSP库逆矩阵求法有局限性,通过Matlab验证是可以求逆矩阵的,而DSP库却不能正确求解。

    21.2 DSP基础运算指令

    本章用到的DSP指令在前面章节都已经讲解过。

    21.3 矩阵初始化(MatInit)

    主要用于矩阵结构体成员的初始化,浮点格式矩阵结构体定义如下:

    typedef struct
    {
    uint16_t numRows;     // 矩阵行数.
    uint16_t numCols;     // 矩阵列数
    float32_t *pData;     // 矩阵地址
    } arm_matrix_instance_f32

    定点数Q31格式矩阵结构体定义如下:

    typedef struct
    {
      uint16_t numRows;     //矩阵行数
      uint16_t numCols;     //矩阵列数
      q31_t *pData;         //矩阵地址
    } arm_matrix_instance_q31;

    定点数Q15格式矩阵结构体定义如下:

    typedef struct
    {
      uint16_t numRows;     //矩阵行数
      uint16_t numCols;     //矩阵列数
      q15_t *pData;         //矩阵地址
    } arm_matrix_instance_q15;

    21.3.1        函数arm_mat_init_f32

    函数原型:

    void arm_mat_init_f32(

      arm_matrix_instance_f32 * S,

      uint16_t nRows,

      uint16_t nColumns,

      float32_t * pData)

    函数描述:

    这个函数用于浮点格式的矩阵数据初始化。

    函数参数:

    •   第1个参数是arm_matrix_instance_f32类型矩阵结构体指针变量。
    •   第2个参数是矩阵行数。
    •   第3个参数是矩阵列数。
    •   第4个参数是矩阵数据地址。

     

    21.3.2        函数arm_mat_init_q31

    函数原型:

    void arm_mat_init_f32(

      arm_matrix_instance_f32 * S,

      uint16_t nRows,

      uint16_t nColumns,

      float32_t * pData)

    函数描述:

    这个函数用于定点数Q31格式的矩阵数据初始化。

    函数参数:

    •   第1个参数是arm_matrix_instance_q31类型矩阵结构体指针变量。
    •   第2个参数是矩阵行数。
    •   第3个参数是矩阵列数。
    •   第4个参数是矩阵数据地址。

     

    21.3.3        函数arm_mat_init_q15

    函数原型:

    void arm_mat_init_f32(

      arm_matrix_instance_f32 * S,

      uint16_t nRows,

      uint16_t nColumns,

      float32_t * pData)

    函数描述:

    这个函数用于定点数Q15格式的矩阵数据初始化。

    函数参数:

    •   第1个参数是arm_matrix_instance_q15类型矩阵结构体指针变量。
    •   第2个参数是矩阵行数。
    •   第3个参数是矩阵列数。
    •   第4个参数是矩阵数据地址。

    21.3.4        使用举例

    程序设计:

    /*
    *********************************************************************************************************
    *    函 数 名: DSP_MatInit
    *    功能说明: 矩阵数据初始化
    *    形    参:无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void DSP_MatInit(void)
    {
        uint8_t i;
        
        /****浮点数数组******************************************************************/
        float32_t pDataA[9] = {1.1f, 1.1f, 2.1f, 2.1f, 3.1f, 3.1f, 4.1f, 4.1f, 5.1f};
        
        arm_matrix_instance_f32 pSrcA; //3行3列数据
        
        /****定点数Q31数组******************************************************************/
        q31_t pDataA1[9] = {1, 1, 2, 2, 3, 3, 4, 4, 5};
        
        arm_matrix_instance_q31 pSrcA1; //3行3列数据
        
        /****定点数Q15数组******************************************************************/
        q15_t pDataA2[9] = {1, 1, 2, 2, 3, 3, 4, 4, 5};
        
        arm_matrix_instance_q15 pSrcA2; //3行3列数据
        
        /****浮点数***********************************************************************/    
        printf("****浮点数******************************************
    ");
        arm_mat_init_f32(&pSrcA, 3,3, pDataA);
        for(i = 0; i < 9; i++)
        {
            printf("pDataA[%d] = %f
    ", i, pDataA[i]);
        }
        
        /****定点数Q31***********************************************************************/
        printf("****浮点数******************************************
    ");
        arm_mat_init_q31(&pSrcA1, 3,3, pDataA1);
        for(i = 0; i < 9; i++)
        {
            printf("pDataA1[%d] = %d
    ", i, pDataA1[i]);
        }
        
        /****定点数Q15***********************************************************************/
        printf("****浮点数******************************************
    ");
        arm_mat_init_q15(&pSrcA2, 3,3, pDataA2);
        for(i = 0; i < 9; i++)
        {
            printf("pDataA2[%d] = %d
    ", i, pDataA2[i]);
        }
    }

    实验现象(按下K1按键后串口打印模平方):

     

    21.4 矩阵加法(MatAdd)

    以3*3矩阵为例,矩阵加法的实现公式如下:

     

    21.4.1 函数arm_mat_add_f32

    函数原型:

    arm_status arm_mat_add_f32(

      const arm_matrix_instance_f32 * pSrcA,

      const arm_matrix_instance_f32 * pSrcB,

      arm_matrix_instance_f32 * pDst)

    函数描述:

    这个函数用于浮点数的矩阵加法。

    函数参数:

    •   第1个参数是矩阵A的源地址。
    •   第2个参数是矩阵B的源地址。
    •   第3个参数是矩阵A + 矩阵B计算结果存储的地址。
    •  返回值,ARM_MATH_SUCCESS表示成功,ARM_MATH_SIZE_MISMATCH表示矩阵大小不一致。

    注意事项:

    1. pSrcA,pSrcB,pDst的行数和列数必须是相同的,否则没有办法使用加法运算。
    2. 矩阵在数组中的存储是从左到右,再从上到下。

    21.4.2 函数arm_mat_add_q31

    函数原型:

    arm_status arm_mat_add_f32(

      const arm_matrix_instance_f32 * pSrcA,

      const arm_matrix_instance_f32 * pSrcB,

      arm_matrix_instance_f32 * pDst)

    函数描述:

    这个函数用于定点数Q31的矩阵加法。

    函数参数:

    •   第1个参数是矩阵A的源地址。
    •   第2个参数是矩阵B的源地址。
    •   第3个参数是矩阵A + 矩阵B计算结果存储的地址。
    •   返回值,ARM_MATH_SUCCESS表示成功,ARM_MATH_SIZE_MISMATCH表示矩阵大小不一致。

    注意事项:

    1. 使用了饱和运算,输出结果范围[0x80000000 0x7FFFFFFF]。
    2. pSrcA,pSrcB,pDst的行数和列数必须是相同的,否则没有办法使用加法运算。
    3. 矩阵在数组中的存储是从左到右,再从上到下。

    21.4.3 函数arm_mat_add_q15

    函数原型:

    arm_status arm_mat_add_f32(

      const arm_matrix_instance_f32 * pSrcA,

      const arm_matrix_instance_f32 * pSrcB,

      arm_matrix_instance_f32 * pDst)

    函数描述:

    这个函数用于定点数Q15的矩阵加法。

    函数参数:

    •   第1个参数是矩阵A的源地址。
    •   第2个参数是矩阵B的源地址。
    •   第3个参数是矩阵A + 矩阵B计算结果存储的地址。
    •   返回值,ARM_MATH_SUCCESS表示成功,ARM_MATH_SIZE_MISMATCH表示矩阵大小不一致。

    注意事项:

    1. 使用了饱和运算,输出结果范围[0x8000 0x7FFF]。
    2. pSrcA,pSrcB,pDst的行数和列数必须是相同的,否则没有办法使用加法运算。
    3. 矩阵在数组中的存储是从左到右,再从上到。

    21.4.4        用举例(含Matlab实现)

    程序设计:

    /*
    *********************************************************************************************************
    *    函 数 名: DSP_MatAdd
    *    功能说明: 矩阵求和
    *    形    参:无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void DSP_MatAdd(void)
    {
        uint8_t i;
    
        /****浮点数数组******************************************************************/
        float32_t pDataA[9] = {1.1f, 1.1f, 2.1f, 2.1f, 3.1f, 3.1f, 4.1f, 4.1f, 5.1f};
        float32_t pDataB[9] = {1.1f, 1.1f, 2.1f, 2.1f, 3.1f, 3.1f, 4.1f, 4.1f, 5.1f};
        float32_t pDataDst[9];
        
        arm_matrix_instance_f32 pSrcA; //3行3列数据
        arm_matrix_instance_f32 pSrcB; //3行3列数据
        arm_matrix_instance_f32 pDst;
        
        /****定点数Q31数组******************************************************************/
        q31_t pDataA1[9] = {1, 1, 2, 2, 3, 3, 4, 4, 5};
        q31_t pDataB1[9] = {1, 1, 2, 2, 3, 3, 4, 4, 5};
        q31_t pDataDst1[9];
        
        arm_matrix_instance_q31 pSrcA1; //3行3列数据
        arm_matrix_instance_q31 pSrcB1; //3行3列数据
        arm_matrix_instance_q31 pDst1;
        
        /****定点数Q15数组******************************************************************/
        q15_t pDataA2[9] = {1, 1, 2, 2, 3, 3, 4, 4, 5};
        q15_t pDataB2[9] = {1, 1, 2, 2, 3, 3, 4, 4, 5};
        q15_t pDataDst2[9];
        
        arm_matrix_instance_q15 pSrcA2; //3行3列数据
        arm_matrix_instance_q15 pSrcB2; //3行3列数据
        arm_matrix_instance_q15 pDst2;
        
        /****浮点数***********************************************************************/
        pSrcA.numCols = 3;
        pSrcA.numRows = 3;
        pSrcA.pData = pDataA;
        
        pSrcB.numCols = 3;
        pSrcB.numRows = 3;
        pSrcB.pData = pDataB;
        
        pDst.numCols = 3;
        pDst.numRows = 3;
        pDst.pData = pDataDst;
        
        printf("****浮点数******************************************
    ");
        arm_mat_add_f32(&pSrcA, &pSrcB, &pDst);
        for(i = 0; i < 9; i++)
        {
            printf("pDataDst[%d] = %f
    ", i, pDataDst[i]);
        }
        
        
        /****定点数Q31***********************************************************************/
        pSrcA1.numCols = 3;
        pSrcA1.numRows = 3;
        pSrcA1.pData = pDataA1;
        
        pSrcB1.numCols = 3;
        pSrcB1.numRows = 3;
        pSrcB1.pData = pDataB1;
        
        pDst1.numCols = 3;
        pDst1.numRows = 3;
        pDst1.pData = pDataDst1;
        
        printf("****定点数Q31******************************************
    ");
        arm_mat_add_q31(&pSrcA1, &pSrcB1, &pDst1);
        for(i = 0; i < 9; i++)
        {
            printf("pDataDst1[%d] = %d
    ", i, pDataDst1[i]);
        }
        
        /****定点数Q15***********************************************************************/
        pSrcA2.numCols = 3;
        pSrcA2.numRows = 3;
        pSrcA2.pData = pDataA2;
        
        pSrcB2.numCols = 3;
        pSrcB2.numRows = 3;
        pSrcB2.pData = pDataB2;
        
        pDst2.numCols = 3;
        pDst2.numRows = 3;
        pDst2.pData = pDataDst2;
        
        printf("****定点数Q15******************************************
    ");
        arm_mat_add_q15(&pSrcA2, &pSrcB2, &pDst2);
        for(i = 0; i < 9; i++)
        {
            printf("pDataDst2[%d] = %d
    ", i, pDataDst2[i]);
        }
    }

    实验现象(按下K2按键后串口打印矩阵加法):

     

    下面通过Matlab来求解矩阵和(在命令窗口输入):

     

    21.5 矩阵减法(MatSub)

    以3*3矩阵为例,矩阵减法的实现公式如下:

     

    21.5.1 函数arm_mat_sub_f32

    函数原型:

    arm_status arm_mat_sub_f32(

      const arm_matrix_instance_f32 * pSrcA,

      const arm_matrix_instance_f32 * pSrcB,

      arm_matrix_instance_f32 * pDst)

    函数描述:

    这个函数用于浮点数的矩阵减法。

    函数参数:

    •   第1个参数是矩阵A的源地址。
    •   第2个参数是矩阵B的源地址。
    •   第3个参数是矩阵A减去矩阵B计算结果存储的地址。
    •   返回值,ARM_MATH_SUCCESS表示成功,ARM_MATH_SIZE_MISMATCH表示矩阵大小不一致。

    注意事项:

    1. pSrcA,pSrcB,pDst的行数和列数必须是相同的,否则没有办法使用加法运算。
    2. 矩阵在数组中的存储是从左到右,再从上到下。

    21.5.2 函数arm_mat_sub_q31

    函数原型:

    arm_status arm_mat_sub_q31(

      const arm_matrix_instance_q31 * pSrcA,

      const arm_matrix_instance_q31 * pSrcB,

            arm_matrix_instance_q31 * pDst)

    函数描述:

    这个函数用于定点数Q31的矩阵减法。

    函数参数:

    •   第1个参数是矩阵A的源地址。
    •   第2个参数是矩阵B的源地址。
    •   第3个参数是矩阵A减去矩阵B计算结果存储的地址。
    •   返回值,ARM_MATH_SUCCESS表示成功,ARM_MATH_SIZE_MISMATCH表示矩阵大小不一致。

    注意事项:

    1. 使用了饱和运算,输出结果范围[0x80000000 0x7FFFFFFF]。
    2. pSrcA,pSrcB,pDst的行数和列数必须是相同的,否则没有办法使用加法运算。
    3. 矩阵在数组中的存储是从左到右,再从上到下。

    21.5.3 函数arm_mat_sub_q15

    函数原型:

    arm_status arm_mat_sub_q15(

      const arm_matrix_instance_q15 * pSrcA,

      const arm_matrix_instance_q15 * pSrcB,

            arm_matrix_instance_q15 * pDst)

    函数描述:

    这个函数用于定点数Q15的矩阵减法。

    函数参数:

    •   第1个参数是矩阵A的源地址。
    •   第2个参数是矩阵B的源地址。
    •   第3个参数是矩阵A减去矩阵B计算结果存储的地址。
    •   返回值,ARM_MATH_SUCCESS表示成功,ARM_MATH_SIZE_MISMATCH表示矩阵大小不一致。

    注意事项:

    1. 使用了饱和运算,输出结果范围[0x8000 0x7FFF]。
    2. pSrcA,pSrcB,pDst的行数和列数必须是相同的,否则没有办法使用加法运算。
    3. 矩阵在数组中的存储是从左到右,再从上。

    21.5.4        使用举例(含Matlab实现)

    程序设计:

    /*
    *********************************************************************************************************
    *    函 数 名: DSP_MatSub
    *    功能说明: 矩阵减法
    *    形    参:无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void DSP_MatSub(void)
    {
        uint8_t i;
        
        /****浮点数数组******************************************************************/
        float32_t pDataA[9] = {1.1f, 1.1f, 2.1f, 2.1f, 3.1f, 3.1f, 4.1f, 4.1f, 5.1f};
        float32_t pDataB[9] = {1.1f, 1.1f, 2.1f, 2.1f, 3.1f, 3.1f, 4.1f, 4.1f, 5.1f};
        float32_t pDataDst[9];
        
        arm_matrix_instance_f32 pSrcA; //3行3列数据
        arm_matrix_instance_f32 pSrcB; //3行3列数据
        arm_matrix_instance_f32 pDst;
        
        /****定点数Q31数组******************************************************************/
        q31_t pDataA1[9] = {1, 1, 2, 2, 3, 3, 4, 4, 5};
        q31_t pDataB1[9] = {2, 2, 2, 2, 2, 2, 2, 2, 2};
        q31_t pDataDst1[9];
        
        arm_matrix_instance_q31 pSrcA1; //3行3列数据
        arm_matrix_instance_q31 pSrcB1; //3行3列数据
        arm_matrix_instance_q31 pDst1;
        
        /****定点数Q15数组******************************************************************/
        q15_t pDataA2[9] = {1, 1, 2, 2, 3, 3, 4, 4, 5};
        q15_t pDataB2[9] = {2, 2, 2, 2, 23, 2, 2, 2, 2};
        q15_t pDataDst2[9];
        
        arm_matrix_instance_q15 pSrcA2; //3行3列数据
        arm_matrix_instance_q15 pSrcB2; //3行3列数据
        arm_matrix_instance_q15 pDst2;
        
        /****浮点数***********************************************************************/
        pSrcA.numCols = 3;
        pSrcA.numRows = 3;
        pSrcA.pData = pDataA;
        
        pSrcB.numCols = 3;
        pSrcB.numRows = 3;
        pSrcB.pData = pDataB;
        
        pDst.numCols = 3;
        pDst.numRows = 3;
        pDst.pData = pDataDst;
        
        printf("****浮点数******************************************
    ");
        arm_mat_sub_f32(&pSrcA, &pSrcB, &pDst);
        for(i = 0; i < 9; i++)
        {
            printf("pDataDst[%d] = %f
    ", i, pDataDst[i]);
        }
        
        /****定点数Q31***********************************************************************/
        pSrcA1.numCols = 3;
        pSrcA1.numRows = 3;
        pSrcA1.pData = pDataA1;
        
        pSrcB1.numCols = 3;
        pSrcB1.numRows = 3;
        pSrcB1.pData = pDataB1;
        
        pDst1.numCols = 3;
        pDst1.numRows = 3;
        pDst1.pData = pDataDst1;
        
        printf("****定点数Q31******************************************
    ");
        arm_mat_sub_q31(&pSrcA1, &pSrcB1, &pDst1);
        for(i = 0; i < 9; i++)
        {
            printf("pDataDst1[%d] = %d
    ", i, pDataDst1[i]);
        }
        
        
        /****定点数Q15***********************************************************************/
        pSrcA2.numCols = 3;
        pSrcA2.numRows = 3;
        pSrcA2.pData = pDataA2;
        
        pSrcB2.numCols = 3;
        pSrcB2.numRows = 3;
        pSrcB2.pData = pDataB2;
        
        pDst2.numCols = 3;
        pDst2.numRows = 3;
        pDst2.pData = pDataDst2;
        
        printf("****定点数Q15******************************************
    ");
        arm_mat_sub_q15(&pSrcA2, &pSrcB2, &pDst2);
        for(i = 0; i < 9; i++)
        {
            printf("pDataDst2[%d] = %d
    ", i, pDataDst2[i]);
        }
    }

    实验现象(按下OK按键后串口打印矩阵减法):

     

    下面通过Matlab来求解矩阵减法(在命令窗口输入)。

     

    21.6 逆矩阵(MatInverse)

    以3*3矩阵为例,逆矩阵的实现公式如下(Gauss-Jordan法求逆矩阵):

     

    21.6.1 函数arm_mat_inverse_f64

    函数原型:

    arm_status arm_mat_inverse_f64(

      const arm_matrix_instance_f64 * pSrc,

            arm_matrix_instance_f64 * pDst)

    函数描述:

    这个函数用于64bit浮点数的逆矩阵求解。

    函数参数:

    •   第1个参数是矩阵源地址。
    •   第2个参数是求逆后的矩阵地址。
    •  返回值,ARM_MATH_SUCCESS表示成功,ARM_MATH_SIZE_MISMATCH表示矩阵大小不一致。ARM_MATH_SINGULAR表示矩阵不可逆。

    注意事项:

    1. pSrc必须得是方阵(行数和列数相同)。
    2. pSrc和pDst必须是相同的方阵。
    3. 输入的矩阵可逆,函数会返回ARM_MATH_SUCCESS,如果不可逆,返回ARM_MATH_SINGULAR。
    4. ARM官方库只提供了浮点数矩阵求逆矩阵。

    21.6.2 函数arm_mat_inverse_f32

    函数原型:

    arm_status arm_mat_inverse_f32(

      const arm_matrix_instance_f32 * pSrc,

      arm_matrix_instance_f32 * pDst)

    函数描述:

    这个函数用于32bit浮点数的逆矩阵求解。

    函数参数:

    •   第1个参数是矩阵源地址。
    •   第2个参数是求逆后的矩阵地址。
    •   返回值,ARM_MATH_SUCCESS表示成功,ARM_MATH_SIZE_MISMATCH表示矩阵大小不一致。ARM_MATH_SINGULAR表示矩阵不可逆。

    注意事项:

    1. pSrc必须得是方阵(行数和列数相同)。
    2. pSrc和pDst必须是相同的方阵。
    3. 输入的矩阵可逆,函数会返回ARM_MATH_SUCCESS,如果不可逆,返回ARM_MATH_SINGULAR。
    4. ARM官方库只提供了浮点数矩阵求逆矩阵。   

    21.6.3        使用举例(含Matlab实现)

    程序设计:

    /*
    *********************************************************************************************************
    *    函 数 名: DSP_MatInverse
    *    功能说明: 求逆矩阵
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void DSP_MatInverse(void)
    {
        uint8_t i;
        
        arm_status sta;
        
        /****浮点数数组******************************************************************/
        float32_t pDataB[36];
        float32_t pDataA[36] = {
                    1.0f,   0.0f,   0.0f,  0.0f,  0.0f,  0.0f,
                    0.0f,   1.0f,   0.0f,  0.0f,  1.0f,  0.0f,
                    0.0f,   0.0f,   2.0f,  0.0f,  0.0f,  0.0f,
                    0.0f,   0.0f,   0.0f,  2.0f,  0.0f,  1.0f,
                    0.0f,   0.0f,   0.0f,  0.0f,  3.0f,  0.0f,
                    0.0f,   0.0f,   0.0f,  0.0f,  0.0f,  4.0f};
         
            
        arm_matrix_instance_f32 pSrcA; //6行6列数据
        arm_matrix_instance_f32 pSrcB; //6行6列数据;
    
        
        /****浮点数***********************************************************************/
        pSrcA.numCols = 6;
        pSrcA.numRows = 6;
        pSrcA.pData = pDataA;
        
        pSrcB.numCols = 6;
        pSrcB.numRows = 6;
        pSrcB.pData = pDataB;
        
        sta = arm_mat_inverse_f32(&pSrcA, &pSrcB);
    
        /*
            sta = ARM_MATH_SUCCESS, 即返回0,表示求逆矩阵成功。
            sta = ARM_MATH_SINGULAR, 即返回-5,表示求逆矩阵失败,也表示不可逆。
            注意,ARM提供的DSP库逆矩阵求发有局限性,通过Matlab验证是可以求逆矩阵的,而DSP库却不能正确求解。
            
        */
        printf("----sta %d
    ", sta);
        
        for(i = 0; i < 36; i++)
        {
            printf("pDataB[%d] = %f
    ", i, pDataB[i]);
        }    
    }

    实验现象(按下K3按键后串口打印逆矩阵):

     

    下面我们通过Matlab来实现求逆矩阵(在命令窗口输入):

     

    21.7 实验例程说明(MDK)

    配套例子:

    V7-216_DSP矩阵运算(加法,减法和逆矩阵)

    实验目的:

    1. 学习DSP复数运算(加法,减法和逆矩阵)

    实验内容:

    1. 启动一个自动重装软件定时器,每100ms翻转一次LED2。
    2. 按下按键K1,串口打函数DSP_MatInit的输出数据。
    3. 按下按键K2,串口打函数DSP_MatAdd的输出数据。
    4. 按下按键K3,串口打函数DSP_MatInverse的输出数据。
    5. 按下摇杆OK键,串口打函数DSP_MatSub的输出数据。

    使用AC6注意事项

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

    上电后串口打印的信息:

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

    详见本章的3.4 ,4.4,5.4和6.3小节。

    程序设计:

      系统栈大小分配:

     

      RAM空间用的DTCM:

     

      硬件外设初始化

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

    /*
    *********************************************************************************************************
    *    函 数 名: bsp_Init
    *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    *    形    参:无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void bsp_Init(void)
    {
        /* 配置MPU */
        MPU_Config();
        
        /* 使能L1 Cache */
        CPU_CACHE_Enable();
    
        /* 
           STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
           - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
           - 设置NVIV优先级分组为4。
         */
        HAL_Init();
    
        /* 
           配置系统时钟到400MHz
           - 切换使用HSE。
           - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
        */
        SystemClock_Config();
    
        /* 
           Event Recorder:
           - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
           - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
        */    
    #if Enable_EventRecorder == 1  
        /* 初始化EventRecorder并开启 */
        EventRecorderInitialize(EventRecordAll, 1U);
        EventRecorderStart();
    #endif
        
        bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
        bsp_InitTimer();      /* 初始化滴答定时器 */
        bsp_InitUart();    /* 初始化串口 */
        bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */    
        bsp_InitLed();        /* 初始化LED */    
    }

      MPU配置和Cache配置:

    数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM),FMC的扩展IO区。

    /*
    *********************************************************************************************************
    *    函 数 名: MPU_Config
    *    功能说明: 配置MPU
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void MPU_Config( void )
    {
        MPU_Region_InitTypeDef MPU_InitStruct;
    
        /* 禁止 MPU */
        HAL_MPU_Disable();
    
        /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
        MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
        MPU_InitStruct.BaseAddress      = 0x24000000;
        MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
        MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
        MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
        MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
        MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
        MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
        MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
        MPU_InitStruct.SubRegionDisable = 0x00;
        MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    
        HAL_MPU_ConfigRegion(&MPU_InitStruct);
        
        
        /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
        MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
        MPU_InitStruct.BaseAddress      = 0x60000000;
        MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;    
        MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
        MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
        MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;    
        MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
        MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
        MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
        MPU_InitStruct.SubRegionDisable = 0x00;
        MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
        
        HAL_MPU_ConfigRegion(&MPU_InitStruct);
    
        /*使能 MPU */
        HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    }
    
    /*
    *********************************************************************************************************
    *    函 数 名: CPU_CACHE_Enable
    *    功能说明: 使能L1 Cache
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void CPU_CACHE_Enable(void)
    {
        /* 使能 I-Cache */
        SCB_EnableICache();
    
        /* 使能 D-Cache */
        SCB_EnableDCache();
    }

      主功能:

    主程序实现如下操作:

    •   启动一个自动重装软件定时器,每100ms翻转一次LED2。
    •   按下按键K1,串口打函数DSP_MatInit的输出数据。
    •   按下按键K2,串口打函数DSP_MatAdd的输出数据。
    •   按下按键K3,串口打函数DSP_MatInverse的输出数据。
    •   按下摇杆OK键,串口打函数DSP_MatSub的输出数据。
    /*
    *********************************************************************************************************
    *    函 数 名: 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_MatInit的输出数据 */
                        DSP_MatInit();
                        break;
                        
                    case KEY_DOWN_K2:            /* 按下按键K2,串口打函数DSP_MatAdd的输出数据 */
                        DSP_MatAdd();
                        break;
    
                    case KEY_DOWN_K3:            /* 按下按键K3,串口打函数DSP_MatInverse的输出数据 */
                        DSP_MatInverse();
                        break;
                    
                    case JOY_DOWN_OK:          /* 按下摇杆OK键,串口打函数DSP_MatSub的输出数据 */
                        DSP_MatSub();
                        break;
    
                    default:
                        /* 其他的键值不处理 */
                        break;
                }
            }
        }
    }

    21.8 实验例程说明(IAR)

    配套例子:

    V7-216_DSP矩阵运算(加法,减法和逆矩阵)

    实验目的:

    1. 学习DSP复数运算(加法,减法和逆矩阵)

    实验内容:

    1. 启动一个自动重装软件定时器,每100ms翻转一次LED2。
    2. 按下按键K1,串口打函数DSP_MatInit的输出数据。
    3. 按下按键K2,串口打函数DSP_MatAdd的输出数据。
    4. 按下按键K3,串口打函数DSP_MatInverse的输出数据。
    5. 按下摇杆OK键,串口打函数DSP_MatSub的输出数据。

    使用AC6注意事项

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

    上电后串口打印的信息:

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

    详见本章的3.4 ,4.4,5.4和6.3小节。

    程序设计:

      系统栈大小分配:

     

      RAM空间用的DTCM:

     

      硬件外设初始化

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

    /*
    *********************************************************************************************************
    *    函 数 名: bsp_Init
    *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    *    形    参:无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void bsp_Init(void)
    {
        /* 配置MPU */
        MPU_Config();
        
        /* 使能L1 Cache */
        CPU_CACHE_Enable();
    
        /* 
           STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
           - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
           - 设置NVIV优先级分组为4。
         */
        HAL_Init();
    
        /* 
           配置系统时钟到400MHz
           - 切换使用HSE。
           - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
        */
        SystemClock_Config();
    
        /* 
           Event Recorder:
           - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
           - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
        */    
    #if Enable_EventRecorder == 1  
        /* 初始化EventRecorder并开启 */
        EventRecorderInitialize(EventRecordAll, 1U);
        EventRecorderStart();
    #endif
        
        bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
        bsp_InitTimer();      /* 初始化滴答定时器 */
        bsp_InitUart();    /* 初始化串口 */
        bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */    
        bsp_InitLed();        /* 初始化LED */    
    }

      MPU配置和Cache配置:

    数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM),FMC的扩展IO区。

    /*
    *********************************************************************************************************
    *    函 数 名: MPU_Config
    *    功能说明: 配置MPU
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void MPU_Config( void )
    {
        MPU_Region_InitTypeDef MPU_InitStruct;
    
        /* 禁止 MPU */
        HAL_MPU_Disable();
    
        /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
        MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
        MPU_InitStruct.BaseAddress      = 0x24000000;
        MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
        MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
        MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
        MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
        MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
        MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
        MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
        MPU_InitStruct.SubRegionDisable = 0x00;
        MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    
        HAL_MPU_ConfigRegion(&MPU_InitStruct);
        
        
        /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
        MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
        MPU_InitStruct.BaseAddress      = 0x60000000;
        MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;    
        MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
        MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
        MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;    
        MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
        MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
        MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
        MPU_InitStruct.SubRegionDisable = 0x00;
        MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
        
        HAL_MPU_ConfigRegion(&MPU_InitStruct);
    
        /*使能 MPU */
        HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    }
    
    /*
    *********************************************************************************************************
    *    函 数 名: CPU_CACHE_Enable
    *    功能说明: 使能L1 Cache
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void CPU_CACHE_Enable(void)
    {
        /* 使能 I-Cache */
        SCB_EnableICache();
    
        /* 使能 D-Cache */
        SCB_EnableDCache();
    }

      主功能:

    主程序实现如下操作:

    •   启动一个自动重装软件定时器,每100ms翻转一次LED2。
    •   按下按键K1,串口打函数DSP_MatInit的输出数据。
    •   按下按键K2,串口打函数DSP_MatAdd的输出数据。
    •   按下按键K3,串口打函数DSP_MatInverse的输出数据。
    •   按下摇杆OK键,串口打函数DSP_MatSub的输出数据。
    /*
    *********************************************************************************************************
    *    函 数 名: 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_MatInit的输出数据 */
                        DSP_MatInit();
                        break;
                        
                    case KEY_DOWN_K2:            /* 按下按键K2,串口打函数DSP_MatAdd的输出数据 */
                        DSP_MatAdd();
                        break;
    
                    case KEY_DOWN_K3:            /* 按下按键K3,串口打函数DSP_MatInverse的输出数据 */
                        DSP_MatInverse();
                        break;
                    
                    case JOY_DOWN_OK:          /* 按下摇杆OK键,串口打函数DSP_MatSub的输出数据 */
                        DSP_MatSub();
                        break;
    
                    default:
                        /* 其他的键值不处理 */
                        break;
                }
            }
        }
    }

    21.9 总结

    本期教程就跟大家讲这么多,有兴趣的可以深入研究下算法的具体实现。

  • 相关阅读:
    Spring MVC 核心组件详解
    Spring MVC 入门就这一篇
    Spring 事务解决方案
    【UGUI源码分析】Unity遮罩之Mask详细解读
    游戏开发中不同时区下的时间问题
    ARTS第十三周(阅读Tomcat源码)
    Win10 电脑安装.NET低版本提示“这台计算机中已经安装了 .NET Framwork 4.6.2或版本更高的更新”问题
    Dynamics 365 Setup 提示SqlServer 存在
    Dynamics CRM "Verification of prerequisites for Domain Controller promotion failed. Certificate Server is installed."
    Dynamics CRM
  • 原文地址:https://www.cnblogs.com/armfly/p/12870249.html
Copyright © 2011-2022 走看看