\ -*- coding: utf-8 -*-

\ Fast Forth For Texas Instrument MSP430FRxxxx FRAM devices
\ Copyright (C) <2019>  <J.M. THOORENS>
\
\ This program is free software: you can redistribute it and/or modify
\ it under the terms of the GNU General Public License as published by
\ the Free Software Foundation, either version 3 of the License, or
\ (at your option) any later version.
\
\ This program is distributed in the hope that it will be useful,
\ but WITHOUT ANY WARRANTY\ without even the implied warranty of
\ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
\ GNU General Public License for more details.
\
\ You should have received a copy of the GNU General Public License
\ along with this program.  If not, see <http://www.gnu.org/licenses/>.
\
; ----------------------------------------------------------------------
; UART2I2CS.f
; ----------------------------------------------------------------------
\
\ TARGET SELECTION
\ LP_MSP430FR2476
\ MSP_EXP430FR5739  MSP_EXP430FR5969    MSP_EXP430FR5994    MSP_EXP430FR6989
\ MSP_EXP430FR4133 can't use LED1 !!! (wired on UART TX)
\ MSP_EXP430FR2433    MSP_EXP430FR2355    CHIPSTICK_FR2433
\
\ FastForth kernel compilation minimal options:
\ DTC = 2, THREADS = 16, FREQUENCY = 16
\ TERMINALBAUDRATE = 115200 up to 2457600, TERMINAL3WIRES, TERMINAL4WIRES
\ MSP430ASSEMBLER, CONDCOMP
\
\
\     notebook                                 USB to I2C_Slave bridge                                     any I2C_slave
\ +---------------+         +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - --+
\ |               |         |   PL2303HXD               master running UART2I2CS @ 16MHz |
\ |               |         +---------------+           +--------------------------------+         +-------------------------------+
\ |               |         |               |           |                                |         |                               |
\ |   TERATERM   -o--> USB -o--> USB2UART --o--> UART --o--> FAST FORTH ---> UART2I2CS --o--> I2C -o--> FAST FORTH with kernel     |
\ |   terminal    |         |               | 921600Bds |                                |  450kHz |     option TERMINAL_I2C       |
\ |               |         +---------------+           +--------------------------------+         +-------------------------------+
\ |               |         |                                                            | 
\ +---------------+         +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - --+
\
\
\ software I2C MASTER, you can use any I/O for SDA and SCL,
\ Preferably use a couple of I/O in the interval Px0...Px3.
\ don't forget to wire 3.3k pullup resitors on pin SDA and SCL.


\ the LEDs TX and RX work fine, uncomment if you want.

\ Multi Master Mode work but is not tested in real word.


PWR_STATE

[DEFINED] {FF_I2C} [IF]  {FF_I2C} [THEN]

MARKER {FF_I2C}

[UNDEFINED] @ [IF]
\ https://forth-standard.org/standard/core/Fetch
\ @     c-addr -- char   fetch char from memory
CODE @
MOV @TOS,TOS
MOV @IP+,PC
ENDCODE
[THEN]

[UNDEFINED] CONSTANT [IF]
\ https://forth-standard.org/standard/core/CONSTANT
\ CONSTANT <name>     n --                      define a Forth CONSTANT 
: CONSTANT 
CREATE
HI2LO
MOV TOS,-2(W)           \   PFA = n
MOV @PSP+,TOS
MOV @RSP+,IP
MOV @IP+,PC
ENDCODE
[THEN]

$1820 CONSTANT SLAVE_ADR    \ CONSTANT = I2C_Slave address in FRAM


ASM QUIT_I2C                    \ as ASM word, QUIT_I2C is hidden.
\ ------------------------------\
BW1 \   STOP I2C                \
\ ------------------------------\
    BIC.B #LED2,&LED2_DIR       \ RX green led OFF
    BIC.B #LED2,&LED2_OUT       \ RX green led OFF
    BIC.B #LED1,&LED1_DIR       \ TX red led OFF
    BIC.B #LED1,&LED1_OUT       \ TX red led OFF
\ ------------------------------\
    BIS #M_BUS,&I2CM_REN        \ reset I/O as reset state
    BIC #M_BUS,&I2CM_DIR        \
    BIS #M_BUS,&I2CM_OUT        \
    MOV #$5A88,&WDTCTL          \ stop WDT
    BIC #1,&SFRIE1              \ disable WDT int
    MOV #COLD,&WDT_VEC          \ restore default WDT_VEC value
    MOV &TERMINAL_INT,&TERM_VEC \ restore default TERM_VEC value
    MOV #WARM,X                 \ X = CFA of WARM
    ADD #4,X                    \ X = BODY of WARM
    MOV X,-2(X)                 \ restore default WARM: BODY --> PFA
\    MOV @IP+,PC                 \ quiet return without WARM
\    MOV #COLD,PC                 \ explicit return with COLD
    MOV X,PC                    \ explicit return with WARM
ENDASM

ASM WDT_INT                     \ enable Alt+B when I2C_Master is sleeping
\ I2C_Master se réveille à l'occurence d'un break qui génère la sortie du programme. 
BIT #8,&TERM_STATW              \ UART break sent by TERATERM ?
0<> IF
    ADD #4,RSP                  \ remove RETI
    POPM #6,IP                  \ remove Y,X,W,T,S,IP from return stack, restore IP
    GOTO BW1                    \
THEN
RETI
ENDASM

\ \ vvvvvvvMulti-Master-Modevvvvvv\
\ ASM DO_IDLE                     \ 
\ MOV #4,W                        \ 1   wait bus idle time = 5 µs @ 16 MHz
\ BEGIN
\     BIT #8,&TERM_STATW          \ 3         break sent by TERATERM ?
\     0<> IF                      \ 2
\         ADD #2,RSP              \           remove RET
\         MOV #QUIT_I2C,PC        \           STOP I2C
\     THEN  
\     BIT.B #MSCL,&I2CM_IN        \ 3 
\     0= IF                       \ 2
\         MOV #4,W                \ 1 if SCL is LOW
\     THEN
\         BIT.B #MSDA,&I2CM_IN    \ 3
\     0= IF                       \ 2
\         MOV #4,W                \ 1 if SDA is LOW
\     THEN
\     SUB #1,W                    \ 1
\ 0= UNTIL                        \ 2
\ MOV @RSP+,PC
\ ENDASM
\ \ ^^^^^^^Multi-Master-Mode^^^^^^\


\ **************************************\
ASM TERM_INT                            \  starts with first char of line input from TERMINAL
\ **************************************\
\ I2C_Master s'est réveillé en début du flux de caractères en provenance du TERMINAL
ADD #4,RSP                              \ 1   remove RET and SR
POPM #6,IP                              \ 8   pop Y,X,W,T,S,IP
\                                       \ S = last char to RX from UART
\                                       \ T = UART RX buffer
\                                       \ W = flag NOECHO/ECHO to TERMINAL
\                                       \ X = UART RX char
\                                       \ Y = I2C TX buffer
\ --------------------------------------\
\ les caractères reçus de TERMINAL sont stockés dans le buffer PAD.
\ A la réception du caractère CR, I2C_Master envoie XOFF à TERMINAL
\ et refait encore un tour pour capter LF.
\ pendant ce temps, I2C_Slave est dans l'état SLEEP, le bus I2C est libre
BEGIN                                   \
    BEGIN                               \
        BEGIN                           \   wait for a char
            BIT #1,&TERM_IFG            \ 3 received char ?
        0<> UNTIL                       \ 2 
        MOV.B &TERM_RXBUF,X             \ 3 received char in TERMRXBUF
BW1     MOV.B X,0(T)                    \ 3 fill I2C_input... ...buffer
        CMP.B S,X                       \ 1 char = char end = $0A ?
        0= ?GOTO FW1                    \ 2 goto out of UART RX loop
        ADD #1,T                        \ 1
        CMP.B #$0D,X                    \ 2 CR ?
    0<> WHILE                           \ 2 30 cycles loop ==> up to 2.66 Mbds @ 8MHz
        CMP #0,W                        \ 1
        0= IF                           \ 2 if echo ON requested by I2C_Slave
            BEGIN                       \
                BIT #2,&TERM_IFG        \ 3 TX buffer empty ?
            0<> UNTIL                   \ 2 
            MOV.B X,&TERM_TXBUF         \ 3
        THEN
    REPEAT                              \ 2
    CALL &RXOFF                         \ stops UART RX after received char CR and before receive char LF
AGAIN                                   \ then take again one loop back to get LF
\ --------------------------------------\
FW1 \ END OF UART RX                    \  CR+LF end the line input from TERMINAL
\ ======================================\ S = last char to transmit
\ ======================================\ T = last char transmitted
BW2 \ I2C MASTER TX                     \ W = bits count / delay count down
\ ======================================\ X = I2C_Address / I2C_Data
\ ======================================\ Y = buffer TX address            
\ --------------------------------------\
BIS.B #LED1,&LED1_DIR                   \ red led ON = I2C TX 
BIS.B #LED1,&LED1_OUT                   \ red led ON = I2C TX
\ --------------------------------------\
\ \     vvvvvvvvvvMulti-Master-Modevvvvvvv\
\ BW3 \ I2C_Master TX Start               \ here, SDA and SCL must be in idle state
\ \     ^^^^^^^^^^Multi-Master-Mode^^^^^^^\
BIS.B   #MSDA,&I2CM_DIR                 \ 4 l   force SDA as output (low)
MOV.B   &SLAVE_ADR,X                    \ 1 h   X = Slave_Address
BIC.B   #1,X                            \ 1 h   Master TX
NOP3                                    \ 3 h
NOP3                                    \ 3 h
BIS.B   #MSCL,&I2CM_DIR                 \ 4 h   force SCL as output (low)
MOV S,T                                 \       
XOR #-1,T                               \ 1     set T <> S before sending I2C address 
\ --------------------------------------\
BEGIN
\   ------------------------------------\
\   I2C Master TX address/Data          \
\   ------------------------------------\
    MOV.B #8,W                          \ 1 l       prepare 8 bits address
    BEGIN                               \
        ADD.B X,X                       \ 1 l       shift one left
        U>= IF                          \ 2 l       carry set ?
            BIC.B #MSDA,&I2CM_DIR       \ 4 l       yes : SDA as input  ==> SDA high because pull up resistor
        ELSE                            \ 2 l
            BIS.B #MSDA,&I2CM_DIR       \ 4 l       no  : SDA as output ==> SDA low
            NOP2                        \ 2
        THEN                            \   l   _
        BIC.B #MSCL,&I2CM_DIR           \ 4 l _^    release SCL (high)
        BEGIN                           \           9~h/16~l
            BIT.B #MSCL,&I2CM_IN        \ 3 h       test if SCL is released
        0<> UNTIL                       \ 2 h 
\ \       vvvvvvvvMulti-Master-Modevvvvvvv\
\         BIT.B #MSDA,&I2CM_IN            \ 3 h _     test SDA
\ \       ^^^^^^^^Multi-Master-Mode^^^^^^^\
        BIS.B #MSCL,&I2CM_DIR           \ 4 h  v_   SCL as output : force SCL low
\ \       vvvvvvvvvvvvMulti-Master-Modevvvvvvvvvvv\
\         0= IF                                   \ 2 l
\             BIT.B #MSDA,&I2CM_DIR               \ 3 l
\             0= IF                               \ 2 l
\ \               --------------------------------\
\ \               collision detected              \   l collision if SDA(IN)=0 AND SDA(DIR)=0
\ \               --------------------------------\
\                 BIS.B #MSCL,&I2CM_DIR           \ 4 l release SCL first
\                 CALL #DO_IDLE                   \     wait stable idle state 
\                 GOTO BW3                        \ 2 l goto START TX
\             THEN                                \
\         THEN                                    \
\ \       ^^^^^^^^^^^^Multi-Master-Mode^^^^^^^^^^^\
        SUB #1,W                        \ 1 l       bits count-1
    0= UNTIL                            \ 2 l
\   ------------------------------------\
    BIC.B   #MSDA,&I2CM_DIR             \ 4 l       after TX byte we must release SDA to read Ack/Nack from Slave
\   ------------------------------------\
\   I2C Master get Slave Ack/Nack       \
\   ------------------------------------\       _
    BIC.B   #MSCL,&I2CM_DIR             \ 3 l _^    release SCL (high)
    BEGIN                               \
        BIT.B #MSCL,&I2CM_IN            \ 3 h       test if SCL is released
    0<> UNTIL                           \ 2 h
    BIT.B   #MSDA,&I2CM_IN              \ 3 h _     get SDA state
    BIS.B   #MSCL,&I2CM_DIR             \ 3 h  v_   SCL as output : force SCL low
\   ------------------------------------\
0= WHILE \ 1 Slave Ack received         \ 2 l       goto THEN; out of loop if Nack
\   ------------------------------------\           
\   I2C_Master_TX_data_loop             \
\   ------------------------------------\
    CMP.B S,T                           \ 1         T = S = last char to transmit ?
0<> WHILE \ 2                           \ 2         goto beyond REPEAT; out of loop if =
    MOV.B @Y+,X                         \ 2 l       get next byte to TX
    MOV X,T                             \ 1         T = last char TX for comparaison above
REPEAT                                  \           <-- WHILE2  search "Extended control-flow patterns"... 
THEN                                    \           <-- WHILE1  ...in https://forth-standard.org/standard/rationale
\   ------------------------------------\
\ Nack or Ack on last char              \           Nack = I2C_Slave request or I2C_Slave RESET, Ack = last char has been TX
\   ------------------------------------\
    NOP3                                \ 3 l   _   delay to reach I2C tLO
    BIC.B #MSCL,&I2CM_DIR               \ 4 l _^    release SCL to enable reSTART
\ --------------------------------------\
    BIC.B #LED1,&LED1_DIR               \ red led OFF = endof I2C TX 
    BIC.B #LED1,&LED1_OUT               \ red led OFF = endof I2C TX
\ --------------------------------------\
\ ======================================\
\ END OF I2C MASTER TX                  \
\ ======================================\
\ ======================================\
\ I2C MASTER RX                         \
\ ======================================\
BW3 \ I2C_Master START RX               \
\ --------------------------------------\
\ le driver I2C_Master envoie START RX en boucle.
\ le test d'un break en provenance de l'UART est intégré dans cette boucle.
\ --------------------------------------\
BEGIN                                   \           I2C MASTER RX
\ --------------------------------------\
    BEGIN                               \           I2C MASTER START RX
\   ------------------------------------\
\       I2C_Master_Start_Cond           \           here, SDA and SCL must be in idle state
\       --------------------------------\
        BIS.B   #MSDA,&I2CM_DIR         \ 4 l       force SDA as output (low)
        MOV.B   &SLAVE_ADR,X            \ 1 h       X = Slave_Address
        BIS.B   #1,X                    \ 1 h       Master RX
        NOP3                            \ 3
        NOP3                            \ 3
        BIS.B   #MSCL,&I2CM_DIR         \ 4 h       force SCL as output (low)
\       --------------------------------\
\       I2C_Master_Send_address         \           may be SCL is held low by slave
\       --------------------------------\
        MOV.B   #8,W                    \ 1 l       prepare 8 bits address
        BEGIN                           \
            ADD.B X,X                   \ 1 l       shift one left
            U>= IF                      \ 2 l       carry set ?
                BIC.B #MSDA,&I2CM_DIR   \ 4 l yes : SDA as input  ==> SDA high because pull up resistor
            ELSE                        \ 2 l
                BIS.B #MSDA,&I2CM_DIR   \ 4 l no  : SDA as output ==> SDA low
                NOP2                    \ 2 l
            THEN                        \       _
            BIC.B #MSCL,&I2CM_DIR       \ 4 l _^    release SCL (high)
            BEGIN                       \
                BIT.B #MSCL,&I2CM_IN    \ 3 h       test if SCL is released
            0<> UNTIL                   \ 2 h
\ \           vvvvvvMulti-Master-Modevvvvv\
\             BIT.B #MSDA,&I2CM_IN                    \ 3 h _     test SDA
\ \           ^^^^^^Multi-Master-Mode^^^^^\
            BIS.B #MSCL,&I2CM_DIR       \ 4 h  v_   SCL as output : force SCL low
\ \           vvvvvvvvvvvvMulti-Master-Modevvvvvvvvvvv\
\             0= IF                                   \ 2 l
\                 BIT.B #MSDA,&I2CM_DIR               \ 3 l
\                 0= IF                               \ 2 l
\ \               ------------------------------------\
\ \               collision detection                 \   l collision if SDA(IN)=0 AND SDA(DIR)=0
\ \               ------------------------------------\
\                     BIS.B #MSCL,&I2CM_DIR           \ 4 l release SCL first
\                     CALL #DO_IDLE                   \     wait stable idle state 
\                     GOTO BW3                        \ 2 l goto START RX
\                 THEN                                \
\             THEN                                    \
\ \           ^^^^^^^^^^^^Multi-Master-Mode^^^^^^^^^^^\
            SUB #1,W                    \ 1 l       bits count - 1
        0= UNTIL                        \ 2 l
\       --------------------------------\
        BIC.B   #MSDA,&I2CM_DIR         \ 4 l   _   after TX address we must release SDA to read Ack/Nack from Slave
        BIC.B   #MSCL,&I2CM_DIR         \ 3 l _^    release SCL (high)
        BEGIN                           \
            BIT.B #MSCL,&I2CM_IN        \ 3 h       test if SCL is released
        0<> UNTIL                       \ 2 h
        BIT.B   #MSDA,&I2CM_IN          \ 3 h _     get SDA
        BIS.B   #MSCL,&I2CM_DIR         \ 3 h  v_   SCL as output : force SCL low
\       --------------------------------\  
    0<> WHILE   \ Nack_On_Address       \ 2 l
\       --------------------------------\  
        NOP3                            \ 3 l       delay to reach tLO
\       --------------------------------\
\       I2C_Master Send STOP            \           after Nack_On_Address
\       --------------------------------\     _
        BIS.B #MSDA,&I2CM_DIR           \ 4 l  v_   SDA as output ==> SDA low
        NOP3                            \ 3 l   _
        BIC.B #MSCL,&I2CM_DIR           \ 4 l _^    release SCL (high)
        NOP3                            \ 3 h
        NOP3                            \ 3 h   _
        BIC.B #MSDA,&I2CM_DIR           \ 4 h _^    SDA as input  ==> SDA high with pull up resistor
\       --------------------------------\
        BIT #8,&TERM_STATW              \ 3         break sent by TERATERM ?
        0<> IF
            MOV #QUIT_I2C,PC            \ 2         STOP I2C
        THEN
\       --------------------------------\
    REPEAT                              \ 2         loop back to MASTER START RX
\   ------------------------------------\
    BIS.B #LED2,&LED2_DIR               \           green led ON = I2C RX
    BIS.B #LED2,&LED2_OUT               \           green led ON = I2C RX
\   ------------------------------------\
\   I2C_Master_RX_data                  \
\   ------------------------------------\
    BEGIN
        BEGIN
            MOV.B #8,W                  \ 1 l       prepare 8 bits transaction
\           ----------------------------\
            BEGIN                       \
\               ------------------------\       _
\               do SCL pulse            \ SCL _| |_
\               ------------------------\       _
                BIC.B #MSCL,&I2CM_DIR   \ 4 l _^    release SCL (high)
                BEGIN                   \           9/16~l
                BIT.B #MSCL,&I2CM_IN    \ 3 h       test if SCL is released
                0<> UNTIL               \ 2 h
                BIT.B #MSDA,&I2CM_IN    \ 3 h _     get SDA
                BIS.B #MSCL,&I2CM_DIR   \ 4 h  v_   SCL as output : force SCL low   13~
                ADDC.B X,X              \ 1 l       C <--- X(7) ... X(0) <--- SDA
                SUB #1,W                \ 1 l       count down of bits
            0= UNTIL                    \ 2 l
\           ----------------------------\
            CMP.B #8,X                  \ 1 l       $08 = char BS
\           ----------------------------\
        U>= WHILE                       \ 2 l       normal char received, comprizing BS
\           ----------------------------\
            BEGIN                       \
                BIT #2,&TERM_IFG        \ 3 l       TX buffer empty ?
            0<> UNTIL                   \ 2 l       loop if no
\           ----------------------------\   
            BIS.B #MSDA,&I2CM_DIR       \ 4 l       prepare Ack
\           ----------------------------\       _   
            BIC.B   #MSCL,&I2CM_DIR     \ 3 l _^    release SCL (high)
            BEGIN                       \
                BIT.B #MSCL,&I2CM_IN    \ 3 h       test if SCL is released
            0<> UNTIL                   \ 2 h
            MOV.B X,&TERM_TXBUF         \ 3 h _     send RX char to UART TERMINAL
            BIS.B #MSCL,&I2CM_DIR       \ 3 h  v_   SCL as output : force SCL low
\           ----------------------------\  
            BIC.B #MSDA,&I2CM_DIR       \ 4 l       before RX next byte, we must release SDA
\           ----------------------------\  
        REPEAT                          \ 2 l       loop back to I2C_Master_RX_data
\       --------------------------------\
\       Ctrl_char received              \
\       --------------------------------\ 
        CMP.B #4,X                      \ 1         
        U>= IF                          \ 2
\           ----------------------------\
            BIS.B #MSDA,&I2CM_DIR       \ 4 l       prepare Ack for $04=NOECHO,$05=ECHO
\           ----------------------------\
        THEN
\       --------------------------------\       _   
        BIC.B   #MSCL,&I2CM_DIR         \ 3 l _^    release SCL (high)
        BEGIN                           \
            BIT.B #MSCL,&I2CM_IN        \ 3 h       test if SCL is released
        0<> UNTIL                       \ 2 h
        BIT.B   #MSDA,&I2CM_IN          \ 3 h _     get SDA
        BIS.B   #MSCL,&I2CM_DIR         \ 3 h  v_   SCL as output : force SCL low
\       --------------------------------\       
    0= WHILE                            \ 2 l       if Ack sent by Master (4 >= char < 8) 
\       --------------------------------\       
        BIC.B #MSDA,&I2CM_DIR           \           before RX next byte, we must release SDA
\       --------------------------------\       
        CMP.B #4,X                      \
\       --------------------------------\       
        0= IF                           \           $04 = ctrl_char for NOECHO request
            MOV #1,&PAD_I2CADR          \           set NOECHO
        ELSE                            \           $05 = ctrl_char for ECHO request
            MOV #0,&PAD_I2CADR          \           set ECHO
        THEN
    REPEAT                              \           loop back to I2C_Master_RX_data
\   ------------------------------------\   
\   if Nack sent by Master              \           SDA is released HIGH
\   ------------------------------------\   
    CMP.B #2,X                          \ 1 l       $02 = ctrl_char for ABORT request
U>= WHILE                               \ 2 l       if Ctrl_char = $02 (ABORT), $03 (COLD)
    0= IF                               \    
\       --------------------------------\   
\       UART_ABORT                      \           if ctrl_char $02
\       --------------------------------\
        MOV #0,&PAD_I2CADR              \           set echo on I2C_Master side (I use the useless address PAD_I2CADR)
        CALL &RXON                      \           resume UART downloading source file
        BEGIN                           \
            BIC #UCRXIFG,&TERM_IFG      \           clear UCRXIFG
            MOV &FREQ_KHZ,Y             \           1000, 2000, 4000, 8000, 16000, 240000
            BEGIN MOV #32,X             \           2~        <-------+ windows 10 seems very slow...
                BEGIN SUB #1,X          \           1~        <---+   | ==> ((32*3)+5)*1000 = 101ms delay
                0= UNTIL                \           2~ 3~ loop ---+   | to refill its USB buffer
                SUB #1,Y                \           1~                |
            0= UNTIL                    \           2~ 101~ loop -----+
\             BEGIN MOV #65,X             \                  <-------+ linux with minicom seems very very slow...
\                 BEGIN SUB #1,X          \                  <---+   | ==> ((65*3)+5)*1000 = 200ms delay
\                 0= UNTIL                \           3~ loop ---+   | to refill its USB buffer
\                 SUB #1,Y                \                          |
\             0= UNTIL                    \           200~ loop -----+
            BIT #UCRXIFG,&TERM_IFG      \           4 new char in TERMRXBUF during this delay ?
        0= UNTIL                        \           2 yes, the input stream may be still active: loop back
    THEN
REPEAT                                  \           loop back to I2C MASTER reSTART RX
\ --------------------------------------\
\ I2C_Master Send STOP                  \           after RX Data(s) 
\ --------------------------------------\       _
BIC.B #MSCL,&I2CM_DIR                   \ 4 l _^    release SCL (high)
NOP3                                    \ 3 h
NOP3                                    \ 3 h   _
BIC.B #MSDA,&I2CM_DIR                   \ 4 h _^    SDA as input  ==> SDA high with pull up resistor
\ --------------------------------------\
BIC.B #LED2,&LED2_DIR                   \ 4 l green led OFF = endof I2C RX
BIC.B #LED2,&LED2_OUT                   \ 4 l green led OFF = endof I2C RX
\ --------------------------------------\
\ ======================================\
\ ======================================\
\ END OF I2C MASTER RX                  \   here I2C_bus is free and Nack on Ctrl_char $00|$01 remains to be processed.
\ ======================================\
\ ======================================\
\ TERMINAL TX --> UART RX               \
\ --------------------------------------\
\ I2C_Slave KEY ctl_char $01            \ I2C_Slave request for KEY input
\ --------------------------------------\
CMP.B #1,X                              \ 1 l
\ Quand I2C_Master reçoit ce caractère de contrôle,
\ il attend un caractère en provenance de TERMINAL UART
\ et une fois ce caractère reçu reSTART TX pour l'envoyer à I2C_Slave
0= IF                                   \ 2 l
    CALL &RXON                          \ 4 l  to enable UART RX; use no registers
    MOV #PAD_I2CCNT,Y                   \ Y = input buffer for I2C_Master TX (I use the useless address PAD_I2CCNT)
    MOV Y,T                             \ T = input buffer for UART RX
    BEGIN                               \   wait for a char or for a break
        BIT #UCRXIFG,&TERM_IFG          \ 3 received char ?
    0<> UNTIL                           \ 2 
    MOV.B &TERM_RXBUF,X                 \ 3 X = UART RX char
    MOV.B X,0(T)                        \ 3 fill I2C_input... ...buffer
    MOV.B X,S                           \ 2 S = KEY char = last char to send with I2C_MASTER TX !
    CALL &RXOFF                         \ stops UART RX
    GOTO BW2                            \ goto I2C MASTER TX
THEN                                    \                             
\ --------------------------------------\
\ I2C_Slave ACCEPT ctrl_char $00        \ I2C_Slave requests I2C_Master to stop RX and start TX
\ --------------------------------------\
\ en début de sa routine ACCEPT, I2C_Slave envoie sur le bus I2C le caractère de contrôle $00
\ avant de s'endormir avec SLEEP
\ I2C_Master envoie NACK + STOP pour signifier la fin de la transaction.
\ --------------------------------------\
\ I2C_Slave SLEEP ctrl_char $00         \ as request to stop I2C_Master RX     
\ --------------------------------------\
\ si I2C_Slave est sorti de son sommeil par un START RX, idem.
\ --------------------------------------\
\ I2C_Master envoie un XON sur l'UART, à destination de TERMINAL
\ --------------------------------------\
MOV #PAD_ORG,Y                          \ Y = input buffer for I2C_Master TX
MOV &PAD_I2CADR,W                       \ W = 0 if ECHO, 1 if NOECHO
MOV Y,T                                 \ T = input buffer for UART RX
MOV #$0A,S                              \ S = last char to send with I2C_MASTER TX
\ --------------------------------------\
BIT #1,&TERM_IFG                        \ 3 RX_Int ?
0<> IF                                  \ if RX_INT
    MOV &TERM_RXBUF,X                   \ 3 clear RX_Int
    CMP #$0A,X                          \ 2 received char = LF ? (end of downloading ?)
    0<> IF                              \
        CALL &RXON                      \ 2 no : send XON then goto process first char of new line.
        GOTO BW1                        \        without SLEEP
    THEN
THEN
\ --------------------------------------\
PUSHM #6,IP                             \ push IP,S,T,W,X,Y, as ACCEPT
MOV #SLEEP,PC                           \ execute RXON then goto dodo
\ --------------------------------------\
\ I2C_Master se réveillera lors d'un flux
\ de caractères en provenance du TERMINAL
\ ou à l'occurence d'un break. 
ENDASM                                  \ 
\ --------------------------------------\





\ --------------------------------------\
ASM WARM_I2C                            \           replace default WARM
\ --------------------------------------\
CMP #4,&SAVE_SYSRSTIV                   \
0= IF
    MOV #QUIT_I2C,PC                    \           if <reset> STOP I2C
THEN                
    CMP #$10,&SAVE_SYSRSTIV             \
    U>= IF
        MOV #QUIT_I2C,PC                \           if other SYS failure >= $10 STOP I2C
    THEN                                \
MOV #0,&SAVE_SYSRSTIV                   \           clear it after use
\ --------------------------------------\
\ init WDT timer                        \
\ --------------------------------------\
MOV #%0101_1010_0101_1111,&WDTCTL       \           start Watchdog Timer : XDTPW, WDTSSEL=VLOCLK, WDTCNTCL=1, WDTIS=2^6 (8ms)
BIS #1,&SFRIE1                          \           enable WDT
MOV #WDT_INT,&WDT_VEC                   \           replace WDT_VEC default value (COLD) by WDT_INT
\ --------------------------------------\
\ init TERMINAL UART                    \
\ --------------------------------------\
BIS #IE_TERM,&TERM_IE                   \           then enable RX interrupt for wake up on terminal input
BIS.B #TERM_BUS,&TERM_SEL               \           Configure pins TXD & RXD for TERM_UART use, otherwise no TERMINAL !
MOV #TERM_INT,&TERM_VEC                 \           replace TERM_VEC default value (TERMINAL_INT) by TERM_INT
\ --------------------------------------\
\ initialisation I2C_MASTER             \           I2CM_DIR(M_BUS) = 0,  M_BUS as input
\ --------------------------------------\
BIC #M_BUS,&I2CM_REN                    \           remove internal pullup resistors (presence of external pullup resistor 3.3k)
BIC #M_BUS,&I2CM_OUT                    \           preset SDA + SCL LOW
\ --------------------------------------\
\ activate I/O                          \           SYSRSTIV = $02 | $0E = POWER ON | SVSH threshold
\ --------------------------------------\
BIC #1,&PM5CTL0                         \           activate all previous I/O settings; if not activated, nothing works after reset !
\ ======================================\
\ ENDOF WARM part                       \
\ ======================================\
GOTO BW3                                \           goto I2C_Master START RX
ENDASM

\ ================================================================================
\ Driver UART to I2CM : this FastForth launchpad becomes an USB to I2C_Slave bridge
\ ================================================================================
\
\ I2C = 450 kHz @ MCLK = 16 MHz, better than an hardware UCB0 I2C Master !
\ I2C bus resistors pullup = 3.3k
\ type on TERMINAL "$10 UART2I2CS" to link TERMINAL with FastForth I2C_Slave at address hex $10
\
\ type Alt+B on TERATERM TERMINAL to send a break to quit, or <reset> on I2C_Master.

\ UART to I2C_Master 
CODE UART2I2CS          \ SlaveAddress --
MOV @RSP+,IP
MOV TOS,&SLAVE_ADR      \ save in FRAM
MOV @PSP+,TOS
MOV #WARM,X
MOV #WARM_I2C,2(X)      \ replace WARM by WARM_I2C, so POR execute WARM_I2C
MOV X,PC                \ execute WARM_I2C
ENDCODE

RST_HERE ECHO

; Since there is no difference in behaviour whether the TERMINAL is connected to the Master
; or to a Slave, the convenient way to check which target is connected to is WARM,
; because WARM displays first the decimal I2C address when TERMINAL is connected to I2C FastForth.

$10 UART2I2CS

WARM    \ to show the target linked to TERMINAL after: see the decimal I2C Slave address first.
; Alt-B to quit UART2I2CS

