From 51c3aa271b588d6925637fe3b44a1dfbe58c4ba8 Mon Sep 17 00:00:00 2001 From: sago35 Date: Tue, 16 Nov 2021 21:19:46 +0900 Subject: [PATCH] axp192: add support for AXP192 single Cell Li-Battery and power system management IC --- Makefile | 4 +- README.md | 3 +- axp192/axp192.go | 258 +++++++++++++++++++ axp192/m5stack-core2-axp192/axp192.go | 158 ++++++++++++ axp192/registers.go | 127 +++++++++ examples/axp192/m5stack-core2-blinky/main.go | 25 ++ 6 files changed, 573 insertions(+), 2 deletions(-) create mode 100644 axp192/axp192.go create mode 100644 axp192/m5stack-core2-axp192/axp192.go create mode 100644 axp192/registers.go create mode 100644 examples/axp192/m5stack-core2-blinky/main.go diff --git a/Makefile b/Makefile index f9099ee..9cb2dec 100644 --- a/Makefile +++ b/Makefile @@ -213,12 +213,14 @@ endif @md5sum ./build/test.hex tinygo build -size short -o ./build/test.hex -target=feather-m4 ./examples/i2csoft/adt7410/ @md5sum ./build/test.hex + tinygo build -size short -o ./build/test.elf -target=wioterminal ./examples/axp192/m5stack-core2-blinky/ + @md5sum ./build/test.hex DRIVERS = $(wildcard */) NOTESTS = build examples flash semihosting pcd8544 shiftregister st7789 microphone mcp3008 gps microbitmatrix \ hcsr04 ssd1331 ws2812 thermistor apa102 easystepper ssd1351 ili9341 wifinina shifter hub75 \ hd44780 buzzer ssd1306 espat l9110x st7735 bmi160 l293x dht keypad4x4 max72xx p1am tone tm1637 \ - pcf8563 mcp2515 servo sdcard rtl8720dn image cmd i2csoft hts221 lps22hb apds9960 + pcf8563 mcp2515 servo sdcard rtl8720dn image cmd i2csoft hts221 lps22hb apds9960 axp192 TESTS = $(filter-out $(addsuffix /%,$(NOTESTS)),$(DRIVERS)) unit-test: diff --git a/README.md b/README.md index ae041ee..fcb490c 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ func main() { ## Currently supported devices -The following 72 devices are supported. +The following 73 devices are supported. | Device Name | Interface Type | |----------|-------------| @@ -63,6 +63,7 @@ The following 72 devices are supported. | [APA102 RGB LED](https://cdn-shop.adafruit.com/product-files/2343/APA102C.pdf) | SPI | | [APDS9960 Digital proximity, ambient light, RGB and gesture sensor](https://cdn.sparkfun.com/assets/learn_tutorials/3/2/1/Avago-APDS-9960-datasheet.pdf) | I2C | | [AT24CX 2-wire serial EEPROM](https://www.openimpulse.com/blog/wp-content/uploads/wpsc/downloadables/24C32-Datasheet.pdf) | I2C | +| [AXP192 single Cell Li-Battery and Power System Management](https://github.com/m5stack/M5-Schematic/blob/master/Core/AXP192%20Datasheet_v1.1_en_draft_2211.pdf) | I2C | | [BBC micro:bit LED matrix](https://github.com/bbcmicrobit/hardware/blob/master/SCH_BBC-Microbit_V1.3B.pdf) | GPIO | | [BH1750 ambient light sensor](https://www.mouser.com/ds/2/348/bh1750fvi-e-186247.pdf) | I2C | | [BlinkM RGB LED](http://thingm.com/fileadmin/thingm/downloads/BlinkM_datasheet.pdf) | I2C | diff --git a/axp192/axp192.go b/axp192/axp192.go new file mode 100644 index 0000000..a9f3d75 --- /dev/null +++ b/axp192/axp192.go @@ -0,0 +1,258 @@ +// Package axp192 provides a driver for the axp192 I2C Enhanced single Cell +// Li-Battery and Power System Management IC. +// +// http://www.x-powers.com/en.php/Info/product_detail/article_id/29 +// Datasheet: https://github.com/m5stack/M5-Schematic/blob/master/Core/AXP192%20Datasheet_v1.1_en_draft_2211.pdf +// +package axp192 // import "tinygo.org/x/drivers/axp192" + +import ( + "tinygo.org/x/drivers" +) + +type Error uint8 + +const ( + ErrInvalidID Error = 0x1 +) + +func (e Error) Error() string { + switch e { + case ErrInvalidID: + return "Invalid chip ID" + default: + return "Unknown error" + } +} + +type Device struct { + bus drivers.I2C + buf []byte + Address uint8 +} + +// New returns AXP192 device for the provided I2C bus using default address. +func New(i2c drivers.I2C) *Device { + return &Device{ + bus: i2c, + buf: make([]byte, 2), + Address: Address, + } +} + +type Config struct { +} + +// Configure the AXP192 device. +func (d *Device) Configure(config Config) error { + return nil +} + +// ReadPowerSupplyStatus reads power supply status. +func (d *Device) ReadPowerSupplyStatus() uint8 { + return d.read8bit(RegPowerSupplyStatus) +} + +// SetVbusIPSOutAccessManagement sets VBUS-IPSOUT access management. +func (d *Device) SetVbusIPSOutAccessManagement(a uint8) { + d.write1Byte(RegVbusIPSOutAccessManagement, a) +} + +// GetVbusIPSOutAccessManagement gets VBUS-IPSOUT access management. +func (d *Device) GetVbusIPSOutAccessManagement() uint8 { + return d.read8bit(RegVbusIPSOutAccessManagement) +} + +// SetGPIO1Control sets GPIO1 function. +func (d *Device) SetGPIO1Control(a uint8) { + d.write1Byte(RegGPIO1Control, a) +} + +// GetGPIO1Control gets GPIO1 function. +func (d *Device) GetGPIO1Control() uint8 { + return d.read8bit(RegGPIO1Control) +} + +// SetGPIO2Control sets GPIO2 function. +func (d *Device) SetGPIO2Control(a uint8) { + d.write1Byte(RegGPIO2Control, a) +} + +// GetGPIO2Control gets GPIO2 function. +func (d *Device) GetGPIO2Control() uint8 { + return d.read8bit(RegGPIO2Control) +} + +// SetGPIO20SignalStatus sets GPIO[2:0] signal status. +func (d *Device) SetGPIO20SignalStatus(a uint8) { + d.write1Byte(RegGPIO20SignalStatus, a) +} + +// GetGPIO20SignalStatus gets GPIO[2:0] signal status. +func (d *Device) GetGPIO20SignalStatus() uint8 { + return d.read8bit(RegGPIO20SignalStatus) +} + +// SetBackupBatteryChargingControl sets backup battery charge control. +func (d *Device) SetBackupBatteryChargingControl(a uint8) { + d.write1Byte(RegBackupBatteryChargingControl, a) +} + +// GetBackupBatteryChargingControl gets backup battery charge control. +func (d *Device) GetBackupBatteryChargingControl() uint8 { + return d.read8bit(RegBackupBatteryChargingControl) +} + +// SetDCDC1VoltageSet sets DC-DC1 output voltage. +func (d *Device) SetDCDC1VoltageSet(a uint8) { + d.write1Byte(RegDCDC1VoltageSet, a) +} + +// GetDCDC1VoltageSet gets DC-DC1 output voltage. +func (d *Device) GetDCDC1VoltageSet() uint8 { + return d.read8bit(RegDCDC1VoltageSet) +} + +// SetDCDC2VoltageSet sets DC-DC2 dynamic voltage parameter. +func (d *Device) SetDCDC2VoltageSet(a uint8) { + d.write1Byte(RegDCDC2VoltageSet, a) +} + +// GetDCDC2VoltageSet gets DC-DC2 dynamic voltage parameter. +func (d *Device) GetDCDC2VoltageSet() uint8 { + return d.read8bit(RegDCDC2VoltageSet) +} + +// SetDCDC3VoltageSet sets DC-DC3 output voltage. +func (d *Device) SetDCDC3VoltageSet(a uint8) { + d.write1Byte(RegDCDC3VoltageSet, a) +} + +// GetDCDC3VoltageSet gets DC-DC3 output voltage. +func (d *Device) GetDCDC3VoltageSet() uint8 { + return d.read8bit(RegDCDC3VoltageSet) +} + +// SetLDO23VoltageSet sets LDO2/3 output voltage. +func (d *Device) SetLDO23VoltageSet(a uint8) { + d.write1Byte(RegLDO23VoltageSet, a) +} + +// GetLDO23VoltageSet gets LDO2/3 output voltage. +func (d *Device) GetLDO23VoltageSet() uint8 { + return d.read8bit(RegLDO23VoltageSet) +} + +// SetDCDC13LDO23Switch sets DC-DC1/3 & LOD2/3 output control. +func (d *Device) SetDCDC13LDO23Switch(a uint8) { + d.write1Byte(RegDCDC13LDO23Switch, a) +} + +// GetDCDC13LDO23Switch gets DC-DC1/3 & LOD2/3 output control. +func (d *Device) GetDCDC13LDO23Switch() uint8 { + return d.read8bit(RegDCDC13LDO23Switch) +} + +// SetGPIO43FunctionControl sets GPIO[4:3] pin function. +func (d *Device) SetGPIO43FunctionControl(a uint8) { + d.write1Byte(RegGPIO43FunctionControl, a) +} + +// GetGPIO43FunctionControl gets GPIO[4:3] pin function. +func (d *Device) GetGPIO43FunctionControl() uint8 { + return d.read8bit(RegGPIO43FunctionControl) +} + +// SetPEKParameterSet sets PEK press key parameter. +func (d *Device) SetPEKParameterSet(a uint8) { + d.write1Byte(RegPEKParameterSet, a) +} + +// GetPEKParameterSet gets PEK press key parameter. +func (d *Device) GetPEKParameterSet() uint8 { + return d.read8bit(RegPEKParameterSet) +} + +// SetADCEnableSet sets ADC enable 1. +func (d *Device) SetADCEnableSet(a uint8) { + d.write1Byte(RegADCEnableSet, a) +} + +// GetADCEnableSet gets ADC enable 1. +func (d *Device) GetADCEnableSet() uint8 { + return d.read8bit(RegADCEnableSet) +} + +// SetGPIO43SignalStatus sets GPIO[4:3] signal status. +func (d *Device) SetGPIO43SignalStatus(a uint8) { + d.write1Byte(RegGPIO43SignalStatus, a) +} + +// GetGPIO43SignalStatus gets GPIO[4:3] signal status. +func (d *Device) GetGPIO43SignalStatus() uint8 { + return d.read8bit(RegGPIO43SignalStatus) +} + +// SetDCVoltage sets DC voltage. +func (d *Device) SetDCVoltage(number uint8, voltage uint16) { + if voltage < 700 { + voltage = 0 + } else { + voltage = (voltage - 700) / 25 + } + + switch number { + case 0: + v := d.GetDCDC1VoltageSet() + d.SetDCDC1VoltageSet((v & 0x80) | (uint8(voltage) & 0x7F)) + case 1: + v := d.GetDCDC2VoltageSet() + d.SetDCDC2VoltageSet((v & 0x80) | (uint8(voltage) & 0x7F)) + case 2: + v := d.GetDCDC3VoltageSet() + d.SetDCDC3VoltageSet((v & 0x80) | (uint8(voltage) & 0x7F)) + } +} + +// SetLDOVoltage sets LDO voltage. +func (d *Device) SetLDOVoltage(number uint8, voltage uint16) { + if voltage > 3300 { + voltage = 15 + } else { + voltage = (voltage / 100) - 18 + } + + switch number { + case 2: + v := d.GetLDO23VoltageSet() + d.SetLDO23VoltageSet((v & 0x0F) | (uint8(voltage) << 4)) + break + case 3: + v := d.GetLDO23VoltageSet() + d.SetLDO23VoltageSet((v & 0xF0) | uint8(voltage)) + break + } +} + +// SetLDOEnable enable LDO. +func (d *Device) SetLDOEnable(number uint8, state bool) { + mark := uint8(0x01) + mark <<= number + switch number { + case 2: + v := d.GetDCDC13LDO23Switch() + d.SetDCDC13LDO23Switch(v | mark) + case 3: + v := d.GetDCDC13LDO23Switch() + d.SetDCDC13LDO23Switch(v & (^mark)) + } +} + +func (d *Device) write1Byte(reg, data uint8) { + d.bus.WriteRegister(d.Address, reg, []byte{data}) +} + +func (d *Device) read8bit(reg uint8) uint8 { + d.bus.ReadRegister(d.Address, reg, d.buf[:1]) + return d.buf[0] +} diff --git a/axp192/m5stack-core2-axp192/axp192.go b/axp192/m5stack-core2-axp192/axp192.go new file mode 100644 index 0000000..9df1b01 --- /dev/null +++ b/axp192/m5stack-core2-axp192/axp192.go @@ -0,0 +1,158 @@ +package axp192 + +import ( + "time" + + "tinygo.org/x/drivers" + axp192orig "tinygo.org/x/drivers/axp192" +) + +// Device wraps an I2C connection to a AXP192 device. +type Device struct { + *axp192orig.Device + LED Pin + RST Pin + SPK_EN Pin +} + +// New creates a new AXP192 connection. The I2C bus must already be +// configured. +// +// This function only creates the Device object, it does not touch the device. +func New(i2c drivers.I2C) *Device { + d := axp192orig.New(i2c) + + axp := &Device{ + Device: d, + } + axp.LED = Pin{pin: 1, axp: axp} + axp.SPK_EN = Pin{pin: 2, axp: axp} + axp.RST = Pin{pin: 4, axp: axp} + + axp.begin() + + return axp +} + +type Config struct { +} + +// Configure sets up the device for communication +func (d *Device) Configure(config Config) error { + return d.Device.Configure(axp192orig.Config{}) +} + +func (d *Device) begin() { + d.SetVbusIPSOutAccessManagement((d.GetVbusIPSOutAccessManagement() & 0x04) | 0x02) + d.SetGPIO1Control(d.GetGPIO1Control() & 0xF8) + d.SetGPIO2Control(d.GetGPIO2Control() & 0xF8) + d.SetBackupBatteryChargingControl((d.GetBackupBatteryChargingControl() & 0x1C) | 0xA2) + d.SetESPVoltage(3350) + d.SetLcdVoltage(3300) + d.SetLDOVoltage(2, 3300) //Periph power voltage preset (LCD_logic, SD card) + d.SetLDOVoltage(3, 2000) //Vibrator power voltage preset + + d.SetLDOEnable(2, true) + d.SetDCDC3(true) // LCD Backlight + // GPIO4 : LCD Reset + d.SetGPIO43FunctionControl((d.GetGPIO43FunctionControl() & 0x72) | 0x84) + // Power On/Off Setting + d.SetPEKParameterSet(0x4C) + d.SetADCEnableSet(0xFF) + + d.RST.Low() + time.Sleep(100 * time.Millisecond) + d.RST.High() + time.Sleep(100 * time.Millisecond) +} + +// ToggleLED toggles LED connected to AXP192. +func (d *Device) ToggleLED() { + v := d.GetGPIO20SignalStatus() + if (v & 0x02) > 0 { + d.SetGPIO20SignalStatus(v & 0xFD) + } else { + d.SetGPIO20SignalStatus(v | 0x02) + } +} + +// SetESPVoltage sets voltage of ESP32. +func (d *Device) SetESPVoltage(voltage uint16) { + if voltage >= 3000 && voltage <= 3400 { + d.SetDCVoltage(0, voltage) + } +} + +// SetLcdVoltage sets voltage of LCD. +func (d *Device) SetLcdVoltage(voltage uint16) { + if voltage >= 2500 && voltage <= 3300 { + d.SetDCVoltage(2, voltage) + } +} + +// SetDCDC3 enables or disables DCDC3. +func (d *Device) SetDCDC3(State bool) { + v := d.GetDCDC13LDO23Switch() + if State == true { + v = (1 << 1) | v + } else { + v = ^(uint8(1) << 1) & v + } + d.SetDCDC13LDO23Switch(v) +} + +// Pin is a single pin on AXP192. +type Pin struct { + pin uint8 + axp *Device +} + +// High sets this GPIO pin to high. +func (p Pin) High() { + switch p.pin { + case 1: // LED + v := p.axp.GetGPIO20SignalStatus() + p.axp.SetGPIO20SignalStatus(v | 0x02) + case 2: // SPK_EN + case 4: // RST + v := p.axp.GetGPIO43SignalStatus() + v |= uint8(0x02) + p.axp.SetGPIO43SignalStatus(v) + } +} + +// Low sets this GPIO pin to low. +func (p Pin) Low() { + switch p.pin { + case 1: // LED + v := p.axp.GetGPIO20SignalStatus() + p.axp.SetGPIO20SignalStatus(v & 0xFD) + case 2: // SPK_EN + case 4: // RST + v := p.axp.GetGPIO43SignalStatus() + v &= ^uint8(0x02) + p.axp.SetGPIO43SignalStatus(v) + } +} + +// Toggle switches an output pin from low to high or from high to low. +func (p Pin) Toggle() { + switch p.pin { + case 1: // LED + v := p.axp.GetGPIO20SignalStatus() + if (v & 0x02) == 0 { + p.axp.SetGPIO20SignalStatus(v | 0x02) + } else { + p.axp.SetGPIO20SignalStatus(v & 0xFD) + } + case 2: // SPK_EN + case 4: // RST + v := p.axp.GetGPIO43SignalStatus() + if (v & 0x02) == 0 { + v |= uint8(0x02) + } else { + v &= ^uint8(0x02) + } + p.axp.SetGPIO43SignalStatus(v) + } +} diff --git a/axp192/registers.go b/axp192/registers.go new file mode 100644 index 0000000..18a5aa1 --- /dev/null +++ b/axp192/registers.go @@ -0,0 +1,127 @@ +package axp192 + +// power supply control class +// 0x00 Power supply status register +// 0x01 Power supply mode/charging status register +// 0x04 OTG VBUS status register +// 0x06‐09 Data buffer register +// 0x10 EXTEN & DC‐DC2 switch register +// 0x12 DC‐DC1/3 & LDO2/3switch register +// 0x23 DC‐DC2 voltage set register +// 0x25 DC‐DC2 voltage slope set register +// 0x26 DC‐DC1voltage set register +// 0x27 DC‐DC3 voltage set register +// 0x28 LDO2/3 voltage set register +// 0x30 VBUS‐IPSOUT access set register +// 0x31 VOFF power off voltage set register +// 0x32 Power off、battery detect、CHGLED control register +// 0x33 Charging control register1 +// 0x34 Charging control register2 +// 0x35 Backup battery charging control register +// 0x36 PEK parameter set register +// 0x37 DCDC switch frequency set register +// 0x38 Battery charging under temperature warning set register +// 0x39 Battery charging over temperature warning set register +// 0x3A APS under voltage Level1 set register +// 0x3B APS under voltage Level2 set register +// 0x3C Battery discharging under temperature warning set register +// 0x3D Battery discharging over temperature warning set register +// 0x80 DCDC mode set register +// 0x82 ADC enable set register 1 +// 0x83 ADC enable set register 2 +// 0x84 ADC sample frequency set, TS pin control register +// 0x85 GPIO [3:0] input range set register +// 0x8A Timer control register +// 0x8B VBUS monitor set register +// 0x8F Over temperature power off control register + +// GPIO control class +// 0x90 GPIO0 control register +// 0x91 GPIO0 LDO mode output voltage set register +// 0x92 GPIO1 control register +// 0x93 GPIO2 control register +// 0x94 GPIO[2:0] signal status register +// 0x95 GPIO[4:3] function control register +// 0x96 GPIO[4:3] signal status register +// 0x97 GPIO[2:0] pull down control register +// 0x98 PWM1 frequency set register +// 0x99 PWM1 duty ratio set register 1 +// 0x9A PWM1 duty ratio set register 2 +// 0x9B PWM2 frequency set register +// 0x9C PWM2 duty ratio set register 1 +// 0x9D PWM2 duty ratio set register 2 +// 0x9E GPIO5 control register + +// IRQ control class +// 0x40 IRQ enable control register 1 +// 0x41 IRQ enable control register 2 +// 0x42 IRQ enable control register 3 +// 0x43 IRQ enable control register 4 +// 0x44 IRQ status register 1 +// 0x45 IRQ status register 2 +// 0x46 IRQ status register 3 +// 0x47 IRQ status register 4 + +// ADC data class +// 0x56 ACIN voltage ADC data high 8 bit +// 0x57 ACIN voltage ADC data low 4 bit +// 0x58 ACIN current ADC data high 8 bit +// 0x59 ACIN current ADC data low 4 bit +// 0x5A VBUS voltage ADC data high 8 bit +// 0x5B VBUS voltage ADC data low 4 bit +// 0x5C VBUS current ADC data high 8 bit +// 0x5D VBUS current ADC data low 4 bit +// 0x5E AXP192 internal temperature monitor ADC data High 8 bit +// 0x5F AXP192 internal temperature monitor ADC data low 4 bit +// 0x62 TS input ADC data High 8 bit,monitor battery temperature by default +// 0x63 TS input ADC data low 4 bit,monitor battery temperature by default +// 0x64 GPIO0 voltage ADC data high 8 bit +// 0x65 GPIO0 voltage ADC data low 4 bit +// 0x66 GPIO1 voltage ADC data high 8 bit +// 0x67 GPIO1 voltage ADC data low 4 bit +// 0x68 GPIO2 voltage ADC data high 8 bit +// 0x69 GPIO2 voltage ADC data low 4 bit +// 0x6A GPIO[3] voltage ADC data high 8 bit +// 0x6B GPIO[3] voltage ADC data low 4 bit +// 0x70 Battery instantaneous power high 8 bit +// 0x71 Battery instantaneous power middle 8 bit +// 0x72 Battery instantaneous power low 8 bit +// 0x78 Battery voltage high 8 bit +// 0x79 Battery voltage low 4 bit +// 0x7A Battery charging current high 8 bit +// 0x7B Battery charging current low 5 bit +// 0x7C Battery discharging current high 8 bit +// 0x7D Battery discharging current low 5 bit +// 0x7E APS voltage high 8 bit +// 0x7F APS voltage low 4 bit +// 0xB0 Battery charging coulomb counter data register 3 +// 0xB1 Battery charging coulomb counter data register 2 +// 0xB2 Battery charging coulomb counter data register 1 +// 0xB3 Battery charging coulomb counter data register 0 +// 0xB4 Battery discharging coulomb counter data register 3 +// 0xB5 Battery discharging coulomb counter data register 2 +// 0xB6 Battery discharging coulomb counter data register 1 +// 0xB7 Battery discharging coulomb counter data register 0 +// 0xB8 Coulomb counter control register + +const ( + // Address is default I2C address. + Address = 0x34 + + RegPowerSupplyStatus = 0x00 + RegDCDC13LDO23Switch = 0x12 + RegVbusIPSOutAccessManagement = 0x30 + RegBackupBatteryChargingControl = 0x35 + RegDCDC2VoltageSet = 0x25 + RegDCDC1VoltageSet = 0x26 + RegDCDC3VoltageSet = 0x27 + RegLDO23VoltageSet = 0x28 + RegPEKParameterSet = 0x36 + RegADCEnableSet = 0x82 + + RegGPIO1Control = 0x92 + RegGPIO2Control = 0x93 + RegGPIO20SignalStatus = 0x94 + RegGPIO43FunctionControl = 0x95 + RegGPIO43SignalStatus = 0x96 +) diff --git a/examples/axp192/m5stack-core2-blinky/main.go b/examples/axp192/m5stack-core2-blinky/main.go new file mode 100644 index 0000000..d77faee --- /dev/null +++ b/examples/axp192/m5stack-core2-blinky/main.go @@ -0,0 +1,25 @@ +package main + +import ( + "machine" + "time" + + axp192 "tinygo.org/x/drivers/axp192/m5stack-core2-axp192" + "tinygo.org/x/drivers/i2csoft" +) + +func main() { + i2c := i2csoft.New(machine.SCL0_PIN, machine.SDA0_PIN) + i2c.Configure(i2csoft.I2CConfig{Frequency: 100e3}) + + axp := axp192.New(i2c) + led := axp.LED + + for { + led.Low() + time.Sleep(time.Millisecond * 500) + + led.High() + time.Sleep(time.Millisecond * 500) + } +}