]> cloudbase.mooo.com Git - avrcpm.git/blame_incremental - avr/i2c.asm
SVN --> GIT
[avrcpm.git] / avr / i2c.asm
... / ...
CommitLineData
1; I2C (TWI) master interface.
2; This is part of the Z80-CP/M emulator written by Sprite_tm.
3;
4; Copyright (C) 2013 Leo C.
5;
6; This file is part of avrcpm.
7;
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.
12;
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.
17;
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/>.
20;
21; $Id: i2c.asm 242 2015-12-11 16:05:52Z rapid $
22;
23
24#if I2C_SUPPORT
25
26
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 */
31
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 */
37
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 */
43
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 */
47
48
49#define I2C_BR ((F_CPU / (2 * I2C_CLOCK)) - 8) /* I2C Bit Rate */
50
51;----------------------------------------------------------------------
52;
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
59;
60; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
61; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)| (1<<TWEA)
62; (1<<TWEN)|(1<<TWIE)|(1<<TWINT)
63;
64; default:
65; (1<<TWEN)| (1<<TWINT)| (1<<TWSTO)
66;
67; Init:
68; (1<<TWEN)
69;
70; start read/write:
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)
75;
76; wait ready:
77; (1<<TWIE)|(1<<TWSTO)
78;
79;----------------------------------------------------------------------
80;
81;i2c_result
82;
83; 0b10000000 Busy (Transmission in progress)
84; 0b01000000 Timeout
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
90;
91;
92;----------------------------------------------------------------------
93
94 .dseg
95
96i2c_var:
97i2ci_idx:
98 .byte 1
99i2c_result:
100 .byte 1
101i2c_txcnt:
102 .byte 1
103i2c_rxcnt:
104 .byte 1
105i2c_buf:
106 .byte I2C_BUFSIZE
107
108 .equ oi2ci_idx = 0
109 .equ oi2c_result = 1
110 .equ oi2c_txcnt = 2
111 .equ oi2c_rxcnt = 3
112 .equ oi2c_buf = 4
113
114;------------------------------------------------------------------
115
116 .cseg
117
118
119 INTERRUPT TWIaddr
120
121 push temp
122 in temp,sreg
123 push temp
124 inm8 temp,TWSR
125.if I2C_STATE_DEBUG
126 push temp
127.endif
128 push temp2
129 push temp3
130 push zh
131 push zl
132
133 ldiw z,i2c_var
134 ldd temp2,z+oi2ci_idx
135 ldd temp3,z+oi2c_result
136
137 cpi temp,TWI_START
138 breq i2ci_START
139 cpi temp,TWI_REP_START
140 breq i2ci_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
153
154 rjmp i2ci_default
155
156i2ci_REP_START: ;Repeated START has been transmitted
157 cbr temp3,0b00010000
158i2ci_START: ;START has been transmitted
159 clr temp2 ;reset buffer index
160 ori temp3,0b10001000
161 rjmp i2ci_11
162i2ci_MTX_ADR_ACK: ;SLA+W has been transmitted and ACK received
163 ori temp3,0b00000100
164 rjmp i2ci_11
165i2ci_MTX_DATA_ACK: ;Data byte has been transmitted and ACK received
166 ori temp3,0b00000010
167i2ci_11:
168 ldd temp,z+oi2c_txcnt
169 cp temp2,temp ;all bytes transmited?
170 brsh i2ci_12 ; yes
171 add zl,temp2
172 adc zh,_0
173 inc temp2
174 ldd temp,z+oi2c_buf ;next byte
175 outm8 TWDR,temp
176 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)
177 rjmp i2ci_end
178
179i2ci_MTX_DATA_NACK: ;Data byte has been transmitted and NACK received
180i2ci_12:
181 ori temp3,0b00000001 ;tx complete
182 sbrs temp3,4 ;Read after Write?
183 rjmp i2ci_default ; no, stop transceiver
184
185 lds temp,i2c_buf
186 sbr temp,0x01 ;<SLA+R>
187 sts i2c_buf,temp
188 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
189 rjmp i2ci_end
190
191i2ci_MRX_ADR_ACK: ;SLA+R has been transmitted and ACK received
192 ori temp3,0b00000100
193 rjmp i2ci_31
194
195i2ci_MRX_DATA_ACK: ;Data byte has been received and ACK transmitted
196 ori temp3,0b00000010
197 add zl,temp2
198 adc zh,_0
199 inc temp2
200 inm8 temp,TWDR
201 std z+oi2c_buf,temp
202i2ci_31:
203 lds temp,i2c_rxcnt
204 dec temp
205 cp temp2,temp
206 brsh i2ci_32
207 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA)
208 rjmp i2ci_end
209i2ci_32:
210 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)
211 rjmp i2ci_end
212
213i2ci_MRX_DATA_NACK: ;Data byte has been received and NACK transmitted
214 ori temp3,0b00000011 ;rx complete
215 add zl,temp2
216 adc zh,_0
217 inc temp2
218 inm8 temp,TWDR
219 std z+oi2c_buf,temp
220; fall thru
221
222i2ci_default:
223 andi temp3,~0b10000000
224 ldi temp,(1<<TWEN)|(0<<TWIE)|(1<<TWINT)|(1<<TWSTO)
225
226i2ci_end:
227 outm8 TWCR,temp
228 sts i2c_result,temp3
229 sts i2ci_idx,temp2
230 pop zl
231 pop zh
232 pop temp3
233 pop temp2
234
235.if I2C_STATE_DEBUG
236 ldi temp,'|'
237 sei
238 rcall uartputc
239 pop temp
240 rcall printhex
241.endif
242
243 pop temp
244 out sreg,temp
245 pop temp
246 reti
247
248;------------------------------------------------------------------
249
250i2c_init:
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
254i2c_iwl: ;
255 dec temp ;1
256 brne i2c_iwl ;2
257
258 ldi temp,I2C_BR
259 outm8 TWBR,temp
260 outm8 TWDR,_255 ;
261 ldi temp,(1<<TWEN) ;Enable TWI, disable TWI interrupt.
262 outm8 TWCR,temp
263
264; sts i2c_result,_0
265
266 ret
267
268;------------------------------------------------------------------
269
270i2c_waitready:
271
272 ldi temp,30
273 sts delay_timer1,temp
274i2c_wrl:
275 inm8 temp,TWCR
276 andi temp,(1<<TWIE)|(1<<TWSTO)
277 breq i2c_wre
278 lds temp,delay_timer1
279 tst temp
280 brne i2c_wrl
281
282 rcall i2c_init
283
284 ldi temp,0b01000000
285
286i2c_wre:
287 lds _tmp0,i2c_result
288 or temp,_tmp0
289 sts i2c_result,temp
290 ret
291
292;------------------------------------------------------------------
293;
294; z: Pointer to the data to write.
295; First byte is slave address
296; temp2: Number of bytes to write including address byte.
297;
298
299i2c_write:
300
301 rcall i2c_waitready
302 cpi temp,0b01000000
303 brsh i2c_we
304 push zh
305 push zl
306 push yh
307 push yl
308
309 ldiw y,i2c_var
310 ldi temp,0b10000000
311 std y+oi2c_result,temp ;result = busy
312 std y+oi2c_txcnt,temp2 ;store size
313 adiw y,oi2c_buf
314 ld temp,z+ ;get SLA
315 cbr temp,0x01 ;
316i2c_wl:
317 st y+,temp
318 dec temp2
319 breq i2c_wle
320 ld temp,z+
321 rjmp i2c_wl
322i2c_wle:
323 ; Enable TWI, TWI int and initiate start condition
324 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
325 outm8 TWCR,temp
326
327 pop yl
328 pop yh
329 pop zl
330 pop zh
331i2c_we:
332 ret
333
334
335;------------------------------------------------------------------
336;
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.)
340;
341; temp: return (fail < 0, else succsess)
342
343i2c_read:
344 rcall i2c_waitready
345 cpi temp,0b01000000
346 brsh i2c_re
347
348 push zh
349 push zl
350 push yh
351 push yl
352 ldiw y,i2c_var
353 ldi temp,0b10000000
354 std y+oi2c_result,temp ;result = busy
355 std y+oi2c_rxcnt,temp2 ;store size
356 ld temp,z
357 sbr temp,0x01 ;<SLA+R>
358 std y+oi2c_buf,temp
359
360 ; Enable TWI, TWI int and initiate start condition
361 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
362 outm8 TWCR,temp
363
364 rcall i2c_waitready
365
366 sbrs temp,1 ;at least 1 byte received
367 rjmp i2c_ex ;
368 ldd temp2,y+oi2ci_idx
369 adiw y,oi2c_buf
370i2c_rl:
371 ld _tmp0,y+
372 st z+,_tmp0
373 dec temp2
374 brne i2c_rl
375
376i2c_ex:
377 pop yl
378 pop yh
379 pop zl
380 pop zh
381i2c_re:
382 lds temp,i2c_result
383 ret
384
385;------------------------------------------------------------------
386;
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.
390;
391
392i2c_write_read:
393
394 rcall i2c_waitready
395 cpi temp,0b01000000
396 brsh i2c_wr_e
397 push yh
398 push yl
399 push zh
400 push zl
401
402 ldiw y,i2c_var
403 ldi temp,0b10010000
404 std y+oi2c_result,temp ;result = busy
405 ldi temp,2
406 std y+oi2c_txcnt,temp ;store tx size
407 std y+oi2c_rxcnt,temp2 ;store rx size
408 adiw y,oi2c_buf
409
410 mov _tmp0,temp ;save tx count
411 ld temp,z+ ;get SLA
412 cbr temp,0x01 ;
413i2c_wr_wl:
414 st y+,temp
415 dec _tmp0
416 breq i2c_wr_wle
417 ld temp,z+
418 rjmp i2c_wr_wl
419i2c_wr_wle:
420 ; Enable TWI, TWI int and initiate start condition
421 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
422 outm8 TWCR,temp
423
424 rcall i2c_waitready
425
426 sbrc temp,4 ;
427 rjmp i2c_wr_ex ;
428 sbrs temp,1 ;at least 1 byte received
429 rjmp i2c_wr_ex ;
430 ldiw y,i2c_var
431 ldd temp2,y+oi2ci_idx
432 adiw y,oi2c_buf
433 pop zl
434 pop zh
435 push zh
436 push zl
437i2c_wr_rl:
438 ld _tmp0,y+
439 st z+,_tmp0
440 dec temp2
441 brne i2c_wr_rl
442
443i2c_wr_ex:
444 pop zl
445 pop zh
446 pop yl
447 pop yh
448i2c_wr_e:
449 lds temp,i2c_result
450 ret
451
452
453;------------------------------------------------------------------
454
455 .dseg
456
457vi2c_stat:
458 .byte 1
459vi2c_blen:
460 .byte 1
461vi2c_addr:
462 .byte 2
463
464 .cseg
465
466vi2c_stat_get:
467 lds temp,i2c_result
468 ret
469
470vi2c_param_get:
471 tst temp3
472 brne vi2c_pg2
473
474 lds temp,i2ci_idx
475 rjmp vi2c_pge
476
477vi2c_pg2:
478 ldiw z,vi2c_blen
479 add zl,temp3
480 adc zh,_0
481 ld temp,z
482vi2c_pge:
483 ret
484
485vi2c_param_set:
486 ldiw z,vi2c_blen
487 add zl,temp3
488 adc zh,_0
489 st z,temp
490 ret
491
492;------------------------------------------------------------------
493;
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.
497;
498
499vi2c_write:
500
501 rcall i2c_waitready
502 cpi temp,0b01000000
503 brsh vi2c_wex
504 ldiw z,i2c_var
505 ldi temp,0b10000000
506 std z+oi2c_result,temp ;result = busy
507 lds temp3,vi2c_blen
508 cpi temp3,I2C_BUFSIZE
509 brlo vi2c_w1
510 ldi temp3,I2C_BUFSIZE
511vi2c_w1:
512 std z+oi2c_txcnt,temp3 ;store size
513 adiw z,oi2c_buf
514 ldsw x,vi2c_addr
515 lcall dram_read_pp
516 cbr temp,0x01
517vi2c_wl:
518 st z+,temp
519 dec temp3
520 breq vi2c_wle
521 lcall dram_read_pp
522 rjmp vi2c_wl
523vi2c_wle:
524 ; Enable TWI, TWI int and initiate start condition
525 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
526 outm8 TWCR,temp
527vi2c_wex:
528 ret
529
530;------------------------------------------------------------------
531;
532; x: Pointer to the data buffer.
533; First byte is slave address
534; temp3: Buffer len. (Number of bytes to read + address byte.)
535;
536
537vi2c_read:
538
539 rcall i2c_waitready
540 cpi temp,0b01000000
541 brsh vi2c_rex
542
543 ldiw z,i2c_var
544 ldi temp,0b10000000
545 std z+oi2c_result,temp ;result = busy
546 lds temp3,vi2c_blen
547 cpi temp3,I2C_BUFSIZE
548 brlo vi2c_r1
549 ldi temp3,I2C_BUFSIZE
550vi2c_r1:
551 std z+oi2c_rxcnt,temp3 ;store size
552 adiw z,oi2c_buf
553 ldsw x,vi2c_addr
554 lcall dram_read_pp
555 sbr temp,0x01
556 st z+,temp
557 dec temp3
558
559 ; Enable TWI, TWI int and initiate start condition
560 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
561 outm8 TWCR,temp
562
563 rcall i2c_waitready
564 andi temp,0b00000011
565 breq vi2c_rex ;
566vi2c_rl:
567 ld temp,z+
568 lcall dram_write_pp
569 dec temp3
570 brne vi2c_rl
571
572vi2c_rex:
573 ret
574
575;------------------------------------------------------------------
576;
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.
580;
581; vi2c_blen: Number of bytes to read including address byte.
582;
583
584vi2c_write_read:
585
586 rcall i2c_waitready
587 cpi temp,0b01000000
588 brsh vi2c_wr_ex
589 ldiw z,i2c_var
590 ldi temp,0b10010000
591 std z+oi2c_result,temp ;result = busy
592 std z+oi2c_txcnt,temp2 ;store tx size
593 lds temp3,vi2c_blen
594 cpi temp3,I2C_BUFSIZE
595 brlo vi2c_wr_w1
596 ldi temp3,I2C_BUFSIZE
597vi2c_wr_w1:
598 std z+oi2c_rxcnt,temp3 ;store rx size
599 adiw z,oi2c_buf
600 ldsw x,vi2c_addr
601 lcall dram_read_pp
602 cbr temp,0x01
603vi2c_wr_wl:
604 st z+,temp
605 dec temp2
606 breq vi2c_wr_wle
607 lcall dram_read_pp
608 rjmp vi2c_wr_wl
609vi2c_wr_wle:
610 ; Enable TWI, TWI int and initiate start condition
611 ldi temp,(1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA)
612 outm8 TWCR,temp
613
614 rcall i2c_waitready
615
616 sbrc temp,4 ;
617 rjmp i2c_wr_ex ;
618 andi temp,0b00000011 ;
619 breq vi2c_rex ;
620 ldiw z,i2c_var
621 ldd temp2,z+oi2ci_idx
622 adiw z,oi2c_buf+1
623 ldsw x,vi2c_addr
624 adiw x,1
625 rjmp vi2c_wr_rl0
626vi2c_wr_rl:
627 ld temp,z+
628 lcall dram_write_pp
629vi2c_wr_rl0:
630 dec temp2
631 brne vi2c_wr_rl
632
633vi2c_wr_ex:
634 ret
635
636;------------------------------------------------------------------
637
638
639vi2c_ctrl:
640 cpi temp,1 ;read ?
641 brne vi2c_c1
642 rjmp vi2c_read
643
644vi2c_c1:
645 cpi temp,2 ;write?
646 brne vi2c_c2
647 rjmp vi2c_write
648vi2c_c2:
649 cpi temp,3 ;write and read ?
650 brne vi2c_c3
651 ldi temp2,2 ;write 1 byte (subaddress), then read
652 rjmp vi2c_write_read
653vi2c_c3:
654vi2c_ce:
655 ret
656
657;------------------------------------------------------------------
658
659
660pcf8574_in:
661 ; make a buffer on stack
662 push _255 ;place holder for input value
663 in zh,sph
664 in zl,spl
665 ldi temp,0x20 ;pcf8574 address (7 bit)
666 add temp,temp3
667 lsl temp
668 push temp ;slave address
669 ldi temp2,2
670 rcall i2c_read
671 pop temp ;remove slave address from stack
672 pop temp ;return input value
673 ret
674
675pcf8574_out:
676 ; make a buffer on stack
677 push temp ;output value
678 in zh,sph
679 in zl,spl
680 ldi temp,0x20 ;pcf8574 address (7 bit)
681 add temp,temp3
682 lsl temp
683 push temp ;slave address
684 ldi temp2,2
685 rcall i2c_write
686 pop temp ;remove buffer from stack
687 pop temp ;
688 ret
689
690
691;------------------------------------------------------------------
692
693#if I2C_UART_SUPPORT
694
695SC16IS740_in:
696 ; make a buffer on stack
697 swap temp3
698 lsr temp3
699 push temp3 ;register address
700 in zh,sph
701 in zl,spl
702 ldi temp,SC16IS740_ADDR ;chip address (8 bit)
703 push temp ;slave address
704 ldi temp2,2
705 rcall i2c_write_read
706 pop temp ;remove slave address from stack
707 pop temp ;return input value
708 ret
709
710SC16IS740_out:
711 ; make a buffer on stack
712 push temp ;output value
713 swap temp3
714 lsr temp3
715 push temp3 ;register address
716 in zh,sph
717 in zl,spl
718 ldi temp,SC16IS740_ADDR ;chip address (8 bit)
719 push temp ;slave address
720 ldi temp2,3
721 rcall i2c_write
722 pop temp ;remove buffer from stack
723 pop temp ;
724 pop temp ;
725 ret
726
727#endif /* I2C_UART_SUPPORT */
728
729#endif /* I2C_SUPPORT */
730;------------------------------------------------------------------
731; vim:set ts=8 noet nowrap