Skip to content

Commit

Permalink
Pinecil v2 tune via PID (#1827)
Browse files Browse the repository at this point in the history
* Start PWM after adc irq fully done

* Filter len 4

* Use comparitor 2 on timer for wrap around

* Update IRQ.cpp

* Tip measurements are uint16_t

Update BSP.cpp

Update BSP.cpp

* WiP PID

move pid tuning to config

Update PIDThread.cpp

* Handle PWM Timer gitchy comparitor

* Tuning

* Dampen with Kd

* Cleaning up

* Use TemperatureType_t for getTipTemp()

* Add small rolling average to user GUI temp to reduce flicker

* Trigger PID when adc is skipped (will use old values)
  • Loading branch information
Ralim authored Oct 20, 2023
1 parent 9c7ad43 commit c308fe8
Show file tree
Hide file tree
Showing 16 changed files with 271 additions and 178 deletions.
5 changes: 2 additions & 3 deletions source/Core/BSP/BSP_Power.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ void power_check();
// Returns the tip resistance in x10 ohms, so 7.5 = 75; 14=140 etc
uint8_t getTipResistanceX10();

uint8_t getTipThermalMass();
uint8_t getTipInertia();

uint16_t getTipThermalMass();
uint16_t getTipInertia();

#ifdef __cplusplus
}
Expand Down
4 changes: 2 additions & 2 deletions source/Core/BSP/MHP30/BSP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ uint64_t getDeviceID() {

uint8_t preStartChecksDone() { return 1; }

uint8_t getTipThermalMass() { return TIP_THERMAL_MASS; }
uint8_t getTipInertia() { return TIP_THERMAL_MASS; }
uint16_t getTipThermalMass() { return TIP_THERMAL_MASS; }
uint16_t getTipInertia() { return TIP_THERMAL_MASS; }

void showBootLogo(void) { BootLogo::handleShowingLogo((uint8_t *)FLASH_LOGOADDR); }
4 changes: 2 additions & 2 deletions source/Core/BSP/Miniware/BSP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ bool isTipShorted() { return tipShorted; }
#else
bool isTipShorted() { return false; }
#endif
uint8_t getTipThermalMass() {
uint16_t getTipThermalMass() {
#ifdef TIP_RESISTANCE_SENSE_Pin
if (lastTipResistance >= 80) {
return TIP_THERMAL_MASS;
Expand All @@ -406,7 +406,7 @@ uint8_t getTipThermalMass() {
return TIP_THERMAL_MASS;
#endif
}
uint8_t getTipInertia() {
uint16_t getTipInertia() {
#ifdef TIP_RESISTANCE_SENSE_Pin
if (lastTipResistance >= 80) {
return TIP_THERMAL_MASS;
Expand Down
4 changes: 2 additions & 2 deletions source/Core/BSP/Pinecil/BSP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ uint8_t getTipResistanceX10() { return TIP_RESISTANCE; }
bool isTipShorted() { return false; }
uint8_t preStartChecksDone() { return 1; }

uint8_t getTipThermalMass() { return TIP_THERMAL_MASS; }
uint8_t getTipInertia() { return TIP_THERMAL_MASS; }
uint16_t getTipThermalMass() { return TIP_THERMAL_MASS; }
uint16_t getTipInertia() { return TIP_THERMAL_MASS; }

void showBootLogo(void) { BootLogo::handleShowingLogo((uint8_t *)FLASH_LOGOADDR); }
16 changes: 3 additions & 13 deletions source/Core/BSP/Pinecilv2/BSP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,18 +160,8 @@ uint8_t getTipResistanceX10() {
return lastTipResistance;
}

uint8_t getTipThermalMass() {
if (lastTipResistance >= 80) {
return 65;
}
return 45;
}
uint8_t getTipInertia() {
if (lastTipResistance >= 80) {
return 90;
}
return 10;
}
uint16_t getTipThermalMass() { return 120; }
uint16_t getTipInertia() { return 750; }
// We want to calculate lastTipResistance
// If tip is connected, and the tip is cold and the tip is not being heated
// We can use the GPIO to inject a small current into the tip and measure this
Expand All @@ -180,7 +170,7 @@ uint8_t getTipInertia() {
// Which is around 0.54mA this will induce:
// 6 ohm tip -> 3.24mV (Real world ~= 3320)
// 8 ohm tip -> 4.32mV (Real world ~= 4500)
// Which is definitely measureable
// Which is definitely measurable
// Taking shortcuts here as we know we only really have to pick apart 6 and 8 ohm tips
// These are reported as 60 and 75 respectively
void performTipResistanceSampleReading() {
Expand Down
71 changes: 46 additions & 25 deletions source/Core/BSP/Pinecilv2/IRQ.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ extern "C" {
}
void start_PWM_output(void);

#define ADC_Filter_Smooth 1
#define ADC_Filter_Smooth 4 /* This basically smooths over one PWM cycle / set of readings */
history<uint16_t, ADC_Filter_Smooth> ADC_Vin;
history<uint16_t, ADC_Filter_Smooth> ADC_Temp;
history<uint16_t, ADC_Filter_Smooth> ADC_Tip;
volatile uint8_t ADCBurstCounter = 0;
void adc_fifo_irq(void) {

// IRQ is called at the end of the 8 set readings, pop these from the FIFO and send to filters
void adc_fifo_irq(void) {
if (ADC_GetIntStatus(ADC_INT_FIFO_READY) == SET) {
// Read out all entries in the fifo
while (ADC_Get_FIFO_Count()) {
ADCBurstCounter++;
volatile uint32_t reading = ADC_Read_FIFO();
uint32_t reading = ADC_Read_FIFO();
// As per manual, 26 bit reading; lowest 16 are the ADC
uint16_t sample = reading & 0xFFFF;
uint8_t source = (reading >> 21) & 0b11111;
Expand All @@ -43,23 +43,16 @@ void adc_fifo_irq(void) {
case VIN_ADC_CHANNEL:
ADC_Vin.update(sample);
break;

default:
break;
}
}

if (ADCBurstCounter >= 8) {
ADCBurstCounter = 0;
start_PWM_output();

// unblock the PID controller thread
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (pidTaskNotification) {
vTaskNotifyGiveFromISR(pidTaskNotification, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
// unblock the PID controller thread
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (pidTaskNotification) {
vTaskNotifyGiveFromISR(pidTaskNotification, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
}
Expand Down Expand Up @@ -100,16 +93,43 @@ void start_PWM_output(void) {
PWM_Channel_Disable(PWM_Channel);
switchToFastPWM();
}
TIMER_Enable(TIMER_CH0);
}

// Timer 0 is used to co-ordinate the ADC and the output PWM
void timer0_comp0_callback(void) {
TIMER_Disable(TIMER_CH0);
ADC_Start();
if (PWM_Channel_Is_Enabled(PWM_Channel)) {
// So there appears to be a bug _somewhere_ where sometimes the comparator doesn't fire
// Its not re-occurring with specific values, so suspect its a weird bug
// For now, we just skip the cycle and throw away the ADC readings. Its a waste but
// It stops stupid glitches in readings, i'd take slight instability from the time jump
// Over the readings we get that are borked as the header is left on
// <Ralim 2023/10/14>
PWM_Channel_Disable(PWM_Channel);
// MSG("ALERT PWM Glitch\r\n");
// Triger the PID now instead
if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (pidTaskNotification) {
vTaskNotifyGiveFromISR(pidTaskNotification, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
}
} else {
ADC_Start();
}
TIMER_ClearIntStatus(TIMER_CH0, TIMER_COMP_ID_0);
}
void timer0_comp1_callback(void) {
// Trigged at end of output cycle; turn off the tip PWM
PWM_Channel_Disable(PWM_Channel);
TIMER_ClearIntStatus(TIMER_CH0, TIMER_COMP_ID_1);
}
void timer0_comp1_callback(void) { PWM_Channel_Disable(PWM_Channel); } // Trigged at end of output cycle; turn off the tip PWM

void timer0_comp2_callback(void) {
// Triggered at end of timer cycle; re-start the tip driver
start_PWM_output();
TIMER_ClearIntStatus(TIMER_CH0, TIMER_COMP_ID_2);
}
void switchToFastPWM(void) {
inFastPWMMode = true;
holdoffTicks = 10;
Expand All @@ -119,8 +139,8 @@ void switchToFastPWM(void) {

// ~10Hz
TIMER_SetCompValue(TIMER_CH0, TIMER_COMP_ID_0, powerPWM + holdoffTicks);
// Set divider to 10 ~= 10.5Hz

// Set divider to 10 ~= 10.5Hz
uint32_t tmpVal = BL_RD_REG(TIMER_BASE, TIMER_TCDR);

tmpVal = BL_SET_REG_BITS_VAL(tmpVal, TIMER_TCDR2, 10);
Expand All @@ -139,7 +159,7 @@ void switchToSlowPWM(void) {
// Adjust ADC
TIMER_SetCompValue(TIMER_CH0, TIMER_COMP_ID_0, powerPWM + holdoffTicks);

// Set divider to 22
// Set divider for ~ 5Hz

uint32_t tmpVal = BL_RD_REG(TIMER_BASE, TIMER_TCDR);

Expand Down Expand Up @@ -193,5 +213,6 @@ uint16_t getADCHandleTemp(uint8_t sample) { return ADC_Temp.average(); }

uint16_t getADCVin(uint8_t sample) { return ADC_Vin.average(); }

// Returns either average or instant value. When sample is set the samples from the injected ADC are copied to the filter and then the raw reading is returned
// Returns the current raw tip reading after any cleanup filtering
// For Pinecil V2 we dont do any rolling filtering other than just averaging all 4 readings in the adc snapshot
uint16_t getTipRawTemp(uint8_t sample) { return ADC_Tip.average() >> 1; }
27 changes: 15 additions & 12 deletions source/Core/BSP/Pinecilv2/Setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ void setup_adc(void) {

adc_cfg.clkDiv = ADC_CLK_DIV_4;
adc_cfg.vref = ADC_VREF_3P2V;
adc_cfg.resWidth = ADC_DATA_WIDTH_14_WITH_64_AVERAGE;
adc_cfg.resWidth = ADC_DATA_WIDTH_14_WITH_16_AVERAGE;
adc_cfg.inputMode = ADC_INPUT_SINGLE_END;
adc_cfg.v18Sel = ADC_V18_SEL_1P72V;
adc_cfg.v11Sel = ADC_V11_SEL_1P1V;
Expand All @@ -111,7 +111,7 @@ void setup_adc(void) {
adc_cfg.chopMode = ADC_CHOP_MOD_AZ_ON;
adc_cfg.biasSel = ADC_BIAS_SEL_MAIN_BANDGAP;
adc_cfg.vcm = ADC_PGA_VCM_1P6V;
adc_cfg.offsetCalibEn = ENABLE;
adc_cfg.offsetCalibEn = DISABLE;
adc_cfg.offsetCalibVal = 0;

ADC_Disable();
Expand All @@ -120,7 +120,7 @@ void setup_adc(void) {

ADC_Init(&adc_cfg);
adc_fifo_cfg.dmaEn = DISABLE;
adc_fifo_cfg.fifoThreshold = ADC_FIFO_THRESHOLD_8;
adc_fifo_cfg.fifoThreshold = ADC_FIFO_THRESHOLD_8; // Triger FIFO when all 8 measurements are done
ADC_FIFO_Cfg(&adc_fifo_cfg);
ADC_MIC_Bias_Disable();
ADC_Tsen_Disable();
Expand All @@ -138,26 +138,29 @@ void setup_timer_scheduler() {
TIMER_Disable(TIMER_CH0);

TIMER_CFG_Type cfg = {
TIMER_CH0, // Channel
TIMER_CLKSRC_32K, // Clock source
TIMER_PRELOAD_TRIG_COMP0, // Trigger; reset after trigger 0
TIMER_COUNT_PRELOAD, // Counter mode
22, // Clock div
(uint16_t)(powerPWM + holdoffTicks), // CH0 compare (adc)
0, // CH1 compare (pwm out)
0, // CH2 compare not used
0, // Preload
TIMER_CH0, // Channel
TIMER_CLKSRC_32K, // Clock source
TIMER_PRELOAD_TRIG_COMP2, // Trigger; reset after trigger 0
TIMER_COUNT_PRELOAD, // Counter mode
22, // Clock div
(uint16_t)(powerPWM + holdoffTicks), // CH0 compare (adc)
(uint16_t)(powerPWM), // CH1 compare (pwm out)
(uint16_t)(powerPWM + holdoffTicks + tempMeasureTicks), // CH2 compare end of cycle
0, // Preload
};
TIMER_Init(&cfg);

Timer_Int_Callback_Install(TIMER_CH0, TIMER_INT_COMP_0, timer0_comp0_callback);
Timer_Int_Callback_Install(TIMER_CH0, TIMER_INT_COMP_1, timer0_comp1_callback);
Timer_Int_Callback_Install(TIMER_CH0, TIMER_INT_COMP_2, timer0_comp2_callback);

TIMER_ClearIntStatus(TIMER_CH0, TIMER_COMP_ID_0);
TIMER_ClearIntStatus(TIMER_CH0, TIMER_COMP_ID_1);
TIMER_ClearIntStatus(TIMER_CH0, TIMER_COMP_ID_2);

TIMER_IntMask(TIMER_CH0, TIMER_INT_COMP_0, UNMASK);
TIMER_IntMask(TIMER_CH0, TIMER_INT_COMP_1, UNMASK);
TIMER_IntMask(TIMER_CH0, TIMER_INT_COMP_2, UNMASK);
CPU_Interrupt_Enable(TIMER_CH0_IRQn);
TIMER_Enable(TIMER_CH0);
}
Expand Down
Loading

0 comments on commit c308fe8

Please sign in to comment.