Port Expander PCA9554

All ESP8266 boards running MicroPython.
Official boards are the Adafruit Huzzah and Feather boards.
Target audience: MicroPython users with an ESP8266 board.
Post Reply
uwe-48
Posts: 5
Joined: Fri Oct 23, 2020 2:17 pm

Port Expander PCA9554

Post by uwe-48 » Tue Oct 27, 2020 1:31 pm

I have a problem with the control of a PCA9554 (I2C) with Micropython (version 1.13) by a NodeMCU module (ESP8266)
Here I have changed a module (PCA9554.PY, __init__, akael "ported" by theshade, 02.09.2019) a little bit.

When starting main.py I get the following error message:
AttributeError: 'module'object has no attribute'PCA9554
I looked it up on the net, but did not find a solution.

I attach all three files if possible.
The examples from Mike Causer for the MCP23017 and PCF8574 work. I can switch one LED on or off at a time.
What have I missed or what is wrong?

Code: Select all

[/# 23.10.2020

from  machine  import  Pin , I2C 
import pca9554
import time

i2c  =  I2C ( scl = Pin ( 5 ), sda = Pin ( 4 ), freq = 100000)
pca  =  pca9554 . PCA9554 (i2c, 0x25)

pca.setoutput()
pca.writebyte(0x00)

while True:
    pca.writebyte(0x00)
    time.sleep (1)
    pca.writebyte(0xff)
    time.sleep (1)]
    
    
    
    [code][/"""
MicroPython PCA9554 8-Bit I2C I/O Expander with Interrupt
Quelle:

################################################################################
# Author			: akael "ported" by theshade
# Creation date 		: 02.02.2019
# Langage			: microPython
# Filename			: pca9554.py
# Target		 		: Pycom pyscan
# Description		: PCA9554A GPIO Expander
################################################################################
23.10.2020
Anpassung an PCA9554 (Init)
"""
import time
from maschine import I2C

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(0x25)
    
    
    def __init__(self, i2c, address=0x25):
        self._i2c = i2c
        self._address = address
        self._port = bytearray(1)
        if i2c.scan().count(address) == 0:
            raise OSError('PCA9554 not found at I2C address {:#x}'.format(address))
   
  
        #"""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  ]

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: Port Expander PCA9554

Post by jimmo » Wed Oct 28, 2020 12:52 am

It sounds like either the pca9554.py file isn't properly copied to the device, or can't be imported correctly.

How are you copying the files to the device?

uwe-48
Posts: 5
Joined: Fri Oct 23, 2020 2:17 pm

Re: Port Expander PCA9554

Post by uwe-48 » Wed Oct 28, 2020 1:05 pm

jimmo wrote:
Wed Oct 28, 2020 12:52 am
It sounds like either the pca9554.py file isn't properly copied to the device, or can't be imported correctly.

How are you copying the files to the device?
I use the IDE uPyCraft V1.1 and copied three files (boot.py, main.py, pca9554.py)
via download into the device. I can also read these files back from the device.
So the required file should be available.

rpr
Posts: 99
Joined: Sat Oct 27, 2018 5:17 pm

Re: Port Expander PCA9554

Post by rpr » Wed Oct 28, 2020 5:50 pm

In your file pca9554.py I see the following typo:

Code: Select all

from maschine import I2C
Not sure if that is causing the issues.

uwe-48
Posts: 5
Joined: Fri Oct 23, 2020 2:17 pm

Re: Port Expander PCA9554

Post by uwe-48 » Thu Oct 29, 2020 12:00 pm

Thanks for the hint, unfortunately it does not solve the problem.
With the simple I2C commands I can change the state of the outputs,
but not with this variant. I will test another hardware variant.

uwe-48
Posts: 5
Joined: Fri Oct 23, 2020 2:17 pm

Re: Port Expander PCA9554

Post by uwe-48 » Sat Oct 31, 2020 12:25 pm

Hello,
I have now built and tested my circuit with a D1 mini (ESP8266EX) and a MCP23017 and a PCA9554. The software works for the MCP23017, but the PCA9554 seems to only run the i2c.scan(). The SDA and SCL signals can be displayed using a logic analyser (salae clone). In the module "pca9554.py) there is still the expression "self.line" from the old source. Does anything need to be changed here, are there any suggestions?

Thanks

uwe-48
Posts: 5
Joined: Fri Oct 23, 2020 2:17 pm

Re: Port Expander PCA9554

Post by uwe-48 » Thu Nov 05, 2020 4:29 pm

Hello, I have changed my test programme, but unfortunately it still does not work.
I don't get an error message on startup anymore, a "T" is now displayed in the output
window on startup, the program still outputs "stat1" and then nothing happens.
Does anyone have an idea? Translate with DeepL

Code: Select all

[/"""
MicroPython PCA9554 8-Bit I2C I/O Expander with Interrupt


Quelle:

################################################################################
# Author			: akael "ported" by theshade
# Creation date 		: 02.02.2019
# Langage			: microPython
# Filename			: pca9554.py
# Target		 		: Pycom pyscan
# Description		: PCA9554A GPIO Expander
################################################################################


23.10.2020
Anpassung an PCA9554 (Init)
"""
#import time
#from machine import I2C



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(0x21)
    
    
    def __init__(self, i2c, address=0x21):
        self._i2c = i2c
        self._address = address
        self._port = bytearray(1)
        if i2c.scan().count(address) == 0:
            raise OSError('PCA9554 not found at I2C address {:#x}'.format(address))
   
  
        #"""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._port))
        self.i2c.writeto_mem(Pca9554_I2CADDR, Pca9554_DIR_REG , currentvalue[0] & 255-(1<<self._port))

        #"""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._port))
        self.i2c.writeto_mem(Pca9554_I2CADDR, Pca9554_DIR_REG ,currentvalue[0] | (0x01<<self._port))
        #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.port)

    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._port)))
		    return
        
    def get(self):
        #"""read input bit value"""
		    linevalue = self.i2c.readfrom_mem(Pca9554_I2CADDR, Pca9554_IN_REG,1)
		    ret = ((linevalue >> self._port) & 1 )
		    return ret]
		    
		    [
# 05.11.2020


from  machine  import  Pin , I2C 
import pca9554
import time


i2c  =  I2C ( scl = Pin ( 5 ), sda = Pin ( 4 ), freq = 100000)
pca  =  pca9554.PCA9554 (i2c, 0x21)

print('stat0')

time.sleep (1)
pca.setoutput(0)

print('stat1')

while True:
  pca.writebyte(0x00)
  print('stat2')
  #pca.set()
  time.sleep (1)
  pca.writebyte(0xff)
  print('stat3')
  #pca.reset()
  time.sleep (1)]

Post Reply