~ubuntu-branches/ubuntu/lucid/avr-libc/lucid

« back to all changes in this revision

Viewing changes to doc/examples/twitest/twitest.c

  • Committer: Bazaar Package Importer
  • Author(s): Hakan Ardo
  • Date: 2005-03-19 11:16:14 UTC
  • mfrom: (1.1.1 upstream) (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050319111614-4g01s2ftv5x5nxf3
Tags: 1:1.2.3-3
* Added build depends on netpbm
* Added build depends on tetex-extra

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * ----------------------------------------------------------------------------
 
3
 * "THE BEER-WARE LICENSE" (Revision 42):
 
4
 * <joerg@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
 
5
 * can do whatever you want with this stuff. If we meet some day, and you think
 
6
 * this stuff is worth it, you can buy me a beer in return.        Joerg Wunsch
 
7
 * ----------------------------------------------------------------------------
 
8
 */
 
9
 
 
10
/* $Id: twitest.c,v 1.2.2.2 2005/02/07 22:47:46 arcanum Exp $ */
 
11
 
 
12
/*
 
13
 * Simple demo program that talks to a 24Cxx I�C EEPROM using the
 
14
 * builtin TWI interface of an ATmega device.
 
15
 */
 
16
 
 
17
#include <inttypes.h>
 
18
#include <stdio.h>
 
19
#include <stdlib.h>
 
20
 
 
21
#include <avr/io.h>
 
22
#include <compat/twi.h>         /* Note [1] */
 
23
 
 
24
#define DEBUG 1
 
25
 
 
26
/*
 
27
 * System clock in Hz.
 
28
 */
 
29
#define F_CPU 14745600UL        /* Note [2] */
 
30
 
 
31
/*
 
32
 * Compatibility defines.  This should work on ATmega8, ATmega16,
 
33
 * ATmega163, ATmega323 and ATmega128 (IOW: on all devices that
 
34
 * provide a builtin TWI interface).
 
35
 *
 
36
 * On the 128, it defaults to USART 1.
 
37
 */
 
38
#ifndef UCSRB
 
39
# ifdef UCSR1A          /* ATmega128 */
 
40
#  define UCSRA UCSR1A
 
41
#  define UCSRB UCSR1B
 
42
#  define UBRR UBRR1L
 
43
#  define UDR UDR1
 
44
# else /* ATmega8 */
 
45
#  define UCSRA USR
 
46
#  define UCSRB UCR
 
47
# endif
 
48
#endif
 
49
#ifndef UBRR
 
50
#  define UBRR UBRRL
 
51
#endif
 
52
 
 
53
/*
 
54
 * Note [3]
 
55
 * TWI address for 24Cxx EEPROM:
 
56
 *
 
57
 * 1 0 1 0 E2 E1 E0 R/~W        24C01/24C02
 
58
 * 1 0 1 0 E2 E1 A8 R/~W        24C04
 
59
 * 1 0 1 0 E2 A9 A8 R/~W        24C08
 
60
 * 1 0 1 0 A10 A9 A8 R/~W       24C16
 
61
 */
 
62
#define TWI_SLA_24CXX   0xa0    /* E2 E1 E0 = 0 0 0 */
 
63
 
 
64
/*
 
65
 * Maximal number of iterations to wait for a device to respond for a
 
66
 * selection.  Should be large enough to allow for a pending write to
 
67
 * complete, but low enough to properly abort an infinite loop in case
 
68
 * a slave is broken or not present at all.  With 100 kHz TWI clock,
 
69
 * transfering the start condition and SLA+R/W packet takes about 10
 
70
 * �s.  The longest write period is supposed to not exceed ~ 10 ms.
 
71
 * Thus, normal operation should not require more than 100 iterations
 
72
 * to get the device to respond to a selection.
 
73
 */
 
74
#define MAX_ITER        200
 
75
 
 
76
/*
 
77
 * Number of bytes that can be written in a row, see comments for
 
78
 * ee24xx_write_page() below.  Some vendor's devices would accept 16,
 
79
 * but 8 seems to be the lowest common denominator.
 
80
 *
 
81
 * Note that the page size must be a power of two, this simplifies the
 
82
 * page boundary calculations below.
 
83
 */
 
84
#define PAGE_SIZE 8
 
85
 
 
86
/*
 
87
 * Saved TWI status register, for error messages only.  We need to
 
88
 * save it in a variable, since the datasheet only guarantees the TWSR
 
89
 * register to have valid contents while the TWINT bit in TWCR is set.
 
90
 */
 
91
uint8_t twst;
 
92
 
 
93
/*
 
94
 * Do all the startup-time peripheral initializations: UART (for our
 
95
 * debug/test output), and TWI clock.
 
96
 */
 
97
void
 
98
ioinit(void)
 
99
{
 
100
 
 
101
#if F_CPU <= 1000000UL
 
102
  /*
 
103
   * Note [4]
 
104
   * Slow system clock, double Baud rate to improve rate error.
 
105
   */
 
106
  UCSRA = _BV(U2X);
 
107
  UBRR = (F_CPU / (8 * 9600UL)) - 1; /* 9600 Bd */
 
108
#else
 
109
  UBRR = (F_CPU / (16 * 9600UL)) - 1; /* 9600 Bd */
 
110
#endif
 
111
  UCSRB = _BV(TXEN);            /* tx enable */
 
112
 
 
113
  /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
 
114
#if defined(TWPS0)
 
115
  /* has prescaler (mega128 & newer) */
 
116
  TWSR = 0;
 
117
#endif
 
118
 
 
119
#if F_CPU < 3600000UL
 
120
  TWBR = 10;                    /* smallest TWBR value, see note [5] */
 
121
#else
 
122
  TWBR = (F_CPU / 100000UL - 16) / 2;
 
123
#endif
 
124
}
 
125
 
 
126
/*
 
127
 * Note [6]
 
128
 * Send character c down the UART Tx, wait until tx holding register
 
129
 * is empty.
 
130
 */
 
131
int
 
132
uart_putchar(char c)
 
133
{
 
134
 
 
135
  if (c == '\n')
 
136
    uart_putchar('\r');
 
137
  loop_until_bit_is_set(UCSRA, UDRE);
 
138
  UDR = c;
 
139
  return 0;
 
140
}
 
141
 
 
142
/*
 
143
 * Note [7]
 
144
 *
 
145
 * Read "len" bytes from EEPROM starting at "eeaddr" into "buf".
 
146
 *
 
147
 * This requires two bus cycles: during the first cycle, the device
 
148
 * will be selected (master transmitter mode), and the address
 
149
 * transfered.  Address bits exceeding 256 are transfered in the
 
150
 * E2/E1/E0 bits (subaddress bits) of the device selector.
 
151
 *
 
152
 * The second bus cycle will reselect the device (repeated start
 
153
 * condition, going into master receiver mode), and transfer the data
 
154
 * from the device to the TWI master.  Multiple bytes can be
 
155
 * transfered by ACKing the client's transfer.  The last transfer will
 
156
 * be NACKed, which the client will take as an indication to not
 
157
 * initiate further transfers.
 
158
 */
 
159
int
 
160
ee24xx_read_bytes(uint16_t eeaddr, int len, uint8_t *buf)
 
161
{
 
162
  uint8_t sla, twcr, n = 0;
 
163
  int rv = 0;
 
164
 
 
165
  /* patch high bits of EEPROM address into SLA */
 
166
  sla = TWI_SLA_24CXX | (((eeaddr >> 8) & 0x07) << 1);
 
167
 
 
168
  /*
 
169
   * Note [8]
 
170
   * First cycle: master transmitter mode
 
171
   */
 
172
  restart:
 
173
  if (n++ >= MAX_ITER)
 
174
    return -1;
 
175
  begin:
 
176
 
 
177
  TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); /* send start condition */
 
178
  while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */
 
179
  switch ((twst = TW_STATUS))
 
180
    {
 
181
    case TW_REP_START:          /* OK, but should not happen */
 
182
    case TW_START:
 
183
      break;
 
184
 
 
185
    case TW_MT_ARB_LOST:        /* Note [9] */
 
186
      goto begin;
 
187
 
 
188
    default:
 
189
      return -1;                /* error: not in start condition */
 
190
                                /* NB: do /not/ send stop condition */
 
191
    }
 
192
 
 
193
  /* Note [10] */
 
194
  /* send SLA+W */
 
195
  TWDR = sla | TW_WRITE;
 
196
  TWCR = _BV(TWINT) | _BV(TWEN); /* clear interrupt to start transmission */
 
197
  while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */
 
198
  switch ((twst = TW_STATUS))
 
199
    {
 
200
    case TW_MT_SLA_ACK:
 
201
      break;
 
202
 
 
203
    case TW_MT_SLA_NACK:        /* nack during select: device busy writing */
 
204
                                /* Note [11] */
 
205
      goto restart;
 
206
 
 
207
    case TW_MT_ARB_LOST:        /* re-arbitrate */
 
208
      goto begin;
 
209
 
 
210
    default:
 
211
      goto error;               /* must send stop condition */
 
212
    }
 
213
 
 
214
  TWDR = eeaddr;                /* low 8 bits of addr */
 
215
  TWCR = _BV(TWINT) | _BV(TWEN); /* clear interrupt to start transmission */
 
216
  while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */
 
217
  switch ((twst = TW_STATUS))
 
218
    {
 
219
    case TW_MT_DATA_ACK:
 
220
      break;
 
221
 
 
222
    case TW_MT_DATA_NACK:
 
223
      goto quit;
 
224
 
 
225
    case TW_MT_ARB_LOST:
 
226
      goto begin;
 
227
 
 
228
    default:
 
229
      goto error;               /* must send stop condition */
 
230
    }
 
231
 
 
232
  /*
 
233
   * Note [12]
 
234
   * Next cycle(s): master receiver mode
 
235
   */
 
236
  TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); /* send (rep.) start condition */
 
237
  while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */
 
238
  switch ((twst = TW_STATUS))
 
239
    {
 
240
    case TW_START:              /* OK, but should not happen */
 
241
    case TW_REP_START:
 
242
      break;
 
243
 
 
244
    case TW_MT_ARB_LOST:
 
245
      goto begin;
 
246
 
 
247
    default:
 
248
      goto error;
 
249
    }
 
250
 
 
251
  /* send SLA+R */
 
252
  TWDR = sla | TW_READ;
 
253
  TWCR = _BV(TWINT) | _BV(TWEN); /* clear interrupt to start transmission */
 
254
  while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */
 
255
  switch ((twst = TW_STATUS))
 
256
    {
 
257
    case TW_MR_SLA_ACK:
 
258
      break;
 
259
 
 
260
    case TW_MR_SLA_NACK:
 
261
      goto quit;
 
262
 
 
263
    case TW_MR_ARB_LOST:
 
264
      goto begin;
 
265
 
 
266
    default:
 
267
      goto error;
 
268
    }
 
269
 
 
270
  for (twcr = _BV(TWINT) | _BV(TWEN) | _BV(TWEA) /* Note [13] */;
 
271
       len > 0;
 
272
       len--)
 
273
    {
 
274
      if (len == 1)
 
275
        twcr = _BV(TWINT) | _BV(TWEN); /* send NAK this time */
 
276
      TWCR = twcr;              /* clear int to start transmission */
 
277
      while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */
 
278
      switch ((twst = TW_STATUS))
 
279
        {
 
280
        case TW_MR_DATA_NACK:
 
281
          len = 0;              /* force end of loop */
 
282
          /* FALLTHROUGH */
 
283
        case TW_MR_DATA_ACK:
 
284
          *buf++ = TWDR;
 
285
          rv++;
 
286
          break;
 
287
 
 
288
        default:
 
289
          goto error;
 
290
        }
 
291
    }
 
292
  quit:
 
293
  /* Note [14] */
 
294
  TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); /* send stop condition */
 
295
 
 
296
  return rv;
 
297
 
 
298
  error:
 
299
  rv = -1;
 
300
  goto quit;
 
301
}
 
302
 
 
303
/*
 
304
 * Write "len" bytes into EEPROM starting at "eeaddr" from "buf".
 
305
 *
 
306
 * This is a bit simpler than the previous function since both, the
 
307
 * address and the data bytes will be transfered in master transmitter
 
308
 * mode, thus no reselection of the device is necessary.  However, the
 
309
 * EEPROMs are only capable of writing one "page" simultaneously, so
 
310
 * care must be taken to not cross a page boundary within one write
 
311
 * cycle.  The amount of data one page consists of varies from
 
312
 * manufacturer to manufacturer: some vendors only use 8-byte pages
 
313
 * for the smaller devices, and 16-byte pages for the larger devices,
 
314
 * while other vendors generally use 16-byte pages.  We thus use the
 
315
 * smallest common denominator of 8 bytes per page, declared by the
 
316
 * macro PAGE_SIZE above.
 
317
 *
 
318
 * The function simply returns after writing one page, returning the
 
319
 * actual number of data byte written.  It is up to the caller to
 
320
 * re-invoke it in order to write further data.
 
321
 */
 
322
int
 
323
ee24xx_write_page(uint16_t eeaddr, int len, uint8_t *buf)
 
324
{
 
325
  uint8_t sla, n = 0;
 
326
  int rv = 0;
 
327
  uint16_t endaddr;
 
328
 
 
329
  if (eeaddr + len < (eeaddr | (PAGE_SIZE - 1)))
 
330
    endaddr = eeaddr + len;
 
331
  else
 
332
    endaddr = (eeaddr | (PAGE_SIZE - 1)) + 1;
 
333
  len = endaddr - eeaddr;
 
334
 
 
335
  /* patch high bits of EEPROM address into SLA */
 
336
  sla = TWI_SLA_24CXX | (((eeaddr >> 8) & 0x07) << 1);
 
337
 
 
338
  restart:
 
339
  if (n++ >= MAX_ITER)
 
340
    return -1;
 
341
  begin:
 
342
 
 
343
  /* Note [15] */
 
344
  TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); /* send start condition */
 
345
  while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */
 
346
  switch ((twst = TW_STATUS))
 
347
    {
 
348
    case TW_REP_START:          /* OK, but should not happen */
 
349
    case TW_START:
 
350
      break;
 
351
 
 
352
    case TW_MT_ARB_LOST:
 
353
      goto begin;
 
354
 
 
355
    default:
 
356
      return -1;                /* error: not in start condition */
 
357
                                /* NB: do /not/ send stop condition */
 
358
    }
 
359
 
 
360
  /* send SLA+W */
 
361
  TWDR = sla | TW_WRITE;
 
362
  TWCR = _BV(TWINT) | _BV(TWEN); /* clear interrupt to start transmission */
 
363
  while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */
 
364
  switch ((twst = TW_STATUS))
 
365
    {
 
366
    case TW_MT_SLA_ACK:
 
367
      break;
 
368
 
 
369
    case TW_MT_SLA_NACK:        /* nack during select: device busy writing */
 
370
      goto restart;
 
371
 
 
372
    case TW_MT_ARB_LOST:        /* re-arbitrate */
 
373
      goto begin;
 
374
 
 
375
    default:
 
376
      goto error;               /* must send stop condition */
 
377
    }
 
378
 
 
379
  TWDR = eeaddr;                /* low 8 bits of addr */
 
380
  TWCR = _BV(TWINT) | _BV(TWEN); /* clear interrupt to start transmission */
 
381
  while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */
 
382
  switch ((twst = TW_STATUS))
 
383
    {
 
384
    case TW_MT_DATA_ACK:
 
385
      break;
 
386
 
 
387
    case TW_MT_DATA_NACK:
 
388
      goto quit;
 
389
 
 
390
    case TW_MT_ARB_LOST:
 
391
      goto begin;
 
392
 
 
393
    default:
 
394
      goto error;               /* must send stop condition */
 
395
    }
 
396
 
 
397
  for (; len > 0; len--)
 
398
    {
 
399
      TWDR = *buf++;
 
400
      TWCR = _BV(TWINT) | _BV(TWEN); /* start transmission */
 
401
      while ((TWCR & _BV(TWINT)) == 0) ; /* wait for transmission */
 
402
      switch ((twst = TW_STATUS))
 
403
        {
 
404
        case TW_MT_DATA_NACK:
 
405
          goto error;           /* device write protected -- Note [16] */
 
406
 
 
407
        case TW_MT_DATA_ACK:
 
408
          rv++;
 
409
          break;
 
410
 
 
411
        default:
 
412
          goto error;
 
413
        }
 
414
    }
 
415
  quit:
 
416
  TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); /* send stop condition */
 
417
 
 
418
  return rv;
 
419
 
 
420
  error:
 
421
  rv = -1;
 
422
  goto quit;
 
423
}
 
424
 
 
425
/*
 
426
 * Wrapper around ee24xx_write_page() that repeats calling this
 
427
 * function until either an error has been returned, or all bytes
 
428
 * have been written.
 
429
 */
 
430
int
 
431
ee24xx_write_bytes(uint16_t eeaddr, int len, uint8_t *buf)
 
432
{
 
433
  int rv, total;
 
434
 
 
435
  total = 0;
 
436
  do
 
437
    {
 
438
#if DEBUG
 
439
      printf("Calling ee24xx_write_page(%d, %d, %p)",
 
440
             eeaddr, len, buf);
 
441
#endif
 
442
      rv = ee24xx_write_page(eeaddr, len, buf);
 
443
#if DEBUG
 
444
      printf(" => %d\n", rv);
 
445
#endif
 
446
      if (rv == -1)
 
447
        return -1;
 
448
      eeaddr += rv;
 
449
      len -= rv;
 
450
      buf += rv;
 
451
      total += rv;
 
452
    }
 
453
  while (len > 0);
 
454
 
 
455
  return total;
 
456
}
 
457
 
 
458
void
 
459
error(void)
 
460
{
 
461
 
 
462
  printf("error: TWI status %#x\n", twst);
 
463
  exit(0);
 
464
}
 
465
 
 
466
void
 
467
main(void)
 
468
{
 
469
  uint16_t a;
 
470
  int rv;
 
471
  uint8_t b[16];
 
472
  uint8_t x;
 
473
 
 
474
  ioinit();
 
475
 
 
476
  fdevopen(uart_putchar, NULL, 0);
 
477
 
 
478
  for (a = 0; a < 256;)
 
479
    {
 
480
      printf("%#04x: ", a);
 
481
      rv = ee24xx_read_bytes(a, 16, b);
 
482
      if (rv <= 0)
 
483
        error();
 
484
      if (rv < 16)
 
485
        printf("warning: short read %d\n", rv);
 
486
      a += rv;
 
487
      for (x = 0; x < rv; x++)
 
488
        printf("%02x ", b[x]);
 
489
      putchar('\n');
 
490
    }
 
491
#define EE_WRITE(addr, str) ee24xx_write_bytes(addr, sizeof(str)-1, str)
 
492
  rv = EE_WRITE(55, "The quick brown fox jumps over the lazy dog.");
 
493
  if (rv < 0)
 
494
    error();
 
495
  printf("Wrote %d bytes.\n", rv);
 
496
  for (a = 0; a < 256;)
 
497
    {
 
498
      printf("%#04x: ", a);
 
499
      rv = ee24xx_read_bytes(a, 16, b);
 
500
      if (rv <= 0)
 
501
        error();
 
502
      if (rv < 16)
 
503
        printf("warning: short read %d\n", rv);
 
504
      a += rv;
 
505
      for (x = 0; x < rv; x++)
 
506
        printf("%02x ", b[x]);
 
507
      putchar('\n');
 
508
    }
 
509
 
 
510
  printf("done.\n");
 
511
 
 
512
}