Fix normal solder screen issues, disable I2C DMA pending some testing

This commit is contained in:
Ben V. Brown
2018-12-16 16:16:31 +11:00
parent 21afc3e898
commit b744f51e2d
14 changed files with 287 additions and 93 deletions

View File

@@ -6,7 +6,7 @@
*/
#include "FRToSI2C.hpp"
//#define I2CUSESDMA
I2C_HandleTypeDef* FRToSI2C::i2c;
SemaphoreHandle_t FRToSI2C::I2CSemaphore;
void FRToSI2C::CpltCallback() {
@@ -20,6 +20,7 @@ void FRToSI2C::CpltCallback() {
void FRToSI2C::Mem_Read(uint16_t DevAddress, uint16_t MemAddress,
uint16_t MemAddSize, uint8_t* pData, uint16_t Size) {
#ifdef I2CUSESDMA
if (I2CSemaphore == NULL) {
// no RToS, run blocking code
HAL_I2C_Mem_Read(i2c, DevAddress, MemAddress, MemAddSize, pData, Size,
@@ -36,6 +37,10 @@ void FRToSI2C::Mem_Read(uint16_t DevAddress, uint16_t MemAddress,
} else {
}
}
#else
HAL_I2C_Mem_Read(i2c, DevAddress, MemAddress, MemAddSize, pData, Size,
5000);
#endif
}
void FRToSI2C::I2C_RegisterWrite(uint8_t address, uint8_t reg, uint8_t data) {
Mem_Write(address, reg, I2C_MEMADD_SIZE_8BIT, &data, 1);
@@ -48,6 +53,7 @@ uint8_t FRToSI2C::I2C_RegisterRead(uint8_t add, uint8_t reg) {
}
void FRToSI2C::Mem_Write(uint16_t DevAddress, uint16_t MemAddress,
uint16_t MemAddSize, uint8_t* pData, uint16_t Size) {
#ifdef I2CUSESDMA
if (I2CSemaphore == NULL) {
// no RToS, run blocking code
HAL_I2C_Mem_Write(i2c, DevAddress, MemAddress, MemAddSize, pData, Size,
@@ -65,9 +71,14 @@ void FRToSI2C::Mem_Write(uint16_t DevAddress, uint16_t MemAddress,
} else {
}
}
#else
HAL_I2C_Mem_Write(i2c, DevAddress, MemAddress, MemAddSize, pData, Size,
5000);
#endif
}
void FRToSI2C::Transmit(uint16_t DevAddress, uint8_t* pData, uint16_t Size) {
#ifdef I2CUSESDMA
if (I2CSemaphore == NULL) {
// no RToS, run blocking code
HAL_I2C_Master_Transmit(i2c, DevAddress, pData, Size, 5000);
@@ -82,4 +93,7 @@ void FRToSI2C::Transmit(uint16_t DevAddress, uint8_t* pData, uint16_t Size) {
} else {
}
}
#else
HAL_I2C_Master_Transmit(i2c, DevAddress, pData, Size, 5000);
#endif
}

View File

@@ -107,7 +107,7 @@ void resetSettings() {
systemSettings.PID_P = 42; // PID tuning constants
systemSettings.PID_I = 50;
systemSettings.PID_D = 15;
systemSettings.CalibrationOffset = 2780; // the adc offset
systemSettings.CalibrationOffset = 1400; // the adc offset
systemSettings.customTipGain =
0; // The tip type is either default or a custom gain
#ifdef MODEL_TS100

View File

@@ -329,7 +329,7 @@ static void MX_TIM2_Init(void) {
HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 255+50; //255 is the largest time period of the drive signal, and the 47 offsets this around 5ms afterwards
sConfigOC.Pulse = 255+50; //255 is the largest time period of the drive signal, and the 50 offsets this around 5ms afterwards
/*
* It takes 4 milliseconds for output to be stable after PWM turns off.
* Assume ADC samples in 0.5ms
@@ -348,6 +348,7 @@ static void MX_TIM2_Init(void) {
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_PWM_Start_IT(&htim2, TIM_CHANNEL_4);
HAL_NVIC_SetPriority(TIM2_IRQn, 15, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}

View File

@@ -662,6 +662,10 @@ static void setTipOffset() {
osDelay(333);
}
systemSettings.CalibrationOffset = offset / 15;
// Need to remove from this the ambient temperature offset
uint32_t ambientoffset = getHandleTemperature(); // Handle temp in C
ambientoffset *=1000;
ambientoffset /= tipGainCalValue;
setCalibrationOffset(systemSettings.CalibrationOffset); // store the error
osDelay(100);
}
@@ -812,10 +816,10 @@ static void settings_setCalibrateVIN(void) {
for (;;) {
OLED::setCursor(0, 0);
OLED::printNumber(getInputVoltageX10(systemSettings.voltageDiv) / 10,
OLED::printNumber(getInputVoltageX10(systemSettings.voltageDiv,0) / 10,
2);
OLED::print(".");
OLED::printNumber(getInputVoltageX10(systemSettings.voltageDiv) % 10,
OLED::printNumber(getInputVoltageX10(systemSettings.voltageDiv,0) % 10,
1);
OLED::print("V");

View File

@@ -127,7 +127,7 @@ uint16_t getTipRawTemp(uint8_t refresh) {
return lastSample;
}
uint16_t getInputVoltageX10(uint16_t divisor) {
uint16_t getInputVoltageX10(uint16_t divisor, uint8_t sample) {
// ADC maximum is 32767 == 3.3V at input == 28.05V at VIN
// Therefore we can divide down from there
// Multiplying ADC max by 4 for additional calibration options,
@@ -141,16 +141,16 @@ uint16_t getInputVoltageX10(uint16_t divisor) {
samples[i] = getADC(1);
preFillneeded--;
}
samples[index] = getADC(1);
index = (index + 1) % BATTFILTERDEPTH;
if (sample) {
samples[index] = getADC(1);
index = (index + 1) % BATTFILTERDEPTH;
}
uint32_t sum = 0;
for (uint8_t i = 0; i < BATTFILTERDEPTH; i++)
sum += samples[i];
sum /= BATTFILTERDEPTH;
if (sum < 50)
preFillneeded = 1;
return sum * 4 / divisor;
}
#ifdef MODEL_TS80
@@ -170,7 +170,7 @@ void seekQC(int16_t Vx10, uint16_t divisor) {
// try and step towards the wanted value
// 1. Measure current voltage
int16_t vStart = getInputVoltageX10(divisor);
int16_t vStart = getInputVoltageX10(divisor, 0);
int difference = Vx10 - vStart;
// 2. calculate ideal steps (0.2V changes)
@@ -185,7 +185,7 @@ void seekQC(int16_t Vx10, uint16_t divisor) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET); //-0.6V
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_IWDG_Refresh(&hiwdg);
HAL_Delay(1);
steps++;
}
@@ -199,7 +199,7 @@ void seekQC(int16_t Vx10, uint16_t divisor) {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
HAL_IWDG_Refresh(&hiwdg);
HAL_Delay(1);
steps--;
}
@@ -235,7 +235,7 @@ void seekQC(int16_t Vx10, uint16_t divisor) {
void startQC(uint16_t divisor) {
// Pre check that the input could be >5V already, and if so, dont both
// negotiating as someone is feeding in hv
uint16_t vin = getInputVoltageX10(divisor);
uint16_t vin = getInputVoltageX10(divisor, 1);
if (vin > 150)
return; // Over voltage
if (vin > 100) {
@@ -275,7 +275,7 @@ void startQC(uint16_t divisor) {
for (uint16_t i = 0; i < 130 && enteredQC == 0; i++) {
// HAL_Delay(10);
vTaskDelay(1);
HAL_IWDG_Refresh(&hiwdg);
}
// Check if D- is low to spot a QC charger
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == GPIO_PIN_RESET)
@@ -292,12 +292,11 @@ void startQC(uint16_t divisor) {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
HAL_IWDG_Refresh(&hiwdg);
// Wait for frontend ADC to stabilise
QCMode = 4;
for (uint8_t i = 0; i < 10; i++) {
if (getInputVoltageX10(divisor) > 80) {
if (getInputVoltageX10(divisor, 1) > 80) {
// yay we have at least QC2.0 or QC3.0
QCMode = 3; // We have at least QC2, pray for 3
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
@@ -321,8 +320,8 @@ void startQC(uint16_t divisor) {
}
// Get tip resistance in milliohms
uint32_t calculateTipR() {
static uint32_t lastRes=0;
if(lastRes)
static uint32_t lastRes = 0;
if (lastRes)
return lastRes;
// We inject a small current into the front end of the iron,
// By measuring the Vdrop over the tip we can calculate the resistance
@@ -340,6 +339,7 @@ uint32_t calculateTipR() {
uint32_t offReading = getTipRawTemp(1);
for (uint8_t i = 0; i < 49; i++) {
vTaskDelay(1); // delay to allow it to stabilize
HAL_IWDG_Refresh(&hiwdg);
offReading += getTipRawTemp(1);
}
@@ -349,6 +349,7 @@ uint32_t calculateTipR() {
uint32_t onReading = getTipInstantTemperature();
for (uint8_t i = 0; i < 49; i++) {
vTaskDelay(1); // delay to allow it to stabilize
HAL_IWDG_Refresh(&hiwdg);
onReading += getTipRawTemp(1);
}
@@ -362,7 +363,7 @@ uint32_t calculateTipR() {
// 4688 milliohms (Measured using 4 terminal measurement) 25x oversampling
// reads this as around 47490 Almost perfectly 10x the milliohms value This
// will drift massively with tip temp However we really only need 10x ohms
lastRes=(difference / 21) + 1; // ceil
lastRes = (difference / 21) + 1; // ceil
return lastRes;
}
static unsigned int sqrt32(unsigned long n) {
@@ -423,8 +424,8 @@ uint8_t getTipPWM() {
return pendingPWM;
}
void setTipPWM(uint8_t pulse) {
PWMSafetyTimer = 2; // This is decremented in the handler for PWM so that the tip pwm is
// disabled if the PID task is not scheduled often enough.
PWMSafetyTimer = 50; // This is decremented in the handler for PWM so that the tip pwm is
// disabled if the PID task is not scheduled often enough.
pendingPWM = pulse;
}
@@ -436,9 +437,10 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
// Period has elapsed
if (htim->Instance == TIM2) {
// we want to turn on the output again
PWMSafetyTimer--; // We decrement this safety value so that lockups in the
// scheduler will not cause the PWM to become locked in an
// active driving state.
PWMSafetyTimer--;
// We decrement this safety value so that lockups in the
// scheduler will not cause the PWM to become locked in an
// active driving state.
// While we could assume this could never happen, its a small price for
// increased safety
htim2.Instance->CCR4 = pendingPWM;

View File

@@ -15,7 +15,7 @@
#define ACCELDEBUG 0
uint8_t PCBVersion = 0;
// File local variables
uint16_t currentlyActiveTemperatureTarget = 0;
uint32_t currentlyActiveTemperatureTarget = 0;
uint32_t lastMovementTime = 0;
uint32_t lastButtonTime = 0;
int16_t idealQCVoltage = 0;
@@ -59,7 +59,6 @@ int main(void) {
systemSettings.SleepTime = 0;
systemSettings.ShutdownTime = 0; // No accel -> disable sleep
systemSettings.sensitivity = 0;
saveSettings();
}
HAL_IWDG_Refresh(&hiwdg);
restoreSettings(); // load the settings from flash
@@ -70,15 +69,15 @@ int main(void) {
/* Create the thread(s) */
/* definition and creation of GUITask */
osThreadDef(GUITask, startGUITask, osPriorityBelowNormal, 0, 768); // 3k
osThreadDef(GUITask, startGUITask, osPriorityBelowNormal, 0, 4 * 1024 / 4);
GUITaskHandle = osThreadCreate(osThread(GUITask), NULL);
/* definition and creation of PIDTask */
osThreadDef(PIDTask, startPIDTask, osPriorityRealtime, 0, 512); // 2k
osThreadDef(PIDTask, startPIDTask, osPriorityRealtime, 0, 2 * 1024 / 4);
PIDTaskHandle = osThreadCreate(osThread(PIDTask), NULL);
if (PCBVersion < 3) {
/* definition and creation of MOVTask */
osThreadDef(MOVTask, startMOVTask, osPriorityNormal, 0, 512); // 2k
osThreadDef(MOVTask, startMOVTask, osPriorityNormal, 0, 2 * 1024 / 4);
MOVTaskHandle = osThreadCreate(osThread(MOVTask), NULL);
}
@@ -91,9 +90,10 @@ int main(void) {
}
void printVoltage() {
OLED::printNumber(getInputVoltageX10(systemSettings.voltageDiv) / 10, 2);
uint32_t volt = getInputVoltageX10(systemSettings.voltageDiv, 0);
OLED::printNumber(volt / 10, 2);
OLED::drawChar('.');
OLED::printNumber(getInputVoltageX10(systemSettings.voltageDiv) % 10, 1);
OLED::printNumber(volt % 10, 1);
}
void GUIDelay() {
// Called in all UI looping tasks,
@@ -201,12 +201,10 @@ void waitForButtonPress() {
while (buttons) {
buttons = getButtonState();
GUIDelay();
GUIDelay();
}
while (!buttons) {
buttons = getButtonState();
GUIDelay();
GUIDelay();
}
}
@@ -231,10 +229,12 @@ void waitForButtonPressOrTimeout(uint32_t timeout) {
#ifdef MODEL_TS100
// returns true if undervoltage has occured
static bool checkVoltageForExit() {
uint16_t v = getInputVoltageX10(systemSettings.voltageDiv);
uint16_t v = getInputVoltageX10(systemSettings.voltageDiv, 0);
//Dont check for first 1.5 seconds while the ADC stabilizes and the DMA fills the buffer
if(xTaskGetTickCount()>150) {
if (xTaskGetTickCount() > 150) {
if ((v < lookupVoltageLevel(systemSettings.cutoutSetting))) {
GUIDelay();
OLED::clearScreen();
OLED::setCursor(0, 0);
if (systemSettings.detailedSoldering) {
@@ -265,7 +265,7 @@ static void gui_drawBatteryIcon() {
// User is on a lithium battery
// we need to calculate which of the 10 levels they are on
uint8_t cellCount = systemSettings.cutoutSetting + 2;
uint16_t cellV = getInputVoltageX10(systemSettings.voltageDiv)
uint16_t cellV = getInputVoltageX10(systemSettings.voltageDiv, 0)
/ cellCount;
// Should give us approx cell voltage X10
// Range is 42 -> 33 = 9 steps therefore we will use battery 1-10
@@ -280,7 +280,7 @@ static void gui_drawBatteryIcon() {
#else
// On TS80 we replace this symbol with the voltage we are operating on
// If <9V then show single digit, if not show duals
uint8_t V = getInputVoltageX10(systemSettings.voltageDiv);
uint8_t V = getInputVoltageX10(systemSettings.voltageDiv, 0);
if (V % 10 >= 5)
V = V / 10 + 1; // round up
else
@@ -506,8 +506,8 @@ static void gui_solderingMode(uint8_t jumpToSleep) {
sleepThres = systemSettings.SleepTime * 10 * 100;
else
sleepThres = (systemSettings.SleepTime - 5) * 60 * 100;
for (;;) {
uint16_t tipTemp = getTipRawTemp(0);
ButtonState buttons = getButtonState();
switch (buttons) {
@@ -543,13 +543,16 @@ static void gui_solderingMode(uint8_t jumpToSleep) {
OLED::setCursor(0, 0);
OLED::clearScreen();
OLED::setFont(0);
uint16_t tipTemp = getTipRawTemp(0);
if (tipTemp > 32752) {
OLED::print(BadTipString);
OLED::refresh();
currentlyActiveTemperatureTarget = 0;
waitForButtonPress();
currentlyActiveTemperatureTarget = 0;
return;
} else {
OLED::setCursor(0, 0);
if (systemSettings.detailedSoldering) {
OLED::setFont(1);
OLED::print(SolderingAdvancedPowerPrompt); // Power:
@@ -570,6 +573,7 @@ static void gui_solderingMode(uint8_t jumpToSleep) {
printVoltage();
OLED::drawChar('V');
} else {
OLED::setFont(0);
// We switch the layout direction depending on the orientation of the
// OLED::
if (OLED::getRotation()) {
@@ -587,10 +591,10 @@ static void gui_solderingMode(uint8_t jumpToSleep) {
OLED::drawChar(' ');
// Draw heating/cooling symbols
OLED::drawHeatSymbol(getTipPWM());
OLED::drawHeatSymbol(milliWattsToPWM(milliWattHistory[0],systemSettings.voltageDiv));
} else {
// Draw heating/cooling symbols
OLED::drawHeatSymbol(getTipPWM());
OLED::drawHeatSymbol(milliWattsToPWM(milliWattHistory[0],systemSettings.voltageDiv));
// We draw boost arrow if boosting, or else gap temp <-> heat
// indicator
if (boostModeOn)
@@ -633,8 +637,9 @@ static void gui_solderingMode(uint8_t jumpToSleep) {
}
#else
// on the TS80 we only want to check for over voltage to prevent tip damage
if (getInputVoltageX10(systemSettings.voltageDiv) > 150) {
if (getInputVoltageX10(systemSettings.voltageDiv, 1) > 150) {
lastButtonTime = xTaskGetTickCount();
currentlyActiveTemperatureTarget = 0;
return; // Over voltage
}
#endif
@@ -662,8 +667,7 @@ __DATE__, "Heap: ", "HWMG: ", "HWMP: ", "HWMM: ", "Time: ", "Move: ", "RTip: ",
#ifdef MODEL_TS80
"QCV: ", "Tr ",
#else
"Tm ",
"Ralim-",
"Tm ", "Ralim-",
#endif
};
@@ -835,7 +839,7 @@ void startGUITask(void const *argument __unused) {
}
currentlyActiveTemperatureTarget = 0; // ensure tip is off
getInputVoltageX10(systemSettings.voltageDiv, 0);
uint16_t tipTemp = tipMeasurementToC(getTipRawTemp(0));
if (tipTemp < 50) {
@@ -862,10 +866,7 @@ void startGUITask(void const *argument __unused) {
OLED::print(TipDisconnectedString);
} else {
OLED::print(IdleTipString);
if (systemSettings.temperatureInF)
OLED::printNumber(tipMeasurementToF(getTipRawTemp(0)), 3);
else
OLED::printNumber(tipMeasurementToC(getTipRawTemp(0)), 3);
gui_drawTipTemp(false);
OLED::print(IdleSetString);
OLED::printNumber(systemSettings.SolderingTemp, 3);
}
@@ -934,8 +935,7 @@ void startPIDTask(void const *argument __unused) {
idealQCVoltage = calculateMaxVoltage(systemSettings.cutoutSetting);
#endif
uint8_t rawC = ctoTipMeasurement(101) - ctoTipMeasurement(100); // 1*C change in raw.
currentlyActiveTemperatureTarget = 0; // Force start with no output (off). If in sleep / soldering this will
// be over-ridden rapidly
#ifdef MODEL_TS80
//Set power management code to the tip resistance in ohms * 10
setupPower(calculateTipR() / 100);
@@ -944,13 +944,13 @@ void startPIDTask(void const *argument __unused) {
setupPower(85);
#endif
history<int16_t> tempError = { { 0 }, 0, 0 };
history<int32_t> tempError = { { 0 }, 0, 0 };
currentlyActiveTemperatureTarget = 0; // Force start with no output (off). If in sleep / soldering this will
// be over-ridden rapidly
pidTaskNotification = xTaskGetCurrentTaskHandle();
for (;;) {
if (ulTaskNotifyTake(pdTRUE, 1000)) {
// Wait a max of 50ms
if (ulTaskNotifyTake(pdTRUE, 2000)) {
// This is a call to block this thread until the ADC does its samples
uint16_t rawTemp = getTipRawTemp(1); // get instantaneous reading
if (currentlyActiveTemperatureTarget) {
@@ -958,13 +958,16 @@ void startPIDTask(void const *argument __unused) {
if (currentlyActiveTemperatureTarget > ctoTipMeasurement(450)) {
currentlyActiveTemperatureTarget = ctoTipMeasurement(450);
}
if (currentlyActiveTemperatureTarget > 32500) {
currentlyActiveTemperatureTarget = 32500;
}
// As we get close to our target, temp noise causes the system
// to be unstable. Use a rolling average to dampen it.
// We overshoot by roughly 1/2 of 1 degree Fahrenheit.
// This helps stabilize the display.
int32_t tError = currentlyActiveTemperatureTarget - rawTemp
+ rawC / 4;
+ (rawC / 4);
tError = tError > INT16_MAX ? INT16_MAX : tError;
tError = tError < INT16_MIN ? INT16_MIN : tError;
tempError.update(tError);
@@ -1011,15 +1014,16 @@ void startPIDTask(void const *argument __unused) {
//If its a TS80, we want to have the option of using an occasional pulse to keep the power bank on
//~200ms @ a low wattage
//Doesnt keep all power banks awake but helps with some
if (xTaskGetTickCount() - lastPowerPulse < 20) {
/*if (xTaskGetTickCount() - lastPowerPulse < 20) {
// for the first 200mS turn on for a bit
setTipMilliWatts(4000); // typically its around 5W to hold the current temp, so this wont raise temp much
setTipMilliWatts(4000); // typically its around 5W to hold the current temp, so this wont raise temp much
} else
setTipMilliWatts(0);
//Then wait until the next second
if (xTaskGetTickCount() - lastPowerPulse > 100) {
lastPowerPulse = xTaskGetTickCount();
}
}*/
setTipMilliWatts(0);
#else
setTipMilliWatts(0);
#endif
@@ -1027,9 +1031,9 @@ void startPIDTask(void const *argument __unused) {
HAL_IWDG_Refresh(&hiwdg);
} else {
if (currentlyActiveTemperatureTarget == 0) {
setTipMilliWatts(0);
}
//ADC interrupt timeout
setTipMilliWatts(0);
setTipPWM(0);
}
}
}
@@ -1040,8 +1044,8 @@ void startMOVTask(void const *argument __unused) {
#ifdef MODEL_TS80
startQC(systemSettings.voltageDiv);
while (idealQCVoltage == 0)
osDelay(20); // To ensure we return after idealQCVoltage is setup
while (pidTaskNotification == 0)
osDelay(20); // To ensure we return after idealQCVoltage/tip resistance
seekQC(idealQCVoltage, systemSettings.voltageDiv); // this will move the QC output to the preferred voltage to start with

View File

@@ -11,9 +11,9 @@
uint8_t tipResistance = 85; //x10 ohms, 8.5 typical for ts100, 4.5 typical for ts80
const uint16_t powerPWM = 255;
const uint16_t totalPWM = 255+50; // Setup.c:sConfigOC.Pulse, the full PWM cycle
const uint16_t totalPWM = 255 + 65; //htim2.Init.Period, the full PWM cycle
history<uint16_t, oscillationPeriod> milliWattHistory = { { 0 }, 0, 0 };
history<uint32_t, oscillationPeriod> milliWattHistory = { { 0 }, 0, 0 };
void setupPower(uint8_t res) {
tipResistance = res;
@@ -41,19 +41,23 @@ uint8_t milliWattsToPWM(int32_t milliWatts, uint8_t divisor) {
// R = R*10
// P therefore is in V^2*10/R = W*10.
// Scale input milliWatts to the pwm rate
int32_t v = getInputVoltageX10(divisor);// 100 = 10v
int32_t v = getInputVoltageX10(divisor, 1); // 100 = 10v
int32_t availableMilliWatts = v * v / tipResistance;
int32_t pwm = (powerPWM * totalPWM / powerPWM) * milliWatts / availableMilliWatts;
int32_t pwm = ((powerPWM * totalPWM / powerPWM) * milliWatts)
/ availableMilliWatts;
if (pwm > powerPWM) {
pwm = powerPWM;
} else if (pwm < 0) {
pwm = 0;
}
if (milliWatts == 0)
pwm = 0;
return pwm;
}
int32_t PWMToMilliWatts(uint8_t pwm, uint8_t divisor) {
int32_t v = getInputVoltageX10(divisor);
int32_t v = getInputVoltageX10(divisor, 0);
return pwm * (v * v / tipResistance) / (powerPWM * totalPWM / powerPWM);
}