Maker Pro
Maker Pro

Bit Banging I2C for communication between Raspberry Pi and PFC8591

John Manuel

Jun 7, 2018
20
Joined
Jun 7, 2018
Messages
20
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()
 
Last edited:

(*steve*)

¡sǝpodᴉʇuɐ ǝɥʇ ɹɐǝɥd
Moderator
Jan 21, 2010
25,510
Joined
Jan 21, 2010
Messages
25,510
An i2c bus can have 127 slaves on it. The PCF8591 can only have 1 of 8 addresses set, so you can only have 8 of them connected to a single bus.

Why not use the single bus the RPI has and whatever standard libraries it has. Surely you can find examples of how to talk to this chip?
 

John Manuel

Jun 7, 2018
20
Joined
Jun 7, 2018
Messages
20
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.

I actually wanted to know how to access different pins in a single PCF8591.
 

(*steve*)

¡sǝpodᴉʇuɐ ǝɥʇ ɹɐǝɥd
Moderator
Jan 21, 2010
25,510
Joined
Jan 21, 2010
Messages
25,510
For true simultaneity you need to trigger all the ADCs at the same time, or to hold the inputs at the same time. A series of sample & hold circuits with a common control would allow you to hold at the signals and then read them one by one. It can be even simpler here with an analog mux because you only need a single ADC.

But banging seems to be the hard way. I understand doing it that way if you have a million units to create; the cost saving in a few chips could outweigh the additional software complexity.
 

John Manuel

Jun 7, 2018
20
Joined
Jun 7, 2018
Messages
20
Thank you very much for your reply! I have already chosen to travel the harder path it seems and I do not wish to turn back now. I will try the same with a multiplexer later, but as of now, I need to do it with bit banging.

It would be tremendously helpful if you could tell me what I am doing wrong with the code.
 

(*steve*)

¡sǝpodᴉʇuɐ ǝɥʇ ɹɐǝɥd
Moderator
Jan 21, 2010
25,510
Joined
Jan 21, 2010
Messages
25,510
if you could tell me what I am doing wrong with the code.

I don't see anything to set the timing.

Have you asked on a specialist forum? (see here)

It appears you can configure additional I2C ports on the RPI that will be bit-banged by the OS.
 
Top