SoftwareWire : Testers wanted for a software I2C library.

This is a library that creates a software I2C bus on any two pins of an Arduino Uno, Leonardo, Pro Mini, Mega, and alike.
More than one software I2C bus can be created.

INSTALL:

Install it from Arduino IDE Library Manager.
For people that use old Arduino IDE download the Library from here Releases · Testato/SoftwareWire · GitHub.

The SoftwareWire is only I2C Master mode.
The clock pulse stretching is implemented, so the Slave can be another Arduino board.

See the example "Small_example.ino" how to use it.
Include the library, and create a SoftwareWire object with the sda and scl pin. After that is should be just like the real Wire library.

#include <SoftwareWire.h>

// SoftwareWire constructor.
// Parameters:
//   (1) pin for the software sda
//   (2) pin for the software scl
//   (3) use internal pullup resistors. Default true. Set to false to disable them.
//   (4) allow the Slave to stretch the clock pulse. Default true. Set to false for faster code.
//
// Using pin 2 (software sda) and 3 (software scl) in this example.

SoftwareWire myWire( 2, 3);

Testers wanted: Please try the library with sensors and maybe with Arduino as Slaves, or with multiple I2C busses and so on.

Background information:
I was asking for such a library here : What about a fully compatible software I2C library ? - Networking, Protocols, and Devices - Arduino Forum
Testato was working on such a library here : [Lib] Testato_SoftI2CMaster - Software - Arduino Forum
I added some glue to that code to make it behave like the Wire library.
This library started in 2008, and is now the result of the work of four.
Enjoy.

I will put todsy it on github and set me and you for Mantainer, so we can update the code and continue to work togheter.
Please register to github edn write me your username.

I will update the lib for arduino lib manager style, we need the proprierty file corrected filled, and only after that i can ask for the integration in the repo.

Are you agree to use the official versioning method ?
So this version become 1.3.1
1.3 is your first big update
1.3.1 is your last little update

Thank you !
The version number is okay of course.

The lib is now present in the official arduino repository.
You can found the last version directly from the Arduino IDE Library Manager :wink:

Some sensors have just one selectable I2C address. If someone wants to use many of those, a hardware mux is needed. The SoftwareWire could be used without the need for extra hardware.

Some ideas for multiple software i2c busses:

1 ) When more then one software i2c bus is used, each object uses 56 bytes ram. However, if the RequestFrom() and readBytes() are used for each sensor, one by one, only one RxBuffer is needed. Perhaps a define could added to have just one shared RxBuffer.

// Use common RxBuffer to reduce memory with more than one Object.
#ifdef SOFTWAREWIRE_SHARED_RXBUFFER
SoftwareWire::RxBuffer[.....

2 ) With multiple software i2c busses, it is possible to share the scl pin. The sensors should be used one by one, so that another sensor is used only after a STOP condition (the i2c bus should be idle). That means that 11 pins are needed for 10 sensors.

I have tried to modify this bmp085/180 library to work with SoftwareWire. I have no real experience in making/modifying libraries.

My problem is that I'm not sure where to put "SoftwareWire myWire( 2, 3);".

I am getting this error message:

Arduino: 1.6.4 (Windows 7), Board: "Arduino Nano, ATmega328"

Arduino-BMP085-Library-no-pow-master-SOFTWARE\BMP085.cpp.o:(.bss.myWire+0x0): multiple definition of `myWire'
BMP085test-SOFTWARE.cpp.o:(.bss.myWire+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
Error compiling.

Thanks!

I made same job on my library here [Lib] Testato_ST7032i_LCD_I2C - Software - Arduino Forum
You can look inside.
The only problem is that the new library depend from the softwarewire library so the softwarewire must be installed on the system.

On my installationnote i writed:

This library [Lib] Testato_SoftI2CMaster need to be installed also if you want use only the classic hardware I2C (Wire library)

@Peter_n
do you know a way for remove this dependency ? so if a people need the hardware i2c he is not obliged to install the SoftwareWire ?

--_, that library initializes the I2C bus with Wire.begin() in the file BMP085.cpp.

I would do this: I would not install the "Arduino-BMP085-Library-no-pow" library, but copy the *.ccp and *.h into the project. Add the "SoftwareWire myWire( 2, 3);" to BMP085.cpp and alter that file to use "myWire..." instead of "Wire...".
If that is working, then I would rearrange the software and functions to allow that other sensors and other code can be added for the software I2C bus.

Hi Peter,

using the SoftwareWire library i am experiencing problems with some I2C devices, in particular with the MCP23017, MCP23008 and the DS1337+. I have opened a new topic in this forum here Problem with the SoftwareWire library and certain devices - Networking, Protocols, and Devices - Arduino Forum
I'm not sure if i am missing something or if it's a bug - either in the library or in the device. (I have seen a lot of cr*ppy I2C devices...)
Thank you very much in advance for your help.

Best regards from Houston (TX),
Frank/2

Hi,

I've just downloaded the SoftwareWire library from GitHub and am experiencing problems with it, described here: SoftwareWire I2C library not recognizing the SN3218 chip - Networking, Protocols, and Devices - Arduino Forum

Thanks a lot for any help,
E.

Hey, Thanks for the code, but is it compatible with SMBus?

Hi,

I´m having some troubles setting up two identical sensors with hardwired I2C-Addresses. My code runs without problems whilest using the original Arduino I2C-Pins. As I tried to replicate the communication via the SoftwareWire I2C-Pins, the timing does not seem to function as intended.

Several tests lead me to the conclusion that there might be some issues with the calculation in the SetClock() - function.

The pictures below show the timing protokoll for the following cases:

  1. SoftwareWire I2C without SetClock() - function
  2. SoftwareWire I2C with SetClock() - function set to default 100kHz
  3. Original I2C set to 100kHz

All pictures show the same time section.

I´d like to mention that the second case (SetClock(2)) does not show any reaction on the osci but the sensor reacts after waiting for about 1 minute or so. The original I2C takes onyl 1 sec.

Another thing is that the Scan-I2C() from Nick Gammon (this was mentioned before...) detects slaves at every address whilst using the SoftwareWire-I2C.

Do you guys have any idea how to help me?

I hope you understand the parts of my code. The whole code is too long to post. It is work in progress and I´m trying several things in the same file...

#include <SoftwareWire.h>

#include <Wire.h>

/* Interrupt Pins am Arduino Mega: 2,3,18,19,20,21 */

/*Initialisieren der I2C-Schnittstellen für parallelen Datentransport*/

const int sdaPin2 = 18;               //Die digitalen Pins 26 und 27 werden für die I2C-Kommunikation vorbereitet
const int sclPin2 = 19;
const int sdaPin3 = 16;
const int sclPin3 = 17;

SoftwareWire myWire_2 = SoftwareWire(sdaPin2, sclPin2, true, false);       
SoftwareWire myWire_3 (sdaPin3, sclPin3);

/* Pinbelegung */

int rxio_sup = 5;                     //3,3 V Versorgungsleitung (oranges Kabel über Linearregler)
int tx_sup = 7;                       //5 V Versorgungsleitung (rotes Kabel)
int resetz = 4;                       //ResetZ-Leitung des AFE4404 (grünes Kabel über Linearregler)
int adc_rdy = 2;                      //ADC_RDY-Leitung des AFE4404 (gelbes Kabel)
int afe_clk =6;                       //AFE_CLK-Leitung des AFE4404 für externen Taktgeber bei Bedarf. Im aktuellen Stand nicht verwendet (graues Kabel)

/* Pinbelegung Platine 2 */

int rxio_sup2 = 9;
int tx_sup2 = 11;
int resetz2 = 8;
int adc_rdy2 = 3;
int afe_clk2 = 10;

/* Variablendeklaration */

int befehl = 0;                       //Variable in welche die Eingabebefehle der seriellen Schnittstelle eingelesen werden
volatile int readDataFlag = 0;        //Variable der Interrupt-Subroutine mit welcher die Messdaten ausgelesen werden
unsigned long AFE_Data_Buff[6]; //
double regValue[10];            
int farbe = 0;                        //Variable zum Steuern der LED-Farbe und der zugehörigen Messwerte
String stringOne, stringTwo, stringThree;   //Ausgabestrings für den Betrieb mit allen 3 LEDs
String PrintAll, Print, Print2;
int platAnzahl = 1;
int i2c_Anzahl = 1;

const double adc_const = 0.000000572; //Konstante zur Umrechnung des 24-Bit ADC-Binärcodes in einen Dezimalwert

int AFE_ADDR = 88;                    //I²C-Adresse des AFE4404

void setup() {
  
  Serial.begin(9600);                 //Baudrate für die Kommunikation über die serielle Schnittstelle. Muss identisch zu der Angabe im seriellen Monitor bzw. der Benutzeroberfläche sein

  /* Bestimmen der Pinbelegungen */
  
  pinMode(resetz, OUTPUT);
  pinMode(rxio_sup, OUTPUT);
  pinMode(tx_sup, OUTPUT);
  pinMode(adc_rdy, INPUT);
  pinMode(afe_clk, INPUT);
  
  Wire.begin();                       //Aktivieren des I2C-Bus
  myWire_2.begin();                   //Aktivieren des zweiten I2C-Bus
  myWire_3.begin();

  Wire.setClock(100000L);
  myWire_2.setClock(2);
}

/**************************************************************************************/
/* I can only show the I2C_write funtcion as it gets to long to show everything                  */






/*********************************************************************************************************/
/*                                   AFE4404_Reg_Write                                                   */
/*                                                                                                       */
/* Da die Register des AFE4404 mit 24-Bit Werten beschrieben werden müssen, der I²C-Datenbuss jedoch nur */
/* 8-Bit auf einmal verschicken kann, wird der 24-Bit String vor dem verschicken in 3x 8-Bit Segmente    */
/* unterteilt welche in einem Array gespeichert und nacheinander über den Bus verschickt werden.         */
/*********************************************************************************************************/
void AFE_Reg_Write (int reg_address, unsigned long data)
{
  byte configData[3];
  configData[0]=(byte)(data >>16);
  configData[1]=(byte)(((data & 0x00FFFF) >>8));
  configData[2]=(byte)(((data & 0x0000FF)));
  if (i2c_Anzahl == 1)
  {    
    I2C_write(AFE_ADDR, reg_address, configData, 3); 
  } else if (i2c_Anzahl == 2)
  {  
    I2C_write2(AFE_ADDR, reg_address, configData, 3); 
  }
}

/**********************************************************************************************************/
/*                              Write to AFE on I2C                                                       */
/*                                                                                                        */
/* Hier findet das eigentliche Beschreiben des I²C-Datenbusses statt                                      */
/**********************************************************************************************************/
char I2C_write (int slave_address, int reg_address, byte configData[], int byteCount)
{
  int trans_end = 0;

  myWire_2.beginTransmission(slave_address);
  myWire_2.write(reg_address);
  myWire_2.write(configData, 3);
  myWire_2.endTransmission();
 
  return (trans_end);
}

char I2C_write2 (int slave_address, int reg_address, byte configData[], int byteCount)
{
  int trans_end = 0;
  
  myWire_3.beginTransmission(slave_address);
  myWire_3.write(reg_address);
  myWire_3.write(configData, 3);
  myWire_3.endTransmission();

  return (trans_end);
}

SoftwareWire.jpg

SoftwareWire_SetClock.jpg

Original.jpg