Shop OBEX P1 Docs P2 Docs Learn Events
Cogless Pixel Drivers for P2 — Parallax Forums

Cogless Pixel Drivers for P2

JonnyMacJonnyMac Posts: 8,964
edited 2024-05-04 22:46 in PASM2/Spin2 (P2)

There are many applications that use just a few smart pixels, and in those cases we can save a cog when using the P2. Attached are drivers for 1-wire (WS2812b, et al.) and 2-wire (APA102c) pixels. Both use inline PASM, and the 2-wire driver uses Smart Pin SPI to generate the output.

These drivers work like Schmarschmino drivers: you change the pixels (with object methods or directly in the app), then call the show() method to refresh the pixel string. Some 1-wire pixels swap the red and green bytes in a color, so there is a swap flag as part of the show() method in that driver.

These are minimalist drivers -- not fancy, but they work well and don't need a cog. I'm using them in a couple of work projects.

Updated: 04 MAY 2024


  • JonnyMacJonnyMac Posts: 8,964
    edited 2023-10-25 16:50

    I didn't like that I was passing the swap flag in the show() method of the single-wire driver. After a great dinner with my friend, Rick Galinson (Mandalorian, Book of Boba Fett, Ahsoka, lots of movies and commercials) last night, and some much needed rest, I found a way to fix that. Of course, it seems obvious now.

    If you downloaded these drivers before I put the "Updated" notice in post #1, please replace them with what's posted now. The swap flag is passed in the startx() method and, so the show() method doesn't need that parameter. I did some formatting clean-ups, and did my best to make both drivers very consistent with each other. Code written for one driver is easier to migrate to the other now (just start() or startx() method change).

  • RaymanRayman Posts: 14,066

    This is very useful for me, thanks.

  • RaymanRayman Posts: 14,066

    I dumbed this down a lot for a certain application....

  • Neat idea to have a simpler driver for single pixels.

    Was there a previous single-pixel version for P1; thinking about driving the Parallax #28085 WS2812B module without a cog ?

  • Ha! Just realised that APA102c you're using @JonnyMac uses the host clock, so you can deploy a much simpler driver than is possible with the WS2812B timing.

    I'm often using something suspiciously :) similar, probably for the same reasons where only a couple indicators are needed and cogs are at a premium. I'll post the "shift out" style driver to OBEX later if I don't find one from you there.

    Anyway- figured I'd share the datasheet, especially for anyone in Europe who might struggle to get the APA device. These clocked serial RGB's are super handy!

  • RaymanRayman Posts: 14,066

    @VonSzarvas Yes, was testing with that Parallax module. Also testing with a new SMT version of neopixel...

  • JonnyMacJonnyMac Posts: 8,964
    edited 2024-05-04 22:44

    The first device I ever worked with (2009-ish) was called the WS2801 which was a 2-wire device. This was long before pixels were commonplace at Adafruit or other suppliers. I got them from a friend who imports containers full of LEDs. Believe it or not, I tested the original device using a BASIC Stamp 2. Things have come a long way since, but the Px processors have certainly made the single wire devices easier to deal with.

    There are a lot of single-wire pixels, but I mostly use the WS2812b at work, so I also broke out that variant as its own object. I'll attach it to the first post.

  • VonSzarvasVonSzarvas Posts: 3,307
    edited 2024-05-05 11:44

    @JonnyMac said:
    ... I mostly use the WS2812b at work, so I also broke out that variant as its own object. I'll attach it to the first post.

    Neat - not much overhead there.

    Is there anything in the PASM2 part that wouldn't compile under PASM for P1 ? (like, any P2 specific instructions that this solution relies on?)

    (yeah I know, I should wait to try it before asking :)

    Edit: looking at the code, the inline PASM would need adjustment, but that doesn't seem like an issue for conversion. Just if the PASM2 in the show method relies on anything P2 specific. Apart from setregs maybe (which I don't recognise yet), nothing else jumps out as being irreplicable... Doesn't seem to be using smartpins...

  • JonnyMacJonnyMac Posts: 8,964
    edited 2024-05-05 17:19

    Is there anything in the PASM2 part that wouldn't compile under PASM for P1 ? (like, any P2 specific instructions that this solution relies on?)

    Yes. In the P1 we need to create a bitmask for the pin, and deal with the OUT and DIR registers -- that's all one instruction in the P2. The biggest change, though, is reversing the positions of the red and green bytes before the data is transmitted.

    P1 (from jm_rgbx_pixel.spin):

    ' Correct placement of rg color bytes
    ' -- $RR_GG_BB_WW --> $GG_RR_BB_WW
                            tjz     swapflag, #shift_out            ' skip fix if swap = 0 
    swap_rg                 mov     t1, colorbits                   ' copy for red
                            mov     t2, colorbits                   ' copy for green
                            and     colorbits, HX_0000FFFF          ' isolate blue and white
                            and     t1, HX_FF000000                 ' isolate red
                            shr     t1, #8                          ' move red from byte3 to byte2
                            or      colorbits, t1                   ' add red back in
                            and     t2, HX_00FF0000                 ' isolate green
                            shl     t2, #8                          ' move green from byte2 to byte3
                            or      colorbits, t2                   ' add green back in


                            testb     swap, #0              wc      ' swap red & green?
            if_c            movbyts   pr1, #%%2310                  '  yes

    The movbyts instruction is magic.

    Note that I include the option to test for R/G swapping in my WS2812b P2 driver so that I can use it with other pixels. There is a version called the APA106A that is a pixel in a standard 5mm LED body (with 4 wires), and that doesn't require RG swapping.

    The P2 rep and waitx instructions make the mane shift_out loop more efficient, too.


    shift_out               mov     nbits, #24                      ' bits for 3 bytes
                            mov     bittimer, cycletix              ' set cycle timer for 800kHz
                            add     bittimer, cnt                   ' sync with system
    :loop                   rcl     colorbits, #1           wc      ' msb --> C
            if_nc           mov     t1, bit0hi                      ' if C = 0, use bit0 timing
            if_c            mov     t1, bit1hi                      ' if C = 1, use bit1 timing
                            or      outa, txmask                    ' make tx high
                            add     t1, cnt                         ' sync with system
                            waitcnt t1, #0                          ' hold high
                            andn    outa, txmask                    ' make tx low
                            waitcnt bittimer, cycletix              ' finish low side of cycle
                            djnz    nbits, #:loop                   ' more bits?


                            rep       #7, #24                       ' loop through all bits
                             shl      pr1, #1               wc      ' get MSB
                             drvh     pr0                           ' pin on
            if_nc            waitx    pr4                           ' hold for bit timing
            if_c             waitx    pr5
                             drvl     pr0                           ' pin off
                             addct1   pr7, pr6                      ' update bit timer
                             waitct1                                ' let bit timing finish

    Doesn't seem to be using smartpins

    My 1-wire pixel drivers for the P2 don't use smart pins, but my 2-wire driver does. It may be possible to use a smart pin for 1-wire pixels (using pulse mode), but I don't think there'd be any benefit given the overhead required by smart pins.

Sign In or Register to comment.