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_2
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
20 \ see symbolic values in \inc\launchpad.pat or/and in \inc\device.pat
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 \ ================================================================================
28 \ -------------------------------------------------
29 ; UARTI2CS.f \I2C to UART bridge for I2C_FastForth\ -------------------------->+
30 \ -------------------------------------------------- |
31 \ ------------------------------ |
32 \ see forthMSP430FR_TERM_I2C.asm |
33 \ ------------------------------ |
36 \ | GND------------------------------GND |
37 \ | 3V3-------------o---o------------3V3 |
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 |
62 \ QUIT UARTI2CS QUIT UARTI2CS
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 \ =============================================================================================
72 \ empiric value of I2C pullup resistors: R (k) = 8 Vcc / MCLK (MHz). ex. VCC = 3.3, MCLK = 24 MHz ==> R = 1k1
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.
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.
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.
89 \ 3- ..without forgetting a visual effect to show the lack of I2C connection.
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.
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.
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.
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.
119 \ This interruption also allows to exit the UARTI2CS program when user sends a software BREAK (Teraterm(Alt-B)).
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.
125 \ driver test : MCLK=24MHz, PL2303CG with shortened cable (20cm), WIFI off, all windows apps closed else Scite and TERATERM.
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 \ └───────────────┘ ╚════════════════════════════════════════════════════════════╝
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+).
148 \ also connected to and tested with another I2C_FastForth target with MCLK = 1MHz (I2C CLK > MCLK !).
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.
154 \ the LEDs TX and RX work fine, comment/uncomment as you want.
156 \ Multi Master Mode works but is not tested in the real word.
159 \ ================================================================================
160 \ REGISTERS USAGE for embedded MSP430 ASSEMBLER
161 \ ================================================================================
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.
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
171 \ example : PUSHM #6,IP pushes IP,S,T,W,X,Y registers to return stack, with IP first pushed
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
176 \ example : POPM #6,IP pop Y,X,W,T,S,IP registers from return stack, with IP last poped
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<
181 \ first, we do some tests allowing the download
182 CODE ABORT_UARTI2CS \
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
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.
198 ABORT_UARTI2CS \ run tests
200 \ here is a MARKER definition, used to free the program memory including it, and restoring previous hardware context if any.
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.
215 \ =========================================================================
216 CODE LEDS MOV @IP+,PC ENDCODE \ comment this line to remove LEDS option
217 \ =========================================================================
219 \ -----------------------------------------------------------------------
220 \ first we download the set of definitions we need (copied from CORE_ANS)
221 \ -----------------------------------------------------------------------
224 \ https://forth-standard.org/standard/core/Equal
225 \ = x1 x2 -- flag test x1=x2
228 SUB #1,TOS \ 1 borrow if TOS was 0
229 SUBC TOS,TOS \ 1 TOS=-1 if borrow was set
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
243 \ -----------------------------
244 \ end of definitions we need...
245 \ -----------------------------
247 [UNDEFINED] TSTBIT [IF]
248 CODE TSTBIT \ addr bit_mask -- true/flase flag
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)
262 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l v_ SDA as output ==> SDA low
264 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
266 BIC.B #SM_SDA,&I2CSM_DIR \ 3 h _^ relase SDA (high) when SCL is high = STOP
269 \ ------------------------------------\
271 \ ------------------------------------\
272 HDNCODE REMOVE_U2I \ REMOVE_APP subroutine
273 \ ------------------------------------\
274 BW1 \ <-- WARM <-- INIT_FORTH <-- SYS_failures|RESET
275 \ ------------------------------------\
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
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
301 \ ------------------------------------\
302 MOV @RSP+,PC \ --> WARM --> previous_HARD_APP --> display I2C_address + WARM message --> FORTH interpreter
304 \ ------------------------------------\
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
312 \ ------------------------------------\
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) ?
321 MOV #WARM_IP_ADR,0(RSP) \ replace BACKGRND_U2I return by INIT_FORTH followed by WARM
323 \ ------------------------------------\
324 BW2 MOV #1,TOS \ to identify manual request to REMOVE_U2I
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.
334 \ ------------------------------------\
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.
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
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)
372 CMP #$0A,TOS \ SYSRSTIV >= violation memory protected areas ?
373 U>= ?GOTO BW1 \ if yes goto REMOVE_U2I, return to WARM
375 \ ------------------------------------\
376 MOV #ABORT,0(RSP) \ replace WARM return by ABORT return
377 MOV @RSP+,PC \ --> ABORT --> ACCCEPT --> BACKGRND --> LPM4
379 \ ------------------------------------\
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
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
402 \ ----------------------------\
403 \ collision detected \ if SDA input low, collision detected
404 \ ----------------------------\
406 BIT #TX,&TERM_IFG \ 3
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
415 \ ----------------------------\
416 BEGIN \ wait for 20us bus idle time
417 BIC.B #SM_BUS,&I2CSM_IFG \ 4 clear SM_BUS IFG
419 MOV.B &COLLISION_DLY,W \ 3 load delay value
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 \ ----------------------------\
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
449 \ ----------------------------------------\
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
461 CMP.B S,W \ 1 char = CR ? (if yes goto next REPEAT)
462 0<> WHILE \ 2 while <> CR
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
467 CMP.B #4,Y \ 1 echo OFF ?
468 0<> IF \ 2 if echo is ON
470 BIT #TX,&TERM_IFG \ 3 > Test TX_Buf empty, mandatory for low baudrates
472 MOV.B W,&TERM_TXBUF \ 3 return all characters to UART_TERMINAL except CR+LF which will be sent later by I2C_SLAVE
475 BIT #RX,&TERM_IFG \ 3 wait for next char received
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
481 BIT #RX,&TERM_IFG \ 3 char LF received ?
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 |
504 \ ----------------------------------------\ |
505 MOV #PAD_ORG-2,T \ 2 Y = buffer pointer, PAD-2 first |
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
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
517 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l no: SDA as output ==> SDA low
518 NOP2 \ 2 l for symmetry
520 BIC.B #SM_SCL,&I2CSM_DIR \ 3 l _^ release SCL (high)
521 \ --------------------------------\
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
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
534 BIS.B #SM_SDA,&I2CSM_DIR \ 3 l no: SDA as output ==> SDA low
535 NOP2 \ 2 l for symmetry
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...
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 \ ========================================\
566 BIC.B #LED1,&LED1_OUT \ red led OFF = endof I2C TX
568 \ ----------------------------------------\
569 GOTO FW1 \ SCL is kept low ──────┐
571 \ ****************************************\ v
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 \ ========================================\
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 ?
603 MOV.B #0,Y \ clear 'no_I2C_Slave' flag, ECHO is ON
604 MOV.B #'CR',&TERM_TXBUF \ send CR+LF to terminal
608 MOV.B #'LF',&TERM_TXBUF \
610 \ ====================================\
611 \ I2C Master RX data \
612 \ ====================================\
614 BIS.B #LED2,&LED2_OUT \ 3 l green led ON = I2C RX
616 \ ------------------------------------\
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
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
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...
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,
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
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
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
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}
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 \ ------------------------------------\
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
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 ---+ |
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 \ ----------------------------------------\
702 \ ========================================\
703 \ END OF I2C MASTER RX datas \ here I2C_bus is freed, CTRL_chars $00|$01 remain to be processed.
704 \ ========================================\
706 BIC.B #LED2,&LED2_OUT \ green led OFF = endof I2C RX
708 \ ========================================\
710 \ ----------------------------------------\
711 \ I2C_Slave ACCEPT ctrl_char $00 \ case of request by I2C_Slave ACCEPT
712 \ ----------------------------------------\
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.
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 ?
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
728 \ ****************************************\
731 \ ==============================================================================
732 \ Driver UART to I2C to do a bridge USB to I2C_FastForth devices
733 \ ==============================================================================
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
738 \ ------------------------------------\
739 CODE START_U2I \ I2C_Addr<<1 --
740 \ ------------------------------------\
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
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 ?
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
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 \ )
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
784 \ ------------------------------------\
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:
789 #18 START_U2I \ $12 is the wanted I2C_Slave_Address<<1 to link