void Atomizer_ReadInfo(Atomizer_Info_t *info) { uint32_t vSum, iSum; uint16_t savedTargetVolts = 0; uint8_t wasOff = 0, numSamples, i; if(Atomizer_curState == POWEROFF) { // Power on at 1.00V for measurement wasOff = 1; savedTargetVolts = Atomizer_targetVolts; Atomizer_SetOutputVoltage(1000); Atomizer_Control(1); Timer_DelayMs(2); } // Sample V and I vSum = iSum = 0; numSamples = wasOff ? 50 : 1; for(i = 0; i < numSamples; i++) { Timer_DelayUs(10); iSum += ADC_Read(ADC_MODULE_CURS); Timer_DelayUs(10); vSum += ADC_Read(ADC_MODULE_VATM); } info->resistance = ATOMIZER_ADC_RESISTANCE(vSum, iSum); if(wasOff) { info->voltage = info->current = 0; // Power off and restore previous target voltage Atomizer_Control(0); Atomizer_SetOutputVoltage(savedTargetVolts); } else { info->voltage = ATOMIZER_ADC_VOLTAGE(vSum); info->current = ATOMIZER_ADC_CURRENT(iSum); } }
void tempFire() { if (timerIndex == -1) timerIndex = requestTimerSlot(); setTarget(s.targetTemperature); initPid(); uint16_t newVolts = g.volts; int pidactive = 0; start = uptime; atTemp = 0; uint32_t nextFire = uptime; #ifdef PROFILING uint32_t beforeFire, afterFire, beforeScreenUpdate, afterScreenUpdate, beforeDumpPid, afterDumpPid, beforeTunePid, afterTunePid; uint32_t FireAve = 0, ScreenAve = 0, DumpPidAve = 0, TunePidAve = 0; uint32_t loopCnt = 0; #endif requestTimer(timerIndex, TimerHighRes); waitForFasterTimer(TimerHighRes); #ifdef PROFILING writeUsb("Fire\tScreen\tDumpPid\tTunePid\r\n"); #endif while (gv.fireButtonPressed) { #ifdef PROFILING loopCnt++; beforeFire = uptime; #endif // < 1ms if (uptime > nextFire) { nextFire += FIREPERIOD; if (!Atomizer_IsOn() && g.atomInfo.resistance != 0 && Atomizer_GetError() == OK) { // Power on Atomizer_Control(1); } // Update info // If resistance is zero voltage will be zero Atomizer_ReadInfo(&g.atomInfo); uint32_t sampled = uptime; EstimateCoilTemp(); if (pidactive) g.watts = getNext(g.curTemp, sampled); #ifdef PROFILING beforeTunePid = uptime; #endif // < 1ms ave if (uptime + 1 < nextFire) { if (s.tunePids) { if (1) { writeUsb("%ld,%d,%ld,%ld,%ld,%lld,%ld,%ld,%ld\r\n", s.targetTemperature, g.curTemp, I.P, I.Error, I.I, I.AveError, I.D, I.DiffError, g.watts); } } } #ifdef PROFILING afterTunePid = uptime; #endif // While the coil is 'cold', bad things can happen if you try to // Push it too hard. Don't consider kicking it up until we've at // least reached 150C if (g.curTemp > 150) { if (!pidactive) { if (s.targetTemperature - g.curTemp >= s.pidSwitch) { g.watts = s.initWatts; } else { if (s.dumpPids) { char b[63]; siprintf(b, "INFO,Switching to PID %" PRId32 " %d\r\n", s.targetTemperature, g.curTemp); USB_VirtualCOM_SendString(b); } pidactive = 1; } } } /* TODO: Maybe make this baseRes dependant // Don't allow firing > 1 ohm in temp mode. if (g.atomInfo.resistance > 1000) { g.watts = 0; } */ if (g.watts <= 1000) g.watts = 1000; if (g.watts > 100000) // Pid probably went c-razy on us, so drop watts. g.watts = 1000; if (g.watts > MAXWATTS) g.watts = MAXWATTS; newVolts = wattsToVolts(g.watts, g.atomInfo.resistance); } if (newVolts != g.volts) { uint16_t tNewVolts = newVolts; if (Atomizer_IsOn()) { // Update output voltage to correct res variations: // If the new voltage is lower, we only correct it in // 10mV steps, otherwise a flake res reading might // make the voltage plummet to zero and stop. // If the new voltage is higher, we push it up by 100mV // to make it hit harder on TC coils, but still keep it // under control. if (tNewVolts < g.volts) { uint16_t dV = (g.volts - tNewVolts); tNewVolts = g.volts - ( dV >= 75 ? 75 : dV); } else { uint16_t dV = (tNewVolts - g.volts); tNewVolts = g.volts + ( dV >= 75 ? 75 : dV); } } if (tNewVolts > MAXVOLTS) { tNewVolts = MAXVOLTS; } g.volts = tNewVolts; Atomizer_SetOutputVoltage(g.volts); } #ifdef PROFILING afterFire = beforeScreenUpdate = uptime; #endif // 7ms ave if (uptime + 7 < nextFire) { if (1) {// Update Screen Interval updateScreen(&g); if (s.stealthMode) { /* GROSS hack to fix stealthmode */ uint32_t b = uptime; do {;} while (b == uptime); } } } #ifdef PROFILING afterScreenUpdate = beforeDumpPid = uptime; #endif // <1ms ave if (uptime + 1 < nextFire) { if (1) { // dumpPids interval if (s.dumpPids) { char buff[63]; siprintf(buff, "PID,%"PRId32",%d,%"PRIu32",%d\r\n", s.targetTemperature, g.curTemp, g.watts, g.atomInfo.resistance); USB_VirtualCOM_SendString(buff); } } } #ifdef PROFILING afterDumpPid = uptime; writeUsb(UPTIME"\t"UPTIME"\t"UPTIME"\t"UPTIME"\r\n", TIMEFMT(afterFire - beforeFire), TIMEFMT(afterScreenUpdate - beforeScreenUpdate), TIMEFMT(afterDumpPid - beforeDumpPid), TIMEFMT(afterTunePid - beforeTunePid)); FireAve += afterFire - beforeFire; ScreenAve += afterScreenUpdate - beforeScreenUpdate; DumpPidAve += afterDumpPid - beforeDumpPid; TunePidAve += afterTunePid - beforeTunePid; #endif } #ifdef PROFILING writeUsb(UPTIME"\t"UPTIME"\t"UPTIME"\t"UPTIME"\r\n", TIMEFMT(FireAve / loopCnt), TIMEFMT(ScreenAve / loopCnt), TIMEFMT(DumpPidAve / loopCnt), TIMEFMT(TunePidAve / loopCnt)); #endif requestTimer(timerIndex, TimerIdle); if (Atomizer_IsOn()) Atomizer_Control(0); }