PIC24 Support Libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pic24_i2c.c
Go to the documentation of this file.
1 /*
2  * "Copyright (c) 2008 Robert B. Reese, Bryan A. Jones, J. W. Bruce ("AUTHORS")"
3  * All rights reserved.
4  * (R. Reese, reese_AT_ece.msstate.edu, Mississippi State University)
5  * (B. A. Jones, bjones_AT_ece.msstate.edu, Mississippi State University)
6  * (J. W. Bruce, jwbruce_AT_ece.msstate.edu, Mississippi State University)
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose, without fee, and without written agreement is
10  * hereby granted, provided that the above copyright notice, the following
11  * two paragraphs and the authors appear in all copies of this software.
12  *
13  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
15  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
16  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17  *
18  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
23  *
24  * Please maintain this header in its entirety when copying/modifying
25  * these files.
26  *
27  *
28  */
29 
30 #include "pic24_i2c.h"
31 #include <stdio.h> //for NULL definition
32 #include "pic24_util.h"
33 #include "pic24_clockfreq.h"
34 
35 // Only include if this UART exists.
36 #if (NUM_I2C_MODS >= 1)
37 
38 // Documentation for this file. If the \file tag is not present,
39 // this file will not be documented.
40 // Note: place this comment below the #if NUM_I2C_MODS so Doxygen
41 // will only see it once.
42 /** \file
43  * I2C support functions. \see pic24_i2c.h for details.
44  */
45 
46 
47 /**
48 Configure and enable the I2C1 module for operation at \em u16_FkHZ kHZ clock speed.
49 \param u16_FkHZ specifies clock speed in kHZ
50 */
51 void configI2C1(uint16_t u16_FkHZ) {
52  uint32_t u32_temp;
53 
54  u32_temp = (FCY/1000L)/((uint32_t) u16_FkHZ);
55  u32_temp = u32_temp - FCY/10000000L - 1;
56  I2C1BRG = u32_temp;
57  I2C1CONbits.I2CEN = 1;
58 }
59 
60 /**
61 Operation: Perform an I2C start operation.
62 */
63 void startI2C1(void) {
64  uint8_t u8_wdtState;
65 
66  sz_lastTimeoutError = "I2C1 Start";
67  u8_wdtState = _SWDTEN; //save WDT state
68  _SWDTEN = 1; //enable WDT
69  I2C1CONbits.SEN = 1; // initiate start
70  // wait until start finished
71  while (I2C1CONbits.SEN);
72  _SWDTEN = u8_wdtState; //restore WDT
73  sz_lastTimeoutError = NULL;
74 }
75 
76 /**
77 Operation: Perform an I2C repeated start operation.
78 */
79 void rstartI2C1(void) { // repeated start
80  uint8_t u8_wdtState;
81 
82  sz_lastTimeoutError = "I2C1 RStart";
83  u8_wdtState = _SWDTEN; //save WDT state
84  _SWDTEN = 1; //enable WDT
85  I2C1CONbits.RSEN = 1; // initiate start
86  // wait until start finished
87  while (I2C1CONbits.RSEN);
88  _SWDTEN = u8_wdtState; //restore WDT
89  sz_lastTimeoutError = NULL;
90 }
91 
92 /**
93 Operation: Perform an I2C stop operation.
94 */
95 void stopI2C1(void) {
96  uint8_t u8_wdtState;
97 
98  sz_lastTimeoutError = "I2C1 Stop";
99  u8_wdtState = _SWDTEN; //save WDT state
100  _SWDTEN = 1; //enable WDT
101  I2C1CONbits.PEN=1; // initiate stop, PEN=1
102  //wait until stop finished
103  while (I2C1CONbits.PEN);
104  _SWDTEN = u8_wdtState; //restore WDT
105  sz_lastTimeoutError = NULL;
106 }
107 
108 /**
109 Operation: Send one byte (\em u8_val), if NAK is returned use reportError() function to save error and do software reset.
110 \param u8_val byte to send
111 */
112 void putI2C1(uint8_t u8_val) {
113  uint8_t u8_wdtState;
114 
115  sz_lastTimeoutError = "I2C1 Put";
116  u8_wdtState = _SWDTEN; //save WDT state
117  _SWDTEN = 1; //enable WDT
118  I2C1TRN = u8_val; // write byte
119  while (I2C1STATbits.TRSTAT); // wait for 8bits+ ack bit to finish
120  _SWDTEN = u8_wdtState; //restore WDT
121  sz_lastTimeoutError = NULL;
122  if (I2C1STATbits.ACKSTAT != I2C_ACK) {
123  //NAK returned
124  reportError("I2CPUT1, NAK returned.");
125  }
126 }
127 
128 /**
129 Operation: Send one byte (\em u8_val), return the acknowledgement bit that comes back from the slave. This
130 function does not error out if a NAK is returned.
131 \param u8_val byte to send
132 \return Ack bit value returned from slave.
133 */
135  uint8_t u8_wdtState;
136 
137  sz_lastTimeoutError = "I2C1 Put";
138  u8_wdtState = _SWDTEN; //save WDT state
139  _SWDTEN = 1; //enable WDT
140  I2C1TRN = u8_val; // write byte
141  while (I2C1STATbits.TRSTAT); // wait for 8bits+ ack bit to finish
142  _SWDTEN = u8_wdtState; //restore WDT
143  sz_lastTimeoutError = NULL;
144  return(I2C1STATbits.ACKSTAT);
145 }
146 
147 /**
148 Operation: Wait for a byte byte on the I2C bus, send \em u8_ack2Send as the acknowledgement bit to send back to the slave.
149 \param u8_ack2Send ack bit to send back to slave after byte is read
150 \return byte read from slave
151 */
152 uint8_t getI2C1(uint8_t u8_ack2Send) {
153  uint8_t u8_wdtState;
154  uint8_t u8_inByte;
155 
156  sz_lastTimeoutError = "I2C1 Get";
157  u8_wdtState = _SWDTEN; //save WDT state
158  _SWDTEN = 1; //enable WDT
159  while (I2C1CON & 0x1F); //wait for idle condition
160  I2C1CONbits.RCEN = 1; //enable receive
161  while (!I2C1STATbits.RBF); //wait for receive byte
162  CLRWDT();
163  u8_inByte = I2C1RCV; //read byte;
164  //wait for idle condition before attempting ACK
165  while (I2C1CON & 0x1F); //lower 5 bits must be 0
166  I2C1CONbits.ACKDT = u8_ack2Send; //ACK bit to send back on receive
167  I2C1CONbits.ACKEN = 1; //enable ACKbit transmittion
168  while (I2C1CONbits.ACKEN); //wait for completion
169  _SWDTEN = u8_wdtState; //restore WDT
170  sz_lastTimeoutError = NULL;
171  return(u8_inByte); //return the value
172 }
173 /**
174 Transaction: Write 1 byte (\em u8_d1) to I2C slave at address \em u8_addr.
175 \param u8_addr Slave I2C address
176 \param u8_d1 Byte to send
177 */
178 void write1I2C1(uint8_t u8_addr,uint8_t u8_d1) {
179  startI2C1();
180  putI2C1(I2C_WADDR(u8_addr));
181  putI2C1(u8_d1);
182  stopI2C1();
183 }
184 /**
185 Transaction: Write 2 bytes (\em u8_d1, \em u8_d2) to I2C slave at address \em u8_addr.
186 \param u8_addr Slave I2C address
187 \param u8_d1 First byte to send
188 \param u8_d2 Second byte to send
189 */
190 void write2I2C1(uint8_t u8_addr,uint8_t u8_d1, uint8_t u8_d2) {
191  startI2C1();
192  putI2C1(I2C_WADDR(u8_addr));
193  putI2C1(u8_d1);
194  putI2C1(u8_d2);
195  stopI2C1();
196 }
197 
198 /**
199 Transaction: Write \em u16_cnt bytes stored in buffer \em *pu8_data to I2C slave at address \em u8_addr.
200 \param u8_addr Slave I2C address
201 \param pu8_data Pointer to buffer containing bytes to send
202 \param u16_cnt Number of bytes to send
203 */
204 void writeNI2C1(uint8_t u8_addr,uint8_t* pu8_data, uint16_t u16_cnt) {
205  uint16_t u16_i;
206  startI2C1();
207  putI2C1(I2C_WADDR(u8_addr));
208  for (u16_i=0; u16_i < u16_cnt; u16_i++) {
209  putI2C1(*pu8_data);
210  pu8_data++;
211  }
212  stopI2C1();
213 }
214 /**
215 Transaction: Read one byte from I2C slave at address \em u8_addr, save to \em *pu8_d1.
216 As per the I2C standard, a NAK is returned for the last byte read from the slave, ACKs are returned for the other bytes.
217 \param u8_addr Slave I2C address
218 \param pu8_d1 Pointer to location to store byte read from slave
219 */
220 void read1I2C1(uint8_t u8_addr,uint8_t* pu8_d1) {
221  startI2C1();
222  putI2C1(I2C_RADDR(u8_addr));
223  *pu8_d1 = getI2C1(I2C_NAK); //last ack bit from master to slave during read must be a NAK
224  stopI2C1();
225 }
226 /**
227 Transaction: Read two bytes from I2C slave at address \em u8_addr, save to \em *pu8_d1, \em *pu8_d2.
228 As per the I2C standard, a NAK is returned for the last byte read from the slave, ACKs are returned for the other bytes.
229 \param u8_addr Slave I2C address
230 \param pu8_d1 Pointer to location to store first byte read from slave
231 \param pu8_d2 Pointer to location to store second byte read from slave
232 */
233 void read2I2C1(uint8_t u8_addr,uint8_t* pu8_d1, uint8_t* pu8_d2) {
234  startI2C1();
235  putI2C1(I2C_RADDR(u8_addr));
236  *pu8_d1 = getI2C1(I2C_ACK);
237  *pu8_d2 = getI2C1(I2C_NAK);
238  stopI2C1();
239 }
240 /**
241 Transaction: Read \em u16_cnt bytes from I2C slave at address \em u8_addr, save to buffer \em *pu8_data.
242 As per the I2C standard, a NAK is returned for the last byte read from the slave, ACKs are returned for the other bytes.
243 \param u8_addr Slave I2C address
244 \param pu8_data Pointer to buffer for storing bytes read from slave
245 \param u16_cnt Number of bytes read from slave.
246 */
247 void readNI2C1(uint8_t u8_addr,uint8_t* pu8_data, uint16_t u16_cnt) {
248  uint16_t u16_i;
249  startI2C1();
250  putI2C1(I2C_RADDR(u8_addr));
251  for (u16_i=0; u16_i < u16_cnt; u16_i++) {
252  if (u16_i != u16_cnt-1) *pu8_data = getI2C1(I2C_ACK);
253  else *pu8_data = getI2C1(I2C_NAK);
254  pu8_data++;
255  }
256  stopI2C1();
257 }
258 
259 #endif // #if (NUM_I2C_MODS >= 1)
260 
261 
262 
263 
264 
265 
266 
267 
268 
269 
270 
271 
272 /*
273  * "Copyright (c) 2008 Robert B. Reese, Bryan A. Jones, J. W. Bruce ("AUTHORS")"
274  * All rights reserved.
275  * (R. Reese, reese_AT_ece.msstate.edu, Mississippi State University)
276  * (B. A. Jones, bjones_AT_ece.msstate.edu, Mississippi State University)
277  * (J. W. Bruce, jwbruce_AT_ece.msstate.edu, Mississippi State University)
278  *
279  * Permission to use, copy, modify, and distribute this software and its
280  * documentation for any purpose, without fee, and without written agreement is
281  * hereby granted, provided that the above copyright notice, the following
282  * two paragraphs and the authors appear in all copies of this software.
283  *
284  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
285  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
286  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
287  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
288  *
289  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
290  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
291  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
292  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
293  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
294  *
295  * Please maintain this header in its entirety when copying/modifying
296  * these files.
297  *
298  *
299  */
300 
301 #include "pic24_i2c.h"
302 #include <stdio.h> //for NULL definition
303 #include "pic24_util.h"
304 #include "pic24_clockfreq.h"
305 
306 // Only include if this UART exists.
307 #if (NUM_I2C_MODS >= 2)
308 
309 // Documentation for this file. If the \file tag is not present,
310 // this file will not be documented.
311 // Note: place this comment below the #if NUM_I2C_MODS so Doxygen
312 // will only see it once.
313 /** \file
314  * I2C support functions. \see pic24_i2c.h for details.
315  */
316 
317 
318 /**
319 Configure and enable the I2C2 module for operation at \em u16_FkHZ kHZ clock speed.
320 \param u16_FkHZ specifies clock speed in kHZ
321 */
322 void configI2C2(uint16_t u16_FkHZ) {
323  uint32_t u32_temp;
324 
325  u32_temp = (FCY/1000L)/((uint32_t) u16_FkHZ);
326  u32_temp = u32_temp - FCY/10000000L - 1;
327  I2C2BRG = u32_temp;
328  I2C2CONbits.I2CEN = 1;
329 }
330 
331 /**
332 Operation: Perform an I2C start operation.
333 */
334 void startI2C2(void) {
335  uint8_t u8_wdtState;
336 
337  sz_lastTimeoutError = "I2C2 Start";
338  u8_wdtState = _SWDTEN; //save WDT state
339  _SWDTEN = 1; //enable WDT
340  I2C2CONbits.SEN = 1; // initiate start
341  // wait until start finished
342  while (I2C2CONbits.SEN);
343  _SWDTEN = u8_wdtState; //restore WDT
344  sz_lastTimeoutError = NULL;
345 }
346 
347 /**
348 Operation: Perform an I2C repeated start operation.
349 */
350 void rstartI2C2(void) { // repeated start
351  uint8_t u8_wdtState;
352 
353  sz_lastTimeoutError = "I2C2 RStart";
354  u8_wdtState = _SWDTEN; //save WDT state
355  _SWDTEN = 1; //enable WDT
356  I2C2CONbits.RSEN = 1; // initiate start
357  // wait until start finished
358  while (I2C2CONbits.RSEN);
359  _SWDTEN = u8_wdtState; //restore WDT
360  sz_lastTimeoutError = NULL;
361 }
362 
363 /**
364 Operation: Perform an I2C stop operation.
365 */
366 void stopI2C2(void) {
367  uint8_t u8_wdtState;
368 
369  sz_lastTimeoutError = "I2C2 Stop";
370  u8_wdtState = _SWDTEN; //save WDT state
371  _SWDTEN = 1; //enable WDT
372  I2C2CONbits.PEN=1; // initiate stop, PEN=1
373  //wait until stop finished
374  while (I2C2CONbits.PEN);
375  _SWDTEN = u8_wdtState; //restore WDT
376  sz_lastTimeoutError = NULL;
377 }
378 
379 /**
380 Operation: Send one byte (\em u8_val), if NAK is returned use reportError() function to save error and do software reset.
381 \param u8_val byte to send
382 */
383 void putI2C2(uint8_t u8_val) {
384  uint8_t u8_wdtState;
385 
386  sz_lastTimeoutError = "I2C2 Put";
387  u8_wdtState = _SWDTEN; //save WDT state
388  _SWDTEN = 1; //enable WDT
389  I2C2TRN = u8_val; // write byte
390  while (I2C2STATbits.TRSTAT); // wait for 8bits+ ack bit to finish
391  _SWDTEN = u8_wdtState; //restore WDT
392  sz_lastTimeoutError = NULL;
393  if (I2C2STATbits.ACKSTAT != I2C_ACK) {
394  //NAK returned
395  reportError("I2CPUT2, NAK returned.");
396  }
397 }
398 
399 /**
400 Operation: Send one byte (\em u8_val), return the acknowledgement bit that comes back from the slave. This
401 function does not error out if a NAK is returned.
402 \param u8_val byte to send
403 \return Ack bit value returned from slave.
404 */
405 uint8_t putNoAckCheckI2C2(uint8_t u8_val) {
406  uint8_t u8_wdtState;
407 
408  sz_lastTimeoutError = "I2C2 Put";
409  u8_wdtState = _SWDTEN; //save WDT state
410  _SWDTEN = 1; //enable WDT
411  I2C2TRN = u8_val; // write byte
412  while (I2C2STATbits.TRSTAT); // wait for 8bits+ ack bit to finish
413  _SWDTEN = u8_wdtState; //restore WDT
414  sz_lastTimeoutError = NULL;
415  return(I2C2STATbits.ACKSTAT);
416 }
417 
418 /**
419 Operation: Wait for a byte byte on the I2C bus, send \em u8_ack2Send as the acknowledgement bit to send back to the slave.
420 \param u8_ack2Send ack bit to send back to slave after byte is read
421 \return byte read from slave
422 */
423 uint8_t getI2C2(uint8_t u8_ack2Send) {
424  uint8_t u8_wdtState;
425  uint8_t u8_inByte;
426 
427  sz_lastTimeoutError = "I2C2 Get";
428  u8_wdtState = _SWDTEN; //save WDT state
429  _SWDTEN = 1; //enable WDT
430  while (I2C2CON & 0x1F); //wait for idle condition
431  I2C2CONbits.RCEN = 1; //enable receive
432  while (!I2C2STATbits.RBF); //wait for receive byte
433  CLRWDT();
434  u8_inByte = I2C2RCV; //read byte;
435  //wait for idle condition before attempting ACK
436  while (I2C2CON & 0x1F); //lower 5 bits must be 0
437  I2C2CONbits.ACKDT = u8_ack2Send; //ACK bit to send back on receive
438  I2C2CONbits.ACKEN = 1; //enable ACKbit transmittion
439  while (I2C2CONbits.ACKEN); //wait for completion
440  _SWDTEN = u8_wdtState; //restore WDT
441  sz_lastTimeoutError = NULL;
442  return(u8_inByte); //return the value
443 }
444 /**
445 Transaction: Write 1 byte (\em u8_d1) to I2C slave at address \em u8_addr.
446 \param u8_addr Slave I2C address
447 \param u8_d1 Byte to send
448 */
449 void write1I2C2(uint8_t u8_addr,uint8_t u8_d1) {
450  startI2C2();
451  putI2C2(I2C_WADDR(u8_addr));
452  putI2C2(u8_d1);
453  stopI2C2();
454 }
455 /**
456 Transaction: Write 2 bytes (\em u8_d1, \em u8_d2) to I2C slave at address \em u8_addr.
457 \param u8_addr Slave I2C address
458 \param u8_d1 First byte to send
459 \param u8_d2 Second byte to send
460 */
461 void write2I2C2(uint8_t u8_addr,uint8_t u8_d1, uint8_t u8_d2) {
462  startI2C2();
463  putI2C2(I2C_WADDR(u8_addr));
464  putI2C2(u8_d1);
465  putI2C2(u8_d2);
466  stopI2C2();
467 }
468 
469 /**
470 Transaction: Write \em u16_cnt bytes stored in buffer \em *pu8_data to I2C slave at address \em u8_addr.
471 \param u8_addr Slave I2C address
472 \param pu8_data Pointer to buffer containing bytes to send
473 \param u16_cnt Number of bytes to send
474 */
475 void writeNI2C2(uint8_t u8_addr,uint8_t* pu8_data, uint16_t u16_cnt) {
476  uint16_t u16_i;
477  startI2C2();
478  putI2C2(I2C_WADDR(u8_addr));
479  for (u16_i=0; u16_i < u16_cnt; u16_i++) {
480  putI2C2(*pu8_data);
481  pu8_data++;
482  }
483  stopI2C2();
484 }
485 /**
486 Transaction: Read one byte from I2C slave at address \em u8_addr, save to \em *pu8_d1.
487 As per the I2C standard, a NAK is returned for the last byte read from the slave, ACKs are returned for the other bytes.
488 \param u8_addr Slave I2C address
489 \param pu8_d1 Pointer to location to store byte read from slave
490 */
491 void read1I2C2(uint8_t u8_addr,uint8_t* pu8_d1) {
492  startI2C2();
493  putI2C2(I2C_RADDR(u8_addr));
494  *pu8_d1 = getI2C2(I2C_NAK); //last ack bit from master to slave during read must be a NAK
495  stopI2C2();
496 }
497 /**
498 Transaction: Read two bytes from I2C slave at address \em u8_addr, save to \em *pu8_d1, \em *pu8_d2.
499 As per the I2C standard, a NAK is returned for the last byte read from the slave, ACKs are returned for the other bytes.
500 \param u8_addr Slave I2C address
501 \param pu8_d1 Pointer to location to store first byte read from slave
502 \param pu8_d2 Pointer to location to store second byte read from slave
503 */
504 void read2I2C2(uint8_t u8_addr,uint8_t* pu8_d1, uint8_t* pu8_d2) {
505  startI2C2();
506  putI2C2(I2C_RADDR(u8_addr));
507  *pu8_d1 = getI2C2(I2C_ACK);
508  *pu8_d2 = getI2C2(I2C_NAK);
509  stopI2C2();
510 }
511 /**
512 Transaction: Read \em u16_cnt bytes from I2C slave at address \em u8_addr, save to buffer \em *pu8_data.
513 As per the I2C standard, a NAK is returned for the last byte read from the slave, ACKs are returned for the other bytes.
514 \param u8_addr Slave I2C address
515 \param pu8_data Pointer to buffer for storing bytes read from slave
516 \param u16_cnt Number of bytes read from slave.
517 */
518 void readNI2C2(uint8_t u8_addr,uint8_t* pu8_data, uint16_t u16_cnt) {
519  uint16_t u16_i;
520  startI2C2();
521  putI2C2(I2C_RADDR(u8_addr));
522  for (u16_i=0; u16_i < u16_cnt; u16_i++) {
523  if (u16_i != u16_cnt-1) *pu8_data = getI2C2(I2C_ACK);
524  else *pu8_data = getI2C2(I2C_NAK);
525  pu8_data++;
526  }
527  stopI2C2();
528 }
529 
530 #endif // #if (NUM_I2C_MODS >= 2)
531 
532 
533 
534 
535 
536 
537 
538 
539 
540 
541 
542