'' EXAMPLE generates a square wave output on one pin, and '' a sinewave output at the same frequency as PWM on a second pin '' uses the ctra and ctrb functions and the sine table in hub ROM '' This version uses pasm not spin, so the update rate is high enough for audio output '' '' File: sinewave0.spin '' Submitted by Tracy Allen, 24 Sept 2006 '' '' DIFFICULTY LEVEL: intermediate '' '' OPERATION: '' '' -- One pin is driven by counter A NCO mode, phsa(31). '' -- The next pin up is driven by counter B in duty mode, phsb(carry), '' which can vary the analog output level by means of PWM. '' -- The pasm program repeatedly reads the phase of counter A '' and looks up the corresponding sine value in the sine table in hub ROM '' and modulates the frqb value of counter B to give the sinusoidal pulsation '' -- The demo board has audio output jacks for p10 and p11, so the program defaults to those pins. '' -- The pins to use and the frequency are passed as parameters when starting the COG. '' -- This program is written all in pasm, so the update rate is every ~1 microsecond. '' good enough for audio frequency sine wave with 80mhz clock. '' ''************************************************************************************************* '' CORRECT OUTPUT: '' first pin shows square wave, second pin shows sine wave. The digital PWM is a mess, '' but the sine wave after filtering is relatively clean '' '' How to calculate frqa value from desired Fout and CLKFREQ: Fout / CLKFREQ * 2^32 '' '' Things to try: '' -- Change the frequency and the amplitude by playing with the parameters. '' -- Make the leds on pins pa16 and pa17 pulse at 1 hertz '' -- Launch two cogs with different frequencies on the audio left and right. ''************************************************************************************************* CON _CLKMODE = XTAL1 + PLL16X _XINFREQ = 5_000_000 var long apin, afreq PUB sinewave3start apin := 10 ' pa10 this is the audio output on the demo board afreq := 536871 ' 536871 is 10 khz cognew(@entry,@apin) ' load the pasm into a cog with par pointing to apin location DAT org 0 entry mov pointer,par ' pointer to paramters rdlong pn,pointer ' read in the pin to use add pointer,#4 ' point to next parameter rdlong frqa,pointer ' read in the frequency parameter or amode,pn ' amode is a cog consant for NCO mode, OR in the pin number shl cat,pn ' this will be the mask to set pins pn and pn+1 as outputs ' or cat,#1 ' pin pa0 can be probed to observe the loop timing add pn,#1 ' next pin or bmode,pn ' bmode is cog constant for duty mode, OR in the pin number mov ctra,amode ' counter A set to NCO mode tied to pin pn mov frqb,center ' this is the 50% duty for counter B in duty mode mov ctrb,bmode ' counter B set to duty mode tied to pin pn+1 mov dira,cat ' set pins used to output loop mov phx,phsa ' main loop looks at counter A phase shr phx,#19 ' shift to make it 13 bits for full circle call #getsin ' find sine of phase shl phx,#15 ' it returns 16 bits signed, make it 32 bits +/- $8000_0000 add phx,center ' offset to center, 0 to $ffff_ffff (actually $1_0000 to $FFFE_0000) mov frqb,phx ' update duty of counter b ' xor outa,#1 ' toggle this pin to probe loop timing jmp #loop getsin test phx,sin_90 wc 'get quadrant 2|4 into c test phx,sin_180 wz 'get quadrant 3|4 into nz negc phx,phx 'if quadrant 2|4, negate offset or phx,sin_table 'or in sin table address >> 1 shl phx,#1 'shift left to get final word address rdword phx,phx 'read word sample from $E000 to $F000 negnz phx,phx 'if quadrant 3|4, negate sample getsin_ret ret ' (this subroutine adapted from Prop manual) sin_90 long $0800 sin_180 long $1000 sin_table long $E000 >> 1 'sine table base shifted right, because program does *2 to convert to word addrs center long $8000_0000 amode long %0_00100_000_00000000_000000_000_000000 bmode long %0_00110_000_00000000_000000_000_000000 cat long 3 phx res 1 pointer res 1 pn res 1