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

How to read I2S configuration and print in UART using NRF52-DK ?

Hello,

I have an analogue audio mic connected to external ADC. The external ADC can give an output of 16bit, 20bits, 24bits and 32 bits I2S data. I have configured to send 20 bit as I2S output.

To enable the I2S communication between the ADC and NRF52 I use below configuration.

    config.sdin_pin  = I2S_SDIN_PIN;
    config.sdout_pin = NRFX_I2S_PIN_NOT_USED;
    config.mck_pin   = NRFX_I2S_PIN_NOT_USED;
    config.mck_setup = NRF_I2S_MCK_32MDIV15;
    config.ratio     = NRF_I2S_RATIO_48X;
    config.format    = NRF_I2S_FORMAT_I2S;
    config.sample_width  = NRF_I2S_SWIDTH_24BIT;
    config.channels      = NRF_I2S_CHANNELS_STEREO;

In the SDK config, I have selected the pin of SDIN as 28. SCK - 31 , LRCK - 30.

While debugging, I watch the RX buffer of the nrf_I2S the data to check values most of the time starts as 0xFF8 or 0xFF9 or 0x00.

I understand that if the 24-bit I2S communication is chosen then when storing NRF stores it with  0xFF"24bit value".

1. Can I communicated with 20 bits from the ADC side or should I use only 16 or 24?

2. If 20 bits can be configured then should I expect the RX buffer data should always starting as 0xFF0"20bits value"? Because I want to store it in SD card. So I need to store the raw data to a WAV header. And the raw data should be removed of first 12 bits.

When I use NRF RTT to print the 32-bit value from RX buffer it seems like NRF LOG stuck in a loop. Without NRF LOG statement I can see that RX buffer updating each time I debug. Need a suggestion for this problem as well.

Thanks

Cecil

Parents
  • Hello,

    So you do receive values with 0xFF'24bit-value'? 

    If the external ADC is using a 20 bit I2S, you must use the 24 bit, in order to capture all of the data. 

    2. Have you tried to manage this? I guess you need to do some bit shifting in order to store this. I assume you want to store samples in whole bytes on the SD card. If each sample is 20 bits, and you store 8 samples, you have 160 bits=20 bytes. So perhaps you want to wait until you have 8 samples (you can use more/less samples, as long as it adds up to n*8 bits. 2 samples are sufficient, but you probably want to store up a decent amount of data before writing to the SD card. 

    // Let us say you stored 8 samples, and they are stored in uint32_t samples[0] -> samples[7]:
    // The actual data are the last 5 bytes of the uint32_t sample[i]: sample[i] & 0x000FFFFF;
    
    static void process_data(uint32_t samples[], uint8_t length, uint8_t processed_data[])
    {
        memset(processed_data, 0x00, sizeof(processed_data); //sizeof(processed_data) should be 5/2*length.
        
        processed_data[0] |= (uint8_t)((samples[0] & 0x000FF000) >> 12);
        processed_data[1] |= (uint8_t)((samples[0] & 0x00000FF0) >>  4);
        processed_data[2] |= (uint8_t)((samples[0] & 0x0000000F) <<  4);
        processed_data[2] |= (uint8_t)((samples[1] & 0x000F0000) >> 16);
        processed_data[3] |= (uint8_t)((samples[1] & 0x0000FF00) >> 16);
        processed_data[4] |= (uint8_t)((samples[1] & 0x000000FF) <<  0);
        
        // At this point, the 2 first buffers (2*20 bits = 40 bits) are stored in the first 5 bytes (5*8bits = 40 bits)
        // transform this into a for loop to handle the entire length:
        
        for (uint8_t i=0; i<length/2; i++)
        {
            processed_data[2*i+0] |= (uint8_t)((samples[5*i+0] & 0x000FF000) >> 12);
            processed_data[2*i+1] |= (uint8_t)((samples[5*i+0] & 0x00000FF0) >>  4);
            processed_data[2*i+2] |= (uint8_t)((samples[5*i+0] & 0x0000000F) <<  4);
            processed_data[2*i+2] |= (uint8_t)((samples[5*i+1] & 0x000F0000) >> 16);
            processed_data[2*i+3] |= (uint8_t)((samples[5*i+1] & 0x0000FF00) >> 16);
            processed_data[2*i+4] |= (uint8_t)((samples[5*i+1] & 0x000000FF) <<  0);
        }
    }

    RTT print issue:

    From where do you print this, and how do you attempt to print it? Can you show some snippets?

    Best regards,

    Edvin

Reply
  • Hello,

    So you do receive values with 0xFF'24bit-value'? 

    If the external ADC is using a 20 bit I2S, you must use the 24 bit, in order to capture all of the data. 

    2. Have you tried to manage this? I guess you need to do some bit shifting in order to store this. I assume you want to store samples in whole bytes on the SD card. If each sample is 20 bits, and you store 8 samples, you have 160 bits=20 bytes. So perhaps you want to wait until you have 8 samples (you can use more/less samples, as long as it adds up to n*8 bits. 2 samples are sufficient, but you probably want to store up a decent amount of data before writing to the SD card. 

    // Let us say you stored 8 samples, and they are stored in uint32_t samples[0] -> samples[7]:
    // The actual data are the last 5 bytes of the uint32_t sample[i]: sample[i] & 0x000FFFFF;
    
    static void process_data(uint32_t samples[], uint8_t length, uint8_t processed_data[])
    {
        memset(processed_data, 0x00, sizeof(processed_data); //sizeof(processed_data) should be 5/2*length.
        
        processed_data[0] |= (uint8_t)((samples[0] & 0x000FF000) >> 12);
        processed_data[1] |= (uint8_t)((samples[0] & 0x00000FF0) >>  4);
        processed_data[2] |= (uint8_t)((samples[0] & 0x0000000F) <<  4);
        processed_data[2] |= (uint8_t)((samples[1] & 0x000F0000) >> 16);
        processed_data[3] |= (uint8_t)((samples[1] & 0x0000FF00) >> 16);
        processed_data[4] |= (uint8_t)((samples[1] & 0x000000FF) <<  0);
        
        // At this point, the 2 first buffers (2*20 bits = 40 bits) are stored in the first 5 bytes (5*8bits = 40 bits)
        // transform this into a for loop to handle the entire length:
        
        for (uint8_t i=0; i<length/2; i++)
        {
            processed_data[2*i+0] |= (uint8_t)((samples[5*i+0] & 0x000FF000) >> 12);
            processed_data[2*i+1] |= (uint8_t)((samples[5*i+0] & 0x00000FF0) >>  4);
            processed_data[2*i+2] |= (uint8_t)((samples[5*i+0] & 0x0000000F) <<  4);
            processed_data[2*i+2] |= (uint8_t)((samples[5*i+1] & 0x000F0000) >> 16);
            processed_data[2*i+3] |= (uint8_t)((samples[5*i+1] & 0x0000FF00) >> 16);
            processed_data[2*i+4] |= (uint8_t)((samples[5*i+1] & 0x000000FF) <<  0);
        }
    }

    RTT print issue:

    From where do you print this, and how do you attempt to print it? Can you show some snippets?

    Best regards,

    Edvin

Children
  • Hello Edvin,

    I have attached one set of I2S samples in a text file. Some times i get 0xFF'24bits data' other times it is 0x00'24bitdata'. I used only one mic through the left channel.512_Samples.txt.

    I still have a doubt is the data is stored as 0xFF"4bits as 0 ,20-bits data " or 0xFF"20-bits data, 4bits as 0"

    Below is the snippet.

    static bool check_samples(uint32_t const * p_block)
    {
        // [each data word contains two 16-bit samples]
        uint16_t i;
        for (i = 0; i < I2S_DATA_BLOCK_WORDS; ++i)
        {
            uint32_t const * p_word = &p_block[i];
            uint32_t sample_actual = *p_word;
            NRF_LOG_INFO("P_word: 0x%x ",sample_actual);
            //Process data for SD card storage/ Uart print
        }
        NRF_LOG_INFO("%3u: OK", m_blocks_transferred);
        return true;
    }

  • How is the data in the 512_Samples.txt generated? 

    If the values are from the RAM, and not memset to 0x00000000 or 0xFFFFFFFF before it is sampled, it may be that the remaining bytes that are not written by the I2S are old (garbage) RAM values. 

  • I am watching the m_buffer_rx[2][512], which is the NRF_I2S_DRV_Buffer for RX. I exported one set of the sample while debugging the project from the watch. I access the buffer from a pointer which is set to NULL each time after processing the buffer values. I am using the I2S code edited for 24-bit word length.

Related