Shop OBEX P1 Docs P2 Docs Learn Events
"Blitzen 24" E1.31 Pixel Light Controller Updates thread. - Page 2 — Parallax Forums

"Blitzen 24" E1.31 Pixel Light Controller Updates thread.

2456

Comments

  • Cool👍

  • Awesome!!!

  • I want to thank everyone on the Propeller Live Forum for the kind words about this project and the Propeller powered light show I have at the house.

    During the live forum, I tested a use case that worked before I made the changes to the pin output and levels, where the Ethernet status would update when unplugged. On the live forum, it didn't work as expected. The ethernet status did not turn yellow, then red when I unplugged the cable.

    So what I found was, the E1.31 cog is now much more aggressive in checking out the lock for the W6100 ethernet. To the point that unless there is E1.31 data flowing into the controller, the other cogs that communicate with the ethernet (The Watchdog and httpd server) might be in a state where they don't get a bite at the apple. This was a problem I anticipated, but it never materialized. Well, here it is :) I am unsure why I am just now seeing it and cannot be 100% sure it is related to the pin configuration changes.

    I am not using the interrupt line on the W6100 (but it is wired on my board). This means that the webserver and E1.31 cogs just hammer away checking the registers to see if they have data available in the W6100. I have a small delay for the httpd and watchdog cogs, to deprioritize them.

    I believe the solution to properly prioritize E1.31 is to configure the interrupt so that it will fire only if there is data available on the E1.31 socket. In addition, have the E1.31 cog attempt to checkout a lock only when there is data to service. This will give the http and watchdog cogs the ability to service any requests when no E1.31 data is being received. The problem currently manifests itself only when there is no E1.31 data to service. When I send data, the webserver and watchdog work appropriately. Servicing the E1.31 data should always be the priority.

    I will keep you all posted.

  • I decided to try something less complicated, and it works, somehow.

    repeat until locktry(EthernetLock) < 0
      waitms(0)
    

    Not sure what waitms(0) gets translated to, but it allows all of the cogs to get a bite at the lock. I will take it. Less complexity the better.

  • test.spin2 has been renamed to Blitzen24.spin2. It is the Topfile.

    Previous versions would set pingroup pixel count based on the first pin of the pingroup. ie pins 1,9, and17. Now pixel count for the pingroup is based on the highest individual port pixel count in the group.

    https://griswoldfx.visualstudio.com/_git/Blitzen 24?path=/&amp;version=GBmain

  • You ever had a bug in a piece of code and when you look at the code you wrote, your mind is completely devoid of any recollection as to how it works? I really should have put more comments in here.

    pub e131post() | output, ei, eti, u , uascii
        longfill(@tE131CONFIG,0,432) ' Clean up the tmp space
        eutmp[0] := 0
        pcnt[0] := 0
        output := str2dec(@READBUFFER + str.instr(@READBUFFER,string("output="))+ 7, 2)
        u  := 1
        ei := 0
        eti := 0
        repeat until (E131CONFIG[ei] == output) or (E131CONFIG[ei] == 0) 'Do this until you get to the current e131 config
          longmove(@tE131CONFIG+(ei*4),@E131CONFIG+(ei*4),4)
          ei := ei + 4
          eti := ei
        str.append_str(@eutmp,string("U"))
        str.append_str(@eutmp,str.dec(u,1))
        str.append_str(@eutmp,string("="))
        str.append_str(@pcnt,string("P"))
        str.append_str(@pcnt,str.dec(u,1))
        str.append_str(@pcnt,string("="))
    
        repeat until str2dec(@READBUFFER + str.instr(@READBUFFER,@eutmp)+ 3, 6) == 0
          tE131CONFIG[ei] := output
          tE131CONFIG[ei+1] := str2dec(@READBUFFER + str.instr(@READBUFFER,@eutmp)+ 3, 6)
          tE131CONFIG[ei+2] := str2dec(@READBUFFER + str.instr(@READBUFFER,@pcnt)+ 3, 3)
    
           'vid.dec(str2dec(@READBUFFER + str.instr(@READBUFFER,@eutmp)+ 3, 6))
           'vid.dec(str2dec(@READBUFFER + str.instr(@READBUFFER,@pcnt)+ 3, 3))
          u := u + 1
          eutmp[0] := 0
          pcnt[0] := 0
          str.append_str(@eutmp,string("U"))
          str.append_str(@eutmp,str.dec(u,1))
          str.append_str(@eutmp,string("="))
          str.append_str(@pcnt,string("P"))
          str.append_str(@pcnt,str.dec(u,1))
          str.append_str(@pcnt,string("="))
          ei := ei + 4
           'waitms(3000)
    
        repeat until (E131CONFIG[eti] <> output) or (E131CONFIG[eti] == 0) or eti >= 432
            eti := eti + 4
    
     '   ei := ei - 4
        repeat until (E131CONFIG[eti] == 0) or eti >= 432
            longmove(@tE131CONFIG+(ei*4),@E131CONFIG+(eti*4),4)
            eti := eti + 4
            ei := ei + 4
    
        longmove(@E131CONFIG,@tE131CONFIG,432)
        ConfigPixels()
        StopPixels()
        StartPixels()
        W6100.stopfastrx()
        W6100.startfastrx(W6100.IDM_BSR_Socket3_Register,@pixelbuffer,@TXBUFFER,@E131CONFIG)
    
  • Comments.........help....so......much. Took me an hour and a half to walk this code manually and write comments as to what it is doing. I needed to do this to get my mind "right" again.

    Basically, it copies the records in E131CONFIG structure to a temporary structure (tE131CONFIG) until it reaches the current output pin record. It then populates the records for the data that was posted to the webserver for the current pin in the tE131CONFIG structure. It must enumerate the Universe/Pixelcount pairs submitted on the form, as you can configure more than one universe for an output pin. Once that is complete, it copies the rest of the records from the E131CONFIG structure to the temporary structure (tE131CONFIG) until all records have been copied. It then copies all of the tE131CONFIG to E131CONFIG, re-runs the pixelconfig to setup where the pixel buffers will land, and restarts all affected cogs.

    I remember writing this overnight after having a nap one weekend. That whole process congealed in my brain for a few hours. Then I never looked back until now. Now I need to actually see what causes the whole controller to lockup when an E1.31 config is removed or added when there are configurations on pins below or above it. The problem may also reside in PixelConfig. I can't recall if every pin is required to be in the E131CONFIG structure and with an E1.31 universe of 0 if not configured. It may be that I also need to clear the contents of the E131CONFIG before overwriting it with tE131CONFIG. That would make sense if we are removing records from the structure.

    I look forward to killing this bug over Christmas!

    pub e131post() | output, ei, eti, u , uascii
        longfill(@tE131CONFIG,0,432) ' Clean up the tmp space
        eutmp[0] := 0
        pcnt[0] := 0
        ' Get the output Pin this E1.31 config is associated with
        output := str2dec(@READBUFFER + str.instr(@READBUFFER,string("output="))+ 7, 2)
        ' Initialize the variables to be used.
        u  := 1
        ei := 0
        eti := 0
        'Populate tE131CONFIG with configured pin/universe/pixelcount/pixelbuffer records in the E131CONFIG structure until we come to the current output.
        repeat until (E131CONFIG[ei] == output) or (E131CONFIG[ei] == 0)
          'Move 4 longs from the E1.31 config structure to the temp structure, before the output is found or end of structure is detected.
          'No idea why I am doing ei*4, maybe because longs?
          longmove(@tE131CONFIG+(ei*4),@E131CONFIG+(ei*4),4)
          ei := ei + 4
          eti := ei
        ' Populate eutemp with "U1="
        str.append_str(@eutmp,string("U"))
        str.append_str(@eutmp,str.dec(u,1))
        str.append_str(@eutmp,string("="))
        ' Populate pcnt (pixelcount) with "P1="
        str.append_str(@pcnt,string("P"))
        str.append_str(@pcnt,str.dec(u,1))
        str.append_str(@pcnt,string("="))
    
        'Look in the read buffer until the location of the current eutmp (ie "U1=", "U2=", etc) is found and repeat the code block. Stop if it cannot be found.
        repeat until str2dec(@READBUFFER + str.instr(@READBUFFER,@eutmp)+ 3, 6) == 0
          ' Set the output pin in the current location (ei) of tE131CONFIG. This is a many to one relationship with the pin in the pixelbuffer.
          tE131CONFIG[ei] := output
          ' Set the value of the eutmp (ie "U1=", "U2=", etc) universe associated with this pin.
          tE131CONFIG[ei+1] := str2dec(@READBUFFER + str.instr(@READBUFFER,@eutmp)+ 3, 6)
          ' Set the value of the pcnt (pixelcount ie "P1=", "P2=", etc ) of this universe assocaited with this pin.
          tE131CONFIG[ei+2] := str2dec(@READBUFFER + str.instr(@READBUFFER,@pcnt)+ 3, 3)
    
           'vid.dec(str2dec(@READBUFFER + str.instr(@READBUFFER,@eutmp)+ 3, 6))
           'vid.dec(str2dec(@READBUFFER + str.instr(@READBUFFER,@pcnt)+ 3, 3))
    
          ' Increment the universe and pixelcount to the next that may have been posted to the page.
          u := u + 1
          ' clear eutmp
          eutmp[0] := 0
          ' clear pcnt
          pcnt[0] := 0
          ' Populate eutemp with the next universe of this pin to look for.
          str.append_str(@eutmp,string("U"))
          str.append_str(@eutmp,str.dec(u,1))
          str.append_str(@eutmp,string("="))
          ' Populate pcnt with the next pixelcount of this pin to look for.
          str.append_str(@pcnt,string("P"))
          str.append_str(@pcnt,str.dec(u,1))
          str.append_str(@pcnt,string("="))
          ' Move to the next pin/universe/pixelcount/pixelbuffer in the structure.
          ei := ei + 4
           'waitms(3000)
        ' Increment et1 until we are past the currently configured output pin or the end of configured pin/universe/pixelcount/pixelbuffer records in the structure or the end of the structure.
        repeat until (E131CONFIG[eti] <> output) or (E131CONFIG[eti] == 0) or eti >= 432
            eti := eti + 4
    
     '   ei := ei - 4
        ' Copy any remaining records in the E1.31 structure to @tE131CONFIG
        repeat until (E131CONFIG[eti] == 0) or eti >= 432
            longmove(@tE131CONFIG+(ei*4),@E131CONFIG+(eti*4),4)
            eti := eti + 4
            ei := ei + 4
    
        ' Overwrite the E131CONFIG with tE131CONFIG
        longmove(@E131CONFIG,@tE131CONFIG,432)
        ' Rebuild the Pixel/E1.31 relationship
        ConfigPixels()
        ' Stop and restart the pixel drivers
        StopPixels()
        StartPixels()
        ' Restart the E1.31 ethernet driver
        W6100.stopfastrx()
        W6100.startfastrx(W6100.IDM_BSR_Socket3_Register,@pixelbuffer,@TXBUFFER,@E131CONFIG)
    
    
  • @ke4pjw said:
    Comments.........help....so......much. Took me an hour and a half to walk this code manually and write comments as to what it is doing. I needed to do this to get my mind "right" again.

    I remember writing this overnight after having a nap one weekend. That whole process congealed in my brain for a few hours. Then I never looked back until now. ....

    This is soooo true!!! I've been there more times than I would like to admit. Good luck!

  • I also know this very well. The common error is to think "I'll do the documentation when I'm finished coding". But after it's halfway done I receive a phone call from a customer who urgently needs a fix for a problem. Then I come back two weeks later and have no clue what part was actually working, already, and what still needs to be fixed and how it was supposed to be implemented. :s

    One possible solution is to document as much as possible before starting to code. At least the interface specifications and purpose of every variable and function can be written down ahead of the code. If you have new ideas while programming write them down immediately.

    The other solution is to lock the door and switch the phone to flight mode until you're finished. B)

  • Comments have been added to the code.

    Bug was found and dispatched.

    New version of Blitzen24.spin2 is in the repo.

    Glad I am not alone in forgeting how your own code works! @ManAtWork I think I am going to document the interface spec for passing the variables from the webserver, as well as document the data structures for the pixel and E1.31 configs. I have comments, but a graphic showing the one to many relationship of those two will be helpful.

  • Blitzen 24 Edge Pre-Release_1 is available in the repo.

    I am ramping up to have boards available for sale, for those that are interested.

    Also, here is a quick video I made when it started snowing before Christmas. It doesn't snow very often in Middle Tennessee.

    Every light in this video is controlled by either a P1 (Rudolph 16 - A.C. dimmer) or P2 (Blitzen 24 - pixel controller).

  • Great! B)

  • ke4pjwke4pjw Posts: 1,169
    edited 2023-01-02 06:46

    More updates! Lots of work done over the holidays.

    New Features!

    • Test mode for outputs. You can blink your LEDS Red, Green, Blue, or White via the Outputs tab. That allows you to ensure that the outputs are wired correctly and also is a way for you to determine if your pixel order is RGB and adjust it so that it is RGB.
    • Quad DMX outputs are working! You can now map up to four E1.31 universes to output to DMX. No more USB needed to control your DMX devices. Just use your network! Walk around with your laptop controlling your fixtures via WiFi.
    • Selectable Speed and Duplex. Ethernet was hard coded to 10BaseT Full. It is now selectable between 10/half/full, 100/half/full and Auto Negotiate. There can be a performance penalty at 100 Full, and that's why this was added. Additionally, some enterprise level switches will not auto negotiate correctly, or properly negotiate 10/Full unless the port specifies it.
    • DNS was added to the network configuration. DNS can be assigned via DHCP. I need to write a resolver. Once that is done, I will add a feature to allow these controllers to update their firmware via the Internet.

    Improvements

    • The watchdog was updated to reflect more accurate E1.31 statistics.
    • The E1.31 indicator on the OLED display blinks Yellow when in outputs are in Test Mode.
    • All HDMI code has been removed and the driver unloaded from memory. All former diagnostic information, such as https logs, are now visible via debug. Just enable debug and load it into RAM. The freed up HDMI cog allowed for the Quad DMX to be implemented.

    There is room for improvement, but this is starting to feel close to solid. I will test all of these features and most likely release this as Release Candidate 2.

    This code is currently available in the Main Branch.

    I hope everyone had a Merry Christmas, A Happy Hanukkah, a joyous Festivus, and will have a happy and prosperous 2023!

    --Terry

  • Found a major bug in the DMX output. The baudticks variable was not copied from hubram to the DMX cog. I had just checked the data with an analyzer, but didn't actually look at the timings. The timings look good now. I will test with actual DMX fixtures later this evening.

  • ke4pjwke4pjw Posts: 1,169
    edited 2023-01-03 06:16

    Found another major bug in the DMX output. Testing on generic Chinese DMX fixtures worked just fine. Testing on my own Rudolph 16's failed. They would indicate that DMX was being received, but would not accept any data from the Blitzen 24. After a couple of hours looking at the beautiful, perfectly timed waveforms generated by my modified version @JonnyMac 's jm_dmx_tx object, and banging my head against the table, I hooked up my old DMX USB dongle that I built based on the P1 to do a side by side. After a couple of minutes banging my head on the desk again, I saw it. The null start code on the DMX dongle. I had accidentally set the start code to a value of "1". Complete brain fart. The Rudolph 16 actually followed the current spec (at the time it was made) and ignored any packets with a start code other than 0.

    Code has been updated in the main branch in the repo.

    --Terry

    "We do these things not because they are hard, but because we thought they would be easy."

  • "We do these things not because they are hard, but because we thought they would be easy."

    that's a nice one

    Mike

  • Remote updates are getting closer to being a thing.
    I can prepare the filesystem for downloads.
    Get a copy of the update manifest.
    Download the files from the manifest.
    Having trouble enumerating files in the root directory and am stuck there at the moment.

  • Over the air updates are working! I do a walk through of the new features in the latest pre-release in the video below.

  • Nice

  • So I upgraded to PropellerTool 2.9.2 and basically, the webserver no longer works. All of my builds are on PropellerTool 2.6.2.

    I will take some time this evening/weekend to find what the issues are. The timings on the locks has changed and I think that may be affecting the performance.

    To be clear, this is not an issue with PropellerTool, it is a problem where I did not use the beta releases to correct my code.

  • I found the "stupid" in my code in the W6100 ethernet driver. It now works properly with PropellerTool 2.9.2.

    PUB readreg(REGISTER,BS,BLEN,RB) : r | i , LADDRL, LADDRH, tmpdata, tmpptr, datapin
    repeat until locktry(EthernetLock) < 0
      waitus(0) ' I removed this stupid thing in 3 places. All works correctly now.
    

    The bug has been fixed in both Pre-Release 4 and the Main branch.

  • ke4pjwke4pjw Posts: 1,169
    edited 2023-01-13 06:42

    Version and Uptime have been added to the Config screen. Once this has been regression tested, I will make it a full 1.0 release.

  • PR4 was promoted to the full 1.0 release, named Music City.

    Binary Release is here.

    Source is here.

    Version 1.1 is also in the works. I have been able to add a real-time view of over-the-air upgrades using Javascript's EventSource. This has been tested in Edge (Chrome) and Firefox, and should work on any modern browser. In addition, I will add MD5 checksums to downloads and upgrade abort/rollback features to the 1.1 release.

  • Great!

  • @jrullan said:
    Great!

    When you get your controller, if you have it configured to boot from SD, (flash off) it should give you the option to upgrade over the air from the config page. I am curious to know if it works for someone that's not me .

  • @ke4pjw said:

    @jrullan said:
    Great!

    When you get your controller, if you have it configured to boot from SD, (flash off) it should give you the option to upgrade over the air from the config page. I am curious to know if it works for someone that's not me .

    Got it on friday. Very exciting! Hope to turn on the switch this week. :)

  • For those that would like to buy boards, it's available in the GriswoldFX store:

    https://store.griswoldfx.com/blitzen-24-edge/

  • @ke4pjw said:
    For those that would like to buy boards, it's available in the GriswoldFX store:

    https://store.griswoldfx.com/blitzen-24-edge/

    Excellent! I DM'd you.

  • @ke4pjw said:
    For those that would like to buy boards, it's available in the GriswoldFX store:

    https://store.griswoldfx.com/blitzen-24-edge/

    Hi Terry!

    Did you post the details, dims & BOM for building and connecting that giant LED strip display somewhere ?

    I'm thinking with your board now available, that would be a neat summer project for me to hand a "lucky" student :)

Sign In or Register to comment.