【STM32H7的DSP教程】第20章 DSP複數運算-模平方,乘法和複數乘實數

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

第20章       DSP複數運算-模平方,乘法和複數乘實數

本期教程主要講解複數運算中的模平方,乘法和複數乘實數。

目錄

第20章       DSP複數運算-模平方,乘法和複數乘實數

20.1 初學者重要提示

20.2 DSP基礎運算指令

20.3 複數模平方(ComplexMagSquared)

20.3.1        函數arm_cmplx_mag_squared_f32

20.3.2        函數arm_cmplx_mag_squared_q31

20.3.3        函數arm_cmplx_mag_squared_q15

20.3.4        使用舉例

20.4 複數乘法 (ComplexMultComplex)

20.4.1        函數arm_cmplx_mult_cmplx_f32

20.4.2        函數arm_cmplx_mult_cmplx_q31

20.4.3        函數arm_cmplx_mult_cmplx_q15

20.4.4        使用舉例

20.5 複數乘實數(ComplexMultReal)

20.5.1 函數arm_cmplx_mult_real_f32

20.5.2 函數arm_cmplx_mult_real_q31

20.5.3 函數arm_cmplx_mult_real_q15

20.5.4        使用舉例

20.6 實驗例程說明(MDK)

20.7 實驗例程說明(IAR)

20.8 總結


 

20.1 初學者重要提示

  1.   複數運算比較重要,後面FFT章節要用到,如果印象不深的話,需要溫習下高數知識了。

20.2 DSP基礎運算指令

本章用到的DSP指令在前面章節都已經講解過。

20.3 複數模平方(ComplexMagSquared)

這部分函數用於複數求模平方,公式描述如下:

for(n=0; n<numSamples; n++) {       

   pDst[n] = pSrc[(2*n)+0]^2 + pSrc[(2*n)+1]^2;       

}  

用代數式來表示模平方:

a+bi模平方 = a2 + b2 。

20.3.1        函數arm_cmplx_mag_squared_f32

函數原型:

void arm_cmplx_mag_f32(

  const float32_t * pSrc,

        float32_t * pDst,

        uint32_t numSamples)

函數描述:

這個函數用於浮點數類型的複數求模平方。

函數參數:

  •   第1個參數是源數據地址。
  •   第2個參數是求模平方後的數據地址。
  •   第3個參數是要求解的複數個數。

注意事項:

數組pSrc中存儲的數據格式是(實部,虛部,實部,虛部……………),一定要按照這個順序存儲數據,比如數據1-j,j,2+3j這個三個數在數組中的存儲格式就是:pSrc[6] = {1, -1, 0, 1, 2, 3}(注意第三個數據是0)。而模值的結果存到pDst裏面。

20.3.2        函數arm_cmplx_mag_squared_q31

函數原型:

void arm_cmplx_mag_squared_q31(

  const q31_t * pSrc,

        q31_t * pDst,

        uint32_t numSamples)

函數描述:

這個函數用於定點數Q31類型的複數求模平方。

函數參數:

  •   第1個參數是源數據地址。
  •   第2個參數是求模平方後的數據地址。
  •   第3個參數是要求解的複數個數。

注意事項:

  1. 兩個1.31格式的定點數相乘爲2.62,程序中將此結果做了放縮,此函數的最終結果轉換後爲3.29。
  2. 數組pSrc中存儲的數據格式是(實部,虛部,實部,虛部……………),一定要按照這個順序存儲數據,比如數據1-j,j,2+3j這個三個數在數組中的存儲格式就是:pSrc[6] = {1, -1, 0, 1, 2, 3}(注意第三個數據是0)。而模值的結果存到pDst裏面。

20.3.3        函數arm_cmplx_mag_squared_q15

函數原型:

void arm_cmplx_mag_squared_q15(

  const q15_t * pSrc,

        q15_t * pDst,

        uint32_t numSamples)

函數描述:

這個函數用於定點數Q15類型的複數求模平方。

函數參數:

  •   第1個參數是源數據地址。
  •   第2個參數是求模平方後的數據地址。
  •   第3個參數是要求解的複數個數。

注意事項:

  1. 兩個1.15格式的定點數相乘爲2.30,程序中將此結果做了放縮,此函數的最終結果轉換後爲3.13。
  2. 數組pSrc中存儲的數據格式是(實部,虛部,實部,虛部……………),一定要按照這個順序存儲數據,比如數據1-j,j,2+3j這個三個數在數組中的存儲格式就是:pSrc[6] = {1, -1, 0, 1, 2, 3}(注意第三個數據是0)。而模值的結果存到pDst裏面。

20.3.4        使用舉例

程序設計:

/*
*********************************************************************************************************
*    函 數 名: DSP_MagSquared
*    功能說明: 複數模的平方
*    形    參:無
*    返 回 值: 無
*********************************************************************************************************
*/
static void DSP_MagSquared(void)
{
    uint8_t i;
    float32_t pSrc[10] = {1.1f, 1.1f, 2.1f, 2.1f, 3.1f, 3.1f, 4.1f, 4.1f, 5.1f, 5.1f};
    float32_t pDst[10];
    
    q31_t pSrc1[10] = {1*268435456, 1*268435456, 2*268435456, 2*268435456, 3*268435456, 3*268435456, 
                        4*268435456, 4*268435456, 5*268435456, 5*268435456};
    q31_t pDst1[10];

    q15_t pSrc2[10] = {5000, 10000, 15000, 20000, 25000,  5000, 10000, 15000, 20000, 25000};
    q15_t pDst2[10];
    
    /***浮點數模平方*******************************************************************************/
    arm_cmplx_mag_squared_f32(pSrc, pDst, 5);
    for(i = 0; i < 5; i++)
    {
        printf("pDst[%d] = %f\r\n", i, pDst[i]);
    }
    
    /***定點數模平方Q31*******************************************************************************/
    arm_cmplx_mag_squared_q31(pSrc1, pDst1, 5);
    for(i = 0; i < 5; i++)
    {
        printf("pDst1[%d] = %d\r\n", i, pDst1[i]);
    }
    
    /***定點數模平方Q15*******************************************************************************/
    arm_cmplx_mag_squared_q15(pSrc2, pDst2, 5);
    for(i = 0; i < 5; i++)
    {
        printf("pDst2[%d] = %d\r\n", i, pDst2[i]);
    }
}

/*
*********************************************************************************************************
*    函 數 名: 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("****浮點數******************************************\r\n");
    arm_mat_init_f32(&pSrcA, 3,3, pDataA);
    for(i = 0; i < 9; i++)
    {
        printf("pDataA[%d] = %f\r\n", i, pDataA[i]);
    }
    
    /****定點數Q31***********************************************************************/
    printf("****浮點數******************************************\r\n");
    arm_mat_init_q31(&pSrcA1, 3,3, pDataA1);
    for(i = 0; i < 9; i++)
    {
        printf("pDataA1[%d] = %d\r\n", i, pDataA1[i]);
    }
    
    /****定點數Q15***********************************************************************/
    printf("****浮點數******************************************\r\n");
    arm_mat_init_q15(&pSrcA2, 3,3, pDataA2);
    for(i = 0; i < 9; i++)
    {
        printf("pDataA2[%d] = %d\r\n", i, pDataA2[i]);
    }
}

 

實驗現象(按下K1按鍵後串口打印模平方):

20.4 複數乘法 (ComplexMultComplex)

這部分函數用於複數乘複數,公式描述如下:

for (n = 0; n < numSamples; n++) {

    pDst[(2*n)+0] = pSrcA[(2*n)+0] * pSrcB[(2*n)+0] - pSrcA[(2*n)+1] * pSrcB[(2*n)+1];

    pDst[(2*n)+1] = pSrcA[(2*n)+0] * pSrcB[(2*n)+1] + pSrcA[(2*n)+1] * pSrcB[(2*n)+0];

}  

用代數式來表示複數乘法:

(a+bi)*(c+di)=(ac -bd)+(ad+bc)i。

20.4.1        函數arm_cmplx_mult_cmplx_f32

函數原型:

void arm_cmplx_mult_cmplx_f32(

  const float32_t * pSrcA,

  const float32_t * pSrcB,

        float32_t * pDst,

        uint32_t numSamples)

函數描述:

這個函數用於浮點數的複數乘復位。

函數參數:

  •   第1個參數是源數據A的地址。
  •   第2個參數是源數據B的地址。
  •   第3個參數是存儲數組A和數組B乘積地址。
  •   第4個參數是要求解的複數個數。

注意事項:

數組pSrcA, pSrcB和pDst中存儲的數據格式是(實部,虛部,實部,虛部……………),源數據A和B一定要按照這個順序存儲數據,比如數據1-j,j,2+3j這個三個數在數組中的存儲格式就是:pSrc[6] = {1, -1, 0, 1, 2, 3}(注意第三個數據是0)。而乘積的結果存到pDst裏面。

20.4.2        函數arm_cmplx_mult_cmplx_q31

函數原型:

void arm_cmplx_mult_cmplx_q31(

  const q31_t * pSrcA,

  const q31_t * pSrcB,

        q31_t * pDst,

        uint32_t numSamples)

函數描述:

這個函數用於Q31格式定點數的複數乘複數。

函數參數:

  •   第1個參數是源數據A的地址。
  •   第2個參數是源數據B的地址。
  •   第3個參數是存儲數組A和數組B乘積地址。
  •   第4個參數是要求解的複數個數。

注意事項:

  1. 兩個1.31格式的定點數相乘爲2.62,程序中將此結果做了放縮,此函數的最終結果轉換後爲3.29。
  2. 數組pSrcA, pSrcB和pDst中存儲的數據格式是(實部,虛部,實部,虛部……………),源數據A和B一定要按照這個順序存儲數據,比如數據1-j,j,2+3j這個三個數在數組中的存儲格式就是:pSrc[6] = {1, -1, 0, 1, 2, 3}(注意第三個數據是0)。而乘積的結果存到pDst裏面。

 

20.4.3        函數arm_cmplx_mult_cmplx_q15

函數原型:

void arm_cmplx_mult_cmplx_f32(

  const float32_t * pSrcA,

  const float32_t * pSrcB,

        float32_t * pDst,

        uint32_t numSamples)

函數描述:

這個函數用於Q15格式定點數的複數乘複數。

函數參數:

  •   第1個參數是源數據A的地址。
  •   第2個參數是源數據B的地址。
  •   第3個參數是存儲數組A和數組B乘積地址。
  •   第4個參數是要求解的複數個數。

注意事項:

  1. 兩個1.15格式的定點數相乘爲2.30,程序中將此結果做了放縮,此函數的最終結果轉換後爲3.13。
  2. 數組pSrcA, pSrcB和pDst中存儲的數據格式是(實部,虛部,實部,虛部……………),源數據A和B一定要按照這個順序存儲數據,比如數據1-j,j,2+3j這個三個數在數組中的存儲格式就是:pSrc[6] = {1, -1, 0, 1, 2, 3}(注意第三個數據是0)。而乘積的結果存到pDst裏面。

20.4.4        使用舉例

程序設計:

/*
*********************************************************************************************************
*    函 數 名: DSP_CmplxMult
*    功能說明: 複數乘法
*    形    參:無
*    返 回 值: 無
*********************************************************************************************************
*/
static void DSP_CmplxMult(void)
{
    uint8_t i;
    float32_t pSrcA[10] = {1.1f, 1.2f, 2.1f, 2.2f, 3.1f, 3.2f, 4.1f, 4.2f, 5.1f, 5.2f};
    float32_t pSrcB[10] = {1.2f, 1.2f, 2.2f, 2.2f, 3.2f, 3.2f, 4.2f, 4.2f, 5.2f, 5.2f};
    float32_t pDst[10];
    
    q31_t pSrcA1[10] = {1*268435456, 1*268435456, 2*268435456, 2*268435456, 3*268435456, 3*268435456, 
                        4*268435456, 4*268435456, 5*268435456, 5*268435456};
    q31_t pSrcB1[10] = {1*268435456, 1*268435456, 2*268435456, 2*268435456, 3*268435456, 3*268435456, 
                        4*268435456, 4*268435456, 5*268435456, 5*268435456};
    q31_t pDst1[10];
    
    q15_t pSrcA2[10] = {5000, 10000, 15000, 20000, 25000,  5000, 10000, 15000, 20000, 25000};
    q15_t pSrcB2[10] = {6000, 11000, 15000, 20000, 25000,  5000, 10000, 15000, 20000, 25000};
    q15_t pDst2[10];
    
    /***浮點數乘法*******************************************************************************/
    arm_cmplx_mult_cmplx_f32(pSrcA, pSrcB, pDst, 5);
    for(i = 0; i < 5; i++)
    {
        printf("pDst[%d] = %f %fj\r\n", i, pDst[2*i], pDst[2*i+1]);
    }
    
    /***定點數乘法Q31*******************************************************************************/
    arm_cmplx_mult_cmplx_q31(pSrcA1, pSrcB1, pDst1, 5);
    for(i = 0; i < 5; i++)
    {
        printf("pDst1[%d] = %d %dj\r\n", i, pDst1[2*i], pDst1[2*i+1]);
    }
    
    /***定點數乘法Q15*******************************************************************************/
    arm_cmplx_mult_cmplx_q15(pSrcA2, pSrcB2, pDst2, 5);
    for(i = 0; i < 5; i++)
    {
        printf("pDst1[%d] = %d %dj\r\n", i, pDst2[2*i], pDst2[2*i+1]);
    }
}

 

實驗現象(按下K2按鍵後串口打印複數乘法):

20.5 複數乘實數(ComplexMultReal)

這部分函數用於複數乘實數,公式描述如下:

for(n=0; n<numSamples; n++) {       

 pCmplxDst[(2*n)+0] = pSrcCmplx[(2*n)+0] * pSrcReal[n];       

pCmplxDst[(2*n)+1] = pSrcCmplx[(2*n)+1] * pSrcReal[n];       

 }   

用代數式來表示複數乘法:

a*(c+di)=ac+adi。

20.5.1 函數arm_cmplx_mult_real_f32

函數原型:

void arm_cmplx_mult_real_f32(

  const float32_t * pSrcCmplx,

  const float32_t * pSrcReal,

        float32_t * pCmplxDst,

        uint32_t numSamples)

函數描述:

這個函數用於浮點數的複數乘實數。

函數參數:

  •   第1個參數是複數的源地址。
  •   第2個參數是實數的源地址。
  •   第3個參數是複數和實數乘積地址。
  •   第4個參數是要進行復數乘實數的個數。

注意事項:

  1. 數組pSrcCmplx和pCmplxDst中存儲的數據格式是(實部,虛部,實部,虛部……………),源數據pSrcCmplx一定要按照這個順序存儲數據,比如數據1-j,j,2+3j這個三個數在數組中的存儲格式就是:pSrc[6] = {1, -1, 0, 1, 2, 3}(注意第三個數據是0)。而乘積的結果存到pCmplxDst裏面。

20.5.2 函數arm_cmplx_mult_real_q31

函數原型:

void arm_cmplx_mult_real_q31(

  const q31_t * pSrcCmplx,

  const q31_t * pSrcReal,

        q31_t * pCmplxDst,

        uint32_t numSamples)

函數描述:

這個函數用於Q31格式定點數的複數乘實數。

函數參數:

  •   第1個參數是複數的源地址。
  •   第2個參數是實數的源地址。
  •   第3個參數是複數和實數乘積地址。
  •   第4個參數是要進行復數乘實數的個數。

注意事項:

  1. 輸出結果做了飽和運算,輸出範圍[0x80000000 0x7FFFFFFF]。
  2. 數組pSrcCmplx和pCmplxDst中存儲的數據格式是(實部,虛部,實部,虛部……………),源數據pSrcCmplx一定要按照這個順序存儲數據,比如數據1-j,j,2+3j這個三個數在數組中的存儲格式就是:pSrc[6] = {1, -1, 0, 1, 2, 3}(注意第三個數據是0)。而乘積的結果存到pCmplxDst裏面。

20.5.3 函數arm_cmplx_mult_real_q15

函數原型:

void arm_cmplx_mult_real_q15(

  const q15_t * pSrcCmplx,

  const q15_t * pSrcReal,

        q15_t * pCmplxDst,

        uint32_t numSamples)

函數描述:

這個函數用於Q15格式定點數的複數乘實數。

函數參數:

  •   第1個參數是複數的源地址。
  •   第2個參數是實數的源地址。
  •   第3個參數是複數和實數乘積地址。
  •   第4個參數是要進行復數乘實數的個數。

注意事項:

  1. 輸出結果做了飽和運算,輸出範圍[0x8000 0x7FFF]。
  2. 數組pSrcCmplx和pCmplxDst中存儲的數據格式是(實部,虛部,實部,虛部……………),源數據pSrcCmplx一定要按照這個順序存儲數據,比如數據1-j,j,2+3j這個三個數在數組中的存儲格式就是:pSrc[6] = {1, -1, 0, 1, 2, 3}(注意第三個數據是0)。而乘積的結果存到pCmplxDst裏面。

20.5.4        使用舉例

程序設計:

/*
*********************************************************************************************************
*    函 數 名: DSP_CmplxMultReal
*    功能說明: 複數乘實數
*    形    參:無
*    返 回 值: 無
*********************************************************************************************************
*/
static void DSP_CmplxMultReal(void)
{
    uint8_t i;
    float32_t pSrcCmplx[10] = {1.1f, 1.2f, 2.1f, 2.2f, 3.1f, 3.2f, 4.1f, 4.2f, 5.1f, 5.2f};
    float32_t pSrcReal[5] = {1.2f, 1.2f, 2.2f, 2.2f, 3.2f};
    float32_t pCmplxDst[10];
    
    q31_t pSrcCmplx1[10] = {1*268435456, 1*268435456, 2*268435456, 2*268435456, 3*268435456, 3*268435456, 
                        4*268435456, 4*268435456, 5*268435456, 5*268435456};
                        
    q31_t pSrcReal1[10] = {1*268435456, 1*268435456, 2*268435456, 2*268435456, 3*268435456};
    q31_t pCmplxDst1[10];
    
    q15_t pSrcCmplx2[10] = {14000, 16000, 20000, 20000, 30000, 31000, 12000, 13000, 14000, 25000};
    q15_t pSrcReal2[10] =  {15000, 17000, 20000, 20000, 30000};
    q15_t pCmplxDst2[10];
    
    /***浮點數*******************************************************************************/
    arm_cmplx_mult_cmplx_f32(pSrcCmplx, pSrcReal, pCmplxDst, 5);
    for(i = 0; i < 5; i++)
    {
        printf("pCmplxDst[%d] = %f %fj\r\n", i, pCmplxDst[2*i], pCmplxDst[2*i+1]);
    }
    
    /***定點數Q31*******************************************************************************/
    arm_cmplx_mult_cmplx_q31(pSrcCmplx1, pSrcReal1, pCmplxDst1, 5);
    for(i = 0; i < 5; i++)
    {
        printf("pCmplxDst1[%d] = %d %dj\r\n", i, pCmplxDst1[2*i], pCmplxDst1[2*i+1]);
    }
    
    /***定點數Q15*******************************************************************************/
    arm_cmplx_mult_cmplx_q15(pSrcCmplx2, pSrcReal2, pCmplxDst2, 5);
    for(i = 0; i < 5; i++)
    {
        printf("pCmplxDst2[%d] = %d %dj\r\n", i, pCmplxDst2[2*i], pCmplxDst2[2*i+1]);
    }
}

 

實驗現象(按下K3按鍵後串口打印實數乘複數):

20.6 實驗例程說明(MDK)

配套例子:

V7-215_DSP複數運算(模平方,複數乘複數和複數乘實數)

實驗目的:

  1. 學習DSP複數運算(模平方,複數乘複數和複數乘實數)

實驗內容:

  1. 啓動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
  2. 按下按鍵K1,串口打函數DSP_MagSquared的輸出數據。
  3. 按下按鍵K2,串口打函數DSP_CmplxMult的輸出數據。
  4. 按下按鍵K3,串口打函數DSP_CmplxMultReal的輸出數據。

使用AC6注意事項

特別注意附件章節C的問題

上電後串口打印的信息:

波特率 115200,數據位 8,奇偶校驗位無,停止位 1。

詳見本章的3.4  4.4,5.4小節。

程序設計:

  系統棧大小分配:

  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_MagSquared的輸出數據。
  •   按下按鍵K2,串口打函數DSP_CmplxMult的輸出數據。
  •   按下按鍵K3,串口打函數DSP_CmplxMultReal的輸出數據。
/*
*********************************************************************************************************
*    函 數 名: 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_MagSquared();
                    break;
                    
                case KEY_DOWN_K2:            /* K2鍵按下,求複數乘複數 */
                    DSP_CmplxMult();
                    break;

                case KEY_DOWN_K3:            /* K3鍵按下,求複數乘實數 */
                    DSP_CmplxMultReal();
                    break;

                default:
                    /* 其他的鍵值不處理 */
                    break;
            }
        }
    }
}

 

20.7 實驗例程說明(IAR)

配套例子:

V7-215_DSP複數運算(模平方,複數乘複數和複數乘實數)

實驗目的:

  1. 學習DSP複數運算(模平方,複數乘複數和複數乘實數)

實驗內容:

  1. 啓動一個自動重裝軟件定時器,每100ms翻轉一次LED2。
  2. 按下按鍵K1,串口打函數DSP_MagSquared的輸出數據。
  3. 按下按鍵K2,串口打函數DSP_CmplxMult的輸出數據。
  4. 按下按鍵K3,串口打函數DSP_CmplxMultReal的輸出數據。

上電後串口打印的信息:

波特率 115200,數據位 8,奇偶校驗位無,停止位 1。

詳見本章的3.4  4.4,5.4小節。

程序設計:

  系統棧大小分配:

  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_MagSquared的輸出數據。
  •   按下按鍵K2,串口打函數DSP_CmplxMult的輸出數據。
  •   按下按鍵K3,串口打函數DSP_CmplxMultReal的輸出數據。
/*
*********************************************************************************************************
*    函 數 名: 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_MagSquared();
                    break;
                    
                case KEY_DOWN_K2:            /* K2鍵按下,求複數乘複數 */
                    DSP_CmplxMult();
                    break;

                case KEY_DOWN_K3:            /* K3鍵按下,求複數乘實數 */
                    DSP_CmplxMultReal();
                    break;

                default:
                    /* 其他的鍵值不處理 */
                    break;
            }
        }
    }
}

 

20.8 總結

本期教程就跟大家講這麼多,有興趣的可以深入研究下算法的具體實現。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章