Rev 17 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
17 | jlesech | 1 | /**************************************************************************//** |
2 | * \brief TWI library |
||
3 | * \author Copyright (C) 2009 Julien Le Sech - www.idreammicro.com |
||
4 | * \version 1.0 |
||
5 | * \date 20090501 |
||
6 | * |
||
7 | * This file is part of the iDreamMicro library. |
||
8 | * |
||
9 | * This library is free software: you can redistribute it and/or modify it under |
||
10 | * the terms of the GNU Lesser General Public License as published by the Free |
||
11 | * Software Foundation, either version 3 of the License, or (at your option) any |
||
12 | * later version. |
||
13 | * |
||
14 | * This library is distributed in the hope that it will be useful, but WITHOUT |
||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
||
16 | * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
||
17 | * details. |
||
18 | * |
||
19 | * You should have received a copy of the GNU Lesser General Public License |
||
20 | * along with this program. If not, see http://www.gnu.org/licenses/ |
||
21 | ******************************************************************************/ |
||
22 | |||
23 | /**************************************************************************//** |
||
24 | * \file twi.c |
||
25 | ******************************************************************************/ |
||
26 | |||
27 | /****************************************************************************** |
||
28 | * Header file inclusions. |
||
29 | ******************************************************************************/ |
||
30 | |||
31 | #include <twi/twi.h> |
||
32 | #include <useful/bits.h> |
||
33 | |||
34 | #include <avr/io.h> |
||
35 | #include <util/twi.h> |
||
36 | |||
37 | #include <assert.h> |
||
38 | #include <stdint.h> |
||
39 | #include <stdlib.h> |
||
40 | |||
41 | /****************************************************************************** |
||
42 | * Private macros. |
||
43 | ******************************************************************************/ |
||
44 | |||
45 | /**************************************************************************//** |
||
46 | * \def TWI__MAX_FREQUENCY |
||
47 | * \brief Max frequency of TWI bus. |
||
48 | ******************************************************************************/ |
||
49 | #define TWI__MAX_FREQUENCY 400000 |
||
50 | |||
51 | /****************************************************************************** |
||
52 | * Private types. |
||
53 | ******************************************************************************/ |
||
54 | |||
55 | /**************************************************************************//** |
||
56 | * \enum twi__prescaler_values |
||
57 | * \brief Available TWI bus prescaler values. |
||
58 | * |
||
59 | * \typedef twi__prescaler_value_t |
||
60 | * \brief TWI bus prescaler value. |
||
61 | ******************************************************************************/ |
||
62 | typedef enum twi__prescaler_values |
||
63 | { |
||
64 | TWI__PRESCALER_VALUE__1, |
||
65 | TWI__PRESCALER_VALUE__4, |
||
66 | TWI__PRESCALER_VALUE__16, |
||
67 | TWI__PRESCALER_VALUE__64, |
||
68 | TWI__PRESCALER_VALUE__INVALID |
||
69 | } twi__prescaler_value_t; |
||
70 | |||
71 | /**************************************************************************//** |
||
72 | * \struct twi__prescaler_configuration |
||
73 | * \brief TWI bus prescaler configuration. |
||
74 | * |
||
75 | * \typedef twi__prescaler_configuration_t |
||
76 | * \brief TWI bus prescaler configuration. |
||
77 | ******************************************************************************/ |
||
78 | typedef struct twi__prescaler_configuration |
||
79 | { |
||
80 | uint8_t value; |
||
81 | uint8_t bits; |
||
82 | } twi__prescaler_configuration_t; |
||
83 | |||
84 | /****************************************************************************** |
||
85 | * Private constant definitions. |
||
86 | ******************************************************************************/ |
||
87 | |||
88 | /**************************************************************************//** |
||
89 | * \var prescaler_configurations |
||
90 | * \brief Available prescaler configurations. |
||
91 | ******************************************************************************/ |
||
92 | static const twi__prescaler_configuration_t prescaler_configurations[] = |
||
93 | { |
||
94 | [TWI__PRESCALER_VALUE__1] = |
||
95 | { |
||
96 | .value = 1, |
||
97 | .bits = 0 |
||
98 | }, |
||
99 | [TWI__PRESCALER_VALUE__4] = |
||
100 | { |
||
101 | .value = 4, |
||
102 | .bits = _BV(TWPS0) |
||
103 | }, |
||
104 | [TWI__PRESCALER_VALUE__16] = |
||
105 | { |
||
106 | .value = 16, |
||
107 | .bits = _BV(TWPS1) |
||
108 | }, |
||
109 | [TWI__PRESCALER_VALUE__64] = |
||
110 | { |
||
111 | .value = 64, |
||
112 | .bits = _BV(TWPS1) | _BV(TWPS0) |
||
113 | } |
||
114 | }; |
||
115 | |||
116 | /****************************************************************************** |
||
117 | * Private function prototypes. |
||
118 | ******************************************************************************/ |
||
119 | |||
120 | /**************************************************************************//** |
||
121 | * \fn static inline uint8_t twi__compute_bit_rate( |
||
122 | * uint32_t f_scl, |
||
123 | * uint8_t prescaler_value) |
||
124 | * |
||
125 | * \brief |
||
126 | * |
||
127 | * \param f_scl SCL frequency. |
||
128 | * \param prescaler_value Prescaler value. |
||
129 | ******************************************************************************/ |
||
130 | static inline |
||
131 | uint8_t |
||
132 | twi__compute_bit_rate |
||
133 | ( |
||
134 | uint32_t f_scl, |
||
135 | uint8_t prescaler_value |
||
136 | ); |
||
137 | |||
138 | /****************************************************************************** |
||
139 | * Public function definitions. |
||
140 | ******************************************************************************/ |
||
141 | |||
142 | /**************************************************************************//** |
||
143 | * \fn void twi__initialize(uint32_t frequency) |
||
144 | * |
||
145 | * \brief Initialize TWI. |
||
146 | * |
||
147 | * \param frequency TWI frequency (up to 400 kHz). |
||
148 | ******************************************************************************/ |
||
149 | void twi__initialize |
||
150 | ( |
||
151 | uint32_t frequency |
||
152 | ){ |
||
153 | // Check the preconditions. |
||
154 | assert(TWI__MAX_FREQUENCY >= frequency); |
||
155 | |||
156 | uint16_t bit_rate = UINT16_MAX; |
||
157 | twi__prescaler_value_t prescaler_value = TWI__PRESCALER_VALUE__1; |
||
158 | |||
159 | // Compute bit rate and prescaler value. |
||
160 | do |
||
161 | { |
||
162 | bit_rate = twi__compute_bit_rate |
||
163 | ( |
||
164 | frequency, |
||
165 | prescaler_configurations[prescaler_value].value |
||
166 | ); |
||
167 | } while (UINT8_MAX < bit_rate && TWI__PRESCALER_VALUE__INVALID > prescaler_value++); |
||
168 | |||
169 | // Set bit rate. |
||
170 | TWBR = bit_rate; |
||
171 | |||
172 | // Set prescaler value. |
||
173 | TWSR = prescaler_configurations[prescaler_value].bits; |
||
174 | } |
||
175 | |||
176 | /**************************************************************************//** |
||
177 | * \fn twi__error_t twi__start(void) |
||
178 | * |
||
179 | * \brief |
||
180 | ******************************************************************************/ |
||
181 | twi__error_t |
||
182 | twi__start |
||
183 | ( |
||
47 | jlesech | 184 | void |
17 | jlesech | 185 | ){ |
47 | jlesech | 186 | // Send start condition. |
187 | TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); |
||
17 | jlesech | 188 | |
47 | jlesech | 189 | // Wait for TWINT flag set. This indicates that the START condition has |
190 | // been transmitted. |
||
191 | while (!(TWCR & (1 << TWINT))); |
||
17 | jlesech | 192 | |
47 | jlesech | 193 | // Check value of TWI Status Register. Mask prescaler bits. |
194 | if (TWSR & TW_NO_INFO != TW_START) |
||
195 | { |
||
196 | // If status is different from START (TW_START), return error. |
||
197 | return TWI__ERROR__ERROR; |
||
198 | } |
||
199 | |||
200 | return TWI__ERROR__NONE; |
||
17 | jlesech | 201 | } |
202 | |||
203 | /**************************************************************************//** |
||
204 | * \fn twi__error_t twi__repeat_start(void) |
||
205 | * |
||
206 | * \brief |
||
207 | ******************************************************************************/ |
||
208 | twi__error_t |
||
209 | twi__repeat_start |
||
210 | ( |
||
47 | jlesech | 211 | void |
17 | jlesech | 212 | ){ |
47 | jlesech | 213 | // TODO: check if TWSTO must be set. |
214 | // Send start condition. |
||
215 | TWCR = (1 << TWEN) | (1 << TWINT) | (1 << TWSTA) | (1 << TWSTO); |
||
17 | jlesech | 216 | |
47 | jlesech | 217 | // Wait for TWINT flag set. This indicates that the START condition has |
218 | // been transmitted. |
||
219 | while (!(TWCR & (1 << TWINT))); |
||
17 | jlesech | 220 | |
47 | jlesech | 221 | // Check value of TWI Status Register. Mask prescaler bits. |
222 | if (TWSR & TW_NO_INFO != TW_REP_START) |
||
223 | { |
||
224 | // If status different from START (TW_REP_START), return error. |
||
225 | return TWI__ERROR__ERROR; |
||
226 | } |
||
227 | |||
228 | return TWI__ERROR__NONE; |
||
17 | jlesech | 229 | } |
230 | |||
231 | /**************************************************************************//** |
||
232 | * \fn twi__error_t twi__send_slar(uint8_t sla) |
||
233 | * |
||
234 | * \brief |
||
235 | * |
||
236 | * \param sla |
||
237 | ******************************************************************************/ |
||
238 | twi__error_t |
||
239 | twi__send_slar |
||
240 | ( |
||
241 | uint8_t sla |
||
242 | ){ |
||
47 | jlesech | 243 | // Load SLA into TWDR register. |
244 | TWDR = sla | TW_READ; |
||
17 | jlesech | 245 | |
47 | jlesech | 246 | // Clear TWINT bit in TWCR to start transmission of address. |
247 | TWCR = (1 << TWINT) | (1 << TWEN); |
||
17 | jlesech | 248 | |
47 | jlesech | 249 | // Wait for TWINT flag set. This indicates that the SLA+W (TW_WRITE) has |
250 | // been transmitted, and ACK/NACK has been received. |
||
251 | while (!(TWCR & (1 << TWINT))); |
||
17 | jlesech | 252 | |
47 | jlesech | 253 | // Check value of TWI Status Register. Mask prescaler bits. If status |
254 | // different from MT_SLA_ACK (TW_MR_SLA_ACK), return error. |
||
255 | if (TWSR & TW_NO_INFO != TW_MR_SLA_ACK) |
||
256 | { |
||
257 | return TWI__ERROR__ERROR; |
||
258 | } |
||
17 | jlesech | 259 | |
47 | jlesech | 260 | return TWI__ERROR__NONE; |
17 | jlesech | 261 | } |
262 | |||
263 | /**************************************************************************//** |
||
264 | * \fn twi__error_t twi__send_slaw(uint8_t sla) |
||
265 | * |
||
266 | * \brief |
||
267 | * |
||
268 | * \param sla |
||
269 | ******************************************************************************/ |
||
270 | twi__error_t |
||
271 | twi__send_slaw |
||
272 | ( |
||
273 | uint8_t sla |
||
274 | ){ |
||
47 | jlesech | 275 | // Load SLA into TWDR register. |
276 | TWDR = sla | TW_WRITE; |
||
17 | jlesech | 277 | |
47 | jlesech | 278 | // Clear TWINT bit in TWCR to start transmission of address. |
279 | TWCR = (1 << TWINT) | (1 << TWEN); |
||
17 | jlesech | 280 | |
47 | jlesech | 281 | // Wait for TWINT flag set. This indicates that the SLA+W (TW_WRITE) has |
282 | // been transmitted, and ACK/NACK has been received. |
||
283 | while (!(TWCR & (1 << TWINT))); |
||
17 | jlesech | 284 | |
47 | jlesech | 285 | // Check value of TWI Status Register. Mask prescaler bits. If status |
286 | // different from MT_SLA_ACK (TW_MT_SLA_ACK), return error. |
||
287 | if (TWSR & TW_NO_INFO != TW_MT_SLA_ACK) |
||
288 | { |
||
289 | return TWI__ERROR__ERROR; |
||
290 | } |
||
17 | jlesech | 291 | |
47 | jlesech | 292 | return TWI__ERROR__NONE; |
17 | jlesech | 293 | } |
294 | |||
295 | /**************************************************************************//** |
||
296 | * \fn twi__error_t twi__send_data(uint8_t data) |
||
297 | * |
||
298 | * \brief |
||
299 | * |
||
300 | * \param data Data to send. |
||
301 | ******************************************************************************/ |
||
302 | twi__error_t |
||
303 | twi__send_data |
||
304 | ( |
||
47 | jlesech | 305 | uint8_t data |
17 | jlesech | 306 | ){ |
47 | jlesech | 307 | // Load data into TWDR register. |
308 | TWDR = data; |
||
17 | jlesech | 309 | |
47 | jlesech | 310 | // Clear TWINT bit in TWCR to start transmission of data. |
311 | TWCR = (1 << TWINT) | (1 << TWEN); |
||
17 | jlesech | 312 | |
47 | jlesech | 313 | // Wait for TWINT flag set. This indicates that the data has been |
314 | // transmitted, and ACK/NACK has been receiver. |
||
315 | while (!(TWCR & (1 << TWINT))); |
||
316 | |||
317 | // Check value of TWI status register. Mask prescaler bits. If status |
||
318 | // different from MT_DATA_ACK (TW_MT_DATA_ACK), return error. |
||
319 | if (TWSR & TW_NO_INFO != TW_MT_DATA_ACK) |
||
320 | { |
||
321 | return TWI__ERROR__ERROR; |
||
322 | } |
||
323 | |||
324 | return TWI__ERROR__NONE; |
||
17 | jlesech | 325 | } |
326 | |||
327 | /**************************************************************************//** |
||
328 | * \fn twi__error_t twi__receive_data_ack(uint8_t* p_data) |
||
329 | * |
||
330 | * \brief |
||
331 | * |
||
332 | * \param p_data |
||
333 | ******************************************************************************/ |
||
334 | twi__error_t |
||
335 | twi__receive_data_ack |
||
336 | ( |
||
47 | jlesech | 337 | uint8_t* p_data |
17 | jlesech | 338 | ){ |
47 | jlesech | 339 | // Check the preconditions. |
340 | assert(NULL != p_data); |
||
17 | jlesech | 341 | |
47 | jlesech | 342 | TWCR = (1 << TWEN) | (1 << TWINT) | (1 << TWEA); |
17 | jlesech | 343 | |
47 | jlesech | 344 | while (!(TWCR & (1 << TWINT))); |
17 | jlesech | 345 | |
47 | jlesech | 346 | if ((TWSR & TW_NO_INFO) != TW_MR_DATA_ACK) |
347 | { |
||
348 | return TWI__ERROR__ERROR; |
||
349 | } |
||
350 | |||
351 | *p_data = TWDR; |
||
352 | |||
353 | return TWI__ERROR__NONE; |
||
17 | jlesech | 354 | } |
355 | |||
356 | /**************************************************************************//** |
||
357 | * \fn twi__error_t twi__receive_data_nack(uint8_t* p_data) |
||
358 | * |
||
359 | * \brief |
||
360 | * |
||
361 | * \param p_data |
||
362 | ******************************************************************************/ |
||
363 | twi__error_t |
||
364 | twi__receive_data_nack |
||
365 | ( |
||
47 | jlesech | 366 | uint8_t* p_data |
17 | jlesech | 367 | ){ |
47 | jlesech | 368 | // Check the preconditions. |
369 | assert(NULL != p_data); |
||
17 | jlesech | 370 | |
47 | jlesech | 371 | TWCR = (1 << TWEN) | (1 << TWINT); |
17 | jlesech | 372 | |
47 | jlesech | 373 | while (!(TWCR & (1 << TWINT))); |
374 | |||
375 | if ((TWSR & TW_NO_INFO) != TW_MR_DATA_NACK) |
||
376 | { |
||
377 | return TWI__ERROR__ERROR; |
||
378 | } |
||
379 | |||
380 | *p_data = TWDR; |
||
381 | |||
382 | return TWI__ERROR__NONE; |
||
17 | jlesech | 383 | } |
384 | |||
385 | /**************************************************************************//** |
||
386 | * \fn void twi__stop(void) |
||
387 | * |
||
388 | * \brief Stop TWI. |
||
389 | ******************************************************************************/ |
||
390 | void |
||
391 | twi__stop |
||
392 | ( |
||
47 | jlesech | 393 | void |
17 | jlesech | 394 | ){ |
47 | jlesech | 395 | // Transmit stop operation. |
396 | TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); |
||
397 | |||
398 | // Wait for stop. |
||
399 | while (TWCR & (1 << TWSTO)); |
||
17 | jlesech | 400 | } |
401 | |||
402 | /****************************************************************************** |
||
403 | * Private function definitions. |
||
404 | ******************************************************************************/ |
||
405 | |||
406 | /**************************************************************************//** |
||
407 | * \fn static inline uint8_t twi__compute_bit_rate( |
||
408 | * uint32_t f_scl, |
||
409 | * uint8_t prescaler_value) |
||
410 | * |
||
411 | * \brief |
||
412 | * |
||
413 | * \param f_scl SCL frequency. |
||
414 | * \param prescaler_value Prescaler value. |
||
415 | ******************************************************************************/ |
||
416 | static inline |
||
417 | uint8_t |
||
418 | twi__compute_bit_rate |
||
419 | ( |
||
420 | uint32_t f_scl, |
||
421 | uint8_t prescaler_value |
||
422 | ){ |
||
423 | uint8_t bit_rate = (F_CPU - 16 * f_scl) / (2 * f_scl * prescaler_value); |
||
424 | |||
425 | return bit_rate; |
||
426 | } |