Shop OBEX P1 Docs P2 Docs Learn Events
How to write to a group of pins in PASM2? — Parallax Forums

How to write to a group of pins in PASM2?

I need to write to 8 sequential pins at the same time by moving a byte of data to them.

If I start @ pin 0, its easy enough:
MOV OUTA, data

But if I want to start at an arbitrary pin by specifying a pinfield it seems there is no single instruction that can do this.

I came up with this 9-instructions approach but I wonder if there is a correct way of doing this or a more efficient way:
CON
        _clkfreq = 160_000_000
VAR
        long stack[40]
        long pinfield

PUB main()
        pinfield := 16 addpins 7
        COGINIT(COGEXEC_NEW,@go,@pinfield)

DAT
        ORG 0

go      

        RDLONG pin_f, PTRA

        DIRH pin_f              'Set pins to outputs

        MOV base, pin_f         'Get base of pinfield
        AND base, #$3F

        '9 operations to move the data byte into an arbitrary position in OUTA
        MOV shifted, OUTA       'Get current value of OUTA

        MOV mask, #$FF          'Create a mask for 8 bits
        SHL mask, base          'Align mask with base pin position
        NOT mask                'Invert the mask
        AND shifted, mask       'Get everything but our pins

        MOV newval, data        'Get the data to send to the pins
        SHL  newval, base       'Shift the new data to base pin position
        OR shifted, newval      'Combine data with the rest of the pins data 
        AND OUTA, shifted       'Finally push the new value to OUTA


data long 21
pin_f  long 0
base long 0
mask long 0 
shifted long 0
newval long 0



Can this be done in less than 9 operations?

Comments

  • If you want set a group of 8 that starts on a multiple of 8, use SETBYTE. Similiarly, there's SETNIB and SETWORD
  • If you can tolerate being on a boundary of 8 bits, you could make use of the streamer, to transfer a byte on every clock
  • Since you're passing a pin field, you could emulate the code Chip uses for the pinwrite() function.
    ' PINW(pins,val)                        (9 longs, must be in regs)
    '
    pinw_           ror     y,#6    wc      'y=pins, w=val (begins at pop2 in LUT)
                    bitc    .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
    .reg            muxq    outa,w
    
            _ret_   dirh    y               'enable outputs
    
  • Wuerfel_21 wrote: »
    If you want set a group of 8 that starts on a multiple of 8, use SETBYTE. Similiarly, there's SETNIB and SETWORD
    Thanks @Wuerfel_21, at the moment the project requires an arbitrary pin assignment. But it is an alternative if I'm forced to de-scope the project.
    Tubular wrote: »
    If you can tolerate being on a boundary of 8 bits, you could make use of the streamer, to transfer a byte on every clock
    Thanks @Tubular, honestly I would love to learn how to use the streamer. The benefits of it could out weight the arbitraryness of the requirements but I've tried to read the available documentation and I haven't been able to put it all together in my head. There seems to be several moving parts which I haven't identified so far.
    JonnyMac wrote: »
    Since you're passing a pin field, you could emulate the code Chip uses for the pinwrite() function.
    Thanks @JonnyMac, it didn't occur to me to see the under the hood approach of other instructions. Seems like the "right way" approach to do what I want. But.. there are a few things to unpack and understand from that snippet:
            bitc .reg, #9
            
            ....
    
    .reg    muxq outa, w
    

    Isn't .reg a symbol pointing to the muxq operation? It seems like bitc is hacking the encoding of muxq to modify its destination address (if that's true it's a pretty neat trick!) That seems to overcome the problem of limiting the arbitraryness to either within OUTA or within OUTB.

    It still cost 9 operations but it is more versatile than my code. Wow so much to learn!
    BITC D,{#}S {WCZ}
    Bits D[S[9:5]+S[4:0]:S[4:0]] = C. Other bits unaffected. Prior SETQ overrides S[9:5]. C,Z = original D[S[4:0]].
    MUXQ D,{#}S
    Used after SETQ. For each '1' bit in Q, copy the corresponding bit in S into D. D = (D & !Q) | (S & Q).

    As always, thank you all, such a great community of like minded people!!
  • jrullan wrote: »
    Isn't .reg a symbol pointing to the muxq operation? It seems like bitc is hacking the encoding of muxq to modify its destination address (if that's true it's a pretty neat trick!) That seems to overcome the problem of limiting the arbitraryness to either within OUTA or within OUTB.

    YES! I can confirm, finally understood the snippet, it in fact modifies the bit #9 of the MUXQ instruction using the carry from the ROR on the pinfield. If base pin is >= 32 the carry == 1 so it changes OUTA address from $1FC to $1FD (which is the address of OUTB) effectively selecting between the two with the carry. WOW!

    THIS IS THE WAY!
Sign In or Register to comment.