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 BIC #UCTXACK,&UCB0CTLW0 \ send Nack address
136 \ --------------------------------------\
137 \ It's my own address \
138 \ --------------------------------------\
139 BIS #UCTXACK,&UCB0CTLW0 \ send software Ack address
140 BIT #UCTR,&UCB0CTLW0 \ test UCB0CTLW0(UCTR) R/W bit
141 0= IF \ I2C_Master Write
142 \ ------------------------------\
143 \ slave receive datas \ yes
144 \ ------------------------------\
145 MOV S,W \ W = input buffer address - 1
147 \ --------------------------\
148 \ slave receive one byte \
149 \ --------------------------\
151 BIT #$8C,&UCB0IFG \ UCB0IFG(STP,STT,CLTO) = 1 ? (STOP, START, SCL low timeout)
153 \ ------------------\
154 \ TX stop or restart\ from master
155 \ ------------------\
156 SUB S,W \ W = Adr_end - Adr_start = length
157 MOV.B W,0(T) \ store length in first byte of buffer output
158 \ --------------------\
159 \ here your RX process\
160 \ --------------------\
163 \ --------------------\
164 \ end of RX process \
165 \ --------------------\
167 THEN \ if not (stop, restart, CLTO)
168 BIT #1,&UCB0IFG \ UCB0IFG(RX0) = 1 ?
170 ADD #1,W \ reserve one byte for length first, then preincrement
171 MOV.B &UCB0RXBUF,0(W) \ [UCB0RXBUF] = data --> +[W]
172 AGAIN \ loop for new received data if any
173 THEN \ end of I2C_Master read
174 \ ------------------------------------\
175 \ slave transmit datas variant 1 \ to loop back after bad_own_address code
176 \ ------------------------------------\
179 \ ------------------------------------\
180 \ slave transmit datas variant 2 \
181 \ ------------------------------------\
182 \ MOV T,W \ W = output buffer address -1
184 \ ADD #1,W \ first reserve one byte for length
185 \ MOV.B @W,&UCB0TXBUF \ +[W] --> UCB0TXBUF
186 \ \ ----------------------------\
187 \ \ slave send byte \
188 \ \ ----------------------------\
190 \ BIT.B #$0C,&UCB0IFG \ UCB0IFG(STP,STT) = 1 ?
192 \ \ ------------------------\
193 \ \ RX stop or restart \ from master
194 \ \ ------------------------\
195 \ SUB T,W \ W = Adr_end - Adr_start = length
196 \ SUB.B #1,W \ sub #1, because char +[W] is not sent
197 \ MOV.B W,0(T) \ store length in first byte of buffer output
198 \ BIC.B #UCTR,&UCB0CTLW0 \ reset UCTR R/W bit for next START
201 \ BIT.B #$02,&UCB0IFG \ UCB0IFG(TX0) = 1 ?
204 \ ------------------------------------\
205 \ End of slave transmit datas variants\
206 \ ------------------------------------\
207 THEN \ if bad I2C address
208 \ --------------------------------------\
209 \ BAD I2C ADDRESS CaseOf \
210 \ --------------------------------------\
211 \ insert here post BAD I2C address code \
212 \ ...that can loop back to I2CS_TX... \
213 \ --------------------------------------\
217 \ --------------------------------------\
218 CODE START \ init I2C_slave
219 \ --------------------------------------\
220 \ UCB0CTLW0 = %0000 0111 1100 0001 $640
221 \ - UCMST = 0 : I2C_Slave
222 \ -- UCMODE = %11 = I2C
223 \ _ USYNC=1 (always 1)
224 \ -- UCSSEL=SMCLK (don't care in slave mode)
225 \ - UCTXACK=0 not auto ACK slave address
226 \ - UCTR=0 : RX (for RX address)
228 \ UCB0CTLW1 = %0000 0000 1101 0000 $642
229 \ - UCETXINT=0 : UCTXIFG0 set address match UCxI2COAx and TX mode
230 \ -- UCCLTO=%11 : SCL low time out = 34 ms
231 \ - UCSWACK=1 : UCTXACK must be written to continue
234 \ UCB0I2COA0 $654 must be written ? enabled ?
237 \ UCB0IE = %0000 0000 0000 0100 $66A
238 \ - UCSTTIE : StartCond Interrupt only
240 \ UCB0IV $66E : write it to clear all IFG
242 \ ------------------------------\
244 MOV #1,&UCB0CTLW0 \ set eUSCI_B in reset state, clear UCB0IE & UCB0IFG all flags
245 BIS #$07A0,&UCB0CTLW0 \
246 BIS #$10,&UCB0CTLW1 \ set software ack address (UCSWACK=1)
247 MOV #%1010,&UCB0I2COA0 \ set my own address
248 BIS #$0400,&UCB0I2COA0 \ UCOAEN=1 enable UCB0I2COA0 with address slave
249 \ MOV #0,&UCB0ADDMSK \ enable address mask for all addresses i.e. software address
250 BIC #1,&UCB0CTLW0 \ activate eUSCI_B (UCSWACK release)
251 MOV #4,&UCB0IE \ enable StartCond interrupt; WARNING ! UCB0IE must be set only after UCSWACK release !
252 \ ------------------------------\
253 \ init interrupt vectors
254 MOV #I2C_S,&$FFEE \ eUSCIB0 interrupt vector
255 \ ------------------------------\
256 \ init PORTA (P2:P1) (complement)
257 \ notice : UCB0 I2C driver seems to control only DIR register !!!
258 BIC.B #S_BUS,&I2CS_REN \ SDA + SCL pullup/down disable
259 BIC.B #S_BUS,&I2CS_OUT \ OUT0 : preset output low
260 BIS.B #S_BUS,&I2CS_SEL1 \ enable I2C I/O
261 \ ------------------------------\
263 ." I2C_Slave is running. Type STOP to quit"
264 LIT recurse is WARM \ insert this routine between COLD and WARM...
265 (WARM) ; \ ...and continue with WARM
268 : STOP \ stops multitasking, must to be used before downloading app
269 ['] (WARM) IS WARM \ remove START app from FORTH init process
270 ECHO COLD \ reset CPU, interrupt vectors, and start FORTH