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

Glitch in analog audio output when using I2S module

Hello.

I'm using the NRF52832 with I2S module connected to TLV320DAC from TI. I've configured the DAC and I2S module successfully. I'm getting audio output (simple sine wave read from a table) but there is an impulse glitch in the audio signal. The glitch appears to occur at the end of every I2S buffer send. When I set the I2S TX buffer size to 250 samples, I see a glitch in the audio at the corresponding time interval. For example, 250 buffer size at 41666 sample rate, causes a glitch in the audio every 0.006 seconds. When I increase the I2S buffer size, the glitch period increases correspondingly.

I've checked my sine table interpolation algorithm. It looks good. I believe the problem is with the NRF52832 and not the DAC. The I2S buffer size is the only variable which seems to affect the audio glitch. Oh, I also tried using I2S slave mode where I program the DAC to send the I2S clocks to the NRF chip. That did not change the glitch though.

I recorded the audio output in Audacity. Take a look at the waveform and frequency spectrum...

\

Parents
  • Okay, looks like I was have been deceived. The scratch buffer seems to have only masked the issue. After some seemingly unrelated code changes the original symptoms returned. This time I managed to suppress them simply by adding an extra word to the start of the buffer, and then passing a pointer to index 1 instead! It's as if the DMA is sucking data from *before* the buffer pointer passed to it.

  • Not sure if I have any idea here, you could try to read the I2S chapter in the product specification for any suggestion also:
    https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52832.ps.v1.1/i2s.html#concept_z2v_24y_vr

    You may also look into placing the i2s buffers into a specific RAM section not used by other peripherals:
    https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52832.ps.v1.1/memory.html#memory

    Kenneth

  • Oh boy. I discovered why. The buffer I was passing was not word aligned. Variables aren't necessary so. The I2S driver checks and enforces word alignment, but the code that does so gets compiled to a nop! This is the critical line of code:

    NRFX_ASSERT((p_initial_buffers->p_tx_buffer == NULL) ||
                    (nrfx_is_in_ram(p_initial_buffers->p_tx_buffer) &&
                     nrfx_is_word_aligned(p_initial_buffers->p_tx_buffer)));



    Alas, it turns out NRFX_ASSERT expands to nothing, so the misalignment goes unnoticed. Assumedly the DMA then takes no notice of the lower two bits in the pointer, resulting in a start address that is half a word early.

    I've now declared my buffer with the suffix __attribute__((aligned(4))) and all is rosy.

    Pretty tough going here...

  • Well spotted, you are likely compiling your code with "Release", not "Debug", then the code will not do these checks, ref:

    #if (defined(DEBUG_NRF) || defined(DEBUG_NRF_USER))
    #define NRF_ASSERT_PRESENT 1
    #else
    #define NRF_ASSERT_PRESENT 0
    #endif
  • Okay thank you. It's a little off-topic, but I have been looking for some guidance for performing a debug build but have not been able to locate any. I cannot find any documentation on DEBUG_NRF. There is no reference to a "Debug" build in the NRF Connect SDK docs, including those associated with running the debugger in SES.

    The closest I've come to instructions on performing a debug build is the notes of a few users, such as Jimmy Wong, who list "CONFIG_LOG", "CONFIG_LOG_DEFAULT_LEVEL" and "CONFIG_DEBUG_OPTIMIZATIONS" as the relevant options.

    Are you aware of any documentation on doing a debug build when working with a project based on the NRF Connect SDK?

  • Oh dear. Not only was it a mission to effectively define DEBUG_NRF with the nRF Connect SDK, after spending far too long trying to figure out why it wasn't working, I finally discover that DEBUG_NRF isn't even part of the SDK! It does not appear anywhere, and is only found in projects with a nRF5x library. This being a nRF9x project does not use it at all!

    So I finally discover that the way to do it now is to use CONFIG_ASSERT - only to find that my bare bones application will no longer run thanks to a mysterious assertion fail in a part of the SDK I've never looked at:

    ASSERTION FAIL [((arch_is_in_isr() == 0) || ((timeout).ticks == (((k_timeout_t) {})).ticks))] @ WEST_TOPDIR/zephyr/kernel/sem.c:140

    The fail is deep within disk_access_init --> sdhc_spi_detect --> spi_nrfx_transceive, but I can't afford to spend any more time unpicking the incomplete nRF SDK. Will have to make do and move on.

  • Aaargh! These issues are three layers deep!

    So while the word-alignment issue I've raised is still valid, it turns out cory123's suggestion from a month ago about having to double buffer the data is also true.

    After re-reading the docs, I see that the driver only double buffers the pointer! So yes, the user also has to double buffer the data, because the driver requests more data before it has finished reading from that previously provided.

Reply
  • Aaargh! These issues are three layers deep!

    So while the word-alignment issue I've raised is still valid, it turns out cory123's suggestion from a month ago about having to double buffer the data is also true.

    After re-reading the docs, I see that the driver only double buffers the pointer! So yes, the user also has to double buffer the data, because the driver requests more data before it has finished reading from that previously provided.

Children
No Data
Related