Play sound file using PIC24 - Page 1
Forum section: electronics / general

author: aurmer
author_rank: Regular Contributor
timestamp: May 23, 2016, 11:24:50 pm
content: BACKGROUND: I am in the design phase of this project. I have tentatively selected the PIC24FJ64GA004http://www.microchip.com/wwwproducts/en/PIC24FJ64GA004](http://www.microchip.com/wwwproducts/en/PIC24FJ64GA004) as my controller.This widget will be produced in large quantities, so low cost and minimizing chip count is our priority.DESIGN SPEC: The widget will play sound files on demand. This is my first time playing sound from a µC, and believe I understand the most basic design...-downsample original CD quality (8bit, 4k-8kHz)-drive data on 8 output pins to an external DAC-amplify DAC output-connect speakerI have come here to ask the pro's. What considerations will I need in my design? I have a few in mind already, but what am I missing?-- sufficient storage capacity for raw sound data.-- DAC bandwidth-- Volume control in the amp circuit--

author: aurmer
author_rank: Regular Contributor
timestamp: May 23, 2016, 11:26:20 pm
content: Alternatively, how could I design this to use fewer pins than the 8-bit width of the data?

author: ataradov
author_rank: Super Contributor
timestamp: May 23, 2016, 11:48:35 pm
content: Quote from: zetharx on May 23, 2016, 11:26:20 pmUse a micro with DAC peripheral. Or use PWM.

author: JPortici
author_rank: Super Contributor
timestamp: May 24, 2016, 06:40:50 am
content: since quality does not seem to be a concern.. choose a mcu which has a dac on board: simpler code, less board space and even if the mcu cost like 1 more a dac would have its cost too.Actually at 8KHz the timebase for 8bit resolution PWM has to be 2.048 MHz which is not that high for a pic16 so in this case you might be good with pwmrequirements.. requirements... oh yeah.-are the samples stored on internal memory?-on external memory?-which kind of memory anyway? on rom? on ram?-how many of them? how long are they?-do you plan to generate them on board? or to load them and then the mcu downsamples there? or load the downsampled files directly?-do you plan to use compression algorythms to increase number of samples?-does everything have to run on batteries?any possibly others

author: lwatts666
author_rank: Unknown
timestamp: May 24, 2016, 06:44:27 am
content: If quality is not a major issue, but cost is, take a look at:http://dmitry.gr/index.php?r=05.Projects&proj=02.%20Single-chip%20audio%20Player

author: dannyf
author_rank: Super Contributor
timestamp: May 24, 2016, 11:09:49 am
content: QuoteIt should work. However, you may want to consider how much processing power it has left for anything else. I haven't looked at the datasheet but something like this is best done via DMA, with no cpu involvement.Short of that, you will need to do it in a timer isr. Assuming a 24Mhz crystal, 12Mhz clock rate, 8Khz signal, 16x samples per period, -> ~100 ticks per isr. 20 ticks overhead, 20 - 30 ticks processing, and your cpu is 50% spent.So if the cpu is handling something, you want to pick a chip that supports dma.

author: tszaboo
author_rank: Super Contributor
timestamp: May 24, 2016, 12:15:43 pm
content: First you should listen to that 8 bit 8 KHz. 8KHz is enought to make speech intelligiblehttp://support.polycom.com/global/documents/support/technical/products/voice/soundstation_vtx1000_wp_effect_bandwidth_speech_intelligibility.pdfbut you need more than 8 bit. I know that phones use 8bit/8KHz, but they also use adaptive PCM or other (PCM) coding for the data. So the data before the encoding is actually 12-13 bit. If it is only jinnglebells, than ignore this and proceed.You can sum two PWMs to gain resolution.Use waw for data storage. Strip the first 40ish bytes from the front.

author: bktemp
author_rank: Super Contributor
timestamp: May 24, 2016, 12:39:39 pm
content: Quote from: NANDBlog on May 24, 2016, 12:15:43 pmPhones use uLAW or aLAW (a simple 8bit floating point format for expanding the dynamic range without much processing power). ADPCM was widely used when speech needed to be stored in a small memory (like DRAMs in digital answering machines). Depending on the required quality 2-4bits per sample were common.8bit sounds fine if the volume does not change much. More important than 2/3/4/8bits is an antialiasing filter after the dac. Without such a lowpass filter 8kHz samplerate are much worse.Here is another great project for playing audio data using a small microcontroller:http://elm-chan.org/works/sd20p/report.htmlhttp://elm-chan.org/works/sd8p/report.htmlhttp://elm-chan.org/works/pcmp/report.html

author: aurmer
author_rank: Regular Contributor
timestamp: May 29, 2016, 03:18:51 pm
content: Quote from: JPortici on May 24, 2016, 06:40:50 amI will pre-process the downsampling, and as of now, I plan to hard-code the bytes into the program. I have a 14 second track which will go into program memory, and that is about it. I may have to pick an MCU with more flash memory, but I am not really putting much on there. I think the 14 seconds will run in the neighborhood of 100kB.The widget uses a lot of LEDs, and I because of that, I already ruled out batteries.Quote from: lwatts666 on May 24, 2016, 06:44:27 amWow, that is a fantastic help to navigating the pwm solution. This resource may end up changing the way I plan to do it.Quote from: dannyf on May 24, 2016, 11:09:49 amI hadn't considered the cpu load. Thank you for pointing it out, I will be sure to test all my functionality to find if I need to up my clock speed, or go the route of DMA like you suggested.Quote from: NANDBlog on May 24, 2016, 12:15:43 pmThank you for noting the concern about quality. I have already downsampled the desired track using Audacity, and I know what it sounds like. It is acceptable.Quote from: bktemp on May 24, 2016, 12:39:39 pmThank you, it is nice to be able to stand on the shoulders of giants. =)

author: aurmer
author_rank: Regular Contributor
timestamp: May 29, 2016, 03:31:18 pm
content: Thanks to everyone for your suggestions. I am very interested in learning more about how this gentleman made his player.Quote from: lwatts666 on May 24, 2016, 06:44:27 amBasically, I do not understand how a waveform is approximated/emulated using PWM. I leave now to ask Google, but if someone knows of a good resource on the subject of "analog signal by PWM", I appreciate any links.

author: Kalvin
author_rank: Super Contributor
timestamp: May 29, 2016, 03:46:07 pm
content: Quote from: zetharx on May 29, 2016, 03:31:18 pmThis may help you to get started:http://www.openmusiclabs.com/learning/digital/pwm-dac.1.htmlhttp://wiki.openmusiclabs.com/wiki/PWMDACGoogle with the following magic keywords to get more technical explanation: PWM DAC

author: aurmer
author_rank: Regular Contributor
timestamp: May 29, 2016, 03:48:25 pm
content: Okay, that research was actually child's play. Don't know why I felt any intimidation about using PWM as a DAC.I will definitely shop for a PIC that has the proper speed and internal components so that I can reduce my chip count.Thanks again to all contributors.

author: aurmer
author_rank: Regular Contributor
timestamp: May 29, 2016, 04:43:12 pm
content: Now my next unknown; how do I determine the necessary clock speed? I understand the basics, but am I missing anything? I need to determine the maximum theoretical processing load that my program will put on the hardware.-I have an interrupt to count seconds (the widget has an internal clock and knows the time of day). This should be a VERY low processing load.-I have an interrupt during music playback which updates output for each sample (8kHz rate). This will by far be the highest portion of the processing load.-I have other sensor inputs which will be read every 15 seconds or so. Negligible processing load.Considerations:-As the widget will keep track of the time of day (and we don't want to accumulate drift); timekeeping is the highest priority. Even when playing sound, keeping time will take priority over updating the sound output on time.-Sensor updates are simply updated, not logged. So if needed, I will turn off sensor updates while playing sound. Sensor updates can resume afterward with no functional consequence.I know my clock speed, therefore I know my instruction frequency. I need to learn how to count the number of instructions in a function so I can know how long it takes to run that function.How many instructions does it take to trigger an interrupt, update the PWM output, and leave the interrupt sequence? I read through my datasheet on timer interrupts, but it is just a little bit heavy for my level of experience.

author: Howardlong
author_rank: Super Contributor
timestamp: May 29, 2016, 05:08:22 pm
content: For this, to measure it empirically I use a GPIO pin and twiddle it on entry and exit from the ISR, measuring the GPIO pulse with a scope.Alternatively, use a timer to measure it, using a volatile global that you print out through the UART outside of the ISR, or berakpoints with a timer and a debugger watch, or the device simulator to measure actual clocks cycles.Rule of thumb, always keep at least one spare GPIO pin for real time debugging!What you are proposing is very well within the capabilities of the PIC you specify.

author: Bruce Abbott
author_rank: Frequent Contributor
timestamp: May 29, 2016, 08:20:05 pm
content: Quote from: zetharx on May 29, 2016, 04:43:12 pmYou don't want anything interrupting the sound while it is playing or it may be audible. The sound playback code should be quite simple and not take many cycles, so it could be done inside the ISR and still leave plenty of time left to handle time of day interrupts.To put it another way - the important thing is not what has the highest priority, but what requires the lowestlatency. If you are measuring time of day in seconds then there is no need for it to have microsecond accuracy, you just have to ensure that ticker interrupts don't get missed.You probably wouldn't hear the effect of an occasional sound sample being delayed or missed, but if it occurs at regular intervals it could become noticeable. At 8KHz the samples should be spaced 125us apart. A bit of jitter between samples is OK so long as the rate doesn't change (just like with the time of day clock). But if a higher priority task causes a sound interrupt to be missed then it will momentarily lower the playback speed, causing the sound to 'warble' as the speed changes.

author: Someone
author_rank: Super Contributor
timestamp: May 30, 2016, 12:42:14 am
content: Quote from: zetharx on May 29, 2016, 04:43:12 pmThose parts have a hardware realtime clock, this will be more robust if you need accurate time keeping.

author: JPortici
author_rank: Super Contributor
timestamp: May 30, 2016, 07:55:12 am
content: Quotefamily Refernce manual, section 8: Interrupts.http://ww1.microchip.com/downloads/en/DeviceDoc/39707a.pdfparagraph 8.3: Interrupt processing timingthen you look at the disassembly of the ISR. In a 24F it is 1 instruction cycle per instruction, with exception for branches if they are taken, GOTOs and such (you find that in the instruction set section / programmer's reference manual)your isr should do only this-fetch the sample from the sample buffer (use a ram buffer. two instructions -> mov RAM into WREGx and mov WREGx to whatever peripheral register instead of setting up a table read to fetch data from flash memory)-put the buffer into whatever (Output port, CCP Period register, internal DAC register, ...)-update the sample buffer index for next read/write on the buffer

author: Howardlong
author_rank: Super Contributor
timestamp: May 30, 2016, 11:37:39 am
content: To.minimise jitter, you can use a static in your ISR to store the last calculated sample, but only load it immediately on entry at the next invokation of the ISR, so any jitter due to different program flows within the ISR, for example as a result of buffer management, can be discounted.As already mentioned, the trick is always to aim to keep you ISRs as svelt and deterministic as possible, and do any processing in advance such as preparing buffers in the super loop. Non-deterministic behaviour in the ISR can be a real headache to debug, and should be minimised.