This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

I2S peripheral's decoding of 32 bit data in slave mode

I'm using a nRF52480 DK board with an adafruit 3421 I2S microphone breakout board attached. I am on Ubuntu 20.04 with SES 5.42c and SDK 16.

I am using a variant of the usbd_cdc_acm example along with a Python3 script that provides communication with the DK board for command, data retrieval, display, and storage.

I'm using the Nordic PWM peripheral to produce SCK and LRCK for the microphone and the Nordic I2S peripheral in slave mode. The microphone's SEL is connected to the DK board's ground as is the microphone ground. The microphone is turned on and off via a GPIO pin's set and clear command.

My SCK PWM channel is setup as follows:

My LRCK PWM channel is setup as follows:

SCK is running at 2MHz and LRCK is running at 31250Hz, so my sample rate is 31250Hz.

The following code shows how the I2S peripheral is initialized.

One of the following screen shots is of the low LRCK with SCK and DOUT, (top channel is SCK, next is DOUT, and bottom is LRCK). The other screen shot is a zoom of the same.

Each of the two EasyDMA buffers are 512 uint32_t long. Buffer pointers are passed back to main by the i2s_data_handler. Main has ram allocated to hold 10 of these buffers. When main has filled  its buffers, it stops the I2S and PWM peripherals. It then prepares the data for transmission over the secondary USB port of the DK board to the Python3 script.

I'm using an  Android app - Tone Generator by epsilon ventures - to generate a "known" signal. I use a 250Hz sine wave. At an LRCK sample rate of 32250Hz, each sample is 32uS, Since the period of my sine wave is 4 mS, each period should be 125 samples long. The following screen shot is a matplotlib.pyplot.plot of 224 of the I2S peripheral's output values of the phone's signal.

Things look like they could be real. This brings me to my questions which concern how to decode the I2S peripheral's output. The following code describes my process and is commented with my reasoning. Could you tell me if my reasoning and methodology is correct?

Question 1: From the documentation, The EasyDMA "...32-bit memory word can ... contain one right-aligned 24-bit sample sign extended to 32 bit." Does sign extended mean that the 23rd bit is repeated 8 times in bits 24 through 31? If the Knowles microphone produces a 24 bit value whose MSB is one, (indicating a negative value), are bits 24 through 31 assigned a value of one? The reason i'm asking is that every negative I2S peripheral value has ff in the most significant 8 bits.

Question 2: Am I right that the I2S peripheral's value has the microphone's value in bits 23 down to bit 0? Where bit 23 is the MSB and bit 0 is LSB?

Question 3: Is this 24 bit thing the same as the 24 bit value that the Knowles microphone is providing or is it a "translation" of some sort, (as with a PDM microphone)? If it is a "translation" are all 24 bits used and what do they represent?

Question 4: If the I2S peripheral's bit 0 through 23 is the same as the Knowles microphones's 24 bit value, then bits 0 through 5 are the zero padding mentioned in the Knowles data sheet and can be discarded? 

Question 5: Could I have a syncing problem between my SCK and LRCK? Is it correct to think that as long as LRCK is low and low long enough to accommodate 32 SCK pulses, the microphone will transmit all of it's data? You'll notice in my initialization of the LRCK PWM, I lengthen the duty cycle by one. So the LRCK's duty cycle is 51%. I did this because the tracings showed some LRCK low periods were questionably encompassing 32 separate SCK pulses on a 50% duty cycle.I thought this 51% duty cycle would be acceptable since I am mono and configure the I2S peripheral as just left channel. My thinking is that since the I2S peripheral is ignoring the right channel, the length of time that LRCK is highr can be a bit shorter. As far as I can make out the microphone doesn't even respond to LRCK high when SEL is grounded. I'm thinking that while the microphone may not mind, the Nordic I2S peripheral is adversely effected

Any comments, questions, answers are appreciated. Thank you.

Top Replies

Parents
  • Hi,

     

    The pictures seems to be missing in your post. Could you re-upload them, so I can see how things are looking?

     

    Based on the sensor, it looks like it assumes "i2s left-justified" data format, and you're using the firmware "algorithm" to emulate support for 32 bit frames in I2S (on nRF52-series devices) from this post?

    https://devzone.nordicsemi.com/f/nordic-q-a/15713/i2s-32-bit-word-size/59992#59992

     

    Note that the above linked project, https://github.com/gregtomasch/nRF52_24-bit-_I2S_Microphone_Audio_Recording_Utility, isn't made by nordic, and I haven't tried it myself.  

    Question 1: From the documentation, The EasyDMA "...32-bit memory word can ... contain one right-aligned 24-bit sample sign extended to 32 bit." Does sign extended mean that the 23rd bit is repeated 8 times in bits 24 through 31? If the Knowles microphone produces a 24 bit value whose MSB is one, (indicating a negative value), are bits 24 through 31 assigned a value of one? The reason i'm asking is that every negative I2S peripheral value has ff in the most significant 8 bits.

     Based on the datasheet: https://media.digikey.com/pdf/Data%20Sheets/Knowles%20Acoustics%20PDFs/SPH0645LM4H-B.pdf

    It looks like it tristates the lines after the 24th bit, and keeps 19 to 23 as '0', but I might be misinterpreting things here.

    Question 2: Am I right that the I2S peripheral's value has the microphone's value in bits 23 down to bit 0? Where bit 23 is the MSB and bit 0 is LSB?

    Left-justified format. First bit is MSB.

    We might be talking "around each other" - Depends on which way you read (left to right, right to left).

    Question 3: Is this 24 bit thing the same as the 24 bit value that the Knowles microphone is providing or is it a "translation" of some sort, (as with a PDM microphone)? If it is a "translation" are all 24 bits used and what do they represent?

    Note, this is left-aligned format, as an example shown in figure 5 in the nRF52832 PS:

    https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52832.ps.v1.1/i2s.html?cp=4_2_0_43_5#concept_vz5_fty_vr

    Question 4: If the I2S peripheral's bit 0 through 23 is the same as the Knowles microphones's 24 bit value, then bits 0 through 5 are the zero padding mentioned in the Knowles data sheet and can be discarded? 

     

    Question 5: Could I have a syncing problem between my SCK and LRCK? Is it correct to think that as long as LRCK is low and low long enough to accommodate 32 SCK pulses, the microphone will transmit all of it's data? You'll notice in my initialization of the LRCK PWM, I lengthen the duty cycle by one. So the LRCK's duty cycle is 51%. I did this because the tracings showed some LRCK low periods were questionably encompassing 32 separate SCK pulses on a 50% duty cycle.I thought this 51% duty cycle would be acceptable since I am mono and configure the I2S peripheral as just left channel. My thinking is that since the I2S peripheral is ignoring the right channel, the length of time that LRCK is highr can be a bit shorter. As far as I can make out the microphone doesn't even respond to LRCK high when SEL is grounded. I'm thinking that while the microphone may not mind, the Nordic I2S peripheral is adversely effected

    Yes, you need the SCK and L/RCK to be aligned. Our serial modules try to sample "in between" a clock cycle, in case of lagging in the signal path, but if you have a 4MHz input signal, that's a maximum of 125 ns (minus SETUP time, 40 ns -> 125-40 = 85ns) delay.

     

    Are you starting the HFCLK? If not, you're running on internal RC oscillator, which has a tolerance in the percentage area.

    Try calling "NRF_CLOCK->TASKS_HFCLKSTART = 1;", then wait for the NRF_CLOCK->EVENTS_HFCLKSTARTED.

     

    Kind regards,

    Håkon

    Do you have some logic analyzer traces I can look at? I'm not sure I fully understand the setup.

  • I will try re-posting the pictures here.

    One of the following screen shots is of the low LRCK with SCK and DOUT, (top channel is SCK, next is DOUT, and bottom is LRCK). The other screen shot is a zoom of the same.

    The following screen shot is a matplotlib.pyplot.plot of 224 of the I2S peripheral's output values of the phone's signal.

    Thank you for your response. I'm still reading it. Let me know if I can provide anything else.

Reply
  • I will try re-posting the pictures here.

    One of the following screen shots is of the low LRCK with SCK and DOUT, (top channel is SCK, next is DOUT, and bottom is LRCK). The other screen shot is a zoom of the same.

    The following screen shot is a matplotlib.pyplot.plot of 224 of the I2S peripheral's output values of the phone's signal.

    Thank you for your response. I'm still reading it. Let me know if I can provide anything else.

Children
  • Hi,

     

    Thanks for posting the pictures.

    Amplitude is a bit low, but that might be "low volume" on the source. Approx. 100 samples for one period (31,25k / num_of_samples) = ~312 Hz, which is ~25% off.

    The WS signal looks to be approx. 16.5 us, which gives a period of 2*16.5 = 33 us -> ~30 kHz.

     

    The timing here is a bit off. Can you confirm if you're using the HFCLK or not?

    Again; it is _very important_ that you run using the external HFCLK when testing I2S. The internal 64 MHz RC oscillator can be quite inaccurate..

     

    Kind regards,

    Håkon

  • I am making the following timer calls in main's initialization sequence:

    ret = nrf_drv_clock_init();
    APP_ERROR_CHECK(ret);
    nrf_drv_clock_lfclk_request(NULL);
    while(!nrf_drv_clock_lfclk_is_running())
    {
    /* Just waiting */
    }

    I'm guessing that a call to nrf_drv_clock_hfclk_request(NULL) would be the same as 

    NRF_CLOCK->TASKS_HFCLKSTART = 1;

    Can I replace nrf_drv_clock_lfclk_request(NULL); with nrf_drv_clock_hfclk_request(NULL); and nrf_drv_clock_lfclk_is_running() with nrf_drv_clock_hfclk_is_running() ? Will I get the same timer functionality throughout the rest of the program?

    I've done that and it has broken something in my communications which is annoying but here is a screen shot from the logic analyzer when I use nrf_drv_clock_hfclk_request(NULL);

     

  • I put my timer initialization back the way it was and added the NRF_CLOCK calls so everything looks like:

    ret = nrf_drv_clock_init();
    APP_ERROR_CHECK(ret);

    nrf_drv_clock_lfclk_request(NULL);
    while(!nrf_drv_clock_lfclk_is_running())
    {
    /* Just waiting */
    }

    NRF_CLOCK->TASKS_HFCLKSTART = 1;
    while(!NRF_CLOCK->EVENTS_HFCLKSTARTED)
    {
    /* Just waiting */
    }

    Here is a logic analyzer screen shot:

    Here is a matplotlib.pyplot.plot of 224 of the I2S peripheral's output values of the phone's signal.

  • Hi,

     

    Good that you're using the HFCLK now, I feared that it wouldn't help the scenario this much however.. Normally you'd see approx. 1-5 % variance with the RC oscillator, where as your frequency deviation is ~20-30 %.

    If you take this screenshot:

    matty said:

    Here is a logic analyzer screen shot:

    Since this bit stream is 2's compliment, salaea detects this as -31660. The range that you are plotting doesn't seem to touch into this value. How are you handling this on the PC side?

    Kind regards,

    Håkon

  • Hello,

    I tried to explain my handling of the I2S peripheral's data in the 80 lines of code at the beginning of the question. That code is commented step by step and try's to explain my reasoning and methods. For that code, the high ordered bits are always the the left most so in a uint32_t, bit 31 is the leftmost bit and the Most Significant Bit while bit 0 is the right most bit and the Least Significant Bit. I would greatly appreciate it if you could look at that commented code and tell me if my reasoning is correct. Particularly in regards to the questions I asked since they' originate in that code. I appreciate your help. Thank you.