1
0
forked from me/IronOS
Files
IronOS/source/Core/Drivers/HUB238.cpp
Ben V. Brown 286afad919 S60 Support (#1692)
* Mock S60

* cleanup

* Start refactor of OLED init

* Setup timers roughly

* Set Vector table offset correctly

Update system_stm32f1xx.c

* Update OLED.cpp

* Update stm32f1xx_hal_msp.c

* Update configuration.h

* I2C init before GPIO

From Errata

Update stm32f1xx_hal_msp.c

Update Software_I2C.h

Allow no hardware I2C

* I2C BB run bus unlock at init

* cleanups

* Software I2C for now

* Mildly more graceful Interpolate

* Handle is powered by DC

Update Power.cpp

Update drawPowerSourceIcon.cpp

Update configuration.h

Update Setup.cpp

* Cleanup HomeScreen

* Segment remap oled at init

* Cleanup

* Update MOVThread.cpp

* Fix PWM Init

* Fix adc2 trigger

* Update configs

* Fixup warning

* Saner default config

* Update ThermoModel.cpp

* Util for current@voltage

* Hub238 warning

* Add hub238 handling in power mode

* Update USBPDDebug_FUSB.cpp

* HUSB238 debug

* Hook PSU Limit

* Use wrapping section of GRAM for scroll

Update OLED.hpp

* Update NTC table

* Fix HUB voltage picker

* Cleanup

* Larger tip filter

* Calibrate in a bunch closer

Update ThermoModel.cpp

* Update configuration.h

* Update HUB238.cpp

* Update configuration.h

* Movement Pin

* Update BSP.cpp

* tim2 irq

* Rough timer conversion (adc broken) but movement working

* Fix tim2 start

* Faster base PWM

* Ensure utils grabs config

* Add wattage limiter tolerance for device

* Speed up PWM and enable PWM current limiting

* tune for 12v

* Prevent start until PD done

* Update configuration.h

* Add HUB238 check for have re-negotiated

* Adjust timer to avoid noise when its possible
2023-06-03 20:05:31 +10:00

220 lines
5.7 KiB
C++

#include "HUB238.hpp"
#include "I2CBB.hpp"
#include "Utils.h"
#include "configuration.h"
#if POW_PD_EXT == 1
bool hub238_probe() { return I2CBB::probe(HUB238_ADDR); }
extern int32_t powerSupplyWattageLimit;
uint16_t hub238_debug_state() {
uint8_t status0 = 0;
uint8_t status1 = 0;
if (!I2CBB::Mem_Read(HUB238_ADDR, HUB238_REG_PD_STATUS0, &status0, 1)) {
return 0xFFFF;
}
if (!I2CBB::Mem_Read(HUB238_ADDR, HUB238_REG_PD_STATUS1, &status1, 1)) {
return 0xFFFF;
}
return status1 | (((uint16_t)status0) << 8);
}
uint16_t pdo_slot_to_currentx100(uint8_t temp) {
temp = temp & 0b1111;
switch (temp) {
case 0b0000:
return 50;
case 0b0001:
return 70;
case 0b0010:
return 100;
case 0b0011:
return 125;
case 0b0100:
return 150;
case 0b0101:
return 175;
case 0b0110:
return 200;
case 0b0111:
return 225;
case 0b1000:
return 250;
case 0b1001:
return 275;
case 0b1010:
return 300;
case 0b1011:
return 325;
case 0b1100:
return 350;
case 0b1101:
return 400;
case 0b1110:
return 450;
case 0b1111:
return 500;
}
}
uint16_t hub238_getVoltagePDOCurrent(uint8_t voltage) {
uint8_t reg = HUB238_REG_SRC_PDO_5V;
switch (voltage) {
case 5:
reg = HUB238_REG_SRC_PDO_5V;
break;
case 9:
reg = HUB238_REG_SRC_PDO_9V;
break;
case 12:
reg = HUB238_REG_SRC_PDO_12V;
break;
case 15:
reg = HUB238_REG_SRC_PDO_15V;
break;
case 18:
reg = HUB238_REG_SRC_PDO_18V;
break;
case 20:
reg = HUB238_REG_SRC_PDO_20V;
break;
default:
return 0;
}
uint8_t temp = 0;
if (I2CBB::Mem_Read(HUB238_ADDR, reg, &temp, 1) == true) {
if (temp & HUB238_PDO_DETECTED) {
return pdo_slot_to_currentx100(temp);
}
}
return 0;
}
uint8_t findBestPDO() {
uint8_t temp = 0;
uint16_t ilim = 0;
uint16_t minimumx10current = 0;
#if USB_PD_VMAX >= 20
ilim = hub238_getVoltagePDOCurrent(20);
minimumx10current = Utils::RequiredCurrentForTipAtVoltage(200);
if (ilim != 0 && ilim / 10 >= minimumx10current) {
powerSupplyWattageLimit = ((20 * ilim) / 100) - 2; // We take off 2W for safety of overhead
return 0b1010;
}
#endif
#if USB_PD_VMAX >= 18
ilim = hub238_getVoltagePDOCurrent(18);
minimumx10current = Utils::RequiredCurrentForTipAtVoltage(180);
if (ilim != 0 && ilim / 10 >= minimumx10current) {
powerSupplyWattageLimit = ((18 * ilim) / 100) - 2; // We take off 2W for safety of overhead
return 0b1001;
}
#endif
#if USB_PD_VMAX >= 15
ilim = hub238_getVoltagePDOCurrent(15);
minimumx10current = Utils::RequiredCurrentForTipAtVoltage(150);
if (ilim != 0 && ilim / 10 >= minimumx10current) {
powerSupplyWattageLimit = ((15 * ilim) / 100) - 2; // We take off 2W for safety of overhead
return 0b1000;
}
#endif
#if USB_PD_VMAX >= 12
ilim = hub238_getVoltagePDOCurrent(12);
minimumx10current = Utils::RequiredCurrentForTipAtVoltage(120);
if (ilim != 0 && (ilim / 10) >= minimumx10current) {
powerSupplyWattageLimit = ((12 * ilim) / 100) - 2; // We take off 2W for safety of overhead
return 0b0011;
}
#endif
#if USB_PD_VMAX >= 9
ilim = hub238_getVoltagePDOCurrent(9);
minimumx10current = Utils::RequiredCurrentForTipAtVoltage(90);
if (ilim != 0 && ilim / 10 >= minimumx10current) {
powerSupplyWattageLimit = ((9 * ilim) / 100) - 2; // We take off 2W for safety of overhead
return 0b0010;
}
#endif
powerSupplyWattageLimit = 10;
return 0b0001; // 5V PDO
}
volatile uint8_t haveSelected = 0xFF;
void hub238_check_negotiation() {
// Dont do anything for first 2 seconds as its internal state machine corrupts if we ask it to change too fast
if (xTaskGetTickCount() < 2000) {
return;
}
// Want to check if there is a better PDO to be using
// First, exit early if we already have changed _or_ no PD
// Even if it negotiates the same voltage as we want, we still re-run it as that makes it ignore the resistor
// and instead ask for max amps
if (haveSelected != 0xFF || !hub238_has_negotiated() || hub238_source_voltage() == 0) {
return;
}
uint8_t currentPDO = 0;
vTaskDelay(5);
uint8_t bestPDO = findBestPDO();
if (I2CBB::Mem_Read(HUB238_ADDR, HUB238_REG_SRC_PDO, &currentPDO, 1) == true) {
currentPDO >>= 4; // grab upper bits
if (currentPDO == bestPDO) {
haveSelected = bestPDO;
return;
}
currentPDO = bestPDO << 4;
if (I2CBB::Mem_Write(HUB238_ADDR, HUB238_REG_SRC_PDO, &currentPDO, 1) == true) {
currentPDO = 0x01; // request for new PDO
if (I2CBB::Mem_Write(HUB238_ADDR, HUB238_REG_GO_COMMAND, &currentPDO, 1) == true) {
haveSelected = bestPDO;
vTaskDelay(50);
return;
}
}
}
}
bool hub238_has_run_selection() { return haveSelected != 0xFF; }
bool hub238_has_negotiated() {
uint8_t temp = 0;
if (I2CBB::Mem_Read(HUB238_ADDR, HUB238_REG_PD_STATUS1, &temp, 1) == true) {
temp >>= 3;
return (temp & 0b111) == 0b001; // success
}
return false;
}
// Return selected source voltage in V
uint16_t hub238_source_voltage() {
uint8_t temp = 0;
if (I2CBB::Mem_Read(HUB238_ADDR, HUB238_REG_PD_STATUS0, &temp, 1) == true) {
temp >>= 4;
switch (temp) {
case 0b0001:
return 5;
case 0b0010:
return 9;
case 0b0011:
return 12;
case 0b0100:
return 15;
case 0b0101:
return 18;
case 0b0110:
return 20;
}
}
return 0;
}
// Return selected source current in Amps * 100
uint8_t hub238_source_currentX100() {
uint8_t temp = 0;
if (I2CBB::Mem_Read(HUB238_ADDR, HUB238_REG_PD_STATUS0, &temp, 1) == true) {
temp &= 0b1111;
return pdo_slot_to_currentx100(temp);
}
return 10;//Failsafe to 0.1 amp
}
#endif