TCA9548 I2C Switch Driver

../_images/TCA9548.jpg

TCA9548 Breakout Board from Adafruit

class src.pico_power_management.TCA9548.TCA9548(name: str, address: int, i2c_bus, description=None, *args, **kwargs)
CHANNELS = (0, 1, 2, 3, 4, 5, 6, 7)
DEFAULT_ADDR = 112
I2C_MAX_FREQ = 400000
I2C_MIN_FREQ = 100000
NUM_CHANNELS = 8
all_channels_status()

Query the status of all channels

channel_status(channel)

Query the status of a channel.

Parameters

channel (int) – Channel number, must be within 0 and 7.

disable_all_channels()

Turn all channels off.

disable_channel(channel)

Turn the specified channel off.

Parameters

channel (int) – Channel number, must be within 0 and 7.

enable_all_channels()

Turn all channels on.

enable_channel(channel)

Turn the specified channel on.

Parameters

channel (int) – Channel number, must be within 0 and 7.

Code

  1# -----------------------------------------
  2#                 NOTES 
  3# -----------------------------------------
  4# 
  5# Dieter Steinhauser
  6# 11/2023
  7# TCA9548 I2C Driver
  8
  9# -----------------------------------------
 10#               IMPORTS
 11# -----------------------------------------
 12
 13desc = r"""
 14The TCA9548A device has eight bidirectional translating switches that can be controlled throughthe I2C bus. The SCL/SDA upstream pair fans out to
 15eight downstream pairs, or channels. Any individual SCn/SDn channel or combination of channels can be selected, determined by the contents of the
 16programmable control register. These downstream channels can be used to resolve I2C slave address conflicts. For example, if eight identical digital
 17temperature sensors are needed in the application, one sensor can be connected at each channel: 0-7.
 18
 19The TCA9548A has a standard bidirectional I2C interface that is controlled by a master device in order to beconfigured or read the status of this device. Each slave on the I2C 
 20bus has a specific device address to differentiate between other slave devices that are on the same I2C bus. Many slave devices require configuration upon startup to set the 
 21behavior of the device. This is typically done when the master accesses internal register maps of the slave, which have unique register addresses. 
 22A device can have one or multiple registers where data is stored, written, or read.
 23
 24"""
 25
 26from machine import Pin, I2C
 27from src.pico_power_management.i2c_device import Device
 28from src.pico_power_management.helpers import *
 29# from i2c_device import Device
 30# from helpers import *
 31# -----------------------------------------
 32#                Class:
 33# -----------------------------------------
 34
 35class TCA9548(Device):
 36
 37    I2C_MIN_FREQ = 100_000
 38    I2C_MAX_FREQ = 400_000
 39    DEFAULT_ADDR = 0x70 # The address is determined by the A2-A0 external pins, allowing 8 different addresses. All are grounded in our circuit.
 40    # ALT_ADDR = 0x75 # The address is determined by the A2-A0 external pins, allowing 8 different addresses.
 41    CHANNELS = tuple(range(0, 8))
 42    NUM_CHANNELS = len(CHANNELS)
 43    
 44    def __init__(self, name:str, address:int, i2c_bus, description = None, *args, **kwargs) -> None:
 45        """Object initialization for TCA9548. Follow device initialization and adds register information to object"""
 46        description = desc if desc is None else description
 47        super().__init__(name, address, i2c_bus, description, *args, **kwargs)
 48
 49        
 50    def enable_channel(self, channel):
 51        """
 52        Turn the specified channel on.
 53
 54        :param channel: Channel number, must be within 0 and 7.
 55        :type channel: int
 56        """
 57        # Throw an error for incorrect channel value
 58        check_type(channel, 'channel', int)
 59        check_range(channel, 'channel', 0, 7)
 60
 61        # perform a read modify write cycle
 62        write_data = read_modify(read_data=self.read(), modify_data= (1 << channel), bit_mask= (1 << channel))
 63
 64        # write to the device
 65        self.write(write_data)
 66
 67
 68    def disable_channel(self, channel):
 69        """
 70        Turn the specified channel off.
 71
 72        :param channel: Channel number, must be within 0 and 7.
 73        :type channel: int
 74        """
 75
 76        # Throw an error for incorrect channel value
 77        check_type(channel, 'channel', int)
 78        check_range(channel, 'channel', 0, 7)
 79
 80        # perform a read modify write cycle
 81        write_data = read_modify(read_data=self.read(), modify_data= (0 << channel), bit_mask= (1 << channel))
 82
 83        # write to the device
 84        self.write(write_data)
 85
 86
 87    def channel_status(self, channel):
 88        """
 89        Query the status of a channel.
 90
 91        :param channel: Channel number, must be within 0 and 7.
 92        :type channel: int
 93        """
 94        # Throw an error for incorrect channel value
 95        check_type(channel, 'channel', int)
 96        check_range(channel, 'channel', 0, 7)
 97
 98        # read the status of the channel
 99        status = (self.read() >> channel ) & 1
100        return status
101
102
103    def enable_all_channels(self):
104        """
105        Turn all channels on.
106        """
107        # write to the device
108        self.write(0xFF)
109
110
111    def disable_all_channels(self):
112        """
113        Turn all channels off.
114        """
115        # write to the device
116        self.write(0x00)
117
118
119    def all_channels_status(self):
120        """Query the status of all channels"""
121        return_dict = {}
122        read_data = self.read()
123        return_dict['CH7'] = (read_data >> 7) & 1
124        return_dict['CH6'] = (read_data >> 6) & 1
125        return_dict['CH5'] = (read_data >> 5) & 1
126        return_dict['CH4'] = (read_data >> 4) & 1
127        return_dict['CH3'] = (read_data >> 3) & 1
128        return_dict['CH2'] = (read_data >> 2) & 1
129        return_dict['CH1'] = (read_data >> 1) & 1
130        return_dict['CH0'] = (read_data >> 0) & 1
131        return return_dict
132
133
134if __name__ == '__main__':
135    i2c_bus =  I2C(1, sda=Pin(14), scl=Pin(15), freq=100_000)
136    tca =  TCA9548(name="TCA9548", address=0x70, i2c_bus=i2c_bus)
137    devices = tca.i2c_bus.scan()
138    hex_addr = [hex(x) for x in devices]
139    print(f"Seen device addresses: {hex_addr}")
140    
141    test = True
142    if test:
143        
144        print(f"Channels Status: {tca.all_channels_status()}")
145        tca.enable_all_channels()
146        print(f"Channels Status: {tca.all_channels_status()}")
147        tca.disable_all_channels()
148        print(f"Channels Status: {tca.all_channels_status()}")
149        
150        tca.enable_channel(0)
151        print(f"Channels Status: {tca.all_channels_status()}")
152        print(f"Channel Status: {tca.channel_status(0)}")
153        tca.disable_channel(0)
154        
155        tca.enable_channel(1)
156        print(f"Channels Status: {tca.all_channels_status()}")
157        print(f"Channel Status: {tca.channel_status(1)}")
158        tca.disable_channel(1)
159        
160        tca.enable_channel(2)
161        print(f"Channels Status: {tca.all_channels_status()}")
162        print(f"Channel Status: {tca.channel_status(2)}")
163        tca.disable_channel(2)
164        
165        
166
167        
168
169# -----------------------------------------
170#              END OF FILE
171# -----------------------------------------