(* 100 Hz (99.7 Hz) interrupt routine for the noForth led badge-2

   It has 70 leds arranged as a 7 x 10 array, the highest bit of
   the picture array ia always high. The brightness of the display
   can be set in 15 steps from 1 to 16!!
   So every row may get a different pulsewidth, the frequency
   is balanced by calculate the time for the eleventh position.

   Further there are two switches named S1 (P2.7) and S2 (P3.7).
   The LiPo voltage is measured using P1.0 (ADC0)

   Uses for the 7-pin extension connector:
   - Flashing the MSP430 using a launchpad board
   - Serial communication with noForth using
     an USB to RS232 cable or a Bluetooth 4.0 dongle.
   - Loading the LiPo battery from 4.4 Volt to 5 Volt.

   Uses register XX and YY exclusive for the SCAN interrupt!!
   xx = address register
   yy = offset register

   021 = P1OUT
   029 = P2OUT
   019 = P3OUT

   Two switches:    S1=P2.7 & S2=P3.7
   RS232:           RX=P1.1 & TX=P1.2
   I2C:             SCL=P1.6 & SDA=P1.7
   LiPo voltage:    P1.0 (ADC0)
   Seventy leds:    P2.0 to P2.6 and all remaning I/O bits

   USCI I2C on MSP430G2553-IPW28 using pull-ups.
   The bitrate values are for an 8 MHz DCO

   Divide 8.000.000/2 = 4 MHz
   So the timer-0 clock input pulse is .25 microsec.

   FEDCBA9876543210 bit-nummers
   0000001001010100 CONSTANT #CONFIG \ TA is zero, count up, SMCLK, presc. /2

   To add:  USCII EEPROM I2C routines.
            EEPROM movie compiler.
            5x7 ASCII character set
*)


(* USCI I2C routines
*)

hex
code INT-OFF  C232 ,  4F00 ,  end-code

: SETUP-I2C ( -- )
    int-off
    C0 026 *bis     \ P1SEL     I2C to pins
    C0 041 *bis     \ P1SEL2
    01 069 *bis     \ UCB0CTL1  reset USCI
    0F 068 c!       \ UCB0CTL0  I2C master
    81 069 c!       \ UCB0CTL1  Use SMclk
    dm 20 06A c!    \ UCB0BR0   Bitrate 400 KHz with 8 MHz DCO
\   dm 80 06A c!    \ UCB0BR0   Bitrate 100 KHz with 8 MHz DCO
\   dm 160 06A c!   \ UCB0BR0   Bitrate 100 KHz with 16 MHz DCO
    00 06B c!       \ UCB0BR1
    01 069 *bic     \ UCB0CTL1  Resume USCI
    08 003 *bis ;   \ IFG2      Start with TX buffer empty

: I2C   ( fl -- )   ?abort ;        \ I2C error message

code I2READY    ( bit -- )
    4378 ,  B7C2 ,  3 ,  2802 ,  4437 ,  4F00 ,
    8318 ,  23F9 ,  ( chere >r )  1205 ,
    4035 ,  ' i2c >body ,  4F00 ,
end-code

code I2DONE     ( bit -- )
    4378 ,  B7C2 ,  69 ,  2C02 ,  4437 ,
    4F00 ,  8318 ,  23F9 ,  3FEE ,  ( r> jmp )
end-code

: I2OUT1    ( b -- )    06F c!  02 i2done  noop ; \ UCB0TXBUF Send first data to TX
: I2OUT     ( b -- )    06F c!  08 i2ready  noop ; \ UCB0TXBUF TX to shiftreg.
: I2IN      ( -- b )    04 i2ready  06E c@ ;  \ UCB0RXBUF Read databyte
: I2IN}     ( -- b )    04 069 *bis  i2in  04 i2done ; \ UCB0CTL1 Read last I2C databyte
: I2STOP}   ( -- )      04 069 *bis  04 i2done ; \ UCB0CTL1 Stop condition & check
: >DEV      ( a -- )    2/ 11A c! ;             \ UCB0I2CSA Set I2C device address

: {I2WRITE) ( -- )              \ Send I2C device address for writing
    12 069 *bis  08 i2ready  noop ;   \ UCB0CTL1  Send start condition

: {I2READ)  ( -- )              \ Send I2C device address for reading
    10 069 *bic  02 069 *bis    \ UCB0CTL1  Setup read & start
    08 i2ready  02 i2done ;     \ Wait for start condition & ack

: {I2WRITE  ( a -- )            \ Send I2C device address for writing
    >dev  {i2write) ;           \ Set slave address

: {I2READ   ( a -- )            \ Set and send I2C device address for reading
    >dev   {i2read) ;           \ Set slave address

: {I2ACK?}  ( -- fl )           \ Flag 'fl' is true when in ACK is received
    {i2write)  i2stop}  08 06D bit* 0= ;

: {POLL}    ( -- )      begin  {i2ack?} until ; \ Wait until an ACK is received


\ Prints -1 if device with address 'a' is present on I2C-bus otherwise 0.
\ : I2C?      ( a -- )            \ Result is true when device 'a' is on I2C bus
\     >dev setup-i2c {i2ack?} . ; \ Address device, present?

setup-i2c   shield HWI2C\   freeze


(* I2C EEPROM

  This code will work on a 64 kByte EEPROM, 128 kByte EEPROM to 512 kByte EEPROM.
  May be used with a 24C64, 24C65, 24C128, 24C256 to a 24C512(B) EEPROM.

*)

hex
\ Address EE-device and sent 16-bit EE-address 'ea'
: {EEADDR   ( ea -- )       A0 {i2write  dup >< i2out1  i2out ;
\ Read next byte from 24C512 EEPROM like COUNT but without address
: NEC@      ( -- b )        {i2read) i2in} ;
\ Read data 'x' from EEPROM address 'ea'.
: EC@       ( ea -- b )     {eeaddr nec@ ;
\ Write 'x' to EEPROM address 'ea'
: EC!       ( b ea -- )     {eeaddr  i2out  i2stop}  {poll} ;
: EC@+      ( ea -- ea+ x ) dup 1+  swap ec@ ;

\ Cell wide read and store operators for 24C512 EEPROM
: E@            ( ea -- x )         ec@  nec@  >< or ;
: E@+           ( ea1 -- ea2 x )    dup 2 +  swap e@ ;
: E!            ( x ea -- )         >r  dup r@ ec!  >< r> 1+ ec! ;
: E+!           ( n ea -- )         >r  r@ e@ +  r> e! ;

\ First cell in EEPROM is used as EHERE, this way it is always up to date
\ We have to take care manually of the forget action on this address pointer
\ Note that EHERE is initialised at address 2 right behind itself!!
\ The out of EE-memory error message, shows an error in EALLOT !!
0 constant EDP   2 edp e!   \ Define and initialise EHERE
: EHERE         ( -- ea )   edp e@ ;
: EFREE         ( -- u )    0000 ehere - ;
: EALLOT        ( +n -- )   efree  over u< ?abort  edp e+! ;
: EC,           ( b -- )    ehere  1 eallot  ec! ;
: E,            ( x -- )    ehere  2 eallot  e! ;
: ECREATE       ( -- ea )   ehere  constant ;

shield EE\  freeze


(* Display driver for 7 x 10 led display
*)

decimal
88 constant #PICT               \ Display buffer length
create BRIGHT  11 cells allot   \ Column brightness (PWM value)
create COPY    10 allot         \ Display buffer copy
create PICTURE #pict allot      \ Display buffer, byte 11 is a dummy

code SET-PAUSE      ( -- )      \ Compact and fast code version of SET-PAUSE
    bright # sun mov            \ Point to brightness array
    dm 40250 # day mov          \ Start total at period length
    dm 10 # moon mov
    begin,
        sun )+ day sub          \ Subtract whole array from period
        #1 moon sub
     0=? until,
     day sun ) mov              \ Store new pause length
     next
end-code

: >BRIGHT)      ( +n row -- )   \ Set brightness of single row
    cells >r  15 umin 1+  250 *  bright r> +  ! ;

: >BRIGHT       ( +n row -- )   \ Set brightness of a single row
    >bright) set-pause ;

: WHOLE         ( +n -- )       \ Set brightness for the whole screen
    10 0 do  dup i >bright)  loop  drop  set-pause ;

hex
: >PICTURE      ( addr -- )     \ Copy picture from mem. address to display
    dm 10 0 do
        i + c@ 80 or  picture i + c! \ Bit-7 always high
    loop
    drop ;

value DELAY                     \ Frame hold time
: FRAME         ( -- )      delay ms ;

\ Picture and movies from EEPROM

: EE>PICTURE    ( eeaddr -- )   \ Copy picture from EE address to display
    dm 10 0 do
        i + ec@ 80 or  picture i + c! \ Bit-7 always high
    loop
    drop ;

\ Note that the first cell of a movie must contain the
\ full length of the stored picture frames in bytes!!
: EEMOVIE       ( eeaddr -- )   \ Play movie from EEPROM
    @+ bounds ?do               \ Get length of movie
        i ee>picture  frame     \ Play one frame at a time
    dm 10 +loop ;               \ To next picture


code SETUP-SCAN ( -- )
    #0 yy mov                   \ Init. offset register
    #0 160 & mov                \ Stop timer-A0
    dm 250 # 172 & mov          \ Interrupt after 500 cycles
    0254 # 160 & mov            \ Start timer
    10 # 162 & bis              \ Compare 0 interrupt on
    #8 sr bis                   \ General interrupts on
    next
end-code

\ This routine builds a picture on a 7 x 10 bits led screen
\ out of the first 10 bytes of the picture buffer.
\ By changing the pulsewidth the display has a variable brightness
\ The brightness may be different for each of the 10 columns.
routine SCAN    ( -- addr )
    picture # xx mov            \ Address of picture buffer
    yy xx add  xx ) 029 & .b mov
    bright # xx mov             \ Address of column brightness
    yy xx add  yy xx add  xx ) 172 & mov  ( TA0CCR0 )
    #0 yy cmp  =? if,           \ P3.6 active
        40 # 019 & .b bic
        #1 yy add  reti
    then,
    #1 yy cmp  =? if,           \ P1.3 active
        40 # 019 & .b bis
        #8 021 & .b bic
        #1 yy add  reti
    then,
    #2 yy cmp  =? if,           \ P1.4 active
        #8 021 & .b bis
        10 # 021 & .b bic
        #1 yy add  reti
    then,
    03 # yy cmp  =? if,         \ P1.5 active
        10 # 021 & .b bis
        20 # 021 & .b bic
        #1 yy add  reti
    then,
    #4 yy cmp  =? if,           \ P3.1 active
        20 # 021 & .b bis
        #2 019 & .b bic
        #1 yy add  reti
    then,
    05 # yy cmp  =? if,         \ P3.0 active
        #2 019 & .b bis
        #1 019 & .b bic
        #1 yy add  reti
    then,
    06 # yy cmp  =? if,         \ P3.2 active
        #1 019 & .b bis
        #4 019 & .b bic
        #1 yy add  reti
    then,
    07 # yy cmp  =? if,         \ P3.3 active
        #4 019 & .b bis
        #8 019 & .b bic
        #1 yy add  reti
    then,
    #8 yy cmp  =? if,           \ P3.4 active
        #8 019 & .b bis
        10 # 019 & .b bic
        #1 yy add  reti
    then,
    09 # yy cmp  =? if,         \ P3.5 active
        10 # 019 & .b bis
        20 # 019 & .b bic
        #1 yy add  reti
    then,
    20 # 019 & .b bis           \ Pause
    #0 yy mov  reti
end-code


\ Display tools

code UP     ( b1 -- b2 )        \ Variant of 2* with bit-7 always set
    7F # tos and>               \ Leave only low 7 bits
    40 # tos bit                \ Bit-6 to carry
    tos tos addc                \ Shift left using carry
    80 # tos bis                \ Bit-7 always high
    next
end-code

code DWN    ( b1 -- b2 )        \ Variant of 2/ with bit-7 always set
    7F # tos and>               \ Leave only low 7 bits
    tos rra  cs? if,            \ Shift right, bit-0 set?
        40 # tos bis            \ Yes, set bit-6
    then,
    80 # tos bis                \ Bit-7 always high
    next
end-code


: <<    ( +n -- )               \ Shift entire buffer +n positions left
    >r  picture copy r@ move
    picture r@ +  picture  #pict r@ - move
    copy picture #pict + r@ - r> move ;

: >>    ( +n -- )               \ Shift entire buffer +n positions right
    >r  picture #pict + r@ - copy r@ move
    picture dup r@ +  #pict r@ - move
    copy picture r> move ;

: /\    ( -- )                  \ Rotate entire picture one row up
    picture #pict bounds do
        i c@  up  i c!
    loop ;

: \/    ( -- )
    picture #pict bounds do     \ Rotate entire picture one row down
        i c@   dwn  i c!
    loop ;

scan  FFF2  vec!                \ Install timer-A0 vector
shield DISPLAY\  freeze

\ End

