Skip to content

PCA9685 I2C PWM Driver #35

@Mikefly123

Description

@Mikefly123

What Does This Component Do?

The PCA9685 is used to toggle power to the sensors on each face of the satellite. This gives us the ability to power cycle them (in case of needing to clear a latch or something) and also save power by powering down these faces when they are not in use.

  • Detect the I2C Device on the Bus
  • Set the duty cycle of each face to either maximum (4096) or off (0)
  • Log the on / off status of each Face power rail
  • Command SLEEP and WAKE

Like with the other power related stuff we mainly just want this component to interface with the sensor and toggle lines on and off. Logic for actually controlling when that happens will come in the form of a Power Manger Component.

Design Notes

Adafruit C++ Library
Adafruit Library Reference

Because of some rather annoying design decisions when moving from the PROVES Kit V1 to V1.5 the sensor data for the satellite faces is piped to the FC Board while the power control was handed over to the Battery Board. Also, the PCA is on an entirely separate board! And it turns out that it is rather power inefficient for a load switching application. So overall, quite a rough state of affairs.

In V2 of the PROVES Kit we'll probably either replace this with a GPIO expander or use it only to drive a bank of load switches rather than directly supplying power to the faces through it.

Example CircuitPython Implementation

import adafruit_pca9685  # LED Driver
...
class Satellite:
...
    # Turns all of the Faces On (Defined before init because this fuction is called by the init)
    def all_faces_on(self):
        # Faces MUST init in this order or the uController will brown out. Cause unknown
        if self.hardware["FLD"]:
            self.Face0.duty_cycle = 0xFFFF
            self.hardware["Face0"] = True
            self.Face1.duty_cycle = 0xFFFF
            self.hardware["Face1"] = True
            self.Face2.duty_cycle = 0xFFFF
            self.hardware["Face2"] = True
            self.Face3.duty_cycle = 0xFFFF
            self.hardware["Face3"] = True
            self.Face4.duty_cycle = 0xFFFF
            self.hardware["Face4"] = True
            self.cam.duty_cycle = 0xFFFF

    def all_faces_off(self):
        # De-Power Faces
        if self.hardware["FLD"]:
            self.Face0.duty_cycle = 0x0000
            time.sleep(0.1)
            self.hardware["Face0"] = False
            self.Face1.duty_cycle = 0x0000
            time.sleep(0.1)
            self.hardware["Face1"] = False
            self.Face2.duty_cycle = 0x0000
            time.sleep(0.1)
            self.hardware["Face2"] = False
            self.Face3.duty_cycle = 0x0000
            time.sleep(0.1)
            self.hardware["Face3"] = False
            self.Face4.duty_cycle = 0x0000
            time.sleep(0.1)
            self.hardware["Face4"] = False
            time.sleep(0.1)
            self.cam.duty_cycle = 0x0000
...
    def __init__(self):
        # Initialize LED Driver
        try:
            self.faces = adafruit_pca9685.PCA9685(self.i2c0, address=int(0x56))
            self.faces.frequency = 2000
            self.hardware["FLD"] = True
        except Exception as e:
            self.debug_print(
                "[ERROR][LED Driver]" + "".join(traceback.format_exception(e))
            )

        # Initialize all of the Faces and their sensors
        try:
            self.Face0 = self.faces.channels[0]
            self.Face1 = self.faces.channels[1]
            self.Face2 = self.faces.channels[2]
            self.Face3 = self.faces.channels[3]
            self.Face4 = self.faces.channels[4]
            self.cam = self.faces.channels[5]
            self.all_faces_on()
        except Exception as e:
            self.debug_print(
                "ERROR INITIALIZING FACES: " + "".join(traceback.format_exception(e))
            )
...
    # =======================================================#
    # Getting and Setting Power for Individual Faces        #
    # =======================================================#
    @property
    def Face0_state(self):
        return self.hardware["Face0"]

    @Face0_state.setter
    def Face0_state(self, value):
        if self.hardware["FLD"]:
            if value:
                try:
                    self.Face0 = 0xFFFF
                    self.hardware["Face0"] = True
                    self.debug_print("z Face Powered On")
                except Exception as e:
                    self.debug_print(
                        "[WARNING][Face0]" + "".join(traceback.format_exception(e))
                    )
                    self.hardware["Face0"] = False
            else:
                self.Face0 = 0x0000
                self.hardware["Face0"] = False
                self.debug_print("z+ Face Powered Off")
        else:
            self.debug_print("[WARNING] LED Driver not initialized")
...

Required Hardware

  • Battery Board V3 or higher
  • Mux Driver Board V1 (if using a Battery Board V3a or higher)
  • Z- Solar Panel Board (for interfacing with the Mux Driver Board V1)

Reference Schematic

Screenshot 2024-10-22 at 6 36 07 PM

Metadata

Metadata

Assignees

No one assigned

    Labels

    new componentCreating a new component for this tasksensorRelating to a sensor implementation

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions