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?

Related