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 /* do some testing */
3335 kaklik 305 printf("Getting adapter functionalities\n");
3331 kaklik 306 i2c_tiny_usb_get_func();
307  
308 /* try to set i2c clock to 100kHz (10us), will actually result in ~50kHz */
309 /* since the software generated i2c clock isn't too exact. in fact setting */
310 /* it to 10us doesn't do anything at all since this already is the default */
3335 kaklik 311 printf("Reseting I2C clock to 100 kHz\n");
3331 kaklik 312 i2c_tiny_usb_set(CMD_SET_DELAY, 10);
313  
314 /* -------- begin of ds1621 client processing --------- */
315 printf("Probing for DS1621 ... ");
316  
317 /* try to access ds1621 at address DS1621_ADDR */
318 if(usb_control_msg(handle, USB_CTRL_IN,
319 CMD_I2C_IO + CMD_I2C_BEGIN + CMD_I2C_END,
320 0, DS1621_ADDR, NULL, 0,
321 1000) < 0) {
322 fprintf(stderr, "USB error: %s\n", usb_strerror());
323 goto quit;
324 }
325  
326 if(i2c_tiny_usb_get_status() == STATUS_ADDRESS_ACK) {
327 int temp;
328  
329 printf("success at address 0x%02x\n", DS1621_ADDR);
330  
331 /* activate one shot mode */
332 if(i2c_write_cmd_and_byte(DS1621_ADDR, 0xac, 0x01) < 0)
333 goto quit;
334  
335 /* wait 10ms */
336 usleep(10000);
337  
338 #if 0
339 /* write default limits */
340 /* high threshold: +15 deg celsius */
341 i2c_write_cmd_and_word(DS1621_ADDR, 0xa1, 0x0f00); /* 15 deg celsius */
342 usleep(10000);
343 /* low threshold: +10 deg celsius */
344 i2c_write_cmd_and_word(DS1621_ADDR, 0xa2, 0x0a00);
345 usleep(10000);
346 #endif
347  
348 /* display limits */
349 temp = i2c_read_with_cmd(DS1621_ADDR, 0xa1, 2);
350 printf("high temperature threshold = %d.%03d\n",
351 temp>>8, 1000 * (temp & 0xff) / 256);
352 temp = i2c_read_with_cmd(DS1621_ADDR, 0xa2, 2);
353 printf("low temperature threshold = %d.%03d\n",
354 temp>>8, 1000 * (temp & 0xff) / 256);
355  
356 printf("Getting %d temperature readings:\n", LOOPS);
357 for(i=0;i<LOOPS;i++) {
358 int temp;
359 int counter, slope;
360  
361 /* just write command 0xee to start conversion */
362 if(i2c_read_with_cmd(DS1621_ADDR, 0xee, 0) < 0)
363 goto quit;
364  
365 ds1621_read_control();
366  
367 temp = i2c_read_with_cmd(DS1621_ADDR, 0xaa, 2);
368 if(temp < 0)
369 goto quit;
370  
371 /* read counter and slope values */
372 counter = i2c_read_with_cmd(DS1621_ADDR, 0xa8, 1);
373 slope = i2c_read_with_cmd(DS1621_ADDR, 0xa9, 1);
374  
375 /* use counter and slope to adjust temperature (see ds1621 datasheet) */
376 temp = (temp & 0xff00) - 256/4;
377 temp += 256 * (slope - counter) / slope;
378  
379 printf("temp = %d.%03d\n", temp>>8, 1000 * (temp & 0xff) / 256);
380 }
381 } else
382 printf("failed\n");
383 /* -------- end of ds1621 client processing --------- */
384  
385 /* -------- begin of pcf8574 client processing --------- */
386 printf("Probing for PCF8574 ... ");
387  
388 /* try to access pcf8574 at address PCF8574_ADDR */
389 if(usb_control_msg(handle, USB_CTRL_IN,
390 CMD_I2C_IO + CMD_I2C_BEGIN + CMD_I2C_END,
391 0, PCF8574_ADDR, NULL, 0,
392 1000) < 0) {
393 fprintf(stderr, "USB error: %s\n", usb_strerror());
394 goto quit;
395 }
396  
397 if(i2c_tiny_usb_get_status() == STATUS_ADDRESS_ACK) {
398 unsigned char bit_mask = 0xfe;
399  
400 printf("success at address 0x%02x\n", PCF8574_ADDR);
401  
402 printf("Cycling 0 bit %d times.\n", LOOPS);
403 /* just rotate a single 0 bit through the outputs */
404  
405 for(i=0;i<LOOPS;i++) {
406 if(i2c_write_byte(PCF8574_ADDR, bit_mask) < 0)
407 goto quit;
408  
409 /* rotate the byte */
410 bit_mask = (bit_mask << 1) | 1;
411 if(bit_mask == 0xff)
412 bit_mask = 0xfe;
413  
414 usleep(100000);
415 }
416 } else
417 printf("failed\n");
418 /* -------- end of pcf8574 client processing --------- */
419  
420 quit:
421 #ifndef WIN
422 ret = usb_release_interface(handle, 0);
423 if (ret)
424 fprintf(stderr, "USB error: %s\n", usb_strerror());
425 #endif
426  
427 usb_close(handle);
428  
429 #ifdef WIN
430 printf("Press return to quit\n");
431 getchar();
432 #endif
433  
434 return 0;
435 }