2
$\begingroup$

Having troubles understanding why a DSP low pass filter was that working on the M4 is no longer working on an M7.

I recently switched over to a STM32H753ZI from a STM32L432KC.

In addition to switching from the L4 to H7 I am using the P2MODI2S2 with the H7 and not the internal ADC like I was when using the L4.

The only thing that came to mind would be the difference of sampling rates. I was using a 44.410kHz sampling rate on the L4 and now I am using a 96kHz sampling rate on the H7 using the PMODI2S2. So I re-did the discrete function and put in the new IIR coefficients and no cigar.

Using the H7 with the PMODI2S2 as a passthrough:

enter image description here

CODE:

#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 with PMODI2S2 with IIR coefficients using 96kHz sampling rate:

enter image description here

Code:

#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;

      }



  }

}

So I thought to myself, since I am using a I2S protocol and since its stereo I tried using a sampling rate of 192kHz just to see what happens:

enter image description here

CODE:

#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;

      }



  }

}

Any ideas? I am not sure if its the M7 or the peripheral in question. This was working on an L4, no problem.

UPDATE 1: I recorded the variables in debugger mode to see what is happening. I took three pictures. The first iteration is index 0-2 and the second iteration from 2-4 and the third picture is many iterations afterwards.

enter image description here

enter image description here

enter image description here

What I noticed is that RxBuffer and RxBuffer_f are out of sync. I also noticed that many iterations later the RxBuffer_f_out just becomes an int like data type and no longer contain any sort of decimals.

UPDATE 2:

I also notice that I am using a I2S device that shoots out stereo audio, am I maybe not adding the coefficients properly to the buffers. What I mean by this do I need to adjust the buffers when they come in, like bit shift them or anything along those lines? The only thing I know about that PMODI2S2 is that I believe it shoots out 24 bits in a 32 data frame, so I am assuming its padded with zeroes and why not.

UPDATE 3:

Was playing around with just multiplying the RxBuffer before putting in the TxBuffer and what it did was increase the PK - PK of the signal, however increasing it more caused this:

Multiplying the RxBuffer by 2^0 (Passthrough)

enter image description here

Multiplying the RxBuffer by 2^1

enter image description here

Multiplying the RxBuffer by 2^2

enter image description here

The last picture looks like the problem I am having, is this maybe an overflow issue?

UPDATE 4:

Talking to a concerned citizen he mentioned the I2S protocol is a 2's complement data encoded. I know what 2's complement is, however I am not sure if the TxBuff or the Rxbuff needs to be complemented. Anyhow I changed both data type of the TxBuff and the Rxbuff to int32_t datatypes and the problem still insist.

UPDATE 5: Tried using the 2's complement or simply just casting it as an int32_t. No luck.

CODE:

#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;

      }



  }

}
$\endgroup$
3
  • $\begingroup$ Have you configured the I2S properly? Does the I2S library that you use support 24-bit stereo data? $\endgroup$ – Olli Niemitalo Oct 15 '20 at 5:56
  • $\begingroup$ Yes, I am assuming it works properly based on the passthrough with no processing, seen in the first picture. The I2S hardware I am using supports 24 bit stereo as you can choose it from the "DATLEN" bit in the SPI_12SCFGR register $\endgroup$ – Pllsz Oct 15 '20 at 5:58
  • $\begingroup$ I have also checked all the clocks, such as FWS. MCLK. and SCLK they are all outputting the correct timing/frequencies has it was intended to be setup. $\endgroup$ – Pllsz Oct 15 '20 at 5:59
4
$\begingroup$

I2S audio samples are signed two's complement. Just add $2^{N-1}$, where $N$ is the number of bits, to the result, and binary and by $2^N-1$, to get the range to $0\ldots2^{N}-1$, which I think you used to get from the built-in analog-to-digital converter (ADC). Do this both to the data you receive and the data you transmit using I2S. You can optimize the calculation a little and combine the add and the binary and into just a binary xor by $2^N-1$.

Or start working with signed numbers. If the 24-bit data is not left-aligned in the 32-bit words, you either need to A) extend the sign bit or B) left-shift the received data and right-shift the data to be transmitted.

You should consult the ADC and DAC datasheets to confirm how the data is aligned, and if that is configurable, that you have configured it properly on the processor and in the peripherals. In I2S, the audio sample bits should be read starting at the second rising edge of the clock line after a transition on the word select line. If your processor RX and TX are configured to start the data at the first rising edge of the clock line, and you don't bother to correct that, and if the peripherals are configured to use I2S, then you effectively have the data aligned starting at the second MSB (most significant bit) of each 32-bit word. In that case, a shift of one in solution B above should suffice.

The first MSB of the 32-bit received words that alternates at the frequency of sinusoidal input is the MSB of the audio sample.

Also, if you switch from using uint32_t to using int32_t, check that your integer↔float conversions supports int32_t. C language type casting should work fine.

$\endgroup$
11
  • $\begingroup$ I am not sure if the method is the same however I did Change the unint32_t back to Int32t and the problem is still there. For the 2’s complement does it both have to be receive and transmit ? $\endgroup$ – Pllsz Oct 14 '20 at 17:53
  • $\begingroup$ What I mean more specifically, what am I 2's complementing the RxBuff or the TxBuff or both? $\endgroup$ – Pllsz Oct 14 '20 at 18:06
  • $\begingroup$ Updated the post. $\endgroup$ – Pllsz Oct 15 '20 at 0:06
  • $\begingroup$ By "2's complementing", what operation were you referring to? Two's complement is an operation that has a definition that is not what I suggest to do. $\endgroup$ – Olli Niemitalo Oct 15 '20 at 5:29
  • 1
    $\begingroup$ Holy I got it working. $\endgroup$ – Pllsz Oct 15 '20 at 7:20
1
$\begingroup$

Solution:

So, I got it working I am not sure if it was due to poorly documentation of I2S or me not understanding the left/ right aligness of a bit, but after reading this on a forum from one the of users, it stated this

"The one you show is Left-justified or as TI calls it "Standard format""

I saw the standard format from here the ADC C5343 datasheet on Pg. 14 in the Serial Audio Interface timing diagram.

Then I tried in the SPI_I2SCFGR register and changed the DATFMT bit to 0x01 for Left aligned and boom everything worked. The filter is working and the wave looks perfect.

The only question left is why it left the voltage on my output sine wave so small ~340mV Pk-PK

$\endgroup$
13
  • $\begingroup$ Did you reconfigure both RX and TX? I don't have access to documentation of your I2S programming interface so can't comment on what format should be configured in SPI_I2SCFGR. $\endgroup$ – Olli Niemitalo Oct 15 '20 at 8:04
  • $\begingroup$ I see, the device Iam using, I believe its linked in the main post has I2S hardware built in. All I had the I2S hardware configured but I guess I oversaw the left/right aligness as it default to right align in the registers. Is I2S always left aligned? $\endgroup$ – Pllsz Oct 15 '20 at 8:10
  • $\begingroup$ Yes the data always starts with the MSB of the audio sample according to the I2S Bus Specification section 3.1 Serial Data. But I don't know if you can accidentally override the specification's "The transmitter always sends the MSB of the next word one clock period after the WS changes." in your processor's I2S library configuration. I'm paranoid that maybe DATFMT=0x01 actually does that and there's another value that gives an alignment that follows the I2S specification. But I don't know. $\endgroup$ – Olli Niemitalo Oct 15 '20 at 8:24
  • $\begingroup$ Yeah, there's another register that sets up alignment such as WSINV, CKPOL $\endgroup$ – Pllsz Oct 15 '20 at 8:28
  • $\begingroup$ off topic question, mentioned in the last bit of my answer. Why is the voltage of my output signal so attenuated now? in the passband? $\endgroup$ – Pllsz Oct 15 '20 at 8:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.