0

I've implemented some codes in STM32F1 DAC to play some WAV audio files. Because the data is too big (for 44.1K 8Bit Sample rate) and the internal flash is not big enough to store it. My approach is to store it in an SPI external flash, read it buffer by buffer (usually 512 bytes at a time), and plug it into the DAC in normal mode. While this approach works, I'll have to be stuck in the buffer feeding loop and cannot do anything with the MCU (except I terminate the loop but the audio will also stop). I could go with another approach: I read all the audio data into an array and feed it with circular mode, but that will take too much RAM space, which is not practical with larger audio files. Is there another way to achieve both worlds?

while(0 < bytes_last) {

    int blksize = (bitsPerSample == 8)? MIN(bytes_last, BUFSIZE / 2) : MIN(bytes_last, BUFSIZE);

    uint32_t bytes_read = 0;

    if (HAL_SPI_Receive(&SPI_FLASH_HANDLE, fileBuffer, blksize, 1000) != HAL_OK)
                 {
                   /* Transfer error in transmission process */
                   Error_Handler();
                 }
    int i = 0;
    while(i < BUFSIZE){
        if(fileBuffer[i] != 0 && fileBuffer[i] != 0xFF){
            bytes_read++;
            i++;
        }else{
            break;
        }

    }

    uint16_t numSamples = bytes_read / bytesPerSample / channels;
    int16_t     *pInput = (int16_t *)fileBuffer;
    uint16_t   *pOutput = (uint16_t *)dmaBuffer[dmaBank];

    prepareData(channels, numSamples, pInput, pOutput);

    // wait for DMA complete
    while(flg_dma_done == 0) {
      __NOP();
    }

    HAL_DAC_Stop_DMA(&hdac, DAC_CHANNEL_1);
    flg_dma_done = 0;
    HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_1, (uint32_t*)dmaBuffer[dmaBank], numSamples, DAC_ALIGN_12B_R);

    dmaBank = !dmaBank;
    bytes_last -= blksize;
  };

  FLASH_CS_HIGH();
  while(flg_dma_done == 0) {
    __NOP();
  }
Travis Su
  • 670
  • 2
  • 7
  • 17
  • 3
    A typical way to achieve glitch-free audio would be using DMA on the DAC with a circular buffer, and use the half-complete and fully-complete interrupts to trigger loading of new data. While the DAC plays the first half of the buffer, you load data into the second half of the buffer, and vice-versa. The buffer doesn't need to be the size of your file, just big enough that there's time to load new data before the DAC reaches that point. – pmacfarlane Aug 15 '23 at 19:33
  • You'll see more what I mean in my [answer, here](https://stackoverflow.com/questions/75483043/configure-sai-peripheral-on-stm32h7/75489305#75489305). They were using SD-card /SAI rather than flash / DAC but all the same principles apply. – pmacfarlane Aug 15 '23 at 19:43
  • @pmacfarlane I'll look into that! I also found this approach: https://community.st.com/t5/touchgfx-and-gui-mcu/stm32f1-transmit-images-from-external-flash-to-the-lcd-via-spi/td-p/409063 it seems there is a way where DMA can directly access the external Flash via SPI without building buffers in the code base. Not sure it will be the same principles for DAC. – Travis Su Aug 15 '23 at 20:52
  • 1
    DMA with half-full (also double buffer or ping-pong) is an approach that Alsa uses. Also, STM has lots of app notes. They also partnered with *DSP Concepts* and the 'audio weaver' product can target some STM MCUs. https://w.dspconcepts.com/ip I have never used the project, but it does look quite powerful. I have implemented soft-modems with NXP products and the AWE platform looks like it address a lot of problems. If you only have playback, it maybe overkill. – artless noise Aug 16 '23 at 13:41

0 Answers0