Rev Author Line No. Line
3331 kaklik 1 /*
2 * i2c_usb.c - test application for the i2c-tiby-usb interface
3 * http://www.harbaum.org/till/i2c_tiny_usb
4 *
5 * $Id: i2c_usb.c,v 1.5 2007/01/05 19:30:43 harbaum Exp $
6 */
7  
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <usb.h>
12  
13 /* ds1621 chip address (A0-A2 tied low) */
14 #define DS1621_ADDR 0x48
15  
16 /* pcf8574 chip address (A0-A2 tied low) */
17 #define PCF8574_ADDR 0x20
18  
19 #define LOOPS 100
20  
21 #define USB_CTRL_IN (USB_TYPE_CLASS | USB_ENDPOINT_IN)
22 #define USB_CTRL_OUT (USB_TYPE_CLASS)
23  
24 /* the vendor and product id was donated by ftdi ... many thanks!*/
25 #define I2C_TINY_USB_VID 0x0403
26 #define I2C_TINY_USB_PID 0xc631
27  
28 #ifdef WIN
29 #include <windows.h>
30 #include <winbase.h>
31 #define usleep(t) Sleep((t) / 1000)
32 #endif
33  
34 #define I2C_M_RD 0x01
35  
36 /* commands via USB, must e.g. match command ids firmware */
37 #define CMD_ECHO 0
38 #define CMD_GET_FUNC 1
39 #define CMD_SET_DELAY 2
40 #define CMD_GET_STATUS 3
41 #define CMD_I2C_IO 4
42 #define CMD_I2C_BEGIN 1 // flag to I2C_IO
43 #define CMD_I2C_END 2 // flag to I2C_IO
44  
45 #define STATUS_IDLE 0
46 #define STATUS_ADDRESS_ACK 1
47 #define STATUS_ADDRESS_NAK 2
48  
49 usb_dev_handle *handle = NULL;
50  
51 /* write a set of bytes to the i2c_tiny_usb device */
52 int i2c_tiny_usb_write(int request, int value, int index){
53  
54 if(usb_control_msg(handle, USB_CTRL_OUT, request,
55 value, index, NULL, 0, 1000) < 0) {
56 fprintf(stderr, "USB error: %s\n", usb_strerror());
57 return -1;
58 }
59 return 1;
60 }
61  
62 /* read a set of bytes from the i2c_tiny_usb device */
63 int i2c_tiny_usb_read(unsigned char cmd, void *data, int len) {
64 int nBytes;
65  
66 /* send control request and accept return value */
67 nBytes = usb_control_msg(handle,USB_CTRL_IN, cmd, 0, 0, data, len, 1000);
68  
69 if(nBytes < 0) {
70 fprintf(stderr, "USB error: %s\n", usb_strerror());
71 return nBytes;
72 }
73  
74 return 0;
75 }
76  
77 /* get i2c usb interface test */
78 void i2c_tiny_usb_test(void) {
79 unsigned long func;
80  
81 if(i2c_tiny_usb_read(CMD_ECHO, &func, sizeof(func)) == 0)
82 printf("Functionality = %lx\n", func);
83 }
84  
85  
86 /* get i2c usb interface firmware version */
87 void i2c_tiny_usb_get_func(void) {
88 unsigned long func;
89  
90 if(i2c_tiny_usb_read(CMD_GET_FUNC, &func, sizeof(func)) == 0)
91 printf("Functionality = %lx\n", func);
92 }
93  
94 /* set a value in the I2C_USB interface */
95 void i2c_tiny_usb_set(unsigned char cmd, int value) {
96 if(usb_control_msg(handle,
97 USB_TYPE_VENDOR, cmd, value, 0,
98 NULL, 0, 1000) < 0) {
99 fprintf(stderr, "USB error: %s\n", usb_strerror());
100 }
101 }
102  
103 /* get the current transaction status from the i2c_tiny_usb interface */
104 int i2c_tiny_usb_get_status(void) {
105 int i;
106 unsigned char status;
107  
108 if((i=i2c_tiny_usb_read(CMD_GET_STATUS, &status, sizeof(status))) < 0) {
109 fprintf(stderr, "Error reading status\n");
110 return i;
111 }
112  
113 return status;
114 }
115  
116 /* write command and read an 8 or 16 bit value from the given chip */
117 int i2c_read_with_cmd(unsigned char addr, char cmd, int length) {
118 unsigned char result[2];
119  
120 if((length < 0) || (length > sizeof(result))) {
121 fprintf(stderr, "request exceeds %lu bytes\n", sizeof(result));
122 return -1;
123 }
124  
125 /* write one byte register address to chip */
126 if(usb_control_msg(handle, USB_CTRL_OUT,
127 CMD_I2C_IO + CMD_I2C_BEGIN
128 + ((!length)?CMD_I2C_END:0),
129 0, addr, &cmd, 1,
130 1000) < 1) {
131 fprintf(stderr, "USB error: %s\n", usb_strerror());
132 return -1;
133 }
134  
135 if(i2c_tiny_usb_get_status() != STATUS_ADDRESS_ACK) {
136 fprintf(stderr, "write command status failed\n");
137 return -1;
138 }
139  
140 // just a test? return ok
141 if(!length) return 0;
142  
143 if(usb_control_msg(handle,
144 USB_CTRL_IN,
145 CMD_I2C_IO + CMD_I2C_END,
146 I2C_M_RD, addr, (char*)result, length,
147 1000) < 1) {
148 fprintf(stderr, "USB error: %s\n", usb_strerror());
149 return -1;
150 }
151  
152 if(i2c_tiny_usb_get_status() != STATUS_ADDRESS_ACK) {
153 fprintf(stderr, "read data status failed\n");
154 return -1;
155 }
156  
157 // return 16 bit result
158 if(length == 2)
159 return 256*result[0] + result[1];
160  
161 // return 8 bit result
162 return result[0];
163 }
164  
165 /* write a single byte to the i2c client */
166 int i2c_write_byte(unsigned char addr, char data) {
167  
168 /* write one byte register address to chip */
169 if(usb_control_msg(handle, USB_CTRL_OUT,
170 CMD_I2C_IO + CMD_I2C_BEGIN + CMD_I2C_END,
171 0, addr, &data, 1,
172 1000) < 1) {
173 fprintf(stderr, "USB error: %s\n", usb_strerror());
174 return -1;
175 }
176  
177 if(i2c_tiny_usb_get_status() != STATUS_ADDRESS_ACK) {
178 fprintf(stderr, "write command status failed\n");
179 return -1;
180 }
181  
182 return 0;
183 }
184  
185 /* write a command byte and a single byte to the i2c client */
186 int i2c_write_cmd_and_byte(unsigned char addr, char cmd, char data) {
187 char msg[2];
188  
189 msg[0] = cmd;
190 msg[1] = data;
191  
192 /* write one byte register address to chip */
193 if(usb_control_msg(handle, USB_CTRL_OUT,
194 CMD_I2C_IO + CMD_I2C_BEGIN + CMD_I2C_END,
195 0, addr, msg, 2,
196 1000) < 1) {
197 fprintf(stderr, "USB error: %s\n", usb_strerror());
198 return -1;
199 }
200  
201 if(i2c_tiny_usb_get_status() != STATUS_ADDRESS_ACK) {
202 fprintf(stderr, "write command status failed\n");
203 return -1;
204 }
205  
206 return 0;
207 }
208  
209 /* write a command byte and a 16 bit value to the i2c client */
210 int i2c_write_cmd_and_word(unsigned char addr, char cmd, int data) {
211 char msg[3];
212  
213 msg[0] = cmd;
214 msg[1] = data >> 8;
215 msg[2] = data & 0xff;
216  
217 /* write one byte register address to chip */
218 if(usb_control_msg(handle, USB_CTRL_OUT,
219 CMD_I2C_IO + CMD_I2C_BEGIN + CMD_I2C_END,
220 0, addr, msg, 3,
221 1000) < 1) {
222 fprintf(stderr, "USB error: %s\n", usb_strerror());
223 return -1;
224 }
225  
226 if(i2c_tiny_usb_get_status() != STATUS_ADDRESS_ACK) {
227 fprintf(stderr, "write command status failed\n");
228 return -1;
229 }
230  
231 return 0;
232 }
233  
234 /* read ds1621 control register */
235 void ds1621_read_control(void) {
236 int result;
237  
238 do {
239 result = i2c_read_with_cmd(DS1621_ADDR, 0xac, 1);
240 } while(!(result & 0x80));
241 }
242  
243  
244  
245 /* main program process */
246  
247  
248 int main(int argc, char *argv[]) {
249 struct usb_bus *bus;
250 struct usb_device *dev;
251 int i;
252 #ifndef WIN
253 int ret;
254 #endif
255  
256 printf("-- i2c-tiny-usb test application --\n");
257 printf("-- (c) 2006 by Till Harbaum --\n");
258 printf("-- http://www.harbaum.org/till/i2c_tiny_usb --\n");
259  
260 usb_init();
261  
262 usb_find_busses();
263 usb_find_devices();
264  
265 for(bus = usb_get_busses(); bus; bus = bus->next) {
266 for(dev = bus->devices; dev; dev = dev->next) {
267 if((dev->descriptor.idVendor == I2C_TINY_USB_VID) &&
268 (dev->descriptor.idProduct == I2C_TINY_USB_PID)) {
269  
270 printf("Found i2c_tiny_usb device on bus %s device %s.\n",
271 bus->dirname, dev->filename);
272  
273 /* open device */
274 if(!(handle = usb_open(dev)))
275 fprintf(stderr, "Error: Cannot open the device: %s\n",
276 usb_strerror());
277  
278 break;
279 }
280 }
281 }
282  
283 if(!handle) {
284 fprintf(stderr, "Error: Could not find i2c_tiny_usb device\n");
285  
286 #ifdef WIN
287 printf("Press return to quit\n");
288 getchar();
289 #endif
290  
291 exit(-1);
292 }
293  
294 #ifndef WIN
295 /* Get exclusive access to interface 0. Does not work under windows. */
296 ret = usb_claim_interface(handle, 0);
297 if (ret != 0) {
298 fprintf(stderr, "USB error: %s\n", usb_strerror());
299  
300 exit(1);
301 }
302 #endif
303  
304 printf("writing to adapter");
305 i2c_tiny_usb_write(0,0,0);
306  
307 /* do some testing */
308 printf("Getting adapter functionalities");
309 i2c_tiny_usb_get_func();
310  
311 /* try to set i2c clock to 100kHz (10us), will actually result in ~50kHz */
312 /* since the software generated i2c clock isn't too exact. in fact setting */
313 /* it to 10us doesn't do anything at all since this already is the default */
314 printf("Reseting I2C clock to 100 kHz");
315 i2c_tiny_usb_set(CMD_SET_DELAY, 10);
316  
317 /* -------- begin of ds1621 client processing --------- */
318 printf("Probing for DS1621 ... ");
319  
320 /* try to access ds1621 at address DS1621_ADDR */
321 if(usb_control_msg(handle, USB_CTRL_IN,
322 CMD_I2C_IO + CMD_I2C_BEGIN + CMD_I2C_END,
323 0, DS1621_ADDR, NULL, 0,
324 1000) < 0) {
325 fprintf(stderr, "USB error: %s\n", usb_strerror());
326 goto quit;
327 }
328  
329 if(i2c_tiny_usb_get_status() == STATUS_ADDRESS_ACK) {
330 int temp;
331  
332 printf("success at address 0x%02x\n", DS1621_ADDR);
333  
334 /* activate one shot mode */
335 if(i2c_write_cmd_and_byte(DS1621_ADDR, 0xac, 0x01) < 0)
336 goto quit;
337  
338 /* wait 10ms */
339 usleep(10000);
340  
341 #if 0
342 /* write default limits */
343 /* high threshold: +15 deg celsius */
344 i2c_write_cmd_and_word(DS1621_ADDR, 0xa1, 0x0f00); /* 15 deg celsius */
345 usleep(10000);
346 /* low threshold: +10 deg celsius */
347 i2c_write_cmd_and_word(DS1621_ADDR, 0xa2, 0x0a00);
348 usleep(10000);
349 #endif
350  
351 /* display limits */
352 temp = i2c_read_with_cmd(DS1621_ADDR, 0xa1, 2);
353 printf("high temperature threshold = %d.%03d\n",
354 temp>>8, 1000 * (temp & 0xff) / 256);
355 temp = i2c_read_with_cmd(DS1621_ADDR, 0xa2, 2);
356 printf("low temperature threshold = %d.%03d\n",
357 temp>>8, 1000 * (temp & 0xff) / 256);
358  
359 printf("Getting %d temperature readings:\n", LOOPS);
360 for(i=0;i<LOOPS;i++) {
361 int temp;
362 int counter, slope;
363  
364 /* just write command 0xee to start conversion */
365 if(i2c_read_with_cmd(DS1621_ADDR, 0xee, 0) < 0)
366 goto quit;
367  
368 ds1621_read_control();
369  
370 temp = i2c_read_with_cmd(DS1621_ADDR, 0xaa, 2);
371 if(temp < 0)
372 goto quit;
373  
374 /* read counter and slope values */
375 counter = i2c_read_with_cmd(DS1621_ADDR, 0xa8, 1);
376 slope = i2c_read_with_cmd(DS1621_ADDR, 0xa9, 1);
377  
378 /* use counter and slope to adjust temperature (see ds1621 datasheet) */
379 temp = (temp & 0xff00) - 256/4;
380 temp += 256 * (slope - counter) / slope;
381  
382 printf("temp = %d.%03d\n", temp>>8, 1000 * (temp & 0xff) / 256);
383 }
384 } else
385 printf("failed\n");
386 /* -------- end of ds1621 client processing --------- */
387  
388 /* -------- begin of pcf8574 client processing --------- */
389 printf("Probing for PCF8574 ... ");
390  
391 /* try to access pcf8574 at address PCF8574_ADDR */
392 if(usb_control_msg(handle, USB_CTRL_IN,
393 CMD_I2C_IO + CMD_I2C_BEGIN + CMD_I2C_END,
394 0, PCF8574_ADDR, NULL, 0,
395 1000) < 0) {
396 fprintf(stderr, "USB error: %s\n", usb_strerror());
397 goto quit;
398 }
399  
400 if(i2c_tiny_usb_get_status() == STATUS_ADDRESS_ACK) {
401 unsigned char bit_mask = 0xfe;
402  
403 printf("success at address 0x%02x\n", PCF8574_ADDR);
404  
405 printf("Cycling 0 bit %d times.\n", LOOPS);
406 /* just rotate a single 0 bit through the outputs */
407  
408 for(i=0;i<LOOPS;i++) {
409 if(i2c_write_byte(PCF8574_ADDR, bit_mask) < 0)
410 goto quit;
411  
412 /* rotate the byte */
413 bit_mask = (bit_mask << 1) | 1;
414 if(bit_mask == 0xff)
415 bit_mask = 0xfe;
416  
417 usleep(100000);
418 }
419 } else
420 printf("failed\n");
421 /* -------- end of pcf8574 client processing --------- */
422  
423 quit:
424 #ifndef WIN
425 ret = usb_release_interface(handle, 0);
426 if (ret)
427 fprintf(stderr, "USB error: %s\n", usb_strerror());
428 #endif
429  
430 usb_close(handle);
431  
432 #ifdef WIN
433 printf("Press return to quit\n");
434 getchar();
435 #endif
436  
437 return 0;
438 }