-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathchat-iic-core.mu4
169 lines (130 loc) · 5.02 KB
/
chat-iic-core.mu4
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
| This file is part of muforth: https://muforth.dev/
|
| Copyright 2002-2025 David Frech. (Read the LICENSE for details.)
loading AVR I2C chat (core)
__meta
hex
label restart
u y movw 1 y sbiw SPL yl out | empty stack
( fall thru) ;c
hook i2c-restart-hook
7 equ TWINT ( bit#) ( ack after all other actions)
6 equ TWEA ( bit#) ( enable receipt of slave address)
2 equ TWEN ( bit#)
1 TWINT <<
1 TWEA << or
1 TWEN << or equ tw-reset
| comment
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Status codes for slave receive mode:
|
| 60 own addr+write received and ACKed
| 80 prev addressed with own address; data byte recvd and ACKed
| a0 STOP or repeated START received while in slave receive mode
|
| Status codes for slave transmit mode:
|
| a8 own addr+read received and ACKed
| b8 data byte xmitted and ACKed
| c0 as above, but NACKed
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| comment
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Register-use:
|
| r0/r1 is used for writing flash (via SPM instruction)
| r26/27 - aka x - is used for status and data bytes
| r30/31 - aka z - is used to point to memory
|
| These are also registers that are considered "scratch" by the
| meta-compiler's conventions.
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
( Save and restore chat registers around the call to yield.)
( XXX Since this is used in only one place it could be inlined.)
label chat-yield
z pushw 0 pushw yield rcall 0 popw z popw ret ;c
| Ack TWINT. Make sure TWEA and TWEN also set. Then Wait for TWINT; read
| status; mask prescaler bits; return status in xl. Clobbers xh.
label await-twint
tw-reset xh ldi TWCR xh sts ( ack TWINT)
begin chat-yield rcall TWCR xl lds TWINT xl sbrs again
TWSR xl lds 0f8 xl andi ret ;c
label recv-byte
await-twint rcall
80 xl cpi restart 0= until ( restart protocol)
TWDR xl lds ret ;c
| This is a bit tricky! Since the host had to send a new transaction for
| the read, on the first byte we're going to see _two_ interrupts: first,
| that while addressed as a slave receiver we got a STOP or RESTART; and
| second, that we were addressed as slave+read. We have to watch for, and
| ack, both.
|
| If we want to send multiple bytes back to the master, we have to look for
| and accept both a8 - addressed as slave+read - and b8 - byte transmitted
| and ACKed. Our caller can sit in a loop since the host will NACK the last
| byte, and we'll get a c0 status, and restart.
label expect-start
await-twint rcall
0a0 xl cpi restart 0= until ( we should see START/RESTART)
( fall thru) ;c
| Returns to caller if either we were just addressed, or the last byte
| written was ACKed by the master.
label send-another?
await-twint rcall
0e8 xl andi 0a8 xl cpi restart 0= until ( match a8 and b8) ret ;c
| After sending byte and acking interrupt, wait for ACK/NACK and only
| return to caller if ok to send another byte.
label send-byte
TWDR xl sts send-another? rjmp ;c
| As with the read-memory commands, we expect a start/restart to initiate
| the read.
label send-word
x pushw expect-start rcall
xl pop send-byte rcall xl pop send-byte rjmp ;c
label recv-word
recv-byte rcall xl push
recv-byte rcall xl xh mov xl pop ret ;c
( EEPROM read/write.)
ld target/AVR/eeprom.mu4
( Flash self-programming support.)
ld target/AVR/flash-self-prog.mu4
( Called by chat startup code.)
label serial-init
( Set I2C slave address from EEPROM)
0 z ldiw read-eeprom-byte rcall 1 invert xl andi TWAR xl out
.def mega168 .def mega328 .or .if
( Set up SCL/SDA pins as inputs with pullups enabled: PC4 and PC5)
xl clr DDRC xl out 30 xl ldi PORTC xl out
.else ( prob mega164/324/644/1284)
( Set up SCL/SDA pins as inputs with pullups enabled: PC0 and PC1)
xl clr DDRC xl out 03 xl ldi PORTC xl out
.then
ret ;c
| On reads, keep streaming bytes from memory to I2C as long as last byte
| was ACKed.
( Command routines.)
label read-data-cmd
expect-start rcall
begin z+ xl ld send-byte rcall again ;c
label read-flash-cmd
expect-start rcall
begin pmz+ xl ld send-byte rcall again ;c
label read-eeprom-cmd
expect-start rcall
begin read-eeprom-byte rcall 1 z adiw send-byte rcall again ;c
| When writing to data space - ram and i/o - keep streaming bytes from I2C
| into memory, until recv-byte gets something other than an 80 status.
label write-data-cmd
begin recv-byte rcall z+ xl st again ;c
label write-eeprom-cmd
begin recv-byte rcall write-eeprom-byte rcall 1 z adiw again ;c
label write-flash-cmd
begin recv-word rcall x 0 movw recv-byte rcall ( cmd) do-spm rcall
2 z adiw again ;c
( For chat dispatch loop.)
label recv-command-byte
( wait until addressed as slave+write)
begin await-twint rcall 60 xl cpi 0= until
recv-byte rjmp ( cmd) ;c
( Load chat entry and command loop.)
ld target/AVR/chat-loop.mu4