OSDN Git Service

9980fe6d9bc8bc4f3073fc4614bbd6999a978c46
[fast-forth/master.git] / MSP430-FORTH / UARTI2CS.f
1 \ -*- coding: utf-8 -*-
2 \
3 \ TARGET SELECTION ( = the name of \INC\target.pat file without extension)
4 \ MSP_EXP430FR5739  MSP_EXP430FR5969    MSP_EXP430FR5994    MSP_EXP430FR6989
5 \ MSP_EXP430FR4133 (can't use LED1 because wired on UART TX)
6 \ MSP_EXP430FR2433  CHIPSTICK_FR2433    MSP_EXP430FR2355
7 \ LP_MSP430FR2476   MY_MSP430FR5738_2
8 \
9 \ from scite editor : copy your target selection in (shift+F8) parameter 1:
10 \
11 \ OR
12 \
13 \ drag and drop this file onto SendSourceFileToTarget.bat
14 \ then select your TARGET when asked.
15 \
16 \
17 \ FastForth kernel compilation minimal options:
18 \ TERMINAL3WIRES | TERMINAL4WIRES
19 \
20 \ see symbolic values in \inc\launchpad.pat or/and in \inc\device.pat
21 \
22 \ ================================================================================
23 \ coupled to a PL2303HXD/GC/TA cable, this driver enables a FastForth target to act as USB to I2C_Slave bridge,
24 \ thus, from TERATERM.exe you can take the entire control of up to 112 I2C_FastForth targets.
25 \ In addition, it simulates a full duplex communication while the I2C bus is only half duplex.
26 \ ================================================================================
27
28 \ ------------------------------------------------- 
29 ; UARTI2CS.f  \I2C to UART bridge for I2C_FastForth\ -------------------------->+
30 \ --------------------------------------------------                            |
31 \ ------------------------------                                                |
32 \ see forthMSP430FR_TERM_I2C.asm                                                |
33 \ ------------------------------                                                |
34 \        |                                                                      |
35 \        |                                                                      |
36 \        |             GND------------------------------GND                     |
37 \        |             3V3-------------o---o------------3V3                     |
38 \        |                             |   |                                    | 
39 \        |                             1   1                                    | 
40 \        |                             k   k                Txy.z output        | 
41 \        v                             0   0                     to             v                 GND-------------------------------------GND 
42 \   I2C_FastForth                      |   |                  Px.y int       UARTI2CS              +-------------------------------------->+
43 \     (hardware         +<-------------|---o------------>+     jumper       (Software              |    +<----------------------------+    |
44 \     I2C Slave)        ^      +<------o----------+      ^     +--->+       I2C Master)            |    |    +------(option)---->+    |    |
45 \                       v      v                  ^      v     ^    |                              ^    v    ^                   v    ^    v
46 \ I2C_FastForth(s)     SDA    SCL  connected to: SCL    SDA    |    v   I2C_to_UART_bridge        TXD  RXD  RTS  connected to : CTS  TXD  RXD  UARTtoUSB <--> COMx <--> TERMINAL
47 \ ------------------   ----   ----               ----   ----             ----------------         ---  ---  ---                 ---  ---  ---  ---------      ----      --------
48 \ MSP_EXP430FR2355     P1.2   P1.3               P3.3   P3.2  P1.7 P1.6  MSP_EXP430FR2355 (24MHz) P4.3 P4.2 P2.0                               PL2303GC                    |      
49 \ MSP_EXP430FR5739     P1.6   P1.7               P4.1   P4.0  P1.1 P1.0  MSP_EXP430FR5739 (24MHz) P2.0 P2.1 P2.2                               PL2303HXD                   v
50 \ MSP_EXP430FR5969     P1.6   P1.7               P1.3   P1.2  P2.2 P3.4  MSP_EXP430FR5969 (16MHz) P2.0 P2.1 P4.1                               PL2303TA               TERATERM.EXE     
51 \ MSP_EXP430FR5994     P7.0   P7.1               P8.1   P8.2  P1.5 P1.4  MSP_EXP430FR5994 (16MHz) P2.0 P2.1 P4.2                               CP2102                      ^ 
52 \ MSP_EXP430FR6989     P1.6   P1.7               P1.5   P1.3  P3.6 P3.7  MSP_EXP430FR6989 (16MHz) P3.4 P3.5 P3.0                                                           |       
53 \ MSP_EXP430FR4133     P5.2   P5.3               P8.3   P8.2  P1.6 P1.7  MSP_EXP430FR4133 (16MHz) P1.0 P1.1 P2.3                                                           |       
54 \ MSP_EXP430FR2433     P1.2   P1.3               P3.1   P3.2  P1.2 P1.3  MSP_EXP430FR2433 (16MHz) P1.4 P1.5 P1.0                                                           |           
55 \ LP_MSP430FR2476      P4.4   P4.3               P3.3   P3.2  P1.2 P1.1  LP_MSP430FR2476  (16MHz) P1.4 P1.5 P6.1                                                           |                                                                     
56 \ MY_MSP430FR5738_2    P1.6   P1.7               P1.3   P1.2  P1.1 P1.0 MY_MSP430FR5738_2 (24MHz) P2.0 P2.1 P2.2                               PL2303HXD                   |
57 \                                                                               ^                                                                                          |
58 \                                                                               |                                                                                          |
59 \                                                                              RST                                                                                       ALT+B
60 \                                                                               ^                                                                                          ^
61 \                                                                               |                                                                                          |
62 \                                                                         QUIT UARTI2CS                                                                             QUIT UARTI2CS
63 \
64 \ =============================================================================================
65 \ don't forget to link 3V3 and GND on each side and to add 1k0 pullup resistors on SDA and SCL.
66 \ =============================================================================================
67 \ don't forget to set the jumper Txy.z <--> Px.y
68 \ =============================================================================================
69 \ don't forget to remove the jumpers SBWTCK & SBWTDIO from the unpowered launchpad if any
70 \ =============================================================================================
71 \
72 \ empiric value of I2C pullup resistors: R (k) = 8 Vcc / MCLK (MHz). ex. VCC = 3.3, MCLK = 24 MHz ==> R = 1k1
73 \
74 \ if you want to see what is happening on the I2C bus with an oscilloscope, pay attention to the capacitance of the probes, 
75 \ switch them from x1 to x10. 
76 \
77 \ ------------
78 \ how it works
79 \ ------------
80 \
81 \ 1- the I2C bus is Master to Slave oriented, the Slave does not decide anything.
82 \    The I2C Master device is placed on the TERMINAL side and the FastForth target on the I2C Slave side.
83 \    Once the Master to Slave link is made, we have to find a trick to reverse the roles, 
84 \    so that the Slave can take control of the data exchange.
85 \
86 \ 2- The I2C bus is a half duplex exchange. 
87 \    Another trick will be to simulate an I2C_Master TERMINAL in Full Duplex mode.
88 \
89 \ 3- ..without forgetting a visual effect to show the lack of I2C connection.
90 \
91 \ Solution: The slave "slavishly" sends control characters to the master, 
92 \ and since this one obeys a bigger than itself, the programmer,
93 \ he makes it his "masterly" duty to obey the slave.
94 \
95 \ To take control of the master, the slave emits one of 5 CTRL-Chars:
96 \   CTRL-Char $00 sent by ACCEPT (before falling asleep with BACKGRND),
97 \   CTRL-Char $01 sent by KEY: request to send a single character from TERMINAL,
98 \   CTRL-Char $04 sent by NOECHO to switch the UART to half-duplex mode,
99 \   CTRL-Char $05 sent by ECHO to switch the UART to full duplex mode,
100 \   CTRL-Char $FF sent by ABORT": request to abort the file being downloaded if any,
101 \                                 followed by a START RX to display the ABORT" message.
102 \   More, if the master receives a $FF as data (it's the case for any SYS event on I2C_Slave side), 
103 \   it considers the link broken and performs ABORT, which forces a START RX into a 500 ms loop with an appropriate visual effect.
104 \   All this guarantees a perfect hot swap of any I2C_slave.
105 \
106 \ Once the slave sends the CTRL_Char $00, he falls asleep, 
107 \ On its receipt, the master sends an UART RXON then falls down to sleep awaiting a UART RX interruption from TERMINAL.
108 \ As long as the TERMINAL is silent, the master and the slave remain in their SLEEP mode,
109 \ (a part a Tx0_INT interrupt (2*12us @24MHz --> Ires < 0,1uA ) every 1/2s on Master side).
110 \ SLEEP mode is LPM0 for the master (else UART does not work), LPM4 for the slave.
111 \
112 \ interruptions
113 \ -------------
114 \ Since the slave can't wake up the master with a dedicated pin interrupt, the master must generate one
115 \ cyclically to listen to the slave.
116 \ 500MS_INT is used to generate a 1/2 second interrupt, obviously taken into account only when the master goes to sleep.
117 \ It performs a (re)START I2C RX that enables the I2C link to be re-established following a RESET performed on I2C_Slave side.
118 \
119 \ This interruption also allows to exit the UARTI2CS program when user sends a software BREAK (Teraterm(Alt-B)).
120 \
121 \ To avoid locking, we have to ensure U2I_TERM_INT priority greater than 500MS_INT. As MSP430FR2xxx don't have timer with lower priority than eUSCI,
122 \ we link the timer output pin with a contiguous pin with lower interrupt than TERM_INT to do this.
123 \
124 \
125 \ driver test : MCLK=24MHz, PL2303CG with shortened cable (20cm), WIFI off, all windows apps closed else Scite and TERATERM.
126 \ -----------                                                                                    .
127 \                                                                                               .         ┌────────────────────────────────┐
128 \     notebook                                  USB to I2C bridge                              +-- I2C -->| up to 112 I2C_FASTFORTH targets|
129 \ ┌───────────────┐          ╔════════════════════════════════════════════════════════════╗   /         ┌───────────────────────────────┐  |
130 \ |   WINDOWS 10  |          ║ PL2303GC/HXD/TA               launchpad running UARTI2CS   ║  +-- I2C -->|    MSP430FR4133 @ 1 MHz       |  |
131 \ |               |          ║───────────────┐           ┌────────────────────────────────║ /        ┌───────────────────────────────┐  |──┘
132 \ |               |          ║               |  3 wires  |    MSP430FR2355 @ 24MHz        ║/         |    MSP430FR5738 @ 24 MHz      |  |
133 \ |   TERATERM   -o--> USB --o--> USB2UART --o--> UART --o--> FASTFORTH  +  UARTI2CS    --o--> I2C --o-->     I2C_FASTFORTH          |──┘
134 \ |   terminal    |          ║               |   6 MBds  |     (software I2C MASTER)      ║          |     (hardware I2C SLAVE)      | 
135 \ |               |          ║───────────────┘           └────────────────────────────────║          └───────────────────────────────┘
136 \ |               |          ║               |<- l=20cm->|                                ║<-l=20cm->| 
137 \ └───────────────┘          ╚════════════════════════════════════════════════════════════╝              
138 \                                                                       |_|
139 \ test results :                                                        RST
140 \ ------------
141 \
142 \ Full duplex downloading (+ interpret + compile + execute) CORETEST.4TH to I2C Master target = 625ms/732kBds.
143 \ Full duplex downloading (+ interpret + compile + execute) CORETEST.4TH to I2C Slave target = 1047ms/431kBds.
144 \ the difference (422 ms) is the effective time of the I2C Half duplex exchange.
145 \ [(9 bits / char) + ( 2*START + 2*addr + 1 CTRL_Char + 1 STOP / line )] = [(45763 chars * 9 bits) + (1538 lines * 30 bits)] / 0,422 = 1,085 MHz
146 \ ==> I2C effective rate = 109 % of I2C Fast-mode Plus (Fm+).
147
148 \ also connected to and tested with another I2C_FastForth target with MCLK = 1MHz (I2C CLK > MCLK !).
149 \
150 \ The I2C_Slave address is defined as 'MYSLAVEADR' in forthMSP430FR.asm source file for the I2C_Slave target.
151 \ You can use any pin for SDA and SCL, preferably in the interval Px0...Px3.  
152 \ don't forget to add 3.3k (maxi) pullup resitors on wires SDA and SCL.
153 \
154 \ the LEDs TX and RX work fine, comment/uncomment as you want.
155 \
156 \ Multi Master Mode works but is not tested in the real word.
157 \
158 \
159 \ ================================================================================
160 \ REGISTERS USAGE for embedded MSP430 ASSEMBLER  
161 \ ================================================================================
162 \ don't use R2, R3,
163 \ R4, R5, R6, R7 must be PUSHed/POPed before/after use
164 \ scratch registers S,T,W,X and Y are free,
165 \ in interrupt routines, IP is free,
166 \ Apply FORTH rules for TOS, PSP, RSP registers.
167 \
168 \ PUSHM order : PSP,TOS, IP, S , T , W , X , Y ,rDOVAR,rDOCON,rDODOES,rDOCOL, R3, SR,RSP, PC
169 \ PUSHM order : R15,R14,R13,R12,R11,R10, R9, R8,  R7  ,  R6  ,  R5   ,  R4  , R3, R2, R1, R0
170 \
171 \ example : PUSHM #6,IP pushes IP,S,T,W,X,Y registers to return stack, with IP first pushed
172 \
173 \ POPM  order :  PC,RSP, SR, R3, rDODOES,rDOCON,rDOVAR,rEXIT,  Y,  X,  W,  T,  S, IP,TOS,PSP
174 \ POPM  order :  R0, R1, R2, R3,   R4   ,  R5  ,  R6  ,  R7 , R8, R9,R10,R11,R12,R13,R14,R15
175 \
176 \ example : POPM #6,IP   pop Y,X,W,T,S,IP registers from return stack, with IP last poped
177 \
178 \ ASSEMBLER conditionnal usage before IF UNTIL WHILE : S< S>= U< U>= 0= 0<> 0>=
179 \ ASSEMBLER conditionnal usage before          ?GOTO : S< S>= U< U>= 0= 0<> 0< 
180
181 \ first, we do some tests allowing the download
182     CODE ABORT_UARTI2CS     \
183     SUB #4,PSP
184     MOV TOS,2(PSP)
185     MOV &KERNEL_ADDON,TOS
186     BIT #$3C00,TOS          \ BIT13|BIT12|BIT11|BIT10 test (UART TERMINAL test)
187     0<> IF MOV #0,TOS THEN  \ if TOS <> 0 (UART TERMINAL), set TOS = 0
188     MOV TOS,0(PSP)
189     MOV &VERSION,TOS
190     SUB #400,TOS            \ FastForth V4.0
191     COLON                   \ ASSEMBLER switch to FORTH with IP backup
192     $0D EMIT                \ return to column 1 without CR
193     ABORT" FastForth V4.0 please!"
194     ABORT" <-- Ouch! unexpected I2C_FastForth target!"
195     RST_RET                 \ remove the ABORT_UARTI2CS definition before continuing the download.
196     ;
197
198     ABORT_UARTI2CS          \ run tests
199
200 \ here is a MARKER definition, used to free the program memory including it, and restoring previous hardware context if any.
201
202     MARKER {UARTI2CS}   \ the command : ' <MARKER_definition>, leaves USER_PARAM address on the stack.
203 \                         &{UARTI2CS}-2   = USER_DOES     <-- #REMOVE_U2I addr, the subroutine used to restore the low level environment below:
204     16 ALLOT            \ &{UARTI2CS}     = USER_PARAM    <-- previous &STOP_APP addr
205                         \ &{UARTI2CS}+2   = USER_PARAM+2  <-- previous &HARD_APP addr
206 \                         &{UARTI2CS}+4   = USER_PARAM+4  <-- previous &BACKGRND_APP addr
207 \                         &{UARTI2CS}+6   = USER_PARAM+6  <-- previous &TERM_VEC addr
208 \                         &{UARTI2CS}+8   = USER_PARAM+8  <-- previous &Px_VEC addr
209 \ local variables :       UARTI2CS_ADR=\{UARTI2CS\}\+10;  <-- I2C_Slave_Addr<<1
210 \                         TIMER_CONF=\{UARTI2CS\}\+12     <-- TIM_CTL configuration
211 \                         COLLISION_DLY=\{UARTI2CS\}\+14; <-- 20 us resolution delay after I2C collision
212 \                         DUPLEX_MODE=\{UARTI2CS\}\+15;   <-- flag = 4 --> NOECHO, <> 4 --> ECHO, -1 = I2C link lost
213 \ USER_PARAMS[-2...+16[ are initialised by START_U2I and USER_PARAMS[-2...+10[ are restored by REMOVE_U2I.
214
215 \ =========================================================================
216     CODE LEDS MOV @IP+,PC ENDCODE \ comment this line to remove LEDS option
217 \ =========================================================================
218
219 \ -----------------------------------------------------------------------
220 \ first we download the set of definitions we need (copied from CORE_ANS)
221 \ -----------------------------------------------------------------------
222 \
223     [UNDEFINED] = [IF]
224 \ https://forth-standard.org/standard/core/Equal
225 \ =      x1 x2 -- flag         test x1=x2
226     CODE =
227     SUB @PSP+,TOS   \ 2
228     SUB #1,TOS      \ 1 borrow if TOS was 0
229     SUBC TOS,TOS    \ 1 TOS=-1 if borrow was set
230     MOV @IP+,PC
231     ENDCODE
232     [THEN]
233
234     [UNDEFINED] + [IF]  \ for [ABORT, (GEMA pattern)
235 \ https://forth-standard.org/standard/core/Plus
236 \ +       n1/u1 n2/u2 -- n3/u3     add n1+n2
237     CODE +
238     ADD @PSP+,TOS
239     MOV @IP+,PC
240     ENDCODE
241     [THEN]
242
243 \ -----------------------------
244 \ end of definitions we need...
245 \ -----------------------------
246 \
247     [UNDEFINED] TSTBIT [IF]
248     CODE TSTBIT         \ addr bit_mask -- true/flase flag
249     MOV @PSP+,X
250     AND @X,TOS
251     MOV @IP+,PC
252     ENDCODE
253     [THEN]
254
255 \ see symbolic values in ..\inc\launchpad.pat or/and in ..\inc\device.pat
256 \ note: HDNCODE definitions are HiDdeN and cannot be called from TERMINAL
257 \   ------------------------------------\
258     HDNCODE I2CM_STOP                   \ sends a STOP on I2C_BUS
259 \   ------------------------------------\     _
260     BIS.B #SM_SCL,&I2CSM_DIR            \ 3 h  v_   force SCL as output (low)
261     NOP3                                \ 3 l _
262     BIS.B #SM_SDA,&I2CSM_DIR            \ 3 l  v_   SDA as output ==> SDA low
263     NOP3                                \ 3 l   _
264     BIC.B #SM_SCL,&I2CSM_DIR            \ 3 l _^    release SCL (high)
265     NOP3                                \ 3 h   _
266     BIC.B #SM_SDA,&I2CSM_DIR            \ 3 h _^    relase SDA (high) when SCL is high = STOP
267     MOV @RSP+,PC                        \ 4
268     ENDCODE                             \
269 \   ------------------------------------\
270
271 \   ------------------------------------\
272     HDNCODE REMOVE_U2I                  \   REMOVE_APP subroutine 
273 \   ------------------------------------\
274 BW1                                     \ <-- WARM <-- INIT_FORTH <-- SYS_failures|RESET 
275 \   ------------------------------------\
276     [DEFINED] LEDS [IF]
277     BIC.B #LED1,&LED1_OUT               \ set TX red led OFF
278     BIC.B #LED1,&LED1_DIR               \ set TX red led pin as input
279     BIC.B #LED2,&LED2_OUT               \ set RX green led OFF
280     BIC.B #LED2,&LED2_DIR               \ set RX green led pin as input
281     [THEN]
282     CALL #I2CM_STOP                     \ stop properly I2C_BUS
283     BIS.B #SM_BUS,&I2CSM_OUT            \ restore I2C_BUS I/O
284     BIS.B #SM_BUS,&I2CSM_REN            \ with pull up resistors
285 \   ------------------------------------\
286     MOV #0,&TIM_CTL                     \ stop timer
287     BIC.B #T_OUT2,&T_OUT2_SEL           \ clear T_OUT2 SEL
288     BIC.B #T_OUT2,&T_OUT2_DIR           \ set T_OUT2 as input
289     BIC.B #INT_IN,&INT_IN_IE            \ clear INT_IN IE
290 \   ------------------------------------\
291     CMP #RET_ADR,&{UARTI2CS}-2          \
292     0<> IF                              \ restore USER_PARAMS[-2...+10[
293         MOV #{UARTI2CS},W               \ W = addr of first user parameter following MARKER
294         MOV #RET_ADR,-2(W)              \ don't forget: restore default USER_DOES call address !
295         MOV @W+,&STOP_APP               \ restore previous (default) STOP_APP value
296         MOV @W+,&HARD_APP               \ restore previous (default) HARD_APP value
297         MOV @W+,&BACKGRND_APP           \ restore previous (default) BACKGRND_APP value
298         MOV @W+,&TERM_VEC               \ restore previous (default) TERM_VEC value
299         MOV @W+,&INT_IN_VEC             \ restore previous (default) INT_IN_VEC value
300     THEN                                \
301 \   ------------------------------------\
302     MOV @RSP+,PC                        \ --> WARM --> previous_HARD_APP --> display I2C_address + WARM message --> FORTH interpreter
303     ENDCODE                             \
304 \   ------------------------------------\
305
306 \   ------------------------------------\
307     HDNCODE STOP_U2I                    \ new STOP_APP subroutine, defined for the example, not used.
308 \   ------------------------------------\
309     CALL #I2CM_STOP                     \ send I2C STOP
310     MOV &{UARTI2CS},PC                  \ run previous STOP_APP then RET
311     ENDCODE                             \
312 \   ------------------------------------\
313
314 \   ------------------------------------\
315     HDNCODE BACKGRND_U2I                \       new BACKGRND_APP subroutine, RET to LPM0 shut down.
316 \   ------------------------------------\
317 \   user request test                   \
318 \   ------------------------------------\
319     BIT #8,&TERM_STATW                  \ 3     break sent by TERATERM (Alt+B) ?
320     0<> IF
321         MOV #WARM_IP_ADR,0(RSP)         \       replace BACKGRND_U2I return by INIT_FORTH followed by WARM 
322         PUSH #INIT_FORTH                \
323 \   ------------------------------------\
324 BW2     MOV #1,TOS                      \       to identify manual request to REMOVE_U2I
325         GOTO BW1                        \ 2
326     THEN
327 \   ------------------------------------\
328     BIC.B #INT_IN,&INT_IN_IFG           \ 4     clear INT_IN IFG
329     MOV #'CR',S                         \ 2     S = 'CR' = penultimate char of line to be RXed by UART
330     MOV #0,T                            \ 2     T = init buffer pointer for UART_TERMINAL input
331     MOV.B &DUPLEX_MODE,Y                \ 3     Y = 4 ==> NOECHO else ECHO, for U2I_TERM_INT and 500MS_INT use
332     MOV &{UARTI2CS}+4,PC                \ 3     previous BACKGRND_APP executes RXON, enabling TERMINAL TX, then RET to LPM0 shut down.
333     ENDCODE                             \
334 \   ------------------------------------\
335
336 \   ------------------------------------\
337     HDNCODE HARD_U2I                    \ new HARD_APP subroutine, RETurn redirected to ABORT --> ACCEPT --> BACKGRND
338 \   ------------------------------------\
339 \   init 500MS_INT                      \ used to scan I2C_Slave hard RESET and to slow down (re)START RX loop
340 \   ------------------------------------\
341 BW3 MOV &TIMER_CONF,&TIM_CTL            \ start RX_timer, up mode
342     MOV #4096,&TIM_CCR0                 \ time  0.5s
343 \   ------------------------------------\
344 \   set TB0.2 to generate 500ms int     \
345 \   ------------------------------------\
346     MOV #$60,&TIM_CCTL2                 \ output mode = set/reset           )
347     MOV #4096,&TIM_CCR2                 \ one cycle pulse to set P1.6IFG    )
348     BIS.B #T_OUT2,&T_OUT2_DIR           \ P1.7 as output                    >  (MSP-EXP430FR2355 values, to custom for your launchpad)
349     BIS.B #T_OUT2,&T_OUT2_SEL           \ P1.7 as TB0.2 output              )
350     BIS.B #INT_IN,&INT_IN_IE            \ P1.6IE                            )
351 \   ------------------------------------\
352 \   init I2C_MASTER I/O                 \
353 \   ------------------------------------\
354     BIC.B #SM_BUS,&I2CSM_REN            \ remove internal pull up resistors because the next instruction which change them to pull down resistors
355     BIC.B #SM_BUS,&I2CSM_OUT            \ preset SDA + SCL output LOW
356     BIC.B #SM_BUS,&I2CSM_IES            \ set IES for SDA_IFG and SCL_IFG on low_to_high transition, for detection collision.
357     [DEFINED] LEDS [IF]
358     BIS.B #LED1,&LED1_DIR               \ set red led (I2C TX) pin as output
359     BIS.B #LED2,&LED2_DIR               \ set green led (I2C RX) pin as output
360     [THEN]
361 \   ------------------------------------\
362 \   run previous HARD_APP               \
363 \   ------------------------------------\
364     CALL &{UARTI2CS}+2                  \       execute previous HARD_APP to init TERM_UC, activates I/O.
365 \   ------------------------------------\       TOS = USERSYS=$00|SYSRSTIV=$02|$04|$0E|$xx as UARTI2CS|POWER_ON|RST|SVSH_threshold|SYS_failures 
366 \   define new SYSRSTIV select          \
367 \   ------------------------------------\
368     CMP #6,TOS                          \       SYSRSTIV = RESET ?
369     0= ?GOTO BW2                        \       if yes goto REMOVE_U2I with TOS = 1, return to WARM
370     CMP #$0E,TOS                        \       SVSHIFG SVSH event = #14 ? (POWER_ON)
371     0<> IF                              \       if not
372         CMP #$0A,TOS                    \           SYSRSTIV >= violation memory protected areas ?
373         U>= ?GOTO BW1                   \       if yes goto REMOVE_U2I, return to WARM
374     THEN                                \
375 \   ------------------------------------\
376     MOV #ABORT,0(RSP)                   \       replace WARM return by ABORT return
377     MOV @RSP+,PC                        \       --> ABORT --> ACCCEPT --> BACKGRND --> LPM4
378     ENDCODE                             \
379 \   ------------------------------------\
380
381 \   ----------------------------------------\
382     HDNCODE I2CM_START                      \           I2C_Master START and TX Address, version with collision detection and resolution
383 \   ----------------------------------------\     _
384     BIS.B   #SM_SDA,&I2CSM_DIR              \ 3    v_   force SDA as output (low)
385     BIS     &UARTI2CS_ADR,X                 \ 3   _     X = (Slave_Address<<1 | R/w bit)
386     BIS.B   #SM_SCL,&I2CSM_DIR              \ 3    v_   force SCL as output (low)
387 \   ----------------------------------------\
388 \   I2C_Master Send I2C Addr                \
389 \   ----------------------------------------\
390     MOV.B #8,W                              \ 1 l       count for 7 bits address + R/w bit
391     BEGIN                                   \
392         ADD.B X,X                           \ 1 l       shift one left
393         U< IF                               \ 2 l       carry set ?
394             BIS.B #SM_SDA,&I2CSM_DIR        \ 3 l   _   no  SDA as output ==> SDA low
395             BIC.B #SM_SCL,&I2CSM_DIR        \ 3 l _^        release SCL (high)
396             NOP3                            \ 3 h           for symmetry.
397         ELSE                                \ 2 l       yes we can detect collision only when SDA is driven high 
398             BIC.B #SM_SDA,&I2CSM_DIR        \ 3 l   _       SDA as input  ==> SDA high because pull up resistor
399             BIC.B #SM_SCL,&I2CSM_DIR        \ 3 l _^        release SCL (high)
400             BIT.B #SM_SDA,&I2CSM_IN         \ 3 h           get SDA input
401             0= IF                           \ 2 h
402 \               ----------------------------\
403 \               collision detected          \               if SDA input low, collision detected
404 \               ----------------------------\
405                 BEGIN                       \
406                     BIT #TX,&TERM_IFG       \ 3
407                 0<> UNTIL                   \ 2
408                 MOV.B #'c',&TERM_TXBUF      \ 3             send 'c' to TERMINAL to show collision
409 \               ----------------------------\
410 \               collision resolution        \
411 \               ----------------------------\
412                 BEGIN                       \               wait until SDA high
413                     BIT.B #SM_SDA,&I2CSM_IN \ 3 h
414                 0<> UNTIL                   \ 2
415 \               ----------------------------\
416                 BEGIN                       \               wait for 20us bus idle time
417                   BIC.B #SM_BUS,&I2CSM_IFG  \ 4                 clear SM_BUS IFG
418                   NOP3                      \ 3
419                   MOV.B &COLLISION_DLY,W    \ 3                 load delay value 
420                   BEGIN                     \
421                     NOP                     \ 1
422                     SUB #1,W                \ 1
423                   0= UNTIL                  \ 2               4~ x (delay value)
424                   BIT.B #SM_BUS,&I2CSM_IFG  \ 4
425                 0= UNTIL                    \ 2             + 16~ dead time for the remainder of idle time
426 \               ----------------------------\
427                 ADD #2,RSP                  \ 1             remove the RET for Nack/Ack processing and select..
428                 MOV @RSP,PC                 \ 4 h           ...RET to ReStart after a collision detection with preserving this RET address on RSP
429 \               ----------------------------\
430             THEN                            \
431         THEN                                \     _   
432         BIS.B #SM_SCL,&I2CSM_DIR            \ 3 h  v_   SCL as output : force SCL low
433         SUB #1,W                            \ 1 l       bits count-1
434     0= UNTIL                                \ 2 l       20 * 8 cycles
435 \   ----------------------------------------\
436 \   I2C_Master get Slave Ack/Nack on address\
437 \   ----------------------------------------\       _
438     BIC.B #SM_SDA,&I2CSM_DIR                \ 3 l _^_   after TX address we must release SDA to read Ack/Nack from Slave
439     BIC.B #SM_SCL,&I2CSM_DIR                \ 3 l _^    release SCL (high)
440     BEGIN                                   \           we must wait I2C_Slave software
441         BIT.B #SM_SCL,&I2CSM_IN             \ 3 h       by testing SCL released
442     0<> UNTIL                               \ 2 h       because Slave can strech SCL low (may be occupied)
443     BIT.B #SM_SDA,&I2CSM_IN                 \ 3 h _     get SDA state: flag Z = 0 if Nack
444     BIS.B #SM_SCL,&I2CSM_DIR                \ 3 h  v_   SCL as output : force SCL low
445 \   ----------------------------------------\
446     MOV @RSP+,0(RSP)                        \ 4         remove RET to (ReStart after a collision detection)
447     MOV @RSP+,PC                            \ 4         RET to RX|RX datas
448     ENDCODE                                 \           195 cycles
449 \   ----------------------------------------\
450
451 \   ****************************************\
452     HDNCODE U2I_TERM_INT                    \ UART RX interrupt starts on first char of each line sent by TERMINAL
453 \   ****************************************\ 
454     ADD #4,RSP                              \ 1 remove unused SR_RET, and remove PC_RET because we want include BACKGRND_U2I as end of U2I_TERM_INT routine
455 \   ----------------------------------------\
456 \   get one line from UART TERMINAL to PAD  \ S = 'CR', T = 0, W = char, Y = ECHO/NOECHO flag (see U2I_BACKGRND)
457 \   ----------------------------------------\
458     BEGIN                                   \ input buffer begins at PAD-2, able to receive CIB_LEN = 84 chars, plus CR+LF !!!
459         MOV.B &TERM_RXBUF,W                 \ 3
460         ADD #1,T                            \ 1
461         CMP.B S,W                           \ 1 char = CR ? (if yes goto next REPEAT)
462     0<> WHILE                               \ 2 while <> CR
463         CMP #CIB_LEN+1,T                    \ 2
464         U< IF                               \ 2 discard chars out of PAD-2 + CIB_LEN bound
465             MOV.B W,PAD_ORG-3(T)            \ 3 write char to input buffer, PAD-2 first
466         THEN
467         CMP.B #4,Y                          \ 1 echo OFF ?
468         0<> IF                              \ 2 if echo is ON
469             BEGIN                           \   )
470                 BIT #TX,&TERM_IFG           \ 3 > Test TX_Buf empty, mandatory for low baudrates
471             0<> UNTIL                       \ 2 )
472             MOV.B W,&TERM_TXBUF             \ 3 return all characters to UART_TERMINAL except CR+LF which will be sent later by I2C_SLAVE
473         THEN                                \
474         BEGIN                               \ 
475             BIT #RX,&TERM_IFG               \ 3 wait for next char received
476         0<> UNTIL                           \ 2 
477     REPEAT                                  \ 2 32 cycles loop ==> up to UART 2.5 Mbds @ 8MHz
478     CALL #UART_RXOFF                        \ stops UART RX still char CR is received, the LF char is being transmitted.
479     MOV.B W,PAD_ORG-3(T)                    \ move CR in buffer
480     BEGIN                                   \
481         BIT #RX,&TERM_IFG                   \ 3 char LF received ?
482     0<> UNTIL                               \ 2
483 \   ----------------------------------------\
484 BW2 \ here, BW2 is redefined                \   <=== KEY input from TERMINAL, via I2C_MASTER
485 \   ----------------------------------------\
486     MOV.B &TERM_RXBUF,S                     \           S = last char RXed by UART (LF|KEY_input), used by I2C_MASTER_TX as last byte to be TXed.         
487     MOV.B S,PAD_ORG-2(T)                    \ 3
488 \   ========================================\ here I2C_Slave is sleeping in its ACCEPT routine
489 \   I2C_MASTER TX                           \ now we transmit UART RX buffer (PAD) to I2C_Slave, S = LF|KEY = last char to transmit
490 \   ========================================\          
491     PUSH PC                                 \           PUSH next address as RET for reSTART after collision detection
492 \   ----------------------------------------\
493 \   I2C Master TX Start                     \ S = last char UART RXed
494 \   ----------------------------------------\
495     MOV #0,X                                \ 1         to Start I2C TX
496     CALL #I2CM_START                        \ 4         flag Z = 0 if Nack_On_Address
497     0<> ?GOTO FW2                           \           if Nack on address ───────────────┐
498 \   ========================================\                                             |
499 \   I2C MASTER TX datas                     \                                             |
500 \   ========================================\                                             |
501     [DEFINED] LEDS [IF]                     \                                             |
502     BIS.B #LED1,&LED1_OUT                   \           red led ON = I2C TX               |
503     [THEN]                                  \                                             |
504 \   ----------------------------------------\                                             |
505     MOV #PAD_ORG-2,T                        \ 2         Y = buffer pointer, PAD-2 first   |
506     BEGIN                                   \                                             |
507         MOV.B @T,X                          \ 2 l       get first char to be TX           |
508 \       ------------------------------------\                                             v
509 \       I2C_Master TX 7 bits of Data        \
510 \       ------------------------------------\
511         MOV.B #7,W                          \ 2 l       count for 7 data bits
512         BEGIN                               \
513             ADD.B X,X                       \ 1 l       shift one left
514             U>= IF                          \ 2 l       carry set ?
515                 BIC.B #SM_SDA,&I2CSM_DIR    \ 3 l       yes : SDA as input  ==> SDA high because pull up resistor
516             ELSE                            \ 2 l
517                 BIS.B #SM_SDA,&I2CSM_DIR    \ 3 l       no: SDA as output ==> SDA low
518             NOP2                            \ 2 l           for symmetry  
519             THEN                            \   l   _
520             BIC.B #SM_SCL,&I2CSM_DIR        \ 3 l _^    release SCL (high)
521 \           --------------------------------\
522             NOP3                            \ 3 h
523 \           --------------------------------\     _
524             BIS.B #SM_SCL,&I2CSM_DIR        \ 3 h  v_   SCL as output : force SCL low
525             SUB #1,W                        \ 1 l       bits count-1
526         0= UNTIL                            \ 2 l
527 \       ------------------------------------\
528 \       I2C_Master TX 8th bit of Data       \
529 \       ------------------------------------\
530         ADD.B X,X                           \ 1 l       shift one left
531         U>= IF                              \ 2 l       carry set ?
532             BIC.B #SM_SDA,&I2CSM_DIR        \ 3 l       yes : SDA as input  ==> SDA high because pull up resistor
533         ELSE                                \ 2 l
534             BIS.B #SM_SDA,&I2CSM_DIR        \ 3 l       no: SDA as output ==> SDA low 
535             NOP2                            \ 2 l           for symmetry  
536         THEN                                \   l   _
537         BIC.B #SM_SCL,&I2CSM_DIR            \ 3 l _^    release SCL (high)
538 \       ------------------------------------\
539         BEGIN                               \           here, (last bit of TX data), I2C_Slave streches SCL low until its RX_BUF is read,
540             BIT.B #SM_SCL,&I2CSM_IN         \ 3 h       that is not documented in any MSP430FRxxx family user's guide...
541         0<> UNTIL                           \ 2 h
542 \       ------------------------------------\     _
543         BIS.B #SM_SCL,&I2CSM_DIR            \ 3 h  v_   SCL as output : force SCL low
544 \       ------------------------------------\
545 \       I2C_Master_TX get Slave Ack/Nack    \
546 \       ------------------------------------\
547         BIC.B #SM_SDA,&I2CSM_DIR            \ 3 l   _   after TX byte we must release SDA to read Ack/Nack from Slave
548         BIC.B #SM_SCL,&I2CSM_DIR            \ 3 l _^    release SCL (high)
549         NOP3                                \           here, I2C_Slave doesn't strech SCL low, as suggested in TI's documentation...
550         BIT.B #SM_SDA,&I2CSM_IN             \ 3 h _     get SDA state
551         BIS.B #SM_SCL,&I2CSM_DIR            \ 3 h  v_   SCL as output : force SCL low, to keep I2C_BUS until next START (RX|TX)
552 \   ----------------------------------------\
553     0= WHILE \ 1- Slave Ack received        \ 2 l       out of loop if Nack on data (goto next THEN)
554 \   ----------------------------------------\
555 \   I2C_Master TX Data Loop                 \
556 \   ----------------------------------------\
557         CMP.B @T+,S                         \ 2 l       last char I2C TXed = last char UART RXed (LF|KEY) ?
558 \   ----------------------------------------\
559     0= UNTIL  \ TXed char = last char       \ 2 l       loop back if <> 0
560 \   ----------------------------------------\
561     THEN                                    \           <-- WHILE1 case of I2C_Slave Nack on Master_TX data
562 \   ========================================\
563 \   END OF I2C MASTER TX datas              \
564 \   ========================================\
565     [DEFINED] LEDS [IF]
566     BIC.B #LED1,&LED1_OUT                   \   red led OFF = endof I2C TX
567     [THEN]
568 \   ----------------------------------------\
569     GOTO FW1                                \   SCL is kept low   ──────┐
570     ENDCODE                                 \                           |
571 \   ****************************************\                           v
572
573 \ wakes up every 1/2s by P1.6 int to listen I2C Slave or 
574 \ break from TERMINAL/USB_to_I2C_bridge.
575 \   ****************************************\                           |                 |
576     HDNCODE 500MS_INT                       \                           |                 |
577 \   ****************************************\                           |                 |
578     ADD #4,RSP                              \ 1 remove PC_RET, SR_RET   |                 |
579 \   ----------------------------------------\                           |                 |    
580 FW1 \ single use forward label              \ <──────── does START <────┘                 |
581 FW2 \ single use forward label              \ <──────── if Nack on Address Master TX <────┘
582 \   ========================================\
583 \   I2C_MASTER RX                           \
584 \   ========================================\
585     PUSH PC                                 \ 3 l       PUSH next address as RET for reSTART after collision detection
586 \   ----------------------------------------\   
587     BEGIN                                   \           Start MASTER RX
588 \       ------------------------------------\
589 \       I2C MASTER (re)START RX             \
590 \       ------------------------------------\       _
591         BIC.B #SM_SCL,&I2CSM_DIR            \ 3 l _^    release SCL to enable START RX
592         MOV #1,X                            \ 1 h       to Start MASTER RX
593         CALL #I2CM_START                    \ 199~      flag Z = 0 if Nack_On_Address
594 \       ------------------------------------\
595         0<> IF                              \ 2 l           if Nack on address
596             CALL #I2CM_STOP                 \ 28~           generate STOP
597             MOV.B #'.',&TERM_TXBUF          \ 4             to view the lack of I2C_target at the I2C_Addr provided.
598             MOV.B #-1,&DUPLEX_MODE          \ 3             set 'no_I2C_Slave' flag
599             MOV #BACKGRND,PC                \ 29~           which calls BACKGRND_U2I then RXON before LPM0 shut down.
600         THEN                                \               (275 cycles for 500MS_INT)
601         CMP.B #-1,Y                         \ 1 l           return of I2C_Slave on bus ?
602         0= IF                               \ 2 l           if yes
603             MOV.B #0,Y                      \                   clear 'no_I2C_Slave' flag, ECHO is ON
604             MOV.B #'CR',&TERM_TXBUF         \                   send CR+LF to terminal
605             BEGIN                           \
606                 BIT #TX,&TERM_IFG           \
607             0<> UNTIL                       \
608             MOV.B #'LF',&TERM_TXBUF         \
609         THEN                                \
610 \       ====================================\
611 \       I2C Master RX data                  \
612 \       ====================================\
613         [DEFINED] LEDS [IF]
614         BIS.B #LED2,&LED2_OUT               \ 3 l       green led ON = I2C RX
615         [THEN]
616 \       ------------------------------------\
617         BEGIN                               \   l
618             BEGIN                           \   l
619                 BIC.B #SM_SDA,&I2CSM_DIR    \ 4 l       after Ack and before RX next byte, we must release SDA
620                 MOV.B #8,W                  \ 2 l       count for 8 data bits
621                 BEGIN                       \       _      
622                   BIC.B #SM_SCL,&I2CSM_DIR  \ 3 l _^    release SCL (high)
623                   BIT.B #SM_SDA,&I2CSM_IN   \ 3 h _     get SDA
624                   BIS.B #SM_SCL,&I2CSM_DIR  \ 3 h  v_   SCL as output : force SCL low   13~
625                   ADDC.B X,X                \ 1 l       C <--- X(7) ... X(0) <--- SDA
626                   SUB #1,W                  \ 1 l       count down of bits
627                 0= UNTIL                    \ 2 l
628 \               ----------------------------\
629 \               case of RX data $FF         \               case of -1 SYS for example
630 \               ----------------------------\
631                 CMP.B #-1,X                 \ 1 l       received char $FF ? let's consider that the slave is lost...
632             0<> WHILE                       \ 2 l
633 \               ----------------------------\
634                 CMP.B #8,X                  \ 1 l       $08 = char BS
635             U>= WHILE                       \ 2 l       ASCII char received, from char 'BS' up to char $FE.
636 \               ----------------------------\
637 \               I2C_Master_RX Send Ack      \           on char {$08...$FE}
638 \               ----------------------------\ 
639                 BIS.B #SM_SDA,&I2CSM_DIR    \ 3 l   _   set SDA low to do Ack
640                 BIC.B #SM_SCL,&I2CSM_DIR    \ 3 l _^    release SCL (high)
641                 BEGIN                       \           we must wait I2C_Slave software (data processing)
642                     BIT.B #SM_SCL,&I2CSM_IN \ 3 h       by testing SCL released,
643                 0<> UNTIL                   \ 2 h _
644                 BIS.B #SM_SCL,&I2CSM_DIR    \ 3 h  v_   SCL as output : force SCL low
645 \               ----------------------------\
646 \               I2C_Master echo to TERMINAL \
647 \               ----------------------------\
648                 CMP.B #4,Y                  \ 1         $04 = NOECHO request
649                 0<> IF                      \ 2
650                     BEGIN                   \
651                         BIT #TX,&TERM_IFG   \ 3 l       UART TX buffer empty ?
652                     0<> UNTIL               \ 2 l       loop if no
653                     MOV.B X,&TERM_TXBUF     \ 3 l       send RXed char to UART TERMINAL
654                 THEN                        \
655             REPEAT                          \ 2 l       loop back to RX data
656 \           --------------------------------\
657 \           case of RX CTRL_Char {$00...$07}\           here Master holds SCL low, Slave can test it: CMP #8,&TERM_STATW
658 \           --------------------------------\           see forthMSP430FR_TERM_I2C.asm
659                 CMP.B #4,X                  \ 1         
660                 U>= IF                      \ 2
661                    MOV.B X,Y                \           NOECHO = $04, ECHO = {$05...$07}
662                    BIS.B #SM_SDA,&I2CSM_DIR \ 3 l       prepare SDA low = Ack for Ctrl_Chars {$04...$07}
663                 THEN                        \
664 \           --------------------------------\
665             THEN                            \           false branch of CMP.B #-1,X 0<> WHILE 
666 \           --------------------------------\
667 \           Master_RX send Ack/Nack on data \           Ack for {$04...$07,$08...$FE}, Nack for {$FF...$03}
668 \           --------------------------------\       _
669             BIC.B #SM_SCL,&I2CSM_DIR        \ 3 l _^    release SCL (high)
670             BEGIN                           \           we must wait I2C_Slave software (data processing)
671                 BIT.B #SM_SCL,&I2CSM_IN     \ 3 h       by testing SCL released
672             0<> UNTIL                       \ 2 h       (because Slave may strech SCL low)
673             BIT.B #SM_SDA,&I2CSM_IN         \ 3 h _     get SDA as TX Ack/Nack state
674             BIS.B #SM_SCL,&I2CSM_DIR        \ 3 h  v_   SCL as output : force SCL low
675 \           --------------------------------\    
676         0<> UNTIL                           \ 2 l       if Ack, loop back to Master_RX data after CTRL_Chars {$04...$07,$08...$FE}
677 \       ------------------------------------\   
678 \       Nack is sent by Master              \           case of CTRL-Chars {$FF...$03}, SDA is high, SCL is low 
679 \       ------------------------------------\   
680         CMP.B #2,X                          \
681     U>= WHILE                               \   l       out of loop for CTRL_chars {$00,$01}
682 \       ------------------------------------\   
683 \       CTRL_Char {$02,$03,$FF}             \           only CTRL_Char $FF is used
684 \       ------------------------------------\
685         MOV.B #0,Y                          \           set echo ON
686         CALL #UART_RXON                     \               resume UART downloading source file
687         BEGIN                               \   
688             BIC #RX,&TERM_IFG               \               clear UCRXIFG
689             MOV &FREQ_KHZ,X                 \               1000, 2000, 4000, 8000, 16000, 240000
690            BEGIN MOV #65,W                  \               2~        <-------+ wait time for TERMINAL to refill its USB buffer
691                BEGIN SUB #1,W               \               1~        <---+   | ==> ((65*3)+5)*FREQ_KHZ/1000 = 200ms delay
692                0= UNTIL                     \               2~ 3~ loop ---+   |
693                SUB #1,X                     \               1~                |
694            0= UNTIL                         \               2~ 200~ loop -----+
695             BIT #RX,&TERM_IFG               \               4 new char in TERMRXBUF during this delay ?
696         0= UNTIL                            \               2 yes, the input stream is still active: loop back
697     REPEAT                                  \   l       loop back to reSTART RX on WARM|ABORT messages.
698 \   ----------------------------------------\
699 \   I2C_Master_RX Send STOP                 \           remainder: CTRL_Chars {$00,$01}
700 \   ----------------------------------------\ 
701     CALL #I2CM_STOP                         \
702 \   ========================================\
703 \   END OF I2C MASTER RX datas              \   here I2C_bus is freed, CTRL_chars $00|$01 remain to be processed.
704 \   ========================================\
705     [DEFINED] LEDS [IF]
706     BIC.B #LED2,&LED2_OUT                   \ green led OFF = endof I2C RX
707     [THEN]
708 \   ========================================\
709     CMP.B #0,X                              \
710 \   ----------------------------------------\
711 \   I2C_Slave ACCEPT ctrl_char $00          \ case of request by I2C_Slave ACCEPT
712 \   ----------------------------------------\
713     0= IF                                   \
714         MOV.B Y,&DUPLEX_MODE                \ save updated NOECHO flag before RET
715         MOV #BACKGRND,PC                    \ which calls BACKGRND_U2I, RXON enabling TERMINAL TX, then LPM0 shut down.
716     THEN                                    \                             
717 \   ----------------------------------------\
718 \   I2C_Slave KEY ctl_char $01              \ I2C_Slave request for KEY input
719 \   ----------------------------------------\
720     CALL #UART_RXON                         \ enables TERMINAL to TX; use no registers
721     BEGIN                                   \ wait for a char
722         BIT #RX,&TERM_IFG                   \ received char ?
723     0<> UNTIL                               \ 
724     CALL #UART_RXOFF                        \ stops UART RX; use no registers
725     MOV #0,T                                \ ready to store KEY char as last char to be received
726     GOTO BW2                                \ goto the end of UART RX line input
727     ENDCODE                                 \ 
728 \   ****************************************\
729 \
730 \
731 \ ==============================================================================
732 \ Driver UART to I2C to do a bridge USB to I2C_FastForth devices
733 \ ==============================================================================
734 \
735 \ I2C_address<<1  mini = $10, maxi = $EE (I2C-bus specification and user manual V6)
736 \ type on TERMINAL "$12 START_U2I" to link teraterm TERMINAL with FastForth I2C_Slave target at address $12
737
738 \   ------------------------------------\
739     CODE START_U2I                      \ I2C_Addr<<1 --   
740 \   ------------------------------------\
741     SUB #2,PSP                          \               DUP
742     MOV TOS,0(PSP)                      \
743     COLON                               \               ASSEMBLER switch to FORTH with IP backup
744     'CR' EMIT 'LF' EMIT                 \
745     ." Connect to I2C_SLAVE at @"       \
746     . 'BS' EMIT                         \               display number without space after
747      ." , TERATERM(Alt-B) "             \
748     ." or I2C_MASTER(RST) to quit..."   \
749     HI2LO                               \               FORTH switch to ASSEMBLER
750     MOV @RSP+,IP                        \               restore IP
751     BEGIN                               \
752         BIT #1,&TERM_STATW              \               uart busy ?
753     0= UNTIL                            \               wait end of TX last char
754     CMP #RET_ADR,&{UARTI2CS}-2          \               USER_DOES default value ?
755     0= IF                               \               if yes
756         MOV #REMOVE_U2I,&{UARTI2CS}-2   \               USER_DOES of {UARTI2CS} will CALL &{UARTI2CS}-2 = CALL #REMOVE_U2I
757         MOV &STOP_APP,&{UARTI2CS}       \               save STOP_APP value to {UARTI2CS}
758         MOV &HARD_APP,&{UARTI2CS}+2     \               save HARD_APP value to {UARTI2CS}+2
759         MOV &BACKGRND_APP,&{UARTI2CS}+4 \               save BACKGRND_APP value to {UARTI2CS}+4
760         MOV &TERM_VEC,&{UARTI2CS}+6     \               save TERM_VEC value to {UARTI2CS}+6
761         MOV &INT_IN_VEC,&{UARTI2CS}+8   \               save INT_IN_VEC value to {UARTI2CS}+8
762         MOV #STOP_U2I,&STOP_APP         \               set STOP_APP with STOP_U2I addr
763         MOV #HARD_U2I,&HARD_APP         \               set HARD_APP with HARD_U2I addr
764         MOV #BACKGRND_U2I,&BACKGRND_APP \               set BACKGRND_APP with BACKGRND_U2I addr
765         MOV #U2I_TERM_INT,&TERM_VEC     \               set TERM_VEC with U2I_TERM_INT addr
766         MOV #500MS_INT,&INT_IN_VEC      \               set INT_IN_VEC with 500MS_INT addr
767 \       --------------------------------\
768         MOV TOS,&UARTI2CS_ADR           \               save I2C_address<<1 at {UARTI2CS}+10
769         KERNEL_ADDON LF_XTAL TSTBIT     \               test ACLK source before compilation
770         [IF]   MOV #$0194,&TIMER_CONF   \              start RX_timer,ACLK=LFXTAL=32768/4=8192Hz,up mode
771         [ELSE] MOV #$0114,&TIMER_CONF   \              start RX_timer,ACLK=VLO=8kHz, up mode
772         [THEN]                          \
773         FREQ_KHZ @ 24000 =              \               in assembly mode the FORTH interpreter is always active, let's enjoy it...
774         [IF]   MOV #116,&COLLISION_DLY  \               )
775         [ELSE] FREQ_KHZ @ 16000 =       \               )
776           [IF]   MOV #76,&COLLISION_DLY \               > set 20us delay = (delay*MHz/4 -4, and set ECHO (<>4)
777           [ELSE] MOV #36,&COLLISION_DLY \               )
778           [THEN]                        \               )
779         [THEN]                          \
780     THEN                                \
781     MOV #0,TOS                          \ -- 0          to enter in HARD_U2I with 0 SYS
782     GOTO BW3                            \               goto HARD_U2I as new HARD_APP, direct return to ABORT
783     ENDCODE                             \
784 \   ------------------------------------\
785
786 RST_SET ECHO    \ RST_SET defines the new bound of program memory protected against any (positive) SYS event,
787                 \ and so protects the MARKER structure before its use by START_U2I:
788 \
789 #18 START_U2I   \ $12 is the wanted I2C_Slave_Address<<1 to link