Experiments with i2c on the (OpenWrt Kamikaze and Debian) Linksys NSLU2 - the Slug
Working drivers for PCF8574 (port expander) and PCF9591 (A/D D/A)
for the LM75 thermometer all is OK on Debian Slug but for OpenWrt
slug I need a "work around" see below
For OpenWrt an ipackage lets you add
- i2cdetect
- i2cdump
- i2cget
- i2cset
use "apt-get install lm-sensors" for Debian
My i2c test board was connected via a Philips designed FET level shifter
(as for the Sweex menu item 6) and I ran "i2cdetect 0" to find my chip addresses -
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- 27 -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- 4c -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- UU
70: -- -- -- -- -- -- -- --
So my chips are at
PCF8574 port expander - - - 0x27 = dec39
LM75 thermometer - - - - - - - 0x48 = dec72
PCF8591 A/D D/A - - - - - - - 0x4c= dec76
I suppose UU is the RTC - real time clock on the Slug board.
I tried to compile my c drivers that worked in the Sweex but they failed
I did some Googling many thanks to this link and cutting and pasting from i2cget and i2cset and the following work fine
This is pure Lesson 1 C-code (copy and pray) - please email me if you can up the quality!
/* usage :- type with spaces but without the < > */ int i2c; int rc; int main(int argc, char *argv[]) /* address is the first number after the program name */ i2c = open("/dev/i2c-0",O_RDWR); /* open the device dev/i2c-0 */ rc=ioctl(i2c,I2C_SLAVE,address); /* set the i2c chip address */ write(i2c,data,1) ; /* send the byte */ i2c = close(i2c); /* Sunspot 080607 */ |
/* 1) set the i2c address of the PCF8574 #include <stdio.h> int i2c; int main(int argc, char ** argv) /* address is the first number after the program name */ i2c = open("/dev/i2c-0",O_RDWR); /* open the device dev/i2c-0 */ data[0] = 255; read(i2c,data,1); /* now data(0) contains the byte of data on the 8 port lines*/ byte = data[0]; printf("BYTE = %d \n", byte); i2c = close(i2c);
/* Sunspot 080607 */ |
/* #include <stdio.h> int i2c; int main(int argc, char** argv) { printf("Error. usage: %s i2c_chip_address D/A_Vout(0-255)\n", argv[0]); } address = atoi(argv[1]); /* address is the first number after the program name */ V_out = atoi(argv[2]); /* A/D input line 0-3 */ i2c = open("/dev/i2c-0",O_RDWR); /* open the device dev/i2c-0 */ AD_line = 0 + 64; /* enable the D/A output pin 0*/ AD_line = 1 + 64; /* enable the D/A output pin 0*/ AD_line = 2 + 64; /* enable the D/A output pin 0*/ AD_line = 3 + 64; /* enable the D/A output pin 0*/ printf("A/D line 0 = %d \n", AD_line_0, " "); /*AD_line_x goes 0 to 255 as voltage input goes from 0 to supply voltage*/ i2c = close(i2c); |
/* #include <stdio.h> int i2c; int rc; int main(int argc, char** argv) address = atoi(argv[1]); /* decimal address is the first number after the program name */ i2c = open("/dev/i2c-0",O_RDWR); /* open the device dev/i2c-0 */ channel = channel + 64; /* enable the D/A output */
printf("%d", AD_input);
/*AD_line_x goes 0 to 255 as voltage input goes from 0 to supply voltage*/ i2c = close(i2c); |
/* */ #include <stdio.h> int i2c; /* address is the first number after the program name */ i2c = open("/dev/i2c-0",O_RDWR); /* open the device dev/i2c-0 */ read(i2c,data,2); byte1 = data[0]; temperature = byte1*256+byte2; printf("%d \n", temperature*5); //cast and divide by 2 (next 2 lines) compiles but gave run error:- i2c = close(i2c); ----------------------------------------------------------------------- I found a way to work round this problem and divide by 10 in a script- Inside my ash script that builds a web page reporting the temperature I use AWK like this - result=`echo $realtemp | awk "$AWKSCRIPT"` echo "<BR><HR> result of AWK print = " - this does the printing and 51, for example, becomes 25.5 as required - or I can get a new ash string result = 25.5 (for example) |
For Debian Slug the print statements compile and run OK - no need for the "work-around" above This code just gives the temperature as a string of characters (eg 23.5) with no return character for i2c decimal address 72 use ./LM75-Deb-slug 72 /* */ #include <stdio.h> int i2c; /* address is the first number after the program name */ i2c = open("/dev/i2c-0",O_RDWR); /* open the device dev/i2c-0 */ read(i2c,data,2); byte1 = data[0]; temperature = byte1*256+byte2; /* the following 2 lines compile and run for Debian Slug i2c = close(i2c); |
Use a Blassic basic program with i2cset and i2cget SE95_i2ctools_read_once.bas #!/usr/sbin/blassic address$ = PROGRAMARG$(1) 'write a 0 to the 0 register SHELL "i2cget -y 0 "+address$+" 0x00 w > /var/www/ramdisk/lm75_1.txt" 'get the two hex bytes from the stored text string 'get the decimal value of the hex numbers sign = 1 temp_all = (HI_dec + LO_dec/256) SYSTEM |