1 \ -*- coding: utf-8 -*-
3 \ Fast Forth For Texas Instrument MSP430FRxxxx FRAM devices
4 \ Copyright (C) <2019> <J.M. THOORENS>
6 \ This program is free software: you can redistribute it and/or modify
7 \ it under the terms of the GNU General Public License as published by
8 \ the Free Software Foundation, either version 3 of the License, or
9 \ (at your option) any later version.
11 \ This program is distributed in the hope that it will be useful,
12 \ but WITHOUT ANY WARRANTY\ without even the implied warranty of
13 \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 \ GNU General Public License for more details.
16 \ You should have received a copy of the GNU General Public License
17 \ along with this program. If not, see <http://www.gnu.org/licenses/>.
19 ; ----------------------------------------------------------------------
21 ; ----------------------------------------------------------------------
25 \ MSP_EXP430FR5739 MSP_EXP430FR5969 MSP_EXP430FR5994 MSP_EXP430FR6989
26 \ MSP_EXP430FR4133 (can't use LED1 because wired on UART TX)
27 \ MSP_EXP430FR2433 MSP_EXP430FR2355 CHIPSTICK_FR2433
29 \ software I2C MASTER, you can use any pin for SDA and SCL,
30 \ Preferably use a couple of pins in the interval Px0...Px3.
31 \ don't forget to wire 3.3k pullup resitors on pin SDA and SCL.
33 \ FastForth kernel compilation minimal options:
34 \ TERMINAL3WIRES, TERMINAL4WIRES
35 \ MSP430ASSEMBLER, CONDCOMP
37 \ driver test @ speed maxi: MCLK=24MHz
38 \ ------------------------------------
40 \ notebook USB to I2C_Slave bridge any I2C_slave
41 \ +---------------+ +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +-------------------------------+
42 \ | | i CP2102 master running UARTI2CS @ 24MHz i +-------------------------------+|
43 \ | | +---------------+ +--------------------------------+ +-------------------------------+||
44 \ | | | | | |RX:1.15MHz| |||
45 \ | TERATERM -o--> USB --o--> USB2UART --o--> UART --o--> FAST FORTH ---> UARTI2CS --o--> I2C --o--> FAST FORTH @ 24MHz with ||+
46 \ | terminal | | | 2457600Bds| |TX:692kHz | kernel option TERMINAL_I2C |+
47 \ | | +---------------+ +--------------------------------+ +-------------------------------+
49 \ +---------------+ +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
51 \ I2C frequency = (TX+RX)/2 = 921 kHz @ MCLK=24 MHz, without any error...
52 \ downloading (+ interpret + compile + execute) CORETEST.4TH to I2C Slave in 859ms.
53 \ downloading (+ interpret + compile + execute) CORETEST.4TH to I2C Master in 625ms.
56 \ the LEDs TX and RX work fine, uncomment if you want.
58 \ Multi Master Mode works but is not tested in the real word.
60 \ les arcanes du bus I2C
61 \ ----------------------
63 \ le bus I2C est orienté Maître vers esclave, l'esclave ne décide de rien.
64 \ Cet ordre des choses permet en tout cas d'établir la liaison.
65 \ On placera donc le maître du côté du TERMINAL de commande et la cible FastForth côté esclave.
66 \ Mais une fois que la liaison est établie il faut trouver une astuce pour renverser
67 \ les rôles, pour que l'esclave puisse prendre le contrôle de la liaison.
69 \ Pour ce faire l'esclave envoie "servilement" des caractères de contrôle au maître,
70 \ et comme celui-ci obéit à un plus grand que lui, le programmeur,
71 \ il se fait un devoir "magistral" d'obéir à l'esclave.
73 \ Pour prendre le contrôle du maître, l'esclave émet donc 1 parmi 6 CTRL-Char:
74 \ CTRL-Char $00 envoyé par ACCEPT (1ère partie, avant SLEEP),
75 \ CTRL-Char $01 envoyé par KEY: demande d'envoi d'un caractère unique saisi sur TERMINAL,
76 \ CTRL-Char $02 envoyé par ABORT: demande d'abandon du fichier en cours de transmission le cas échéant,
77 \ suivi de la réception du message envoyé par ABORT,
78 \ CTRL-Char $03 envoyé par COLD, pour que le maître relance la connexion I2C,
79 \ CTRL-Char $04 envoyé par NOECHO, pour qu'il passe l'UART en mode half duplex,
80 \ CTRL-Char $05 envoyé par ECHO, pour qu'il rétablisse l'UART en mode full duplex.
82 \ Enfin, si le maître reçoit un caractère $FF, il considère que la liaison est coupée,
83 \ il envoie le reste du fichier en cours de téléchargment à la poubelle, quitte le driver
86 \ Une fois que l'esclave a envoyé le CTRL_Char $00, il s'endort,
87 \ à la reception de ce CTRL_Char, le maître s'endort aussi, dans l'attente d'une nouvelle entrée TERMINAL.
88 \ Tant que le TERMINAL n'envoie pas de nouvelle ligne, le maître et l'esclave sont en mode SLEEP,
89 \ LPM0 pour le maître, LPM4 pour l'esclave.
92 \ le timer TB0 sert à générer une interruption 1/2 seconde
93 \ pour détecter un hard RESET effectué sur I2C_Slave, quand I2C_Master fait dodo,
94 \ ainsi que pour effectuer le couplage dans la boucle I2C_Master RX:
95 \ si X U>= 4 (I2C_WARM state) ==> un START RX à chaque 1/2s,
96 \ si X U< 4 (I2C_Slave COLD|RESET|ABORT) ==> continuous repeated START RX
100 [DEFINED] {FF_I2C} [IF] {FF_I2C} [THEN]
105 \ https://forth-standard.org/standard/core/Fetch
106 \ @ c-addr -- char fetch char from memory
113 [UNDEFINED] CONSTANT [IF]
114 \ https://forth-standard.org/standard/core/CONSTANT
115 \ CONSTANT <name> n -- define a Forth CONSTANT
119 MOV TOS,-2(W) \ PFA = n
126 $1820 CONSTANT SLAVE_ADR \ CONSTANT = I2C_Slave address in FRAM
128 ASM QUIT_I2C \ as ASM word, QUIT_I2C is hidden.
129 \ ------------------------------\
131 \ \ ------------------------------\
132 \ BIC.B #LED2,&LED2_DIR \ RX green led OFF
133 \ BIC.B #LED2,&LED2_OUT \ RX green led OFF
134 \ BIC.B #LED1,&LED1_DIR \ TX red led OFF
135 \ BIC.B #LED1,&LED1_OUT \ TX red led OFF
136 \ \ ------------------------------\
137 BIS.B #SM_BUS,&I2CSM_REN \ reset I/O as reset state
138 BIC.B #SM_BUS,&I2CSM_DIR \
139 BIS.B #SM_BUS,&I2CSM_OUT \
140 MOV #$5A88,&WDTCTL \ stop WDT
141 BIC #1,&SFRIE1 \ disable WDT int
142 MOV #COLD,&WDT_VEC \ restore default WDT_VEC value
143 \ MOV #0,&TA0CTL \ stop timer
144 \ MOV #COLD,&TA0_x_VEC \ restore default TA0_x_VEC value
145 MOV #0,&TB0CTL \ stop timer
146 MOV #COLD,&TB0_x_VEC \ restore default TB0_x_VEC value
147 MOV &TERMINAL_INT,&TERM_VEC \ restore default TERM_VEC value
148 MOV #WARM,X \ X = CFA of WARM
149 ADD #4,X \ X = BODY of WARM
150 MOV X,-2(X) \ restore default WARM: BODY of WARM --> PFA of WARM
151 MOV #COLD,PC \ explicit return with COLD
154 ASM WDT_INT \ to enable Alt+B when I2C_Master is sleeping
155 BIT #8,&TERM_STATW \ UART break sent by TERATERM ?
157 ADD #4,RSP \ remove RETI
163 \ \ vvvvvvvMulti-Master-Modevvvvvv\
165 \ MOV #4,W \ 1 wait bus idle time = 5 µs @ 16 MHz
167 \ BIT #8,&TERM_STATW \ 3 break sent by TERATERM ?
169 \ ADD #2,RSP \ remove RET
170 \ MOV #QUIT_I2C,PC \ STOP I2C
172 \ BIT.B #SM_SCL,&I2CSM_IN \ 3
174 \ MOV #4,W \ 1 if SCL is LOW
176 \ BIT.B #SM_SDA,&I2CSM_IN \ 3
178 \ MOV #4,W \ 1 if SDA is LOW
184 \ \ ^^^^^^^Multi-Master-Mode^^^^^^\
186 \ wake up from LPM0 is longer with MSP30FR2xxx devices than with MSP430FR5xxx devices:
187 \ @ MCLK = 24MHz baudrate max = 5MBds with FR2xxx, and 6MBds with FR57xx.
188 \ **************************************\
189 ASM TERM_INT \ interrupt starts on RX first char of line input from TERMINAL
190 \ **************************************\
191 ADD #4,RSP \ 1 remove RET and SR
192 \ --------------------------------------\
193 MOV &PAD_I2CADR,W \ 3 W = 0 if ECHO, 1 if NOECHO
194 MOV #PAD_ORG,T \ 2 T = input buffer for I2C_Master TX
195 MOV #$0D,S \ 2 S = last char to be RXed by UART
197 MOV.B &TERM_RXBUF,Y \ 3 move char from TERM_RXBUF...
199 MOV.B Y,-1(T) \ 3 ... to buffer (PAD)
200 CMP.B Y,S \ 1 char = CR ?
201 0<> WHILE \ 2 28 cycles loop ==> up to 2.96 Mbds @ 8MHz
203 0= IF \ 2 if echo ON requested by I2C_Slave
205 BIT #2,&TERM_IFG \ 3 > mandatory for low baudrates
207 MOV.B Y,&TERM_TXBUF \ 3
210 BIT #1,&TERM_IFG \ 3 received char ?
213 CALL &RXOFF \ stops UART RX still char CR is received and before receiving char LF
215 BIT #1,&TERM_IFG \ 3 char $0A received ?
216 0<> UNTIL \ 2 RX_int flag is cleared
217 \ --------------------------------------\
218 BW1 \ <=== Ctrl_char $01 (KEY input)
219 \ --------------------------------------\
220 MOV.B &TERM_RXBUF,S \ 3 S = last char (LF|KEY) ...
221 MOV.B S,0(T) \ 4 store it into buffer
222 \ ======================================\
223 \ ======================================\ S = last char to be transmitted
224 \ I2C MASTER TX \ T = last char transmitted
225 \ ======================================\ W = bits count
226 \ ======================================\ X = I2C_Address / I2C_Data
227 \ \ --------------------------------------\
228 \ BIS.B #LED1,&LED1_DIR \ red led ON = I2C TX
229 \ BIS.B #LED1,&LED1_OUT \ red led ON = I2C TX
230 \ \ --------------------------------------\
231 \ \ vvvvvvvvvvMulti-Master-Modevvvvvvv\
232 BW2 \ I2C_Master TX Start \ here, SDA and SCL must be in idle state
233 \ \ ^^^^^^^^^^Multi-Master-Mode^^^^^^^\
234 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l force SDA as output (low)
235 MOV.B &SLAVE_ADR,X \ 3 h X = Slave_Address
236 MOV #PAD_ORG,Y \ 2 h Y = input buffer for I2C_Master TX
238 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h force SCL as output (low)
239 \ --------------------------------------\
241 \ ------------------------------------\
242 \ I2C Master TX address/Data \
243 \ ------------------------------------\
244 MOV.B #8,W \ 1 l prepare 8 bits address
246 ADD.B X,X \ 1 l shift one left
247 U>= IF \ 2 l carry set ?
248 BIC.B #SM_SDA,&I2CSM_DIR \ 3 l yes : SDA as input ==> SDA high because pull up resistor
250 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l no : SDA as output ==> SDA low
253 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
255 BIT.B #SM_SCL,&I2CSM_IN \ 3 h test if SCL is released (Slave RX addr/data)
257 \ \ vvvvvvvvMulti-Master-Modevvvvvvv\
258 \ BIT.B #SM_SDA,&I2CSM_IN \ 3 h _ test SDA
259 \ \ ^^^^^^^^Multi-Master-Mode^^^^^^^\
260 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ SCL as output : force SCL low
261 \ \ vvvvvvvvvvvvMulti-Master-Modevvvvvvvvvvv\
263 \ BIT.B #SM_SDA,&I2CSM_DIR \ 3 l
265 \ \ --------------------------------\
266 \ \ collision detected \ l collision if SDA(IN)=0 AND SDA(DIR)=0
267 \ \ --------------------------------\
268 \ BIS.B #SM_SCL,&I2CSM_DIR \ 4 l release SCL first
269 \ CALL #DO_IDLE \ wait stable idle state
270 \ GOTO BW2 \ 2 l goto START TX
273 \ \ ^^^^^^^^^^^^Multi-Master-Mode^^^^^^^^^^^\
274 SUB #1,W \ 1 l bits count-1
276 \ ------------------------------------\
277 BIC.B #SM_SDA,&I2CSM_DIR \ 3 l after TX byte we must release SDA to read Ack/Nack from Slave
278 \ ------------------------------------\
279 \ I2C Master get Slave Ack/Nack \
280 \ ------------------------------------\ _
281 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
283 \ BIT.B #SM_SCL,&I2CSM_IN \ 3 h useless test if SCL is released (SLAVE ACK Addr/data)
286 BIT.B #SM_SDA,&I2CSM_IN \ 3 h _ get SDA state
287 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ SCL as output : force SCL low
288 \ ------------------------------------\
289 0= WHILE \ 1 Slave Ack received \ 2 l goto THEN; out of loop if Nack
290 \ ------------------------------------\
291 \ I2C_Master_TX_data_loop \
292 \ ------------------------------------\
293 CMP S,T \ 1 T = S = last char to transmit ? after address is sent, T = PAD_ORG <> S = any char
294 0<> WHILE \ 2 \ 2 out of loop if yes
295 MOV.B @Y+,X \ 2 l get next byte to TX
296 MOV X,T \ 1 T = last char TX for comparaison above
297 REPEAT \ <-- WHILE2 search "Extended control-flow patterns"...
298 THEN \ <-- WHILE1 ...in https://forth-standard.org/standard/rationale
299 \ ------------------------------------\
300 \ Nack or Ack on last char \ Nack = I2C_Slave request or I2C_Slave RESET, Ack = last char has been TX
301 \ ------------------------------------\
302 NOP3 \ 3 l _ delay to reach I2C tLO
303 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL to enable reSTART
304 \ \ --------------------------------------\
305 \ BIC.B #LED1,&LED1_DIR \ red led OFF = endof I2C TX
306 \ BIC.B #LED1,&LED1_OUT \ red led OFF = endof I2C TX
307 \ \ --------------------------------------\
308 GOTO FW1 \ X > 4 ==> continuous repeated START RX below
309 \ ======================================\
310 \ END OF I2C MASTER TX \
311 \ ======================================\
315 \ **************************************\
317 \ **************************************\
318 ADD #4,RSP \ 1 remove RET and SR
319 \ --------------------------------------\
320 FW1 \ from TERM_INT above
321 \ --------------------------------------\
322 BW3 \ from I2C_WARM below
323 \ --------------------------------------\
324 \ I2C_Master START RX \
325 \ --------------------------------------\
326 CMP #0,&KERNEL_ADDON \ 3
327 0>= IF \ 2 if LF XTAL present
328 MOV #%0001_0101_0110,&TB0CTL \ 3 (re)starts RX_timer,ACLK=VLO=8kHz,/2=4096Hz,up mode,clear timer,enable TB0 int, clear IFG
329 \ MOV #%0001_0101_0110,&TA0CTL \ 3 (re)starts RX_timer,ACLK=VLO=8kHz,/2=4096Hz,up mode,clear timer,enable TB0 int, clear IFG
331 MOV #%0001_1101_0110,&TB0CTL \ 3 (re)starts RX_timer,ACLK=LFXTAL=32738,/8=4096Hz,up mode,clear timer,enable TB0 int, clear IFG
332 \ MOV #%0001_1101_0110,&TA0CTL \ 3 (re)starts RX_timer,ACLKLFXTAL=32768,/8=4096Hz,up mode,clear timer,enable TB0 int, clear IFG
334 \ --------------------------------------\
335 \ le driver I2C_Master envoie START RX en boucle continue (X < 4) ou discontinue (X >= 4).
336 \ le test d'un break en provenance de l'UART est intégré dans cette boucle.
337 \ --------------------------------------\
338 BEGIN \ I2C MASTER RX
339 \ --------------------------------------\
340 BEGIN \ I2C MASTER START RX
341 \ ------------------------------------\
342 BIT #8,&TERM_STATW \ 3 break sent by TERATERM ?
344 MOV #QUIT_I2C,PC \ 2 STOP I2C
346 \ --------------------------------\
347 \ I2C_Master_Start_Cond \ here, SDA and SCL must be in idle state
348 \ --------------------------------\
349 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l force SDA as output (low)
350 MOV.B &SLAVE_ADR,Y \ 3 h X = Slave_Address
351 BIS.B #1,Y \ 1 h Master RX
353 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h force SCL as output (low)
354 \ --------------------------------\
355 \ I2C_Master_Send_address \ may be SCL is held low by slave
356 \ --------------------------------\
357 MOV.B #8,W \ 1 l prepare 8 bits address
359 ADD.B Y,Y \ 1 l shift one left
360 U>= IF \ 2 l carry set ?
361 BIC.B #SM_SDA,&I2CSM_DIR \ 3 l yes : SDA as input ==> SDA high because pull up resistor
363 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l no : SDA as output ==> SDA low
366 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
368 \ BIT.B #SM_SCL,&I2CSM_IN \ 3 h useless test if SCL is released (SLAVE RX Addr)
371 \ \ vvvvvvMulti-Master-Modevvvvv\
372 \ BIT.B #SM_SDA,&I2CSM_IN \ 3 h _ test SDA
373 \ \ ^^^^^^Multi-Master-Mode^^^^^\
374 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ SCL as output : force SCL low
375 \ \ vvvvvvvvvvvvMulti-Master-Modevvvvvvvvvvv\
377 \ BIT.B #SM_SDA,&I2CSM_DIR \ 3 l
379 \ \ ------------------------------------\
380 \ \ collision detection \ l collision if SDA(IN)=0 AND SDA(DIR)=0
381 \ \ ------------------------------------\
382 \ BIS.B #SM_SCL,&I2CSM_DIR \ 4 l release SCL first
383 \ CALL #DO_IDLE \ wait stable idle state
384 \ GOTO BW3 \ 2 l goto START RX
387 \ \ ^^^^^^^^^^^^Multi-Master-Mode^^^^^^^^^^^\
388 SUB #1,W \ 1 l bits count - 1
390 \ --------------------------------\
391 \ Wait Ack/Nack on address \
392 \ --------------------------------\
393 BIC.B #SM_SDA,&I2CSM_DIR \ 3 l _ after TX address we must release SDA to read Ack/Nack from Slave
394 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
396 BIT.B #SM_SCL,&I2CSM_IN \ 3 h test if SCL is released (SLAVE TX ACK_ON_Addr)
398 BIT.B #SM_SDA,&I2CSM_IN \ 3 h _ get SDA
399 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ SCL as output : force SCL low
400 \ --------------------------------\
401 0<> WHILE \ Nack_On_Address \ 2 l
402 \ --------------------------------\
403 NOP3 \ 3 l delay to reach tLO
404 \ --------------------------------\
405 \ I2C_Master Send STOP \ after Nack_On_Address
406 \ --------------------------------\ _
407 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l v_ SDA as output ==> SDA low
409 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
412 BIC.B #SM_SDA,&I2CSM_DIR \ 3 h _^ SDA as input ==> SDA high with pull up resistor
413 CMP.B #4,X \ last CTRL_char <> ABORT ?
415 MOV #SLEEP,PC \ 4 if yes goto dodo
418 \ \ ------------------------------------\
419 \ BIS.B #LED2,&LED2_DIR \ green led ON = I2C RX
420 \ BIS.B #LED2,&LED2_OUT \ green led ON = I2C RX
421 \ \ ------------------------------------\
422 \ I2C_Master_RX_data \
423 \ ------------------------------------\
426 BIC.B #SM_SDA,&I2CSM_DIR \ 4 l after Ack and before RX next byte, we must release SDA
427 MOV.B #8,W \ 1 l prepare 8 bits transaction
428 \ ----------------------------\
430 \ -------------------------\ _
431 \ do SCL pulse \ SCL _| |_
432 \ -------------------------\ _
433 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
435 \ BIT.B #SM_SCL,&I2CSM_IN \ 3 h useless test if SCL is released (SLAVE TX Data)
438 BIT.B #SM_SDA,&I2CSM_IN \ 3 h _ get SDA
439 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ SCL as output : force SCL low 13~
440 ADDC.B X,X \ 1 l C <--- X(7) ... X(0) <--- SDA
441 SUB #1,W \ 1 l count down of bits
443 \ --------------------------------\
445 0= IF \ 2 received char $FF: let's consider that the slave is lost...
446 MOV #2,X \ to do ABORT action
448 \ --------------------------------\
449 CMP.B #8,X \ 1 l $08 = char BS
450 U>= WHILE \ 2 l ASCII char received, from char 'BS' up to char $7F.
451 \ ----------------------------\
453 BIT #2,&TERM_IFG \ 3 l UART TX buffer empty ?
454 0<> UNTIL \ 2 l loop if no
455 \ ----------------------------\
456 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l prepare Ack
457 \ ----------------------------\ _
458 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
460 BIT.B #SM_SCL,&I2CSM_IN \ 3 h test if SCL is released (SLAVE RX Ack)
462 MOV.B X,&TERM_TXBUF \ 3 h _ send RX char to UART TERMINAL
463 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ SCL as output : force SCL low
464 REPEAT \ 2 l loop back to I2C_Master_RX_data
465 \ --------------------------------\
466 \ case of Ctrl_char received \ here Master holds SCL low, Slave can test it: CMP #8,&TERM_STATW
467 \ --------------------------------\
471 MOV #1,&PAD_I2CADR \ 3 set NOECHO if char $04
473 MOV #0,&PAD_I2CADR \ set ECHO if char >$04
475 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l prepare Ack
477 \ --------------------------------\ _
478 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
480 BIT.B #SM_SCL,&I2CSM_IN \ 3 h test if SCL is released (SLAVE RX Ack)
482 BIT.B #SM_SDA,&I2CSM_IN \ 3 h _ get SDA
483 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ SCL as output : force SCL low
484 \ --------------------------------\
485 0<> UNTIL \ 2 l until Nack sent by Master for CTRL-Char {$00|$01|$02|$03}
486 \ ------------------------------------\
487 \ Nack is sent by Master \
488 \ ------------------------------------\
489 CMP.B #2,X \ 1 l $02 = ctrl_char for ABORT request
491 \ ------------------------------------\
492 \ CTRL_Char $02|$03 \ if ABORT|COLD requests
493 \ ------------------------------------\
494 0= IF \ if ctrl_char $02 = ABORT request
495 MOV #0,&PAD_I2CADR \ set echo ON I2C_Master side (I use the useless address PAD_I2CADR)
496 CALL &RXON \ resume UART downloading source file
498 BIC #UCRXIFG,&TERM_IFG \ clear UCRXIFG
499 MOV &FREQ_KHZ,Y \ 1000, 2000, 4000, 8000, 16000, 240000
500 BEGIN MOV #32,W \ 2~ <-------+ windows 10 seems very slow...
501 BEGIN SUB #1,W \ 1~ <---+ | ==> ((32*3)+5)*1000 = 101ms delay
502 0= UNTIL \ 2~ 3~ loop ---+ | to refill its USB buffer
504 0= UNTIL \ 2~ 101~ loop -----+
505 \ BEGIN MOV #65,W \ <-------+ linux with minicom seems very very slow...
506 \ BEGIN SUB #1,W \ <---+ | ==> ((65*3)+5)*1000 = 200ms delay
507 \ 0= UNTIL \ 3~ loop ---+ | to refill its USB buffer
509 \ 0= UNTIL \ 200~ loop -----+
510 BIT #UCRXIFG,&TERM_IFG \ 4 new char in TERMRXBUF during this delay ?
511 0= UNTIL \ 2 yes, the input stream may be still active: loop back
512 \ ELSE \ do nothing if Ctrl_char = $03
514 REPEAT \ loop back to I2C MASTER reSTART RX
515 \ --------------------------------------\
516 \ CTRL_Char $00|$01 \ if ACCEPT|KEY requests
517 \ --------------------------------------\
518 \ I2C_Master RX Send STOP \
519 \ --------------------------------------\
520 BIS.B #SM_SDA,&I2CSM_DIR \ 3 before STOP, we must pull SDA low
521 \ ------------------------------------\ _
522 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
524 MOV #PAD_ORG,T \ 2 h _ ready to store KEY char: MOV.B S,0(T)
525 BIC.B #SM_SDA,&I2CSM_DIR \ 3 h _^ SDA as input ==> SDA high with pull up resistor
526 \ \ --------------------------------------\
527 \ BIC.B #LED2,&LED2_DIR \ 4 l green led OFF = endof I2C RX
528 \ BIC.B #LED2,&LED2_OUT \ 4 l green led OFF = endof I2C RX
529 \ \ --------------------------------------\
530 \ ======================================\
531 \ ======================================\
532 \ END OF I2C MASTER RX \ here I2C_bus is freed and Nack on Ctrl_char $FF|$00|$01 remains to be processed.
533 \ ======================================\
534 \ ======================================\
535 \ TERMINAL TX --> UART RX \
536 \ --------------------------------------\
537 \ I2C_Slave KEY ctl_char $01 \ I2C_Slave request for KEY input
538 \ --------------------------------------\
540 \ Quand I2C_Master reçoit ce caractère de contrôle,
541 \ il attend un caractère en provenance de TERMINAL UART
542 \ et une fois ce caractère reçu reSTART TX pour l'envoyer à I2C_Slave
544 CALL &RXON \ 4 l to enable UART RX; use no registers
545 BEGIN \ wait for a char or for a break
546 BIT #UCRXIFG,&TERM_IFG \ 3 received char ?
548 CALL &RXOFF \ stops UART RX
549 GOTO BW1 \ goto end of TERMINAL line input to RX KEY char to 0(T) with T =
551 \ --------------------------------------\
552 \ I2C_Slave ACCEPT ctrl_char $00 \ I2C_Slave requests I2C_Master to stop RX and start TX
553 \ --------------------------------------\
554 \ en début de sa routine ACCEPT, I2C_Slave envoie sur le bus I2C le caractère de contrôle $00
555 \ avant de s'endormir avec SLEEP
556 \ I2C_Master envoie NACK + STOP pour signifier la fin de la transaction.
557 \ --------------------------------------\
558 \ et si I2C_Slave est sorti de son sommeil par un START RX, idem.
559 \ --------------------------------------\
560 MOV #SLEEP,PC \ execute RXON then goto dodo
561 \ --------------------------------------\
562 \ I2C_Master se réveillera au premier caractère saisi sur le TERMINAL ==> TERM_INT,
563 \ ou en fin du temps TxyCCR0 ==> RX_INT,
564 \ ou par un break opérateur ==> WDT_INT.
566 \ --------------------------------------\
569 \ --------------------------------------\
570 ASM I2C_WARM \ replace default WARM
571 \ --------------------------------------\
572 CMP #4,&SAVE_SYSRSTIV \ hard RESET ?
574 BIT.B #SW2,&SW2_IN \ SW2 pressed ? ( SW2 <> SW1 = Deep RESET)
576 MOV #QUIT_I2C,PC \ quit I2C only if SW2+RESET
579 CMP #$10,&SAVE_SYSRSTIV \
580 U>= IF \ if SYS failure >= $10 then STOP I2C
583 MOV #0,&SAVE_SYSRSTIV \ clear SAVE_SYSRSTIV after use
584 \ --------------------------------------\
586 \ --------------------------------------\
587 MOV #%0101_1010_0101_1111,&WDTCTL \ start Watchdog Timer : XDTPW, WDTSSEL=VLOCLK, WDTCNTCL=1, WDTIS=2^6 (8ms)
588 BIS #1,&SFRIE1 \ enable WDT
589 MOV #WDT_INT,&WDT_VEC \ replace WDT_VEC default value (COLD) by WDT_INT
590 \ --------------------------------------\
591 \ init RX_INT \ used to scan I2C_Slave hard RESET during SLEEP and to slow START RX loop
592 \ --------------------------------------\
593 MOV #$800,&TB0CCR0 \ be careful: RX_Int time = (2047+1)/4096 = 0.5s must be >> COLD time !
594 MOV #RX_INT,&TB0_x_VEC \
595 \ MOV #$800,&TA0CCR0 \ be careful: RX_Int time = (2047+1)/4096 = 0.5s must be >> COLD time !
596 \ MOV #RX_INT,&TA0_x_VEC \
597 \ --------------------------------------\
599 \ --------------------------------------\
600 MOV #TERM_INT,&TERM_VEC \ replace TERM_VEC default value (TERMINAL_INT) by TERM_INT
601 \ --------------------------------------\
602 \ init I2C_MASTER I/O \ reset state: I2CSM_DIR(SM_BUS) = 0
603 \ --------------------------------------\
604 BIC.B #SM_BUS,&I2CSM_REN \ remove internal pullup resistors because of external 3.3k pullup resistor
605 BIC.B #SM_BUS,&I2CSM_OUT \ preset SDA + SCL output LOW
606 \ --------------------------------------\
607 \ activate I/O \ SYSRSTIV = $02 | $0E = POWER ON | SVSH threshold
608 \ --------------------------------------\
609 BIC #1,&PM5CTL0 \ activate all previous I/O settings; if not activated, nothing works after reset !
610 \ --------------------------------------\
611 MOV.B #4,X \ to enable RX_INT sleep
612 GOTO BW3 \ goto I2C_Master START RX loop
615 \ ================================================================================
616 \ Driver UART to I2CM: this FastForth launchpad becomes an USB to I2C_Slave bridge
617 \ ================================================================================
618 \ type on TERMINAL "$10 UARTI2CS" to link TERMINAL with FastForth I2C_Slave at address hex $10
620 : UARTI2CS \ SlaveAddress --
621 CR \ to compensate the lack of one INTERPRET
624 MOV TOS,&SLAVE_ADR \ save in FRAM
627 MOV #I2C_WARM,2(X) \ replace WARM by I2C_WARM, so POR falls down to I2C_WARM
628 MOV X,PC \ execute I2C_WARM
632 #16 UARTI2CS ; Alt-B (TERATERM) or S2+RESET (I2C_Master) to quit
634 ; Since there is no difference in behaviour whether the TERMINAL is connected to the Master
635 ; or bridged to any Slave, WARM is the convenient way to check which target is connected to,
636 ; because, as any ABORT message, WARM displays first the decimal I2C address if applicable: