PASM version of pinwrite(pinfield, data)?
Is there a simple way to set non-contiguous pin values within a pinfield in a single PASM2 instruction? I am trying to turn non-contiguous Smart Pins on/off in the same clock cycle with a drvh/drvl type of mechanism and am unable to come up with the right approach.
Comments
You can write directly into OUTA and OUTB registers to affect pin states.
(pinwrite(base addpins ext), data)
is roughly equivalent to this (minus port a/b handling)
bmask ext rol ext,base rol data,base setq ext muxq outa,data
Infact, the actual pinwrite implementation in the Spin2 Interpreter (y and w are the parameters):
pinw_ ror y,#6 wc 'y=pins, w=val (begins at pop2 in LUT) bitc pinw_reg,#9 'select outa/outb for writing bmask v,y 'make mask rol y,#6 rol v,y 'justify mask rol w,y 'justify val setq v 'mux val into outa/outb using mask pinw_reg muxq outa,w _ret_ dirh y 'enable outputs
Of course if your pin numbers start on a multiple of 8, you might use SETBYTE instead of the longer SETQ/MUXQ approach. (same for SETIB/SETWORD).
Or if you just want to toggle pin states, you can obviously just a XOR instruction.
Thank you for the response. This makes sense but I have a problem implementing...
This code is intended to blink leds 56 and 59 (p_ext, p_base = 5, 24) but it doesn't. Am I close?
dat org p_write mov dirb, ##$ff00_0000 bmask ext rol ext, base getct ct1 .loop addct1 ct1, delay waitct1 mov data, #1 rol data, base setq ext muxq outb, data addct1 ct1, delay waitct1 mov data, #4 rol data, base setq ext muxq outb, data jmp #.loop ct1 res 1 delay long 297_000_000 ext long p_ext base long p_base data long 0
RES variables must always come after everything else, otherwise the addresses shift around and everything stops making sense.
Works like a champ; only the desired pinfield is modified. Thank you for the solution and for remedial PASM education.
I am having a problem understanding how this works. If I put the assembly code inline it works. If I put it in a cog it fails. Am I missing a fundamental consideration.
This version works:
PUB main() | pins, data, mask pins := 56 addpins 4 data := %10101 org start ror pins, #6 wc bitc led, #9 bmask mask, pins rol pins, #6 rol mask, pins dirh pins rol data, pins loop setq mask led muxq outa, data jmp #loop end
This version does not:
VAR cogvar[8] PUB main() | _pins, _data, _mask _pins := 56 addpins 4 _data := %10101 longmove(@cogvar, @_pins, 2) coginit(1, @start, @cogvar) DAT org start setq #1 rdlong pins, ptra ror pins, #6 wc bitc led, #9 bmask mask, pins rol pins, #6 rol mask, pins dirh pins rol data, pins loop setq mask led muxq outa, data jmp #loop pins res 1 data res 1 mask res 1
Normally, you want your main to not return while other tasks are still going, put an empty repeat block after coginit (or coginit over cog 0, if you really want). Not sure if that's it though.
If I use outb in the led register it works. Apparently the bitc led,#9 instruction isn't modifying the register.
That would normally indicate missing ORG, but it seems to be there (i usually prefer explicit
ORG 0
but it shouldn't matter. Or does it? Am confused on this one, too.).I am confused too but now I have a version that works... sometimes I think I am losing my mind!
CON _clkfreq = 297_000_000 'set clock frequency delay = 297_000_000 VAR cogvar[8] PUB main() | _pins, _data, _mask _pins := 56 addpins 4 _data := %10101 longmove(@cogvar, @_pins, 2) coginit(1, @start, @cogvar) waitms(10) repeat cogvar[1] += 1 waitms(50) DAT org start setq #1 rdlong pins, ptra add ptra, #4 ror pins, #6 wc bitc led, #9 bmask mask, pins rol pins, #6 rol mask, pins dirh pins loop rdlong data, ptra rol data, pins setq mask led muxq outa, data jmp #loop pins res 1 data res 1 mask res 1