ClassD PWM Questions

Technical questions regarding the xTIMEcomposer, xSOFTip Explorer and Programming with XMOS.
User avatar
Andy
Respected Member
Posts: 279
Joined: Fri Dec 11, 2009 1:34 pm

Re: ClassD PWM Questions

Postby Andy » Wed Mar 10, 2010 11:35 pm

Woody wrote:You need to check the volume or override it to maximum all the time. You'd be surprised how loud the audio can be when the PWM just looks like a square wave. Tiny modulations have quite a big effect.

From memory there should be a SOF every 1ms, so that's 44.1 samples for each SOF per channel. The L and R samples are interlaced.
Ah of course! I wasn't setting the volume and didn't notice it is 0 as default - thanks for pointing this out.

It now looks like the sine wave is outputting correctly on the waveform... what cut-off frequency should I be aiming for with the RC filter?
User avatar
Andy
Respected Member
Posts: 279
Joined: Fri Dec 11, 2009 1:34 pm

Postby Andy » Thu Mar 11, 2010 12:48 am

I also can't seem to get the sample input timing correct as I keep underflowing or overflowing after about a second. My sample sender test function looks like:

Code: Select all

while(1)
	{
	    select
	    {
	       case cSOFGen :> int _:
	         for (int i=0; i < 88; i++)
	  	 {
	  	     PCM <: (unsigned)0xFFFF;
	  	 }
	  	 cSOFGen <: 1;	// ACK
	         break;
	       default:
	          break;
	    }
	}
However a value of 88 is giving me underflow:

Code: Select all

USB Buf flow err.  Exp: 0xCC88  Act: 0xCB88  Count: 0
USB sample buffer underflow
and 89 is giving overflow. Is this failing because the sample (usb) input timing has to be exact?
User avatar
Woody
XCore Addict
Posts: 165
Joined: Wed Feb 10, 2010 2:32 pm

Postby Woody » Thu Mar 11, 2010 10:32 am

RC
Andy wrote:what cut-off frequency should I be aiming for with the RC filter?
Obviously an RC isn't going to give you an exceptional filter performance, but I found it very useful. You may have audio signals you want at 20kHz, this means that you'll get the alias of that signal (that you need to filter out) at (44.1kHz*8)-20kHz=332.8kHz.

An RC isn't going to let you have a 3dB point at 20kHz and 60dB of attentuation at 332.8kHz, so you'll need to know how much supression you need at higher frequencies, and pick your RC values accordingly.

Underflow/Overflow
The PWM output always issues 8 PWM pulses for each sample it expects at 44.1kHz. So if you're only supplying data at 44kHz (88 samples per ms) you're going to underflow, but if you give it 89 samples per ms that's 44.5kHz and you'll overflow. You need to give it an average of exactly 1 sample per PWM_PERIOD_44100 (timed on a timer), otherwise you'll over/underflow.
User avatar
Andy
Respected Member
Posts: 279
Joined: Fri Dec 11, 2009 1:34 pm

Postby Andy » Thu Mar 11, 2010 2:23 pm

I seem to be getting closer but my method of timing doesn't seem quite right. I'm slightly confused how to average 44.1kHz over one frame...

Code: Select all

	  				for (int i=0; i < 88; i++)
	  				{
	  					t :> time;
	  					PCM <: sample;
	  					time += PWM_PERIOD_44100;
	  					t when timerafter(time) :> void;
	  				}
Here the timing is better but I'm stilling only sending 88 samples per frame?
User avatar
Woody
XCore Addict
Posts: 165
Joined: Wed Feb 10, 2010 2:32 pm

Postby Woody » Thu Mar 11, 2010 3:32 pm

You don't want to read the time new each loop. Instead read it once then just keep adding the sample period. E.g.

Code: Select all

  t :> time;
  while (1)
  {
    PCM <: sample;
    time += PWM_PERIOD_44100;
    t when timerafter(time) :> void;
  }
That way you don't get a couple of extra instructions delay per sample.
User avatar
Andy
Respected Member
Posts: 279
Joined: Fri Dec 11, 2009 1:34 pm

Postby Andy » Thu Mar 11, 2010 3:39 pm

Should I be sending samples in an infinite loop? I'm unsure how to respond to SOF requests if this is the case.

I've moved the timer outside the loop but I'm still underflowing by a smaller amount:

Code: Select all

USB Buf flow err.  Exp: 0xDC00  Act: 0xDB00  Count: 0
USB sample buffer underflow
Any suggestions?
User avatar
Woody
XCore Addict
Posts: 165
Joined: Wed Feb 10, 2010 2:32 pm

Postby Woody » Thu Mar 11, 2010 5:20 pm

Presumably you aren't actually getting your sample from a USB interface are you? Assuming not, you don't need to send a SOF anywhere! Where is the source of your samples?
User avatar
Andy
Respected Member
Posts: 279
Joined: Fri Dec 11, 2009 1:34 pm

Postby Andy » Fri Mar 12, 2010 2:24 pm

The samples will be coming from a MP3 decoder running on another another core. I assumed I needed the SOF stuff to keep the sample timing correct?

If I get rid of this case in the select statement

Code: Select all

case tSOF when timerafter(timeSOF) :> int _ :

and just stream 'samples' across a channel to the audioManager() in an infinite loop using

Code: Select all

t :> time;
  while (1)
  {
    PCM <: sample;
    time += PWM_PERIOD_44100;
    t when timerafter(time) :> void;
  }
I seem to overflow the buffer immediately

Code: Select all

USB sample buffer overflow
USB sample buffer overflow
Am I missing something?
User avatar
Andy
Respected Member
Posts: 279
Joined: Fri Dec 11, 2009 1:34 pm

Postby Andy » Fri Mar 12, 2010 3:58 pm

If I double the buffer size I start to see output before it overflows

Code: Select all

#define USB_SAMPLE_BUFFER_SIZE               512
#define USB_SAMPLE_BUFFER_INIT               256
#define USB_SAMPLE_BUFFER_PTR_MASK            511
but the sample input timing starts to change

Image

Is this the expected behaviour? (Port C is the output from #define DEBUG RX_SAMPLE)
User avatar
Andy
Respected Member
Posts: 279
Joined: Fri Dec 11, 2009 1:34 pm

Postby Andy » Fri Mar 12, 2010 4:56 pm

Strangely, changing the timing from

Code: Select all

time += PWM_PERIOD_44100
to

Code: Select all

time += (PWM_PERIOD_44100 * 4);
has fixed it. Why 4 I'm not quite sure.

Image

Who is online

Users browsing this forum: No registered users and 0 guests