1 \ name : MSP430FR5xxx_I2C_Slave.f
5 \ Copyright (C) <2015> <J.M. THOORENS>
7 \ This program is free software: you can redistribute it and/or modify
8 \ it under the terms of the GNU General Public License as published by
9 \ the Free Software Foundation, either version 3 of the License, or
10 \ (at your option) any later version.
12 \ This program is distributed in the hope that it will be useful,
13 \ but WITHOUT ANY WARRANTY\ without even the implied warranty of
14 \ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 \ GNU General Public License for more details.
17 \ You should have received a copy of the GNU General Public License
18 \ along with this program. If not, see <http://www.gnu.org/licenses/>.
20 \ driver I2C SLAVE with START interrupt only, for any I2C_Slave addresses
21 \ Target: MSP430FR5xxx @ 8,16,24 MHz
22 \ version 1.0 2015-03-17
24 \ ---------------------------------------------------------------------------------------------------------------------;
25 \ SCL clock generation, timing, and test of data(s) number are made by I2C_Master.
26 \ slave can strech SCL low after Start Condition and after any bit.
28 \ address Ack/Nack is generated by the slave on SDA line (released by the master)
29 \ Two groups of eight addresses (000$xxy and 1111xxxy) are not allowed (reserved)
30 \ after address or data is sent, the transmitter (Master or Slave) must release SDA line to allow (N)Ack by the receiver
31 \ data Ack/Nack are generated by the receiver (master or slave) on SDA line
32 \ a master receiver must signal the end of data to the slave transmitter by sending a Nack bit
33 \ Stop or restart conditions must be generated by master after a Nack bit.
34 \ after Ack bit is sent, Slave must release SDA line to allow master to do stop or restart conditions
36 \ __ _____ _____ _..._ _____ _____ _NACK _____ _____ _..._ _____ _____ _NACK _
37 \ SDA \____/_MSB_X_____X_..._X_LSB_X_R/W_x_ACK_x_MSB_X_____X_..._X_____X_LSB_X_ACK_X___/
38 \ _____ _ _ _ _ _ _ _ _ _ _ ___
39 \ SCL \___/1\___/2\___...___/7\___/8\___/9\___/1\___/2\___...___/7\___/8\___/9\___/
41 \ | |Slave Stretch Low |SSL |SSL |SSL |SSL |
43 \ |Start Condition |stoP Condition
45 \ __ _____ _____ _..._ _____ _____ _NACK _____ _____ _..._ _____ _____ _NACK ___
46 \ SDA \____/_MSB_X_____X_..._X_LSB_X_R/W_x_ACK_x_MSB_X_____X_..._X_____X_LSB_X_ACK_X \____...
47 \ _____ _ _ _ _ _ _ _ _ _ _ ____
48 \ SCL \___/1\___/2\___...___/7\___/8\___/9\___/1\___/2\___...___/7\___/8\___/9\___/ \_...
50 \ | |Slave Stretch Low |SSL |SSL |SSL |SSL |
52 \ |Start Condition |reStart Condition
54 \ tHIGH : SCL high time
56 \ tBUF : SDA high time between Stop and Start conditions
57 \ tHD:STA : Start_Condition SCL high time after SDA is low
58 \ tSU:STO : Stop_Condition SCL high time before SDA rise
59 \ tSU:STA : Start_Condition SCL high time before SDA fall
60 \ tHD:DAT : SDA data change time after SCL is low
61 \ the SDA line must be strobe just after SCL is high
62 \ the SDA data must be change just after SCL is low
63 \ standard mode (up to 100 kHz) : tHIGH = tHD:STA = tSU:STO = 4µs
64 \ tLOW = tSU:STA = tBUF = 4,7µs
67 \ fast mode (up to 400 kHz) : tHIGH = tHD:STA = tSU:STO = 0,6µs
68 \ tLOW = tSU:STA = tBUF = 1,3µs
70 \ -------------------------------------------------------------------------------------------------------------------;
74 VARIABLE I2CS_OWN \ slave I2C address without RW flag (low byte) + DATA0 input (HIGH byte)
75 \ 2 ALLOT \ next the low byte of I2CS_OWN word, it is the input buffer
76 VARIABLE I2CS_BUF \ buffer output, lentgh (low byte),DATA0 output (HIGH byte)
77 \ 2 ALLOT \ this byte lentgh is shared by input and output buffers
79 \ ******************************\
80 ASM I2CS_TX \ TX part of I2C_Slave
81 \ ******************************\
83 \ \ use W = TX buffer_ptr
84 \ \ out : low(I2CS_BUF) = RX or TX lentgh
85 \ ------------------------------\
86 MOV T,W \ W = TX_buf_ptr -1
88 ADD #1,W \ first reserve one byte for length then inc
89 MOV.B @W,&UCB0TXBUF \ +[W] --> UCB0TXBUF
90 \ ----------------------------\
92 \ ----------------------------\
94 BIT #$0C,&UCB0IFG \ UCB0IFG(STP,STT) = 1 ?
96 \ --------------------\
97 \ stop or restart received
98 \ --------------------\
100 SUB.B #1,W \ sub #1, because char +[W] is not sent
101 MOV.B W,0(T) \ store length in first byte of buffer output
102 BIC #UCTR,&UCB0CTLW0 \ reset UCTR R/W bit for next START
103 MOV @RSP+,PC \ ===> ret
104 \ --------------------\
106 BIT #2,&UCB0IFG \ UCB0IFG(TX0) = 1 ?
112 \ -------------+------+------+------+------++---+---+---+---+---------+
113 \ SR(low byte) | SCG1 | SCG0 |OSCOFF|CPUOFF||GIE| N | Z | C | current |
114 \ -------------+------+------+------+------++---+---+---+---+---------+
115 \ LPM0 = $18 | 0 | 0 | 0 | 1 || 1 | x | x | x | 180uA | default mode
116 \ LPM1 = $58 | 0 | 1 | 0 | 1 || 1 | x | x | x | | same mode as LPM0
117 \ LPM2 = $98 | 1 | 0 | 0 | 1 || 1 | x | x | x | 60uA |
118 \ LPM3 = $D8 | 1 | 1 | 0 | 1 || 1 | x | x | x | 10uA | 32768Hz XTAL is running
119 \ LPM4 = $F8 | 1 | 1 | 1 | 1 || 1 | x | x | x | 6uA |
120 \ -------------+------+------+------+------++---+---+---+---+---------+
122 \ **************************************\
123 ASM I2C_S \ <== eUSCIB0 interrupt vector : i2c_addres&R/w sent by master is received
124 \ **************************************\
125 BIC #$F8,0(RSP) \ SCG1,SCG0,OSCOFF,CPUOFF and GIE are OFF in retiSR to force LPM0_LOOP with pending interrupt
126 MOV #$98,&LPM_MODE \ to reenter in LPM2 mode. LPM3-4 don't work with MSP430FR57xx.
127 \ --------------------------------------\
128 MOV #I2CS_BUF,T \ T = buffer output address -1
129 MOV #I2CS_OWN,S \ S = buffer input address -1
130 MOV #0,&UCB0IFG \ write UCB0IFG to clear all int flags (STTIFG,TXIFG,..)
131 CMP.B &UCB0I2COA0,&UCB0ADDRX \ UCB0ADDRX = own address ?
133 \ --------------------------------------\
134 \ It's my own address \
135 \ --------------------------------------\
136 BIS #UCTXACK,&UCB0CTLW0 \ send software Ack address
137 BIT #UCTR,&UCB0CTLW0 \ test UCB0CTLW0(UCTR) R/W bit
138 0= IF \ I2C_Master Write
139 \ --------------------------------\
140 \ slave receive datas \ yes
141 \ --------------------------------\
142 MOV S,W \ W = input buffer address - 1
144 \ ----------------------------\
145 \ slave receive one byte \
146 \ ----------------------------\
148 BIT #$8C,&UCB0IFG \ UCB0IFG(STP,STT,CLTO) = 1 ? (STOP, START, SCL low timeout)
150 \ --------------------\
151 \ TX stop or restart \ from master
152 \ --------------------\
153 SUB S,W \ W = Adr_end - Adr_start = length
154 MOV.B W,0(T) \ store length in first byte of buffer output
155 \ --------------------\
156 \ insert here post RX code
157 \ --------------------\
159 THEN \ if not (stop, restart, CLTO)
160 BIT #1,&UCB0IFG \ UCB0IFG(RX0) = 1 ?
162 ADD #1,W \ reserve one byte for length first, then preincrement
163 MOV.B &UCB0RXBUF,0(W) \ [UCB0RXBUF] = data --> +[W]
164 AGAIN \ loop for new received data if any
165 THEN \ end of I2C_Master read
166 \ ------------------------------------\
167 \ slave transmit datas variant 1 \ to loop back after bad_own_address code
168 \ ------------------------------------\
171 \ ------------------------------------\
172 \ slave transmit datas variant 2 \
173 \ ------------------------------------\
174 \ MOV T,W \ W = output buffer address -1
176 \ ADD #1,W \ first reserve one byte for length
177 \ MOV.B @W,&UCB0TXBUF \ +[W] --> UCB0TXBUF
178 \ \ ----------------------------\
179 \ \ slave send byte \
180 \ \ ----------------------------\
182 \ BIT.B #$0C,&UCB0IFG \ UCB0IFG(STP,STT) = 1 ?
184 \ \ ------------------------\
185 \ \ RX stop or restart \ from master
186 \ \ ------------------------\
187 \ SUB T,W \ W = Adr_end - Adr_start = length
188 \ SUB.B #1,W \ sub #1, because char +[W] is not sent
189 \ MOV.B W,0(T) \ store length in first byte of buffer output
190 \ BIC.B #UCTR,&UCB0CTLW0 \ reset UCTR R/W bit for next START
193 \ BIT.B #$02,&UCB0IFG \ UCB0IFG(TX0) = 1 ?
196 \ ------------------------------------\
197 \ End of slave transmit datas variants\
198 \ ------------------------------------\
199 THEN \ if bad I2C address
200 \ --------------------------------------\
201 \ BAD I2C ADDRESS CaseOf \
202 \ --------------------------------------\
203 \ insert here post BAD I2C address code \
204 \ ...that can loop back to I2CS_TX... \
205 \ --------------------------------------\
206 BIC #UCTXACK,&UCB0CTLW0 \ send Nack address
211 \ --------------------------------------\
212 CODE START \ init I2C_slave
213 \ --------------------------------------\
214 \ UCB0CTLW0 = %0000 0111 1100 0001 $640
215 \ - UCMST = 0 : I2C_Slave
216 \ -- UCMODE = %11 = I2C
217 \ _ USYNC=1 (always 1)
218 \ -- UCSSEL=SMCLK (don't care in slave mode)
219 \ - UCTXACK=0 not auto ACK slave address
220 \ - UCTR=0 : RX (for RX address)
222 \ UCB0CTLW1 = %0000 0000 1101 0000 $642
223 \ - UCETXINT=0 : UCTXIFG0 set address match UCxI2COAx and TX mode
224 \ -- UCCLTO=%11 : SCL low time out = 34 ms
225 \ - UCSWACK=1 : UCTXACK must be written to continue
228 \ UCB0I2COA0 $654 must be written ? enabled ?
231 \ UCB0IE = %0000 0000 0000 0100 $66A
232 \ - UCSTTIE : StartCond Interrupt only
234 \ UCB0IV $66E : write it to clear all IFG
236 \ ------------------------------\
238 MOV #1,&UCB0CTLW0 \ set eUSCI_B in reset state, clear UCB0IE & UCB0IFG all flags
239 BIS #$07A0,&UCB0CTLW0 \
240 BIS #$10,&UCB0CTLW1 \ set software ack address (UCSWACK=1)
241 MOV #%1010,&UCB0I2COA0 \ set my own address
242 BIS #$0400,&UCB0I2COA0 \ UCOAEN=1 enable UCB0I2COA0 with address slave
243 \ MOV #0,&UCB0ADDMSK \ enable address mask for all addresses i.e. software address
244 BIC #1,&UCB0CTLW0 \ activate eUSCI_B
245 MOV #4,&UCB0IE \ enable StartCond interrupt
246 \ ------------------------------\
247 \ init interrupt vectors
248 MOV #I2C_S,&$FFEE \ eUSCIB0 interrupt vector
249 \ ------------------------------\
250 \ init PORTA (P2:P1) (complement)
251 \ notice : UCB0 I2C driver seems to control only DIR register !!!
252 BIC.B #S_BUS,&I2CS_REN \ SDA + SCL pullup/down disable
253 BIC.B #S_BUS,&I2CS_OUT \ OUT0 : preset output low
254 BIS.B #S_BUS,&I2CS_SEL1 \ enable I2C I/O
255 \ ------------------------------\
257 ." I2C_Slave is running. Type STOP to quit"
258 LIT recurse is WARM \ insert this routine between COLD and WARM...
259 (WARM) ; \ ...and continue with WARM
262 : STOP \ stops multitasking, must to be used before downloading app
263 ['] (WARM) IS WARM \ remove START app from FORTH init process
264 ECHO COLD \ reset CPU, interrupt vectors, and start FORTH