1 \ -*- coding: utf-8 -*-
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_1
9 \ from scite editor : copy your target selection in (shift+F8) parameter 1:
13 \ drag and drop this file onto SendSourceFileToTarget.bat
14 \ then select your TARGET when asked.
17 \ FastForth kernel compilation minimal options:
18 \ TERMINAL3WIRES, TERMINAL4WIRES
19 \ MSP430ASSEMBLER, CONDCOMP
21 \ ================================================================================
22 \ REGISTERS USAGE for embedded MSP430 ASSEMBLER
23 \ ================================================================================
25 \ R4, R5, R6, R7 must be PUSHed/POPed before/after use
26 \ scratch registers S to Y are free,
27 \ under interrupt, IP is free,
28 \ Apply FORTH rules for TOS, PSP, RSP registers use.
30 \ PUSHM order : PSP,TOS, IP, S , T , W , X , Y ,rDOVAR,rDOCON,rDODOES,rDOCOL, R3, SR,RSP, PC
31 \ PUSHM order : R15,R14,R13,R12,R11,R10, R9, R8, R7 , R6 , R5 , R4 , R3, R2, R1, R0
33 \ example : PUSHM #6,IP pushes IP,S,T,W,X,Y registers to return stack
35 \ POPM order : PC,RSP, SR, R3, rDODOES,rDOCON,rDOVAR,rEXIT, Y, X, W, T, S, IP,TOS,PSP
36 \ POPM order : R0, R1, R2, R3, R4 , R5 , R6 , R7 , R8, R9,R10,R11,R12,R13,R14,R15
38 \ example : POPM #6,IP pop Y,X,W,T,S,IP registers from return stack
40 \ ASSEMBLER conditionnal usage before IF UNTIL WHILE : S< S>= U< U>= 0= 0<> 0>=
41 \ ASSEMBLER conditionnal usage before ?GOTO : S< S>= U< U>= 0= 0<> 0<
43 \ ================================================================================
44 \ coupled to a PL2303HXD/TA cable, this driver enables a FastForth target to act as USB to I2C_Slave bridge,
45 \ thus, from TERATERM.exe you can take the entire control of up to 112 I2C_FastForth targets.
46 \ In addition, it simulates a full duplex communication while the I2C bus is only half duplex.
47 \ Don't forget to wire 3k3 pull up resistors on wires SDA SCL!
48 \ ================================================================================
50 \ driver test : MCLK=24MHz, PL2303HXD with shortened cable (20cm), WIFI off, all windows apps closed else Scite and TERATERM.
52 \ / ┌────────────────────────────────┐
53 \ notebook USB to I2C_Slave bridge +-- I2C -->| up to 112 I2C_Slave targets |
54 \ ┌───────────────┐ ╔════════════════════════════════════════════════════════════╗ / ┌───────────────────────────────┐ |
55 \ | | ║ PL2303HXD target running UARTI2CS @ 24MHz ║ +-- I2C -->| MSP430FR4133 @ 1 MHz | |
56 \ | | ║───────────────┐ ┌────────────────────────────────║ / ┌───────────────────────────────┐ |──┘
57 \ | | ║ | 3 wires | MSP430FR2355 @ 24MHz ║/ | MSP430FR5738 @ 24 MHz | |
58 \ | TERATERM -o--> USB --o--> USB2UART --o--> UART --o--> FAST FORTH ---> UARTI2CS --o--> I2C --o--> FAST FORTH with option |──┘
59 \ | terminal | ║ | 6 MBds | (I2C MASTER) ║ | TERMINAL_I2C (I2C SLAVE) |
60 \ | | ║───────────────┘ └────────────────────────────────║ └───────────────────────────────┘
61 \ | | ║ |<- l=20cm->| ║
62 \ └───────────────┘ ╚════════════════════════════════════════════════════════════╝
67 \ downloading (+ interpret + compile + execute) CORETEST.4TH to I2C Master target = 1016ms.
68 \ downloading (+ interpret + compile + execute) CORETEST.4TH to I2C Slave target = 1422ms.
69 \ the difference (406 ms) is the time of the I2C Half duplex exchange.
70 \ [(45906 chars * 9 bits) + (1533 * 31)] / 0,406 = 1,135 MHz (9 bits / char + (2*START + 2*STOP + 2*addr + CTRL_Char) / line)
71 \ ==> 113 % of I2C Fast-mode Plus (Fm+)!
73 \ also connected to and tested with another I2C_FastForth target with MCLK = 1MHz (I2C CLK = MCLK ! ).
75 \ The I2C_Slave address is defined as 'MYSLAVEADR' in forthMSP430FR.asm source file of I2C_Slave target.
76 \ You can use any pin for SDA and SCL, preferably in the interval Px0...Px3.
77 \ you will find SCA and SCL pin by searching 'SM_BUS' in your \inc\target.pat files (I2C_Master and I2C_Slave)
78 \ don't forget to add 3.3k pullup resitors on wires SDA and SCL.
81 \ the LEDs TX and RX work fine, comment/uncomment as you want.
83 \ Multi Master Mode works but is not tested in the real word.
88 \ 1- the I2C bus is Master to Slave oriented, the Slave does not decide anything.
89 \ This order of things allows in any case to establish the connection.
90 \ The I2C Master device is therefore placed on the control TERMINAL side and the FastForth target on the I2C Slave side.
91 \ But once the link is established, we have to find a trick to reverse the roles,
92 \ so that the slave can take control of the data exchange.
94 \ 2- The I2C bus operates on half duplex.
95 \ Another trick will be to simulate an I2C_Master TERMINAL in Full Duplex mode.
97 \ Solution: The slave "slavishly" sends control characters to the master,
98 \ and since this one obeys a bigger man than himself: the programmer..,
99 \ he makes it his "masterly" duty to obey the slave.
101 \ To take control of the master, the slave emits 1 of 6+1 CTRL-Char:
102 \ CTRL-Char $00 sent by ACCEPT (before falling asleep with SLEEP),
103 \ CTRL-Char $01 sent by KEY: request to send a single character entered on TERMINAL,
104 \ CTRL-Char $02 sent by ABORT": request to abort the file being downloaded if any,
105 \ followed by a START RX for ABORT" message,
106 \ CTRL-Char $03 sent by WARM, to do a reSTART RX for WARM message,
107 \ CTRL-Char $04 sent by NOECHO, to switch the UART to half-duplex mode,
108 \ CTRL-Char $05 sent by ECHO, to switch the UART to full duplex mode.
110 \ Finally, if the master receives a $FF as data, he considers the link broken,
111 \ it performs ABORT which forces a START RX on a loop.
113 \ Once the slave sends the CTRL_Char $00, he falls asleep,
114 \ On receipt of this CTRL_Char, the master also falls asleep, awaiting a UART RX interruption.
115 \ As long as the TERMINAL is silent, the master and the slave remain in SLEEP mode,
116 \ (a part the Tx0_INT interrupt every 1/2 s).
117 \ SLEEP mode is LPM0 for the master (UART does not work if LPMx > LPM0), LPM4 for the slave.
121 \ Since the slave can't wake up the master with a dedicated interrupt, the master must generate one
122 \ cyclically to listen to the slave.
123 \ HALF_S_INT is used to generate a 1/2 second interrupt, obviously taken into account only when the master goes to sleep.
124 \ It performs a (re)START RX that enables the I2C link to be re-established following a RESET performed on I2C_Slave.
126 \ This interruption also allows the UARTI2CS program to exit when Teraterm sends a BREAK (Alt-B).
128 \ the other interruption U2I_TERM_INT is used to communicate with TERMINAL, by replacing of the TERM_INT one.
130 \ Software +----------------------------------+ Hardware
131 \ I2C Master | +-------------------+ | I2C Slave
133 \ UART to I2C bridge SCL SDA connected to: SDA SCL I2CFastForth target
134 \ ------------------- ---- ---- ---- ---- ------------------
135 \ MSP_EXP430FR5739 P4.1 P4.0 P1.6 P1.7 MSP_EXP430FR5739
136 \ MSP_EXP430FR5969 P1.3 P1.2 P1.6 P1.7 MSP_EXP430FR5969
137 \ MSP_EXP430FR5994 P8.1 P8.2 P7.0 P7.1 MSP_EXP430FR5994
138 \ MSP_EXP430FR6989 P1.5 P1.3 P1.6 P1.7 MSP_EXP430FR6989
139 \ MSP_EXP430FR4133 P8.3 P8.2 P5.2 P5.3 MSP_EXP430FR4133
140 \ CHIPSTICK_FR2433 P2.2 P2.0 P1.2 P1.3 CHIPSTICK_FR2433
141 \ MSP_EXP430FR2433 P3.1 P3.2 P1.2 P1.3 MSP_EXP430FR2433
142 \ MSP_EXP430FR2355 P3.3 P3.2 P1.2 P1.3 MSP_EXP430FR2355
143 \ LP_MSP430FR2476 P3.3 P3.2 P4.4 P4.3 LP_MSP430FR2476
145 \ don't forget to link 3V3 and GND on each side and to add 3k3 pullup resistors on SDA and SCL.
147 ; ----------------------------------------------------------------------
148 ; UARTI2CS.f (Software I2C Master)
149 ; ----------------------------------------------------------------------
151 \ first, we do some tests before downloading application
155 MOV &KERNEL_ADDON,TOS
157 0<> IF MOV #0,TOS THEN \ if TOS <> 0 (UART TERMINAL), set TOS = 0
160 SUB #308,TOS \ FastForth V3.8
162 $0D EMIT \ return to column 1 without CR
163 ABORT" FastForth V3.8 please!"
164 ABORT" <-- Ouch! unexpected I2C_FastForth target!"
165 PWR_STATE \ remove the ABORT_UARTI2CS definition before continuing the download.
168 ABORT_UARTI2CS \ abort test
170 [DEFINED] {UARTI2CS} [IF] {UARTI2CS} [THEN] \ remove {UARTI2CS} if already defined
172 MARKER {UARTI2CS} \ {UARTI2CS}+8 = RET_ADR by default
173 8 ALLOT \ {UARTI2CS}+10 <-- previous INI_APP
174 \ {UARTI2CS}+12 <-- previous TERM_VEC
175 \ {UARTI2CS}+14 <-- previous Tx0_x_VEC
176 \ {UARTI2CS}+16 <-- Half_Duplex flag : 0=ECHO, <>0=NOECHO
178 [UNDEFINED] CONSTANT [IF]
179 \ https://forth-standard.org/standard/core/CONSTANT
180 \ CONSTANT <name> n -- define a Forth CONSTANT
184 MOV TOS,-2(W) \ PFA = n
191 I2CSLA0 CONSTANT I2CS_ADR \ I2CSLA0=$FFA2
193 \ note: HDNCODE definitions are HiDdeN and cannot be executed from TERMINAL
194 \---------------------------\
195 HDNCODE I2CSTOP \ sends a STOP on I2C_BUS
196 \---------------------------\ _
197 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ force SCL as output (low)
199 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l v_ SDA as output ==> SDA low
201 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
203 BIC.B #SM_SDA,&I2CSM_DIR \ 3 h _^ relase SDA (high) when SCL is high = STOP
206 \---------------------------\
208 \---------------------------\
209 HDNCODE STOP_U2I \ STOP_APP subroutine, the next of TERATERM(ALT+B)|SW2+RST|SYS_failures
210 \ --------------------------\ UARTI2CS can't be stopped by any other means.
211 BW1 \ <-- I2C_MASTER_RX <-- TERATERM break (Alt+B)
212 CMP #RET_ADR,&{UARTI2CS}+8 \
213 0<> IF \ run STOP_U2I once, only if MARKER_DOES is already initialized
214 \ \ ----------------------\
215 \ BIC.B #LED2,&LED2_DIR \ set RX green led OFF
216 \ BIC.B #LED2,&LED2_OUT \ set RX green led OFF
217 \ BIC.B #LED1,&LED1_DIR \ set TX red led OFF
218 \ BIC.B #LED1,&LED1_OUT \ set TX red led OFF
219 \ \ ----------------------\
220 CALL #I2CSTOP \ stop properly I2C_BUS
222 BIC.B W,&I2CSM_DIR \ restore I2C_BUS I/O as input
223 BIS.B W,&I2CSM_OUT \ with pull up resistors
225 \ MOV #0,&TA0CTL \ stop timer and clear its interrupt flags IE, IFG
226 MOV #0,&TB0CTL \ stop timer and clear its interrupt flags IE, IFG
227 \ --------------------------\
228 MOV #{UARTI2CS}+10,W \ W = addr of first saved param after MARKER_DOES
229 MOV #RET_ADR,-2(W) \ don't forget: restore default MARKER_DOES call address !
230 MOV @W+,&WARM+2 \ restore previous (default) INI_APP address
231 MOV @W+,&TERM_VEC \ restore previous (default) TERM_VEC value
232 \ MOV @W+,&TA0_X_VEC \ restore previous (default) TB0_x_VEC value
233 MOV @W+,&TB0_X_VEC \ restore previous (default) TB0_x_VEC value
234 MOV #1,TOS \ to identify Alt+B|SW2+RST request in WARM message
236 \ --------------------------\ when STOP_U2I is the next of: TERATERM(ALT+B)|SW2+RESET|SYS_failures
237 MOV @RSP+,PC \ RET to: WARM_BODY|WARM_BODY|WARM_BODY
239 \ --------------------------\
242 \ \ vvvvvvvMulti-Master-Modevvvvvv\
244 \ MOV #4,W \ 1 wait bus idle time = 5 µs @ 16 MHz
246 \ BIT.B #SM_SCL,&I2CSM_IN \ 3
248 \ MOV #4,W \ 1 if SCL is LOW
250 \ BIT.B #SM_SDA,&I2CSM_IN \ 3
252 \ MOV #4,W \ 1 if SDA is LOW
258 \ \ ^^^^^^^Multi-Master-Mode^^^^^^\
260 \ **************************************\
261 HDNCODE U2I_TERM_INT \ UART RX interrupt starts on first char of each line sent by TERMINAL
262 \ **************************************\
263 ADD #4,RSP \ 1 remove unused PC_RET and SR_RET
264 \ --------------------------------------\
265 MOV &{UARTI2CS}+16,W \ 3 W = HALF_DUPLEX = 0 if ECHO, -1 if NOECHO
266 MOV #PAD_ORG,T \ 2 T = buffer pointer for UART_TERMINAL input
267 MOV #$0D,S \ 2 S = 'CR' = penultimate char of line to be RXed by UART
269 MOV.B &TERM_RXBUF,Y \ 3 move char from TERM_RXBUF...
271 MOV.B Y,-1(T) \ 3 ... to input buffer
272 CMP.B Y,S \ 1 char = CR ? (if yes goto next REPEAT)
274 CMP #0,W \ 1 HALF_DUPLEX = 0 ?
275 0= IF \ 2 yes, echo is ON
277 BIT #2,&TERM_IFG \ 3 > Test TX_Buf empty, mandatory for low baudrates
279 MOV.B Y,&TERM_TXBUF \ 3 echo char to UART_TERMINAL
282 BIT #1,&TERM_IFG \ 3 wait for next char received
284 REPEAT \ 2 31 cycles loop ==> up to UART 2.58 Mbds @ 8MHz
285 CALL #UART_RXOFF \ stops UART RX still char CR is received, the LF char is being transmitted.
287 BIT #1,&TERM_IFG \ 3 char LF received ?
289 \ --------------------------------------\
290 BW2 \ <=== Ctrl_char $01 (KEY input)
291 \ --------------------------------------\
292 MOV.B &TERM_RXBUF,S \ 3 S = last char RXed by UART (LF|KEY)
293 MOV.B S,0(T) \ 4 store it into buffer
294 \ ======================================\
295 \ ======================================\
296 \ I2C MASTER TX \ now we transmit UART RX buffer (PAD) to I2C_Slave, S = LF|KEY = last char to transmit
297 \ ======================================\
298 \ ======================================\
299 BW3 \ <=== multi master TX
300 \ --------------------------------------\
301 \ BIS.B #LED1,&LED1_DIR \ red led ON = I2C TX
302 \ BIS.B #LED1,&LED1_OUT \ red led ON = I2C TX
303 \ --------------------------------------\
304 \ I2C_Master_TX_Start \ here, SDA and SCL must be in idle state
305 \ --------------------------------------\ _
306 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l v_ force SDA low when SCL is high = START
307 MOV.B &I2CS_ADR,X \ 3 h X = Slave_Address
308 MOV #PAD_ORG,Y \ 2 h Y = buffer pointer for I2C_Master TX
310 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ force SCL as output (low)
311 \ --------------------------------------\
313 \ ------------------------------------\
314 \ I2C_Master_TX address/Data \
315 \ ------------------------------------\
316 MOV.B #8,W \ 1 l prepare 8 bits address
318 ADD.B X,X \ 1 l shift one left
319 U>= IF \ 2 l carry set ?
320 BIC.B #SM_SDA,&I2CSM_DIR \ 3 l yes : SDA as input ==> SDA high because pull up resistor
322 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l no : SDA as output ==> SDA low
324 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
325 BEGIN \ we must wait I2C_Slave software
326 BIT.B #SM_SCL,&I2CSM_IN \ 3 h by testing SCL released
327 0<> UNTIL \ 2 h (because Slave can strech SCL low)
328 \ \ vvvvvvvvMulti-Master-Modevvvvvvv\
329 \ BIT.B #SM_SDA,&I2CSM_IN \ 3 h test SDA
330 \ \ ^^^^^^^^Multi-Master-Mode^^^^^^^\ _
331 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ SCL as output : force SCL low
332 \ \ vvvvvvvvvvvvMulti-Master-Modevvvvvvvvvvv\
333 \ 0= IF \ 2 l SDA input low
334 \ BIT.B #SM_SDA,&I2CSM_DIR \ 3 l + SDA command high
335 \ 0= IF \ 2 l = collision detected
336 \ BIS.B #SM_SCL,&I2CSM_DIR \ 4 l release SCL first
337 \ CALL #DO_IDLE \ wait stable idle state
338 \ GOTO BW3 \ 2 l goto START TX
341 \ \ ^^^^^^^^^^^^Multi-Master-Mode^^^^^^^^^^^\
342 SUB #1,W \ 1 l bits count-1
344 \ ------------------------------------\
345 BIC.B #SM_SDA,&I2CSM_DIR \ 3 l after TX byte we must release SDA to read Ack/Nack from Slave
346 \ ------------------------------------\
347 \ I2C_Master_TX get Slave Ack/Nack \
348 \ ------------------------------------\ _
349 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
351 \ BIT.B #SM_SCL,&I2CSM_IN \ 3 h testing SCL released is useless
352 \ 0<> UNTIL \ 2 h because no risk of Slave streching SCL low
353 NOP3 \ 3 h replaced by NOP3.
354 BIT.B #SM_SDA,&I2CSM_IN \ 3 h _ get SDA state
355 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ SCL as output : force SCL low, to keep I2C_BUS until next I2C_MASTER START (RX|TX)
356 \ ------------------------------------\
357 0= WHILE \ 1- Slave Ack received \ 2 l out of loop if Nack (goto THEN next REPEAT)
358 \ ------------------------------------\
359 \ I2C_Master_TX_data_loop \
360 \ ------------------------------------\
361 CMP S,T \ 1 last char TXed = last char RXed ? (when address is sent, T = 16bits <> S = 8bits)
362 \ ------------------------------------\
363 0<> WHILE \ 2- TXed char <> last char \ 2 out of loop if TXed char T = last char S to be TXed (goto below REPEAT)
364 \ ------------------------------------\
365 MOV.B @Y+,X \ 2 l get next RXed char
366 MOV X,T \ 1 T = last TX char for comparaison above, on next loop.
367 REPEAT \ <-- WHILE2 search "Extended control-flow patterns"...
368 THEN \ <-- WHILE1 ...in https://forth-standard.org/standard/rationale
369 \ \ --------------------------------------\
370 \ BIC.B #LED1,&LED1_DIR \ red led OFF = endof I2C TX
371 \ BIC.B #LED1,&LED1_OUT \ red led OFF = endof I2C TX
372 \ \ --------------------------------------\
373 GOTO FW1 \ X > 4 ==> reSTART RX repeated every 1/2s
374 \ ======================================\
375 \ END OF I2C MASTER TX \ SCL is kept low until START RX --┐
376 \ ======================================\ |
378 \ **************************************\ v
381 \ **************************************\
382 HDNCODE HALF_S_INT \ wakes up every 1/2s to listen I2C Slave or break from TERMINAL.
383 \ **************************************\
384 ADD #4,RSP \ 1 remove PC_RET and SR_RET |
385 \ --------------------------------------\ |
386 FW1 \ <-- the next of TERM_INT above <--┘
387 BW3 \ <-- the next of INI_U2I below <--┐
388 \ --------------------------------------\ |
389 CMP #0,&KERNEL_ADDON \ 3 KERNEL_ADDON(BIT15) = LF XTAL flag
390 0>= IF \ if no LF XTAL
391 \ MOV #%0001_0101_0110,&TA0CTL \ 3 (re)starts RX_timer,ACLK=VLO=8kHz,/2=4096Hz,up mode,clear timer,enable TA0 int, clear IFG
392 MOV #%0001_0101_0110,&TB0CTL \ 3 (re)starts RX_timer,ACLK=VLO=8kHz,/2=4096Hz,up mode,clear timer,enable TB0 int, clear IFG
394 \ MOV #%0001_1101_0110,&TA0CTL \ 3 (re)starts RX_timer,ACLK=LFXTAL=32768,/8=4096Hz,up mode,clear timer,enable TA0 int, clear IFG
395 MOV #%0001_1101_0110,&TB0CTL \ 3 (re)starts RX_timer,ACLK=LFXTAL=32738,/8=4096Hz,up mode,clear timer,enable TB0 int, clear IFG
397 \ ======================================\
398 \ I2C_MASTER RX \ le driver I2C_Master envoie START RX en boucle continue (X < 4) ou discontinue (X >= 4).
399 \ ======================================\ le test d'un break en provenance de l'UART est intégré dans cette boucle.
400 BEGIN \ I2C MASTER START RX \ ABORT|WARM loop back
401 \ ------------------------------------\ _
402 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL to enable ReSTART RX
403 BIT #8,&TERM_STATW \ 3 break (Alt+B) sent by TERATERM ?
404 0<> ?GOTO BW1 \ goto STOP_U2I, exit to WARM+4.
405 \ ------------------------------------\
406 \ I2C_Master_RX_Start_Cond \ here, SDA and SCL must be in idle state
407 \ ------------------------------------\ _
408 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l v_ force SDA as output (low)
409 MOV.B &I2CS_ADR,Y \ 3 h X = Slave_Address
410 BIS.B #1,Y \ 1 h set Master RX
412 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ force SCL as output (low)
413 \ ------------------------------------\
414 \ I2C_Master_RX_Send_address \ may be SCL is held low by slave
415 \ ------------------------------------\
416 MOV.B #8,W \ 1 l prepare 8 bits address
418 ADD.B Y,Y \ 1 l shift one left
419 U>= IF \ 2 l carry set ?
420 BIC.B #SM_SDA,&I2CSM_DIR \ 3 l yes : SDA as input ==> SDA high because pull up resistor
422 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l no : SDA as output ==> SDA low
424 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
426 \ BIT.B #SM_SCL,&I2CSM_IN \ 3 h testing SCL released is useless
427 \ 0<> UNTIL \ 2 h because no risk of Slave streching SCL low
428 NOP3 \ 3 replaced by NOP3
429 \ \ vvvvvvMulti-Master-Modevvvvvvvvv\
430 \ BIT.B #SM_SDA,&I2CSM_IN \ 3 h test SDA
431 \ \ ^^^^^^Multi-Master-Mode^^^^^^^^^\ _
432 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ force SCL as output (low)
433 \ \ vvvvvvvvvvvvMulti-Master-Modevvvvvvvvvvv\
434 \ 0= IF \ 2 l SDA input low
435 \ BIT.B #SM_SDA,&I2CSM_DIR \ 3 l + SDA command high
436 \ 0= IF \ 2 l = collision detected
437 \ BIS.B #SM_SCL,&I2CSM_DIR \ 4 l release SCL first
438 \ CALL #DO_IDLE \ wait stable idle state
439 \ GOTO BW3 \ 2 l goto START RX
442 \ \ ^^^^^^^^^^^^Multi-Master-Mode^^^^^^^^^^^\
443 SUB #1,W \ 1 l bits count - 1
445 \ ------------------------------------\
446 \ Wait Ack/Nack on address \
447 \ ------------------------------------\ _
448 BIC.B #SM_SDA,&I2CSM_DIR \ 3 l _^_ after TX address we must release SDA to read Ack/Nack from Slave
449 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
450 BEGIN \ we must wait I2C_Slave software
451 BIT.B #SM_SCL,&I2CSM_IN \ 3 h by testing SCL released
452 0<> UNTIL \ 2 h (because Slave can strech SCL low)
453 BIT.B #SM_SDA,&I2CSM_IN \ 3 h _ get SDA
454 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ SCL as output : force SCL low
455 \ ------------------------------------\
456 0<> IF \ Nack_On_Address \ 2 l
457 \ --------------------------------\
458 \ I2C_Master Send STOP \
459 \ --------------------------------\
461 MOV #SLEEP,PC \ 4 goto dodo for 1/2 s .. wake up by HALF_S_INT
463 \ ------------------------------------\
464 \ I2C_Master_RX_data \
465 \ \ ------------------------------------\
466 \ BIS.B #LED2,&LED2_DIR \ green led ON = I2C RX
467 \ BIS.B #LED2,&LED2_OUT \ green led ON = I2C RX
468 \ \ ------------------------------------\
471 BIC.B #SM_SDA,&I2CSM_DIR \ 4 l after Ack and before RX next byte, we must release SDA
472 MOV.B #8,W \ 1 l prepare 8 bits transaction
473 \ ----------------------------\
475 \ -------------------------\ _
476 \ do SCL pulse \ SCL _| |_
477 \ -------------------------\ _
478 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
480 \ BIT.B #SM_SCL,&I2CSM_IN \ 3 h testing SCL released is useless
481 \ 0<> UNTIL \ 2 h because no risk of Slave streching SCL low
482 NOP3 \ 3 replaced by NOP3
483 BIT.B #SM_SDA,&I2CSM_IN \ 3 h _ get SDA
484 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ SCL as output : force SCL low 13~
485 ADDC.B X,X \ 1 l C <--- X(7) ... X(0) <--- SDA
486 SUB #1,W \ 1 l count down of bits
487 0= UNTIL \ 2 l here, slave releases SDA
488 \ ----------------------------\
489 \ case of RX data $FF \
490 \ ----------------------------\
492 0= IF \ 2 received char $FF: let's consider that the slave is lost...
493 MOV #2,X \ to do ABORT action
495 \ ----------------------------\
496 CMP.B #8,X \ 1 l $08 = char BS
497 U>= WHILE \ 2 l ASCII char received, from char 'BS' up to char $7F.
498 \ ----------------------------\
500 BIT #2,&TERM_IFG \ 3 l UART TX buffer empty ?
501 0<> UNTIL \ 2 l loop if no
502 \ ----------------------------\
503 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l prepare Ack
504 \ ----------------------------\
505 \ I2C_Master_RX Send Ack \ on ASCII char >= $08
506 \ ----------------------------\ _
507 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
508 BEGIN \ we must wait I2C_Slave software
509 BIT.B #SM_SCL,&I2CSM_IN \ 3 h by testing SCL released
510 0<> UNTIL \ 2 h (because Slave can strech SCL low)
511 \ ----------------------------\
512 MOV.B X,&TERM_TXBUF \ 3 h send RXed ASCII char to UART TERMINAL
513 \ ----------------------------\ _
514 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ SCL as output : force SCL low
515 REPEAT \ 2 l loop back to I2C_Master_RX_data for chars >= 8
516 \ --------------------------------\
517 \ case of RX CTRL_Chars < $08 \ here Master holds SCL low, Slave can test it: CMP #8,&TERM_STATW
518 \ --------------------------------\ see forthMSP430FR_TERM_I2C.asm
521 MOV #0,&{UARTI2CS}+16 \ preset ECHO
523 MOV #-1,&{UARTI2CS}+16 \ 3 set NOECHO if char $04
525 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l prepare Ack for Ctrl_Chars $04 $05
527 \ --------------------------------\
528 \ Master_RX send Ack/Nack on data \ Ack for $04, $05, Nack for $00, $01, $02, $03
529 \ --------------------------------\ _
530 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
531 BEGIN \ we must wait I2C_Slave software
532 BIT.B #SM_SCL,&I2CSM_IN \ 3 h by testing SCL released
533 0<> UNTIL \ 2 h (because Slave can strech SCL low)
534 BIT.B #SM_SDA,&I2CSM_IN \ 3 h _ get SDA as TX Ack/Nack state
535 BIS.B #SM_SCL,&I2CSM_DIR \ 3 h v_ SCL as output : force SCL low
536 \ --------------------------------\ l
537 0<> UNTIL \ if Ack, loop back to Master_RX data for CTRL_Char $04,$05
538 \ ------------------------------------\
539 \ Nack is sent by Master \ l case of CTRL-Char {$00|$01|$02|$03}
540 \ ------------------------------------\
541 CMP.B #2,X \ $02 = ctrl_char for ABORT request
542 U>= WHILE \ $03 = Ctrl_Char for WARM request
543 \ ------------------------------------\
544 \ CTRL_Char $02|$03 \ l if ABORT|WARM requests, SDA is high, SCL is low
545 \ ------------------------------------\
546 0= IF \ if ABORT request:
547 MOV #0,&{UARTI2CS}+16 \ set echo ON I2C_Master side
548 CALL #UART_RXON \ resume UART downloading source file
550 BIC #UCRXIFG,&TERM_IFG \ clear UCRXIFG
551 MOV &FREQ_KHZ,Y \ 1000, 2000, 4000, 8000, 16000, 240000
552 BEGIN MOV #32,W \ 2~ <-------+ windows 10 seems very slow...
553 BEGIN SUB #1,W \ 1~ <---+ | ==> ((32*3)+5)*1000 = 101ms delay
554 0= UNTIL \ 2~ 3~ loop ---+ | to refill its USB buffer
556 0= UNTIL \ 2~ 101~ loop -----+
557 \ BEGIN MOV #65,W \ <-------+ linux with minicom seems very very slow...
558 \ BEGIN SUB #1,W \ <---+ | ==> ((65*3)+5)*1000 = 200ms delay
559 \ 0= UNTIL \ 3~ loop ---+ | to refill its USB buffer
561 \ 0= UNTIL \ 200~ loop -----+
562 BIT #UCRXIFG,&TERM_IFG \ 4 new char in TERMRXBUF during this delay ?
563 0= UNTIL \ 2 yes, the input stream may be still active: loop back
565 REPEAT \ l loop back to reSTART RX
566 \ --------------------------------------\
567 \ I2C_Master_RX Send STOP \ l remainder: CTRL_Chars $00,$01
568 \ --------------------------------------\
570 \ \ --------------------------------------\
571 \ BIC.B #LED2,&LED2_DIR \ green led OFF = endof I2C RX
572 \ BIC.B #LED2,&LED2_OUT \ green led OFF = endof I2C RX
573 \ ======================================\
574 \ END OF I2C MASTER RX \ here I2C_bus is freed, Nack on Ctrl_char $FF|$00|$01 remains to be processed.
575 \ ======================================\
576 \ I2C_Slave KEY ctl_char $01 \ I2C_Slave request for KEY input
577 \ --------------------------------------\
579 \ Quand I2C_Master reçoit ce caractère de contrôle,
580 \ il attend un caractère en provenance de TERMINAL UART
581 \ et une fois ce caractère reçu reSTART TX pour l'envoyer à I2C_Slave
583 MOV #PAD_ORG,T \ ready to store KEY char: MOV.B S,0(T)
584 CALL #UART_RXON \ enables TERMINAL to TX; use no registers
585 BEGIN \ wait for a char
586 BIT #UCRXIFG,&TERM_IFG \ received char ?
588 CALL #UART_RXOFF \ stops UART RX then
589 GOTO BW2 \ goto end of UART RX line input, for receiving last char
591 \ --------------------------------------\
592 \ I2C_Slave ACCEPT ctrl_char $00 \ I2C_Slave requests I2C_Master to stop RX and start TX
593 \ --------------------------------------\
594 \ en début de sa routine ACCEPT, I2C_Slave envoie sur le bus I2C le caractère de contrôle $00
595 \ avant de s'endormir avec SLEEP
596 \ I2C_Master envoie NACK + STOP pour signifier la fin de la transaction.
597 \ --------------------------------------\
598 \ et si I2C_Slave est sorti de son sommeil par un START RX, idem.
599 \ --------------------------------------\
600 MOV #SLEEP,PC \ executes RXON (that enables TERMINAL to TX) before LPM0 shut down.
601 \ --------------------------------------\
602 \ I2C_Master se réveillera au premier caractère saisi sur le TERMINAL ==> TERM_INT,
603 \ ou en fin du temps TxIFG ==> HALF_S_INT\
605 \ **************************************\
607 \---------------------------\
608 HDNCODE INI_U2I \ define INI_HARD_APP subroutine called by WARM
609 \ --------------------------\
610 CALL &{UARTI2CS}+10 \ previous INI_APP executing init TERM_UC, activates I/O and sets TOS = RSTIV_MEM.
611 \ --------------------------\ TOS = SYSRSTIV = $00|$02|$04|$0E|$xx = POWER_ON|RST|SVSH_threshold|SYS_failures
612 CMP #$0E,TOS \ SVSHIFG SVSH event ?
614 CMP #$0A,TOS \ RSTIV_MEM >= violation memory protected areas ?
615 U>= ?GOTO BW1 \ execute STOP_U2I then RET to BODY of WARM
616 THEN \ RSTIV_MEM = {$00,$02,$04,$6,$0E} as: {WARM,PWR_ON,RST,COLD,SVSH_Threshold}
617 BIT.B #SW2,&SW2_IN \ SW2 pressed ?
618 0= ?GOTO BW1 \ if yes execute STOP_U2I then RET to BODY of WARM
619 MOV #0,&RSTIV_MEM \ clear RSTIV_MEM before next RST event!
620 \ --------------------------\
621 \ init HALF_S_INT \ used to scan I2C_Slave hard RESET and to slow (re)START RX loop
622 \ --------------------------\
623 MOV #$800,&TB0CCR0 \ time = (2047+1)/4096 = 0.5s
624 \ MOV #$800,&TA0CCR0 \ time = (2047+1)/4096 = 0.5s
625 \ --------------------------\
626 \ init I2C_MASTER I/O \ see \inc\your_target.pat to find I2C MASTER SDA & SCL pins (as SM_BUS)
627 \ --------------------------\
628 BIC.B #SM_BUS,&I2CSM_REN \ remove internal pullup resistors to avoid pulling down resistors with next instruction:
629 BIC.B #SM_BUS,&I2CSM_OUT \ preset SDA + SCL output LOW
630 \ --------------------------\
631 GOTO BW3 \ goto I2C_Master START RX loop, with no other return than ALT+B|SW2+RST
632 \ --------------------------\
634 \ --------------------------\
636 \ ==============================================================
637 \ Driver UART to I2CM which does the bridge USB to I2C_FastForth
638 \ ==============================================================
640 \ I2C address mini = 10h, maxi = 0EEh (I2C-bus specification and user manual V6)
641 \ type on TERMINAL "16 UARTI2CS" to link teraterm TERMINAL with FastForth I2C_Slave at address $10
642 \ you can also link with last known I2C_Slave address : "I2CS_ADR @ UARTI2CS"
644 : UARTI2CS \ I2C_Slave_Address_%0 --
645 CR I2CS_ADR ! \ -- save I2C_Slave_Address_%0
647 CMP #RET_ADR,&{UARTI2CS}+8 \
648 0= IF \ save parameters only if MARKER_DOES is not initialized
649 MOV #STOP_U2I,&{UARTI2CS}+8 \ MARKER_DOES of {UARTI2CS} will do CALL &{UARTI2CS}+8 = CALL #STOP_U2I
650 MOV &WARM+2,&{UARTI2CS}+10 \ save previous INI_APP from WARM PFA to {UARTI2CS}+10
651 MOV &TERM_VEC,&{UARTI2CS}+12 \ save previous TERM_VEC value to {UARTI2CS}+12, see target.pat
652 MOV &TB0_X_VEC,&{UARTI2CS}+14 \ save previous TB0_X_VEC value to {UARTI2CS}+14
653 \ MOV &TA0_X_VEC,&{UARTI2CS}+14 \ save previous TA0_X_VEC value to {UARTI2CS}+14
654 MOV #0,&{UARTI2CS}+16 \ reset Half_Duplex variable (set ECHO ON)
655 MOV #INI_U2I,&WARM+2 \ replace INI_APP by new INI_U2I
656 MOV #U2I_TERM_INT,&TERM_VEC \ set TERM_VEC with U2I_TERM_INT
657 MOV #HALF_S_INT,&TB0_X_VEC \ set TB0_X_VEC with HALF_S_INT
658 \ MOV #HALF_S_INT,&TA0_X_VEC \ set TA0_X_VEC with HALF_S_INT
660 MOV #WARM,PC \ execute INI_U2I then goto BW3; abort with Alt-B or SW2+RST.
664 18 UARTI2CS ; TERATERM(Alt-B) or I2C_Master(SW2+RST) to quit