I need to reproduce a short audio stream with a Cortex-M0+ MCU (it's SAM D21E from Atmel/Microchip). The audio bitstream will be stored in an external SPI Flash memory (I need to manage many short audio streams, so the internal Flash memory is not sufficient). SAMD21 features DAC, SPI and DMA. The audio will not be high-fidelity. 8 bits at 8kHz sampling frequency is enough. I didn't make many tests, but I think I can use streams with lower bitrates. Here the problem isn't the compress ratio, i.e. reducing the memory requirements to store all the streams, but to arrange an effective way to transfer samples from external Flash to DAC. The simplest method I think is to configure the SPI transfer rate exactly at 8kHz, by calibrating the SPI clock (I think I can do): every 125us=8kHz a new sample is received, an interrupt is raised and the value is moved to the DAC register. The only problem I see for this method is that the MCU must be interrupted every 125us. The MCU will run at 48MHz and should manage a serial RS485 38400bps (260us) too. One solution to free the MCU is to use the DMA peripheral, but I never used it in the past. Will it be possible to use DMA to automatically move the byte received from SPI to DAC register, without interrupting the normal execution code? Of course this "direct method" (from external memory to DAC output, without processing) can be done with uncompressed 8-bits samples audio streams. If I need to reduce the memory requirements, I need to use a compress (even simple) algorithm... there are many. Anyway in this case I can't move the samples from SPI to DAC, because I need to uncompress the samples. Is it possible to use a normal (not DSP) Cortex-M0+ MCU to play a compressed audio stream? If yes, what is the best method to: - arrange the load of compressed stream from external memory - uncompress the input stream - move the uncompressed samples to DAC Here the SPI input transfer rate is not perfectly syncronized with the DAC output transfer rate (fixed at 64kHz). I think I have to manage a FIFO buffer with two thresholds. When the FIFO is full over first threshold, the SPI transfer is stopped. When the FIFO is empty lower than the second threshold, the SPI transfer is started again. Are there some examples to study?
Play an audio stream with a Cortex-M0+
Started by ●May 3, 2017
Reply by ●May 3, 20172017-05-03
Il giorno mercoledì 3 maggio 2017 12:22:22 UTC+2, pozz ha scritto:> I need to reproduce a short audio stream with a Cortex-M0+ MCU (it's SAM > D21E from Atmel/Microchip). The audio bitstream will be stored in an > external SPI Flash memory (I need to manage many short audio streams, so > the internal Flash memory is not sufficient). > SAMD21 features DAC, SPI and DMA. > > The audio will not be high-fidelity. 8 bits at 8kHz sampling frequency > is enough. I didn't make many tests, but I think I can use streams with > lower bitrates. > > Here the problem isn't the compress ratio, i.e. reducing the memory > requirements to store all the streams, but to arrange an effective way > to transfer samples from external Flash to DAC. > > The simplest method I think is to configure the SPI transfer rate > exactly at 8kHz, by calibrating the SPI clock (I think I can do): every > 125us=8kHz a new sample is received, an interrupt is raised and the > value is moved to the DAC register. > > The only problem I see for this method is that the MCU must be > interrupted every 125us. The MCU will run at 48MHz and should manage a > serial RS485 38400bps (260us) too. > > One solution to free the MCU is to use the DMA peripheral, but I never > used it in the past. Will it be possible to use DMA to automatically > move the byte received from SPI to DAC register, without interrupting > the normal execution code? > > Of course this "direct method" (from external memory to DAC output, > without processing) can be done with uncompressed 8-bits samples audio > streams. > If I need to reduce the memory requirements, I need to use a compress > (even simple) algorithm... there are many. Anyway in this case I can't > move the samples from SPI to DAC, because I need to uncompress the samples. > > Is it possible to use a normal (not DSP) Cortex-M0+ MCU to play a > compressed audio stream? If yes, what is the best method to: > - arrange the load of compressed stream from external memory > - uncompress the input stream > - move the uncompressed samples to DAC > Here the SPI input transfer rate is not perfectly syncronized with the > DAC output transfer rate (fixed at 64kHz). I think I have to manage a > FIFO buffer with two thresholds. When the FIFO is full over first > threshold, the SPI transfer is stopped. When the FIFO is empty lower > than the second threshold, the SPI transfer is started again. > > Are there some examples to study?mbed.org has a mp3 player that works on M0+. Use DMA to fill the audio buffer from SPI. Maybe You may also use the DMA to feed the DAC. Bye Jack
Reply by ●May 3, 20172017-05-03
Pumping audio from storage to speaker is a matter of keeping the pipeline full so the the output pointer is always ahead of the input pointer. You'll need some amount of buffer memory for that. Start by loading your buffer, and when it reaches some comfortable level of playable data, start outputting it. While you're waiting for the output mechanism to drain your buffer to some tolerably low level, you can be filling the pipe from SPI memory. DMA varies among MCUs so only you will know about that. I suspect DMA will be the key to your success unless your MCU is extremely fast or unloaded, in whcih case you might not need it. I suggest you use it if you have it. I've had good results using mu-law compression when fidelity expectations are low. You can find mu-law codec code on the web. You might find that compression is not needed. Large SPI memory devices are cheap and PCM wave files aren't that big so storage limitations should be ok for you (YMMV, of course). JJS
Reply by ●May 5, 20172017-05-05
On Wed, 03 May 2017 12:22:15 +0200, pozz wrote:> I need to reproduce a short audio stream with a Cortex-M0+ MCU (it's SAM > D21E from Atmel/Microchip). The audio bitstream will be stored in an > external SPI Flash memory (I need to manage many short audio streams, so > the internal Flash memory is not sufficient). > SAMD21 features DAC, SPI and DMA. > > The audio will not be high-fidelity. 8 bits at 8kHz sampling frequency > is enough. I didn't make many tests, but I think I can use streams with > lower bitrates. > > Here the problem isn't the compress ratio, i.e. reducing the memory > requirements to store all the streams, but to arrange an effective way > to transfer samples from external Flash to DAC. > > The simplest method I think is to configure the SPI transfer rate > exactly at 8kHz, by calibrating the SPI clock (I think I can do): every > 125us=8kHz a new sample is received, an interrupt is raised and the > value is moved to the DAC register. > > The only problem I see for this method is that the MCU must be > interrupted every 125us. The MCU will run at 48MHz and should manage a > serial RS485 38400bps (260us) too. > > One solution to free the MCU is to use the DMA peripheral, but I never > used it in the past. Will it be possible to use DMA to automatically > move the byte received from SPI to DAC register, without interrupting > the normal execution code? > > Of course this "direct method" (from external memory to DAC output, > without processing) can be done with uncompressed 8-bits samples audio > streams. > If I need to reduce the memory requirements, I need to use a compress > (even simple) algorithm... there are many. Anyway in this case I can't > move the samples from SPI to DAC, because I need to uncompress the samples. > > Is it possible to use a normal (not DSP) Cortex-M0+ MCU to play a > compressed audio stream? If yes, what is the best method to: > - arrange the load of compressed stream from external memory > - uncompress the input stream > - move the uncompressed samples to DAC > Here the SPI input transfer rate is not perfectly syncronized with the > DAC output transfer rate (fixed at 64kHz). I think I have to manage a > FIFO buffer with two thresholds. When the FIFO is full over first > threshold, the SPI transfer is stopped. When the FIFO is empty lower > than the second threshold, the SPI transfer is started again. > > Are there some examples to study?I know the M3 supports peripheral to peripheral DMA but I'm not sure about the M0. It's not that hard to set up the channels once you kind of get your head around it. Transfer chaining makes it a lot easier. SPI read is a little of an issue as you have to keep the DMA controller issuing SCLKs. If the M0 will do p to p you should be able to setup the DMA descriptors, fire and forget until you get the final transfer complete interrupt. -- Chisolm Republic of Texas