/* Copyright 2012-2025 <>< Charles Lohr This file may be used for any purposes (commercial or private) just please leave this copyright notice in there somewhere. You may cross license this as MIT or NewBSD. Now, generic I2C library for any GPIO-based system. Include this in your .c file only!!! Include it after the following are defined: I2CDELAY_FUNC -> If you wish to override the internal delay functions. I2CSPEEDBASE -> define speed base multiplier 1 = normal, 10 = slow, .1 = fast; failure to define this will result in the clock being as fast as possible. I2CNEEDGETBYTE -> Do we need to be able to read data? I2CPREFIX -> #define to be the prefix, i.e. BOB will cause BOBConfigI2C to be generated. I2CNOSTATIC -> #define if you want the functions to be generated as not-static code. NOTE: You must initially configure the port to be outputs on both DSDA and DSCL and set them both to be driven high. */ /* Example: #define DELAY1 Delay_Us(1); #define DELAY2 Delay_Us(2); #define DSCL_IHIGH { funPinMode( PIN_SCL, GPIO_CFGLR_IN_PUPD ); funDigitalWrite( PIN_SCL, 1 ); } #define DSDA_IHIGH { funPinMode( PIN_SDA, GPIO_CFGLR_IN_PUPD ); funDigitalWrite( PIN_SDA, 1 ); } #define DSDA_INPUT { funPinMode( PIN_SDA, GPIO_CFGLR_IN_PUPD ); funDigitalWrite( PIN_SDA, 1 ); } #define DSCL_OUTPUT { funDigitalWrite( PIN_SCL, 0 ); funPinMode( PIN_SCL, GPIO_CFGLR_OUT_2Mhz_PP ); } #define DSDA_OUTPUT { funDigitalWrite( PIN_SDA, 0 ); funPinMode( PIN_SDA, GPIO_CFGLR_OUT_2Mhz_PP ); } #define READ_DSDA funDigitalRead( PIN_SDA ) #define I2CNEEDGETBYTE 1 #define I2CNEEDSCAN 1 #include "static_i2c.h" ... */ #ifndef I2CPREFIX #define I2CPREFIX #endif #ifndef I2CNOSTATIC #define I2CSTATICODE #else #define I2CSTATICODE static #endif #ifndef I2CFNCOLLAPSE #define INTI2CFNCOLLAPSE(PFX, name) PFX##name #define I2CFNCOLLAPSE(PFX, name) INTI2CFNCOLLAPSE(PFX, name) #endif #ifndef I2CNEEDGETBYTE #define I2CNEEDGETBYTE 1 #endif #ifndef DSCL_IHIGH #define DSCL_IHIGH DSCL_INPUT #endif #ifndef DSDA_IHIGH #define DSDA_IHIGH DSDA_INPUT #endif I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, ConfigI2C)() { DSDA_IHIGH DSCL_IHIGH } I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, SendStart)() { DELAY1 DSCL_IHIGH DELAY1 DSDA_OUTPUT DELAY1 DSCL_OUTPUT DELAY1 } I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, SendStop)() { DELAY1 DSDA_OUTPUT DELAY1 DSCL_IHIGH DELAY1 DSDA_IHIGH DELAY1 } // Return nonzero on failure. I2CSTATICODE unsigned char I2CFNCOLLAPSE(I2CPREFIX, SendByte)(unsigned char data) { unsigned int i; // Assume we are in a started state (DSCL = 0 & DSDA = 0) for (i = 0; i < 8; i++) { DELAY1 if (data & 0x80) { DSDA_IHIGH } else { DSDA_OUTPUT } data <<= 1; DELAY2 DSCL_IHIGH DELAY2 DSCL_OUTPUT } // Immediately after sending last bit, open up DDDR for control. DELAY1 DSDA_INPUT DELAY1 DSCL_IHIGH DELAY1 i = READ_DSDA; DELAY1 DSCL_OUTPUT DELAY1 return !!i; } #if I2CNEEDGETBYTE I2CSTATICODE unsigned char I2CFNCOLLAPSE(I2CPREFIX, GetByte)(uint8_t send_nak) { unsigned char i; unsigned char ret = 0; DSDA_INPUT for (i = 0; i < 8; i++) { DELAY1 DSCL_IHIGH DELAY2 ret <<= 1; if (READ_DSDA) ret |= 1; DSCL_OUTPUT } // Send ack. if (send_nak) { } else { DSDA_OUTPUT } DELAY1 DSCL_IHIGH DELAY2 DSCL_OUTPUT DELAY1 DSDA_IHIGH return ret; } #endif // In case you want SCAN code #if I2CNEEDSCAN I2CSTATICODE void I2CFNCOLLAPSE(I2CPREFIX, Scan)() { int i; printf( " " ); for( i = 0; i < 16; i++ ) { printf( " %x", i ); } for( i = 0; i < 128; i++ ) { if( ( i & 0xf ) == 0 ) { printf( "\n%02x ", i ); } SendStart(); int b = SendByte( i<<1 ); SendStop(); printf( "%c ", b?'.':'#' ); } printf( "\n" ); } #endif