3

I'll try to explain everything with detail as this is one will be a hard one to explain.

Essentially what I am trying to achieve is sum both the left & right channel to produce a mono signal to be outputted via I2S as the subwoofer line.

The problem I am having right now is that after summing the samples and sending it back to the peripheral I am observing at least double the frequency compare to the input and I have no idea why. Also at lower frequencies the signal looks chopped (see pictures)

What I have done for you is:

  • Ensured the I2S Clock is running correctly
  • Without summing just sending 1:1 samples and it's a mirror image of the input

The I2S3 DMA is setup as follow:

  • Length = 2048 (Tx_BUFF)

The I2S1 DMA is setup as follow:

  • Length = 4096 (Rx_BUFF)
  • Length - 4096 (Tx_BUFF)

Code: I2S_HALFCOMPLETE_CALLBACK()

void I2S_HALFCOMPLETE_CALLBACK() {

    int * I2S3_TxBUFF = getI2S3_TxBUFF();
    int INSAMPLE_I2S_MONO[1024];
  
  for (int i = 0; i < 2048; i++) {

    if ((i % 2) == 0){ // L Samples

        INSAMPLE_I2S_MONO[i >> 1] = I2S1_RxBUFF[i];

    } else if ((i % 2) == 1){ // R Samples

      if (inputSourceMode == INPUT_INLINE) {

          INSAMPLE_I2S_MONO[(i - 1) >> 1] += I2S1_RxBUFF[i];
          INSAMPLE_I2S_MONO[(i - 1) >> 1]  =  INSAMPLE_I2S_MONO[(i - 1) >> 1] >> 1;
      }
    }
  }

  for (int i = 0; i < 2048; i++) {

    if ((i % 2) == 0) { // L Samples

    

    }   else if ((i % 2) == 1) { // R Samples

    

    }
      
     if (i < 1024) {
         I2S3_TxBUFF[i] =  INSAMPLE_I2S_MONO[i];
      }

  }


}

CODE: I2S_TRANSFERCOMPLETE_CALLBACK()

void I2S_TRANSFERCOMPLETE_CALLBACK() {

    int * I2S3_TxBUFF = getI2S3_TxBUFF();
    int INSAMPLE_I2S_MONO[1024];

  int * I2S3_TxBUFF = getI2S3_TxBUFF();

  int INSAMPLE_I2S_MONO[1024];
  
  for (int i = 2048; i < 4096; i++) {

    if ((i % 2) == 0) { // L Samples

        INSAMPLE_I2S_MONO[(i >> 1)-1024] = I2S1_RxBUFF[i];
        
    } else if ((i % 2) == 1){ // R Samples

             INSAMPLE_I2S_MONO[((i - 1) >> 1) - 1024] += I2S1_RxBUFF[i];
             INSAMPLE_I2S_MONO[((i - 1) >> 1) - 1024]  =  INSAMPLE_I2S_MONO[((i - 1) >> 1) - 1024] >> 1;

    }

  }

  for (int i = 2048; i < 4096; i++) {

    if ((i % 2) == 0) { // L Samples


    } else if ((i % 2) == 1){ // R Samples


    }


    if (i < 3072) {

        I2S3_TxBUFF[i - 1024] =  INSAMPLE_I2S_MONO[i-2048];

    }
  }

Results: @ 6Hz enter image description here

@ 56Hz enter image description here

@ 1kHz enter image description here

@ 4khz enter image description here

UPDATE 1:

I still dont have a clue, but since the frequencies are being doubled, does it have to do with feeding the audio samples at half? For example I am receiving a total of 4096 samples but when summing I am only sending back out 2048. Is that why? Its trying to send 2048 within the 4096 sample period?

UPDATE 2:

Another gut feeling is coming from adding the two samples together. I feel like it has something to do with the sampling rate. Tried output L + R samples and it works fine, but when I combine them the sample rate is doubled.

Leoc
  • 1,393
  • 1
  • 9
  • 21
  • seems a complex problem. But you really should clean up your code – delete all that's commented out. Not only is this kind of something you should generally do out of politeness before discussing your code, it also helps yourself concentrate. Also, I can guarantee that you don't want `double` on a microcontroller, that will just be terrible performance-wise, and you don't need it. So, let go of that code – and delete it. You're using git to track your code changes, anyway. Right? – Marcus Müller Jun 12 '21 at 01:16
  • Hi!, sorry you're right, ill tidy that up. Yes, I agree with you on the double, however it's there to do double arithmetic for the DSP. The MCU i am using has a double - FPU. And yes using git to track revisions – Leoc Jun 12 '21 at 01:22
  • 2
    Cool! Thanks for the code cleanup. (now it's only duplicate empty lines) – Marcus Müller Jun 12 '21 at 01:24
  • looks like you might be forgetting to fetch the current rx buffer pointer in your halftime callback? What microcontroller is this? – Marcus Müller Jun 12 '21 at 01:26
  • also, make sure your callback actually *completes* in the time it takes the hardware to work half a buffer. You're doing a lot of non-DMA copying, and you're using 4 kB (I assume 32 bit ints) of Stack space – that's actually not great. – Marcus Müller Jun 12 '21 at 01:27
  • This is the STM32H753ZI, beefy boy. When the function halftimeCB() gets called it fetches the current Rx Buffer at THE time, otherwise what do you mean? For the second part. Its completing for sure. I have a much much more computational DSP working in another function and it works perfectly. This is nothing compare to that – Leoc Jun 12 '21 at 01:28
  • I see what you mean, forgot the variables. – Leoc Jun 12 '21 at 01:30
  • These kind of problems need a step by step approach. For this I suggest following and verifying each step. Start by dumping your buffer with debugger and see if it matches the expected waveform or not. – Erik Friesen Jun 13 '21 at 22:00

1 Answers1

0

The issue was resolved with the help of Hilmar over at DSP Stackexchange

The problem was I was populating the array with half the samples (2048) of the I2S1_RxBUFF where it should have been the total 4096 samples

Leoc
  • 1,393
  • 1
  • 9
  • 21