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 | #include <inttypes.h>
|
11 | #include <stdio.h>
|
12 | #include <stdlib.h>
|
13 | #include <util/delay.h>
|
14 |
|
15 | #include <avr/io.h>
|
16 | #include <util/twi.h> /* Note [1] */
|
17 |
|
18 | #define DEBUG 1
|
19 |
|
20 | /*
|
21 | * System clock in Hz.
|
22 | */
|
23 | #define F_CPU 8000000UL /* Note [2] */
|
24 |
|
25 |
|
26 |
|
27 | /*
|
28 | * Compatibility defines. This should work on ATmega8, ATmega16,
|
29 | * ATmega163, ATmega323 and ATmega128 (IOW: on all devices that
|
30 | * provide a builtin TWI interface).
|
31 | *
|
32 | * On the 128, it defaults to USART 1.
|
33 | */
|
34 | #ifndef UCSRB
|
35 | # ifdef UCSR1A /* ATmega128 */
|
36 | # define UCSRA UCSR1A
|
37 | # define UCSRB UCSR1B
|
38 | # define UBRR UBRR1L
|
39 | # define UDR UDR1
|
40 | # else /* ATmega8 */
|
41 | # define UCSRA USR
|
42 | # define UCSRB UCR
|
43 | # endif
|
44 | #endif
|
45 | #ifndef UBRR
|
46 | # define UBRR UBRRL
|
47 | #endif
|
48 |
|
49 |
|
50 |
|
51 | /*
|
52 | * Note [3]
|
53 | * TWI address for 24Cxx EEPROM:
|
54 | *
|
55 | * 1 0 1 0 E2 E1 E0 R/~W 24C01/24C02
|
56 | * 1 0 1 0 E2 E1 A8 R/~W 24C04
|
57 | * 1 0 1 0 E2 A9 A8 R/~W 24C08
|
58 | * 1 0 1 0 A10 A9 A8 R/~W 24C16
|
59 | */
|
60 | #define TWI_SLA_24CXX 0xA2 /* E2 E1 E0 = 0 0 0 */
|
61 |
|
62 |
|
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 |
|
78 | /*
|
79 | * Number of bytes that can be written in a row, see comments for
|
80 | * ee24xx_write_page() below. Some vendor's devices would accept 16,
|
81 | * but 8 seems to be the lowest common denominator.
|
82 | *
|
83 | * Note that the page size must be a power of two, this simplifies the
|
84 | * page boundary calculations below.
|
85 | */
|
86 | #define PAGE_SIZE 8
|
87 |
|
88 |
|
89 |
|
90 | /*
|
91 | * Saved TWI status register, for error messages only. We need to
|
92 | * save it in a variable, since the datasheet only guarantees the TWSR
|
93 | * register to have valid contents while the TWINT bit in TWCR is set.
|
94 | */
|
95 | uint8_t twst;
|
96 |
|
97 |
|
98 | /*
|
99 | * Do all the startup-time peripheral initializations: UART (for our
|
100 | * debug/test output), and TWI clock.
|
101 | */
|
102 |
|
103 |
|
104 |
|
105 | void ioinit(void)
|
106 | {
|
107 |
|
108 | #if F_CPU <= 1000000UL
|
109 | /*
|
110 | * Note [4]
|
111 | * Slow system clock, double Baud rate to improve rate error.
|
112 | */
|
113 | UCSRA = _BV(U2X);
|
114 | UBRR = (F_CPU / (8 * 9600UL)) - 1; /* 9600 Bd */
|
115 | #else
|
116 | UBRR = (F_CPU / (16 * 9600UL)) - 1; /* 9600 Bd */
|
117 | #endif
|
118 | UCSRB = _BV(TXEN); /* tx enable */
|
119 |
|
120 | /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
|
121 | TWBR = 0x20;
|
122 | TWSR = 0x00;
|
123 | }
|
124 |
|
125 |
|
126 |
|
127 | /*
|
128 | * Note [6]
|
129 | * Send character c down the UART Tx, wait until tx holding register
|
130 | * is empty.
|
131 | */
|
132 | int uart_putchar(char c, FILE *unused)
|
133 | {
|
134 |
|
135 | if (c == '\n')
|
136 | uart_putchar('\r', 0);
|
137 | loop_until_bit_is_set(UCSRA, UDRE);
|
138 | UDR = c;
|
139 | return 0;
|
140 | }
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 | unsigned char I2C_start(void)
|
151 | {
|
152 | /*writing a one to TWINT clears it, TWSTA=Start, TWEN=TWI-enable*/
|
153 | TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
|
154 | /*wait, until start condition has been sent --> ACK*/
|
155 | while (!(TWCR & _BV(TWINT)));
|
156 | // printf("TWSR Start %#04x\n ", TWSR);
|
157 | return TWSR;
|
158 | }
|
159 |
|
160 |
|
161 | void I2C_stop(void)
|
162 | {
|
163 | /*writing a one to TWINT clears it, TWSTO=Stop, TWEN=TWI-enable*/
|
164 | TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN);
|
165 | // printf("TWSR Stop %#04x\n ", TWSR);
|
166 | }
|
167 |
|
168 |
|
169 | unsigned char eeprom_send_add_w (unsigned char address, unsigned char rw)
|
170 | {
|
171 |
|
172 | unsigned char addr_byte = 0;
|
173 |
|
174 | addr_byte |= rw;
|
175 |
|
176 | addr_byte |= address;
|
177 |
|
178 | TWDR = addr_byte;
|
179 |
|
180 | TWCR = _BV(TWINT) | _BV(TWEN);
|
181 |
|
182 | /*wait, until address has been sent --> ACK*/
|
183 | while (TWSR !=0x18);
|
184 | // printf("TWSR Adresse %#04x\n ", TWSR);
|
185 | return TWSR;
|
186 | }
|
187 |
|
188 |
|
189 | unsigned char ext_eeprom_send_byte (unsigned char byte)
|
190 | {
|
191 | /*TWDR contains byte to send*/
|
192 | TWDR = byte;
|
193 | /*send content of TWDR*/
|
194 | TWCR = _BV(TWINT) | _BV(TWEN);
|
195 | /*wait, until byte has been sent --> ACK*/
|
196 | while (!(TWCR & _BV(TWINT)));
|
197 | // printf("TWSR senden %#04x\n ", TWSR);
|
198 | return TWSR;
|
199 | }
|
200 |
|
201 |
|
202 | unsigned char ext_eeprom_read_byte(void)
|
203 | {
|
204 | /*send content of TWDR; TWEA = enable ACK*/
|
205 |
|
206 | TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN);
|
207 | /*wait, until byte has been received --> ACK*/
|
208 |
|
209 |
|
210 | while (!(TWCR & _BV(TWINT)));
|
211 |
|
212 | // printf("TWSR lesen %#04x\n ", TWSR);
|
213 | return TWSR;
|
214 | }
|
215 |
|
216 |
|
217 |
|
218 |
|
219 | unsigned char eeprom_send_add_r (unsigned char address, unsigned char rw)
|
220 | {
|
221 |
|
222 | unsigned char addr_byte = 0;
|
223 |
|
224 | addr_byte |= rw;
|
225 |
|
226 | addr_byte |= address;
|
227 |
|
228 |
|
229 | TWDR = addr_byte;
|
230 | // printf("TWDR Adresse %#04x\n ", TWDR);
|
231 | /*send content of TWDR*/
|
232 | TWCR = _BV(TWINT) | _BV(TWEN);
|
233 | // printf("TWCR Adresse %#04x\n ", TWCR);
|
234 | // printf("TWSR Adresse %#04x\n ", TWSR);
|
235 | /*wait, until address has been sent --> ACK*/
|
236 | while (TWSR !=0x40);
|
237 | // printf("TWSR Adresse %#04x\n ", TWSR);
|
238 | return TWSR;
|
239 | }
|
240 |
|
241 |
|
242 |
|
243 |
|
244 |
|
245 | void write_eeprom(unsigned char adresse, unsigned char speicher_pos_x, unsigned char speicher_pos_y,
|
246 | unsigned char daten)
|
247 | {
|
248 |
|
249 |
|
250 | I2C_start(); // Startbedingung
|
251 |
|
252 | eeprom_send_add_w (adresse,0);
|
253 |
|
254 | ext_eeprom_send_byte(speicher_pos_x);
|
255 |
|
256 | ext_eeprom_send_byte(speicher_pos_y);
|
257 |
|
258 | ext_eeprom_send_byte(daten);
|
259 |
|
260 | I2C_stop();
|
261 |
|
262 | printf("schreibe: %#04x\n", daten);
|
263 | putchar('\n');
|
264 | }
|
265 |
|
266 |
|
267 |
|
268 |
|
269 | unsigned char read_eeprom(unsigned char adresse, unsigned char speicher_pos_x, unsigned char speicher_pos_y)
|
270 | {
|
271 |
|
272 | unsigned char daten; // Hilfvariable die die Daten später zurückgibt
|
273 |
|
274 |
|
275 | I2C_start(); // Startbedingung
|
276 |
|
277 | eeprom_send_add_w (adresse,0);
|
278 |
|
279 | ext_eeprom_send_byte(speicher_pos_x);
|
280 |
|
281 | ext_eeprom_send_byte(speicher_pos_y);
|
282 |
|
283 | I2C_start();
|
284 |
|
285 | eeprom_send_add_r (adresse,1);
|
286 |
|
287 | ext_eeprom_read_byte();
|
288 |
|
289 | I2C_stop();
|
290 |
|
291 | daten = TWDR;
|
292 | return daten;
|
293 |
|
294 | }
|
295 |
|
296 |
|
297 |
|
298 | FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
|
299 |
|
300 |
|
301 |
|
302 |
|
303 | int main(void)
|
304 | {
|
305 |
|
306 |
|
307 | unsigned char rv;
|
308 | unsigned char x;
|
309 | unsigned char a;
|
310 | unsigned char b;
|
311 |
|
312 | ioinit();
|
313 |
|
314 | stdout = &mystdout;
|
315 | printf("Los geht es mit schreiben.\n");
|
316 |
|
317 | for (a = 0; a < 2;)
|
318 | {
|
319 | for (x = 0; x < 16;)
|
320 | {
|
321 | write_eeprom(TWI_SLA_24CXX, a, x, 0xFF);
|
322 | printf("Postion %d schreiben: %d\n", x,x);
|
323 | x++;
|
324 | _delay_ms(20);
|
325 | }
|
326 | a++;
|
327 | }
|
328 |
|
329 | printf("Weiter geht es mit lesen.\n");
|
330 | for (a = 0; a < 2;)
|
331 | {
|
332 | for (b = 0; b < 16;)
|
333 | {
|
334 | rv = read_eeprom(TWI_SLA_24CXX, a, b);
|
335 | printf("Postion %d , %d lesen: %#04x\n ", a,b,rv);
|
336 | TWCR=0x00;
|
337 |
|
338 | b++;
|
339 | }
|
340 |
|
341 | a++;
|
342 | }
|
343 | printf("done.\n");
|
344 | return 0;
|
345 | }
|