1 ; I2C (TWI) master interface.
2 ; This is part of the Z80-CP/M emulator written by Sprite_tm.
4 ; Copyright (C) 2013 Leo C.
6 ; This file is part of avrcpm.
8 ; avrcpm is free software: you can redistribute it and/or modify it
9 ; under the terms of the GNU General Public License as published by
10 ; the Free Software Foundation, either version 3 of the License, or
11 ; (at your option) any later version.
13 ; avrcpm is distributed in the hope that it will be useful,
14 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ; GNU General Public License for more details.
18 ; You should have received a copy of the GNU General Public License
19 ; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
21 ; $Id: i2c.asm 242 2015-12-11 16:05:52Z rapid $
27 /* General TWI Master status codes */
28 #define TWI_START 0x08 /* START has been transmitted */
29 #define TWI_REP_START 0x10 /* Repeated START has been transmitted */
30 #define TWI_ARB_LOST 0x38 /* Arbitration lost */
32 /* TWI Master Transmitter status codes */
33 #define TWI_MTX_ADR_ACK 0x18 /* SLA+W has been transmitted and ACK received */
34 #define TWI_MTX_ADR_NACK 0x20 /* SLA+W has been transmitted and NACK received */
35 #define TWI_MTX_DATA_ACK 0x28 /* Data byte has been transmitted and ACK received */
36 #define TWI_MTX_DATA_NACK 0x30 /* Data byte has been transmitted and NACK received */
38 /* TWI Master Receiver status codes */
39 #define TWI_MRX_ADR_ACK 0x40 /* SLA+R has been transmitted and ACK received */
40 #define TWI_MRX_ADR_NACK 0x48 /* SLA+R has been transmitted and NACK received */
41 #define TWI_MRX_DATA_ACK 0x50 /* Data byte has been received and ACK transmitted */
42 #define TWI_MRX_DATA_NACK 0x58 /* Data byte has been received and NACK transmitted */
44 /* TWI Miscellaneous status codes */
45 #define TWI_NO_STATE 0xF8 /* No relevant state information available */
46 #define TWI_BUS_ERROR 0x00 /* Bus error due to an illegal START or STOP condition */
49 #define I2C_BR ((F_CPU / (2 * I2C_CLOCK)) - 8) /* I2C Bit Rate */
51 ;----------------------------------------------------------------------
53 ; TWINT: TWI Interrupt Flag
54 ; TWEA: TWI Enable Acknowledge Bit
55 ; TWSTA: TWI START Condition Bit
56 ; TWSTO: TWI STOP Condition Bit
57 ; TWEN: TWI Enable Bit
58 ; TWIE: TWI Interrupt Enable
60 ; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
61 ; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)| (1<<TWEA)
62 ; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
65 ; (1<<TWEN)| (1<<TWINT)| (1<<TWSTO)
71 ; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
72 ; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
73 ; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
74 ; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
77 ; (1<<TWIE)|(1<<TWSTO)
79 ;----------------------------------------------------------------------
83 ; 0b10000000 Busy (Transmission in progress)
85 ; 0b00010000 Read after Write
86 ; 0b00001000 Start transmitted
87 ; 0b00000100 Slave acknowledged address
88 ; 0b00000010 Data byte(s) transmitted/received
89 ; 0b00000001 Transmission completed
92 ;----------------------------------------------------------------------
114 ;------------------------------------------------------------------
134 ldd temp2,z+oi2ci_idx
135 ldd temp3,z+oi2c_result
139 cpi temp,TWI_REP_START
141 cpi temp,TWI_MTX_ADR_ACK
142 breq i2ci_MTX_ADR_ACK
143 cpi temp,TWI_MTX_DATA_ACK
144 breq i2ci_MTX_DATA_ACK
145 cpi temp,TWI_MTX_DATA_NACK
146 breq i2ci_MTX_DATA_NACK
147 cpi temp,TWI_MRX_ADR_ACK
148 breq i2ci_MRX_ADR_ACK
149 cpi temp,TWI_MRX_DATA_ACK
150 breq i2ci_MRX_DATA_ACK
151 cpi temp,TWI_MRX_DATA_NACK
152 breq i2ci_MRX_DATA_NACK
156 i2ci_REP_START: ;Repeated START has been transmitted
158 i2ci_START: ;START has been transmitted
159 clr temp2 ;reset buffer index
162 i2ci_MTX_ADR_ACK: ;SLA+W has been transmitted and ACK received
165 i2ci_MTX_DATA_ACK: ;Data byte has been transmitted and ACK received
168 ldd temp,z+oi2c_txcnt
169 cp temp2,temp ;all bytes transmited?
174 ldd temp,z+oi2c_buf ;next byte
176 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)
179 i2ci_MTX_DATA_NACK: ;Data byte has been transmitted and NACK received
181 ori temp3,0b00000001 ;tx complete
182 sbrs temp3,4 ;Read after Write?
183 rjmp i2ci_default ; no, stop transceiver
186 sbr temp,0x01 ;<SLA+R>
188 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
191 i2ci_MRX_ADR_ACK: ;SLA+R has been transmitted and ACK received
195 i2ci_MRX_DATA_ACK: ;Data byte has been received and ACK transmitted
207 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)
210 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)
213 i2ci_MRX_DATA_NACK: ;Data byte has been received and NACK transmitted
214 ori temp3,0b00000011 ;rx complete
223 andi temp3,~0b10000000
224 ldi temp,(1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO)
248 ;------------------------------------------------------------------
251 outm8 TWCR,_0 ;Disable TWI, disable TWI interrupt.
252 ;(Reset TWI hardware state machine.)
253 ldi temp,(5 * TC_1US+3)/3 ;1 Delay 5 us
261 ldi temp,(1<<TWEN) ;Enable TWI, disable TWI interrupt.
268 ;------------------------------------------------------------------
273 sts delay_timer1,temp
276 andi temp,(1<<TWIE)|(1<<TWSTO)
278 lds temp,delay_timer1
292 ;------------------------------------------------------------------
294 ; z: Pointer to the data to write.
295 ; First byte is slave address
296 ; temp2: Number of bytes to write including address byte.
311 std y+oi2c_result,temp ;result = busy
312 std y+oi2c_txcnt,temp2 ;store size
323 ; Enable TWI, TWI int and initiate start condition
324 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
335 ;------------------------------------------------------------------
337 ; z: Pointer to data buffer.
338 ; First byte of buffer is slave address
339 ; temp2: Buffer len. (Number of bytes to read + address byte.)
341 ; temp: return (fail < 0, else succsess)
354 std y+oi2c_result,temp ;result = busy
355 std y+oi2c_rxcnt,temp2 ;store size
357 sbr temp,0x01 ;<SLA+R>
360 ; Enable TWI, TWI int and initiate start condition
361 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
366 sbrs temp,1 ;at least 1 byte received
368 ldd temp2,y+oi2ci_idx
385 ;------------------------------------------------------------------
387 ; z: Pointer to the data to write/read.
388 ; First byte is slave address
389 ; temp2: Number of bytes to read, including address byte.
404 std y+oi2c_result,temp ;result = busy
406 std y+oi2c_txcnt,temp ;store tx size
407 std y+oi2c_rxcnt,temp2 ;store rx size
410 mov _tmp0,temp ;save tx count
420 ; Enable TWI, TWI int and initiate start condition
421 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
428 sbrs temp,1 ;at least 1 byte received
431 ldd temp2,y+oi2ci_idx
453 ;------------------------------------------------------------------
492 ;------------------------------------------------------------------
494 ; vi2c_addr: Pointer to the data to write.
495 ; First byte is slave address
496 ; vi2c_blen: Number of bytes to write including address byte.
506 std z+oi2c_result,temp ;result = busy
508 cpi temp3,I2C_BUFSIZE
510 ldi temp3,I2C_BUFSIZE
512 std z+oi2c_txcnt,temp3 ;store size
524 ; Enable TWI, TWI int and initiate start condition
525 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
530 ;------------------------------------------------------------------
532 ; x: Pointer to the data buffer.
533 ; First byte is slave address
534 ; temp3: Buffer len. (Number of bytes to read + address byte.)
545 std z+oi2c_result,temp ;result = busy
547 cpi temp3,I2C_BUFSIZE
549 ldi temp3,I2C_BUFSIZE
551 std z+oi2c_rxcnt,temp3 ;store size
559 ; Enable TWI, TWI int and initiate start condition
560 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
575 ;------------------------------------------------------------------
577 ; vi2c_addr: Pointer to the data to write.
578 ; First byte is slave address
579 ; temp2: Number of bytes to write including address byte.
581 ; vi2c_blen: Number of bytes to read including address byte.
591 std z+oi2c_result,temp ;result = busy
592 std z+oi2c_txcnt,temp2 ;store tx size
594 cpi temp3,I2C_BUFSIZE
596 ldi temp3,I2C_BUFSIZE
598 std z+oi2c_rxcnt,temp3 ;store rx size
610 ; Enable TWI, TWI int and initiate start condition
611 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
618 andi temp,0b00000011 ;
621 ldd temp2,z+oi2ci_idx
636 ;------------------------------------------------------------------
649 cpi temp,3 ;write and read ?
651 ldi temp2,2 ;write 1 byte (subaddress), then read
657 ;------------------------------------------------------------------
661 ; make a buffer on stack
662 push _255 ;place holder for input value
665 ldi temp,0x20 ;pcf8574 address (7 bit)
668 push temp ;slave address
671 pop temp ;remove slave address from stack
672 pop temp ;return input value
676 ; make a buffer on stack
677 push temp ;output value
680 ldi temp,0x20 ;pcf8574 address (7 bit)
683 push temp ;slave address
686 pop temp ;remove buffer from stack
691 ;------------------------------------------------------------------
696 ; make a buffer on stack
699 push temp3 ;register address
702 ldi temp,SC16IS740_ADDR ;chip address (8 bit)
703 push temp ;slave address
706 pop temp ;remove slave address from stack
707 pop temp ;return input value
711 ; make a buffer on stack
712 push temp ;output value
715 push temp3 ;register address
718 ldi temp,SC16IS740_ADDR ;chip address (8 bit)
719 push temp ;slave address
722 pop temp ;remove buffer from stack
727 #endif /* I2C_UART_SUPPORT */
729 #endif /* I2C_SUPPORT */
730 ;------------------------------------------------------------------
731 ; vim:set ts=8 noet nowrap