need help with pwm filter design

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,
I'm trying to generate two constant 1 kHz sine waves using timer1. I'm pretty sure I've got the code running right but I'm having trouble getting an actual sine wave out of the RC lowpass filter I tacked onto the output of OC1A and OC1B. I started out using AVR131 but that doesn't actually tell you how to size the filter. http://ww1.microchip.com/downloads/en/AppNotes/00538c.pdf is the best info I've found so far but with my PWM frequency set at 80kHz and values of 100k and 1000pF for my filter I'm getting nothing but rounded square waves. Could anyone tell me what I'm doing wrong or tell me where I should set my corner frequency? Here is my code if that helps:

//sig_gen.c
#include
#include
#include  

#define TOP 		199
#define PULSECOUNT 	80

void HWInit();


uint8_t LUTable[PULSECOUNT]= 	{0x6C,0x73,0x7B,0x83,0x8A,0x91,0x98,0x9E,0xA4,0xAA,0xAF,0xB4,0xB8,0xBC,0xBF,0xC2,0xC4,0xC6,0xC7,0xC7,
						0xC7,0xC6,0xC4,0xC2,0xBF,0xBC,0xB8,0xB4,0xAF,0xAA,0xA4,0x9E,0x98,0x91,0x8A,0x83,0x7B,0x73,0x6C,0x64,
						0x5C,0x55,0x4D,0x45,0x3E,0x37,0x30,0x2A,0x24,0x1E,0x19,0x14,0x10,0x0C,0x09,0x06,0x04,0x02,0x01,0x01,
						0x01,0x02,0x04,0x06,0x09,0x0C,0x10,0x14,0x19,0x1E,0x24,0x2A,0x30,0x37,0x3E,0x45,0x4D,0x55,0x5C,0x64};//put this in flash later

volatile uint8_t OCR1AIndex =0;//one o/p phase shifted 3pi/2 for interrupt processing headroom
volatile uint8_t OCR1BIndex = 60; 

int main()
{
	HWInit();
	sei();

	while(1);
	//	i++;
	return 0;
}

//clock frequency is 16MHz using 1khz output frequency
void HWInit()
{	
	PRR =(1<<PRTIM2)|(1<<PRTWI)|(PRTIM0)|(1<<PRUSART0)|(PRADC);//shutdown everything useless
	DDRB = 0b00000110;//set ports b1 and b2 to outputs
	
	//timer config
	TCCR1B = 0;//stop timer
	
	TCCR1A = (1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);//fast pwm non inverting ICR1 is top value
	TCCR1B = (1<<WGM12)|(1<<WGM13);
	
	OCR1A = LUTable[0];//load first trip point
	OCR1B = LUTable[0];
	
	ICR1 = TOP;

	TIMSK1 = (1<<OCIE1A)|(1<<OCIE1B);//enable compare match interrupts
	
	TCCR1B |= (1<<CS10);//clock = fcpu no prescaler start clock
	
	return;
}	


ISR(TIMER1_COMPA_vect)
{
	OCR1A = LUTable[OCR1AIndex];
	OCR1AIndex++;
	if(OCR1AIndex >= PULSECOUNT)
		OCR1AIndex = 0;

}

ISR(TIMER1_COMPB_vect)
{
	OCR1B = LUTable[OCR1BIndex];
	OCR1BIndex +=2;
	if(OCR1BIndex >= PULSECOUNT)
		OCR1BIndex = 0;
}


ISR(BADISR_vect)
{
 static int j = 0;
 while(1)
 	j++;
    // user code here
}

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is an area that digital folks have a real problem with!

First off, an RC low pass filter has a "pole" or "corner frequency" at 1/(2*PI*R*C) This corner frequency needs to be ABOVE the frequency you are trying to reconstruct (the sine, in this case) and BELOW the repetition frequency of the PWM signal. In order for all this to work, the PWM repetition frequency must be substantially higher than the tone frequency. 10X is sort of a marginal minimum.

There are some challenges, here. The port pin that produces the PWM signal has, itself, about 25 ohms of "resistance". So, you want the R in the filter to be, oh, maybe 1000 ohms or more. From that, you can find the C. On the other hand, what you connect to the filter output appears in parallel with the other two parts, decreasing both the amplitude and the effective R value. That is why you MIGHT need an op-amp as a buffer, depending on the load. If you do go with an op-amp, then you might as well make a two pole active filter which reduces the spread needed between the PWM frequency and the signal frequency.

On the PWM frequency, this is NOT the PWM clock frequency. It is the frequency of the generated PWM signal (measured from one rising edge to the next rising edge, for example). It is the frequency that you would see with an oscilloscope looking at the PWM output pin.

Hope this helps,
Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the reply. I'm sorry if I used the wrong terminology. My PWM is clocked off of system clock which should be 16MHz the PRR should be 80kHz. Is there any rule of thumb about where in between the output frequency and my pulse frequency I should be putting my corner frequency? I will probably try right in the middle and then try moving the resistor value one way or the other and see what I get but if theres a quicker way I would appreciate the info. I've got the pads on the board to place an LM358 and associated components, so I can add another filter if necessary.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Pulse frequency is what I called "PWM repetition frequency". Same thing.

If you are using an 8 bit counter, the pulse frequency is probably (counter clock)/256. Counter clock COULD be the system frequency if the prescale value is 1. With a 16MHz system clock and a prescale of 1, pulse frequency is 62.5KHz if you count a full 256 counts per cycle.

You would like to have the corner frequency at least twice the highest tone frequency, otherwise the tone amplitude will vary with the tone frequency. The lower you can get the corner frequency relative to the pulse frequency, the less "ripple" (from the PWM pulse) there will be. This MIGHT not be an issue, however, if it is only intended for human listening as nobody will be able to hear 62.5KHz.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

looks like it works. Thanks a lot for the help.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Glad to help!

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!