Propeller Controlled 8x8 RGB LED Array ($7.50 from eBay)

Duane DegnDuane Degn Posts: 10,262
edited 2015-03-04 - 21:50:38 in Propeller 1
Here's my attempt at driving an eight by eight RGB LED array.

I paid just under $7 for these arrays but they now cost less than $6 $7.50 from ebay.

I'm using two SN754410 H-bridge chips to drive the eight anodes at 5V. The anodes are the rows of the array (I said columns in the video).

The 24 cathodes are controlled with three TPIC6B595 high power shift registers. There are three cathodes per column (one per color).

I used 150 ohm resistors between each red cathode and the shift registers and 100 ohm resistors on the green and blue cathodes. I'm not sure if the resistors are really needed, if I could make sure the multiplexing didn't stop. If I could be sure the multiplexing were reliable, I could probably remove the resistors and even increase the voltage to the array. I'd need to have the Prop control some of the enable pins on the H-bridges and/or shift registers because as it is now, when the Prop is reset the power to all the anodes is often turned on.

As I mentioned in the video, I initially tried to use only Spin in the control program. Spin couldn't cycle the LEDs fast enough to have controllable dimming without having a very pronounced flicker (I think "flash" is a more appropriate description than "flicker" in this case).

Even in PASM, I still had to keep the resolution down in order not to have a noticeable flicker. At 7-bits per color the flicker was noticeable on some colors (all colors to my wife). I might have been able to get away with 6-bits per color but I wanted to make sure the flicker wasn't a problem so I reduced the resolution to 5-bits per color. I personally think 32,768 colors is plenty on this type of a display.

While I don't think these displays look as nice as Parallax's new arrays (product page link) (forum post link), I'm think they're pretty darn cool for $6 each. I'm pretty sure I can control a couple of more displays with the same Propeller and still keep the 15-bit resolution. I'm planning on adding an additional set of three TPIC6B595 shift registers for every added array. I might use a separate data line for each set of shift registers in order to keep the PWM frequency relatively high (I'd still share the shift and latch lines). I think the 754410 h-bridge chips could probably handle multiple array rows so I doubt I'll need to add more of these.

I'll likely add some other fonts to the program. Back when I was looking for fonts for my 12x10 red LED array, I found that there were lots of 8 pixel high fonts. One thing I'd like to try with a scrolling text array, is to use some sort of variable brightness font where the LEDs aren't just on or off but some of the font's pixels would be dimmed compared to the others. I'm not sure if such fonts exist, but I've often wondered how a "grey scale" font would look.

I don't really have an application for these arrays in mind; I just thought they looked too cool to pass up. Some of you may have seen the LEDs I added to my hexacopter. I have 160 more of the LEDs I used on the hexacopter that will likely get used with other quad/hex 'copters in the future. I'm still trying to figure out if these 8x8 have aerial applications. I'm thinking they're probably too small (6cm squared) for a "Close Encounters" style light show.

I'm sure I could be persuaded to post the code if anyone is interested in it. I'll try to add support for a second (or more) array so the scrolling text is easier to read.

I know LEDs are supposed to be the easy stuff for microcontrollers, but I still get a kick out of seeing a bunch of LEDs light up in a fun pattern.
«1

Comments

  • Duane DegnDuane Degn Posts: 10,262
    edited 2013-05-08 - 13:47:41
    Schematic
    Updated June 4, 2013

    Caution!
    Not all LED arrays use the same pin configurations. The PCB I designed controls an array with the anode on pins 17 - 20 and pins 29 - 32 (inclusive). The cathodes to the green LEDs are on pins 21 - 28. Pins 1 - 8 are the cathodes of the blue LEDs and pins 9 - 15 are the red LEDs' cathodes.
    If you plan to use this schematic/PCB with a LED array make sure your array's pins match those just given.

    According to the datasheet of the array sold by ebay (link in post #1), the array being sold should work with this schematic. (The last time I checked the datasheet was on June 6, 2013.)

    Edit (November 13, 2013): A jumper must be added to J3 in order for the data in line to reach the chips on the board. This was added to allow multiple data lines for large displays.


    attachment.php?attachmentid=102085&d=1370405303

    J1 is the header across the top of the PCB with pin #1 on the left. Pins 1 through 4 connect to anodes of the top four rows of the RGB LEDs and pins 12 through 16 connect to anodes of the bottom four rows of the RGB LEDs. Pins 5 through 11 control the cathodes of the green LEDs.

    I'm using 100 ohm resistors for R1 - R8.

    J2 is the header across the bottom of the PCB with pin #1 on the left. Pins 1 through 8 control the cathodes of the blue LEDs and pins 9 through 16 control the cathodes of the red LEDs.

    I'm using also using 100 ohm resistors for R9 - R16. R17 - R24 limit current to the red LEDs which have a lower forward voltage than the green and blue LEDs. I'm using 150 ohm resistors on R17-R24.

    J4 is the header on the right side of the board. The top eight pins connect to the anodes of the LEDs.The shift register control pins and power connections make up the remaining eight pins. The "data in" pin is not directly connected to the first shift register. The jumper at J3 needs to be shorted in order for the data in pin on J4 to connect with the data in pin of the first (top) shift register. See not below about J3.

    J5 is very similar to J4, with only difference being a "data out" pin instead of a "data in" pin.

    I use a male right angle header on J4 and a female right angle header on F5. This lets me plug one LED board into another to make using the arrays in rows easier. If the pins at J3 are shorted, then the data lines of the shift registers get daisy chained from one board to the next. Daisy chaining more than two boards can cause problems in maintaining color resolution. I find two boards can display 25-bit color (5-bits each color) well but adding a third array will cause the displays to noticeably flicker with 24-bit color. To get around this problem, I've included an "alternate data in" connection. Pin 1 of J3 can be used to connect to another data line running in parallel with the original data in line. An independent wire would need to be connected between the "alternate data in" pin and the microcontroller. The microcontroller would need to be programmed to use this additional data line.

    I haven't programmed my current driver to use use a second data pin. I did use a second data pin on my all red LED array.

    There are three 0.1uF ceramic 0603 capacitors on the board. Each TPIC6B595 chip has one close to the Vcc pin.

    The anode drive chips are not located on this PCB. I use a separate PCB for the anode control since anode of multiple arrays may be driven in parallel.

    The TPIC6B595 datasheets states the high-level input voltage should be 0.85 * Vcc. At 5V this comes to 4.25V. I'm driving the logic directly from the Propeller's 3.3V I/O pins. I've used TPIC6B595 chips in several projects where I've used 3.3V logic without any problem.

    When I design a circuit board, I usually start by creating a schematic in Diptrace. With this board I skipped the schematic stage. I created this schematic after the fact so the PCB I'm using was not created directly from the above schematic.

    Here's the schematic to the LED array itself.

    attachment.php?attachmentid=102105&d=1370491053

    Row 1, pin 17 connects with pin 1 of J1 on the top schematic.

    Column 1, pin 1 on the LED array connects with pin 1 of J2 on the top schematic.

    Edit (November 13, 2013) I added note about J3 above the schematic. I also used the bold font on a line about J3 below the schematic (only the font was altered, not the text).

    attachment.php?attachmentid=104976&d=1384362585

    The location of the J3 jumper is shown above. The copper pours on the top and bottom layer have been blocked from this area so a small piece of wire can be used as a jumper (soldered in place).
  • Duane DegnDuane Degn Posts: 10,262
    edited 2013-05-08 - 13:48:01
    Bill of Material

    The prices listed are what I last paid for this items. It should be possible to purchase several of this components for less by purchasing larger quantities.

    PCB price to be determined.

    LED array. Presently $7.50 from eBay.

    TPIC6B595 high power shift registers $1.26 (in qty 100) (Digi-Key # 296-1956-5-ND). 3 required per array.

    Passives:
    Resistor 100 ohm 0603 size $0.0027)(in qty 1000)(Digi-Key # 311-100HRCT-ND). 16 required per array.
    Resistor 150 ohm 0603 size $0.00288) (in qty 1000)(Digi-Key # 311-150HRCT-ND). 8 required per array.
    Capacitor 0.1uF 0603 size $0.00813 (in qty 1000)(Digi-Key # 587-1240-1-ND). 3 required per array. 1 per anode drive chip also required.

    Headers:
    Female 1 x 40 $1.35 (in qty 10) (SparkFun # PRT-00115). 1 required per array. Needs to be cut into two 16 position segments.
    or
    Female 1 x 16 $0.9576 (in qty 25) (Digi-Key # S7049-ND). 2 required per array. This method is more expensive than using the 1 x 40 headers above.

    Male right angle 1 x 40 $1.76 (in qty 10) (SparkFun # PRT-00553). 1 required per two arrays. 14 pins are used per array.

    Female right angle 1 x 14 (tin) $0.964 (in qty 10)(Digi-Key # S5450-ND). Optional part. One per array may be added to allow daisy chaining arrays. Not needed for single array.

    Anode Drivers:
    SN754410 quad half bridge $2.12 (in qty 10) (SparkFun # COM-00315) 2 required to drive anodes. A single pair can drive more than one array.
    or
    ULN2803A Darlington array. $1.50 (Parallax # 500-00005) 1 required to drive anodes. Should only be used to drive a single array.
  • Duane DegnDuane Degn Posts: 10,262
    edited 2013-05-08 - 13:48:22
    Software
    Added June 8, 2013.

    It took me awhile longer to clean up this code than I had thought it would.

    There's a lot of memory shifting going on I made a few of my favorite mistakes (buffer overrun) as I attempted to streamline the code.

    I previously had several sub menus but I moved all the selection choice into a single menu in hopes it would make the program a bit more user friendly.

    Here's the displayed menu.
       8 x 8 RGB LED Array Demo
    
    
       program name of top object = Led3ByteColor130608hP
    
    
       LED mode = TEXT_MODE
       active color = RAINBOW
       number of active LEDs = 5
       brightness = 255
       scroll speed = 80
    
    
          Select a Mode.
    
    
       S) Stop / Off (all LEDs off)
       P) Pulse (buffer pulses)
       A) Cycling Pattern
       L) Cycling Colors
       T) Scroll Text
       X) Display Rainbow Text
    
    
       Or Select a Color.
    
    
       R) Red
       O) Orange
       Y) Yellow
       G) Green
       B) Blue
       V) Violet (really purple)
       W) White
    
    
       Other Actions
    
    
       +) Small Brightness Increase
       *) Large Brightness Increase
       -) Small Brightness Decrease
       /) Large Brightness Decrease
       6) Small Scroll Speed Increase
       8) Large Scroll Speed Increase
       4) Small Scroll Speed Decrease
       2) Large Scroll Speed Decrease
       0) "Free Design" Font
       1) "SimplyTronics" 5 x 8 Font
    
    
    
    
    

    I'll try to add a video of the various features of this demo sometime soon.

    The attached code has been cobbled together from several other projects. I removed a bunch of stuff in an attempt to make the program more readable be I know I left of bunch of unused variables.

    For instance in the method "MainMenu" there is the following code:
          case localCharacter
            "S", "s": 
              modifiableColorFlag := 0
              modifiableNumberFlag := 0
              modifiableBrightnessFlag := 0
              ledMode := OFF_MODE      
            "P", "p":
              modifiableColorFlag := 1
              modifiableNumberFlag := 1
              activeLedsUpperLimit := DISPLAY_PIXELS 
              activeLedsLowerLimit := 1
              modifiableBrightnessFlag := 1
              ledMode := PULSE_MODE            
    

    The variables "modifiableColorFlag", "modifiableNumberFlag", "activeLedsUpperLimit", activeLedsLowerLimit" and "modifiableBrightnessFlag" do not affect the way the program behaves. They are left over from a previous version which changed the menu choices based on these parameter. In order to simplify the program, I disabled this feature for the demo. I didn't want to completely delete all these variables since I plan to reinstate the features which use these variables.

    Edit(3/11/15): Warning, the code attached is an old version. There are likely better options available.
    I plan to upload this program or an improved version to my GitHub account
    If there isn't code similar to what is attached here on my on GitHub, send me a message and I'll make and check for any improved versions of the code.
  • Duane DegnDuane Degn Posts: 10,262
    edited 2013-05-08 - 13:48:42
    Temporary Software

    Added November 18, 2013. While the program was uploaded to the forum on November 18, 2013, the last time the program was modified was on June 19, 2013

    This program includes a feature for "graphing" the number of times the spacebar is pressed. The spacebar is used to show how other data could be displayed.

    The program is not documented well. I plan to clean this up a bit and make a video showing how some of the features are used. The video will likely be made within the next few days.

    I will likely remove this program once I post the cleaned up version.

    A menu will be displayed in a terminal window. If the menu isn't being displayed properly, it can be cleared and refreshed by pressing "c".

    I'm not sure if all the features listed in the menu are currently functionable.

    The number of displays can be changed by using the "5" and "3" keys. "5" adds one to the displays driven and "3" reduces the number of arrays. The robot eyes feature only works with two arrays.

    The color depth can also be changed while the program is running. The display will likely start to have a noticeable flash with color depths greater than 5-bits per color (15-bit color). The 15-bit color looks okay with two displays. If the number of displays is increased beyond two, the color bits will need to be reduced in order to keep the display from flashing.

    If only one bit per color is used (each color is either on or off), it is possible to drive six arrays without a noticeable flash.

    Warning: This program needs to be cleaned up. It's not really ready to be released but I wanted a version of the program which included the graphing feature to be available. I plan to post an improved version of this code and a demo video explaining its use within the next few days. If you're not anxious to try these new features, I'd suggest waiting a few days and download the improved version.

    I will add a post to this thread when the improved version is available.

    Edit(3/11/15): Warning, the code attached is an old version. There are likely better options available.
    I plan to upload this program or an improved version to my GitHub account
    If there isn't code similar to what is attached here on my on GitHub, send me a message and I'll make and check for any improved versions of the code.
  • Duane DegnDuane Degn Posts: 10,262
    edited 2013-05-08 - 13:49:13
    I made a PCB to hold the array, shift registers and other component to drive these inexpensive arrays.

    Here are a few pictures.

    attachment.php?attachmentid=101500&d=1368046217

    Above are the bare PCBs. I forgot and used an earlier revision in the photo. The pads (crossed out) in the top right corner of the left board are not on the final version.

    As I mentioned previously I'm using TPIC6B595 on the cathode side of the LEDs. I'm using 100 ohm resistors on the green and blue LEDs and 150 ohm on the red LEDs. I've been driving the circuit with 5V but I think it would be safe to drive them with even higher voltage if you could be sure to keep the multiplexing active. These are plenty bright at 5V. These are much much brighter than the Parallax displays.

    Here's a picture of a populated board.

    attachment.php?attachmentid=101499&d=1368046217

    I'm using headers so the array can plug into the boards. Here's a picture to so the hieght of a a completed board.

    attachment.php?attachmentid=101498&d=1368046217


    Since these arrays have the anodes in the center of the top pins, it's possible to mount the LEDs without headers to the bottom of the board. You'd need to switch the blue and red resistors and make changes in the software to change how the data gets clocked out to the shift registers but doing so would give you a thinner board. I'm not sure how you'd mount the array this way.

    One thing I've learned since starting this project is there are a lot of LED arrays available for some pretty good prices. I don't expect to make much selling these, but I thought I'd make them available in case anyone is interested.

    My current plan is to only charge a profit on the PCBs. I'll sell the other components at my cost(to those buying a PCB). I'm hoping $8 per PCB will make selling them worth the time and effort.

    It will be while (a month?) before I have extra PCBs to sell. I've already sold the few I had extra.

    I'm planning on making a large (how large I haven't decided) display using these arrays.

    I think something like SparkFun's LED coffee table would be cool. I'm not sure if I want to use 64 of these or not though.

    These PCBs require a separate Propeller board to control the shift registers. The PCB do not include the anode drive chips. One sent of anode drive chips could power several boards.

    I'm currently use SN754410 chips to drive the anodes. I'm very interested to hear about alternatives to the SN754410 chips for anode control.

    I'll add a BOM and more details in the next few days.
    748 x 276 - 114K
    441 x 342 - 118K
    742 x 340 - 157K
  • TinkersALotTinkersALot Posts: 535
    edited 2013-05-08 - 15:15:43
    Duane Degn wrote: »
    Here's my attempt at driving an eight by eight RGB LED array.

    ...Even in PASM, I still had to keep the resolution down in order not to have a noticeable flicker. At 7-bits per color the flicker was noticeable on some colors (all colors to my wife). I might have been able to get away with 6-bits per color but I wanted to make sure the flicker wasn't a problem so I reduced the resolution to 5-bits per color. I personally think 32,768 colors is plenty on this type of a display....

    Have you seen JohnyMac's RGB BAM driver in the Obex? It may be worth checking out.

    Duane Degn wrote: »
    I know LEDs are supposed to be the easy stuff for microcontrollers, but I still get a kick out of seeing a bunch of LEDs light up in a fun pattern.

    Posilutely Absotively Agree!
  • JonnyMacJonnyMac Posts: 6,939
    edited 2013-05-08 - 15:29:03
    Have you seen JohnnyMac's RGB BAM driver in the Obex? It may be worth checking out.

    I stopped using BAM a long time ago -- more problems than it's worth. I have, however, written a dimmer that used those TPIC6B595 shift registers. I'm going have to pick up a few of those displays and give my code a try.
  • Duane DegnDuane Degn Posts: 10,262
    edited 2013-05-08 - 15:34:30
    Have you seen JohnyMac's RGB BAM driver in the Obex? It may be worth checking out.

    I'm not sure if I've seen that particular object. I do use a lot of Jon's objects in my projects and I've learned a lot from his Spin Zone articles. I'll check out the BAM driver. I'm not sure if it will help much in this application since the shift registers need their bits in a particular order and my current PASM driver seems to be working well.

    Edit: My first attempt at posting didn't take. Since then I see JonnyMac posted.

    @Jon, If you PM your address, I'll send you a PCB. I'd sure like to return a favor if you'd let me.
  • TinkersALotTinkersALot Posts: 535
    edited 2013-05-08 - 16:02:07
    JonnyMac wrote: »
    ...written a dimmer that used those TPIC6B595 shift registers. I'm going have to pick up a few of those displays and give my code a try.

    Currently, I am playing with TLC5947's. They are pretty cool little devices.
  • Martin_HMartin_H Posts: 4,050
    edited 2013-05-08 - 16:29:57
    This is a neat project, I can't believe I missed it the first time. Using the H bridge chips as a current source is creative hack, but since you only want to drive the lines high wouldn't a darlington array work?
  • Duane DegnDuane Degn Posts: 10,262
    edited 2013-05-08 - 17:56:39
    Martin_H wrote: »
    This is a neat project, I can't believe I missed it the first time. Using the H bridge chips as a current source is creative hack, but since you only want to drive the lines high wouldn't a darlington array work?

    I mainly used the H-bridge chips since I had them on hand. Don't darlington's drop the voltage output a bit? I took another look at the SN754410 datasheet and it looks like they also drop the voltage. The SN754410 drop the voltage 1.4V (if I'm reading the datasheet correctly). So it looks like either way, I'd end up with a lower voltage.

    I'd really like to keep the driving voltage at 5V so I don't need another regulator. Also 5V power supplies are really common.

    Using a darlington array would be fine with me. I'm hoping to keep the current capacity pretty high since I'd like to use the same chips to drive multiple arrays. Even though only one row of LEDs is on at a time, there are still 24 LEDs per row. Multiply that by four arrays, and it adds up to kind of a lot of current.

    I wanted to keep the PCB small since the board houses charge by the square inch. I thought keeping the anode control separate from the cathode would let me keep the board small.

    I haven't used darlingtons much myself. I suppose they probably make higher current versions than the ULN2303A I'm familiar with?

    I'm open to suggestions on the best way to drive the anodes.

    Once I decide on a driving chip, I'll likely make a board to plug into a QuickStart.

    I'm still unsure how many displays I can drive with a single Propeller. I know one cog can drive two displays with 5-bits per color resolution. I don't recall if I was able to get a third board working with a single cog. I think I did but the flicker started to be noticeable.

    12 arrays per Propeller shouldn't be a problem. I'll need to keep one cog as a master control and a second cog to control the serial line(s). The remaining six cogs could drive two arrays each.

    So to make my 64 array coffee table, I may need up to six Propeller chips. Or. . . nine Props to control 100 arrays.
  • Martin_HMartin_H Posts: 4,050
    edited 2013-05-09 - 03:20:12
    All of the 8 output darlington arrays I've seen are limited to 500 ma, but the four output arrays can go up to 1.5 A. But if you budget 30 ma per LED, an 8 output darlington could drive 16 LED's. With LED's I don't worry about voltage as long as it's above the LED's forward voltage. I just pick a current limit resistor that provides the desired current at that voltage.
  • Duane DegnDuane Degn Posts: 10,262
    edited 2013-06-04 - 16:26:56
    Martin_H wrote: »
    All of the 8 output darlington arrays I've seen are limited to 500 ma, but the four output arrays can go up to 1.5 A. But if you budget 30 ma per LED, an 8 output darlington could drive 16 LED's. With LED's I don't worry about voltage as long as it's above the LED's forward voltage. I just pick a current limit resistor that provides the desired current at that voltage.

    Martin, Sorry for not replying to your post sooner. Thanks for the information. Here's my problem, each anode needs to drive up to 24 LEDs at a time. I had planned to be able to drive each LED at about 20mA. The datasheet says their max current is 50mA. Apparently I've been driving them far below the 20mA target. Since the anodes are only 3.6V instead of 5V the current to each LED is greatly reduced since I calculated resistor values assuming a 5V driving voltage. As I previously mentioned, I used 100 ohm resistors on the green and blue LEDs. These have a forward voltage of 3.4V so the remaining 0.2V is voltage drop across the resistor. This give a current of only 2mA through the blue and green LEDs. This sure seems strange to me because the LEDs look so bright.

    If I were to increase the voltage to the anode drive chips so the output was 5V and not 3.6V, it's possible each anode would need to provide 480mA. So the ULN2303A should work with one array but if I want to drive multiple arrays from the same set of chips I'd need a higher current solution than the ULN2303A

    I plan to use a 7.4V source on my drive chips so get the full 5V to the LED/resistors. Oh, wait. Does the shift register have a voltage drop? I'll need to check. I may need more than 7.4V to get 5V across the LEDs.

    Does anyone know of a drive chip that can output 5V with a 5V supply? Is there such a chip that can supply several amps to drive multiple arrays at once?

    I'm still trying to figure out the best way to drive the anodes on the arrays.
  • Duane DegnDuane Degn Posts: 10,262
    edited 2013-06-04 - 16:35:54
    I've added a schematic to post #2. I still have a few things I plan to add to post #2 so check back later to see the additions.

    Here are the top and bottom layers of the boards I've made so far. The the top of the board is displayed in yellow.

    attachment.php?attachmentid=102073&d=1370388491

    The top layer has a 5V power plane.

    The bottom of the board is displayed in orange.

    attachment.php?attachmentid=102074&d=1370388492

    Its copper pour is connected to ground.

    Please let me know if any of you have suggestions for improvements.
    655 x 657 - 57K
    631 x 631 - 45K
  • Duane DegnDuane Degn Posts: 10,262
    edited 2013-06-05 - 19:45:07
    The size of my current PCB design is just a little bit over 5cm squared. If I can trim the board down to 5cm x 5cm I can take advantage of Itead's $9.95 for 10 board deal.

    This is what my 5cm x 5cm board design looks like.

    attachment.php?attachmentid=102102&d=1370486157

    I'm debating if I should make the mounting holes smaller. The holes are currently 0.125" which works with 4-40 and M3 hardware. Having the hole so close to the edge of the board makes me a bit nervous but I'd rather not reduce its size. I also don't see a logical alternative location for the mounting holes.

    The grey square surrounding the PCB is the size of the LED array (6cm x 6cm).

    Any suggestions on improving this latest revision?
    745 x 752 - 63K
  • Duane DegnDuane Degn Posts: 10,262
    edited 2013-06-08 - 16:08:43
    A couple of days ago, I added a BOM to post #3 above.

    I just now added software to drive these arrays to post #4.

    I'll try to add some video of the demo code in action soon.
  • Duane DegnDuane Degn Posts: 10,262
    edited 2013-06-09 - 16:46:27
    MJB,

    Thanks for the information and links. Your post got me wondering about other arrays I've seen. After looking around Adafruit a bit, I remembered Rayman had worked on driving Adafruit's 16x32 RGB arrays.

    Adafruit's 16x32 arrays are only $44.95 now. I just sold two of my PCBs with parts to make two 8x8 arrays for $42.90. I sold the parts at my cost. I now realize I'd crazy to try to make these arrays to sell. If the parts for an 8x16 array cost almost as much as an array with four times as many LEDs, I think there will not be much interest in my little PCBs.

    I've used LED strips with WS2801 chips to control the individual LEDs but I haven't ever tried the WS2803 chips. The HT1632C chip looks interesting. I couldn't figure out if it would be a good match for these arrays or not. From what I could figure out, it looks like they work better with common cathode arrays rather than common anode arrays (these ebay arrays are common anode).

    I noticed the Adafruit 16x32 arrays drive the red green and blue data lines in parallel. I may try modifying my design to use separate data lines for each color. Each of the colors use a separate shift register chip in my design since pins controlling the colors are grouped together on the LED module, routing all the traces of a single color to a single chip was much easier than laying out a board with alternating colors connecting to each chip (as I had done with my breadboarded circuit in post #1). I should be able to route a couple of extra data lines without too much trouble. Being able to clock out three bits of color at once should make it possible to chain more arrays together than just two or three.
  • Duane DegnDuane Degn Posts: 10,262
    edited 2013-06-11 - 14:29:19
    As I've mentioned a couple of times in this thread, I'm still very unsure about how to drive the anodes of these arrays.

    For now, I've been using SN754410 H-bridge chips to drive the anodes.
    Here's a schematic of how I'm using the SN754410 chips.

    attachment.php?attachmentid=102201&d=1370984789

    I think I'll probably increase the supply for the anode power from 5V to 7.5V or 8V to compensate for the drop across the semiconductors.

    I also plan to try using the Darlington array mentioned by Martin. Page 56 (I think it's page 4 of the pdf) of this article mentions how to use a Darlington array.

    I looks like the Darlington used a similar way as the h-bridge. The Prop connects to the "In" pins and the LED anodes connect to the "Out" pins.
    1024 x 697 - 51K
  • Duane DegnDuane Degn Posts: 10,262
    edited 2013-11-13 - 09:17:35
    I added a note about the need for a jumper on the data in line to post #2.

    I also added this image to show the location of the jumper.

    attachment.php?attachmentid=104976&d=1384362585

    While the jumper was mentioned in the earlier post it was not very obvious. Sorry for not making this requirement more apparent.
  • zenthoefzenthoef Posts: 16
    edited 2013-11-19 - 10:36:00
    I have been trying to get the graph to slow down beyond the MIN_SCROLL_SPEED. I'd like the graph to move over once every minute (in the future 10 minutes) or so. Obviously, I can't make MIN_SCROLL_SPEED go any lower than 0, but I thought there might be somewhere else in the code where I can increase the scrolling delay. Is there a place like this? Where can I find it in the code?
  • Duane DegnDuane Degn Posts: 10,262
    edited 2013-11-19 - 11:35:38
    I posted some newer code (six months old today) to post #5 above. I told zenthoef in a PM about the code. That's what his question is about.
    zenthoef wrote: »
    I have been trying to get the graph to slow down beyond the MIN_SCROLL_SPEED. I'd like the graph to move over once every minute (in the future 10 minutes) or so. Obviously, I can't make MIN_SCROLL_SPEED go any lower than 0, but I thought there might be somewhere else in the code where I can increase the scrolling delay. Is there a place like this? Where can I find it in the code?

    As you noticed, I have the following constants to set the minimum and maximum scroll speeds.
    MIN_SCROLL_SPEED = 0              '' user changeable  MAX_SCROLL_SPEED = 100            '' user changeable but don't go higher
    

    I had tried to come up with some sort of equation to convert a speed to a delay. I noticed all my linear equations didn't work very well. I finalally decided to use a logrithmic scale between speed and delay but I didn't want to have to add floating point math to the program nor did I want to learn how to access the Prop's internal log tables (though this would have been a better solution). Instead a generated a table in a spreadsheet and included it to the DAT section as the "speedToDelay" array.
    DAT 'speed to delay lookup table
    
    speedToDelay            long 2000, 1951, 1904, 1857, 1811, 1765, 1721, 1677, 1635, 1593
                            long 1551, 1511, 1471, 1432, 1394, 1357, 1320, 1284, 1249, 1214
                            long 1180, 1147, 1115, 1083, 1051, 1021, 991, 961, 933, 904
                            long 877, 850, 824, 798, 772, 748, 723, 700, 677, 654
                            long 632, 610, 589, 569, 549, 529, 510, 491, 473, 455
                            long 438, 421, 404, 388, 373, 358, 343, 328, 314, 301
                            long 287, 275, 262, 250, 238, 227, 216, 205, 194, 184
                            long 175, 165, 156, 147, 139, 131, 123, 115, 108, 101
                            long 94, 88, 82, 76, 70, 65, 59, 55, 50, 46
                            long 41, 37, 34, 30, 27, 24, 21, 18, 16, 14
    extraJustIncase         long 12, 10, 8, 6, 4, 3, 2, 1, 0
    

    The above table is in units of milliseconds but these values get converted to clock cycles so you're delay amount is limited to the number of clock cycles it takes for the Prop to rollover its counter. This limits the delay to about 53 seconds (it might be half this amount).

    This would be rather easy to change. The method "IncrementTime" is used to wait for the next scroll time. Instead of having the time measured in clock cycles, the time could be measured in seconds. You'd then need a way of counting up seconds. You'd also want to change the program not to wait for the next scroll time but to just check to see it the time has passed yet.

    You might want to check one of the real time clock objects to see how to measure longer periods of time. There's a SpinZone article about keeping time with the Propeller. I learned a lot about programming the Propeller from JonnyMac's SpinZone articles (there's a link in post #3 of my index).

    If you get stuck making a longer delay let me know.
  • Duane DegnDuane Degn Posts: 10,262
    edited 2015-02-28 - 10:16:20
    Here's a stripped down version of the LED code.

    This one just graphs input from an I/O pin (active low).

    I haven't tested this code yet. I know it's not a good idea to post untested code but once in a while I get lucky and untested code works.

    Besides graphing input from the I/O pin, it will also graph lowercase "s" presses.

    I'll test this myself once I find my arrays.

    The attached code should work with either one or two arrays. If more than two arrays are used, one of the constants will need to be changed.

    Edit: Not surprisingly, the attached code does not work. I have found my arrays and I'm currently trying to figure out what's wrong.
    Edit again: I've removed the non-working code. See post #26 for an improved version.
  • Duane DegnDuane Degn Posts: 10,262
    edited 2015-02-28 - 11:36:27
    I found my arrays and tested the code. It does not work.

    I'm trying to figure out why now.
  • Duane DegnDuane Degn Posts: 10,262
    edited 2015-02-28 - 11:56:20
    This version kind of works.

    The "s" key can be used along with the active low pin. The "enter" key will force the display to progress one column without waiting for the time period to elapse.

    There's still a ghosting issue. I think I found this problem in the past but for some reason the fix isn't included here. I'll either find the fixed version or fix it again.

    Edit: This "c" version should be a little better than the "b" version. There's still some ghosting. I can't find the cause.

    Edit(3/11/15): Warning, the code attached is an old version. There are likely better options available.
    I plan to upload this program or an improved version to my GitHub account
    If there isn't code similar to what is attached here on my on GitHub, send me a message and I'll make and check for any improved versions of the code.
  • zenthoefzenthoef Posts: 16
    edited 2015-02-28 - 14:02:02
    I'll be trying this out tonight! Thanks Duane!
  • zenthoefzenthoef Posts: 16
    edited 2015-03-02 - 17:39:46
    I've been looking and the code and have come up with several questions, and I'm going to start with high-ish level questions in this post, and work my way down to the details in later posts.

    1. To use the Led object, all I really have to do is pass all the parameters defined by Led.Start, and then update eventCount each time there is an event, correct? I think it is clear how most of those parameters are used by Led.Start. The two parameters I am confused about are @pixel0 and @displayBuffer. How are used both in GraphRgbDemo150228c and GraphRgb150228c? I understand that pixel0 is related to the color each row is set to, and that displayBuffer is how the graph is displayed, but beyond that I don't understand how they work.

    2. Several questions about the Led object:
    a. GraphLeds appears to have two main tasks: Use LoadColumn() to update the 0th column with the color definitions given by columnColorsPtr and use ScrollDisplay to scroll the graph over one column if the timer expires or the scroll is forced. Are these the main things this method does or did I miss something?

    b. I think LoadColumn() loads the column specified by dataThisColumn, and supplies the color definition for each row. Am I on the right track? If I'm not, could you fill me in on what this method does?

    c. My last question for now is about ScrollSpace(). I know this method scrolls the graph to the left by the localSize variable value. Beyond that, I'm also confused about how this method works. Can you clarify how it works for me?

    3. Is the data that is graphed stored in displayBuffer? If so, how does that work?
  • Duane DegnDuane Degn Posts: 10,262
    edited 2015-03-02 - 20:19:34
    zenthoef wrote: »
    I've been looking and the code and have come up with several questions, and I'm going to start with high-ish level questions in this post, and work my way down to the details in later posts.

    1. To use the Led object, all I really have to do is pass all the parameters defined by Led.Start, and then update eventCount each time there is an event, correct?
    zenthoef wrote: »
    I think it is clear how most of those parameters are used by Led.Start. The two parameters I am confused about are @pixel0 and @displayBuffer. How are used both in GraphRgbDemo150228c and GraphRgb150228c? I understand that pixel0 is related to the color each row is set to, and that displayBuffer is how the graph is displayed, but beyond that I don't understand how they work.

    "@pixel0" Is the location of the first set of colors to be used when graphing. I would be possible to change these values as the program is running. If the values stored in the "pixel" arrays were to change, the colors used to graph the data would also change. If the colors were changed while the program was running, only the new columns would contain the new colors. The previously filled columns wouldn't be affected by the new colors.

    The demo program doesn't change these colors while the program is running but it would be possible to have certain events cause the colors used in the graph to change. As the demo program is currently written, the colors used by the graph could be easily changed by manualling typing in new values and loading the new code to the Propeller.

    Each pixel is made up of three bytes. One byte per color (red, green and blue). The low level driver doesn't always use all 8-bits for each color. The default color depth is 5-bits per color. The '595 shift registers take too long to refresh to produce full 8-bit color (while testing, I had a hard time distinguishing between 8-bit color and 5-bit color, I thought both color depths looked good).

    Here's the list of colors used to graph the data. As mentioned in the comments, the first three bytes correspond to the lowest pixel of the column being graphed.

    The parameter "columnColorsPtr" in the child object receives the memory location "@pixel0" so the child object knows where to find the color information to copy into the display buffer. See page 173 of the Propeller Manual v1.2 for information about the Symbol Address operator ("@").
    DAT
     
    columnColors                'red  green, blue
    pixel0                  byte $00, $FF, $00  ' green (on the bottom)
    pixel1                  byte $00, $FF, $00
    pixel2                  byte $FF, $6F, $00  ' yellow
    pixel3                  byte $FF, $6F, $00
    pixel4                  byte $FF, $2F, $00  ' orange
    pixel5                  byte $FF, $2F, $00
    pixel6                  byte $FF, $00, $00
    pixel7                  byte $FF, $00, $00  ' red at the top 
    

    The array "displayBuffer" is used as the display buffer. The location of this buffer is passed to the child object with "@displayBuffer". I'll go into more detail how the pixels are organized in the display buffer while answering one of your other questions.

    The address "@displayBuffer" is received by the child parameter with the local variable "displayBufferPtr_". This is then stored in a global variable "displayBufferPtr". The two variables names (local and global) have to be different from each other so I just add the underscore to the local name. The global variable "displayBufferPtr" allows the other methods to access the display buffer. This same address is passed to the low level driver which continuously reads the values from the display buffer and uses the information to know when a LED should be turn on or not.
    zenthoef wrote: »
    2. Several questions about the Led object:
    a. GraphLeds appears to have two main tasks: Use LoadColumn() to update the 0th column with the color definitions given by columnColorsPtr and use ScrollDisplay to scroll the graph over one column if the timer expires or the scroll is forced. Are these the main things this method does or did I miss something?

    I think you understand how the "GraphLeds" method works. The value "dataThisColumn" is the amount "eventCount" (in the parent object) has changed since the last time the columns were scrolled. If the interval being monitored is 26 seconds or less, the time can be measured directly as clock cycles but for intervals longer than 26 seconds the math won't work out correctly if clock cycles are used because of the 32-bit roll over (and the math only works up to 31-bits). In order to allow longer intervals, I timed the intervals with milliseconds. Using milliseconds, I think the interval can be about four days before there's a 32-bit math problem.
    zenthoef wrote: »

    b. I think LoadColumn() loads the column specified by dataThisColumn, and supplies the color definition for each row. Am I on the right track? If I'm not, could you fill me in on what this method does?

    I think you're understanding correctly. The "LoadColumn" method either fills the column with the background color:
    background              byte 0, 0, 0
    

    Or it copies the colors listed under "pixel0" in the parent object. Rather than copying the colors directly, the method reduces the brightness of the colors if the brightness has been set less than 255 (aka $FF). IMO, it's easier to add a brightness correction than changing all the color values listed under "pixel0". While there's a method to change the brightness, the demo doesn't use this method. Any changes to brightness will only affect the new columns graphed. The values already loaded to the display buffer won't be changed.
    zenthoef wrote: »

    c. My last question for now is about ScrollSpace(). I know this method scrolls the graph to the left by the localSize variable value. Beyond that, I'm also confused about how this method works. Can you clarify how it works for me?

    The method "ScrollSpace" was reused from the earlier program which included scrolling text. "ScrollSpace" adds blank columns to the display buffer. The blank columns in this case are unlit LEDs but if the value of the three bytes used as "background" were non-zero values, the blank columns would be lit with the colors stored in the "background" three byte array.

    Since we read left to right, scrolling text looks best when it enters from the right of of a display and moves to the left. Graphed data also seems more intuitive when scrolled this same direction. The "ScrollSpace" method is used to add space between characters when scrolling text. I use it in this program to scroll a single column and then load this blank column with the latest data to be graphed.

    The start of the display buffer starts at the top left pixel of the display. Each pixel is three bytes so each row of the display is three times the width (in pixels) of the display. The width of the display is eight times the number of 8 x 8 arrays used in the display. The default number of arrays is two. It doesn't cause the program a problem if only one array is used when it's set to use two arrays. Since the program is set to use two arrays, the display buffer is 16 pixels wide. 16 pixels is 48 bytes. The 49th byte (element 48 of the array) takes us back to the far left of the display but down one row. The display buffer for two 8 x 8 RGB arrays is 3 * 2 * 8 * 8 = 384 bytes.

    The bottom right pixel of the display is corresponds with the last three bytes of the "displayBuffer" array.

    If two arrays are used, once the graph reaches the left side of the right array, it will continue on to the right side of the left array. If the power to the anodes is connected through the right side, then the left array may be plugged in or unplugged while the program is running. When the second array is connected, it will immediately display the data in the display buffer.

    If more than two arrays are used, the constants in the low level object should be changed to reflect the number of arrays in use. The low level driver can change the number of arrays and the color depth on the fly (I think the cog stops and restarts) but there isn't an example of how to do this in the graphing program.

    zenthoef wrote: »
    3. Is the data that is graphed stored in displayBuffer? If so, how does that work?

    Hopefully this was just answered in reply to question 2c.

    It could be argued rather than using three bytes per color, I should use a single long. This is a valid option. I have other RGB LED projects which store each pixel in a long. It's really not much harder to shift groups of three bytes as it is to shift longs. If one is making a large LED array, the savings in RAM from using three bytes rather than four bytes in a long can make the little extra work to shift the bytes worth the effort.
  • zenthoefzenthoef Posts: 16
    edited 2015-03-04 - 17:38:25
    That really helps clear things up. Thanks Duane!

    As promised, there are a few things that I am still confused about, but are not quite as big picture. Here are my final (for now) questions:

    1. In GraphRgb150228c, why does Start return the result of @ledStack? I don't see where this pointer value is used in GraphRgbDemo150228c. Is it there for use in the future or am I missing something?

    2. I think I'm starting to understand how to columnColors data structure works. Is columnColors a structure that contains pixel0 thru pixel7? If so, it looks like each time AdjustBrightness() is called, it uses the address given by @pixel0 as a reference point to get the current pixelX address in columnColors for the pixel row that is being loaded. Is that accurate? Hopefully you can understand that; I feel like my explanation of what I think is going on is convoluted.

    3. Initialization questions:
    a. In GraphRgb150228c, method GraphLeds, does previousDataValue get initialized to 0 somewhere? I can't seem to see it being initialized in GraphLeds function. Also, does GraphLeds return previousDataValue? Is that why it is declared after the : in the function declaration? If it does return that value, where does it get returned to?

    b. In GraphRgbDemo150228c, where does eventCount get initialized? Or is it simply initialized to 0 by declaring it? Or does it even need to be initialized? I think the two initialization question are more issues of me learning the Spin syntax.

    Those are all my questions for now. I think I have a really good idea of how to use the code.

    Now that I have a better understanding of what your code is doing I have to say I am really impressed with what you have done! I think you have made some really amazing code! I think I'll be getting my custom PCBs for my project this weekend. If so, I will put this all together and possibly post a video of it.
  • Duane DegnDuane Degn Posts: 10,262
    edited 2015-03-04 - 21:50:38
    zenthoef wrote: »
    1. In GraphRgb150228c, why does Start return the result of @ledStack? I don't see where this pointer value is used in GraphRgbDemo150228c. Is it there for use in the future or am I missing something?

    I had the Start method return the address of the stack so I could check to see how much of the stack was really being used. IIRC it used 55 of the 100 longs reserved for the stack. Somewhere (towards the end of the list) in post #2 of my index is a link "My attempt to understand stack space" or something like that. I used techniques described in that thread to monitor the stack space. I removed the stack monitoring code but left the address to the stack as the return value.
    zenthoef wrote: »
    2. I think I'm starting to understand how to columnColors data structure works. Is columnColors a structure that contains pixel0 thru pixel7? If so, it looks like each time AdjustBrightness() is called, it uses the address given by @pixel0 as a reference point to get the current pixelX address in columnColors for the pixel row that is being loaded. Is that accurate?

    I think you understand this. The "columnColors" is the address of "pixel0" in the parent object. The colors are adjusted for brightness by "AdjustBrightness" before being copied to the display buffer. You can use a different initial brightness level by either changing the value of "brightness" at the bottom of the DAT section in the parent object or by changing the value of "DEFAULT_BRIGHTNESS" in the child object.

    The "+" and "-" keys should also adjust the brightness but brightness is perceived on a logarithmic scale so you'll have to press "-" many times (like 100) to see a big difference.
    zenthoef wrote: »
    3. Initialization questions:
    a. In GraphRgb150228c, method GraphLeds, does previousDataValue get initialized to 0 somewhere? I can't seem to see it being initialized in GraphLeds function. Also, does GraphLeds return previousDataValue? Is that why it is declared after the : in the function declaration? If it does return that value, where does it get returned to?

    Global variables (defined in the VAR section) are initialized to zero and the "result" local variable is also initialized to zero. When a local variable is declared with the ":" it becomes another name for the "result" variable. If I need a local variable initialized to zero, I often use as the "result" variable as I did with "previousDataValue". The method "GraphLeds" is an endless loop so it never returns a value.
    zenthoef wrote: »
    b. In GraphRgbDemo150228c, where does eventCount get initialized? Or is it simply initialized to 0 by declaring it?

    I think I just covered this. Global variables are initialized to zero. It is very important to remember local variables are not initialized with the exception of "result" which each method has as its return value. If result is renamed, it is still initialized to zero.

    The Propeller Tool allows you to use both "result" and an alias for "result" without warning you've done so. This has caused me trouble a couple of times with I end up using two names for the same variable.

    I look forward to seeing a video. Good luck with it. I've made videos several times of my arrays but I end up not posting them since the colors never look as good in the video as they do in real life.
Sign In or Register to comment.