Bit Banging I2C for communication between Raspberry Pi and PCF8591

Thread Starter

John Manuel

Joined Jun 6, 2018
17
I am trying to interface multiple PCF8591 (around 5) to a single Raspberry Pi using I2C protocol. Since a Rpi has only one set of SDA and SCL pins, I am trying to bit-bang to make the other GPIO pins work as SDA and SCL. I am trying to use RPi.GPIO library for making the bit banging code in python.

I don't understand how to communicate with PCF8591 even after referring to the manual plenty of times. I could not figure out how to receive data from a specific pin from PCF8591 since there are 4 pins available (AIN0, AIN1, AIN2, AIN3). I also want the input voltage as the differential voltage between two pins. It would be very helpful if anyone could tell me the steps to change and access different pins of PCF8591.

I am attaching the code I am using. I get a reading of '255' throughout whenever I run it. It is working more or less as I could see the SCA and SDA waveforms in an oscilloscope.


Code:
import RPi.GPIO as GPIO
import time
import matplotlib.pyplot as plt

pin_SCL = 0
pin_SDA = 0
signal = []

def plot_graph(time, data, graph_no, label_):
    fig = plt.figure(graph_no)
    axes = fig.add_subplot(111)
    axes.patch.set_facecolor('black')
    plt.plot(time, data, label = label_)
    plt.ylabel('Voltage')
    plt.xlabel('Time')
    plt.legend(loc='upper right')

def set_pin(SCL, SDA):
    global pin_SCL
    global pin_SDA
    pin_SCL = SCL
    pin_SDA = SDA
    GPIO.setup(pin_SCL, GPIO.OUT)

def start():
    GPIO.setup(pin_SDA, GPIO.OUT)
   
    GPIO.output(pin_SCL, GPIO.HIGH)
    GPIO.output(pin_SDA, GPIO.HIGH)
   
    time.sleep(10)
   
    GPIO.output(pin_SDA, GPIO.LOW)
    GPIO.output(pin_SCL, GPIO.LOW)
   
def send_byte(byte):
    GPIO.setup(pin_SDA,GPIO.OUT)
   
    for i in range(8):
        GPIO.output(pin_SDA,byte & 0b10000000)
        GPIO.output(pin_SCL,GPIO.HIGH)
        GPIO.output(pin_SCL,GPIO.LOW)
        byte = byte << 1

def acknowledge_from_slave():
    GPIO.setup(pin_SDA,GPIO.IN)
   
    GPIO.output(pin_SCL,GPIO.HIGH)
    status = GPIO.input(pin_SDA)
    GPIO.output(pin_SCL,GPIO.LOW)
   
    if(status == GPIO.HIGH):
        print("BYTE NOT RECEIVED")
           
def acknowledge_from_master():
    GPIO.setup(pin_SDA,GPIO.OUT)
   
    GPIO.output(pin_SCL,GPIO.HIGH)
    GPIO.output(pin_SDA,GPIO.LOW)
    GPIO.output(pin_SCL,GPIO.LOW)

def receive_byte():
    global signal
    byte = ''
   
    GPIO.setup(pin_SDA,GPIO.IN)
   
    for i in range(8):
            GPIO.output(pin_SCL,GPIO.HIGH)
            byte = byte + str(GPIO.input(pin_SDA))
            GPIO.output(pin_SCL,GPIO.LOW)
   
    byte = int(byte,2)
    signal.append(byte)
           
if __name__ == "__main__":
    global signal
   
    GPIO.setmode(GPIO.BOARD)
    set_pin(38,40)
    start()
    send_byte(0b10010001)
    acknowledge_from_slave()
   
    send_byte(0b00110000)#control byte to tell pcf8591 work as differential input
   
    acknowledge_from_master()

    try:
        while True:
            receive_byte()
            acknowledge_from_master()
           
    except KeyboardInterrupt:
        plot_graph(range(len(signal)),signal,1,'Detected Signal')

    plt.show()
    GPIO.cleanup()
 

Thread Starter

John Manuel

Joined Jun 6, 2018
17
PCF8591 has 3 address pins so you can address 8 of them. Why don't you connect them all to the same I2C bus?
I need data from all the ADC at the same time instant for my project. I came to know that the master can communicate with only one slave at any time instant and the other slaves have to sit idle at that time instant.
 

Papabravo

Joined Feb 24, 2006
22,083
And the differential timing between you bit banging and the hardware I2C will destroy any concept of simultaneity you might imagine to exist. What you want is a sample and hold system for which I2C is not well suited. You need to get your head out of the dark place it seemingly inhabits.
 

John P

Joined Oct 14, 2008
2,063
I'd have thought that if you could control a port's pins all at once--a pretty simple concept--you actually could bit-bang multiple I2C channels with identical timing, both for output and input. Whether this is really worth doing is another question, though.

Call it port-banging instead of bit-banging, maybe.
 
Top