# i2c [Inter-Cntergrated Circuit](https://en.wikipedia.org/wiki/I%C2%B2C) protocol, used to communicate with a wide verity of IC devices on a single physical bus. 9front / plan9 provide I2C support in a form of kernel device abstraction, but not necessarily enabled for your specific device. 9front does not support I2C on Raspberry Pi out of the box. ## installation As of 9front release [HUMANBIOLOGICS](http://9front.org/releases/2023/11/22/0/) on 2023.11.22, the I2C code is part of the base system, with tweaks to deferentiate betweeen miltiple I2C busses (if they exist). If hardware support is in for your device, just use it. ## usage When supported / enabled, I2C devices should be accessible through __#J__ kernel device. ### Example - bme680 (address 0x77) raw I2C access: * check if device exists in terminal cd '#J77' There should be a directory with I2C bus names for the device (eg. i2c1). * bind device to dev bind -b '#J77' /dev This should bind data (/dev/i2c1/i2c.77.data) and control (/dev/i2c1/i2c.77.ctl) files to __/dev/BusName__ directory. Use those files to communicate with the device. * use I2C device in code #include #include int opendev(void) { /* default location for bme680 is 0x77 */ int fd = -1; if(access("/dev/i2c1/i2c.77.data", 0) != 0){ if(bind("#J77", "/dev", MBEFORE) < 0){ sysfatal("no J77 device"); } } fd = open("/dev/i2c1/i2c.77.data", ORDWR); if(fd < 0){ sysfatal("cannot open i2c.77.data file"); } return(fd); } void closedev(int fd) { close(fd); unmount("#J77", "/dev"); } int initdev(int fd) { uchar cmd[1]; uchar res[1]; cmd[0] = 0xD0; /* location of id register */ pwrite(fd, cmd, 1, 0); pread(fd, res, 1, 0); fprint(1, "device id val: %x\n", res[0]); /* value 0x61 is the id of bme680 device */ if(res[0] == 0x61){ return 1; } return 0; } void main(int, char*) { int fd; fd = opendev(); sleep(1000); initdev(fd); sleep(1000); closedev(fd); exits(nil); } # DEPRECATED Raspberry Pi 1 - (RPI 1) DEPRECATED Enabling I2C support on Raspberry Pi 1 with 9front, by including code from plan9. Luckily, many resources can be found on this topic. Here is a cleanup and condensed summary. ## references * Richard Miller I2C code from plan9: [https://9p.io/sources/contrib/miller/9/bcm/](https://9p.io/sources/contrib/miller/9/bcm/) adventuresin9 video on the subject: [youtube](https://www.youtube.com/watch?v=9_qrXHysu3c) ## preparation * kernel code is located in __/sys/src/9__ * kernel code for RPI 1 is located in __/sys/src/9/bcm__ * files needed from Richard Miller I2C code: * i2c.c - I2C implementation for the Broadcom chip used by RPI 1 * to be copied in __bcm__ directory * devi2c.c - I2C device abstraction for plan9 kernel * to be copied in __bcm__ directory * dat.h - i2C data structure to be referenced * use as a reference to edit the file already in __bcm__ directory * fns.h - I2C callback functions to be referenced * use as a reference to edit the file already in __bcm__ directory ## code installation * copy __i2c.c__ to __/sys/src/9/bcm__ * copy __devi2c.c__ to __/sys/src/9/bcm__ * edit __dat.h__ in __/sys/src/9/bcm__ * add the data structure: /* * I2C */ typedef struct I2Cdev I2Cdev; struct I2Cdev { int salen; int addr; int tenbit; }; * edit __fsn.h__ in __/sys/src/9/bcm__ * add the callback functions: /* * I2C */ extern void i2csetup(int); extern long i2crecv(I2Cdev*, void*, long, ulong); extern long i2csend(I2Cdev*, void*, long, ulong); * edit __pi__ in __/sys/src/9/bcm__ * add I2C device definitions to dev section: i2c i2c under gpio if you have no preference where to put it * edit __mkfile__ in __/sys/src/9/bcm__ * confirm/change CONF variable to to pi, to build RPI 1 kernel ## compile and install new kernel The process also requires mounting the boot partition and editing config files. ### mount RPI 1 boot partition RPI1 uses a fat/dos partition with config files that are used to boot the board. The boot partition can be mounted with 9fs script: 9fs pidos This will bind the boot partition to __/n/pidos__ folder. If you get an error that partition cannot be found (usually when using rpuc for remote access), block kernel device needs to be mounted first: bind -b '#S' /dev This will mount __/dev/sdM0__ directory with partition devices on the sd card. ### compile kernel In __/sys/src/9/bcm__ directory run the build command: cd /sys/src/9/bcm mk install This will create new kernel image __9pi__ in __/arm__ directory. Don't forget to clean up __AFTER__ installing the kernel: mk clean ### installing the kernel It is a good idea to keep old kernel images around in case anything goes wrong, to restore the previous working state. Either rename old images to a new name and copy new images using the old name. Or Copy new images with a new name and edit the config file, selecting the kernel image. For example, we will copy new images with a new name and edit the config file to showcase where everything is. The mounted pidos partition in __/n/pidos__ should contain many files. This time we're interested in __9pi__ and __config.txt__ (ignore the cmdline.txt that was edited during RPI 1 setup). * check if boot partition is mounted to __/n/pidos__ (check above) * copy new kernel image to boot partition cp /arm/9pi /n/pidos/9pi.i2c * edit config file to reference new kernel image * edit file __/n/pidos/config.txt__ and change: [pi1] kernel=9pi to [pi1] kernel=9pi.i2c or change all kernel variables referencing 9pi image * reboot the system fshalt -r * don't forget to clean up the source directory (see above)