
\ -------------------------------------------------------------
\  A not-so-small "blinky" using the LED matrix on Microbit
\ -------------------------------------------------------------

$50000504 constant gpio_out         \ Write GPIO port
$50000508 constant gpio_outset      \ Set individual bits in GPIO port
$5000050C constant gpio_outclr      \ Clear individual bits in GPIO port
$50000510 constant gpio_in          \ Read GPIO port
$50000514 constant gpio_dir         \ Direction of GPIO pins
$50000518 constant gpio_dirset      \ Setting DIR register
$5000051c constant gpio_dirclr      \ Clearing DIR register
$50000700 constant gpio_cnf         \ Configuration of pin 0, add 4*n for other pins.

\ Pin config:
\ Bits 17 and 16:    0: No sense 1: Sense for high level 2: Sense for low level
\ Bits 10, 9, 8:
\                    0: Standard 0,   standard 1
\                    1: High drive 0, standard 1
\                    2: Standard 0,   high drive 1
\                    3: High drive 0, high drive 1
\                    4: Disconnect 0, standard 1
\                    5: Disconnect 0, high drive 1
\                    6: Standard 0,   disconnect 1
\                    7: High drive 0, disconnect 1

\ Bits 3 and 2:      0: No pull 1: Pull down 2: Pull up
\ Bit 1:             0: Connect input buffer 1: Disconnect input buffer
\ Bit 0:             0: Input, 1: Output

\ -------------------------------------------------------------
\  Setup pins and wires
\ -------------------------------------------------------------

$FFF0 constant matrixmask

: init-matrix ( -- ) \ Prepare LEDs and Buttons

  matrixmask gpio_outclr !  \ All matrix pins low

  $301 gpio_cnf  4 cells + !  \ High drive in both directions, Input buffer active, Output
  $301 gpio_cnf  5 cells + !
  $301 gpio_cnf  6 cells + !
  $301 gpio_cnf  7 cells + !
  $301 gpio_cnf  8 cells + !
  $301 gpio_cnf  9 cells + !
  $301 gpio_cnf 10 cells + !
  $301 gpio_cnf 11 cells + !
  $301 gpio_cnf 12 cells + !
  $301 gpio_cnf 13 cells + !
  $301 gpio_cnf 14 cells + !
  $301 gpio_cnf 15 cells + !

  $008 gpio_cnf 17 cells + !  \ Button A Input with Pullup
  $008 gpio_cnf 26 cells + !  \ Button B Input with Pullup
;

: buttona ( -- ? ) 1 17 lshift gpio_in bit@ not ;
: buttonb ( -- ? ) 1 26 lshift gpio_in bit@ not ;

\ -------------------------------------------------------------
\  Matrix is connected in a strange way
\ -------------------------------------------------------------

\ This is a really quite strange matrix.
\ Configuration:

\  $0010: Cathode 1
\   ...
\  $1000: Cathode 9

\  $2000: Common Anode 1 (a)
\  $4000: Common Anode 2 (b)
\  $8000: Common Anode 3 (c)

\  a1 b4 a2 b5 a3
\  c4 c5 c6 c7 c8
\  b2 a9 b3 c9 b1
\  a8 a7 a6 a5 a4
\  c3 b7 c1 b6 c2

0 0 0 3 nvariable matrixbuffer
 
: mpixel ( anode cathode -- )
  8 swap lshift        ( anode bitmask )
  swap                 ( bitmask anode )
  cells matrixbuffer + ( bitmask addr )
  bic!
;

hex
: matrix ( image -- ) \ Turns 25 pixels into three rows of matrix data.

  \ Prepare Anodes, with all Cathode lines high

  $3FF0 matrixbuffer 0 + !
  $5FF0 matrixbuffer 4 + !
  $9FF0 matrixbuffer 8 + !

  \ Prepare Cathodes by clearing singular bits. Chaotic wiring !

  dup      1 and if 2 3 mpixel then \ c3
  dup      2 and if 1 7 mpixel then \ b7
  dup      4 and if 2 1 mpixel then \ c1
  dup      8 and if 1 6 mpixel then \ b6
  dup     10 and if 2 2 mpixel then \ c2

  dup     20 and if 0 8 mpixel then \ a8
  dup     40 and if 0 7 mpixel then \ a7
  dup     80 and if 0 6 mpixel then \ a6
  dup    100 and if 0 5 mpixel then \ a5
  dup    200 and if 0 4 mpixel then \ a4

  dup    400 and if 1 2 mpixel then \ b2
  dup    800 and if 0 9 mpixel then \ a9
  dup   1000 and if 1 3 mpixel then \ b3
  dup   2000 and if 2 9 mpixel then \ c9
  dup   4000 and if 1 1 mpixel then \ b1
         
  dup   8000 and if 2 4 mpixel then \ c4
  dup  10000 and if 2 5 mpixel then \ c5
  dup  20000 and if 2 6 mpixel then \ c6
  dup  40000 and if 2 7 mpixel then \ c7
  dup  80000 and if 2 8 mpixel then \ c8

  dup 100000 and if 0 1 mpixel then \ a1
  dup 200000 and if 1 4 mpixel then \ b4
  dup 400000 and if 0 2 mpixel then \ a2
  dup 800000 and if 1 5 mpixel then \ b5
     1000000 and if 0 3 mpixel then \ a3

;
decimal

\ -------------------------------------------------------------
\  A few example images
\ -------------------------------------------------------------

%11011.00000.00100.10001.01110 drop constant :-)  \ Use drop to allow usage of . for clarity in image data.
%00011.00000.00100.10001.01110 drop constant ,-)
%11000.00000.00100.10001.01110 drop constant '-)
%11011.00000.00000.01110.10001 drop constant :-(

\ -------------------------------------------------------------
\  Display an image, as simple as possible...
\ -------------------------------------------------------------

: blinky ( -- )
  init-matrix
  :-) matrix  

  begin

    matrixmask  gpio_outclr !        \ All matrix pins low
    matrixbuffer 0 + @ gpio_outset !  \ First row data
    100 0 do loop

    matrixmask  gpio_outclr !        \ All matrix pins low
    matrixbuffer 4 + @ gpio_outset !  \ Second row data
    100 0 do loop

    matrixmask  gpio_outclr !        \ All matrix pins low
    matrixbuffer 8 + @ gpio_outset !  \ Third row data
    100 0 do loop

  key? until

  matrixmask  gpio_outclr !
;

\ -------------------------------------------------------------
\  A matrix handler to care of shining in the background
\ -------------------------------------------------------------

0 variable currentanode

: matrix-handler ( -- ) \ Interrupt handler for matrix handling
    matrixmask  gpio_outclr !                                    \ All matrix pins low
    matrixbuffer currentanode @ cells + @ gpio_outset !           \ Display current row
    currentanode @ dup 2 u< if 1+ else drop 0 then currentanode !  \ Next row next time.
;

\ Hook the matrix handler into pause so that it continues to shine while typing.

: matrix-on ( -- )  
  init-matrix 0 matrix  
  ['] matrix-handler hook-pause ! \ You can hook this into a timer interrupt if you wish !
;

: matrix-off ( -- )
  ['] nop hook-pause !
  matrixmask  gpio_outclr !
;

\ -------------------------------------------------------------
\  A small demo of everything.
\ -------------------------------------------------------------

: demo ( -- )
  matrix-on
  
  begin
    :-)
    buttona             if drop '-) then
    buttonb             if drop ,-) then
    buttona buttonb and if drop :-( then
    matrix
  key? until

  matrix-off
;

