TMRpcm wav playback library

Please do not post requests
victor_pv
Posts: 1864
Joined: Mon Apr 27, 2015 12:12 pm

TMRpcm wav playback library

Post by victor_pv » Tue Jun 30, 2015 8:48 pm

I needed to be able to play some sounds and decided to give a shot to porting this library, which reproduces audio in the Arduino using the timers in PWM output mode.
https://github.com/TMRh20/TMRpcm/wiki

I am almost done porting it, although I am removing a bunch of options that are very specific to AVR, but the function call are going to be the same with the same functionality and hopefully good compatibility with different wav files. I have never used the library in Arduino but have heard some audio with pwm before and is good enough for what I need.
I am using interrupts at first, and probably will use DMA later to free up CPU.
I'll make the port available once finished. I am not planing for 16 bit quality, but should be fairly easy to implement just using 2 CC for each output, and combining them with some resistors. Anyway I'll use a whole timer, so using 1 or 2 outputs per channel just means using 2 more pins.

victor_pv
Posts: 1864
Joined: Mon Apr 27, 2015 12:12 pm

Re: TMRpcm wav playback library

Post by victor_pv » Thu Jul 02, 2015 1:35 pm

Just a quick update for anyone that read this thread, I have the library compiling without any errors now.
I need to wire a filter and speaker and test it out.

User avatar
RogerClark
Posts: 7683
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: TMRpcm wav playback library

Post by RogerClark » Fri Jul 03, 2015 4:02 am

Victor,

Thanks for letting the community know how this is going. I imagine the playback quality should be better than on AVR as the sample rate etc should be higher

victor_pv
Posts: 1864
Joined: Mon Apr 27, 2015 12:12 pm

Re: TMRpcm wav playback library

Post by victor_pv » Sat Jul 04, 2015 9:26 pm

Finally got it working except for the systick callback that should be loading the data from the sd card to the buffer.
I think I can't properly access the sdcard from a function called from an ISR. It may have to do with using interrupts for the SPI port, I may test it later without DMA &interrupts.

Anyway, I moved away from using the class. I removed all the class stuff, and a lot of conditional compiling. For me it works better this way, at least at the moment it works.
I can play different wav files. The quality seems just fair for what it is, plus I am not properly filtering the noise out, I didn't have a small enough capacitor around.
It plays with only 8 bit of resolution, in stereo. Next step is test out using 2 compare channels for each audio channel, to achieve 16bits of resolution, and adding a proper RC low pass filter.
I made a rudimentary amplifier with a BS170, and that works good enough.
Once I have tested it a bit more and have polished the code I'll share it.

The audio playing part should be usable to play any audio, so it may come handy for very small sounds stored in flash, or like I'm using it now, for wav files stored in an SD-Card.

I think the quality can be on par with the ESP8266 mp3 playing library with a proper noise filter.
Last edited by victor_pv on Sun Jul 05, 2015 5:05 am, edited 1 time in total.

User avatar
RogerClark
Posts: 7683
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: TMRpcm wav playback library

Post by RogerClark » Sat Jul 04, 2015 9:33 pm

Hi Victor,

Re:ISR

I read something the other day about interrupt priorities on ARM.

Each ISR input is allocated a priority, the lower the number the higher the priority, i.e. 0 = highest priority.
Interrupts of higher priority can interrupt code already running in a lower priority interrupt.

However, that being said... I didnt think SPI uses an ISR (or does your code use a SPI ISR ?

victor_pv
Posts: 1864
Joined: Mon Apr 27, 2015 12:12 pm

Re: TMRpcm wav playback library

Post by victor_pv » Sun Jul 05, 2015 5:11 am

RogerClark wrote:Hi Victor,

Re:ISR

I read something the other day about interrupt priorities on ARM.

Each ISR input is allocated a priority, the lower the number the higher the priority, i.e. 0 = highest priority.
Interrupts of higher priority can interrupt code already running in a lower priority interrupt.

However, that being said... I didnt think SPI uses an ISR (or does your code use a SPI ISR ?
The DMA SPI uses and interrupt to signal when is the transfer over.
I have been think about it, and as those functions are blocking anyway, we could check the DMA complete bit in a loop, rather than stay on a loop waiting for an interrupt to change a variable.
Now, that is just a theory, I need to set the sdfat library to just not use DMA and test again, so the sdfat library should not depend on any ISR at that point.
If that works, then it's just that, that the systick ISR is not being interrupted by the DMA isr. In that case then next will be checking if I can change the DMA code to loop waiting for a bit in the DMA registers rather than an interrupt.

User avatar
RogerClark
Posts: 7683
Joined: Mon Apr 27, 2015 10:36 am
Location: Melbourne, Australia
Contact:

Re: TMRpcm wav playback library

Post by RogerClark » Sun Jul 05, 2015 6:18 am

Victor

Ideally, we need to move away from blocking functions if possible.

Well blocking functions are OK, but they don't give us the full benefit of DMA, i.e they give slightly faster transfers, but they don't give us the ability that the processor can go off and do other things while the DMA is transferring.

And Ideally, we could run multiple separate SPI DMA's on different channels.

e.g. I built a test rig with an SD card and also a VS1053 MP3 decoder, where the SD is on SPI1 and the MP3 decoder is on SPI2 - however at the moment there is no point in using 2 SPI channels as its impossible to transfer from SD at the same time as its transferring to MP3.

Also if I had a UI on this (which I don't at the moment), it would probably have issues, as most of the time, the code is having to wait for either SD transfer to complete or MP3 transfer to complete - so I'd need to write code that polls for UI stuff

User avatar
mrburnette
Posts: 2207
Joined: Mon Apr 27, 2015 12:50 pm
Location: Greater Atlanta
Contact:

Re: TMRpcm wav playback library

Post by mrburnette » Sun Jul 05, 2015 1:11 pm

RogerClark wrote:Victor

Ideally, we need to move away from blocking functions if possible.

Well blocking functions are OK, <...>

Also if I had a UI on this (which I don't at the moment), it would probably have issues, as most of the time, the code is having to wait for either SD transfer to complete or MP3 transfer to complete - so I'd need to write code that polls for UI stuff
Well, blocking is OK IMO only if the underlying uC slices are managed bY a RTOS to prevent critical stalls in other code sections. Of course - this is not reality as we all have had to work with blocking functions since forever! However, we do not need to unwittingly propagate this paragigm needlessly. Nested priority interrupts provide a mechanism to keep critical routines from starving - but, every system will have different level of "priorities" from the application programmer's reference. Hence, RTOS is typically the better approach, IMO.

More of us should embrace RTOS and modularize code to conform to the requirements for RTOS... even if the RTOS was removed, the resulting code would be superior to my spaghetti :lol:

Ray

victor_pv
Posts: 1864
Joined: Mon Apr 27, 2015 12:12 pm

Re: TMRpcm wav playback library

Post by victor_pv » Sun Jul 05, 2015 2:00 pm

I did some tests with CoOS. I believe I included that with one of the ports of CoOS (there are 2, the old one I found, and the latest version I ported by carrying over the changes in the old one).
Well, that example goes to test whether using some RTOS function in the DMA while loop, so the RTOS inmediately releases the CPU to another task, provides any gain.
I don't remember if I implemented it by using a delay, which is fact causes a task switch in the RTOS, or a Semaphore, which has the same effect, or I even used a new taskswitch function that I found on a forums and I implemented, I would have to look back at it to confirm.

But the result of that test was that having the DMA block in a while loop without any additional "cpu releasing" command, or having it release the CPU for another task had very little or no effect as far as DMA for screen access.

As Ray points out, using the RTOS already takes care of giving CPU to other tasks when you block. I noticed when I looked the ESP8266 mp3 player that they use FreeRTOS, so the ESP can be doing all it's networking stuff, and at the same time running a customer program easily.
I agree with Ray that we should be using it more. I am completely new to it, and still have to learn much, but I already have written a couple of examples to test things out and have been impressed with it.
Recently I wrote a test sketch that measures the CPU usage while running the same Cubes sketch, that rotates 2 cubes in the screen fairly fast.
CPU usage was around 28% only by using a fast DMA driver for the screen.

Next I need to test the wav player under CoOS or FreeRTOS, and I plan on measuring CPU usage for it. My intention is to make the wav player DMA driven.
The bad part is that the DMA channels are shared between different peripherals, so you need to carefully plan which peripherals will use DMA and which will not.

About the SPI DMA blocking, I remember we talked about implementing a callback mechanism and not block, but we decided to block because most current drivers toggle CS and other pins as soon as the SPI call returns, and they would need to be heavily rewritten to manage non blocking SPI access. But with an RTOS we dont need to rewrite anything, just start the DMA and switch task, and let the RTOS scheduler decide what to run next.

Still should be easy to provide for a blocking and a non-blocking option, so when you write a driver for something you can decide if the non-blocking option may work and plan around it from the start.

To encourage anyone to use RTOS, I will publish somewhere the sketch that measures CPU usage and shows it in the screen.
I plan on using it all the time when using an RTOS and perhaps only remove it once the project is finished, but during development I think is a great help.

EDIT: Video showing the cpu usage, next comes adding the wav playing to it, The Black Keys sound awesome even with 8bits ;)
https://www.youtube.com/watch?v=ObeDcXQ7SzA

User avatar
mrburnette
Posts: 2207
Joined: Mon Apr 27, 2015 12:50 pm
Location: Greater Atlanta
Contact:

Re: TMRpcm wav playback library

Post by mrburnette » Sun Jul 05, 2015 10:40 pm

victor_pv wrote:I did some tests with CoOS.
https://www.youtube.com/watch?v=ObeDcXQ7SzA
Yes, impressive!

Ray

Post Reply