I2C Communication with Softwire Library

Hello everyone, i am a student doing this Project where i have to use I2C Protocoll to use my SHT31 Sensor. Now the Prototype Shield that i have for my ATMega 2560 does not have any SDA and SCL Pins configured on it, so i researched and found out that a library like Softwire could do the job to set the SDA and SCL Pins on any other Pins(rather than 20 and 21) as i would like to.

So i decided to work first with the Arduino's Wire Library and do the same thing with my Softwire Library, as both the libraries have similar Functions. While working with the Wire Library and default SDA and SCL Pins it works perfectly but when i change the Pins and use the SoftWire Library, it doesn't.

Here is the Code with my Wire library after i got helped from a YT Video:

 #include <Wire.h>

#define Slave_Addr 0x44
#define SHT_MEAS_HIGHREP_nOHOLD_CMD 0x2400
#define SHT31_MEAS_WAIT 20


uint8_t data[6];
uint32_t temp_raw, hum_raw;

void setup() {
  Serial.begin(9600);
  while (!Serial);
    Serial.println("Test");
  
  Wire.begin();
}

void loop() {
  Wire.beginTransmission(Slave_Addr);
  Wire.write(SHT_MEAS_HIGHREP_nOHOLD_CMD >> 8);
  Wire.write(SHT_MEAS_HIGHREP_nOHOLD_CMD & 0xFF);
  Wire.endTransmission();

  delay(SHT31_MEAS_WAIT);

  Wire.requestFrom(Slave_Addr,6);

  if (Wire.available()==6) {
    for (int i=0; i<=6; i++) {
    data[i] = Wire.read();
    }

    temp_raw = ((uint16_t)data[0]<<8) | data[1];
    hum_raw = ((uint16_t)data[3]<<8) | data[4];

    float cTemp = (temp_raw * 175 / 65535.0) - 45;

   float humidity =  hum_raw * 100 / 65535.0;

  Serial.print("Relative Humidity : ");
  Serial.print(humidity);
  Serial.println("%");
  Serial.print("Temperature = ");
  Serial.print(cTemp);
  Serial.print("°C");
  }

  delay(2000);
}

And this is my modified Code with Softwire Library:

#include <SoftWire.h>

// PINS for Custom SDA ans SCL
#define SDA_PIN 2   
#define SCL_PIN 3

// Slave Address
#define Slave_Addr 0x44

// SHT31 Measurement with High Repeatability without Clock Stretching
#define SHT_MEAS_HIGHREP_nOHOLD_CMD 0x2400

// Delay time for SHT31 to measure the data
#define SHT31_MEAS_WAIT 20

// Instantiate SoftWire with custom pins
SoftWire mywire = SoftWire(SDA_PIN, SCL_PIN); 

uint8_t data[6];
uint32_t temp_raw, hum_raw;

void setup() {
  Serial.begin(9600);
  while (!Serial);
  Serial.println("Initializing SHT31 sensor...");
  mywire.begin();
  delay(1000); // Allow time for stabilization
}

void loop() {
  mywire.beginTransmission(Slave_Addr);
  mywire.write(SHT_MEAS_HIGHREP_nOHOLD_CMD >> 8);
  mywire.write(SHT_MEAS_HIGHREP_nOHOLD_CMD & 0xFF);
  mywire.endTransmission();

  delay(SHT31_MEAS_WAIT);

  mywire.requestFrom(Slave_Addr, 6);

  if (mywire.available() == 6) {
    for (int i = 0; i < 6; i++) {
      data[i] = mywire.read();
    }

    temp_raw = ((uint16_t)data[0] << 8) | data[1];
    hum_raw = ((uint16_t)data[3] << 8) | data[4];

    float cTemp = (temp_raw * 175.0 / 65535.0) - 45.0;
    float humidity = hum_raw * 100.0 / 65535.0;

    Serial.print("Relative Humidity: ");
    Serial.print(humidity);
    Serial.println("%");
    Serial.print("Temperature: ");
    Serial.print(cTemp);
    Serial.println("°C");
  }

  delay(2000);
}

I would really really appreciate if anyone here could help me with this Problem.

Thanks in Advance.

Welcome to the forum.

Can you show a photo with the Arduino board, the prototype shield, the sensor module and the wiring ?
Can you give a link to your prototype shield ? Is it a shield for an Arduino Uno without the SDA and SCL pins near the AREF pin ?

Instead of trying to communicate with the sensor, it is easier to run a I2C Scanner.
Can you try this:

// Forum: https://forum.arduino.cc/t/i2c-communication-with-softwire-library/1237721
// This Wokwi project: https://wokwi.com/projects/392870739462268929
// 
// Question: Does the SoftWire library work on a Arduino Mega ?
// Answer: Yes, I think it does.


#include <SoftWire.h>

// PINS for Custom SDA ans SCL
#define SDA_PIN 2   
#define SCL_PIN 3

// Instantiate SoftWire with custom pins
SoftWire mywire = SoftWire(SDA_PIN, SCL_PIN); 

void setup() 
{
  Serial.begin(9600);
  mywire.begin();

  Serial.print("Scan: ");
  for(int address=1; address<=127; address++)
  {
    mywire.beginTransmission(address);
    int error = mywire.endTransmission();
    if(error==0)
    {
      Serial.print("0x");
      Serial.print(address,HEX);
      Serial.print(" ");
    }
  }
  Serial.println("  --> Finished");
}

void loop() 
{
  delay(10);
}

This sketch in Wokwi:

Hi @kaazi32 ,

this seems to be the github location for the Softwire library you use:

https://github.com/stevemarple/SoftWire/tree/master

I copied the example for reading a DS1307 RTC to a Wokwi project and checked it with an Arduino MEGA and the pins 2 and 3. It is working there:

https://wokwi.com/projects/392870429864925185

The main difference I saw is that the example reserves space for Tx/Rx data:

// These buffers must be at least as large as the largest read or write you perform.
char swTxBuffer[16];
char swRxBuffer[16];

and uses this initialization in Setup()

  sw.setTxBuffer(swTxBuffer, sizeof(swTxBuffer));
  sw.setRxBuffer(swRxBuffer, sizeof(swRxBuffer));
  sw.setDelay_us(5);
  sw.setTimeout(1000);
  sw.begin();

You could copy the declaration and initialization of the buffers to your code and give it a try... (of course change the name from "sw." to "mywire." ... :wink: )

Good luck!
ec2021

2 Likes

1. Make chnage in your sketch as follows and try again:

#include<SoftwareWire.h>   //include SoftwareWire.h Library 
SoftWareWire mywire(SDA_PIN, SCL_PIN);

2. My test sketches to check the functionality of SoftwareWire.h Library connectig MEGA (Master) and UNO (slave).
Master Sketch:

#include <SoftwareWire.h>
// PINS for Custom SDA ans SCL
#define SDA_PIN 2
#define SCL_PIN 3

#define Slave_Addr 0x44

SoftwareWire mywire(SDA_PIN, SCL_PIN); 

void setup()
{
  Serial.begin(9600);
  mywire.begin();
  //--------------------
  mywire.beginTransmission(Slave_Addr);
  byte busStatus = mywire.endTransmission();
  if(busStatus != 0)
  {
    Serial.println("Slave is not found.");
    while(true); //wait for ever
  }
  Serial.println("Slave is present.");
}

void loop() {}

Slave Sketch:

#include<Wire.h>

void setup() 
{
  Wire.begin(0x44);
}

void loop() {}

Output:

Slave is present.

Hi @Koepel, these are the photos of my Shield and the wiring i made. I just wanted to check first with the connections i made in Breadboard before i use the Shield. The Shield is custom made and provided to me by my Professor and told me that he doesnt have any Documentation . So here it is.

I also tested the code you provided for the i2c scanner. It worked.


Hello @ec2021, yes that is the library i am using. Sorry i didnt post the link. Those Rx and Tx are responsible for the receiving and transmitting data? I will give it a try. Thanks.

Hi @GolamMostafa i am sorry i dont understand. I have my ATmega but am not using Uno as my Slave. So i dont think it is the right way, right?

OMG, @ec2021 Thanks mate, it worked. Although i dont get it what are those chars for Rx and Tx. What do they do ? Could you please explain it to me? Thank you very much, appreciate it. :blush: :blush:

In my post #4, I have connected UNO as Slave just to check the functionality of the soft I2C bus. You will go with your sensors being connected as Slaves.

If you "dive" a little bit into the library you'll find this

    // The Wire compatibility functions require RX and TX buffers. The same address space may be used for both
    // as long as the user does not call receiveFrom between startTransmission and endTransmission.
    inline void setRxBuffer(void *rxBuffer, uint8_t rxBufferSize) {
      _rxBuffer = (uint8_t*)rxBuffer;
      _rxBufferSize = rxBufferSize;
      _rxBufferIndex = 0;
      _rxBufferBytesRead = 0;
    }

It are just buffers for reception/transmission due to Wire compatibility.

As the comment says the same buffer would be sufficient for both purposes if the function receiveFrom() is not called between startTransmission() and endTransmission(). That might save some valuable memory space if required.

Can you solder wires to the pins of the normal I2C bus ?

If it works please mark my post (#3) as the solution so that other members know it has been solved.

no i'm afraid not. But it has already worked, so thanks for your effort. :blush:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.