更换为新的 MCU 后,DSP 低通滤波器 (IIR) 不再工作

信息处理 过滤器 模数 数模
2022-02-21 07:56:10

很难理解为什么 DSP 低通滤波器在 M4 上工作不再在 M7 上工作。

我最近从STM32L432KC切换到STM32H753ZI

除了从 L4 切换到 H7 之外,我还在使用P2MODI2S2和 H7,而不是像使用 L4 时那样使用内部 ADC。

唯一想到的是采样率的差异。我在 L4 上使用 44.410kHz 采样率,现在我在使用 PMODI2S2 的 H7 上使用 96kHz 采样率。所以我重新做了离散函数并输入了新的 IIR 系数并且没有雪茄。

使用带有 PMODI2S2 的 H7 作为直通:

在此处输入图像描述

代码:

#define ARM_MATH_CM7

#include "main.h"

#include "arm_math.h"


void init_Clock(void);
void init_I2S(void);
void init_Debugging(void);
void init_Interrupt(void);
void init_SpeedTest(void);

uint32_t RxBuff[4];
uint32_t TxBuff[4];
uint8_t TC_Callback = 0;
uint8_t HC_Callback = 0;

char uartBuff[8];

float iir_coeffs[5] = {0.00102, 0.002041, 0.00102, 1.908, -0.9116}; //B0, B1, B2, A1, A2
float iir_mono_state[4];

float Rx_Buff_f[8];
float Rx_Buff_f_out[8];


arm_biquad_casd_df1_inst_f32 monoChannel;


void DMA1_Stream0_IRQHandler(void) {

    if (((DMA1 -> LISR) & (DMA_LISR_TCIF0)) != 0){
        DMA1 -> LIFCR |= DMA_LIFCR_CTCIF0;
        TC_Callback = 1;
    }

    else if (((DMA1 -> LISR) & (DMA_LISR_HTIF0)) != 0){
         DMA1 -> LIFCR |= DMA_LIFCR_CHTIF0;
         HC_Callback = 1;

    }
}

int main(void) {

    init_Clock();
    init_I2S();
    //init_Debugging();
    init_Interrupt();
    //init_SpeedTest();
    arm_biquad_cascade_df1_init_f32(&monoChannel, 1, iir_coeffs, iir_mono_state);

  while (1)
  {

      if (HC_Callback == 1){

         // GPIOA->BSRR |= GPIO_BSRR_BS3_HIGH;

         

          for (int i = 0; i < 2; i++){
                TxBuff[i] = RxBuff[i];
            }

          HC_Callback = 0;

      } else  if (TC_Callback == 1){


        //  GPIOA->BSRR |= GPIO_BSRR_BR3_LOW;



                  for (int i = 2; i < 4; i++){
                        TxBuff[i] =  RxBuff[i];
                    }



          TC_Callback = 0;

      }



  }

}

H7 与 PMODI2S2 与 IIR 系数使用 96kHz 采样率:

在此处输入图像描述

代码:

#define ARM_MATH_CM7

#include "main.h"

#include "arm_math.h"


void init_Clock(void);
void init_I2S(void);
void init_Debugging(void);
void init_Interrupt(void);
void init_SpeedTest(void);

uint32_t RxBuff[4];
uint32_t TxBuff[4];
uint8_t TC_Callback = 0;
uint8_t HC_Callback = 0;

char uartBuff[8];

float iir_coeffs[5] = {0.00102, 0.002041, 0.00102, 1.908, -0.9116}; //B0, B1, B2, A1, A2
float iir_mono_state[4];

float Rx_Buff_f[8];
float Rx_Buff_f_out[8];


arm_biquad_casd_df1_inst_f32 monoChannel;


void DMA1_Stream0_IRQHandler(void) {

    if (((DMA1 -> LISR) & (DMA_LISR_TCIF0)) != 0){
        DMA1 -> LIFCR |= DMA_LIFCR_CTCIF0;
        TC_Callback = 1;
    }

    else if (((DMA1 -> LISR) & (DMA_LISR_HTIF0)) != 0){
         DMA1 -> LIFCR |= DMA_LIFCR_CHTIF0;
         HC_Callback = 1;

    }
}

int main(void) {

    init_Clock();
    init_I2S();
    //init_Debugging();
    init_Interrupt();
    //init_SpeedTest();
    arm_biquad_cascade_df1_init_f32(&monoChannel, 1, iir_coeffs, iir_mono_state);

  while (1)
  {

      if (HC_Callback == 1){

         // GPIOA->BSRR |= GPIO_BSRR_BS3_HIGH;

          for (int i = 0; i < 2; i++){
              Rx_Buff_f[i] = (float)RxBuff[i];
          }

          arm_biquad_cascade_df1_f32(&monoChannel, Rx_Buff_f, Rx_Buff_f_out, 2);

          for (int i = 0; i < 2; i++){
                TxBuff[i] = (uint32_t)Rx_Buff_f_out[i];
            }

          HC_Callback = 0;

      } else  if (TC_Callback == 1){


        //  GPIOA->BSRR |= GPIO_BSRR_BR3_LOW;


          for (int i = 2; i < 4; i++){
               Rx_Buff_f[i] = (float)RxBuff[i];
            }

                  arm_biquad_cascade_df1_f32(&monoChannel, &Rx_Buff_f[2], &Rx_Buff_f_out[2], 2);

                  for (int i = 2; i < 4; i++){
                        TxBuff[i] =  (uint32_t)Rx_Buff_f_out[i];
                    }



          TC_Callback = 0;

      }



  }

}

所以我心想,因为我使用的是 I2S 协议,并且由于它的立体声,我尝试使用 192kHz 的采样率来看看会发生什么:

在此处输入图像描述

代码:

#define ARM_MATH_CM7

#include "main.h"

#include "arm_math.h"


void init_Clock(void);
void init_I2S(void);
void init_Debugging(void);
void init_Interrupt(void);
void init_SpeedTest(void);

uint32_t RxBuff[4];
uint32_t TxBuff[4];
uint8_t TC_Callback = 0;
uint8_t HC_Callback = 0;

char uartBuff[8];

float iir_coeffs[5] = {0.0002507, 0.0005013, 0.0002507, 1.955, -0.9557}; //B0, B1, B2, A1, A2
float iir_mono_state[4];

float Rx_Buff_f[8];
float Rx_Buff_f_out[8];


arm_biquad_casd_df1_inst_f32 monoChannel;


void DMA1_Stream0_IRQHandler(void) {

    if (((DMA1 -> LISR) & (DMA_LISR_TCIF0)) != 0){
        DMA1 -> LIFCR |= DMA_LIFCR_CTCIF0;
        TC_Callback = 1;
    }

    else if (((DMA1 -> LISR) & (DMA_LISR_HTIF0)) != 0){
         DMA1 -> LIFCR |= DMA_LIFCR_CHTIF0;
         HC_Callback = 1;

    }
}

int main(void) {

    init_Clock();
    init_I2S();
    //init_Debugging();
    init_Interrupt();
    //init_SpeedTest();
    arm_biquad_cascade_df1_init_f32(&monoChannel, 1, iir_coeffs, iir_mono_state);

  while (1)
  {

      if (HC_Callback == 1){

         // GPIOA->BSRR |= GPIO_BSRR_BS3_HIGH;

          for (int i = 0; i < 2; i++){
              Rx_Buff_f[i] = (float)RxBuff[i];
          }

          arm_biquad_cascade_df1_f32(&monoChannel, Rx_Buff_f, Rx_Buff_f_out, 2);

          for (int i = 0; i < 2; i++){
                TxBuff[i] = (uint32_t)Rx_Buff_f_out[i];
            }

          HC_Callback = 0;

      } else  if (TC_Callback == 1){


        //  GPIOA->BSRR |= GPIO_BSRR_BR3_LOW;


          for (int i = 2; i < 4; i++){
               Rx_Buff_f[i] = (float)RxBuff[i];
            }

                  arm_biquad_cascade_df1_f32(&monoChannel, &Rx_Buff_f[2], &Rx_Buff_f_out[2], 2);

                  for (int i = 2; i < 4; i++){
                        TxBuff[i] =  (uint32_t)Rx_Buff_f_out[i];
                    }



          TC_Callback = 0;

      }



  }

}

有任何想法吗?我不确定它是 M7 还是有问题的外围设备。这是在L4上工作的,没问题。

更新 1:我在调试器模式下记录了变量以查看发生了什么。我拍了三张照片。第一次迭代是索引 0-2,第二次迭代是 2-4,第三张图片是之后的多次迭代。

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

我注意到的是 RxBuffer 和 RxBuffer_f 不同步。我还注意到,经过多次迭代,RxBuffer_f_out 只是变成了类似 int 的数据类型,不再包含任何类型的小数。

更新 2:

我还注意到我正在使用一个 I2S 设备来输出立体声音频,我可能没有将系数正确地添加到缓冲区中。我的意思是,当缓冲区进入时,我是否需要调整缓冲区,比如对它们进行位移或任何类似的事情?关于 PMODI2S2,我唯一知道的是,我相信它会在 32 个数据帧中输出 24 位,所以我假设它用零填充,为什么不填充。

更新 3:

在放入 TxBuffer 之前只是将 RxBuffer 相乘,它所做的是增加信号的 PK - PK,但是增加它更多会导致:

将 RxBuffer 乘以 2^0(直通)

在此处输入图像描述

将 RxBuffer 乘以 2^1

在此处输入图像描述

将 RxBuffer 乘以 2^2

在此处输入图像描述

最后一张图片看起来像我遇到的问题,这可能是溢出问题吗?

更新 4:

在与一位关心的公民交谈时,他提到 I2S 协议是一个 2 的补码数据编码。我知道 2 的补码是什么,但我不确定 TxBuff 或 Rxbuff 是否需要补码。无论如何,我将 TxBuff 和 Rxbuff 的数据类型都更改为 int32_t 数据类型,但问题仍然存在。

更新 5:尝试使用 2 的补码或只是将其转换为 int32_t。没运气。

代码:

#define ARM_MATH_CM7

#include "main.h"

#include "arm_math.h"


void init_Clock(void);
void init_I2S(void);
void init_Debugging(void);
void init_Interrupt(void);
void init_SpeedTest(void);

int32_t RxBuff[4];
int32_t TxBuff[4];
uint8_t TC_Callback = 0;
uint8_t HC_Callback = 0;

char uartBuff[8];
 float32_t iir_coeffs[5] = {0.00102, 0.002041, 0.00102, 1.908, -0.9116}; //B0, B1, B2, A1, A2
float32_t iir_mono_state[4];

float32_t Rx_Buff_f[4];
float32_t Rx_Buff_f_out[4];


arm_biquad_casd_df1_inst_f32 monoChannel;


void DMA1_Stream0_IRQHandler(void) {

    if (((DMA1 -> LISR) & (DMA_LISR_TCIF0)) != 0){
        DMA1 -> LIFCR |= DMA_LIFCR_CTCIF0;
        TC_Callback = 1;
    }

    else if (((DMA1 -> LISR) & (DMA_LISR_HTIF0)) != 0){
         DMA1 -> LIFCR |= DMA_LIFCR_CHTIF0;
         HC_Callback = 1;

    }
}

int main(void) {

    init_Clock();
    init_I2S();
    //init_Debugging();
    init_Interrupt();
    //init_SpeedTest();
    arm_biquad_cascade_df1_init_f32(&monoChannel, 1, iir_coeffs, iir_mono_state);

  while (1)
  {

      if (HC_Callback == 1){

         // GPIOA->BSRR |= GPIO_BSRR_BS3_HIGH;

          for (int i = 0; i < 2; i++){
              Rx_Buff_f[i] = (float32_t)RxBuff[i];
          }

          arm_biquad_cascade_df1_f32(&monoChannel, Rx_Buff_f, Rx_Buff_f_out, 2);

          for (int i = 0; i < 2; i++){
                TxBuff[i] = Rx_Buff_f_out[i];
            }

          HC_Callback = 0;

      } else  if (TC_Callback == 1){


        //  GPIOA->BSRR |= GPIO_BSRR_BR3_LOW;


          for (int i = 2; i < 4; i++){
               Rx_Buff_f[i] = (float32_t)RxBuff[i];
            }

                  arm_biquad_cascade_df1_f32(&monoChannel, &Rx_Buff_f[2], &Rx_Buff_f_out[2], 2);

                  for (int i = 2; i < 4; i++){
                        TxBuff[i] =  Rx_Buff_f_out[i];
                    }



          TC_Callback = 0;

      }



  }

}
2个回答

I2S 音频样本是带符号的二进制补码。只需添加2N1, 在哪里N是位数,结果,and二进制2N1, 得到范围02N1,我认为您曾经从内置的模数转换器 (ADC) 中获得。对您接收的数据和使用 I2S 传输的数据执行此操作。您可以稍微优化计算并将加法和二进制组合and一个二进制xor2N1.

或者开始使用签名号码。如果 24 位数据在 32 位字中没有左对齐,则需要 A) 扩展符号位或 B) 将接收到的数据左移并右移要传输的数据。

您应该查阅 ADC 和 DAC 数据表以确认数据是如何对齐的,如果可以配置,那么您已经在处理器和外设中正确配置了它。在 I2S 中,应在字选择线上的转换后的时钟线的第二个上升沿开始读取音频样本位。如果您的处理器 RX 和 TX 被配置为在时钟线的第一个上升沿开始数据,并且您无需费心纠正它,并且如果外围设备被配置为使用 I2S,那么您有效地使数据对齐开始在每个 32 位字的第二个 MSB(最高有效位)处。在这种情况下,在上面的解决方案 B 中移动 1 就足够了。

以正弦输入频率交替的 32 位接收字的第一个 MSB 是音频样本的 MSB。

此外,如果您从 using 切换uint32_t到 using int32_t,请检查您的 integer↔float转换是否支持int32_t. C 语言类型转换应该可以正常工作。

解决方案:

所以,我让它工作了

“你展示的那个是左对齐的,或者 TI 称之为“标准格式””

我从这里看到了Pg 上的ADC C5343 数据表的标准格式。14 在串行音频接口时序图中。

然后我尝试在 SPI_I2SCFGR 寄存器中将 DATFMT 位更改为 0x01 以实现左对齐,然后一切正常。过滤器正在工作,波浪看起来很完美。

剩下的唯一问题是为什么它使我的输出正弦波上的电压如此之小~340mV Pk-PK