New Art / Study Project

julianE

Senior Member
Oh wow, what a complicated process, I almost wish you had went with the home made boards. I have ordered other people's designs and the boards are always well made, I'm pretty sure you'll be pleased by the boards you had made. Thank you for taking the time to explain the process much better than the information I read on line. I also did not know that I had to be online in order to use the program that's a bit of an annoyance but something everything is headed towards. I'm old enough to remember main frames and how a PC on every desk was going to free us, we have circled back to mainframe/terminal paradigm.

Thanks again for all the info, I'll take your advice and make a simple transistor circuit as an exercise before making more complicated boards.
 

datasmith

Well-known member
Got my first PCBS from JLCPCB today. Let's see, I ordered them on the 29th of March. They got here on the the 6th of April. Unbelievable!
On a side note... I'm glad I held off on submitting the master control board. Not because of any mechanical issues. Rather, I just realized that driving 48 LEDS in parallel at 20ma each (which will happen occasionally with some of my animation sequences) will require a 1 amp power cube and a heftier board power connector than standard .1 inch header pins I was going to use. Looking now at JST battery connectors to get from the board to my 5mm chassis power jack. Also looking for a decent 1 amp power cube.

JLCPCB-Disp-Mod-Boards.jpg
 

Hemi345

Senior Member
Those look great. Nice job.

Do you really need to drive each LED at 20mA? You might do some testing to see if you notice a discernible difference in brightness with variations in current. For some LEDs I use, 5mA is enough to make them insanely bright.
 

hippy

Senior Member
will require a 1 amp power cube and a heftier board power connector than standard .1 inch header pins I was going to use
0.1" headers should be good for 2A and more and the cable shouldn't need to be too hefty. It should be easy to find a 1.5A USB charger which will do the job of delivering enough power.

You could use a USB-B socket for power. Or USB-A though A-to-A cables are harder to find than A-to-B. Or just cut a USB-A cable so it's a flying lead which plugs straight into the charger.
 

lbenson

Senior Member
The "Amazon's Choice" raspberry pi power supply is quite beefy, though a bit on the expensive side:

I've used a number of these on projects calling from more than 1A.
 

datasmith

Well-known member
Hi Hemi,
I have some bright LED's, typically the clear case ones, that are indeed extremely bright and don't require much current. But, I've got these red diffused rectangular LED's that I was going with for this art project, and they are not near as bright as the clear case LED's. Must be the diffused plastic. They are intended as panel indicators, afterall. I'm having to give them the full 20ma to show up properly for this art piece.

Hippy,
I agree that the header pins on the PCB are beefy enough to handle an amp. I was more concerned about the little female crimp pins on the standard black .1 inch connectors. The JST connectors (the 2.5 ones) also have the same size board pins, but I think the plugs are a little bit heavier. I ordered some of these, along with these to see if they are any heavier duty. If nothing else, they will lock together, which will be fine for securing my chassis power connector to the board.

lbenson,
That power cube is not bad at all. Also has a power switch and a decent cable length. It's not any more pricey than other 1+ amp power cubes I've seen.
 

datasmith

Well-known member
So, I'm waiting for some more parts (.1 inch plug pins to make some breadboard connections, resistors, and those JST connector kits). In the mean time I just have my breadboard mock-up to play with. Since it represents only one panel of six (the last panel as I am shifting out MSB first). I am looking as some of my animated art code. Since I am just using the 08M2 I am always trying to really budget my code and data space to get my bang for the byte. One of my animations sequences (the first one I wrote) is a kaleidoscope effect. It's kind of a cheater code as I write the sequence for a single array byte (representing one of the panels) and simply repeat it across all six panels.
Code snip...
Code:
' six byte output array (28 through 33) representing the six diplay panels
symbol Cur_LED_Array = 28
' Pointers to individual bytes for each panel 
symbol Panel1 = 28    
symbol Panel2 = 29
symbol Panel3 = 30
symbol Panel4 = 31
symbol Panel5 = 32
symbol Panel6 = 33

symbol Tgt_LED_Array1 = 0

' Pattern for Kaleidoscope Sequence
DATA Tgt_LED_Array1, (%00000000,_
                      %00000000,_
                      %00011000,_
                      %00111100,_
                      %01111110,_
                      %11111111,_
                      %11111111,_
                      %11100111,_
                      %11000011,_
                      %10000001,_
                      %00000000,_
                      %00000000)

symbol loopctr1 = b1
symbol loopctr2 = b2
symbol tmpval1 = b11
symbol tgtval = b14

Kaleidoscope1:
        tmpval1 = Tgt_LED_Array1 ' point to source byte pattern - 12 frames    
        for loopctr2 = 1 to 12 
            bptr = Cur_LED_Array ' point to output array
            read tmpval1, tgtval ' get each frame of the pattern array
            for loopctr1 = 1 to 6 ' write it to each byte of the output array           
                @bptrinc = tgtval 
            next loopctr1
            gosub Output_to_SR ' for each frame send the output array
                       ' out to the six panel-shift-registers (thanks to Hippy!)
            pause 50 ' animation frame delay
            inc tmpval1 ' point to the next frame in the Kaleidoscope sequence
        next loopctr2 ' loop for all 12 frames in the sequence
        goto Kaleidoscope1 ' in this drill just keep repeating
Here's a mock-up of what it does. I can at least see the last panel on my breadboard.
circle-kaleidoscope-animation.gif
 

datasmith

Well-known member
Another sequence is a full rotation sequence. This requires shifting bits to the left through the entire six byte array. I first write a pattern into the array. It could be a pattern that fills any number of panels. But in this case I am writing a pattern into a single panel (byte) and then rotating it around the circle. Data storage will depend on how big the pattern is. (one byte in this case).
Here's the code for this...
Code:
' six byte array (28 through 33) representing the six diplay panels
symbol Cur_LED_Array = 28
' Pointers to individual bytes for each panel
symbol Panel1 = 28   
symbol Panel2 = 29
symbol Panel3 = 30
symbol Panel4 = 31
symbol Panel5 = 32
symbol Panel6 = 33


symbol loopctr1 = b1
symbol loopctr2 = b2
symbol tmpval1 = b11

symbol tmpwrd = w6
symbol tmpval2 = b12 ' tmpwrd LSB
symbol tmpval3 = b13 ' tmpwrd MSB - holds shift-left carry

'Full Rotation
Sequence1:
    bptr = Panel1
    @bptr = %11101101  ' write an 8 bit pattern into "Panel 1"
    rotate_steps = 240 ' this will rotate it five times
    gosub Rotate_Right

    goto Sequence1  'rinse and repeat

Rotate_Right:
    bptr = Cur_LED_Array 'point to the output array
    for loopctr2 = 1 to rotate_steps
        tmpval1 = 0 ' this will hold the carry bit between bytes
        for loopctr1 = 1 to 6 ' steps through each byte in the array
            tmpval3 = 0    ' clears the carry bit
            tmpval2 =@bptr  ' gets next byte in output array
            tmpwrd = tmpwrd * 2 ' shifts left pushing msb into tmpval3
            tmpval2 = tmpval2 + tmpval1 'adds previous carry as lsb
            @bptrinc = tmpval2 ' writes shifted and carried value back to array
            tmpval1 = tmpval3 ' stores new carry  bit
        next loopctr1 ' for each byte in the output array
        bptr = Cur_LED_Array ' then goes back to first byte
        tmpval2 =@bptr
        tmpval2 = tmpval2 + tmpval1 ' and adds last byte carry bit[ATTACH type="full"]23797[/ATTACH] to the first byte
        @bptr = tmpval2
        gosub Output_to_SR ' outputs array to panels for each step
    next loopctr2 ' next rotation step
    return
circle-rotation-animation.gif
 

datasmith

Well-known member
Non-cyclic animations are going to take more resources than cyclic ones. Hers an animation where the LEDs "sweep up" from the bottom on both sides and then out the top. It takes 48 frames, and if I were to just do the whole animation with complete patterns for all six panels, that would be 48 x 6 bytes of memory (288 bytes). While the output routine would be a simple loop, there's not enough memory to store the raw patterns. So I broke this down into the six respective panels. First I run a loop subroutine to zero-out all six panels (bytes). Then I animate the bottom panel (Panel5) with 4 pattern frames (Tgt_LED_Array2a). Next, I animate the lower left and lower right panels (Panel4 and Panel6) with 2-8 pattern frames (Tgt_LED_Array2b and Tgt_LED_Array2c). I repeat the same pattern animations for the upper left and upper right panels (Panel1 and Panel3) and then finish off the top panel (Panel2) with 4 pattern frames (Tgt_LED_Array2d). to finish the second half of the sweep, clearing the LEDs, I simply run through the same routine inverting the pattern bits for each frame. This uses only 24 bytes of data storage, but the code is about 5 times as much as a simple loop. Fortunately I have more available code space than data space.
Code:
' six byte array (28 through 33) representing the six diplay panels
symbol Cur_LED_Array = 28
' Pointers to individual bytes for each panel 
symbol Panel1 = 28    
symbol Panel2 = 29
symbol Panel3 = 30
symbol Panel4 = 31
symbol Panel5 = 32
symbol Panel6 = 33

'Pointers to Sequence2 Source Patterns
symbol Tgt_LED_Array2a = 12
symbol Tgt_LED_Array2b = 16
symbol Tgt_LED_Array2c = 24
symbol Tgt_LED_Array2d = 32

'Sequence2 Source Patterns            
DATA Tgt_LED_Array2a,(%00011000,%00111100,%01111110,%11111111)
DATA Tgt_LED_Array2b,(%10000000,%11000000,%11100000,%11110000,%11111000,%11111100,%11111110,%11111111)
DATA Tgt_LED_Array2c,(%00000001,%00000011,%00000111,%00001111,%00011111,%00111111,%01111111,%11111111)
Data Tgt_LED_Array2d,(%10000001,%11000011,%11100111,%11111111)

symbol loopctr1 = b1
symbol loopctr2 = b2
symbol tmpval1 = b11
symbol tgtval = b14

symbol tmpval2 = b12 ' tmpwrd LSB
symbol tmpval3 = b13 ' tmpwrd MSB - holds shift-left carry

' Sweep-Up Routine

Sequence2:
    byte_pattern = %00000000 ' zero's out all six panels
    gosub Set_Byte_Pattern

    for Loopctr2 = 1 to 8 'this gives me four full up sweeps. 
                'Sweep ON on the odd count, seeep OFF on the even count
        tmpval3 = Loopctr2 AND 1 is this an odd or even loop cycle?
        'Panel5 - do the bottom panel first
        tmpval1 = Tgt_LED_Array2a ' point to bottom panel frame array
        bptr = Panel5
        for Loopctr1 = 1 to 4 ' step through the four frames
            read tmpval1, tgtval
            if tmpval3 = 1 then ' Inverts the same pattern data for "sweep off"
                tgtval = tgtval NAND %11111111 
            endif
            @bptr = tgtval
            gosub Output_to_SR 'send out the animation frame
            inc tmpval1
            pause pause_val ' speed control
        next Loopctr1
    
        'Panel4 and Panel6
        tmpval1 = Tgt_LED_Array2b 'Point to Tgt LED Array B
        for Loopctr1 = 1 to 8
            bptr = Panel4
            read tmpval1, tgtval
            if tmpval3 = 0 then
                tgtval = tgtval NAND %11111111
            endif
            @bptr = tgtval
            tmpval2 = tmpval1 + 8 ' Point to Tgt LED Array C
            bptr = Panel6
            read tmpval2, tgtval
            if tmpval3 = 0 then
                tgtval = tgtval NAND %11111111
            endif
            @bptr = tgtval
            gosub Output_to_SR 'send out the animation frame
            inc tmpval1
            pause pause_val    ' speed control
        next Loopctr1
    
    
        ''Panel1 and Panel3
        tmpval1 = Tgt_LED_Array2b
        for Loopctr1 = 1 to 8
            bptr = Panel1
            read tmpval1, tgtval
            if tmpval3 = 0 then
                tgtval = tgtval NAND %11111111
            endif
            @bptr = tgtval
            tmpval2 = tmpval1 + 8
            bptr = Panel3
            read tmpval2, tgtval
            if tmpval3 = 0 then
                tgtval = tgtval NAND %11111111
            endif
            @bptr = tgtval
            gosub Output_to_SR 'send out the animation frame
            inc tmpval1
        pause pause_val    
        next Loopctr1        
    
        'Panel2
        tmpval1 = Tgt_LED_Array2d
        bptr = Panel2
        for Loopctr1 = 1 to 4
            read tmpval1, tgtval
            if tmpval3 = 0 then
                tgtval = tgtval NAND %11111111
            endif
            @bptr = tgtval
            gosub Output_to_SR
            inc tmpval1
            pause pause_val
        next Loopctr1
    next Loopctr2
    goto Sequence2 ' rinse and repeat
Looking at this code I bet I can combine the two center loops as they are doing exactly the same thing, except to different panel pairs, If I can work out changing pointers to those alternate panels in a common loop.
LED-Circle-Panels.gifcircle-sweep-up-animation.gif
 

hippy

Senior Member
Non-cyclic animations are going to take more resources than cyclic ones.
I was wondering if there isn't something to be gained from going for a more programmatic solution by which LED's are sequenced rather than a frame based solution.

For example a single clockwise or anti-clockwise LED is just the number of the LED incremented or decremented. An arc of LED's exactly the same with a number of LED's before or after also set.

Having multiple LED's or arcs running at different speeds and directions would only require controlling the lead LED and adding the tails. All those could be built up from a number of simple primitives.

Untested, and incomplete ( no LED output routine ), but something like ...
Code:
#Define Panel(n)     n - 1 * 8
#Define Led(n)       n

#Define IncLed(bVar) bVar = bVar + 1  // 48
#Define DecLed(bVar) bVar = bVar + 49 // 48
 
#Define ClrAll                   Gosub Do_ClrAll
#Define SetLed(bVar) b0 = bVar : Gosub Do_SetLed
#Define ClrLed(bVar) b0 = bVar : Gosub Do_ClrLed
#Define TogLed(bVar) b0 = bVar : Gosub Do_TogLed

Symbol reserveW0   = w0 ; b1:b0
Symbol cwLed       = b2
Symbol acLed       = b3

Symbol PANEL_ARRAY = 10 ; b10

PowerOnReset:
  ClrAll

SingleClockwise:
  cwLed = Panel(1) + Led(0)
  Do
    SetLed(cwLed)
    Gosub UpdateLeds
    Pause 500
    ClrLed(cwLed)
    IncLed(cwLed)
  Loop

SingleAntiClockwise:
  acLed = Panel(1) + Led(0)
  Do
    SetLed(acLed)
    Gosub UpdateLeds
    Pause 500
    ClrLed(acLed)
    DecLed(acLed)
  Loop

CounterPair:
  cwLed = Panel(1) + Led(0)
  acLed = Panel(1) + Led(0)
  Do
    SetLed(cwLed)
    SetLed(acLed)
    Gosub UpdateLeds
    Pause 500
    ClrLed(cwLed)
    ClrLed(acLed)
    IncLed(cwLed)
    DecLed(acLed)
  Loop

UpdateLeds:
  Return

Do_ClrAll:
  bPtr = PANEL_ARRAY
  For b0 = 1 To 6
    @bPtrInc = 0
  Next
  Return

Do_SetLed:
  Gosub SetPtrAndBit
  @bPtr = @bPtr | b0 
  Return

Do_ClrLed:
  Gosub SetPtrAndBit
  @bPtr = @bPtr &/ b0
  Return

Do_TogLed:
  Gosub SetPtrAndBit
  @bPtr = @bPtr ^ b0 
  Return

SetPtrAndBit:
  bPtr = b0 / 8 + PANEL_ARRAY
  b0   = b0 & 7
  LookUp b0, ($01,$02,$04,$08,$10,$20,$40,$80), b0
  Return
 

Aries

New Member
To merge the two middle loops, assuming you keep the Panelx symbols as they are, then you could do something like:
Code:
for LoopCtrx = Panel4 to Panel1 step -3
       ....
       for Loopctr1 = 1 to 8
            bptr = LoopCtrx
            ....
            bptr = bptr + 2
            .....
       next LoopCtr1
 next LoopCtrx
 

datasmith

Well-known member
Yeah Aries, you're right in line with what I was thinking.

Hippy, your code has given me a lot to chew on. I have plenty of program space to have both frame based and pure logic based sequences. It will be interesting to see what kind of patterns come out of both concepts. Right now I only see the "last" panel on my breadboard, until I get the rest of my parts in. One thing your code did was remind me to move from my old 5.x editor to the newer 6.1 editor. Your #Define directives were giving me syntax errors in the older editor. AND, you have enlightened me on making my code much more readable by using #Define. I went crazy writing a bunch of single-line macros. Now, to deconstruct your code and play with it.
 

datasmith

Well-known member
I can't believe that I fried my Darlingtons! My LED Circle is comprised of six panels of eight LEDs. Each of the panel LEDs is sinked by an NPN Darlington array (ULN2803A). But, I decided to source all the panel LEDs with a PNP darlington (BC516) transistor tied back to a pwm output on the 08M2, so I could fade the LEDs in and out for some of my sequences. This all worked fine on my breadboard. But, I think I cooked the transistors soldering them into my new circuit board. A little alligator clip on the leads would have probably saved the day. But, I was anxious to see it work and was in a hurry. It was all the BC516's I had too. Waiting for a batch from China to arrive. In the mean time I had to pull out the dead transistors and jump V+ to the PNP collector pad. You can see the spaces in the back circuit board below where those darlington PNP's go.

I was going to buy a couple of solder pin heat sinks from Amazon, but they want as much as $8 US for just a pair. Really? I guess I stick with an alligator clip.
first-build.jpg
 

Hemi345

Senior Member
Great job.

I'm pretty sure you would be still at it drilling holes if you'd made a home-made PCB ;)
 

premelec

Senior Member
Amazing what an 08M2 and craftsman can do together - It's art - good work! Please go on to more color with APA102s... ;-0
 
Top