pyscan EXPANDER IO BUT0-BUT7



  • Hello all,

    Looking at the pinout of the PYSCAN here:
    https://docs.pycom.io/.gitbook/assets/pyscan-pinout.pdf
    it does clearly represent some BUT0-BUT7 IO pins
    Looking into the chip marking I found out it is a PCA9554 which is great because it seems its IO are 5 V tolerant according to the datasheet which is great because I need to interface some relays (albeit with opto couplers but the logic still uses 5V) and some down voltage converters enable pins...
    So far so good. But there seem to be a serious lack of documentation, I2C address of the PCA9554, maybe examples on how to use it... A small library would even be great!! Any hint on how to use it would be just fine!!

    I found some example code here, but it would only work if the I2C address is the same and the I2C bus is on the PYCOM.
    https://github.com/kaelmik/amp/blob/master/pca9554.py

    Thank you



  • @Paul-Thornton Thanks for the pointers and @theshade thanks for the library.

    Can we find out how this works in deepsleep? Questions such as:
    Does the PCA remain powered up?
    Can we choose to power it down if we aren't using it?
    Can the PCA interrupt line be used? If so how?
    Can the PCA interrupt signal the PIC to wake the main processor from deepsleep?
    If so, how do we establish why we woke from deepsleep? Can the PIC tell us?

    Or perhaps you could just give us the schematics/PIC code and we could figure it out ;-)

    Thanks!!



  • Dear @paul-thornton,

    Now that the library porting works I need to look into the hardware, I figured that the best I could do to use those ports is to make my own "intermediate" PCB to access them and fan them out.
    I also want to access other pins which on the fipy so putting a board inbetween seems to be the best option.
    Anyway since the pins don't seem to be aligned on any particular grid, would it be possible to share the mechanical drawing of the connectors dxf, gerber or kicad format ?
    Thank you



  • @theshade

    I just tried the lib with the folowing main.py and line1 seems to switch every second.
    pca9554.py micropython ported lib is not tested but apparently works enough for me.

    import time
    from PCA9554 import PCA9554
    
    line1 = PCA9554(line=1, direction=0)
    
    while True:
        line1.set()
        time.sleep(1)
        line1.reset()
        time.sleep(1)


  • This is the ported lib to use the expander IO

    ################################################################################
    # Author			: akael "ported" by theshade
    # Creation date 		: 02.02.2019
    # Langage			: microPython
    # Filename			: pca9554.py
    # Target		 		: Pycom pyscan
    # Description		: PCA9554A GPIO Expander
    ################################################################################
    
    import time
    from machine import I2C
    
    
    IN = const(1)
    OUT = const(0)
    #"""
    #Pca9554 (8 bit I2C expander)
    #"""
    class PCA9554():
        #Define register
        Pca9554_IN_REG = const(0x00) #Input register
        Pca9554_OUT_REG = const(0x01) #Output register
        Pca9554_POL_REG = const(0x02) #Polarity inversion register (1=data inverted)
        Pca9554_DIR_REG = const(0x03) #Config register (0=output, 1=input)
        Pca9554_I2CADDR = const(0x20)
        i2c_bus=-1
        i2c_address=-1
        line=0xFF
    	#def __init__(self, bus_id=0,address=0x39,line=0, direction="Null"):
        def __init__(self, line=0x00, direction=1, sda = 'P22', scl = 'P21'):
            #if pysense is not None:
            #   self.i2c = pyscan.i2c
            #else:
            self.i2c = I2C(0, mode=I2C.MASTER, pins=(sda, scl))
            #self.i2c_bus = smbus.SMBus(bus_id)
    		#Pca9554_I2CADDR=address
            print(line)
            self.line=line
            print(self.line)
            print('setting direction')
            if direction == 1:
                self.setinput()
            if direction == 0:
                self.setoutput()
    
            time.sleep(0.01)
    
    	def set_dir_reg(self, value):
    		#"""set direction register : 0=output, 1=input"""
    		self.i2c.writeto_mem(Pca9554_I2CADDR, Pca9554_DIR_REG, value)
    
            #"""set bit as output"""
        def setoutput(self):
            print('setting output to')
            currentvalue = self.i2c.readfrom_mem(Pca9554_I2CADDR , Pca9554_DIR_REG, 1)
            print(currentvalue[0] | (0x01<<self.line))
            self.i2c.writeto_mem(Pca9554_I2CADDR, Pca9554_DIR_REG , currentvalue[0] & 255-(1<<self.line))
    
            #"""set bit as input"""
        def setinput(self):
            print('setting input to')
            currentvalue = self.i2c.readfrom_mem(Pca9554_I2CADDR , Pca9554_DIR_REG, 1)
            print(currentvalue[0] | (0x01<<self.line))
            self.i2c.writeto_mem(Pca9554_I2CADDR, Pca9554_DIR_REG ,currentvalue[0] | (0x01<<self.line))
            #self.i2c.writeto_mem(Pca9554_I2CADDR, Pca9554_DIR_REG , self.line)
    
        def writebyte(self,value):
    		#"""write output byte value"""
    		self.i2c.writeto_mem(Pca9554_I2CADDR, Pca9554_OUT_REG, value)
    		return
        def readbyte(self):
    		#"""read input byte value"""
            return self.i2c.readfrom_mem(Pca9554_I2CADDR, Pca9554_IN_REG,1)
    
        def set(self):
            #"""set output bit at 1"""
            currentvalue = self.i2c.readfrom_mem(Pca9554_I2CADDR, Pca9554_OUT_REG,1)
            #self.i2c.writeto_mem(Pca9554_I2CADDR, Pca9554_OUT_REG, 1<<2)
            self.i2c.writeto_mem(Pca9554_I2CADDR, Pca9554_OUT_REG, currentvalue[0] | 1<<self.line)
    
        def reset(self):
    		#"""reset output bit at 0"""
    		currentvalue = self.i2c.readfrom_mem(Pca9554_I2CADDR, Pca9554_OUT_REG,1)
    		self.i2c.writeto_mem(Pca9554_I2CADDR, Pca9554_OUT_REG, currentvalue[0] & (255-(1<<self.line)))
    		return
        def get(self):
    		#"""read input bit value"""
    		linevalue = self.i2c.readfrom_mem(Pca9554_I2CADDR, Pca9554_IN_REG,1)
    		ret = ((linevalue >> self.line) & 1 )
    		return ret
    


  • @theshade Yeah your right. Ill look into getting it sorted!



  • @paul-thornton
    Hey Paul, You are probably right about the no upgraded firmware. But just in case someone flashes the DFU with a wrong version.. it would be cool to be able find the current and only one somewhere I guess.



  • @theshade I dont think we have ever released an upgraded firmware for the pyscan. I think the version you have installed is likely to be the latest version I will how ever confirm this with the team.



  • @paul-thornton

    Hey Paul,
    in the process of getting started with this I tried to update the firmware / dfu of my pyscan
    according to this:
    https://docs.pycom.io/pytrackpysense/installation/firmware.html
    unfortunately the link is missing and I am unable to find the dfu for the pyscan...
    not even being able to find the firmware for a released product seems odd to me... Can you help or is it somewhere hidden. I searched most if not all of the GIT and forum but can't still find it.

    Cheers



  • @paul-thornton Thank you now worries, that is all I needed to get started!!



  • Hey,

    Apologies for the slow response. the team took a look at the thread and suggested a few things:

    Datasheet for the PCA is available here: http://www.ti.com/lit/ds/symlink/pca9554.pdf

    Use I2C commands to interact with IO Expander, A2,A1,A0=Low so the address is 20 (HEX). Then the registers are described in the chapter 8.3 of the datasheet.

    An example library lives here: https://github.com/kaelmik/amp/blob/master/pca9554.py which shouldn’t be too difficult to rewrite for MicroPython

    Hopefully this is some help. Any other querys and Ill gladly take them back to the team :)



Pycom on Twitter