
\ ------------------------------------------------------------------------------
\  Blinky using a timer interrupt
\ ------------------------------------------------------------------------------

\ Let it shine! This example blinks the green LED on GPIO 25.

$40028000 constant IO_BANK0_BASE

IO_BANK0_BASE 25 8 * +     constant GPIO_25_STATUS
IO_BANK0_BASE 25 8 * + 4 + constant GPIO_25_CTRL

$40038000 constant PADS_BANK0_BASE

PADS_BANK0_BASE 25 1+ 4 * + constant GPIO_25_PAD

$D0000000 constant SIO_BASE

SIO_BASE $004 + constant  GPIO_IN

SIO_BASE $010 + constant  GPIO_OUT
SIO_BASE $018 + constant  GPIO_OUT_SET
SIO_BASE $020 + constant  GPIO_OUT_CLR
SIO_BASE $028 + constant  GPIO_OUT_XOR

SIO_BASE $030 + constant  GPIO_OE
SIO_BASE $038 + constant  GPIO_OE_SET
SIO_BASE $040 + constant  GPIO_OE_CLR
SIO_BASE $048 + constant  GPIO_OE_XOR

SIO_BASE $1a4 + constant  MTIME_CTRL
SIO_BASE $1b0 + constant  MTIME      \ One set of time registers for both cores
SIO_BASE $1b4 + constant  MTIMEH
SIO_BASE $1b8 + constant  MTIMECMP   \ Each core has its own compare registers
SIO_BASE $1bc + constant  MTIMECMPH

\ ------------------------------------------------------------------------------

\ The tick counter is initialised in the Forth core for counting microseconds.

: ticks ( -- u ) mtime @ ;

: delay-ticks ( ticks -- )
  ticks ( ticks start )
  begin
    \ Call pause, but only if running on the boot core ID 0.
    \ The coprocessor has ID 1 and shall not cause a task switch
    \ if the multitasker is loaded.
    mhartid@ 0= if pause then

    2dup ( ticks start ticks start )
    ticks ( ticks start ticks start current )
    swap - ( ticks start ticks elapsed )
    u<=
  until
  2drop
;

\ ------------------------------------------------------------------------------

1000000 variable ticks-until-next-interrupt \ Change LED state once a second

: next-irq ( ticks -- )
  0 \ u --> ud

  \ 64 bit register, but with little endian ordering.
  \ Forth 2! stores high part first, requiring a swap.

  mtimecmp 2@ swap d+ swap mtimecmp 2!
;

: tick ( -- )

   mcause@ $8000000B =        \ External interrupt
  meinext@ 29 4 *    = and     \ number 29 ?

  if
    1 25 lshift gpio_out_xor !
    ticks-until-next-interrupt @ next-irq
  else
    unhandled
  then
;

: blinky-irq ( -- )

    5 GPIO_25_CTRL !  \ Set GPIO[25] function to single-cyle I/O: Function 5 SIO
  $34 GPIO_25_PAD  !   \ Remove pad isolation control bit and select drive strength to 12 mA
  1 25 lshift gpio_oe ! \ Set LED pin as output

  ['] tick irq-collection !

  mtime64 swap mtimecmp 2! \ Trigger next interrupt now
  29 enable-irq
  eint
;
