/* * QC3.c * * Created on: 29 May 2020 * Author: Ralim */ // Quick charge 3.0 supporting functions #include "QC3.h" #include "BSP.h" #include "cmsis_os.h" #include "configuration.h" #include "stdint.h" enum QCState { NOT_STARTED = 0, // Have not checked QC_3 = 1, QC_2 = 2, NO_QC = 3, }; void QC_Seek9V() { QC_DNegZero_Six(); QC_DPlusThree_Three(); } void QC_Seek12V() { QC_DNegZero_Six(); QC_DPlusZero_Six(); } void QC_Seek20V() { QC_DNegThree_Three(); QC_DPlusThree_Three(); } void QC_SeekContMode() { QC_DNegThree_Three(); QC_DPlusZero_Six(); } void QC_SeekContPlus() { QC_SeekContMode(); osDelay(30); QC_Seek20V(); osDelay(10); QC_SeekContMode(); } void QC_SeekContNeg() { QC_SeekContMode(); osDelay(30); QC_Seek12V(); osDelay(10); QC_SeekContMode(); } QCState QCMode = QCState::NOT_STARTED; uint8_t QCTries = 0; void seekQC(int16_t Vx10, uint16_t divisor) { if (QCMode == QCState::NOT_STARTED) startQC(divisor); if (Vx10 < 40) // Bail out if less than 4V return; if (xTaskGetTickCount() < TICKS_SECOND) return; // Seek the QC to the Voltage given if this adapter supports continuous mode // try and step towards the wanted value // 1. Measure current voltage int16_t vStart = getInputVoltageX10(divisor, 0); int difference = Vx10 - vStart; // 2. calculate ideal steps (0.2V changes) int steps = difference / 2; if (QCMode == QCState::QC_3) { while (steps < 0) { QC_SeekContNeg(); vTaskDelay(3 * TICKS_10MS); steps++; } while (steps > 0) { QC_SeekContPlus(); vTaskDelay(3 * TICKS_10MS); steps--; } osDelay(100); } #ifdef ENABLE_QC2 // Re-measure /* Disabled due to nothing to test and code space of around 1k*/ steps = vStart - getInputVoltageX10(divisor, 0); if (steps < 0) steps = -steps; if (steps > 4) { // No continuous mode, so QC2 QCMode = QCState::QC_2; // Goto nearest if (Vx10 > 190) { // request 20V QC_Seek20V(); } else if (Vx10 > 110) { // request 12V QC_Seek12V(); } else { // request 9V QC_Seek9V(); } } #endif } // Must be called after FreeRToS Starts 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 if (getInputVoltageX10(divisor, 0) > 80) { QCTries = 11; QCMode = QCState::NO_QC; return; } if (QCTries > 10) { QCMode = QCState::NO_QC; return; } QCMode = QCState::NOT_STARTED; QC_Init_GPIO(); // Tries to negotiate QC for 9V // This is a multiple step process. // 1. Set around 0.6V on D+ for 1.25 Seconds or so // 2. After this It should un-short D+->D- and instead add a 20k pulldown on // D- QC_DPlusZero_Six(); // Delay 1.25 seconds uint8_t enteredQC = 0; for (uint16_t i = 0; i < 200 && enteredQC == 0; i++) { vTaskDelay(TICKS_10MS); // 10mS pause if (i > 130) { if (QC_DM_PulledDown()) { enteredQC = 1; } if (i == 140) { // For some marginal QC chargers, we try adding a pulldown QC_DM_PullDown(); } } } QC_DM_No_PullDown(); if (enteredQC) { // We have a QC capable charger QC_Seek9V(); QC_Post_Probe_En(); QC_Seek9V(); // Wait for frontend ADC to stabilise QCMode = QCState::QC_2; for (uint8_t i = 0; i < 10; i++) { if (getInputVoltageX10(divisor, 0) > 80) { // yay we have at least QC2.0 or QC3.0 QCMode = QCState::QC_3; // We have at least QC2, pray for 3 return; } vTaskDelay(TICKS_100MS); // 100mS } QCMode = QCState::NOT_STARTED; QCTries++; } else { // no QC QCTries++; QCMode = QCState::NO_QC; } } bool hasQCNegotiated() { return QCMode == QCState::QC_3 || QCMode == QCState::QC_2; }