| LPCOpen Platform v1.03 LPCOpen Platform for NXP LPC Microcontrollers

- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

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 */
103 static I2C_XFER_T seep_xfer;
104 static I2C_XFER_T iox_xfer;
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 */
121 static void i2c_state_handling(I2C_ID_T id)
122 {
123 if (Chip_I2C_IsMasterActive(id)) {
124 Chip_I2C_MasterStateHandler(id);
125 } else {
126 Chip_I2C_SlaveStateHandler(id);
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)) {
156 Chip_I2C_SlaveStateHandler(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);
236 Chip_I2C_SetMasterEventHandler(id, Chip_I2C_EventHandler);
237 NVIC_EnableIRQ(I2C0_IRQn);
238 } else {
239 mode_poll |= 1 << id;
240 NVIC_DisableIRQ(I2C0_IRQn);
241 Chip_I2C_SetMasterEventHandler(id, Chip_I2C_EventHandlerPolling);
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 */
259 static void i2c_probe_slaves(I2C_ID_T i2c)
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 */
296 static void i2c_eeprom_events(I2C_ID_T id, I2C_EVENT_T event)
297 {
298 static int is_addr = 1;
299 switch(event) {
300 case I2C_EVENT_DONE:
301 is_addr = 1;
302 i2c_eeprom_update_state(&seep_xfer, seep_data, I2C_SLAVE_EEPROM_SIZE);
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 */
311 i2c_eeprom_update_state(&seep_xfer, seep_data, I2C_SLAVE_EEPROM_SIZE);
312 break;
313 }
314
315 seep_data[0] ++;
316 seep_data[0] &= (I2C_SLAVE_EEPROM_SIZE - 1);
317 if (seep_xfer.rxSz == 1)
318 i2c_eeprom_update_state(&seep_xfer, seep_data, I2C_SLAVE_EEPROM_SIZE);
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)
325 i2c_eeprom_update_state(&seep_xfer, seep_data, I2C_SLAVE_EEPROM_SIZE);
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);
338 Chip_I2C_SlaveSetup(id, I2C_SLAVE_0, &seep_xfer, i2c_eeprom_events, 0);
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 */
357 static void i2c_iox_events(I2C_ID_T id, I2C_EVENT_T event)
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);
370 i2c_iox_update_regs(1);
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 {
385 Board_Buttons_Init();
386 iox_xfer.slaveAddr = (I2C_SLAVE_IOX_ADDR << 1);
387 i2c_iox_events(id, I2C_EVENT_DONE);
388 Chip_I2C_SlaveSetup(id, I2C_SLAVE_1, &iox_xfer, i2c_iox_events, 0);
389 i2c_iox_update_regs(3);
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 {
406 i2c_iox_update_regs(2);
407 tick_cnt ++;
408 }
409
414 void I2C_IRQHandler(void)
415 {
416 i2c_state_handling(I2C0);
417 }
418
423 int main(void)
424 {
425 int tmp;
426 int xflag = 0;
427 static I2C_XFER_T xfer;
428
429 Board_Init();
430 i2c_app_init(I2C0, SPEED_100KHZ);
431
432 /* Simulate an EEPROM slave in I2C0 */
433 i2c_eeprom_init(I2C_EEPROM_BUS);
434
435 /* Simuldate an IO Expansion slave in I2C0 */
436 i2c_iox_init(I2C_IOX_BUS);
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:
454 i2c_probe_slaves(i2cDev);
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;
475 Chip_I2C_MasterTransfer(i2cDev, &xfer);
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 }
486 Chip_I2C_DeInit(I2C0);
487
488 return 0;
489 }
490