// Communicating with mast via SPI void COMM_Manager(void) { static uint16_t unCOM_Buff[COMM_FIFO_LENGTH]; static uint32_t unLastFrameCNT = 0; static uint32_t unLastCheckTime = 0; // All transactions are handled in interrupt if (tMotor.structMotor.MSR.bNewComFrameReceived == TRUE) { memcpy(unCOM_Buff, unCOM_SPI_ReadData, COMM_FIFO_LENGTH); tMotor.structMotor.MSR.bNewComFrameReceived = FALSE; if (CRC16((uint8_t *)unCOM_Buff, (IS_COMM_RD_CMD(unCOM_Buff[0]) ? ((COMM_RD_CMD_CNT - 1) << 1) : ((COMM_WR_CMD_CNT - 1) << 1))) == (IS_COMM_RD_CMD(unCOM_Buff[0]) ? unCOM_Buff[COMM_RD_CMD_CNT - 1] : unCOM_Buff[COMM_WR_CMD_CNT - 1])) { unValidFrameCNT++; // safe zone if (IS_COMM_RD_CMD(unCOM_Buff[0])) { nReadCommandHandler(unCOM_Buff); } else { nWriteCommandHandler(unCOM_Buff); } } else { unCOM_SPI_TransErrCNT++; } } // Comm protection 1: If have NOT received any frame in 500ms, error if ((uint32_t)(unSystemTick - unLastCheckTime) > 500) { unLastCheckTime = unSystemTick; if ((uint32_t)(unValidFrameCNT - unLastFrameCNT) < 1) { BLDC_stopMotor(); setError(ERR_COMMUNICATION_FAIL); } unLastFrameCNT = unValidFrameCNT; } // Comm protection 2: If received error frame exceed some threshold, error if (unCOM_SPI_TransErrCNT > COM_SPI_TRANS_ERR_THRESHOLD) { BLDC_stopMotor(); setError(ERR_COMMUNICATION_FAIL); } }
/*************************************************************** * Function: void MOT_commandDutyCycle(uint16_t dutyCycle) * * Purpose: To update the duty cycle required by higher- * level software * * Parameters: uint16_t dutyCycle This is the fixed-point representation * of the motor duty cycle. 0%-100% is scaled * to 0-65535 * * Returns: none * * Globals affected: none **************************************************************/ void MOT_commandDutyCycle(uint16_t dutyCycle) { if(dutyCycle < MOT_MIN_DUTY_CYCLE) { dutyCycle = 0; MOT_stopMotor(); } else { MOT_startMotor(); } switch(motor.type) { case MOT_DC: MDC_commandDutyCycle(dutyCycle); break; case MOT_BLDC: BLDC_commandDutyCycle(dutyCycle); break; default: BLDC_stopMotor(); break; } return; } // END MOT_commandDutyCycle
__INLINE void dutyProtection(void) { // Duty too big protection if ((tMotor.structMotor.unActualDuty > MAX_MOTOR_PWR_DUTY) || (PWM->CMR[1] > MAX_MOTOR_PWR_DUTY)) { BLDC_stopMotor(); setError(ERR_INTERNAL); } }
/*************************************************************** * Function: void MOT_stopMotor(void) * * Purpose: To stop the appropriate motor based on the * previously defined motor type * * Parameters: none * * Returns: none * * Globals affected: none **************************************************************/ void MOT_stopMotor(void) { switch(motor.type) { case MOT_DC: MDC_stopMotor(); break; case MOT_BLDC: BLDC_stopMotor(); break; default: BLDC_stopMotor(); break; } return; } // END MOT_stopMotor()
/*************************************************************** * Function: void MOT_defineMotorType(_MOT_motorType motorType) * * Purpose: This defines the motor type to be used, which chooses * the motor library to be utilized * * Parameters: _MOT_motorType motorType * * Returns: none * * Globals affected: motor.type **************************************************************/ void MOT_defineMotorType(_MOT_motorType motorType) { // Stop all motor activity BLDC_stopMotor(); MDC_stopMotor(); // Change the motor type motor.type = motorType; MOT_initMotor(); return; } // END MOT_defineMotorType()
__INLINE void phaseDurationProtection(uint32_t unLastPhaseChangeTime) { static uint32_t unCurrentPHCHG; // Single phase duration too long protection if (TRUE == tMotor.structMotor.MSR.bMotorPowerOn) { if (unCurrentPHCHG != PWM->PHCHG) { unCurrentPHCHG = PWM->PHCHG; unLastPhaseChangeTime = unSystemTick; } else { if ((uint32_t)(unSystemTick - unLastPhaseChangeTime) > MAX_SINGLE_PHASE_DURATION) { BLDC_stopMotor(); setError(ERR_INTERNAL); } } } }
// Take charge of all Motot control void BLDC_SensorLessManager(void) { uint16_t unMotorAlreadyRotatingPhaseTime; static uint32_t iEnterTimeBeforeWait; dutyProtection(); phaseDurationProtection(unLastPhaseChangeTime); switch (tMotorState) { case MOTOR_IDLE: if (tMotor.structMotor.MCR.bMotorNeedToRun && NO_MOTOR_EEROR) { unRotateDetectStartTime = unSystemTick; tRotateDetectState = DETECT_START; tMotorState = MOTOR_START; } break; case MOTOR_START: if (tMotor.structMotor.MCR.bMotorNeedToRun && NO_MOTOR_EEROR) { // Later implement this when motor can rotate // Then stop it while rotating to measure the waveform // Manually rotate it is too slow unMotorAlreadyRotatingPhaseTime = canMotorContinueRunning(); if (unMotorAlreadyRotatingPhaseTime != IS_ROTATING_DETECTING) { if (unMotorAlreadyRotatingPhaseTime > 0) { // 1 to 65534 tMotorState = MOTOR_LOCKED; } else { // When back to Idle state the motor was already shut down // MOTOR_SHUT_DOWN; unCurrentPhase = 0; unLocateIndex = 0; tMotor.structMotor.MSR.unMissedZXD_CNT = 0; unLastPhaseChangeTime = unSystemTick; tMotor.structMotor.MSR.bMotorPowerOn = TRUE; // Clear start detect zero cross flag tMotor.structMotor.MSR.bZeroCrossDetecting = FALSE; tMotor.structMotor.MSR.bLocked = FALSE; //setPhaseManually(tMotor.structMotor.LCT_DUTY, unCurrentPhase); BRG_ENABLE; tMotorState = MOTOR_LOCATE; } } } else { BLDC_stopMotor(); } break; case MOTOR_LOCATE: if (tMotor.structMotor.MCR.bMotorNeedToRun && NO_MOTOR_EEROR) { if (BLDC_LocatingManager() == STATUS_FINISHED) { iEnterTimeBeforeWait = unSystemTick; tMotorState = MOTOR_WAIT_AFTER_LOCATE; } } else { BLDC_stopMotor(); } break; case MOTOR_WAIT_AFTER_LOCATE: if (tMotor.structMotor.MCR.bMotorNeedToRun && NO_MOTOR_EEROR) { if ((uint32_t)(unSystemTick - iEnterTimeBeforeWait) >= WAIT_AFTER_LOCATE_TIME) { tMotor.structMotor.unActualDuty = tMotor.structMotor.unRampUpDuty; tMotor.structMotor.unActualPeriod = tMotor.structMotor.unRampUpPeriod; tMotor.structMotor.MSR.bMotorPowerOn = TRUE; PHASE_INCREASE(unCurrentPhase); setPhaseManually(tMotor.structMotor.unActualDuty, unCurrentPhase); BRG_ENABLE; // Set timer 0 valure, use timer 0 to change phase automatically // ************************************************************************ // ----==== From here current unCurrentPhase is actually next phase ====---- // ----==== Because we want to use the HW auto phase changer (PWM->PHCHGNXT) ====---- // So increase unCurrentPhase again. Want to get real current phase value? Read PWM->PHCHG. // ************************************************************************ PHASE_INCREASE(unCurrentPhase); PWM->PHCHGNXT = GET_PHASE_VALUE(unCurrentPhase); // !!!! Need to make sure CPU runs to here every min tMotor.structMotor.ACT_PERIOD time !!! // !!!! If not , timer counter may already passed tMotor.structMotor.ACT_PERIOD, !!!! // !!!! then need to count to max timer counter number (which is 2^24), !!!! // !!!! go back to 0 and triger interrupt when reach ACT_PERIOD again !!!! TIMER_SET_CMP_VALUE(TIMER0, tMotor.structMotor.unActualPeriod); TIMER_Start(TIMER0); // Once started, running and interrupting until Motor stop TIMER_EnableInt(TIMER0); unPeriodChangeCNT_AfterPR_ReachMini = 0; unPhaseChangeCNT_AtCurrentDuty = 0; unPhaseChangeCNT_AtCurrentPeriod = 0; tMotorState = MOTOR_RAMPUP_WO_ZXD; } } else { BLDC_stopMotor(); } break; case MOTOR_RAMPUP_WO_ZXD: // without zero cross detection if (tMotor.structMotor.MCR.bMotorNeedToRun && NO_MOTOR_EEROR) { BLDCRampUp_Manager(); if (tMotor.structMotor.unActualPeriod <= MOTOR_START_ZXD_SPEED) //(iRampUpPeriodMiniCNT > MOTOR_START_ZXD_MINROT_CNT) // { tMotor.structMotor.MSR.bThisPhaseDetectedZX = FALSE; tMotor.structMotor.MSR.bZeroCrossDetecting = TRUE; // Speed is enough for zero cross detecting // Prepare everything // T0 used to change phase automatically -- already configured // T1 used to filter ZX // TIMER_SET_CMP_VALUE(TIMER1, GET_TIM1_CMP_VALUE(TIMER1->TDR + AVOID_ZXD_AFTER_PHCHG)); // FLAG_TIM1_USEAGE = ENUM_TIM1_AVOID_ZXD; ACMP0_ENABLE; TIMER_Start(TIMER1); // Once started, running until Motor stop // TIMER_EnableInt(TIMER1); // Suppose last ZX detected time // unLastZXDetectedTime = MINI51_TIM_CNT_MAX - tMotor.structMotor.ACT_PERIOD / 2; tMotorState = MOTOR_RAMPUP_W_ZXD; } } else { BLDC_stopMotor(); } break; case MOTOR_RAMPUP_W_ZXD: // with zero cross detection if (tMotor.structMotor.MCR.bMotorNeedToRun && NO_MOTOR_EEROR) { if (TRUE == tMotor.structMotor.MSR.bLocked) { // Finally, everything was prepared: // T0 used to change phase automatically // T1 used to filter ZX tMotorState = MOTOR_LOCKED; } else { if (unPeriodChangeCNT_AfterPR_ReachMini < RAMP_UP_MIN_PERIOD_NUM_THRS) { BLDCRampUp_Manager(); } else { setError(ERR_RAMPUP_FAIL); } } } else { BLDC_stopMotor(); } break; case MOTOR_LOCKED: if (tMotor.structMotor.MCR.bMotorNeedToRun && NO_MOTOR_EEROR) { BLDCSpeedManager(); // Mainly PWM duty increase/decrease } else { BLDC_stopMotor(); } break; default: break; } }