Shop OBEX P1 Docs P2 Docs Learn Events
WS2812 light controller with ENC28J60 ethernet — Parallax Forums

WS2812 light controller with ENC28J60 ethernet

EE351EE351 Posts: 81
edited 2014-04-11 09:09 in Propeller 1
Hello all!

I have been able to coble together an Ethernet based ws2812 light controller using code found on this forum. The Ethernet driver was written by Harrison Pham, the UDP code was written by localroger, and the ws2812 driver was written by Jon McPhalen. Using xLights pc software, I can output E1.31 data to control 480 ws2812 leds across 6 output pins (80 leds per pin) at a refresh rate of 20 hz. I hope to double the number of leds with the same refresh rate, but I am not sure how to speed up the code I wrote to combine the hardware. I think the bottleneck is where the udp packet is analyzed and the ws2812 code is called. Hopefully someone here can tell me if there is a better way to handle this.

UDP_enc28j60_ws2812_demo.zip
PRI handle_udp | udplen, i, templong 
  '

    '
 
  
  other_mac_known~~     
  
  udplen := packet[udp_len]<<8 + packet[udp_len+1]
  if udplen > eth_pkt_max - 34
    udplen := eth_pkt_max - 34
  'i := udp_data
 ' repeat while i <  udplen+constant(udp_data-8) and ser.txcheck
    'ser.tx(packet[i++])
 
  if (packet[156] == 10)                       'check the universe #
    repeat i from 0 to 79
      templong.byte[1] := packet[3*i+168]
      templong.byte[2] := packet[3*i+169]
      templong.byte[0] := packet[3*i+170]
      strip.set(i,templong)

  if (packet[156] == 11)                       'check the universe #
    repeat i from 0 to 79
      templong.byte[1] := packet[3*i+168]
      templong.byte[2] := packet[3*i+169]
      templong.byte[0] := packet[3*i+170]
      strip2.set(i,templong)

  if (packet[156] == 12)                       'check the universe #
    repeat i from 0 to   79
      templong.byte[1] := packet[3*i+168]
      templong.byte[2] := packet[3*i+169]
      templong.byte[0] := packet[3*i+170]
      strip3.set(i,templong)

  if (packet[156] == 13)                       'check the universe #
    repeat i from 0 to 79
      templong.byte[1] := packet[3*i+168]
      templong.byte[2] := packet[3*i+169]
      templong.byte[0] := packet[3*i+170]
      strip4.set(i,templong)

  if (packet[156] == 14)                       'check the universe #
    repeat i from 0 to 79
      templong.byte[1] := packet[3*i+168]
      templong.byte[2] := packet[3*i+169]
      templong.byte[0] := packet[3*i+170]
      strip5.set(i,templong)


  if (packet[156] == 15)                       'check the universe #
    repeat i from 0 to 79
      templong.byte[1] := packet[3*i+168]
      templong.byte[2] := packet[3*i+169]
      templong.byte[0] := packet[3*i+170]
      strip6.set(i,templong)

Comments

  • kwinnkwinn Posts: 8,697
    edited 2014-03-27 22:36
    The simplest thing to try would be a case statement in place of the multiple if's to see how much that speeds it up. The next thing would be to divide the analysis of the udp packet and possibly the driving of the leds between multiple cogs.
  • EE351EE351 Posts: 81
    edited 2014-03-28 11:44
    I'll try changing the if statements to case statements. Right now, each ws2812 output pin is running in it's own cog.
    kwinn wrote: »
    The simplest thing to try would be a case statement in place of the multiple if's to see how much that speeds it up. The next thing would be to divide the analysis of the udp packet and possibly the driving of the leds between multiple cogs.
  • kwinnkwinn Posts: 8,697
    edited 2014-03-28 21:49
    EE351 wrote: »
    I'll try changing the if statements to case statements. Right now, each ws2812 output pin is running in it's own cog.

    Perhaps you could have each of the 6 cogs analyze the packet input for two of the cases and control two of the pins going to the leds. Not sure if that is possible without looking at all the code you are using now.
  • EE351EE351 Posts: 81
    edited 2014-03-29 14:07
    I was able to speed up things slightly by using a variation of Jon's WS2812 driver. I can now drive 95 pixels per output at a 20 hz rate to each of the six outputs. I'm pretty sure if I could offload the udp packet handling to the cog driving the WS2812 leds, it would run much faster. I'm just not sure how that can be done without rewriting the ws2812 driver.

    UDP_enc28j60_ws2812_demo2.zip
    PRI handle_udp | udplen, i, templong 
      '
    
        repeat i from 0 to ledNO - 1
          templong.byte[1] := packet[3*i+168]
          templong.byte[2] := packet[3*i+169]
          templong.byte[0] := packet[3*i+170]
          RGB[i] :=templong
    
      case packet[156]
        10 : strip.execute(LEDS,ledNO,@RGB)    'check the universe # 
        11 : strip2.execute(LEDS2,ledNO,@RGB)
        12 : strip3.execute(LEDS3,ledNO,@RGB)
        13 : strip4.execute(LEDS4,ledNO,@RGB)
        14 : strip5.execute(LEDS5,ledNO,@RGB)
        15 : strip6.execute(LEDS6,ledNO,@RGB)
    
  • EE351EE351 Posts: 81
    edited 2014-04-02 21:13
    I was able to optimize the spin routine that transfers the udp packet data to the ws2812 driver. I can now drive 70 leds across 12 output pins.

    UDP_enc28j60_ws2812_demo3.zip
    PRI handle_udp | i, templong, tempindex
      '
        tempindex:=167                                'byte before R, G, B bytes
        repeat i from 0 to ledNO -1 
          tempindex++
          templong.byte[1] := packet[tempindex]
          tempindex++
          templong.byte[2] := packet[tempindex]
          tempindex++
          templong.byte[0] := packet[tempindex] 
          RGB[i] :=templong
          
         
      
      
      case packet[156]                           'check the universe #
        10 : strip.execute(LEDS,ledNOD2,@RGB)
           strip2.execute(LEDS2,ledNOD2,@RGB[ledNOD2])
             
        11 : strip3.execute(LEDS3,ledNOD2,@RGB)
             strip4.execute(LEDS4,ledNOD2,@RGB[ledNOD2])
        
        12 : strip5.execute(LEDS5,ledNOD2,@RGB)
             strip6.execute(LEDS6,ledNOD2,@RGB[ledNOD2])
        
        13 : strip.execute(LEDS7,ledNOD2,@RGB)
             strip2.execute(LEDS8,ledNOD2,@RGB[ledNOD2])
        
        14 : strip3.execute(LEDS9,ledNOD2,@RGB)
             strip4.execute(LEDS10,ledNOD2,@RGB[ledNOD2])
        
        15 : strip5.execute(LEDS11,ledNOD2,@RGB)
             strip6.execute(LEDS12,ledNOD2,@RGB[ledNOD2])
    
  • EE351EE351 Posts: 81
    edited 2014-04-10 19:04
    I have improved it a bit more, it can now output data for 1008 pixels across 18 outputs at a 20hz rate.

    UDP_enc28j60_ws2812_demo4.zip
  • TubularTubular Posts: 4,703
    edited 2014-04-11 07:47
    Nice work so far, EE351

    I've been working on a pasm based ws2812 driver that might help your case. Its designed to drive 5 strips at full pelt from a single cog running at 100 MHz.

    But, there is one last challenge to solve that is proving elusive, and I should probably throw it over to the forum. Worst case is I will have to drop to 4 strips per cog (which is OK since there are 28 free pins, so 7 cog drivers + 1 master cog), or accept a bit rate slower than 800 kbps. Its just I was hoping to have some more cogs free

    This should be able to use all the hub ram, if desired, so you're looking at up to ~7,000 leds managed by a single prop. Divide by 28 outputs, 250 leds per output, at around a 130 Hertz refresh rate. Not bad for a $8 micro, still available in DIP :)
  • EE351EE351 Posts: 81
    edited 2014-04-11 09:09
    Thanks, I think right now I'm more constrained by the enc28j60. I seem to recall reading on the forums that it maxes out at about 100 kilobytes/second and I'm currently pushing about 80 kB. A faster ethernet chip could be used instead but you can't beat the enc28j60 for the price (about $3.60 for a complete breakout board on ebay).
    Tubular wrote: »
    Nice work so far, EE351

    I've been working on a pasm based ws2812 driver that might help your case. Its designed to drive 5 strips at full pelt from a single cog running at 100 MHz.

    But, there is one last challenge to solve that is proving elusive, and I should probably throw it over to the forum. Worst case is I will have to drop to 4 strips per cog (which is OK since there are 28 free pins, so 7 cog drivers + 1 master cog), or accept a bit rate slower than 800 kbps. Its just I was hoping to have some more cogs free

    This should be able to use all the hub ram, if desired, so you're looking at up to ~7,000 leds managed by a single prop. Divide by 28 outputs, 250 leds per output, at around a 130 Hertz refresh rate. Not bad for a $8 micro, still available in DIP :)
Sign In or Register to comment.