This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C123GH6PM: Calculating and Sending Audio Samples to a DAC "On the Fly"

Part Number: TM4C123GH6PM

Hi Guys - I've been playing around with a MAX541 audio DAC chip (datasheet here) and my TM4C123G LaunchPad lately.  I've got audio output working fine, but I'm now trying to get it to play different sine wave tones that are calculated "on the fly" depending on the pitch the user wants to hear.

The way I've designed it is by setting up a "multi-shot" SysTick interrupt that calls the ISR every ~1500 ticks.  The ISR calculates the current sample value and sends it to the MAX541 DAC chip using SSI.

The problem I'm running into is that the pitch I hear is not constant.  It slowly drops in pitch.  What I'm fairly certain is happening is that my "on the fly" sample calculation is taking too long and thus causing a delay in getting the sample value to the DAC for output.

I'm fairly certain about this because I can pre-calculate a single period of sine wave samples into an array - before starting audio playback - then after starting audio playback simply loop through them, sending the sample value at the current index to the DAC and the pitch remains constant in this case.

When using my "on the fly" method, I believe the delay is likely caused by the sin() call from math.h that I need to do when calculating the current sample value.  I've stepped through the code for this function and it runs through MANY instructions.

I'm wondering if anyone has any thoughts or suggestions of any possibilities of getting this to work without the latency issue?

  • Hi Bob,

    I don't know the "audio" part of the story - although I'd love to have time to play with audio generation. But I have some experience with signal.

    There are a few solutions for your sin generation: a table on memory, or on the fly.

    A table on memory with so many sin values is common for very limited MCUs - not really the case for the TM4Cs - still the idea is to define how many "steps" you want (the fine resolution of your sin output), and simply read each multiplier of the table in a sequence.

    Calculating on the fly is not bad: just calculate THE NEXT value way before you need it - in other words, change your signal output, calculate the next value, and go back to doing nothing until it is time for a new change. The new change will be immediate.

    Compare how many cycles does your CPU takes with both the sin 64bits (the default on C compiler, which uses double) and sin 32bits (which uses float - the size of the FPU HW of TM4C) functions. Make sure you enable the floating point in your MCU.

    As for the signal output itself, I suggest you use the PWM peripheral - the sin will actually be a change on the duty.

    Cheers

    Bruno

  • Hi,

    I suggest to look for CORDIC algorithm and this link as an example of implementation in C.

    Also the ARM's CMSIS package has some fast trigonometric functions, either float32 or Q15/Q31.

  • Bruno Saraiva said:

    Compare how many cycles does your CPU takes with both the sin 64bits (the default on C compiler, which uses double) and sin 32bits (which uses float - the size of the FPU HW of TM4C) functions. 

    Bruno - Thanks for the suggestions.  I had completely forgotten about sin(double) vs sinf(float).  Just doing some quick testing right now I see the sinf() function is indeed faster (which makes sense).  Also, yes, I agree, I probably should just be calculating a signal period of the signal I need and then cache it and loop through it.  Thanks again, much appreciated.

  • Petrei said:

    Hi,

    I suggest to look for CORDIC algorithm and this link as an example of implementation in C.

    Also the ARM's CMSIS package has some fast trigonometric functions, either float32 or Q15/Q31.

    Petrei - Thanks for this info!  I was not aware of this CORDIC algorithm or ARM's CMSIS.  I found this document to learn how to use it with TI's Code Composer and am reading it now.