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

PDM to I2S by nRF52832

Hello, I use nrf52832 (SDK 17)  and I wanna send sounds from a microphone (which uses PDM) to TAS2521 which is connected to a headphone and it uses I2S. here is my code to initialize TAS2521 by SPI:

uint8_t tas2521_regRead(uint8_t regAddress) {
    uint8_t SPI_TX_Buff[1] = {(regAddress << 1) | 1};
    uint8_t SPI_RX_Buff[2] = {0, 0};
    nrf_gpio_pin_clear(SPI_AMP_SS_PIN);
    spi_xfer_done = false;
    APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, SPI_TX_Buff, 1, SPI_RX_Buff, 2));
    while (!spi_xfer_done) {
        __WFE();
    }
    nrf_gpio_pin_set(SPI_AMP_SS_PIN);
    return SPI_RX_Buff[1];
}
void tas2521_regWrite(uint8_t regAddress, uint8_t value) {
    uint8_t SPI_TX_Buff[2] = {(regAddress << 1) | 0, value};
    nrf_gpio_pin_clear(SPI_AMP_SS_PIN);
    spi_xfer_done = false;
    APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, SPI_TX_Buff, 2, NULL, 0));
    while (!spi_xfer_done) {
        __WFE();
    }
    nrf_gpio_pin_set(SPI_AMP_SS_PIN);
}
void tas2521_pageSwitch(uint8_t page) {
    tas2521_regWrite(0, page);
}
void tas2521_softReset() {
    tas2521_pageSwitch(0);
    tas2521_regWrite(0x01, 0x01);
}

void tas2521_ldoSet() {
    tas2521_pageSwitch(1);
    tas2521_regWrite(0x02, 0x00);
}

void tas2521_powerUp() {
    tas2521_pageSwitch(0);
    tas2521_regWrite(0x04, 0x00);
    tas2521_regWrite(0x0B, 0x81);
    tas2521_regWrite(0x0C, 0x82);
    tas2521_regWrite(0x0D, 0x00);
    tas2521_regWrite(0x0E, 0x80);
    tas2521_regWrite(0x1B, 0x00);
    tas2521_regWrite(0x1C, 0x00);
    tas2521_regWrite(0x3C, 0x02);
    tas2521_pageSwitch(1);
    tas2521_regWrite(0x01, 0x10);
    tas2521_regWrite(0x0A, 0x00);
    tas2521_regWrite(0x0C, 0x08);
    tas2521_regWrite(0x16, 0x00);
    tas2521_regWrite(0x09, 0x20);
    tas2521_regWrite(0x10, 0x00);
    tas2521_pageSwitch(0);
    tas2521_regWrite(0x3F, 0x90);
    tas2521_regWrite(0x41, 0x00);
    tas2521_regWrite(0x40, 0x04);
}

and in the main() function I initialized SPI and use these functions:

    nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
    spi_config.frequency = NRF_DRV_SPI_FREQ_1M; //Check 1MHz
    spi_config.mode = NRF_DRV_SPI_MODE_1;
    spi_config.bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST;
    spi_config.ss_pin = NRF_DRV_SPI_PIN_NOT_USED; //Select Slave
    spi_config.miso_pin = SPI_MISO_PIN;
    spi_config.mosi_pin = SPI_MOSI_PIN;
    spi_config.sck_pin = SPI_SCK_PIN;
    spi_config.irq_priority = APP_IRQ_PRIORITY_HIGH;
    err_code = nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL);
    APP_ERROR_CHECK(err_code);

    nrf_gpio_cfg_output(SPI_AMP_SS_PIN);
    nrf_gpio_pin_set(SPI_AMP_SS_PIN);
    
    tas2521_softReset();
    tas2521_ldoSet();
    tas2521_powerUp();

I also Initialized I2S after that:

    nrf_drv_i2s_config_t i2s_config = NRF_DRV_I2S_DEFAULT_CONFIG;
    i2s_config.sdin_pin = I2S_SDIN_PIN;
    i2s_config.mck_pin = I2S_MCK_PIN;
    i2s_config.sck_pin = I2S_BCK_PIN;
    i2s_config.lrck_pin = I2S_WCK_PIN;
    i2s_config.sdout_pin = I2S_SDOUT_PIN;
    i2s_config.mck_setup = NRF_I2S_MCK_32MDIV32;
    i2s_config.ratio = NRF_I2S_RATIO_96X;
    i2s_config.sample_width = NRF_I2S_SWIDTH_16BIT;
    i2s_config.channels = NRF_I2S_CHANNELS_LEFT;
    err_code = nrf_drv_i2s_init(&i2s_config, i2s_data_handler);
    APP_ERROR_CHECK(err_code);
    nrf_drv_i2s_buffers_t const initial_buffers = {
        .p_tx_buffer = i2s_buffer_tx[0],
        .p_rx_buffer = i2s_buffer_rx[0],
    };
    err_code = nrf_drv_i2s_start(&initial_buffers, PDM_BUFFER_SIZE_SAMPLES, 0);
    APP_ERROR_CHECK(err_code);

PDM microphone works fine (I checked it) and PDM_BUFFER_SIZE_SAMPLES is equal to 125. I also use these functions for I2S:

static void i2s_data_handler(nrf_drv_i2s_buffers_t const *p_released,
    uint32_t status) {
    ASSERT(p_released);
    if (!(status & NRFX_I2S_STATUS_NEXT_BUFFERS_NEEDED)) {
        return;
    }
    if (!p_released->p_rx_buffer) {
        for (uint16_t i = 0; i < PDM_BUFFER_SIZE_SAMPLES; i++) {
            i2s_buffer_tx[0][i] = i2s_buffer_tx[1][i];
        }
        nrf_drv_i2s_buffers_t const next_buffers = {
            .p_rx_buffer = i2s_buffer_rx[0],
            .p_tx_buffer = i2s_buffer_tx[0],
        };
        APP_ERROR_CHECK(nrf_drv_i2s_next_buffers_set(&next_buffers));
    } else {
        APP_ERROR_CHECK(nrf_drv_i2s_next_buffers_set(p_released));
    }
}

static void prepare_tx_data(uint16_t p_block[]) {
    for (uint16_t i = 0; i < PDM_BUFFER_SIZE_SAMPLES; i++) {
        p_block[i] = pdm_buffer[i];
    }
}

Whenever pdm_event_handler function indicates that 125 samples are ready it calls prepare_tx_data(i2s_buffer_tx[1]).

I can hear some sounds from headphones, but it is very distorted and noisy, It is possible to help me?

Parents
  • Hi 

    Are you using some kind of ringbuffer/FIFO to store the incoming PDM data before it is sent out to the TAS2521?

    Have you verified if the PDM and the I2S interfaces are running in sync, and produce/consume data at the same speed?

    Have you done any scope measurements to see what happens with the sound?
    A common technique is to apply a sine wave to the input, and see how it changes on the output side. 

    Best regards
    Torbjørn

Reply
  • Hi 

    Are you using some kind of ringbuffer/FIFO to store the incoming PDM data before it is sent out to the TAS2521?

    Have you verified if the PDM and the I2S interfaces are running in sync, and produce/consume data at the same speed?

    Have you done any scope measurements to see what happens with the sound?
    A common technique is to apply a sine wave to the input, and see how it changes on the output side. 

    Best regards
    Torbjørn

Children
No Data
Related