/** * @file Cadence.c * @author Wang, Zhiyu(wangzy49@midea.com) * @brief Cadence of ebike * @version 0.1 * @date 2021-09-29 * * @copyright Copyright (c) 2021 * */ /************************************************************************ Beginning of File, do not put anything above here except notes Compiler Directives: *************************************************************************/ #include "syspar.h" #include "Cadence.h" #include "CodePara.h" #include "api.h" #include "board_config.h" /****************************** * * Parameter * ******************************/ CADENCE_COF cadence_stFreGetCof = CADENCE_COF_DEFAULT; CADENCE_OUT cadence_stFreGetOut = CADENCE_OUT_DEFAULT; static ULONG cad_pvt_ulCadFreqPu = 0; static ULONG cad_pvt_ulCapValErr = 0; static ULONG cad_pvt_ulCapValErrLast = 0; /*************************************************************** Function: cadence_voCadenceCof; Description: cadence function coef cal Call by: Input Variables: N/A Output/Return Variables: N/A Subroutine Call: N/A; Reference: N/A ****************************************************************/ void cadence_voCadenceCof(void) { #ifdef RUN_ARCH_SIM cadence_stFreGetCof.uwNumbersPulses = CADENCE_NUMBERS_PULSES; #endif cadence_stFreGetCof.uwSartIntervalTimeCnt = CADENCE_START_INTERVALTIME / CADENCE_TIM_TIMERUNIT; cadence_stFreGetCof.uwNumbersValidPulse2Start = CADENCE_NUMBERS_VALIDPULSE2START; cadence_stFreGetCof.uwLfRecordTimeCnt = CADENCE_LF_RECORDTIME / CADENCE_TIM_TIMERUNIT; cadence_stFreGetCof.uwLfMinFrePu = ((((ULONG)CADENCE_LF_MINFRE << 10) / 100) << 10) / FBASE; // Q20 cadence_stFreGetCof.uwHfMaxTimeCnt = CADENCE_HF_MAXTIME / CADENCE_TIM_TIMERUNIT; cadence_stFreGetCof.uwErrorResetCnt = CADENCE_ERROR_RESETTIME / CADENCE_TIM_TIMERUNIT; cadence_stFreGetCof.uwTimerUnit = CADENCE_TIM_TIMERUNIT; cadence_stFreGetCof.uwCadenceLPFgain = CADENCE_LPF_GAIN; cadence_stFreGetCof.uwMaxCadenceFre = ((ULONG)CADENCE_MAX_FREQUENCY << 20) / FBASE; // Q20 } /*************************************************************** Function: cadence_voCadenceIdle; Description: Call by: Input Variables: N/A Output/Return Variables: N/A Subroutine Call: N/A; Reference: N/A ****************************************************************/ static void cadence_voCadenceIdle(UWORD source) { if (source == 1) { cadence_stFreGetOut.uwCaputureOverflowCnt++; if (cadence_stFreGetOut.uwCaputureOverflowCnt > cadence_stFreGetCof.uwSartIntervalTimeCnt) { cadence_stFreGetOut.uwCaputureOverflowCnt = 0; cadence_stFreGetOut.uwCaputureNumCnt = 0; } } else { if (cadence_stFreGetOut.cadence_dir == CADENCE_DIR_BACKWARD) { cadence_stFreGetOut.uwCaputureOverflowCnt = 0; cadence_stFreGetOut.uwCaputureNumCnt = 0; cadence_stFreGetOut.cadence_fsm = CADENCE_BACKWOR; } if (cadence_stFreGetOut.cadence_dir == CADENCE_DIR_FORWARD) { cadence_stFreGetOut.uwCaputureNumCnt++; cadence_stFreGetOut.uwCaputureOverflowCnt = 0; } if (cadence_stFreGetOut.uwCaputureNumCnt >= cadence_stFreGetCof.uwNumbersValidPulse2Start) { cadence_stFreGetOut.blCadenceCalStartState = TRUE; cadence_stFreGetOut.uwCaputureOverflowCnt = 0; cadence_stFreGetOut.uwCaputureNumCnt = 0; cadence_stFreGetOut.cadence_fsm = CADENCE_HFreWork; cadence_stFreGetOut.uwForwardCnt = 0; } } } /*************************************************************** Function: cadence_voCadenceHighFrequencyWork Description: Call by: functions in main loop Input Variables: N/A Output/Return Variables: N/A Subroutine Call: N/A Reference: N/A ****************************************************************/ static void cadence_voCadenceHighFrequencyWork(UWORD source) { /* 只有踏频一个脉冲会即source==1 && cadence_stFreGetOut.uwCaputureNumCnt==0,需要处理 */ if (source == 1 && cadence_stFreGetOut.uwCaputureNumCnt == 1) { cadence_stFreGetOut.uwCaputureOverflowCnt++; } else if (source == 1 && cadence_stFreGetOut.uwCaputureNumCnt == 0) { cadence_stFreGetOut.uwCaputureOverflowCnt2++; } else if (source == 2) { if (cadence_stFreGetOut.uwCaputureNumCnt == 0) { cadence_stFreGetOut.uwCaputureNumCnt = 1; cadence_stFreGetOut.uwCaputure1Cnt = (UWORD)iCap_GetCaptureValue(0, CAP_CH(2)); } else if (cadence_stFreGetOut.uwCaputureNumCnt == 1) { cadence_stFreGetOut.uwForwardCnt++; cadence_stFreGetOut.uwCaputureNumCnt = 2; cadence_stFreGetOut.uwCaputure2Cnt = (UWORD)iCap_GetCaptureValue(0, CAP_CH(2)); cad_pvt_ulCapValErrLast = cad_pvt_ulCapValErr; cad_pvt_ulCapValErr = ((ULONG)cadence_stFreGetOut.uwCaputureOverflowCnt * 720 * cadence_stFreGetCof.uwTimerUnit) - cadence_stFreGetOut.uwCaputure1Cnt + cadence_stFreGetOut.uwCaputure2Cnt; cadence_stFreGetOut.uwCaputureOverflowCnt = 0; /* Cadence Freq Cal */ cad_pvt_ulCadFreqPu = (ULONG)(((UQWORD)HW_TIM1CLK_KHZ * 1000 << 20) / ((((UQWORD)cad_pvt_ulCapValErr + (UQWORD)cad_pvt_ulCapValErrLast)>>1)* cadence_stFreGetCof.uwNumbersPulses * FBASE)); cadence_stFreGetOut.uwCaputureNumCnt = 1; cadence_stFreGetOut.uwCaputure1Cnt = cadence_stFreGetOut.uwCaputure2Cnt; } else { //do nothing } } else { //do nothing } if (cadence_stFreGetOut.cadence_dir == CADENCE_DIR_BACKWARD) { cadence_stFreGetOut.cadence_fsm = CADENCE_BACKWOR; } if (cad_pvt_ulCadFreqPu > cadence_stFreGetCof.uwMaxCadenceFre) { cadence_stFreGetOut.uwFrequencyPu = 0; cadence_stFreGetOut.uwLPFFrequencyPu = 0; cadence_stFreGetOut.blCadenceCalStartState = FALSE; cadence_stFreGetOut.blCadenceSensorErrorFlg = TRUE; cadence_stFreGetOut.uwCaputureOverflowCnt = 0; cadence_stFreGetOut.uwCaputureNumCnt = 0; cadence_stFreGetOut.uwCaputure2Cnt = 0; cadence_stFreGetOut.uwCaputure1Cnt = 0; cadence_stFreGetOut.cadence_dir = CADENCE_DIR_ERROR; cadence_stFreGetOut.cadence_fsm = CADENCE_ERROR; cadence_stFreGetOut.uwFreqPercent = 0; cad_pvt_ulCadFreqPu = 0; cadence_stFreGetOut.uwCaputureOverflowCnt2 = 0; } else if (cadence_stFreGetOut.uwCaputureOverflowCnt > cadence_stFreGetCof.uwHfMaxTimeCnt || cadence_stFreGetOut.uwCaputureOverflowCnt2 > cadence_stFreGetCof.uwHfMaxTimeCnt) { cadence_stFreGetOut.uwFrequencyPu = 0; cadence_stFreGetOut.uwLPFFrequencyPu = 0; cadence_stFreGetOut.blCadenceCalStartState = FALSE; cadence_stFreGetOut.blCadenceSensorErrorFlg = FALSE; cadence_stFreGetOut.uwCaputureOverflowCnt = 0; cadence_stFreGetOut.uwCaputureNumCnt = 0; cadence_stFreGetOut.uwCaputure2Cnt = 0; cadence_stFreGetOut.uwCaputure1Cnt = 0; cadence_stFreGetOut.cadence_dir = CADENCE_DIR_IDLE; cadence_stFreGetOut.cadence_fsm = CADENCE_IDLE; cadence_stFreGetOut.uwFreqPercent = 0; cad_pvt_ulCadFreqPu = 0; cadence_stFreGetOut.uwCaputureOverflowCnt2 = 0; } else { cadence_stFreGetOut.uwFrequencyPu = cad_pvt_ulCadFreqPu; // Q20 cadence_stFreGetOut.uwLPFFrequencyPu = (cadence_stFreGetOut.uwLPFFrequencyPu * cadence_stFreGetCof.uwCadenceLPFgain + cadence_stFreGetOut.uwFrequencyPu * (100 - cadence_stFreGetCof.uwCadenceLPFgain)) / 100; // Q20 cadence_stFreGetOut.uwFreqPercent = (UWORD)(((ULONG)cadence_stFreGetOut.uwLPFFrequencyPu << 14) / cadence_stFreGetCof.uwMaxCadenceFre); // Q14 } } /*************************************************************** Function: cadence_voCadenceBackword Description: Call by: functions in main loop Input Variables: N/A Output/Return Variables: N/A Subroutine Call: N/A Reference: N/A ****************************************************************/ static void cadence_voCadenceBackword(UWORD source) { cadence_stFreGetOut.uwFrequencyPu = 0; cadence_stFreGetOut.uwLPFFrequencyPu = 0; cadence_stFreGetOut.uwFreqPercent = 0; cad_pvt_ulCadFreqPu = 0; if (cadence_stFreGetOut.cadence_dir == CADENCE_DIR_FORWARD) { cadence_stFreGetOut.uwCaputureOverflowCnt = 0; cadence_stFreGetOut.uwCaputureOverflowCnt2 = 0; cadence_stFreGetOut.uwCaputureNumCnt = 0; cadence_stFreGetOut.uwCaputure2Cnt = 0; cadence_stFreGetOut.uwCaputure1Cnt = 0; cadence_stFreGetOut.uwFreqPercent = 0; cadence_stFreGetOut.cadence_fsm = CADENCE_HFreWork; } } /*************************************************************** Function: cadence_voCadenceDir Description: cadence frequency get Call by: functions in main loop Input Variables: N/A Output/Return Variables: N/A Subroutine Call: N/A Reference: N/A ****************************************************************/ static void cadence_voCadenceDir(void) { if (iGpio_Read(HW_GPIO_CADDIR_PIN) == 0) { cadence_stFreGetOut.cadence_dir = CADENCE_DIR_FORWARD; } else { cadence_stFreGetOut.cadence_dir = CADENCE_DIR_BACKWARD; } } /*************************************************************** Function: cadence_voCadenceError Description: Call by: Input Variables: N/A Output/Return Variables: N/A Subroutine Call: N/A Reference: N/A ****************************************************************/ static void cadence_voCadenceError(UWORD source) { if (source == 1) { cadence_stFreGetOut.uwCaputureErrorCnt++; } if (cadence_stFreGetOut.uwCaputureErrorCnt == cadence_stFreGetCof.uwErrorResetCnt) { cadence_voCadenceInit(); cadence_stFreGetOut.cadence_fsm = CADENCE_IDLE; } } /*************************************************************** Function: cadence_voFreGetInit Description: cadence frequency get initialization Call by: Input Variables: N/A Output/Return Variables: N/A Subroutine Call: N/A Reference: N/A ****************************************************************/ void cadence_voCadenceInit(void) { cadence_stFreGetOut.uwFrequencyPu = 0; cadence_stFreGetOut.uwLPFFrequencyPu = 0; cadence_stFreGetOut.uwCaputure1Cnt = 0; cadence_stFreGetOut.uwCaputure2Cnt = 0; cadence_stFreGetOut.uwCaputureNumCnt = 0; cadence_stFreGetOut.uwCaputureErrorCnt = 0; cadence_stFreGetOut.uwCaputureOverflowCnt = 0; cadence_stFreGetOut.uwCaputureOverflowCnt2 = 0; cadence_stFreGetOut.blCadenceSensorErrorFlg = FALSE; cadence_stFreGetOut.blCadenceCalStartState = FALSE; cadence_stFreGetOut.cadence_fsm = CADENCE_IDLE; cadence_stFreGetOut.cadence_dir = CADENCE_DIR_IDLE; cad_pvt_ulCadFreqPu = 0; cad_pvt_ulCapValErr = 0; cad_pvt_ulCapValErrLast = 0; } /*************************************************************** Function: cadence_voCadenceCal Description: cadence frequency get Call by: Input Variables: N/A Output/Return Variables: N/A Subroutine Call: N/A Reference: N/A ****************************************************************/ void cadence_voCadenceCal(UWORD source) { cadence_voCadenceDir(); switch (cadence_stFreGetOut.cadence_fsm) { case CADENCE_IDLE: cadence_voCadenceIdle(source); break; case CADENCE_HFreWork: cadence_voCadenceHighFrequencyWork(source); break; case CADENCE_BACKWOR: cadence_voCadenceBackword(source); break; case CADENCE_ERROR: cadence_voCadenceError(source); break; default: break; } } /************************************************************************* End of this File (EOF)! Do not put anything after this part! *************************************************************************/