1 ; -*- coding: utf-8 -*-
3 ; --------------------------------------------------- ---------------------------
4 ; TERMINAL driver for I2CFastForth target (I2C Slave) see MSP430-FORTH/UARTI2CS.f
5 ; --------------------------------------------------- ---------------------------
8 ; | GND------------------------------GND |
9 ; | 3V3-------------o---o------------3V3 |
12 ; | k k Txy.z output |
13 ; v 0 0 to v GND-------------------------------------GND
14 ; I2C_FastForth | | Px.y int UARTI2CS +-------------------------------------->+
15 ; (hardware +<-------------|---o------------>+ jumper (Software | +<----------------------------+ |
16 ; I2C Slave) ^ +<------o----------+ ^ +--->+ I2C Master) | | +------(option)---->+ | |
17 ; v v ^ v ^ | ^ v ^ v ^ v
18 ; 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
19 ; ------------------ ---- ---- ---- ---- ---------------- --- --- --- --- --- --- --------- ---- --------
20 ; MSP_EXP430FR2355 P1.2 P1.3 P3.3 P3.2 P1.7 P1.6 MSP_EXP430FR2355 (24MHz) P4.3 P4.2 P2.0 PL2303GC |
21 ; 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
22 ; 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
23 ; MSP_EXP430FR5994 P7.0 P7.1 P8.1 P8.2 P1.5 P1.4 MSP_EXP430FR5994 (16MHz) P2.0 P2.1 P4.2 CP2102
24 ; MSP_EXP430FR6989 P1.6 P1.7 P1.5 P1.3 P3.6 P3.7 MSP_EXP430FR6989 (16MHz) P3.4 P3.5 P3.0
25 ; MSP_EXP430FR4133 P5.2 P5.3 P8.3 P8.2 P1.6 P1.7 MSP_EXP430FR4133 (16MHz) P1.0 P1.1 P2.3
26 ; MSP_EXP430FR2433 P1.2 P1.3 P3.1 P3.2 P1.2 P1.3 MSP_EXP430FR2433 (16MHz) P1.4 P1.5 P1.0
27 ; LP_MSP430FR2476 P4.4 P4.3 P3.3 P3.2 P1.2 P1.1 LP_MSP430FR2476 (16MHz) P1.4 P1.5 P6.1
29 ; don't forget to link 3V3 and GND on each side and to add 3k3 pullup resistors on SDA and SCL.
31 ;-----------------------------------------------------------------------------------------------------------
32 ; I2C TERMINAL: ?ABORT, INIT values of ABORT_APP, BACKGRND_APP, HARD_APP, COLD_APP and SOFT_APP
33 ;-----------------------------------------------------------------------------------------------------------
35 ; ==================================;
36 ABORT_TERM ; INIT value of ABORT_APP, used by SD_CARD_ERROR
37 ; ==================================;
38 MOV.B #-1,Y ; send $FF (QABORT_YES Ctrl_Char) to UARTtoI2C bridge (I2C Master), used by SD_CARD_ERROR
39 JMP I2C_CTRL_CH ; then RET
40 ;-----------------------------------;
42 ; ?ABORT defines the run-time part of ABORT"
43 ;-----------------------------------;
44 QABORT CMP #0,2(PSP) ; -- f addr cnt if f is true abort current process then display ABORT" msg.
48 ; ----------------------------------;
49 QABORT_YES CALL &ABORT_APP ; QABORT_YES called by INTERPRET, QREVEAL, TYPE2DOES
50 ; ----------------------------------;
51 CALL #INIT_FORTH ; common ?ABORT|PUC subroutine
52 .word DUP ; -- f addr cnt cnt
53 .word QFBRAN,ABORT_END; -- f addr 0 if cnt = 0 display nothing
54 .word ECHO ; -- f addr cnt force ECHO
56 .byte 5,27,"[7m",'@' ;
57 .word TYPE ; cmd "reverse video" + displays "@"
58 .word LIT,I2CSLAVEADR ;
59 .word FETCH,DOT ; displays I2C_Slave_Address<<1
60 ; ----------------------------------;
61 ; Display ABORT|WARM message ; -- f addr cnt <== WARM jumps here
62 ; ----------------------------------;
63 ABORT_TYPE .word TYPE ; -- f display QABORT|WARM message
64 SDABORT_END .word XSQUOTE ; set normal video Display then goto ABORT
66 .word TYPE ; set normal video
67 ABORT_END .word ABORT ; -- f|f addr 0 no return
68 ; ----------------------------------;
70 ; ==================================;
71 INIT_BACKGRND ; INIT value of BACKGRND_APP
72 ; ==================================;
73 I2C_ACCEPT MOV.B #0,Y ; ACCEPT request Ctrl_Char = $00
74 JMP I2C_CTRL_CH ; then RET
75 ; ----------------------------------;
77 ;-------------------------------------------------------------------------------
78 ; INIT TERMinal then enable I/O
79 ;-------------------------------------------------------------------------------
81 ; ==================================;
82 INIT_TERM ; INIT value of HARD_APP called by WARM
83 ; ==================================;
84 BIS #07C0h,&TERM_CTLW0 ; set I2C_Slave in RX mode to receive I2C_address
85 MOV &I2CSLAVEADR,Y ; I2C_Slave_address<<1 value found in FRAM INFO
86 RRA Y ; shift it right one
87 BIS #400h,Y ; enable I2COA0 Slave address
89 BIS.B #BUS_TERM,&TERM_SEL ; Configure pins TERM_I2C
90 BIC #1,&TERM_CTLW0 ; release UC_TERM from reset...
91 BIS #WAKE_UP,&TERM_IE ; ...enable interrupt for wake up on START
92 BIC #LOCKLPM5,&PM5CTL0 ; then activate all previous I/O settings.
93 ; ==================================;
94 INIT_STOP ; INIT value of STOP_APP called by SYS, does nothing
95 ; ==================================;
96 INIT_SOFT ; INIT value of SOFT_APP
97 ; ==================================;
99 ; ----------------------------------;
101 ;-------------------------------------------------------------------------------
102 ; I2C TERMINAL : SYS COLD RESET WARM
103 ;-------------------------------------------------------------------------------
105 ;-----------------------------------;
107 ;-----------------------------------;
108 CALL &HARD_APP ; init HARD_APP, i.e. I2C_TERMinal then unlock IO's
112 .byte 7,13,10,27,"[7m@" ; CR+LF + cmd "reverse video" + @
114 .word LIT,I2CSLAVEADR ;
115 .word FETCH,DOT ; display decimal I2C_address<<1
117 .word DOT ; display signed USERSYS
119 .byte 25,"FastForth ",169 ;
120 .byte "J.M.Thoorens, " ;
122 .word LIT,FRAM_FULL ;
123 .word HERE,MINUS,UDOT ;
125 .byte 10,"bytes free" ; bytes free
126 .word BRAN,ABORT_TYPE ; no return
127 ;-----------------------------------;
129 FORTHWORD "SYS" ; n -- select COLD, DEEP_COLD, WARM (as software RST,DEEP_RST,WARM)
130 ;-----------------------------------;
131 SYS CALL &STOP_APP ; default STOP_APP = INIT_STOP, set by DEEP_RESET.
133 JL TOS2COLD ; if -n SYS --> COLD --> PUC --> INIT_FORTH --> DEEP_RESET --> WARM
134 JZ TOS2WARM ; if [0] SYS --> INIT_FORTH --> WARM
136 JZ TOS2COLD ; if +n SYS (+n even)--> COLD --> PUC --> INIT_FORTH --> WARM
137 TOS2WARM CALL #INIT_FORTH ; if +n SYS (+n odd) --> INIT_FORTH --> WARM
138 FWARM .word WARM ; no return
139 TOS2COLD MOV TOS,&USERSYS ;
140 ;*******************************************************************************
141 COLD ; <--- USER_NMI vector <--- <RESET> and <RESET> + <SW1> (DEEP_RESET)
142 ;*******************************************************************************
143 ; as pin RST is replaced by pin NMI, RESET by pin activation is redirected here via USER NMI vector
144 ; that allows actions to be performed before executing software BOR.
145 BIT.B #SW1,&SW1_IN ; <SW1> pressed ?
147 MOV #-1,&USERSYS ; yes, set negative value to force DEEP_RESET
148 DO_BOR MOV #0A504h,&PMMCTL0 ; ---------------------------> software_BOR --->+
149 ;******************************************************************************* |
150 RESET ; <-- RST vect. <-- SYS_failures PUC POR BOR <--+
151 ;*******************************************************************************
152 ; PUC 1: replace pin RESET by pin NMI, stops WDT_RESET
153 ;-------------------------------------------------------------------------------
154 BIS #1,&SFRRPCR ; pin RST becomes pin NMI with rising edge, so SYSRSTIV = 6
155 BIS #10h,&SFRIE1 ; enable NMI interrupt ==> hardware RESET is redirected to COLD.
156 MOV #5A80h,&WDTCTL ; disable WDT RESET
157 ;-------------------------------------------------------------------------------
159 ;-------------------------------------------------------------------------------
160 MOV #RSTACK,RSP ; init return stack
161 MOV #PSTACK,PSP ; init parameter stack
162 ;-------------------------------------------------------------------------------
163 ; PUC 3: I/O, RAM, RTC, CS, SYS initialisation limited to FastForth usage.
164 ; All unused I/O are set as input with pullup resistor.
165 ;-------------------------------------------------------------------------------
166 .include "TargetInit.asm" ; include target specific init code
167 ;-------------------------------------------------------------------------------
168 ; PUC 4: init RAM to 0
169 ;-------------------------------------------------------------------------------
170 MOV #RAM_LEN,X ; 2 RAM_LEN must be even and > 1, obviously.
171 INITRAMLOOP SUB #2,X ; 1
172 MOV #0,RAM_ORG(X) ; 3
173 JNZ INITRAMLOOP ; 2 6 cycles loop !
174 ; ;-------------------------------------------------------------------------------
175 ; ; PUC 5: GET SYSRSTIV and USERSYS
176 ; ;-------------------------------------------------------------------------------
177 ; MOV &SYSRSTIV,X ; X <-- SYSRSTIV <-- 0
178 ;-------------------------------------------------------------------------------
179 ; PUC 5: GET SYSUNIV_SYSSNIV_SYSRSTIV ( %0_UUU0_SSSS0_RRRRR0) and USERSYS
180 ;-------------------------------------------------------------------------------
181 MOV &SYSUNIV,X ; 0 --> SYSUNIV --> X (%0000_0000_0000_UUU0) (7 values)
182 RLAM #4,X ; make room for SYSSNIV (%0000_0000_UUU0_0000)
183 ADD X,X ; (%0000_000U_UU00_0000)
184 BIS &SYSSNIV,X ; 0 --> SYSSNIV --> X (%0000_000U_UU0S_SSS0) (15 values)
185 RLAM #4,X ; make room for SYSRSTIV(%000U_UU0S_SSS0_0000)
186 RLAM #2,X ; (%0UUU_0SSS_S000_0000)
187 BIS.B &SYSRSTIV,X ; 0 --> SYSRSTIV --> X (%0UUU_0SSS_S0RR_RRR0) (31 values)
188 ;-------------------------------------------------------------------------------
189 MOV &USERSYS,TOS ; TOS = USERSYS (FRAM)
190 MOV #0,&USERSYS ; and clear USERSYS
191 BIT.B #-1,TOS ; high byte reserved use
192 JNZ PUC6 ; if TOS <> 0, keep this USERSYS value
193 MOV X,TOS ; else TOS = SYSRSTIV
194 ;-------------------------------------------------------------------------------
195 ; PUC 6: START FORTH engine: WARM (BOOT)
196 ;-------------------------------------------------------------------------------
197 PUC6 CALL #INIT_FORTH ; common part of QABORT|PUC
198 PUCNEXT .word WARM ; no return. May be replaced by XBOOT by BOOT ;-)
199 ;-----------------------------------;
201 ;-------------------------------------------------------------------------------
202 ; INTERPRETER INPUT: ACCEPT KEY EMIT ECHO NOECHO
203 ;-------------------------------------------------------------------------------
206 ; ----------------------------------;
207 ;https://forth-standard.org/standard/core/ACCEPT
208 ;C ACCEPT addr addr len -- addr len' get a line from TERMINAL
209 ACCEPT MOV @PC+,PC ;3 Code Field Address (CFA) of ACCEPT
210 PFAACCEPT .word BODYACCEPT ; Parameter Field Address (PFA) of ACCEPT
211 ; ----------------------------------;
212 ; ACCEPT part I prepare TERMINAL_INT;
213 ; ----------------------------------;
214 BODYACCEPT MOV TOS,W ;1 -- org len W=len
215 MOV @PSP,TOS ;2 -- org ptr )
216 ADD TOS,W ;1 -- org ptr W=buf_end )
217 MOV #0Ah,T ;2 T = 'LF' to speed up char loop in part II > prepare stack and registers for TERMINAL_INT use
218 MOV #20h,S ;2 S = 'BL' to speed up char loop in part II )
219 PUSHM #4,IP ;6 PUSH IP,S,T,W R-- IP, 'BL', 'LF', buf_end )
221 ; here, FAST FORTH sleeps, waiting any interrupt. With LPM4, supply current is below 1uA.
222 ; IP,S,T,W,X,Y registers (R13 to R8) are free...
223 ; ...and also TOS, PSP and RSP stacks within their rules of use.
224 ;###################################################################################
225 BACKGRND CALL &BACKGRND_APP ; default BACKGRND_APP = INIT_BACKGRND = I2C_ACCEPT, value set by DEEP_RESET.
226 BIS &LPM_MODE,SR ;2 enter in LPM4 mode with GIE=1
227 JMP BACKGRND ;2 return for all interrupts.
228 ;###################################################################################
230 ; As TI says nothing about the reset of the UCSTTIFG flag by the I2C_Slave,
231 ; it is assumed that it clears it as soon as the first byte has been exchanged.
232 ; **********************************;
233 TERMINAL_INT ; <--- 80us <--- START interrupt vector, bus is stalled, I2C_Master waits ACK on address
234 ; **********************************;
235 ; ACCEPT part II wake on TERM_INT ; Org Ptr --
236 ; ----------------------------------;
237 ADD #4,RSP ;1 remove SR and PC from stack, SR flags are lost (unused by FORTH interpreter)
238 BIC #WAKE_UP,&TERM_IFG ; clear UCSTTIFG before return to BACKGRND if any (here, UCSTTIFG is not yet cleared !)
239 BIT #10h,&TERM_CTLW0 ;4 test UCTR
240 JNZ BACKGRND ; if Master RX loop back to BACKGRND
241 ACCEPT_YES POPM #4,IP ;6 POPM S=20h, T=0Ah, W=src_end, IP=ret_IP
242 QNEWCHAR BIT #RX_TERM,&TERM_IFG ;3 test RX BUF IFG
243 JZ QNEWCHAR ;2 wait RX BUF full
244 ; ----------------------------------;
245 AKEYREAD MOV.B &TERM_RXBUF,Y ;3 read char into Y, RX_IFG is cleared, bus unstalled by I2C_Slave
246 ; ----------------------------------;
247 CMP.B S,Y ;1 printable char ?
248 JC ASTORETEST ;2 jump if char U>= BL
249 CMP.B T,Y ;1 char = LF ?
250 JZ LF_NEXT ;2 jump if char = LF
251 ; ----------------------------------;
252 CMP.B #8,Y ; char = BS ?
253 JNZ QNEWCHAR ; case of all other control chars: skip them
254 ; ----------------------------------;
255 ; case of backspace ; made only by an human
256 ; ----------------------------------;
257 CMP @PSP,TOS ; Ptr = Org ?
258 JZ QNEWCHAR ; yes: does nothing
259 SUB #1,TOS ; no : dec Ptr
261 ; ----------------------------------;
262 ASTORETEST CMP W,TOS ; 1 end of buffer is reached ?
263 JC QNEWCHAR ; 2 yes: don't store char @ dst_Ptr, don't increment TOS
264 MOV.B Y,0(TOS) ; 3 no: store char @ dst_Ptr
265 ADD #1,TOS ; 1 increment dst_Ptr
267 ; ----------------------------------;
268 LF_NEXT BIT #10h,&TERM_CTLW0 ;4 test UCTR, instead of BUS idle because a ReSTART perhaps used by Master
269 JZ LF_NEXT ; wait until Master switched from TX to RX
270 ; ----------------------------------;
271 SUB @PSP+,TOS ; -- len'
272 MOV S,Y ; output a BL on TERMINAL (for the case of error occuring)
273 JMP QYEMIT ; before going to INTERPRET
274 ; **********************************;
277 ; ----------------------------------;
278 ; https://forth-standard.org/standard/core/KEY
279 ; KEY -- c wait character from input device ; primary DEFERred word
280 KEY MOV @PC+,PC ; Code Field Address (CFA) of KEY
281 PFAKEY .word BODYKEY ; Param Field Address (PFA) of KEY, with its default value
282 BODYKEY PUSH #KEYNEXT ;
283 MOV.B #1,Y ; KEY request Ctrl_Char = $01
284 ; ----------------------------------;
285 I2C_CTRL_CH BIT #TX_TERM,&TERM_IFG ; send it to I2C_Master_RX to restart it in TX mode
286 JZ I2C_CTRL_CH ; wait TX buffer empty
287 MOV.B Y,&TERM_TXBUF ; send Ctrl_Char
289 ; ----------------------------------;
290 KEYNEXT SUB #2,PSP ;1 push old TOS..
291 MOV TOS,0(PSP) ; ..onto stack
292 BKEYLOOP BIT #RX_TERM,&TERM_IFG ; received char ?
293 JZ BKEYLOOP ; wait char received
294 MOV &TERM_RXBUF,TOS ; -- char
295 CALL #I2C_ACCEPT ; send Ctrl_Char $00 to I2C_Master to restart its UART in TX mode
296 BKEYEND MOV @IP+,PC ; -- char
297 ; ----------------------------------;
300 ; ----------------------------------;
301 ; https://forth-standard.org/standard/core/EMIT
302 ; EMIT c -- output character to an output device ; primary DEFERred word
303 EMIT MOV @PC+,PC ;3 Code Field Address (CFA) of EMIT
304 PFAEMIT .word BODYEMIT ; Parameter Field Address (PFA) of EMIT, with its default value
305 BODYEMIT MOV TOS,Y ;1 sends character to the default output TERMINAL
307 QYEMIT BIT #TX_TERM,&TERM_IFG ;3 NOECHO stores here : MOV @IP+,PC, ECHO store here the first word of: BIT #TX_TERM,&TERM_IFG
308 JZ QYEMIT ;2 wait TX buffer empty
309 MOV.B Y,&TERM_TXBUF ;3
310 MOV @IP+,PC ;4 11 words
311 ; ----------------------------------;
313 FORTHWORD "ECHO" ; -- connect EMIT to TERMINAL (default)
314 ;-----------------------------------;
315 ECHO MOV #0B3A2h,&QYEMIT ; MOV #'BIT #TX_TERM,0(PC)',&QYEMIT
316 MOV.B #5,Y ; ECHO request Ctrl_Char = $05
317 ECHOEND CALL #I2C_CTRL_CH ;
319 ; ----------------------------------;
321 FORTHWORD "NOECHO" ; -- disconnect TERMINAL from EMIT
322 ;-----------------------------------;
323 NOECHO MOV #4D30h,&QYEMIT ; MOV #'MOV @IP+,PC',&QYEMIT
324 MOV.B #4,Y ; NOECHO request Ctrl_Char = $04
326 ; ----------------------------------;