Modulating a radio signal without using RLP

A while back I was working on a project to modulate a radio signal using a Panda and it seemed like people thought it couldn’t be done without using RLP… So I used RLP. However I recently realized the OutputCompare class could be use to create essentially the same thing with specific timings for the upper and lower frequencies. And it works!

Code is here:

Yes OutputCompare can do a lot of things, thanks for sharing

One thing I’ve noticed is that the non-RLP code seems to focus more of the energy in the correct frequencies (2125 and 1775 Hz in this case) while the signal itself isn’t quite as clean, which is ok. Here is the non RLP received spectrum and I’ll post the RLP one next.

The RLP one is using PWM and is turning it on and off while the non RLP one is not using PWM. Any idea what would cause the differences? I would expect the PWM generated signal to be both cleaner (which it is) and more focused near the frequencies (which it isn’t).

RLP spectrum

Not sure, PWM is as accurate as the crustal, which is very accurate.

somewhere there is a thread about Stopping PWM Clean. if i recall correctly then there is a register you must set else changing the pwm has immediate effect, chopping the current cycle short, which will give you nasty spread and such…

Stopping PWM clean:

Ok, I’m already doing the PWM in RLP with registers so probably if I look over the register based code and do it that way I’ll get the best of both worlds. Thanks!

Remember to set up the PWM up so that changes to the duty cycle only takes effect at the start of the next cycle…

I looked at the registers being used and couldn’t see where that was occurring in your code. Here is what I currently have, what changes do you suggest?

 #define TCR_CNT_EN		0x00000001
 #define TCR_RESET		0x00000002
 #define TCR_PWM_EN		0x00000008
 #define PWMMR0R			1 << 1
 #define LER0_EN			1 << 0
 #define LER1_EN			1 << 1
 #define LER2_EN			1 << 2
 #define LER5_EN			1 << 5
 #define PWMENA1			1 << 9
 #define PWMENA2			1 << 10
 #define PWMENA5			1 << 13

 #define PINSEL_BASE_ADDR	0xE002C000
 #define PINSEL3        (*(volatile unsigned long *)(PINSEL_BASE_ADDR + 0x0C))
 #define PWM1_BASE_ADDR		0xE0018000
 #define PWM1TCR         (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x04))
 #define PWM1PR          (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x0C))
 #define PWM1MCR         (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x14))
 #define PWM1MR0         (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x18))
 #define PWM1MR1         (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x1C))
 #define PWM1MR2         (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x20))
 #define PWM1MR5         (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x44))
 #define PWM1PCR         (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x4C))
 #define PWM1LER         (*(volatile unsigned long *)(PWM1_BASE_ADDR + 0x50))
 #define UART0_BASE_ADDR		0xE000C000
 #define U0THR          (*(volatile unsigned long *)(UART0_BASE_ADDR + 0x00))

 #define MICROSECOND   18 
int PwmStart(unsigned int frequencyHz, unsigned char duty)
    PINSEL3 |= 0x20220;	/* set GPIOs for all PWM1, PWM2 & PWM5 */
    PWM1TCR = TCR_RESET;	/* Counter Reset */ 
    PWM1PR = 0x00;			/* count frequency:Fpclk */
    PWM1MCR = PWMMR0R;	    /* reset on PWMMR0, reset TC if PWM0 matches */				
	//avoid increase in compile size by avoiding float math and scaling numebrs up
	long CYCLE_WIDTH = (1000000000 / frequencyHz) * MICROSECOND / 1000;
    PWM1MR0 = CYCLE_WIDTH;		/* set PWM cycle */
	//avoid increase in compile size by avoiding float math and scaling numebrs up
	long rate = CYCLE_WIDTH * ((duty * 1000) / 100) / 1000;
    PWM1MR1 = rate;
    PWM1MR2 = rate;
    PWM1MR5 = rate;
    /* PWM latches enabled, ready to start */
    PWM1LER = LER0_EN | LER1_EN | LER2_EN | LER5_EN;

    /* All single edge, all enable */
    PWM1TCR = TCR_CNT_EN | TCR_PWM_EN;	    /* counter enable, PWM enable */

    return 1;

I think this is the code that i’m refering to:

    /* PWM latches enabled, ready to start */
    PWM1LER = LER0_EN | LER1_EN | LER2_EN | LER5_EN;

So you already have it.

If I understand it correctly then setting that will fix the non RPL code too…

Yeah, once I ponder the original 2 images in this thread a bit more I think the “focus” is the same but because the frequencies aren’t exactly right the dots are spread out a bit more instead of the nice fine lines which are more visible in the PWM case. So I’m guessing that is probably as good as it gets without introducing hardware frequency filtering.

Please try this:

Seems like that might have made it slightly worse, but not much difference either way.

Are these generated by spectrum analyzer? You know that PWM generates squared signal (not sinusoidal signals) so you will never see pure power at any frequency.

Squared wave is made of infinite number of sine waves:

I think he’s trying to explain the red lines not the yellow power. The yellow of course is because of the armonics of the square wave.