LED Matrix PacMan
Ale
Posts: 2,363
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