@UMD @peekay123 @ScruffR
I went ahead and used the same library @UMD used to keep things simple.
I added the SoftI2CMaster .cpp & .h files to my program and changed the lines of code as @UMD suggested.
I figure once we get this worked out we can add it to the new library system for others
SoftI2CMaster.cpp
/*
* SoftI2CMaster.cpp -- Multi-instance software I2C Master library
*
*
* 2010-12 Tod E. Kurt, http://todbot.com/blog/
*
* This code takes some tricks from:
* http://codinglab.blogspot.com/2008/10/i2c-on-avr-using-bit-banging.html
*
* 2014, by Testato: update library and examples for follow Wire’s API of Arduino IDE 1.x
*
*/
#if (ARDUINO >= 100)
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#include "SoftI2CMaster.h"
#include <util/delay.h>
#include <string.h>
#define i2cbitdelay 50
#define I2C_ACK 1
#define I2C_NAK 0
// HR's port
#define i2c_scl_release() \
pinMode(_sclPin, INPUT);
#define i2c_sda_release() \
pinMode(_sdaPin, INPUT);
// sets SCL low and drives output
#define i2c_scl_lo() \
pinResetFast(_sclPin); \
pinMode(_sclPin, OUTPUT);
// sets SDA low and drives output
#define i2c_sda_lo() \
pinResetFast(_sdaPin); \
pinMode(_sdaPin, OUTPUT);
// Setting SCL high and to input releases pin ie floating
// HR NOTE - not implementing PULLUP as is pulled up externally
#define i2c_scl_hi() \
pinSetFast(_sclPin); \
pinMode(_sclPin, INPUT);
// Setting SDA high and to input releases pin ie floating
// HR NOTE - not implementing PULLUP as is pulled up externally
#define i2c_sda_hi() \
pinSetFast(_sdaPin); \
pinMode(_sdaPin, INPUT);
//
// Constructor
//
SoftI2CMaster::SoftI2CMaster()
{
// do nothing, use setPins() later
}
//
SoftI2CMaster::SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin)
{
setPins(sclPin, sdaPin, true);
//i2c_init(); Removed via HR's sugesstion.
}
//
SoftI2CMaster::SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin, uint8_t pullups)
{
setPins(sclPin, sdaPin, pullups);
//i2c_init(); Removed via HR's sugesstion.
}
//
// Turn Arduino pin numbers into PORTx, DDRx, and PINx
//
void SoftI2CMaster::setPins(uint8_t sclPin, uint8_t sdaPin, uint8_t pullups)
{
uint8_t port;
usePullups = pullups;
_sclPin = sclPin;
_sdaPin = sdaPin;
_sclBitMask = digitalPinToBitMask(sclPin);
_sdaBitMask = digitalPinToBitMask(sdaPin);
port = digitalPinToPort(sclPin);
_sclPortReg = portOutputRegister(port);
_sclDirReg = portModeRegister(port);
port = digitalPinToPort(sdaPin);
_sdaPortReg = portOutputRegister(port);
_sdaDirReg = portModeRegister(port);
initialized = 255;
}
//
//
//
uint8_t SoftI2CMaster::beginTransmission(uint8_t address)
{
i2c_start();
uint8_t rc = i2c_write((address<<1) | 0); // clr read bit
// The standard Wire library returns a status in endTransmission(), not beginTransmission().
// So we will return the status here but also remember the result so we can return it in endTransmission().
// It also allows us to disable other I2C functions until beginTransmission has been called, if we want.
initialized = rc;
return rc;
}
//
uint8_t SoftI2CMaster::requestFrom(uint8_t address)
{
i2c_start();
uint8_t rc = i2c_write((address<<1) | 1); // set read bit
return rc;
}
//
uint8_t SoftI2CMaster::requestFrom(int address)
{
return requestFrom( (uint8_t) address);
}
// Added for compatibility with the standard Wire library.
uint8_t SoftI2CMaster::requestFrom(int address, int quantity)
{
return requestFrom( (uint8_t) address);
// Ignore 'quantity', since SoftI2CMaster::requestFrom() just sets the start of read adresses,
// so it's the same for any number of bytes.
(void)quantity;
}
// Added for compatibility with the standard Wire library.
uint8_t SoftI2CMaster::requestFrom(uint8_t address, uint8_t quantity)
{
return requestFrom( (uint8_t) address);
// Ignore 'quantity', since SoftI2CMaster::requestFrom() just sets the start of read adresses,
// so it's the same for any number of bytes.
(void)quantity;
}
//
uint8_t SoftI2CMaster::beginTransmission(int address)
{
return beginTransmission((uint8_t)address);
}
//
//
//
uint8_t SoftI2CMaster::endTransmission(void)
{
i2c_stop();
return initialized; // Use the result of beginTransmission()
}
// must be called in:
// slave tx event callback
// or after beginTransmission(address)
uint8_t SoftI2CMaster::write(uint8_t data)
{
return i2c_write(data);
}
// must be called in:
// slave tx event callback
// or after beginTransmission(address)
void SoftI2CMaster::write(uint8_t* data, uint8_t quantity)
{
for(uint8_t i = 0; i < quantity; ++i){
write(data[i]);
}
}
// must be called in:
// slave tx event callback
// or after beginTransmission(address)
void SoftI2CMaster::write(char* data)
{
write((uint8_t*)data, strlen(data));
}
// must be called in:
// slave tx event callback
// or after beginTransmission(address)
void SoftI2CMaster::write(int data)
{
write((uint8_t)data);
}
//--------------------------------------------------------------------
void SoftI2CMaster::i2c_writebit( uint8_t c )
{
if ( c > 0 ) {
i2c_sda_hi();
} else {
i2c_sda_lo();
}
i2c_scl_hi();
_delay_us(i2cbitdelay);
i2c_scl_lo();
_delay_us(i2cbitdelay);
if ( c > 0 ) {
i2c_sda_lo();
}
_delay_us(i2cbitdelay);
}
//
uint8_t SoftI2CMaster::i2c_readbit(void)
{
i2c_sda_hi();
i2c_scl_hi();
_delay_us(i2cbitdelay);
uint8_t port = digitalPinToPort(_sdaPin);
volatile uint8_t* pinReg = portInputRegister(port);
uint8_t c = *pinReg; // I2C_PIN;
i2c_scl_lo();
_delay_us(i2cbitdelay);
return ( c & _sdaBitMask) ? 1 : 0;
}
// Inits bitbanging port, must be called before using the functions below
//
void SoftI2CMaster::i2c_init(void)
{
//I2C_PORT &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL ));
//*_sclPortReg &=~ (_sdaBitMask | _sclBitMask);
i2c_sda_hi();
i2c_scl_hi();
_delay_us(i2cbitdelay);
}
// Send a START Condition
//
void SoftI2CMaster::i2c_start(void)
{
// set both to high at the same time
//I2C_DDR &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL ));
//*_sclDirReg &=~ (_sdaBitMask | _sclBitMask);
i2c_sda_hi();
i2c_scl_hi();
_delay_us(i2cbitdelay);
i2c_sda_lo();
_delay_us(i2cbitdelay);
i2c_scl_lo();
_delay_us(i2cbitdelay);
}
void SoftI2CMaster::i2c_repstart(void)
{
// set both to high at the same time (releases drive on both lines)
//I2C_DDR &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL ));
//*_sclDirReg &=~ (_sdaBitMask | _sclBitMask);
i2c_sda_hi();
i2c_scl_hi();
i2c_scl_lo(); // force SCL low
_delay_us(i2cbitdelay);
i2c_sda_release(); // release SDA
_delay_us(i2cbitdelay);
i2c_scl_release(); // release SCL
_delay_us(i2cbitdelay);
i2c_sda_lo(); // force SDA low
_delay_us(i2cbitdelay);
}
// Send a STOP Condition
//
void SoftI2CMaster::i2c_stop(void)
{
i2c_scl_hi();
_delay_us(i2cbitdelay);
i2c_sda_hi();
_delay_us(i2cbitdelay);
}
// write a byte to the I2C slave device
//
uint8_t SoftI2CMaster::i2c_write( uint8_t c )
{
for ( uint8_t i=0;i<8;i++) {
i2c_writebit( c & 128 );
c<<=1;
}
return i2c_readbit();
}
// read a byte from the I2C slave device
//
uint8_t SoftI2CMaster::i2c_read( uint8_t ack )
{
uint8_t res = 0;
for ( uint8_t i=0;i<8;i++) {
res <<= 1;
res |= i2c_readbit();
}
if ( ack )
i2c_writebit( 0 );
else
i2c_writebit( 1 );
_delay_us(i2cbitdelay);
return res;
}
// FIXME: this isn't right, surely
uint8_t SoftI2CMaster::read( uint8_t ack )
{
return i2c_read( ack );
}
//
uint8_t SoftI2CMaster::read()
{
return i2c_read( I2C_ACK );
}
//
uint8_t SoftI2CMaster::readLast()
{
return i2c_read( I2C_NAK );
}
SoftI2CMaster.h
/*
* SoftI2CMaster.h -- Multi-instance software I2C Master library
*
* 2010-2012 Tod E. Kurt, http://todbot.com/blog/
* 2014, by Testato: update library and examples for follow Wire’s API of Arduino IDE 1.x
*
*/
#ifndef SoftI2CMaster_h
#define SoftI2CMaster_h
#include <inttypes.h>
#define _SOFTI2CMASTER_VERSION 13 // software version of this library
class SoftI2CMaster
{
private:
// per object data
uint8_t _sclPin;
uint8_t _sdaPin;
uint8_t _sclBitMask;
uint8_t _sdaBitMask;
volatile uint8_t *_sclPortReg;
volatile uint8_t *_sdaPortReg;
volatile uint8_t *_sclDirReg;
volatile uint8_t *_sdaDirReg;
uint8_t usePullups;
// 'initialized' will be:
// 255 on startup,
// 0 if beginTransmission() was called and successful,
// any other value if there was an error during beginTransmission().
uint8_t initialized;
// private methods
void i2c_writebit( uint8_t c );
uint8_t i2c_readbit(void);
void i2c_init(void);
void i2c_start(void);
void i2c_repstart(void);
void i2c_stop(void);
uint8_t i2c_write( uint8_t c );
uint8_t i2c_read( uint8_t ack );
public:
// public methods
SoftI2CMaster();
SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin);
SoftI2CMaster(uint8_t sclPin, uint8_t sdaPin, uint8_t usePullups);
void setPins(uint8_t sclPin, uint8_t sdaPin, uint8_t usePullups);
uint8_t beginTransmission(uint8_t address);
uint8_t beginTransmission(int address);
uint8_t endTransmission(void);
uint8_t write(uint8_t);
void write(uint8_t*, uint8_t);
void write(int);
void write(char*);
void begin(void) {return;};
uint8_t requestFrom(int address);
uint8_t requestFrom(uint8_t address);
uint8_t requestFrom(int address, int quantity);
uint8_t requestFrom(uint8_t address, uint8_t quantity);
uint8_t read( uint8_t ack );
uint8_t read();
uint8_t readLast();
};
#endif
My .ino code is below:
#include "application.h"
#include "BQ20Z45.h" //Include BQ78350 Header File
#include "SoftI2CMaster.h"
void setup(void)
{
// We start the serial library to output our messages.
Serial.begin(115200);
// Start i2c communication.
Wire.begin();
}
void loop(void)
{
delay(4000);
}
I only get 1 error so far when I compile the code as shown below and I’m guessing I do not need that file on the Photon and it should be removed but I wanted to ask before assuming.
@UMD Can you show me the code you used in your main .ino file for setting the I2C pins properly and then calling begin for the SoftI2CMaster bus? That would keep me from guessing