1
0
forked from me/IronOS

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
This commit is contained in:
Ben V. Brown
2023-06-03 20:05:31 +10:00
committed by GitHub
parent 1acb29fcf3
commit 286afad919
116 changed files with 72488 additions and 259 deletions

View File

@@ -141,6 +141,22 @@ const uint8_t disconnectedTip[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x04, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
#endif
#if defined(MODEL_S60) > 0
const uint8_t buttonA[] = {
// width = 42
// height = 16
0x00, 0x00, 0x00, 0x00, 0xe0, 0x18, 0x04, 0x02, 0x02, 0x01, 0x81, 0x49, 0x31, 0x01, 0xc1, 0x25, 0x19, 0x01, 0xc1, 0x25, 0x19, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x04, 0x18, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x18, 0x20, 0x40, 0x40, 0x80, 0x89, 0x8a, 0x88, 0x94,
0x8c, 0x94, 0xae, 0x80, 0xbe, 0x8e, 0xa6, 0x8e, 0xa6, 0x8e, 0xa6, 0x8e, 0xa6, 0x8a, 0xa6, 0x8a, 0xa6, 0x8a, 0xa6, 0x8a, 0x46, 0x4a, 0x22, 0x18, 0x07, 0x00, 0x00, 0x00};
const uint8_t disconnectedTip[] = {
// width = 42
// height = 16
0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0xc0, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xcc, 0x9c, 0x38, 0x70, 0xe0, 0xc0, 0x80, 0x20, 0x70, 0x38, 0x1c, 0xcc, 0x40,
0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0x60, 0xe0, 0x00, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x05, 0x00, 0x07, 0x01, 0x04, 0x01, 0x04, 0x01,
0x04, 0x31, 0x38, 0x1c, 0x0e, 0x04, 0x01, 0x03, 0x07, 0x0e, 0x1c, 0x39, 0x30, 0x01, 0x03, 0x00, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x02, 0x01, 0x04, 0x09, 0x0f, 0x00};
#endif
const uint8_t buttonB[] = {
// width = 42
// height = 16

View File

@@ -0,0 +1,220 @@
#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

View File

@@ -0,0 +1,51 @@
#pragma once
#ifndef _DRIVERS_HUB238_HPP_
#define _DRIVERS_HUB238_HPP_
#include "configuration.h"
#if POW_PD_EXT == 1
#include <stdbool.h>
#include <stdint.h>
#define HUB238_ADDR 0x08 << 1
#define HUB238_REG_PD_STATUS0 0x00
#define HUB238_REG_PD_STATUS1 0x01
#define HUB238_REG_SRC_PDO_5V 0x02
#define HUB238_REG_SRC_PDO_9V 0x03
#define HUB238_REG_SRC_PDO_12V 0x04
#define HUB238_REG_SRC_PDO_15V 0x05
#define HUB238_REG_SRC_PDO_18V 0x06
#define HUB238_REG_SRC_PDO_20V 0x07
#define HUB238_REG_SRC_PDO 0x08
#define HUB238_REG_GO_COMMAND 0x09
#define HUB238_PDO_DETECTED (0x01 << 7)
// The HUB238 is fairly simple device to interact to, with fairly few registers all in all
// It only appears to support fixed PDO's up to 20V
// And they have just dedicated registers to each potential option
// Given a tip resistance we try and pick the best possible PDO option to suit that resistance
// (Using I2C overrides any hardware strapping).
// Probe if the hub238 exists on the I2C bus
bool hub238_probe();
// If we have not manually picked a PDO,
// but there is an active PD supply, try for our preference
void hub238_check_negotiation();
// Returns true when negotiation has finished
bool hub238_has_negotiated();
// Returns true when we have run selection and negotiated higher current
bool hub238_has_run_selection();
// Return an encoded state for debugging
uint16_t hub238_debug_state();
// Return selected source voltage in V
uint16_t hub238_source_voltage();
// Return selected source current in Amps * 100
uint8_t hub238_source_currentX100();
uint16_t hub238_getVoltagePDOCurrent(uint8_t voltage);
#endif
#endif

View File

@@ -26,6 +26,19 @@ void I2CBB::init() {
HAL_GPIO_Init(SCL2_GPIO_Port, &GPIO_InitStruct);
SOFT_SDA_HIGH();
SOFT_SCL_HIGH();
// To ensure bus is unlocked; we toggle the Clock a bunch of times to make things error out
for (int i = 0; i < 128; i++) {
SOFT_SCL_LOW();
asm("nop");
asm("nop");
asm("nop");
asm("nop");
SOFT_SCL_HIGH();
asm("nop");
asm("nop");
asm("nop");
asm("nop");
}
I2CSemaphore = xSemaphoreCreateMutexStatic(&xSemaphoreBuffer);
unlock();
}
@@ -83,14 +96,12 @@ bool I2CBB::Mem_Write(uint16_t DevAddress, uint16_t MemAddress, const uint8_t *p
bool ack = send(DevAddress);
if (!ack) {
stop();
asm("bkpt");
unlock();
return false;
}
ack = send(MemAddress);
if (!ack) {
stop();
asm("bkpt");
unlock();
return false;
}
@@ -99,7 +110,6 @@ bool I2CBB::Mem_Write(uint16_t DevAddress, uint16_t MemAddress, const uint8_t *p
ack = send(pData[0]);
if (!ack) {
stop();
asm("bkpt");
unlock();
return false;
}
@@ -267,9 +277,7 @@ uint8_t I2CBB::read_bit() {
void I2CBB::unlock() { xSemaphoreGive(I2CSemaphore); }
bool I2CBB::lock() {
if (I2CSemaphore == NULL) {
asm("bkpt");
}
if (I2CSemaphore == NULL) {}
bool a = xSemaphoreTake(I2CSemaphore, (TickType_t)100) == pdTRUE;
return a;
}

View File

@@ -23,7 +23,7 @@ OLED::DisplayState OLED::displayState;
int16_t OLED::cursor_x, OLED::cursor_y;
bool OLED::initDone = false;
uint8_t OLED::displayOffset;
uint8_t OLED::screenBuffer[16 + (OLED_WIDTH * 2) + 10]; // The data buffer
uint8_t OLED::screenBuffer[16 + (OLED_WIDTH * (OLED_HEIGHT / 8)) + 10]; // The data buffer
uint8_t OLED::secondFrameBuffer[OLED_WIDTH * 2];
uint32_t OLED::displayChecksum;
/*Setup params for the OLED screen*/
@@ -32,31 +32,35 @@ uint32_t OLED::displayChecksum;
/*Data packets are prefixed with 0x40*/
I2C_CLASS::I2C_REG OLED_Setup_Array[] = {
/**/
{0x80, 0xAE, 0}, /*Display off*/
{0x80, 0xD5, 0}, /*Set display clock divide ratio / osc freq*/
{0x80, 0x52, 0}, /*Divide ratios*/
{0x80, 0xA8, 0}, /*Set Multiplex Ratio*/
{0x80, 0x0F, 0}, /*16 == max brightness,39==dimmest*/
{0x80, 0xC0, 0}, /*Set COM Scan direction*/
{0x80, 0xD3, 0}, /*Set vertical Display offset*/
{0x80, 0x00, 0}, /*0 Offset*/
{0x80, 0x40, 0}, /*Set Display start line to 0*/
{0x80, 0xA0, 0}, /*Set Segment remap to normal*/
{0x80, 0x8D, 0}, /*Charge Pump*/
{0x80, 0x14, 0}, /*Charge Pump settings*/
{0x80, 0xDA, 0}, /*Set VCOM Pins hardware config*/
{0x80, 0x02, 0}, /*Combination 2*/
{0x80, 0x81, 0}, /*Brightness*/
{0x80, 0x00, 0}, /*^0*/
{0x80, 0xD9, 0}, /*Set pre-charge period*/
{0x80, 0xF1, 0}, /*Pre charge period*/
{0x80, 0xDB, 0}, /*Adjust VCOMH regulator ouput*/
{0x80, 0x30, 0}, /*VCOM level*/
{0x80, 0xA4, 0}, /*Enable the display GDDR*/
{0x80, 0XA6, 0}, /*Normal display*/
{0x80, 0x20, 0}, /*Memory Mode*/
{0x80, 0x00, 0}, /*Wrap memory*/
{0x80, 0xAF, 0}, /*Display on*/
{0x80, 0xAE, 0}, /*Display off*/
{0x80, 0xD5, 0}, /*Set display clock divide ratio / osc freq*/
{0x80, 0x52, 0}, /*Divide ratios*/
{0x80, 0xA8, 0}, /*Set Multiplex Ratio*/
{0x80, OLED_HEIGHT - 1, 0}, /*Multiplex ratio adjusts how far down the matrix it scans*/
{0x80, 0xC0, 0}, /*Set COM Scan direction*/
{0x80, 0xD3, 0}, /*Set vertical Display offset*/
{0x80, 0x00, 0}, /*0 Offset*/
{0x80, 0x40, 0}, /*Set Display start line to 0*/
#ifdef OLED_SEGMENT_MAP_REVERSED
{0x80, 0xA1, 0}, /*Set Segment remap to normal*/
#else
{0x80, 0xA0, 0}, /*Set Segment remap to normal*/
#endif
{0x80, 0x8D, 0}, /*Charge Pump*/
{0x80, 0x14, 0}, /*Charge Pump settings*/
{0x80, 0xDA, 0}, /*Set VCOM Pins hardware config*/
{0x80, OLED_VCOM_LAYOUT, 0}, /*Combination 0x2 or 0x12 depending on OLED model*/
{0x80, 0x81, 0}, /*Brightness*/
{0x80, 0x00, 0}, /*^0*/
{0x80, 0xD9, 0}, /*Set pre-charge period*/
{0x80, 0xF1, 0}, /*Pre charge period*/
{0x80, 0xDB, 0}, /*Adjust VCOMH regulator ouput*/
{0x80, 0x30, 0}, /*VCOM level*/
{0x80, 0xA4, 0}, /*Enable the display GDDR*/
{0x80, 0XA6, 0}, /*Normal display*/
{0x80, 0x20, 0}, /*Memory Mode*/
{0x80, 0x00, 0}, /*Wrap memory*/
{0x80, 0xAF, 0}, /*Display on*/
};
// Setup based on the SSD1307 and modified for the SSD1306
@@ -71,9 +75,9 @@ const uint8_t REFRESH_COMMANDS[17] = {
0x80,
0x21, // cmd
0x80,
0x20, // A
OLED_GRAM_START, // A
0x80,
0x7F, // B
OLED_GRAM_END, // B
// Set COM output scan direction (normal mode, COM0 to COM[N-1])
0x80,
@@ -87,7 +91,7 @@ const uint8_t REFRESH_COMMANDS[17] = {
0x80,
0x00, // A
0x80,
0x01, // B
(OLED_HEIGHT / 8), // B
// Start of data
0x40,
@@ -217,7 +221,7 @@ void OLED::maskScrollIndicatorOnOLED() {
// it from the screen buffer which is updated by `OLED::setRotation`.
uint8_t rightmostColumn = screenBuffer[7];
uint8_t maskCommands[] = {
// Set column address:
// Set column address:
// A[6:0] - Column start address = rightmost column
// B[6:0] - Column end address = rightmost column
0x80,
@@ -304,24 +308,26 @@ void OLED::useSecondaryFramebuffer(bool useSecondary) {
* method, as doing so will overwrite the previous screen data. The caller
* does not need to call `OLED::refresh()` after this function returns.
*
* **This function blocks until the transition has completed.**
* **This function blocks until the transition has completed or user presses button**
*/
void OLED::transitionScrollDown() {
// We want to draw the updated framebuffer to the next page downward.
uint8_t const pageStart = screenBuffer[13];
uint8_t const nextPage = (pageStart + 2) % 8;
uint8_t const nextPage = (pageStart + (OLED_HEIGHT / 8)) % 8;
// Change page start address:
screenBuffer[13] = nextPage;
// Change page end address:
screenBuffer[15] = nextPage + 1;
screenBuffer[15] = (nextPage + 1) % 8;
refresh();
refresh(); // Now refresh to write out the contents to the new page
osDelay(TICKS_100MS / 5);
uint8_t const startLine = pageStart * 8 + 1;
uint8_t const scrollTo = (pageStart + 2) * 8;
uint8_t startLine = (pageStart * 8) + 1;
uint8_t scrollTo = (pageStart + (OLED_HEIGHT / 8)) * 8;
// Scroll the screen by changing display start line.
// This effectively scrolls off the bottom of the current page and into the next one
for (uint8_t current = startLine; current <= scrollTo; current++) {
if (getButtonState() != BUTTON_NONE) {
current = scrollTo;
@@ -337,6 +343,13 @@ void OLED::transitionScrollDown() {
I2C_CLASS::I2C_RegisterWrite(DEVICEADDR_OLED, 0x80, scrollCommandByte);
osDelay(TICKS_100MS / 7);
}
// Now that scroll is done, revert to default page to avoid wrap issues
screenBuffer[13] = pageStart;
screenBuffer[15] = (pageStart + 1) % 8;
uint8_t scrollCommandByte = 0b01000000;
OLED_Setup_Array[8].val = scrollCommandByte;
I2C_CLASS::I2C_RegisterWrite(DEVICEADDR_OLED, 0x80, scrollCommandByte);
refresh();
}
void OLED::setRotation(bool leftHanded) {
@@ -346,22 +359,32 @@ void OLED::setRotation(bool leftHanded) {
if (inLeftHandedMode == leftHanded) {
return;
}
#ifdef OLED_SEGMENT_MAP_REVERSED
if (!leftHanded) {
OLED_Setup_Array[9].val = 0xA1;
} else {
OLED_Setup_Array[9].val = 0xA0;
}
#else
if (leftHanded) {
OLED_Setup_Array[9].val = 0xA1;
} else {
OLED_Setup_Array[9].val = 0xA0;
}
#endif
// send command struct again with changes
if (leftHanded) {
OLED_Setup_Array[5].val = 0xC8; // c1?
OLED_Setup_Array[9].val = 0xA1;
} else {
OLED_Setup_Array[5].val = 0xC0;
OLED_Setup_Array[9].val = 0xA0;
}
I2C_CLASS::writeRegistersBulk(DEVICEADDR_OLED, OLED_Setup_Array, sizeof(OLED_Setup_Array) / sizeof(OLED_Setup_Array[0]));
osDelay(TICKS_10MS);
inLeftHandedMode = leftHanded;
screenBuffer[5] = inLeftHandedMode ? 0 : 32; // display is shifted by 32 in left handed
// mode as driver ram is 128 wide
screenBuffer[7] = inLeftHandedMode ? 95 : 0x7F; // End address of the ram segment we are writing to (96 wide)
screenBuffer[5] = inLeftHandedMode ? OLED_GRAM_START_FLIP : OLED_GRAM_START; // display is shifted by 32 in left handed
// mode as driver ram is 128 wide
screenBuffer[7] = inLeftHandedMode ? OLED_GRAM_END_FLIP : OLED_GRAM_END; // End address of the ram segment we are writing to (96 wide)
screenBuffer[9] = inLeftHandedMode ? 0xC8 : 0xC0;
// Force a screen refresh
const int len = FRAMEBUFFER_START + (OLED_WIDTH * 2);

View File

@@ -32,9 +32,32 @@ extern "C" {
#include "I2C_Wrapper.hpp"
#endif
#define DEVICEADDR_OLED (0x3c << 1)
#define OLED_WIDTH 96
#define OLED_HEIGHT 16
#define DEVICEADDR_OLED (0x3c << 1)
#ifdef OLED_128x32
// TODO; for now just cropping in on the screen from 128x32 to 96x16
#define OLED_WIDTH 96
#define OLED_HEIGHT 16
#define OLED_GRAM_START 0x10 // Should be 0x00 when we have full width
#define OLED_GRAM_END 0x6F // Should be 0x7F when we have full width
#define OLED_GRAM_START_FLIP 0
#define OLED_GRAM_END_FLIP 95
#define OLED_VCOM_LAYOUT 0x12
#define OLED_SEGMENT_MAP_REVERSED
#warning "S60 Not fully supported"
#else
#define OLED_WIDTH 96
#define OLED_HEIGHT 16
#define OLED_VCOM_LAYOUT 0x02
#define OLED_GRAM_START 0x20
#define OLED_GRAM_END 0x7F
#define OLED_GRAM_START_FLIP 0
#define OLED_GRAM_END_FLIP 95
#define OLED_SEGMENT_MAP 0xA0
#endif
#define FRAMEBUFFER_START 17
enum class FontStyle {
@@ -51,9 +74,9 @@ public:
static bool isInitDone();
// Draw the buffer out to the LCD if any content has changed.
static void refresh() {
if (checkDisplayBufferChecksum()) {
const int len = FRAMEBUFFER_START + (OLED_WIDTH * 2);
const int len = FRAMEBUFFER_START + (OLED_WIDTH * 2);
I2C_CLASS::Transmit(DEVICEADDR_OLED, screenBuffer, len);
// DMA tx time is ~ 20mS Ensure after calling this you delay for at least 25ms
// or we need to goto double buffering
@@ -114,17 +137,17 @@ public:
static void transitionScrollDown();
private:
static bool checkDisplayBufferChecksum(){
uint32_t hash = 0;
static bool checkDisplayBufferChecksum() {
uint32_t hash = 0;
const int len = FRAMEBUFFER_START + (OLED_WIDTH * 2);
for (int i = 0; i < len; i++) {
hash += (i * screenBuffer[i]);
}
bool result = hash!=displayChecksum;
displayChecksum= hash;
bool result = hash != displayChecksum;
displayChecksum = hash;
return result;
}
}
static void drawChar(uint16_t charCode, FontStyle fontStyle); // Draw a character to the current cursor location
static void setFramebuffer(uint8_t *buffer);
static uint8_t *firstStripPtr; // Pointers to the strips to allow for buffer having extra content

View File

@@ -1,6 +1,6 @@
#include "USBPD.h"
#include "configuration.h"
#if POW_PD
#ifdef POW_PD
#include "BSP_PD.h"
#include "FreeRTOS.h"

View File

@@ -6,7 +6,7 @@
#include <stdint.h>
#ifdef __cplusplus
#if POW_PD
#ifdef POW_PD
class USBPowerDelivery {
public:
static bool start(); // Start the PD stack

View File

@@ -5,19 +5,30 @@
* Author: Ralim
*/
#include "BSP_Power.h"
#include "configuration.h"
#include <Utils.h>
int32_t Utils::InterpolateLookupTable(const int32_t *lookupTable, const int noItems, const int32_t value) {
if (value) {
for (int i = 1; i < (noItems - 1); i++) {
// If current tip temp is less than current lookup, then this current lookup is the higher point to interpolate
if (value < lookupTable[i * 2]) {
return LinearInterpolate(lookupTable[(i - 1) * 2], lookupTable[((i - 1) * 2) + 1], lookupTable[i * 2], lookupTable[(i * 2) + 1], value);
}
for (int i = 1; i < (noItems - 1); i++) {
// If current tip temp is less than current lookup, then this current lookup is the higher point to interpolate
if (value < lookupTable[i * 2]) {
return LinearInterpolate(lookupTable[(i - 1) * 2], lookupTable[((i - 1) * 2) + 1], lookupTable[i * 2], lookupTable[(i * 2) + 1], value);
}
return LinearInterpolate(lookupTable[(noItems - 2) * 2], lookupTable[((noItems - 2) * 2) + 1], lookupTable[(noItems - 1) * 2], lookupTable[((noItems - 1) * 2) + 1], value);
}
return 0;
return LinearInterpolate(lookupTable[(noItems - 2) * 2], lookupTable[((noItems - 2) * 2) + 1], lookupTable[(noItems - 1) * 2], lookupTable[((noItems - 1) * 2) + 1], value);
}
int32_t Utils::LinearInterpolate(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x) { return y1 + (((((x - x1) * 1000) / (x2 - x1)) * (y2 - y1))) / 1000; }
uint16_t Utils::RequiredCurrentForTipAtVoltage(uint16_t voltageX10) {
uint8_t tipResistancex10 = getTipResistanceX10() + 5;
#ifdef MODEL_HAS_DCDC
// If this device has step down DC/DC inductor to smooth out current spikes
// We can instead ignore resistance and go for max voltage we can accept; and rely on the DC/DC regulation to keep under current limit
tipResistancex10 = 255; // (Push to 25.5 ohms to effectively disable this check)
#endif
// V/R = I
uint16_t currentX10 = (voltageX10 * 10) / tipResistancex10;
return currentX10;
}

View File

@@ -12,6 +12,10 @@ class Utils {
public:
static int32_t InterpolateLookupTable(const int32_t *lookupTable, const int noItems, const int32_t value);
static int32_t LinearInterpolate(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t x);
// Return the required current in X10 for the specified voltage
static uint16_t RequiredCurrentForTipAtVoltage(uint16_t voltageX10);
};
#endif /* CORE_DRIVERS_UTILS_H_ */