12 Bit PWM Sound Output and Math all in one Thread

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
williamk
Experienced Member
Posts: 114
Joined: Fri Oct 01, 2010 7:47 pm

12 Bit PWM Sound Output and Math all in one Thread

Post by williamk »

Guys, bear with me on this one, as I'm just starting up. I read the XC manual for months now, but I still don't get some things. I'm posting here to keep you updated on what I'm trying, and seeking any advice along the way. I will, eventually, figure things out, but any help in advance will be much appreciated, so I don't spend hours trying to re-invent the wheel; something I tend to do often... :oops:

Edit: actually so far I only got 12 bits, not 16 bits.

The idea I have is very simple: create in a single thread a PWM 16-bit audio output and also the Math that will produce this audio output. I have done that before, but not with a XMOS chip.

1) Set output speaker port to 1 then use a port timer to toggle the port back to 0 after a X time, which will determinate the PWM output. If the sound output is zero, nothing is done. The time will be set form the last math done for the audio. So there will be one sample delay.

2) do all the math for the next sample, them hold until the end of this sample-rate block.

This should be very simple to handle, but I'm tied up in the MATH that follows... :shock:

The design would like like this:

- If Sound > 0 { set Speaker Port to 1 and store Speaker Port to Port-Timer variable. Also start another timer variable with the sample-rate time , them set Speaker Port to 0 @ PWM time for the last computed Sound variable }
- Do all the math for the next Sound variable
- sample-rate timer hold until the next frame

Makes sense? ;-)

Wk
Last edited by williamk on Tue Sep 13, 2011 6:51 pm, edited 1 time in total.


Wusik Dot Com (http://www.Wusik.com)
William-K.com (http://www.William-K.com)
User avatar
williamk
Experienced Member
Posts: 114
Joined: Fri Oct 01, 2010 7:47 pm

Post by williamk »

This is what I got so far, which, doesn't work correctly. I'm pretty sure I'm doing it all wrong, but heck, at least I got somewhere. It does produce sound, but not in the right way.

Code: Select all

#include <platform.h>
#include <xs1.h>
#include <platform.h>

out buffered port:1 speaker = PORT_SPEAKER;
clock clk = XS1_CLKBLK_1;

int main (void)
{
	int count;
	unsigned int soundOut = 0;
	unsigned int soundRate = 0;
	unsigned int soundRateCounter = 0;
	unsigned time;
	timer t;

	configure_clock_rate(clk, 100, 1); 		// 100 Mhz
	configure_out_port(speaker, clk, 0);	// Set Clock to Port
	start_clock(clk);
	t :> time;

	// 12 bits = 0 to 2500 * 40 Khz = 100 Mhz

	while (1)
	{

		if (soundOut > 0)
		{
			speaker <: 1 @ count;  					// Find out the current port time
			count += soundOut;
			speaker @ count <: 0;
		}

		// Calculate the next soundOutTime //
		soundOut += soundRate;
		if (soundOut > 2500) soundOut = 0;

		soundRateCounter++;
		if (soundRateCounter > 5000)
		{
			soundRateCounter = 0;
			soundRate++;
			if (soundRate > 2500) soundRate = 0;
		}

		time += 2500;
		t when timerafter(time) :> time;
	}

	return 0;
}
Wusik Dot Com (http://www.Wusik.com)
William-K.com (http://www.William-K.com)
MaxFlashrom
Experienced Member
Posts: 82
Joined: Fri Nov 05, 2010 2:59 pm

Post by MaxFlashrom »

Has anyone tried making a 1-bit DAC using PDM and a simple 1 pole RC filter or an LC/ Pi filter
as detailed here. See pseudo-code at the bottom of the page.
http://en.wikipedia.org/wiki/Pulse-density_modulation

I imagine at the high frequency waveforms one can generate with XMOS, that a passable result could be produced. How many bits worth equivalent could one get at say 50MHz/20ns min pulse width?

Has anyone done the maths?
Max.
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

XMOS made an example with both SW and HW with power FETs on a PCB.

It was available from the XMOS site, and can be found on github.
https://github.com/xcore/sc_class_d_amplifier

XMOS has a first order modulator.
I wrote a higher order myself with optimized coeffs, but I never pushed it to GIT.

PWM is the special case of PDM, but not the other way, so from my perspective the methods should be namned pdmxxx and not pwm xx in the module.
Probably not the most confused programmer anymore on the XCORE forum.
User avatar
williamk
Experienced Member
Posts: 114
Joined: Fri Oct 01, 2010 7:47 pm

Post by williamk »

I'm actually wondering if I should just go ahead and use a 16 bit DAC, like this one: Philips TDA1543 - I got 2 of those already here, so I may do some tests.

Them I could serialize 16 bits using a 1 bit port with the required clock output. I have to check if I can make the clock run lower as required by the chip.

Wk
Wusik Dot Com (http://www.Wusik.com)
William-K.com (http://www.William-K.com)
MaxFlashrom
Experienced Member
Posts: 82
Joined: Fri Nov 05, 2010 2:59 pm

Post by MaxFlashrom »

lilltroll wrote:XMOS made an example with both SW and HW with power FETs on a PCB.

It was available from the XMOS site, and can be found on github.
https://github.com/xcore/sc_class_d_amplifier

XMOS has a first order modulator.
I wrote a higher order myself with optimized coeffs, but I never pushed it to GIT.

PWM is the special case of PDM, but not the other way, so from my perspective the methods should be namned pdmxxx and not pwm xx in the module.
Lilltroll, thanks for the pointers. That's most interesting. Now I just need to research SACD, Sigma-Delta modulators and do a load of Z-transforms :)
Max.
User avatar
williamk
Experienced Member
Posts: 114
Joined: Fri Oct 01, 2010 7:47 pm

Post by williamk »

williamk wrote:I'm actually wondering if I should just go ahead and use a 16 bit DAC, like this one: Philips TDA1543 - I got 2 of those already here, so I may do some tests.

Them I could serialize 16 bits using a 1 bit port with the required clock output. I have to check if I can make the clock run lower as required by the chip.

Wk

So far I couldn't make it work, can't figure out things yet. So any help would be much appreciated. 8-)

Thanks, Wk
Wusik Dot Com (http://www.Wusik.com)
William-K.com (http://www.William-K.com)
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

BCLocK must be below 9.2 MHz with the TDA, so you cannot use the > 10 MHz clock as it is on the XMOS card, but othervise it should work.g

You may create a slower clock for testing by writing 0xFFFF0000 to a 1 bit buffered port in an infinite loop.
That will create a 1 for 16 cycles and a 0 for 16 cycles, e.g. a 3.125 MHz signal. (on a 400 MHz chip)

0xFF00FF00 => 6.25 MHz (on a 400 MHz chip)

It might jitter a little, so you will probably not have 16 ENOB, but good for testing it out.
Probably not the most confused programmer anymore on the XCORE forum.
User avatar
williamk
Experienced Member
Posts: 114
Joined: Fri Oct 01, 2010 7:47 pm

Post by williamk »

But what other type of clock could I generate them? I'm a bit lost on this, and don't have much free time to work on it for now. :(

Wl

See my updated post/ lilltroll
Wusik Dot Com (http://www.Wusik.com)
William-K.com (http://www.William-K.com)
User avatar
williamk
Experienced Member
Posts: 114
Joined: Fri Oct 01, 2010 7:47 pm

Post by williamk »

williamk wrote:This is what I got so far, which, doesn't work correctly. I'm pretty sure I'm doing it all wrong, but heck, at least I got somewhere. It does produce sound, but not in the right way.

Code: Select all

#include <platform.h>
#include <xs1.h>
#include <platform.h>

out buffered port:1 speaker = PORT_SPEAKER;
clock clk = XS1_CLKBLK_1;

int main (void)
{
	int count;
	unsigned int soundOut = 0;
	unsigned int soundRate = 0;
	unsigned int soundRateCounter = 0;
	unsigned time;
	timer t;

	configure_clock_rate(clk, 100, 1); 		// 100 Mhz
	configure_out_port(speaker, clk, 0);	// Set Clock to Port
	start_clock(clk);
	t :> time;

	// 12 bits = 0 to 2500 * 40 Khz = 100 Mhz

	while (1)
	{

		if (soundOut > 0)
		{
			speaker <: 1 @ count;  					// Find out the current port time
			count += soundOut;
			speaker @ count <: 0;
		}

		// Calculate the next soundOutTime //
		soundOut += soundRate;
		if (soundOut > 2500) soundOut = 0;

		soundRateCounter++;
		if (soundRateCounter > 5000)
		{
			soundRateCounter = 0;
			soundRate++;
			if (soundRate > 2500) soundRate = 0;
		}

		time += 2500;
		t when timerafter(time) :> time;
	}

	return 0;
}

My code above, I still don't get why it doesn't work. Any tips would be much appreciated. :oops:

Best Regards, WilliamK
Wusik Dot Com (http://www.Wusik.com)
William-K.com (http://www.William-K.com)