Help with clashing I2C addresses

Hi. I have an issue when trying to use I2C addresses to interface MAX 5487 digipot and GUI Tkinter switches with an Arduino Mega 2560. I have tried to declare different slave addresses for the switches and slider for the digipot but this would usually lead to at least one of the functions not working. (If I'm not wrong I was getting an error that said return self.func(*args)) The I2C communication is achieved by using the GPIO ports on a Raspberry Pi 4. The only way I managed to fix this was to use the same addresses for both functions. However this would lead to overlapping data. Any help is greatly appreciated.
The python code is as follows:

# Import the required libraries
import tkinter
from tkinter import *
import tkinter.font as tkFont
from PIL import ImageTk, Image
# import time 
import smbus
import serial
import os

bus = smbus.SMBus(1)
#arduinodata = serial.Serial(port='/dev/ttyACM0', baudrate=9600) #initialise serial port to connect to arduino
SLAVE_ADDRESS = 0x08
SLAVE_ADDRESS1 = 0x10

class App:
    def __init__(self, master):

        def SendScaleReading(self):
            S = scale.get() #retrieve value from slider
            print(S)
            bus.write_byte(SLAVE_ADDRESS, S) #write data to slave address

        frame = Frame(master)
        frame.pack()
        scale = tkinter.Scale(root,from_=0,to=255,length=700,bg='black',fg='#0000FF', highlightthickness = 0, bd = 0, command=SendScaleReading) #set parameters of slider
        scale.place(relx=0.75, rely=0.05)
        #scale.place(relx = 0, rely = 0) # set position of slider
        fontstyle = tkFont.Font(family='Arial', size=50) #initialise font
        scale['font'] = fontstyle 
        # cannot use .place()


def PowerFn():
    global powerBool
#     print(ledBool)

    if powerBool:
        #print('went to on button')
        powerBtn.config(image=On_BtnImg)  
        powerBtn.image = On_BtnImg
        #print("on button configured")
        powerLabel.config(text="POWER: ON", fg='#00FF00')
        # communicating with arduino
#         arduinodata.write(string('1', encoding='utf-8'))
        bus.write_byte(SLAVE_ADDRESS1, 1) #write data to slave address
    else:
        #print('went to off button')
        powerBtn.config(image=Off_BtnImg)
        powerBtn.image = Off_BtnImg
        #print("off button configured")
        powerLabel.config(text="POWER: OFF", fg='#FF0000')
        # communicating with arduino
        bus.write_byte(SLAVE_ADDRESS1, 0) #write data to slave address
    powerBool = not powerBool

def DirectionFn():
    global directionBool
#     print(cbBool)
    if directionBool: 
        #print('went to CbOn button')
        directionBtn.config(image = On_BtnImg)
        directionBtn.image = On_BtnImg
        #print("CbOn button configured")
        directionLabel.config(text="FORWARD", fg='#00FF00')
        # communicating with arduino
        bus.write_byte(SLAVE_ADDRESS1, 3) #write data to slave address

    else:
        #print('went to CbOff button')
        directionBtn.config(image = Off_BtnImg)
        directionBtn.image = Off_BtnImg
#         print("CbOff button configured")
        directionLabel.config(text="REVERSE", fg='#FF0000')
        # communicating with arduino
        bus.write_byte(SLAVE_ADDRESS1, 2) #write data to slave address
    directionBool = not directionBool

root = Tk()
app = App(root)
root.config(bg='black')
#root.attributes('-zoomed', True)
#root.state('fullscreen')
rootWidth = root.winfo_screenwidth()
rootHeight = root.winfo_screenheight()
# Create mini window
#canvas = Canvas(root, bg='black', highlightbackground='white')
#canvas.place(relx=0.1, rely=0.03, relheight=0.51, relwidth=0.505)

On_img = Image.open("/home/pi/Downloads/on.png")
Off_img = Image.open("/home/pi/Downloads/off.png")

# Resize the image using resize() method according to the screen height and width
btnWidth = int(rootWidth / 6.4)
print(btnWidth)
infobtnWidth = int(rootHeight / 10)
print(infobtnWidth)

On_resize_img = On_img.resize((btnWidth, btnWidth))
Off_resize_img = Off_img.resize((btnWidth, btnWidth))
On_BtnImg = ImageTk.PhotoImage(On_resize_img)
Off_BtnImg = ImageTk.PhotoImage(Off_resize_img)

normalWidth = 1920  # Width of monitor screen used to write this code
normalHeight = 1080  # Height of monitor screen used to write this code

percentWidth = rootWidth / (normalWidth / 100)
percentHeight = rootHeight / (normalHeight / 100)

scale = ((percentWidth + percentHeight) / 2) / 100

fontsize = int(14 * scale)
fontsize = 50
fontstyle = tkFont.Font(family='Arial', size=fontsize)

titleFontsize = int(50 * scale)
if titleFontsize < 8:
    titleFontsize = 8
TitleFontstyle = tkFont.Font(family="Gothic", size=titleFontsize)
## Labels ##
titleLabel = Label(root, text="MAX5487 DigiPot", font=TitleFontstyle, fg="red", bg="black")
titleLabel.place(relx=0.35, rely=0.05)


powerLabel = Label(root, text="POWER: OFF", font=fontstyle, fg='red', bg='black')
powerLabel.place(relx=0.2, rely=0.65, anchor=N)
directionLabel = Label(root, text="REVERSE", font=fontstyle, fg='red', bg='black')
directionLabel.place(relx=0.5, rely=0.65 , anchor=N)

powerBool = True  # boolean for led button
powerBtn = Button(root, image=Off_BtnImg, bg='black', bd=0, activebackground='black', highlightthickness = 0, command=PowerFn)
powerBtn.place(relx=0.2, rely=0.35, anchor=N)

directionBool = True
  
directionBtn = Button(root, image=Off_BtnImg, bg='black', bd=0, activebackground='black', highlightthickness = 0, command=DirectionFn)
directionBtn.place(relx=0.5, rely=0.35, anchor=N)

# Button for closing
exit_button = Button(root, text="Exit", font=fontstyle, fg='white', bg='red', highlightthickness = 0, command=root.destroy)
exit_button.place(relx=0.5, rely=0.9, anchor=N)

root.mainloop()

And here is the code for the Arduino Mega:

#include <SPI.h>
#include <Wire.h> 
#define ADDRESS 0x08
#define ADDRESS1 0x10
TwoWire Wire1;
const byte ssPin = 53;
const byte writepotA = B00000001;
const byte writepotB = B00000010;
byte x;
byte y;

void setup() {
  Serial.begin(9600);//set baud rate
  pinMode(ssPin, OUTPUT);
  for (int pinNo = 22; pinNo <= 26; pinNo += 2){
    pinMode(pinNo, OUTPUT);
  }
  digitalWrite(ssPin, LOW);// activate MAX 5487 chip
  for (int pinNo = 22; pinNo <= 26; pinNo += 2){
    digitalWrite(pinNo, LOW);
  }
  SPI.begin();// begin Serial Peripheral Interface
  SPI.setBitOrder(MSBFIRST);// Most significant bit first
  SPI.setDataMode(SPI_MODE3);// set SPI to Mode 3
  Wire.begin(ADDRESS);// join i2c bus with address 0x08
  Wire1.begin(ADDRESS1);// join i2c bus with address 0x08
  Wire.onReceive(receiveEvent); // register event
  Wire1.onReceive(receiveEvent1); // register event
} 
 
// get called when I2C write occurs
void receiveEvent(int WiperPos) {

    int val = Wire.read();
    x = val; // retrieve value from I2C to variable x
// read value sent from python
  while (Wire.available() > 0 ) {
    Wire.read();
  }
}
// get called when I2C write occurs
void receiveEvent1(String Pos) {
    byte val1 = Wire1.read();
    y = val1; // retrieve value from I2C to variable x
// read value sent from python
  while (Wire1.available() > 0 ) {
    Wire1.read();
  }
}
void loop() {
  Serial.print(y);
  switch (y){
  case 0:
  digitalWrite(22, LOW);
  break;
  case 1:
  digitalWrite(22, HIGH);
  break;
  case 2:
  digitalWrite(24, LOW);
  break;
  case 3:
  digitalWrite(24, HIGH);
  break;
  default:
  for (int pinNo = 22; pinNo <= 26; pinNo += 2){
    digitalWrite(pinNo, LOW);
  } 
}
  Serial.print(x);
  setPotWiper(writepotA, x);// alter position of wiper A
  setPotWiper(writepotB, x);// alter position of wiper B
  delay(15);
}
void setPotWiper(int addr, int pos){
  pos =  constrain(pos, 0, 255);// limit wiper values
  digitalWrite(ssPin, LOW);// enable chip
  SPI.transfer(addr);// transfer data to address
  SPI.transfer(pos);// write wiper position to address
  digitalWrite(ssPin, HIGH);// disable chip
}

Is a MAX5487 an SPI device, not I2C?

Apologies for the confusion what I meant to say was I2C was used to transfer data from the Raspberry Pi to Arduino, the latter of which the MAX5487 is connected to

There are so many things that I don't understand.

I understand that you have a Raspberry Pi 4 with the I2C bus enabled. And you run the TKinter Python user interface : https://wiki.python.org/moin/TkInter.

From then on it gets fuzzy.
Do you know that the I2C on the Raspberry Pi is working ? Can you test it with a I2C device ?
You may not connect the Arduino Mega to the same I2C bus. Do you use a level shifter ?
The Arduino Mega has only one I2C bus, there is no Wire1.
There is no need to clear the buffer in the receiveEvent.
Variables that are used in a interrupt and in the loop() should be 'volatile'.
Try to avoid to use too many Serial.print(). There is only a delay(15) in the loop() to reduce the number of outgoing serial data and the baudrate is very slow.

If you connect the Arduino Mega board with a USB cable to the Raspberry Pi, then you can use the Serial interface. That might be a better solution to communicate between those boards.

Thanks for the reply, appreciate you taking the time to help.
For the I2C on the Raspberry Pi, I have used the i2cdetect command in the Raspberry Pi's python terminal to check that the I2C bus is working. The data transfer also seems to work fine with 1 wire, which seems to line up with your point about the Arduino Mega only having 1 I2C bus.
Excuse my ignorance but what is a level shifter and what do you mean by clearing the buffer in receiveEvent and variables that are used in a interrupt and in the loop() should be 'volatile'?

I've also attempted to use Serial interfacing for the switches before. I ended up with I2C as the Serial Interface would cause the program to have a weird freezing issue. I've made a post about it here:

I will answer in your other topic about the Serial things.

A bidirectional I2C voltage level shifter connects a 5V I2C bus to a 3.3V I2C bus.
Sparkfun has a tutorial about it: https://learn.sparkfun.com/tutorials/bi-directional-logic-level-converter-hookup-guide/all.

The Arduino Mega 2560 had 10k pullup resistors on board. When you connect that to a Raspberry Pi, then 5V leaks into the Raspberry Pi pin via the 10k pullup resistor. That is not nice.

It can be dangerous, when a 3.3V I2C sensor is in sleep mode and uses no current. Then that very small current can lift the voltage of the whole sensor to 5V and the sensor might get damaged.

The I2C bus works with packages, it is not a stream of data. There is no need to clear a buffer.

volatile byte x;           // volatile, because it is used both in a interrupt and in the loop()

void receiveEvent(int WiperPos) 
{
  x = Wire.read();       // read one byte

  // no need to clear the buffer, no need to read remaining data
  // while (Wire.available() > 0 ) 
  // {
  //   Wire.read();
  // }
}

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