LED Matrix PacMan
in Propeller 1
Hello everyone,
Some time ago, I saw that someone had made a PacMan with a LED Matrix as display, something like 32x32 or so.
After some weeks of thinking which processor to use for these modules I finally decided that the Propeller would be as good a choice as any other uC. I decided today to finally give it a go.
It was as I should have expected, easier, fun and in a few hours (of finding where did I miss a '#' and things like that), I have something that quite works, if I had all modules:
The code is not yet finished, but the plan is:
6 8x8 WS2812 Modules (from aliexpress for like 7 € each).
1 Prop+EEPROM: 1 pin for LED data, and 4 pins for the 2 potentiometers in the joystick
1 Analog Joystick
A board and a battery
Display driver
Some time ago, I saw that someone had made a PacMan with a LED Matrix as display, something like 32x32 or so.
After some weeks of thinking which processor to use for these modules I finally decided that the Propeller would be as good a choice as any other uC. I decided today to finally give it a go.
It was as I should have expected, easier, fun and in a few hours (of finding where did I miss a '#' and things like that), I have something that quite works, if I had all modules:
The code is not yet finished, but the plan is:
6 8x8 WS2812 Modules (from aliexpress for like 7 € each).
1 Prop+EEPROM: 1 pin for LED data, and 4 pins for the 2 potentiometers in the joystick
1 Analog Joystick
A board and a battery
{Object_Title_and_Purpose}
CON
_clkmode = xtal1 + pll16x 'Standard clock mode * crystal frequency = 80 MHz
_xinfreq = 5_000_000
MAP_SIZE = 16*24
VAR
long adch_value
long adcl_value
long display_buffer[384]
long counter
OBJ
adchoriz : "ADC"
adcvert : "ADC2"
serial : "FullDuplexSerial"
disp : "WS2812"
PUB Main
serial.Start(31, 30, %0000, 9_600)
adchoriz.SigmaDelta(@adch_value)
adcvert.SigmaDelta(@adcl_value)
disp.WS2812_Start(@display_buffer)
InitMap
TranslateMap
repeat
PRI InitMap | idx
idx := 0
repeat while idx < MAP_SIZE
playmap[idx] := imap[idx]
idx := idx + 1
PRI TranslateMap | idx
idx := 0
repeat while idx < MAP_SIZE
display_buffer[idx] := CLUT[playmap[idx]]
idx := idx + 1
DAT
imap byte "BBBBBBBBBBBBBBBB"
byte "B......BB......B"
byte "B*BB.B.BB.B.BB*B"
byte "B.BB.B....B.BB.B"
byte "B......BB......B"
byte "B.BB.B....B.BB.B"
byte "B....BBBBBB....B"
byte "B.BB........BB.B"
byte "B..B.BB..BB.B..B"
byte "BB.B.B....B.B.BB"
byte "B..B.B....B.B..B"
byte "BB.B.B....B.B.BB"
byte "BB.B.BBBBBB.B.BB"
byte "B..............B"
byte "B.BBBB.BB.BBBB.B"
byte "B..............B"
byte "B.BBB.BBBB.BBB.B"
byte "B.BBB.BBBB.BBB.B"
byte "B*..B......B..*B"
byte "BBB.B.BBBB.B.BBB"
byte "B......BB......B"
byte "B.BBBB.BB.BBBB.B"
byte "B..............B"
byte "BBBBBBBBBBBBBBBB"
playmap byte 0 [MAP_SIZE]
CLUT long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
' * .
long 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, $1F1F0000, 0, 0, 0, $07070000, 0
' 1 2 3 4 5
long $3F000000, $003F0000, $003F3F00, $00003F00, $42420000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
'
long 0, 0, $00000F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
Display driver
{WS2812 Matrix driver
Supports refresh of a 16x24 RGB led matrix all at once
Matrix data is read from HUB and latched in COG memory
Timing WS2812, :
350u 800u
__
0 / \________/
700u 600u
_____
1 / \_____/
Ale 500
}
CON
DISP_PIN =16
PUB WS2812_Start (buffer)
cognew(@start, buffer) ' lauch display driver
DAT
org
start or DIRA, DISP_OUT
andn OUTA, DISP_OUT
mov task_cnt, task_20ms
add task_cnt, CNT
waitcnt task_cnt, task_20ms ' wait for first cycle
updatein mov hubsrc_ptr,par
mov lcnt,#384 ' 16x24 RGB matrix one long per RGB LED
mov x,#0
updatein_loop mov hubsrc_ptr,x
andn hubsrc_ptr,#$78
test x,#64 wz
if_nz or hubsrc_ptr, #8
test x,#8 wz
if_nz or hubsrc_ptr, #16
test x,#16 wz
if_nz or hubsrc_ptr, #32
test x,#32 wz
if_nz or hubsrc_ptr, #64
shl hubsrc_ptr,#2
add hubsrc_ptr,par
rdlong pixel, hubsrc_ptr ' load pixel data from buffer
compute mov bcnt, #24
bit_loop shl pixel, #1 wc
or OUTA, DISP_OUT
nop ' 50 ns
nop ' 100 ns
nop ' 150 ns
nop ' 200 ns
nop
nop
if_nc andn OUTA,DISP_OUT ' clear if zero
nop ' 400 ns
nop ' 450 ns
nop ' 500 ns
nop
nop ' 600 ns
nop
andn OUTA,DISP_OUT ' clear for 1
nop ' 750 ns
nop ' 800 ns
nop ' 850 ns
nop ' 900 ns
nop ' 950 ns
nop '1000 ns
nop '1050 ns
nop '1100 ns
djnz bcnt, #bit_loop
add x, #1
djnz lcnt, #updatein_loop
waitcnt task_cnt, task_20ms
jmp #updatein
x long 0
bcnt long 0
lcnt long 0
pixel long 0
ADD_1_D_FIELD long 1<<9 ' add 1 to D field
DISP_OUT long 1<<DISP_PIN
task_cnt long 0
task_20ms long 50_000*80 ' 20 ms refresh task
hubsrc_ptr long 0
cogdst_ptr long 0
org 128-16
pixel_data res 384

Comments
I'm using 2 ADC objects, a serial object for debug, one self-written driver object and a main loop. The player can move its... dot, the ghosts have 4 different colors and change to blue when the big corner dots are eaten, and two maps are provided.
It needs some clean up, because there are two translation tables with positions and the ghosts do not move yet. I'll dedicate a cog to them because I think spin would be a bit slow when all the logic is in the main loop, maybe. Code follows.
Jim