stusb4500

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 23, 2020 License: MIT Imports: 10 Imported by: 0

README

tinygo-stusb4500

TinyGo driver for real-time capabilities of the STUSB4500 USB PD sink controller with I²C
Rewrite of Arduino driver STUSB4500

Features

  • Re-written entirely in pure Go
    • Improved stability and compatibility over Arduino predecessor STUSB4500
  • Tested on TinyGo 1.14, 1.15, 1.16
  • Compatible with all I²C-capable devices supported by TinyGo
  • USB Power Delivery v2.0 and v3.0 compatible state machine
  • Designed for STUSB4500 Compact Breakout
  • Detect cable orientation (CC1/CC2 termination)
  • Completely enable/disable power output
  • Provides user callback support for:
    Callback Description
    OnInitFail I²C initialization failure
    OnResetFail I²C reconnection to STUSB4500 failed
    OnConnect I²C connection to STUSB4500 succeeded
    OnConnectFail I²C connection to STUSB4500 failed
    OnError I²C or STUSB4500 runtime error
    OnCableAttach USB Type-C cable connected
    OnCableDetach USB Type-C cable disconnected
    OnCapabilities USB PD capabilities received from source
  • Can analyze and identify all available power profiles
  • Can request and use any arbitrary power profile +5-20V/0-5A in 50mV/10mA increments
    • Does not lose VBUS on power transition, maintains power output
  • Set up to 3 custom power profiles for fallback
  • Reformat NVM for default power profiles in standalone mode (not yet implemented)

Installation

  1. Install TinyGo, of course.
  2. Fetch the TinyGo drivers:
    • go get tinygo.org/x/drivers
  3. If this driver has been merged into that repository, you are done with installation.
  4. Navigate into new drivers installation directory:
    • cd $( go env GOPATH )/src/tinygo.org/x/drivers
  5. Fetch this driver, naming it stusb4500:
    • git clone https://github.com/ardnew/tinygo-stusb4500.git stusb4500

Usage

An example program is provided at examples/main.go, which performs the following described in its header comments:


// This example demonstrates how to use the STUSB4500 driver to monitor cable
// attach/detach, read the USB PD source capabilities, and negotiate different
// power profiles.
//
// An external button is used to cycle through each of the power profiles
// discovered.
//
// An LED is used to indicate USB PD negotiation activity.
//
// Note that your STUSB4500 should be powered via VBUS, which is connected to
// the USB Type-C cable itself, and NOT via VSYS/VCC (which should be connected
// to ground).
Wiring
  • TBD
Troubleshooting (from previous Arduino project)

The PD protocol has very rigid timing requirements. These can be difficult to accommodate even in normal circumstances, but is even more difficult since there is another device (our STUSB4500) mediating communication over an I²C bus, which is rather slow. This is partly why the interrupts are vital to successful operation.

Point being, it may be difficult to achieve reliable results on some systems (such as AVR-based devices like Arduino Uno), and you may need to experiment with different microcontrollers.

If you have issues receiving cable attach/detach or PD capability discovery events, ensure the following:

  • You are using a hardware I²C port on the microcontroller
  • The I²C (SDA/SCL) and interrupt (ALRT/ATCH) wires connecting microcontroller and STUSB4500 are as short as possible
  • GND on STUSB4500 is connected to GND on microcontroller
  • VDD (VPP on oxplot breakout) is pulled up to 3.3V (or to same level as I2C bus voltage)
  • VSYS (VCC on oxplot breakout) is pulled down to ground (use microcontroller ground pin)
    • The Sparkfun breakout pulls this high to VDD (according to their schematic), but the datasheet says to connect it to ground if it is not used (and it isn't used, because the device is powered by VBUS from the USB-C receptacle). So I'm not sure about this one. Try pulling this in the opposite direction if you're having issues.

Documentation

Overview

Package stusb4500 provides a driver for the STUSB4500 USB PD sink controller by STMicroelectronics.

Datasheet: https://www.st.com/resource/en/datasheet/stusb4500.pdf

Index

Constants

View Source
const (
	REG_BCD_TYPEC_REV_LOW         = 0x06 // BCD_TYPEC_REV_LOW register
	REG_BCD_TYPEC_REV_HIGH        = 0x07 // BCD_TYPEC_REV_HIGH register
	REG_BCD_USBPD_REV_LOW         = 0x08 // BCD_USBPD_REV_LOW register
	REG_BCD_USBPD_REV_HIGH        = 0x09 // BCD_USBPD_REV_HIGH register
	REG_DEVICE_CAPAB_HIGH         = 0x0A // DEVICE_CAPAB_HIGH register
	REG_ALERT_STATUS_1            = 0x0B // ALERT_STATUS_1 register
	REG_ALERT_STATUS_1_MASK       = 0x0C // ALERT_STATUS_1_MASK register
	REG_PORT_STATUS_0             = 0x0D // PORT_STATUS_0 register
	REG_PORT_STATUS_1             = 0x0E // PORT_STATUS_1 register
	REG_TYPEC_MONITORING_STATUS_0 = 0x0F // TYPEC_MONITORING_STATUS_0 register
	REG_TYPEC_MONITORING_STATUS_1 = 0x10 // TYPEC_MONITORING_STATUS_1 register
	REG_CC_STATUS                 = 0x11 // CC_STATUS register
	REG_CC_HW_FAULT_STATUS_0      = 0x12 // CC_HW_FAULT_STATUS_0 register
	REG_CC_HW_FAULT_STATUS_1      = 0x13 // CC_HW_FAULT_STATUS_1 register
	REG_PD_TYPEC_STATUS           = 0x14 // PD_TYPEC_STATUS register
	REG_TYPEC_STATUS              = 0x15 // TYPEC_STATUS register
	REG_PRT_STATUS                = 0x16 // PRT_STATUS register
	REG_PHY_STATUS                = 0x17 // PHY_STATUS register
	REG_CC_CAPABILITY_CTRL        = 0x18 // CC_CAPABILITY_CTRL register
	REG_PRT_TX_CTRL               = 0x19 // PRT_TX_CTRL register
	REG_PD_COMMAND_CTRL           = 0x1A // PD_COMMAND_CTRL register
	REG_MONITORING_CTRL_0         = 0x20 // MONITORING_CTRL_0 register
	REG_MONITORING_CTRL_2         = 0x22 // MONITORING_CTRL_2 register
	REG_RESET_CTRL                = 0x23 // RESET_CTRL register
	REG_VBUS_DISCHARGE_TIME_CTRL  = 0x25 // VBUS_DISCHARGE_TIME_CTRL register
	REG_VBUS_DISCHARGE_CTRL       = 0x26 // VBUS_DISCHARGE_CTRL register
	REG_VBUS_CTRL                 = 0x27 // VBUS_CTRL register
	REG_PE_FSM                    = 0x29 // PE_FSM register
	REG_GPIO_SW_GPIO              = 0x2D // GPIO_SW_GPIO register
	REG_DEVICE_ID                 = 0x2F // DEVICE_ID register
	REG_RX_BYTE_CNT               = 0x30 // RX_BYTE_CNT register
	REG_RX_HEADER_LOW             = 0x31 // RX_HEADER_LOW register
	REG_RX_HEADER_HIGH            = 0x32 // RX_HEADER_HIGH register
	REG_RX_DATA_OBJ1_0            = 0x33 // RX_DATA_OBJ1_0 register
	REG_RX_DATA_OBJ1_1            = 0x34 // RX_DATA_OBJ1_1 register
	REG_RX_DATA_OBJ1_2            = 0x35 // RX_DATA_OBJ1_2 register
	REG_RX_DATA_OBJ1_3            = 0x36 // RX_DATA_OBJ1_3 register
	REG_RX_DATA_OBJ2_0            = 0x37 // RX_DATA_OBJ2_0 register
	REG_RX_DATA_OBJ2_1            = 0x38 // RX_DATA_OBJ2_1 register
	REG_RX_DATA_OBJ2_2            = 0x39 // RX_DATA_OBJ2_2 register
	REG_RX_DATA_OBJ2_3            = 0x3A // RX_DATA_OBJ2_3 register
	REG_RX_DATA_OBJ3_0            = 0x3B // RX_DATA_OBJ3_0 register
	REG_RX_DATA_OBJ3_1            = 0x3C // RX_DATA_OBJ3_1 register
	REG_RX_DATA_OBJ3_2            = 0x3D // RX_DATA_OBJ3_2 register
	REG_RX_DATA_OBJ3_3            = 0x3E // RX_DATA_OBJ3_3 register
	REG_RX_DATA_OBJ4_0            = 0x3F // RX_DATA_OBJ4_0 register
	REG_RX_DATA_OBJ4_1            = 0x40 // RX_DATA_OBJ4_1 register
	REG_RX_DATA_OBJ4_2            = 0x41 // RX_DATA_OBJ4_2 register
	REG_RX_DATA_OBJ4_3            = 0x42 // RX_DATA_OBJ4_3 register
	REG_RX_DATA_OBJ5_0            = 0x43 // RX_DATA_OBJ5_0 register
	REG_RX_DATA_OBJ5_1            = 0x44 // RX_DATA_OBJ5_1 register
	REG_RX_DATA_OBJ5_2            = 0x45 // RX_DATA_OBJ5_2 register
	REG_RX_DATA_OBJ5_3            = 0x46 // RX_DATA_OBJ5_3 register
	REG_RX_DATA_OBJ6_0            = 0x47 // RX_DATA_OBJ6_0 register
	REG_RX_DATA_OBJ6_1            = 0x48 // RX_DATA_OBJ6_1 register
	REG_RX_DATA_OBJ6_2            = 0x49 // RX_DATA_OBJ6_2 register
	REG_RX_DATA_OBJ6_3            = 0x4A // RX_DATA_OBJ6_3 register
	REG_RX_DATA_OBJ7_0            = 0x4B // RX_DATA_OBJ7_0 register
	REG_RX_DATA_OBJ7_1            = 0x4C // RX_DATA_OBJ7_1 register
	REG_RX_DATA_OBJ7_2            = 0x4D // RX_DATA_OBJ7_2 register
	REG_RX_DATA_OBJ7_3            = 0x4E // RX_DATA_OBJ7_3 register
	REG_TX_HEADER_LOW             = 0x51 // TX_HEADER_LOW register
	REG_TX_HEADER_HIGH            = 0x52 // TX_HEADER_HIGH register
	REG_DPM_PDO_NUMB              = 0x70 // DPM_PDO_NUMB register
	REG_DPM_SNK_PDO1_0            = 0x85 // DPM_SNK_PDO1_0 register
	REG_DPM_SNK_PDO1_1            = 0x86 // DPM_SNK_PDO1_1 register
	REG_DPM_SNK_PDO1_2            = 0x87 // DPM_SNK_PDO1_2 register
	REG_DPM_SNK_PDO1_3            = 0x88 // DPM_SNK_PDO1_3 register
	REG_DPM_SNK_PDO2_0            = 0x89 // DPM_SNK_PDO2_0 register
	REG_DPM_SNK_PDO2_1            = 0x8A // DPM_SNK_PDO2_1 register
	REG_DPM_SNK_PDO2_2            = 0x8B // DPM_SNK_PDO2_2 register
	REG_DPM_SNK_PDO2_3            = 0x8C // DPM_SNK_PDO2_3 register
	REG_DPM_SNK_PDO3_0            = 0x8D // DPM_SNK_PDO3_0 register
	REG_DPM_SNK_PDO3_1            = 0x8E // DPM_SNK_PDO3_1 register
	REG_DPM_SNK_PDO3_2            = 0x8F // DPM_SNK_PDO3_2 register
	REG_DPM_SNK_PDO3_3            = 0x90 // DPM_SNK_PDO3_3 register
	REG_RDO_REG_STATUS_0          = 0x91 // RDO_REG_STATUS_0 register
	REG_RDO_REG_STATUS_1          = 0x92 // RDO_REG_STATUS_1 register
	REG_RDO_REG_STATUS_2          = 0x93 // RDO_REG_STATUS_2 register
	REG_RDO_REG_STATUS_3          = 0x94 // RDO_REG_STATUS_3 register
)

Constants defining the important register addresses of the STUSB4500

Variables

View Source
var (
	ErrDeviceNotConfigured = errors.New("stusb4500: device not configured")
	ErrDeviceNotFound      = errors.New("stusb4500: device not found")
	ErrInvalidNumPDO       = errors.New("stusb4500: invalid number of PDO")
	ErrUndefinedRDO        = errors.New("stusb4500: undefined RDO")
	ErrCableDisconnected   = errors.New("stusb4500: cable is disconnected")
	ErrByteCountPDHeader   = errors.New("stusb4500: invalid byte count in USB PD message header")
	ErrSourcePDOTimeout    = errors.New("stusb4500: timeout requesting source capabilities")
	ErrMonitorStarted      = errors.New("stusb4500: monitor already started")
	ErrMonitorNotStarted   = errors.New("stusb4500: monitor not yet started")
	ErrMonitorResetUndef   = errors.New("stusb4500: reset pin not defined for monitor")
	ErrMonitorAlertUndef   = errors.New("stusb4500: alert pin not defined for monitor")
	ErrMonitorAttachUndef  = errors.New("stusb4500: attach pin not defined for monitor")
)
View Source
var Address uint8 = 0x28

Address is the default I2C peripheral address of the STUSB4500 used when creating a new connection. Use the GetAddress method to get the peripheral address of a connected Device.

Functions

This section is empty.

Types

type CableStatus

type CableStatus uint8

CableStatus represents the connection status of a USB Type-C cable.

const (
	Disconnected CableStatus = 0 // no cable attached to the USB Type-C port
	ConnectedCC1 CableStatus = 1 // cable attached (normal/unflipped orientation)
	ConnectedCC2 CableStatus = 2 // cable attached (twisted/flipped orientation)
	CableInvalid CableStatus = 0xFF
)

type Device

type Device struct {

	// most recent PDOs advertised from source.
	SnkRDO PDO
	SnkPDO []PDO
	SrcPDO []PDO
	// contains filtered or unexported fields
}

Device wraps the I2C connection to an STUSB4500 device.

func New

func New(bus drivers.I2C) *Device

New creates a new STUSB4500 connection. The given I2C interface must already be configured.

func (*Device) Configure

func (d *Device) Configure(config conf.Configuration) *Device

Configure modifies the device configuration settings and must be called after a Device is created via New.

Note that the given pins must already be configured as follows:

config.ResetPin  - GPIO output
config.AlertPin  - GPIO input pullup (must be external interrupt capable)
config.AttachPin - GPIO input pullup (must be external interrupt capable)

func (*Device) Connected

func (d *Device) Connected() bool

Connected returns true if and only if we are connected to an STUSB4500. A valid connection is determined by reading the device ID register over I2C.

func (*Device) GetAddress

func (d *Device) GetAddress() uint8

GetAddress returns the I2C peripheral address of a connected Device.

func (*Device) GetCableStatus

func (d *Device) GetCableStatus() (bool, CableStatus)

GetCableStatus returns whether a USB cable is connected and the orientation of its plug to the STUSB4500 Type-C port.

func (*Device) Initialize

func (d *Device) Initialize() error

Initialize clears and unmasks all needed interrupts, and initializes device registers and USB PD state machine. A non-nil error is returned if communication with device was unsuccessful, or the device was unable to negotiate with a USB PD-capable supply.

func (*Device) Monitor

func (d *Device) Monitor() error

Monitor provides an event loop for maintaining connection to the STUSB4500, and calling user callback functions for important state changes.

Since the STUSB4500 may occassionally lose power (such as when a USB Type-C cable or PD supply source is disconnected), this will safely re-establish a connection and re-initialize the device on subsequent cable attachments.

Note this method will not normally return to the caller. Therefore, this method is designed to be run in a goroutine, and it will periodically yield to any other goroutines needing processor time (via `runtime.Gosched()`).

Call this Device receiver's `StopMonitor` method to terminate this monitor and stop processing all USB PD events.

This routine is implemented entirely with public exported methods from package `stusb4500`. Meaning, the user may view this method as a convenience function, or as a template for manually managing USB PD connections from their own driver package.

func (*Device) Reset

func (d *Device) Reset(wait bool) error

Reset performs a hard reset of the STUSB4500 by asserting and de-asserting the active-high RST pin for a short duration.

All registers and power contracts are reset to their default power-on state.

If the given bool argument wait is true, Reset will not return until the STUSB4500 is identified and communicating over I2C.

func (*Device) SetPower

func (d *Device) SetPower(voltage uint32, current uint32) error

SetPower attempts to negotiate an explicit power contract with given voltage and current from the PD source.

The given voltage, in millivolts (mV), must be a multiple of 50 mV. The given current, in milliamps (mA), must be a multiple of 10 mA.

func (*Device) SetPowerUSBDefault

func (d *Device) SetPowerUSBDefault() error

SetPowerUSBDefault selects the default +5V (0.5-3.0A) USB power profile. This is the fallback power profile used when USB PD negotiation fails and is the same power profile used by all USB 2.0 devices.

func (*Device) SoftReset

func (d *Device) SoftReset(wait bool) error

SoftReset performs a soft reset of the STUSB4500 by setting and then clearing the REG_RESET_CTRL (0x23) register.

This resets the internal registers and USB PD state machine, and it causes electrical disconnect on both source and sink sides. While reset, all pending interrupts and internal alerts are cleared.

If the given bool argument wait is true, SoftReset will not return until the STUSB4500 is identified and communicating over I2C.

func (*Device) StopMonitor

func (d *Device) StopMonitor() error

StopMonitor signals the monitor event loop to terminate and stop all USB PD processing and message handling.

func (*Device) Update

func (d *Device) Update() error

Update processes interrupts and internal alerts, and progresses the PD state machine by one cycle. The user application must call Update continuously for successful operation of the STUSB4500.

type PDO

type PDO struct {
	Number     int
	Voltage    uint32
	Current    uint32
	MaxCurrent uint32
}

func (PDO) Equals

func (p PDO) Equals(o PDO) bool

func (PDO) IsValid

func (p PDO) IsValid() bool

func (PDO) String

func (p PDO) String() string

Directories

Path Synopsis
Package conf provides the interface used to modify STUSB4500 configuration.
Package conf provides the interface used to modify STUSB4500 configuration.
This example demonstrates how to use the STUSB4500 driver to monitor cable attach/detach, read the USB PD source capabilities, and negotiate different power profiles.
This example demonstrates how to use the STUSB4500 driver to monitor cable attach/detach, read the USB PD source capabilities, and negotiate different power profiles.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL