-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathi2c.s
111 lines (97 loc) · 2.14 KB
/
i2c.s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
; Written by Anders Nielsen, 2023-2024
; License: https://creativecommons.org/licenses/by-nc/4.0/legalcode
SCL = 1 ; DRB0 bitmask
SCL_INV = $FE ; Inverted for easy clear bit
SDA = 2 ; DRB1 bitmask
SDA_INV = $FD
; i2c routines for the 65uino
i2c_start:
lda I2CADDR
rol ; Shift in carry
sta outb ; Save addr + r/w bit
lda #SCL_INV
and DDRB
sta DDRB ; Start with SCL as input HIGH - that way we can inc/dec from here
lda #SDA ; Ensure SDA is output low before SCL is LOW
ora DDRB
sta DDRB
lda #SDA_INV
and DRB
sta DRB
lda #SCL_INV ; Ensure SCL is low when it turns to output
and DRB
sta DRB
inc DDRB ; Set to output by incrementing the direction register == OUT, LOW
; Fall through to send address + RW bit
; After a start condition we always send the address byte so we don't need to RTS+JSR again here
i2cbyteout: ; Clears outb
lda #SDA_INV ; In case this is a data byte we set SDA LOW
and DRB
sta DRB
ldx #8
bne first ; BRA - skip INC since first time already out, low
I2Cbyteloop:
inc DDRB ; SCL out, low
first:
asl outb ; MSB to carry
bcc seti2cbit0 ; If bit was low
lda DDRB ; else set it high
and #SDA_INV
sta DDRB
bcs wasone ; BRA doesn't exist on 6507
seti2cbit0:
lda DDRB
ora #SDA
sta DDRB
wasone:
dec DDRB
dex
bne I2Cbyteloop
inc DDRB
lda DDRB ; Set SDA to INPUT (HIGH)
and #SDA_INV
sta DDRB
dec DDRB ; Clock high
lda DRB ; Check ACK bit
sec
and #SDA
bne nack
clc ; Clear carry on ACK
nack:
inc DDRB ; SCL low
rts
i2cbytein:
; Assume SCL is low from address byte
lda DDRB ; SDA, input
and #SDA_INV
sta DDRB
lda #0
sta inb
ldx #8
i2cbyteinloop:
clc
dec DDRB ; SCL HIGH
lda DRB ; Let's read after SCL goes high
and #SDA
beq got0
sec
got0:
rol inb ; Shift bit into the input byte
inc DDRB ; SCL LOW
dex
bne i2cbyteinloop
lda DDRB ; Send NACK == SDA high (only single bytes for now)
and #SDA_INV
sta DDRB
dec DDRB ; SCL HIGH
inc DDRB ; SCL LOW
rts
i2c_stop:
lda DDRB ; SDA low
ora #SDA
sta DDRB
dec DDRB ; SCL HIGH
lda DDRB ; Set SDA high after SCL == Stop condition
and #SDA_INV
sta DDRB
rts