analogdevicesinc / msdk

Software Development Kit for Analog Device's MAX-series microcontrollers
Apache License 2.0
61 stars 82 forks source link

i2s dma hao pop #290

Closed xinshuwei closed 1 year ago

xinshuwei commented 1 year ago

i have MAX78000 FTHR_RevA board .I want set up max9867 codec. I learn I2S config with example. Codec is working,i found use

MXC_DMA_ReleaseChannel(0); MXC_I2S_TXDMAConfig() This code once play is ok,but when i send a lot of samples with “SDHC fread“ wav files, release dma ch and TXDMAConfig(), Codec play audio have pop, I have capture this audio wav with audtion(set send bu'ffer size is 1600 ,16bit two ch out,400 samples have pop) 93114dbfe8d524da031f5874a1c861f

How can i setup is codec with FTHR_RevA I2S ,playback a long file is not have pop? Can help me?

jessexm commented 1 year ago

The tx dma channel may be running out of data. For sustained output a double buffered approach using async transfers may be needed.

The following pseudo code outlines the process.

#define TXBUF_LEN 1600

volatile int txdmaDone = 0;

unsigned char txbuf_0[TXBUF_LEN];
unsigned char txbuf_1[TXBUF_LEN];
unsigned char* activeBuf;

void DMA0_IRQHandler(void)
{
  MXC_DMA_Handler();
}

void txdmaCallback(int x, int xx)
{
  txdmaDone = 1;
}

void workLoop(void)
{
  int dmaChannel;

  NVIC_EnableIRQ(DMA0_IRQn);

  MXC_I2S_RegisterDMACallback(txdmaCallback);

  /* read and send initial buffer */
  sdhc-read(file, txbuf_0, TXBUF_LEN);
  dmaChannel = MXC_I2S_TXDMAConfig(txbuf_0, TXBUF_LEN);
  activeBuf = txbuf_0;

  /* pre-read next buffer */
  sdhc-read(file, txbuf_1, TXBUF_LEN);

  while (1) {
    if (txdmaDone) {
      txdmaDone = 0;

      MXC_DMA_ReleaseChannel(dmaChannel);

      if (activeBuf == txbuf_0) {
        /* send pre-read buffer */
        dmaChannel = MXC_I2S_TXDMAConfig(txbuf_1, TXBUF_LEN);
        /* read next buffer while active buffer is transmitted */
        sdhc-read(file, txbuf_0, TXBUF_LEN);
        /* set active buffer */
        activeBuf = txbuf_1;
      } else {
        dmaChannel = MXC_I2S_TXDMAConfig(txbuf_0, TXBUF_LEN);
        sdhc-read(file, txbuf_1, TXBUF_LEN);
        activeBuf = txbuf_0;
      }
    }

    /*
      other work
    */
  }
}
xinshuwei commented 1 year ago

i also use double buffered approach.code set like is

1. init

NVIC_EnableIRQ(DMA0_IRQn); MXC_I2S_RegisterDMACallback(i2s_dma_cb); MXC_NVIC_SetVector(DMA0_IRQn, DMA_IRQHandler); void DMA_IRQHandler(void) { MXC_DMA_Handler(); } void i2s_dma_cb(int handle, int error) { i2s_done = 1; }

2. update data

void update_first_data(voidflash_buf,int size) { i2s_buf= flash_buf; //MXC_DMA_ReleaseChannel(0); dmaChannel = MXC_I2S_TXDMAConfig(i2s_buf, size); //MXC_DMA_Start(0); flash_buf = BUF_SEL(flash_buf, buf0, buf1); // Get next set of audio samples } void update_frame_data(void flash_buf,int size) { while(!i2s_done) { } i2s_buf= flash_buf; i2s_done = 0; MXC_DMA_ReleaseChannel(dmaChannel); dmaChannel= MXC_I2S_TXDMAConfig(i2s_buf, size); //MXC_DMA_Start(0); flash_buf = BUF_SEL(flash_buf, buf0, buf1); // Get next set of audio samples }

3.main audio read and playback if((err = f_read(&file,flash_buf,BUF_READ_SIZE,&bytes_read))!= FR_OK) { printf("Error reading file: %s\n", FF_ERRORS[err]); f_mount(NULL, "", 0); return ; } read_size +=BUF_READ_SIZE; update_first_data(flash_buf,BUF_READ_SIZE); while(read_size<file_size) { for(int i= 0;i<file_size;i+=BUF_READ_SIZE) { //LED_Toggle(0); //LED_Toggle(1); if((err = f_read(&file,flash_buf,BUF_READ_SIZE,&bytes_read))!= FR_OK) { printf("Error reading file: %s\n", FF_ERRORS[err]); f_mount(NULL, "", 0); return ; } read_size +=BUF_READ_SIZE; update_frame_data(flash_buf,BUF_READ_SIZE); } }

BUF_READ_SIZE = sizeof(buf1) = sizeof(buf0)=16000

xinshuwei commented 1 year ago

@Jake-Carter @jessexm my code set also have pop, can you help me?

Jake-Carter commented 1 year ago

@xinshuwei It's a difficult issue to debug remotely.

As Jesse mentioned a double-buffered approach with DMA is recommended.

I would also recommend using f_stream instead of f_read. From the f_read documentation: "If the file needs to be read fast, it should be read in large chunk as possible." f_read is slow. See f_forward for documentation and out_stream for an example where I implemented the data streaming function to stream to UART.

Additionally, have you verified that the sine lookup table you're sending from is perfectly continuous? I would recommend starting and ending blocks of audio data at the Zero-Crossing for a sine wave.

xinshuwei commented 1 year ago

Desktop.zip @Jake-Carter Thanks your reply. 1.I had upload my file, please check.

  1. "f_stream" instead of f_read i will try it, thks.