55a33a3ae4d53d65c4df10d6f608fdb50f57bfaa
[simavr] / simavr / sim / avr_twi.c
1 /*
2         avr_twi.c
3
4         Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
5
6         This file is part of simavr.
7
8         simavr is free software: you can redistribute it and/or modify
9         it 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         simavr 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 simavr.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include <stdio.h>
23 #include "avr_twi.h"
24
25 /*
26  * This block respectfully nicked straight out from the Atmel sample
27  * code for AVR315. Typos and all.
28  * There is no copyright notice on the original file.
29  */
30 /****************************************************************************
31   TWI State codes
32 ****************************************************************************/
33 // General TWI Master staus codes
34 #define TWI_START                  0x08  // START has been transmitted
35 #define TWI_REP_START              0x10  // Repeated START has been transmitted
36 #define TWI_ARB_LOST               0x38  // Arbitration lost
37
38 // TWI Master Transmitter staus codes
39 #define TWI_MTX_ADR_ACK            0x18  // SLA+W has been tramsmitted and ACK received
40 #define TWI_MTX_ADR_NACK           0x20  // SLA+W has been tramsmitted and NACK received
41 #define TWI_MTX_DATA_ACK           0x28  // Data byte has been tramsmitted and ACK received
42 #define TWI_MTX_DATA_NACK          0x30  // Data byte has been tramsmitted and NACK received
43
44 // TWI Master Receiver staus codes
45 #define TWI_MRX_ADR_ACK            0x40  // SLA+R has been tramsmitted and ACK received
46 #define TWI_MRX_ADR_NACK           0x48  // SLA+R has been tramsmitted and NACK received
47 #define TWI_MRX_DATA_ACK           0x50  // Data byte has been received and ACK tramsmitted
48 #define TWI_MRX_DATA_NACK          0x58  // Data byte has been received and NACK tramsmitted
49
50 // TWI Slave Transmitter staus codes
51 #define TWI_STX_ADR_ACK            0xA8  // Own SLA+R has been received; ACK has been returned
52 #define TWI_STX_ADR_ACK_M_ARB_LOST 0xB0  // Arbitration lost in SLA+R/W as Master; own SLA+R has been received; ACK has been returned
53 #define TWI_STX_DATA_ACK           0xB8  // Data byte in TWDR has been transmitted; ACK has been received
54 #define TWI_STX_DATA_NACK          0xC0  // Data byte in TWDR has been transmitted; NOT ACK has been received
55 #define TWI_STX_DATA_ACK_LAST_BYTE 0xC8  // Last data byte in TWDR has been transmitted (TWEA = �0�); ACK has been received
56
57 // TWI Slave Receiver staus codes
58 #define TWI_SRX_ADR_ACK            0x60  // Own SLA+W has been received ACK has been returned
59 #define TWI_SRX_ADR_ACK_M_ARB_LOST 0x68  // Arbitration lost in SLA+R/W as Master; own SLA+W has been received; ACK has been returned
60 #define TWI_SRX_GEN_ACK            0x70  // General call address has been received; ACK has been returned
61 #define TWI_SRX_GEN_ACK_M_ARB_LOST 0x78  // Arbitration lost in SLA+R/W as Master; General call address has been received; ACK has been returned
62 #define TWI_SRX_ADR_DATA_ACK       0x80  // Previously addressed with own SLA+W; data has been received; ACK has been returned
63 #define TWI_SRX_ADR_DATA_NACK      0x88  // Previously addressed with own SLA+W; data has been received; NOT ACK has been returned
64 #define TWI_SRX_GEN_DATA_ACK       0x90  // Previously addressed with general call; data has been received; ACK has been returned
65 #define TWI_SRX_GEN_DATA_NACK      0x98  // Previously addressed with general call; data has been received; NOT ACK has been returned
66 #define TWI_SRX_STOP_RESTART       0xA0  // A STOP condition or repeated START condition has been received while still addressed as Slave
67
68 // TWI Miscellaneous status codes
69 #define TWI_NO_STATE               0xF8  // No relevant state information available; TWINT = �0�
70 #define TWI_BUS_ERROR              0x00  // Bus error due to an illegal START or STOP condition
71
72
73 static inline void
74 _avr_twi_status_set(
75                 avr_twi_t * p,
76                 uint8_t v,
77                 int interrupt)
78 {
79         avr_regbit_setto_raw(p->io.avr, p->twsr, v);
80         avr_raise_irq(p->io.irq + TWI_IRQ_STATUS, v);
81         if (interrupt)
82                 avr_raise_interrupt(p->io.avr, &p->twi);
83 }
84
85 static inline uint8_t
86 _avr_twi_status_get(
87                 avr_twi_t * p)
88 {
89         return avr_regbit_get_raw(p->io.avr, p->twsr);
90 }
91
92 static avr_cycle_count_t
93 avr_twi_set_state_timer(
94                 struct avr_t * avr,
95                 avr_cycle_count_t when,
96                 void * param)
97 {
98         avr_twi_t * p = (avr_twi_t *)param;
99         _avr_twi_status_set(p, p->next_twstate, 1);
100         p->next_twstate = 0;
101         return 0;
102 }
103
104 /*
105  * This is supposed to trigger a timer whose duration is a multiple
106  * of 'twi' clock cycles, which should be derived from the prescaler
107  * (100khz, 400khz etc).
108  * Right now it cheats and uses one twi cycle == one usec.
109  */
110 static void
111 _avr_twi_delay_state(
112                 avr_twi_t * p,
113                 int twi_cycles,
114                 uint8_t state)
115 {
116         p->next_twstate = state;
117         // TODO: calculate clock rate, convert to cycles, and use that
118         avr_cycle_timer_register_usec(
119                         p->io.avr, twi_cycles, avr_twi_set_state_timer, p);
120 }
121
122 static void
123 avr_twi_write(
124                 struct avr_t * avr,
125                 avr_io_addr_t addr,
126                 uint8_t v,
127                 void * param)
128 {
129         avr_twi_t * p = (avr_twi_t *)param;
130
131         uint8_t twen = avr_regbit_get(avr, p->twen);
132         uint8_t twsta = avr_regbit_get(avr, p->twsta);
133         uint8_t twsto = avr_regbit_get(avr, p->twsto);
134         uint8_t twint = avr_regbit_get(avr, p->twi.raised);
135
136         avr_core_watch_write(avr, addr, v);
137
138         printf("avr_twi_write %02x START:%d STOP:%d ACK:%d INT:%d TWSR:%02x\n", v,
139                         avr_regbit_get(avr, p->twsta),
140                         avr_regbit_get(avr, p->twsto),
141                         avr_regbit_get(avr, p->twea),
142                         avr_regbit_get(avr, p->twi.raised),
143                         avr_regbit_get_raw(p->io.avr, p->twsr));
144
145         if (twen != avr_regbit_get(avr, p->twen)) {
146                 twen = !twen;
147                 if (!twen) { // if we were running, now now are not
148                         avr_regbit_clear(avr, p->twea);
149                         avr_regbit_clear(avr, p->twsta);
150                         avr_regbit_clear(avr, p->twsto);
151                         avr_clear_interrupt(avr, p->twi.vector);
152                         avr_core_watch_write(avr, p->r_twdr, 0xff);
153                         _avr_twi_status_set(p, TWI_NO_STATE, 0);
154                         p->state = 0;
155                         p->peer_addr = 0;
156                 }
157                 printf("TWEN: %d\n", twen);
158         }
159         if (!twen)
160                 return;
161
162         uint8_t cleared = avr_regbit_get(avr, p->twi.raised);
163
164         /*int cleared = */avr_clear_interrupt_if(avr, &p->twi, twint);
165 //      printf("cleared %d\n", cleared);
166
167         if (!twsto && avr_regbit_get(avr, p->twsto)) {
168                 // generate a stop condition
169                 printf("<<<<< I2C stop\n");
170
171                 if (p->state) { // doing stuff
172                         if (p->state & TWI_COND_START) {
173                                 avr_raise_irq(p->io.irq + TWI_IRQ_MOSI,
174                                                 avr_twi_irq_msg(TWI_COND_STOP, p->peer_addr, 1));
175                         }
176                 }
177                 p->state = 0;
178         }
179         if (!twsta && avr_regbit_get(avr, p->twsta)) {
180                 printf(">>>>> I2C %sstart\n", p->state & TWI_COND_START ? "RE" : "");
181                 // generate a start condition
182                 if (p->state & TWI_COND_START)
183                         _avr_twi_delay_state(p, 3, TWI_REP_START);
184                 else
185                         _avr_twi_delay_state(p, 3, TWI_START);
186                 p->peer_addr = 0;
187                 p->state = TWI_COND_START;
188         }
189
190         if (cleared &&
191                         !avr_regbit_get(avr, p->twsta) &&
192                         !avr_regbit_get(avr, p->twsto)) {
193                 // writing or reading a byte
194                 if (p->state & TWI_COND_ADDR) {
195                         if (p->peer_addr & 1)
196                                 printf("I2C READ byte from %02x\n", p->peer_addr);
197                         else
198                                 printf("I2C WRITE byte %02x to %02x\n", avr->data[p->r_twdr], p->peer_addr);
199                         // a normal data byte
200                         uint8_t msgv = p->peer_addr & 1 ? TWI_COND_READ : TWI_COND_WRITE;
201                         if (avr_regbit_get(avr, p->twea))
202                                 msgv |= TWI_COND_ACK;
203
204                         p->state &= ~TWI_COND_ACK;      // clear ACK bit
205
206                         // we send an IRQ and we /expect/ a slave to reply
207                         // immediately via an IRQ to set the COND_ACK bit
208                         // otherwise it's assumed it's been nacked...
209                         avr_raise_irq(p->io.irq + TWI_IRQ_MOSI,
210                                         avr_twi_irq_msg(msgv, p->peer_addr, avr->data[p->r_twdr]));
211
212                         if (p->peer_addr & 1) { // read ?
213                                 _avr_twi_delay_state(p, 9,
214                                                 msgv & TWI_COND_ACK ?
215                                                                 TWI_MTX_DATA_ACK : TWI_MTX_DATA_NACK);
216                         } else {
217                                 _avr_twi_delay_state(p, 9,
218                                                 p->state & TWI_COND_ACK ?
219                                                                 TWI_MTX_DATA_ACK : TWI_MTX_DATA_NACK);
220                         }
221
222                 } else {
223                         printf("I2C Master address %02x\n", avr->data[p->r_twdr]);
224                         // send the address
225                         p->state |= TWI_COND_ADDR;
226                         p->peer_addr = avr->data[p->r_twdr];
227                         p->state &= ~TWI_COND_ACK;      // clear ACK bit
228
229                         // we send an IRQ and we /expect/ a slave to reply
230                         // immediately via an IRQ tp set the COND_ACK bit
231                         // otherwise it's assumed it's been nacked...
232                         avr_raise_irq(p->io.irq + TWI_IRQ_MOSI,
233                                         avr_twi_irq_msg(TWI_COND_START, p->peer_addr, 0));
234
235                         if (p->peer_addr & 1) { // read ?
236                                 _avr_twi_delay_state(p, 9,
237                                                 p->state & TWI_COND_ACK ?
238                                                                 TWI_MRX_ADR_ACK : TWI_MRX_ADR_NACK);
239                         } else {
240                                 _avr_twi_delay_state(p, 9,
241                                                 p->state & TWI_COND_ACK ?
242                                                                 TWI_MTX_ADR_ACK : TWI_MTX_ADR_NACK);
243                         }
244                 }
245         }
246 }
247
248 /*
249  * prevent code from rewriting out status bits, since we actualy use them!
250  */
251 static void
252 avr_twi_write_status(
253                 struct avr_t * avr,
254                 avr_io_addr_t addr,
255                 uint8_t v,
256                 void * param)
257 {
258         avr_twi_t * p = (avr_twi_t *)param;
259         uint8_t sr = avr_regbit_get(avr, p->twsr);
260         uint8_t c = avr_regbit_get(avr, p->twps);
261
262         avr_core_watch_write(avr, addr, v);
263         avr_regbit_setto(avr, p->twsr, sr);     // force restore
264
265         if (c != avr_regbit_get(avr, p->twps)) {
266                 // prescaler bits changed...
267         }
268 }
269
270 static void
271 avr_twi_irq_input(
272                 struct avr_irq_t * irq,
273                 uint32_t value,
274                 void * param)
275 {
276         avr_twi_t * p = (avr_twi_t *)param;
277         avr_t * avr = p->io.avr;
278
279         // check to see if we are enabled
280         if (!avr_regbit_get(avr, p->twen))
281                 return;
282         avr_twi_msg_irq_t msg;
283         msg.u.v = value;
284
285         // receiving an acknowledge bit
286         if (msg.u.twi.msg & TWI_COND_ACK) {
287                 printf("I2C received ACK:%d\n", msg.u.twi.data & 1);
288                 if (msg.u.twi.data & 1)
289                         p->state |= TWI_COND_ACK;
290                 else
291                         p->state &= ~TWI_COND_ACK;
292         }
293         // receive a data byte from a slave
294         if (msg.u.twi.msg & TWI_COND_READ) {
295                 printf("I2C received %02x\n", msg.u.twi.data);
296                 avr->data[p->r_twdr] = msg.u.twi.data;
297         }
298 }
299
300 void avr_twi_reset(struct avr_io_t *io)
301 {
302         avr_twi_t * p = (avr_twi_t *)io;
303         avr_irq_register_notify(p->io.irq + TWI_IRQ_MISO, avr_twi_irq_input, p);
304 }
305
306 static const char * irq_names[TWI_IRQ_COUNT] = {
307         [TWI_IRQ_MISO] = "8<mosi",
308         [TWI_IRQ_MOSI] = "32>miso",
309         [TWI_IRQ_STATUS] = "8>status",
310 };
311
312 static  avr_io_t        _io = {
313         .kind = "twi",
314         .reset = avr_twi_reset,
315         .irq_names = irq_names,
316 };
317
318 void avr_twi_init(avr_t * avr, avr_twi_t * p)
319 {
320         p->io = _io;
321         avr_register_io(avr, &p->io);
322         avr_register_vector(avr, &p->twi);
323
324         //printf("%s TWI%c init\n", __FUNCTION__, p->name);
325
326         // allocate this module's IRQ
327         avr_io_setirqs(&p->io, AVR_IOCTL_TWI_GETIRQ(p->name), TWI_IRQ_COUNT, NULL);
328
329         avr_register_io_write(avr, p->twen.reg, avr_twi_write, p);
330         avr_register_io_write(avr, p->twsr.reg, avr_twi_write_status, p);
331 }
332