## 24x24 LED Game of Life...

What have you built or do you want to design to go with your replica 1

### 24x24 LED Game of Life...

I guess you are never a true geek until you have written a Game of Life program.
Just to stand out of all the other geeks, let's write it in 6502 Assembler on a computer most people never heard on and on top of that, add a homebrew hardware that took months to build.

It's quite simple, hook up a 6522 VIA and map it to address \$C040.

Get an old ATX power supply (since I had one lying around) and convert it to a poor mans Lab supply.
http://www.wikihow.com/Convert-a-Comput ... wer-Supply

Then order some 8x8 LED units from China for \$23 and wait one month to get them.
During this time, order free samples from http://www.maxim-ic.com/, it took me 4 months to get 10 Max7219...
They won't send you 10 of these puppies at once so just keep ordering...

Then get a few more parts for around \$30 and spend another month soldering...
At the end, you will have a beautiful 24x24 LED display...

Testing the display:

The setup running game of life:

The not-so-easy-to-debug side of the board:

Here is a short Video I put on Photobucket:

Check it out here => http://www.brielcomputers.com/replica1.html

And the 6502 assembler for your Replica,
Code: Select all
`; Game of Life on a 24x24 LED.; Rules taken from Wikipedia, http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life...; The universe of the Game of Life is an infinite two-dimensional orthogonal grid of square cells,; each of which is in one of two possible states, live or dead. ; Every cell interacts with its eight neighbours, which are the cells that are directly horizontally,; vertically, or diagonally adjacent. At each step in time, the following transitions occur:;   1. Any live cell with fewer than two live neighbours dies, as if by loneliness.;   2. Any live cell with more than three live neighbours dies, as if by overcrowding.;   3. Any live cell with two or three live neighbours lives, unchanged, to the next generation.;   4. Any dead cell with exactly three live neighbours comes to life.; The initial pattern constitutes the 'seed' of the system.; The first generation is created by applying the above rules simultaneously to every cell in the seed--; births and deaths happen simultaneously, and the discrete moment at which this happens is sometimes called a tick.; (In other words, each generation is based entirely on the one before.) ; The rules continue to be applied repeatedly to create further generations.; ========================================================================================; My version has a 24x24 grid displayed on the screen.; There is no editor so edit Grid1 and re-compile.; Note that I have two grids 26x26 bytes, but I only use 24x24 bytes for game of life.; This is to make the calculations simpler when calculating number of neighbours.; I don't have to do any calculations for wrap around or anything like that.; START @ \$1000      .org \$1000VIA      = \$C040VIA_IOB      = VIA      ; Input/Output register BVIA_IOA      = VIA+1      ; Input/Output register AVIA_DDRB   = VIA+2      ; Data Direction Port BVIA_DDRA   = VIA+3      ; Data Direction Port AVIA_T1CL   = VIA+4      ; T1 Low Order CounterVIA_T1CH   = VIA+5      ; T1 High Order CounterVIA_T1LL   = VIA+6      ; T1 Low Order LatchesVIA_T1LH   = VIA+7      ; T1 High Order LatchesVIA_T2CL   = VIA+8      ; T2 Low Order CounterVIA_T2CH   = VIA+9      ; T2 High Order CounterVIA_SR      = VIA+10   ; Shift RegisterVIA_ACR      = VIA+11   ; Auxiliary Control RegisterVIA_PCR      = VIA+12   ; Pheriperal Control RegisterVIA_IFR      = VIA+13   ; Interrupt Flag RegisterVIA_IER      = VIA+14   ; Interrupt Enable RegisterVIA_IOA2   = VIA+15   ; Input/Output register A, No handshake; VIA stuffadd      = \$30      ; Address in Max7219dat      = \$31      ; Data for Addressunits      = \$32      ; LED units.count      = \$33      ; Counterrows      = \$34      ; Rowscols      = \$35      ; Columnstemp      = \$36      ; Temp StorageLEDGridl   = \$37      ; Grid Pointer LowLEDGridh   = \$38      ; Grid Pointer Hightemp2      = \$39      ; Temp Storage 2; Game Of Life Stufftick      = \$40      ; Even use grid 1, Odd use grid 2row_counter   = \$41      ; count the rows to print.GridLow      = \$42      ; Grid pointer.GridHi      = \$43WorkGridLow   = \$44      ; Grid Pointer for work grid.WorkGridHi   = \$45cell_count   = \$46      ; Used to count cells.moves      = \$47      ; Just a few movesMAIN      LDA #\$09      ; 9 UNITS, 24X24 ledS      STA units      JSR init_VIA      ; Init VIA      JSR init_max7219   ; Inint Dispaly      LDA #\$00      STA tick      ; Start with grid 1      LDA #\$00      ; 256 moves      STA movesMainLoop      JSR LifeToLED      ; Conver Lif grid to LED grid      JSR showGridData   ; Display it      JSR next_tick      ; Calcualte next move in the Game of Life Universe.      INC tick      ; Next tick      JSR delay      ; Small delay      DEC moves      ; Are we done yet ?      BNE MainLoop      ; Nope, continue.      RTS      delay      LDY #\$80      ; Loop 256*128 times...      LDX #\$00.dloop1      DEX      BNE .dloop1      DEY      BNE .dloop1      RTS      LifeToLED   LDA tick      ; Test which grid to print.      AND #\$01      BNE .load_grid2      LDA #<Grid1      ; Load Grid1 to pointer.      STA GridLow      LDA #>Grid1      STA GridHi      BRA .grid_loaded.load_grid2   LDA #<Grid2      ; Load Grid2 to pointer.      STA GridLow      LDA #>Grid2      STA GridHi.grid_loaded   CLC         ; Clear carry so we can add 27 to the grid address.      LDA GridLow      ADC #27         ; Add 27 bytes, that means we are on the second row, second column.      STA GridLow      BCC .no_carry      ; If we got a carry, we need to increase the High byte.      INC GridHi.no_carry   LDA #<GridData      ; Pointer to LED Grid      STA LEDGridl      LDA #>GridData      STA LEDGridh      LDA #\$08      ; Count 8 bit per byte.      STA count      LDY #0         ; Start at second row in grid, one byte in.      STY cols      ; Since it's zero, set offset in LED grid as well.      LDX #24         ; We want to set 24 LEDs per row.      STX row_counter.grid_loop2   LDA (GridLow),Y      ; Get byte in current grid.      BEQ .setDead      ; If, zero it's a dead cell.      SEC      JSR updateLedGrid      BRA .set_Done.setDead   CLC      JSR updateLedGrid.set_Done   INY         ; Next byte.      DEX         ; Count down column.      BNE .grid_loop2      ; Are we done with this row ?      CLC         ; Clear carry so we can add 26 to the grid address.      LDA GridLow      ADC #26         ; Add 26 bytes, that means we are on the next row, second column.      STA GridLow      BCC .no_carry2      ; If we got a carry, we need to increase the High byte.      INC GridHi      .no_carry2   LDY #0         ; Reset Y      LDX #24         ; Reset column bytes      DEC row_counter      BNE .grid_loop2      RTSupdateLedGrid   ROL temp      ; Shift in LED.      DEC count      ; 8 bits yet ?      BNE ulgdone      LDA #\$08      STA count      ; Reset counter      STY temp2      ; Save Y      LDY cols      ; Load offset in LED grid.      LDA temp      ; Get LED data      STA (LEDGridl),y   ; Store it in grid.      INC cols      ; Increase offset.      LDY temp2      ; Restore Y.ulgdone      RTSnext_tick   LDA tick      AND #\$01      BNE .load_grid2      LDA #<Grid1      ; Load Grid1 to pointer.      STA GridLow      LDA #>Grid1      STA GridHi      LDA #<Grid2      ; Load Grid2 to Work grid pointer.      STA WorkGridLow      LDA #>Grid2      STA WorkGridHi      BRA .grid_loaded.load_grid2   LDA #<Grid2      ; Load Grid2 to pointer.      STA GridLow      LDA #>Grid2      STA GridHi      LDA #<Grid1      ; Load Grid1 to Work grid pointer.      STA WorkGridLow      LDA #>Grid1      STA WorkGridHi.grid_loaded   CLC         ; We will count cells on Grid(Low/Hi) and put them on WorkGrid(Low/Hi).      LDA WorkGridLow      ADC #27         ; Add 27 bytes, that means we are on the second row, second column.      STA WorkGridLow      BCC .no_carry      ; If we got a carry, we need to increase the High byte.      INC WorkGridHi.no_carry   LDX #24         ; We want to scan 24 rows      STX row_countergrid_loop   JSR count_hood      ; Count neighbours.      LDY #0         ; Zero Y            LDA cell_count      ; Get result      CMP #02         ; Two cells ?      BCC cell_dies      ; Less than two, cell dies.      CMP #3         ; Three cells ?      BEQ cell_birth      ; Three cells will come a life or stay alive, just put one there.      BCS cell_dies      ; If more than 3 cells, it dies.      LDY #27         ; We have two cells alive, copy cell from Grid(Low/Hi).      LDA (GridLow),Y      ; Got the cell      LDY #0         ; Form pos 27 on Grid(*) to WorkGrid(*).      STA (WorkGridLow),Y   ; Store cell.         BRA cell_count_done   ; Continue on...cell_dies   LDA #0         ; Cell dies, A = 0      STA (WorkGridLow),Y   ; Store cell.         BRA cell_count_done   ; Continue on...cell_birth   LDA #1         ; Cell was born, A = 1      STA (WorkGridLow),Y   ; Store cell.   cell_count_done   INC WorkGridLow      ; Next position      BNE .no_inc1      INC WorkGridHi.no_inc1   INC GridLow      ; Next position      BNE .no_inc2      INC GridHi.no_inc2   DEX         ; Next col.      BNE grid_loop      ; Row not done, continue.      LDX #24         ; Reset col counter.      INC WorkGridLow      ; Next position, for each row we have to move Two spaces.      BNE .no_inc3      INC WorkGridHi.no_inc3   INC GridLow      ; Next position 1 Grid      BNE .no_inc4      INC GridHi.no_inc4   INC WorkGridLow      ; Next position 2 WorkGrid      BNE .no_inc5      INC WorkGridHi.no_inc5   INC GridLow      ; Next position 2 Grid      BNE .no_inc6      INC GridHi.no_inc6   DEC row_counter      ; Next row.      BNE grid_loop      ; Row not done, continue.      RTS      count_hood   LDY #0      STY cell_count      ; Zero cell count.      LDA (GridLow),Y      ; Y=0, neighbour top left.      BEQ .no_add1      INC cell_count.no_add1   LDY #1      LDA (GridLow),Y      ; Y=1, neighbour top middle.      BEQ .no_add2      INC cell_count.no_add2   LDY #2      LDA (GridLow),Y      ; Y=2, neighbour top right.      BEQ .no_add3      INC cell_count.no_add3   LDY #26      LDA (GridLow),Y      ; Y=26, neighbour to the left.      BEQ .no_add4      INC cell_count.no_add4   LDY #28      LDA (GridLow),Y      ; Y=28, neighbour to the right.      BEQ .no_add5      INC cell_count.no_add5   LDY #52      LDA (GridLow),Y      ; Y=52, neighbour to the bottom left.      BEQ .no_add6      INC cell_count.no_add6   LDY #53      LDA (GridLow),Y      ; Y=53, neighbour to the bottom middle.      BEQ .no_add7      INC cell_count.no_add7   LDY #54      LDA (GridLow),Y      ; Y=53, neighbour to the bottom middle.      BEQ .no_add8      INC cell_count.no_add8   RTSshowGridData      LDA #<GridData      STA LEDGridl      LDA #>GridData      STA LEDGridh      LDY #1      ; Start with row 1      STY rows      LDY #8      sty count   ; Count 8 rows      sgdloop1   LDX rows   ; Row to X      STX add      ; Store in address      STX temp   ; Prepare to multiply by three      CLC      ROL temp      LDA rows      ADC temp      ADC #47      TAY      ; Y=(row*3) + 47, this is 9:th chars row.      LDX #3      ; do three chars      STX temp2   ; three times = 9 chars..loop1      LDA (LEDGridl),y      STA dat      JSR SendData      DEY      ; point to previous chars byte.      DEX      ; Three chars ?      BNE .loop1            TYA      SEC      SBC #21      TAY      ; Y = Y - 21, move back 3 chars and compensate for the three rows already done.      LDX #3      ; Three more chars to go.      DEC temp2   ; did we do all 9 chars ?      BNE .loop1            JSR LatchData            INC rows   ; Next row      DEC count   ; Did we do them all ?      BNE sgdloop1   ; Nope, recalculate etc...      RTSinit_VIA   LDA #\$FF   ; Make port A output.      STA VIA_DDRA      LDA #\$00   ; Make ports low.      STA VIA_IOA      LDA VIA_ACR   ; Load ACR      AND #\$E3   ; Zero bit 4,3,2.      ORA #\$18   ; Shift out using Phi2      STA VIA_ACR      RTSinit_max7219   LDA #10      ; Intensity address      STA add      LDA #10      ; 10 out of 15      STA dat      JSR SendAllUnits      JSR LatchData            LDA #11      ; Scan limits (How many rows)      STA add      LDA #7      ; All 8 rows      STA dat      JSR SendAllUnits      JSR LatchData      LDA #9      ; Decode mode      STA add      LDA #0      ; No decoding, use all 8 bits as data      STA dat      JSR SendAllUnits      JSR LatchData      LDA #12      ; Shutdown register      STA add      LDA #1      ; No shutdown, normal operation      STA dat      JSR SendAllUnits      JSR LatchData      RTSSendAllUnits   LDY units   ; Send same data to all unitssauloop      JSR SendData      DEY      BNE sauloop      RTSSendData   LDA add      ; Address for MAX7219      STA VIA_SR   ; Shift it....wait1      LDA VIA_IFR   ; Are we done yet ?      AND #\$04      BEQ .wait1   ; Nope, continue...      LDA dat      ; Data for MAX7219      STA VIA_SR   ; Shift it....wait2      LDA VIA_IFR   ; Are we done yet ?      AND #\$04      BEQ .wait2   ; Nope, continue...      RTS      LatchData   LDA #\$01   ; Set Pin PA0 high      STA VIA_IOA   ; This will load the data...      LDA #\$00   ; Set Pin PA0 Low      STA VIA_IOA   ; Done loading the data, ready for more...      RTS      GridData      .BYTE \$7E, \$00, \$00 ; 1      .BYTE \$7E, \$00, \$00 ; 2      .BYTE \$66, \$00, \$00 ; 3      .BYTE \$66, \$3C, \$00 ; 4      .BYTE \$0C, \$3C, \$00 ; 5      .BYTE \$0C, \$66, \$00 ; 6      .BYTE \$18, \$66, \$00 ; 7      .BYTE \$18, \$66, \$3C ; 8      .BYTE \$18, \$66, \$3C ; 9      .BYTE \$18, \$3C, \$66 ; 10      .BYTE \$18, \$3C, \$66 ; 11      .BYTE \$18, \$66, \$66 ; 12      .BYTE \$18, \$66, \$66 ; 13      .BYTE \$18, \$66, \$3E ; 14      .BYTE \$00, \$66, \$3E ; 15      .BYTE \$00, \$3C, \$06 ; 16      .BYTE \$00, \$3C, \$06 ; 17      .BYTE \$00, \$00, \$66 ; 18      .BYTE \$00, \$00, \$66 ; 19      .BYTE \$00, \$00, \$3C ; 20      .BYTE \$00, \$00, \$3C ; 21      .BYTE \$11, \$00, \$00 ; 22      .BYTE \$00, \$11, \$00 ; 23      .BYTE \$00, \$00, \$11 ; 24;      .org \$1300      ; For DebugGrid1      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 1      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 2      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 3      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 4      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 5      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 6      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 7      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 8      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 9      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 10      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 11      .BYTE 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0 ; 12      .BYTE 0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0 ; 13      .BYTE 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0 ; 14      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 15      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 16      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 17      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 18      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 19      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 20      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 21      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 22      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 23      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 24      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 25      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 26   ;      .org \$1600      ; For DebugGrid2      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 1      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 2      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 3      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 4      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 5      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 6      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 7      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 8      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 9      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 10      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 11      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 12      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 13      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 14      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 15      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 16      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 17      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 18      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 19      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 20      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 21      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 22      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 23      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 24      .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 25            .BYTE 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; 26`

Fixed bug in code 4/25, now it works better...
Last edited by fsafstrom on Apr Thu 26, 2007 10:09 am, edited 3 times in total.

fsafstrom

Posts: 154
Joined: Dec Tue 26, 2006 2:57 pm
Location: San Antonio, Texas

I just had to take a break before I document how this thing works...

The 24x24 LED display is actually nine 8x8 LED units.
Each 8x8 unit is controlled by a MAX 7219 LED driver, if you look at the test I made, you can see how they are organized.
So that is basically LED unit 1-9 from top left to bottom right.
The Max 7219 keeps track of which LEDs I want to light up, so I only need to send the data once and then the chip will do the rest for me.
Each row (cathode) in the LED unit is connected to the digit section on the Max 7219 and each column (Anode) to the Segment section.
The Max 7219 accepts serial data so the chips are daisy chained together, however the clock and latch are parallel and goes to all chips in parallel.
Data basically flows from one chip to another so the most efficient way of sending data is to send 9 commands in a row and then latch it (tell the driver to use the data).
So when sending graphical data, you send 9 columns and then latch it.
Then row two, three and so on to row 8.

The VIA (6522) have a shift register so it's really doing a lot of work for me, all I need to do is load the shift register and tell it to send the data to the Max 7219.

Let me know if you have any questions or comments.

MAX 7219 Datasheet,
http://datasheets.maxim-ic.com/en/ds/MA ... AX7221.pdf

fsafstrom

Posts: 154
Joined: Dec Tue 26, 2006 2:57 pm
Location: San Antonio, Texas

That is awesome! I think that there is potential for games with this set up!!
Max Wooden
cheese1113

Posts: 92
Joined: Nov Sun 13, 2005 1:49 am
Location: CA

Yes, there will soon be a LED Pong game, maybe with a SID 6581 for sound effects or a SoundGin...
IF I can get the SoundGin to work that is, they don't seem to work to well on solderless breadboards...

fsafstrom

Posts: 154
Joined: Dec Tue 26, 2006 2:57 pm
Location: San Antonio, Texas

Max Wooden
cheese1113

Posts: 92
Joined: Nov Sun 13, 2005 1:49 am
Location: CA

I actually sent the link to Hack a day...
I'm glad they picked it up.

Here is a short Video I put on Photobucket:

fsafstrom

Posts: 154
Joined: Dec Tue 26, 2006 2:57 pm
Location: San Antonio, Texas

Very nice. I can probably figure it out the hard way by inspecting the code, but how did you attach the 6522 to the array of 7219s? I'm guessing CB2 is data-in to the first 7219, but what are the other pin assignments?

Thanks and congrats on this. I need to track down a pile of LED matrices. I already have a few 7219s on hand.

-ethan
ethan

Posts: 1
Joined: May Wed 02, 2007 12:18 pm

Hi Ethan,

The Load data (pin 12) on Max 7219 is connected to PA0 (pin 2) on the 6522.
Clock (pin 13) on Max 7219 is connected to CB1 (pin 18 ) on the 6522.
Data In (pin 1) on Max 7219 is connected to CB2 (pin 19) on the 6522.

The VIA (6522) is setup with port A as output and for the shift register to shift out at the pace of Phi2.

Code: Select all
`init_VIA   LDA #\$FF   ; Make port A output.      STA VIA_DDRA      LDA #\$00   ; Make ports low.      STA VIA_IOA      LDA VIA_ACR   ; Load ACR      AND #\$E3   ; Zero bit 4,3,2.      ORA #\$18   ; Shift out using Phi2      STA VIA_ACR      RTS`

To send (or shift out) data, simply store the value you want to shift out in VIA_SR.
Then wait for bit 2 to be set in the VIA_IFR, that means the shift out is done.
Code: Select all
`SendData   LDA add      ; Address for MAX7219      STA VIA_SR   ; Shift it....wait1      LDA VIA_IFR   ; Are we done yet ?      AND #\$04      BEQ .wait1   ; Nope, continue...`

Then latch the data by setting the Load pin high and then low again.
Code: Select all
`LatchData   LDA #\$01   ; Set Pin PA0 high      STA VIA_IOA   ; This will load the data...      LDA #\$00   ; Set Pin PA0 Low      STA VIA_IOA   ; Done loading the data, ready for more...      RTS`

That's it, have fun...

/Bamse

fsafstrom

Posts: 154
Joined: Dec Tue 26, 2006 2:57 pm
Location: San Antonio, Texas

I LOVE a project with LEDs!

Here is a picture of mine:

Front: http://www.stockly.com/images2/060129-L ... t_2718.jpg

Back: http://www.stockly.com/images2/060129-L ... k_2716.jpg

Legs: http://www.stockly.com/images2/060129-W ... s_2696.jpg

I have not built the driver circuits. I only finished it to win a bet (which had no wagers). I averaged 3.5 hours per 990 LED board.

I plan to make a new one with finer pitch LED MODULES. Like your modules, with a .3" pitch. My display has a .4 inch pitch.

I built it for my Altair and Apple-1. The only thing I know is ALL the LEDs are in correctly and all light up.
logjam

Posts: 14
Joined: May Tue 15, 2007 1:10 am

Now that's an LED display...

I'm not sure I dare to ask, but how many LED's is in that display ?

fsafstrom

Posts: 154
Joined: Dec Tue 26, 2006 2:57 pm
Location: San Antonio, Texas

19,008. It is 192x99, or 24x9 characters of 8x11 pixels.

I thought I'd be able to refresh 30 rows when I made the boards. I did some tests with my LEDs and found that I could only do a little over 10. I decided to refresh 11 rows at once since that is how many rows are in one character. The display will be refreshed as 1728x11.

I'm thinking about a different display of about 64x48. This display would display greyscale data. I took some movies I had and converted them to 64x48 greyscale. You have to squint to see them, but it was pretty good!

64x48 greyscale is 3072 bytes per frame. 4 bits of gray scale might be enough, so we could get 1536 bytes per frame.

It would be fun to use the Apple 1 as a source for the streaming video. It would take 15-30k per second so the 6502 would have no time to do anything but receive frames...
logjam

Posts: 14
Joined: May Tue 15, 2007 1:10 am

Very impressive...

What kind of hardware do you use to drive the LED's ?
The MAX7219 "only" handles 8x8 LED's so my guess would be some kind of custom hardware...

By the way, I calculated my power requirement to be 3 Amps for the 575 LED's with full intensity.
For 19008 LED's that would translate into 100 Amps for the whole board...

On the other hand, I never measured the actual consumption so I could be way off...

fsafstrom

Posts: 154
Joined: Dec Tue 26, 2006 2:57 pm
Location: San Antonio, Texas

Not off...

I found a 5V 90A power supply here:
http://www.surpluscenter.com/item.asp?U ... e=electric

There is also a new 5v 100A or even 150A supply for \$168 or \$295

http://www.power-factor-1st.com/shop/en ... page2.html

So it should be around as bright as a 500W light bulb all said and done... Which over the area of the entire panel shouldn't be TOO bright...

My driver circuits are here:

http://www.stockly.com/images2/060121-Root_1_1.PDF

Each DriverBlock.sch is one of these:

http://www.stockly.com/images2/060121-D ... ck_1_1.PDF

I have not sketched out the design for the 11 row drivers. They are basically the same thing except I will be using MOSFETs instead of those ULN2803s.

I have a 574 latch so that the entire row of LEDs changes at once instead of seeing a possible "wipe" of the display as new line data is clocked in. Possibly a waste, possibly not. This display is not like yours. I have to actually multiplex the LEDs myself. The MAX chip does that for you. I'm probably going to use an FPGA to do all of the bit twiddling and then have the display appear to the computer as "memory". A bit in memory would show up as one LED. This also allows for interesting things like "seeing" a program run as its memory space changes!
logjam

Posts: 14
Joined: May Tue 15, 2007 1:10 am

That Root.sch I posted is for 64 columns. There are 1728 columns total. There are an estimated 8,000 solder joints in the driver boards. I am not looking forward to that.
logjam

Posts: 14
Joined: May Tue 15, 2007 1:10 am

I saw that this thread passed 10 000 views, kewl...

Let's hope that at least one or two people got interested enough in the Replica to buy one...

fsafstrom

Posts: 154
Joined: Dec Tue 26, 2006 2:57 pm
Location: San Antonio, Texas

Next