Weekend PASM puzzle:
Beau Schwabe
Posts: 6,568
jazzed posted something yesterday here that got me thinking. His original code was a way to throttle a clock pulse without using a counter... the bare bones code looks something like this...
...If the value in ptr is a non zero, then basically the tight loop generates a 2.5MHz clock, otherwise there is no clock.
I thought well for sure you can get at least 5MHz out of this and still be able to throttle the clock. So the code I came up with looks something like this...
This will allow you to generate a 5MHz square wave. The only thing is, is that you can't use any other I/O's during this
loop, and it will only work on P0.
The function of the 'ptr' value expands to something that could be very useful for data transmission
if ptr = 0, then the 5MHz is off
if ptr = 1, then only 1 pulse (100ns wide) is sent
if ptr = 2,4,6,8, etc., then 5MHz is ON starting out LOW
if ptr = 3,5,7,9, etc., then 5MHz is ON starting out HIGH
.... In other words you could toggle the ptr between 2 and 3 and you could flip the phase by 180 Deg could be interesting
for data transmission.
If you remove the nop instruction, the frequency is still 5MHz, but now ...
if ptr = 0, then the 5MHz is off
if ptr = 1, then only 1 pulse (50ns wide) is sent
if ptr = 2,4,6,8, etc., then 5MHz is ON starting out LOW with a 75% duty cycle
if ptr = 3,5,7,9, etc., then 5MHz is ON starting out HIGH with a 25% duty cycle
.... In this case you could toggle the ptr between 2 and 3 transmitting data by altering the duty cycle.
Now, I think that 5MHz is the limit based on the rdlong function requiring 16 clock cycles, however if you expand your options to use an I/O pin for control I can "almost" get 10MHz. What I mean by almost, is that when P0 is HIGH P1 will output 10MHz, and when P0 is LOW P1 will output a 25% duty cycle 5MHz frequency for a little while, before it drops out and doesn't produce any signal at all.
The challenge if it is possible, is to throttle the 10MHz without the 25% duty 5MHz, without using a counter.
If someone wants to show how to do it with a counter that would be fine, I believe you can go back to using the pointer variable to control it this way. I just thought this would be a good exercise to get back on topic of programming.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 9/12/2009 4:32:16 AM GMT
CON _CLKMODE = XTAL1 + PLL16X _XINFREQ = 5_000_000 PUB start|ptr ptr := 1 cognew(@PASM, @ptr) DAT PASM org 0 mov dira, #1 :loop rdlong val, par wz xor outa, #1 if_nz jmp #:loop val res
...If the value in ptr is a non zero, then basically the tight loop generates a 2.5MHz clock, otherwise there is no clock.
I thought well for sure you can get at least 5MHz out of this and still be able to throttle the clock. So the code I came up with looks something like this...
CON _CLKMODE = XTAL1 + PLL16X _XINFREQ = 5_000_000 PUB start|ptr ptr := 3 cognew(@PASM, @ptr) DAT PASM org 0 mov dira, #1 '5MHz clock :loop rdlong outa, par wz nop if_nz djnz outa, #:loop NoEnd jmp #NoEnd
This will allow you to generate a 5MHz square wave. The only thing is, is that you can't use any other I/O's during this
loop, and it will only work on P0.
The function of the 'ptr' value expands to something that could be very useful for data transmission
if ptr = 0, then the 5MHz is off
if ptr = 1, then only 1 pulse (100ns wide) is sent
if ptr = 2,4,6,8, etc., then 5MHz is ON starting out LOW
if ptr = 3,5,7,9, etc., then 5MHz is ON starting out HIGH
.... In other words you could toggle the ptr between 2 and 3 and you could flip the phase by 180 Deg could be interesting
for data transmission.
If you remove the nop instruction, the frequency is still 5MHz, but now ...
if ptr = 0, then the 5MHz is off
if ptr = 1, then only 1 pulse (50ns wide) is sent
if ptr = 2,4,6,8, etc., then 5MHz is ON starting out LOW with a 75% duty cycle
if ptr = 3,5,7,9, etc., then 5MHz is ON starting out HIGH with a 25% duty cycle
.... In this case you could toggle the ptr between 2 and 3 transmitting data by altering the duty cycle.
Now, I think that 5MHz is the limit based on the rdlong function requiring 16 clock cycles, however if you expand your options to use an I/O pin for control I can "almost" get 10MHz. What I mean by almost, is that when P0 is HIGH P1 will output 10MHz, and when P0 is LOW P1 will output a 25% duty cycle 5MHz frequency for a little while, before it drops out and doesn't produce any signal at all.
The challenge if it is possible, is to throttle the 10MHz without the 25% duty 5MHz, without using a counter.
If someone wants to show how to do it with a counter that would be fine, I believe you can go back to using the pointer variable to control it this way. I just thought this would be a good exercise to get back on topic of programming.
CON _CLKMODE = XTAL1 + PLL16X _XINFREQ = 5_000_000 PUB start cognew(@PASM, 0) DAT PASM org 0 mov dira, #%10 'Set Pin directions P0 = input P1 = output mov outa, ina {{ If P0 is HIGH, then P1 will output a 10MHz clock If P0 is LOW, then P1 will output a 5MHz clock before dropping off to no clock output }} '5MHz/10MHz clock :loop1 andn outa, ina djnz outa, #:loop1 NoEnd jmp #NoEnd
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 9/12/2009 4:32:16 AM GMT
Comments
I think this meets the minimum criteria — probably not what you had in mind, though, right?
-Phil
Post Edited (Phil Pilgrim (PhiPi)) : 9/12/2009 4:43:20 AM GMT
The idea was more for a continuous pulse stream that you can break out of the "tight loop" from some external event and continue code execution within the same PASM cog after the tight loop.
"runty pulses" - I liked that - [noparse]:o[/noparse]) - but Phil removed it [noparse]:o[/noparse](
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Post Edited (Beau Schwabe (Parallax)) : 9/12/2009 5:07:46 AM GMT
-Phil
Post Edited (Phil Pilgrim (PhiPi)) : 9/12/2009 5:03:18 AM GMT
Many times I've been tempted to dig out my old 20MHz from the garage ... I hear your screams! [noparse]:o[/noparse])
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
If P0 is high then the andn will apply -4 ($FFFF_FFFC) and pull P1 low while djnz forces outa to -1 (P1 high) and continues the loop. OTOH, if P0 is low at this stage, andn will apply -3 ($FFFF_FFFD). That leaves a convenient %01 in outa and djnz ends the loop.
Something a bit more wasteful but workable (from a POC point of view):
The lower 9bit of outa are set to PC+1 and PC+2 so it can be arranged that at least one bit is changing state. ina needs to be arranged so that its lower 9bit either point to :loop+1 or somewhere else to end clock generation.
I really like option #1, and I don't think one extra 10MHz cycle would be an issue.
Here is a method using one of the counters. The example is set to output 40MHz, but could certainly be adjusted to anything from DC to 128MHz. If ptr is equal to anything non Zero, then P0 will output a 40MHz signal.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Beau Schwabe
IC Layout Engineer
Parallax, Inc.
Bruce