LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
i2c.c
Go to the documentation of this file.
1 /*
2  * @brief I2C example
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2012
6  * All rights reserved.
7  *
8  * @par
9  * Software that is described herein is for illustrative purposes only
10  * which provides customers with programming information regarding the
11  * LPC products. This software is supplied "AS IS" without any warranties of
12  * any kind, and NXP Semiconductors and its licensor disclaim any and
13  * all warranties, express or implied, including all implied warranties of
14  * merchantability, fitness for a particular purpose and non-infringement of
15  * intellectual property rights. NXP Semiconductors assumes no responsibility
16  * or liability for the use of the software, conveys no license or rights under any
17  * patent, copyright, mask work right, or any other intellectual property rights in
18  * or to any products. NXP Semiconductors reserves the right to make changes
19  * in the software without notification. NXP Semiconductors also makes no
20  * representation or warranty that such application will be suitable for the
21  * specified use without further testing or modification.
22  *
23  * @par
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation is hereby granted, under NXP Semiconductors' and its
26  * licensor's relevant copyrights in the software, without fee, provided that it
27  * is used in conjunction with NXP Semiconductors microcontrollers. This
28  * copyright, permission, and disclaimer notice must appear in all copies of
29  * this code.
30  */
31 
32 #include <stdlib.h>
33 #include <string.h>
34 #include "board.h"
35 
71 /*****************************************************************************
72  * Private types/enumerations/variables
73  ****************************************************************************/
74 #define DEFAULT_I2C I2C0
75 
76 #define I2C_EEPROM_BUS DEFAULT_I2C
77 #define I2C_IOX_BUS DEFAULT_I2C
78 
79 #define SPEED_100KHZ 100000
80 #define SPEED_400KHZ 400000
81 
82 #ifdef DEBUG_ENABLE
83 static const char menu[] =
84 "**************** I2C Demo Menu ****************\r\n"
85 "\t0: Exit Demo\r\n"
86 "\t1: Select I2C peripheral [\033[1;32mI2C%d\033[0;37m]\r\n"
87 "\t2: Toggle mode POLLING/INTERRUPT [\033[1;32m%s\033[0;37m]\r\n"
88 "\t3: Probe for Slave devices\r\n"
89 "\t4: Read slave data\r\n"
90 "\t5: Write slave data\r\n"
91 "\t6: Write/Read slave data\r\n";
92 #endif
93 
94 static int mode_poll; /* Poll/Interrupt mode flag */
95 static I2C_ID_T i2cDev = DEFAULT_I2C; /* Currently active I2C device */
96 
97 /* EEPROM SLAVE data */
98 #define I2C_SLAVE_EEPROM_SIZE 64
99 #define I2C_SLAVE_EEPROM_ADDR 0x5A
100 #define I2C_SLAVE_IOX_ADDR 0x5B
101 
102 /* Xfer structure for slave operations */
105 
106 /* Data area for slave operations */
107 static uint8_t seep_data[I2C_SLAVE_EEPROM_SIZE + 1];
108 static uint8_t buffer[2][256];
109 static uint8_t iox_data[2]; /* PORT0 input port, PORT1 Output port */
110 static volatile uint32_t tick_cnt;
111 
112 /*****************************************************************************
113  * Public types/enumerations/variables
114  ****************************************************************************/
115 
116 /*****************************************************************************
117  * Private functions
118  ****************************************************************************/
119 
120 /* State machine handler for I2C0 and I2C1 */
122 {
123  if (Chip_I2C_IsMasterActive(id)) {
125  } else {
127  }
128 }
129 
130 /* Print data to console */
131 static void con_print_data(const uint8_t *dat, int sz)
132 {
133  int i;
134  if (!sz) return;
135  for (i = 0; i < sz; i++) {
136  if (!(i & 0xF)) DEBUGOUT("\r\n%02X: ", i);
137  DEBUGOUT(" %02X", dat[i]);
138  }
139  DEBUGOUT("\r\n");
140 }
141 
142 /* Get an integer input from UART */
143 static int con_get_input(const char *str)
144 {
145 #ifdef DEBUG_ENABLE
146  int input_valid = 0;
147  int x;
148  char ch[16], *ptr;
149  int i = 0;
150 
151  while (!input_valid) {
152  DEBUGOUT("%s", str);
153  while(1) {
154  /* Setting poll mode for slave is a very bad idea, it works nevertheless */
155  if((mode_poll & (1 << i2cDev)) && Chip_I2C_IsStateChanged(i2cDev)) {
157  }
158 
159  x = DEBUGIN();
160  if (x == EOF) continue;
161  if (i >= sizeof(ch) - 2) break;
162  if ((x == '\r' || x == '\n') && i) {
163  DEBUGOUT("\r\n");
164  break;
165  }
166  if (x == '\b') {
167  if (i) {
168  DEBUGOUT("\033[1D \033[1D");
169  i --;
170  }
171  continue;
172  }
173  DEBUGOUT("%c", x);
174  ch[i++] = x;
175  };
176  ch[i] = 0;
177  i = strtol(ch, &ptr, 0);
178  if (*ptr) {
179  i = 0;
180  DEBUGOUT("Invalid input. Retry!\r\n");
181  continue;
182  }
183  input_valid = 1;
184  }
185  return i;
186 #else
187  static int sind = -1;
188  static uint8_t val[] = {5, I2C_SLAVE_IOX_ADDR, 1, 0};
189  if (sind >= sizeof(val)) sind = -1;
190  while (sind < 0 && (tick_cnt & 0x7F)) {}
191  if (sind < 0){
192  sind = 0;
193  val[3] = !val[3];
194  tick_cnt++;
195  }
196  return val[sind++];
197 #endif
198 }
199 
200 static void i2c_rw_input(I2C_XFER_T *xfer, int ops)
201 {
202  int tmp, i;
203 
204  tmp = con_get_input("Enter 7-Bit Slave address : ");
205  tmp &= 0xFF;
206  xfer->slaveAddr = tmp;
207  xfer->rxBuff = 0;
208  xfer->txBuff = 0;
209  xfer->txSz = 0;
210  xfer->rxSz = 0;
211 
212  if (ops & 1) {
213  tmp = con_get_input("Enter number of bytes to read : ");
214  tmp &= 0xFF;
215  xfer->rxSz = tmp;
216  xfer->rxBuff = buffer[1];
217  }
218 
219  if (ops & 2) {
220  tmp = con_get_input("Enter number of bytes to write : ");
221  tmp &= 0xFF;
222  for (i = 0; i < tmp; i++) {
223  DEBUGOUT("%d:", i + 1);
224  buffer[0][i] = con_get_input("Enter Data: ");
225  }
226  xfer->txSz = tmp;
227  xfer->txBuff = buffer[0];
228  }
229 }
230 
231 /* Set I2C mode to polling/interrupt */
232 static void i2c_set_mode(I2C_ID_T id, int polling)
233 {
234  if(!polling) {
235  mode_poll &= ~(1 << id);
237  NVIC_EnableIRQ(I2C0_IRQn);
238  } else {
239  mode_poll |= 1 << id;
240  NVIC_DisableIRQ(I2C0_IRQn);
242  }
243 }
244 
245 /* Initialize the I2C bus */
246 static void i2c_app_init(I2C_ID_T id, int speed)
247 {
248  Board_I2C_Init(id);
249 
250  /* Initialize I2C */
251  Chip_I2C_Init(id);
252  Chip_I2C_SetClockRate(id, speed);
253 
254  /* Set default mode to interrupt */
255  i2c_set_mode(id, 0);
256 }
257 
258 /* Function that probes all available slaves connected to an I2C bus */
260 {
261  int i;
262  uint8_t ch[2];
263 
264  DEBUGOUT("Probing available I2C devices...\r\n");
265  DEBUGOUT("\r\n 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
266  DEBUGOUT("\r\n====================================================");
267  for (i = 0; i <= 0x7F; i++) {
268  if (!(i & 0x0F)) DEBUGOUT("\r\n%02X ", i >> 4);
269  if (i <= 7 || i > 0x78) {
270  DEBUGOUT(" ");
271  continue;
272  }
273  /* Address 0x48 points to LM75AIM device which needs 2 bytes be read */
274  if(Chip_I2C_MasterRead(i2c, i, ch, 1 + (i == 0x48)) > 0)
275  DEBUGOUT(" %02X", i);
276  else
277  DEBUGOUT(" --");
278  }
279  DEBUGOUT("\r\n");
280 }
281 
282 static int i2c_menu(void)
283 {
284  DEBUGOUT(menu, i2cDev, (mode_poll & (1 << i2cDev)) ? "POLLING" : "INTERRUPT");
285  return con_get_input("\r\nSelect an option [0 - 6] :");
286 }
287 
288 /* Update the EEPROM state */
289 static void i2c_eeprom_update_state(I2C_XFER_T *xfer, uint8_t *buff, int sz)
290 {
291  xfer->txBuff = xfer->rxBuff = &buff[buff[0]+1];
292  xfer->rxSz = xfer->txSz = sz - buff[0] + 1;
293 }
294 
295 /* Slave event handler for simulated EEPROM */
297 {
298  static int is_addr = 1;
299  switch(event) {
300  case I2C_EVENT_DONE:
301  is_addr = 1;
303  seep_xfer.rxBuff = seep_data;
304  seep_xfer.rxSz ++;
305  break;
306 
307  case I2C_EVENT_SLAVE_RX:
308  if (is_addr) {
309  is_addr = 0;
310  seep_data[0] &= (I2C_SLAVE_EEPROM_SIZE - 1); /* Correct addr if required */
312  break;
313  }
314 
315  seep_data[0] ++;
316  seep_data[0] &= (I2C_SLAVE_EEPROM_SIZE - 1);
317  if (seep_xfer.rxSz == 1)
319  break;
320 
321  case I2C_EVENT_SLAVE_TX:
322  seep_data[0] ++;
323  seep_data[0] &= (I2C_SLAVE_EEPROM_SIZE - 1);
324  if (seep_xfer.txSz == 1)
326  break;
327  }
328 }
329 
330 /* Simulate an I2C EEPROM slave */
331 static void i2c_eeprom_init(I2C_ID_T id)
332 {
333  memset(&seep_data[1], 0xFF, I2C_SLAVE_EEPROM_SIZE);
334  seep_xfer.slaveAddr = (I2C_SLAVE_EEPROM_ADDR << 1);
335  seep_xfer.txBuff = &seep_data[1];
336  seep_xfer.rxBuff = seep_data;
337  seep_xfer.txSz = seep_xfer.rxSz = sizeof(seep_data);
339 }
340 /*-------- IO Expansion slave device implementation ----------*/
341 /* Update IN/OUT port states to real devices */
342 void i2c_iox_update_regs(int ops)
343 {
344  if (ops & 1) { /* update out port */
345  Board_LED_Set(0, iox_data[1] & 1);
346  Board_LED_Set(1, iox_data[1] & 2);
347  Board_LED_Set(2, iox_data[1] & 4);
348  Board_LED_Set(3, iox_data[1] & 8);
349  }
350 
351  if (ops & 2) { /* update in port */
352  iox_data[0] = (uint8_t) Buttons_GetStatus();
353  }
354 }
355 
356 /* Slave event handler for simulated EEPROM */
358 {
359  switch(event) {
360  case I2C_EVENT_DONE:
361  iox_xfer.rxBuff = &iox_data[1];
362  iox_xfer.rxSz = sizeof(iox_data);
363  iox_xfer.txBuff = (const uint8_t *)iox_data;
364  iox_xfer.txSz = sizeof(iox_data) + 1;
365  break;
366 
367  case I2C_EVENT_SLAVE_RX:
368  iox_xfer.rxBuff = &iox_data[1];
369  iox_xfer.rxSz = sizeof(iox_data);
371  break;
372 
373  case I2C_EVENT_SLAVE_TX:
374  if(iox_xfer.txSz == 1) {
375  iox_xfer.txBuff = (const uint8_t *)iox_data[0];
376  iox_xfer.txSz = sizeof(iox_data) + 1;
377  }
378  break;
379  }
380 }
381 
382 /* Simulate an IO Expansion slave device */
383 static void i2c_iox_init(I2C_ID_T id)
384 {
386  iox_xfer.slaveAddr = (I2C_SLAVE_IOX_ADDR << 1);
388  Chip_I2C_SlaveSetup(id, I2C_SLAVE_1, &iox_xfer, i2c_iox_events, 0);
390  /* Setup SysTick timer to get the button status updated at regular intervals */
391  SysTick_Config(Chip_Clock_GetSystemClockRate() / 50);
392 }
393 
394 /*-------------------- End of IO Expansion slave device ----------------------*/
395 
396 /*****************************************************************************
397  * Public functions
398  ****************************************************************************/
404 void SysTick_Handler(void)
405 {
407  tick_cnt ++;
408 }
409 
414 void I2C_IRQHandler(void)
415 {
417 }
418 
423 int main(void)
424 {
425  int tmp;
426  int xflag = 0;
427  static I2C_XFER_T xfer;
428 
429  Board_Init();
431 
432  /* Simulate an EEPROM slave in I2C0 */
434 
435  /* Simuldate an IO Expansion slave in I2C0 */
437 
438  while (!xflag) {
439  switch(i2c_menu()) {
440  case 0:
441  xflag = 1;
442  DEBUGOUT("End of I2C Demo! Bye!\r\n");
443  break;
444 
445  case 1:
446  i2cDev = I2C0;
447  break;
448 
449  case 2:
450  i2c_set_mode(i2cDev, !(mode_poll & (1 << i2cDev)));
451  break;
452 
453  case 3:
455  break;
456 
457  case 4:
458  i2c_rw_input(&xfer, 1);
459  tmp = Chip_I2C_MasterRead(i2cDev, xfer.slaveAddr, xfer.rxBuff, xfer.rxSz);
460  DEBUGOUT("Read %d bytes of data from slave 0x%02X.\r\n", tmp, xfer.slaveAddr);
461  con_print_data(buffer[1], tmp);
462  break;
463 
464  case 5:
465  i2c_rw_input(&xfer, 2);
466  if (xfer.txSz == 0) break;
467  tmp = Chip_I2C_MasterSend(i2cDev, xfer.slaveAddr, xfer.txBuff, xfer.txSz);
468  DEBUGOUT("Written %d bytes of data to slave 0x%02X.\r\n", tmp, xfer.slaveAddr);
469  break;
470 
471  case 6:
472  i2c_rw_input(&xfer, 3);
473  tmp = xfer.rxSz;
474  if (!tmp && !xfer.txSz) break;
476  DEBUGOUT("Master transfer : %s\r\n",
477  xfer.status == I2C_STATUS_DONE ? "SUCCESS" : "FAILURE");
478  DEBUGOUT("Received %d bytes from slave 0x%02X\r\n", tmp - xfer.rxSz, xfer.slaveAddr);
479  con_print_data(buffer[1], tmp - xfer.rxSz);
480  break;
481 
482  default:
483  DEBUGOUT("Input Invalid! Try Again.\r\n");
484  }
485  }
487 
488  return 0;
489 }
490