// 标志的PWM配置流程 static void pwm_simple_test(void) { // 3个配置PWM的结构体 // Structure of PWM configuration stc_bt_pwm_config_t stcPwmConfig; // structure to select the PWM interrupt stc_pwm_int_sel_t stcPwmIntSel; // structure to set the PWM interrupt callback function stc_pwm_int_cb_t stcPwmIntCallback; // PWM的周期与占空比 // 这里PWM配置PwmPres1Div4, 从PCLK = 80MHZ四分频为20MHZ; // PWM clock = 20MHZ(0.05us), cycle = (1+pwm_cycle)*(Pwm clock cycle) // PWM clock = 20MHZ(0.05us), duty = (1+pwm_duty)*(PWM clock cycle) uint32_t pwm_cycle = 999; // (1+999) * 0.05us = 50us = 20kHZ uint32_t pwm_duty = 99; // (1+99) * 0.05us = 5us // Set Basetimer IO port, 将P40引脚设为TIOA0_0功能; PwmInitOutput(); // Set requested I/O mode // 将定时器配置为I/O mode 0(I/O mode 0: Standard 16-bit timer mode); Bt_ConfigIOMode(&USER_BT, BtIoMode0); // 将定时器配置为16-bit PWM功能; Bt_SelTimerMode(&USER_BT, BtPwmMode); // Initialize PWM timer stcPwmConfig.enPres = PwmPres1Div4; // PWM clock = 20MHz @ PCLK = 80MHz stcPwmConfig.enMode = PwmContinuous; // pwm continuous, 连续不间断模式; stcPwmConfig.enExtTrig = PwmExtTrigDisable; //关闭外部trigger; stcPwmConfig.enOutputMask = PwmOutputNormal; //输出掩码配置 stcPwmConfig.enOutputPolarity = PwmPolarityLow; //优先级配置 stcPwmConfig.enRestartEn = PwmRestartEnable; //PWM复位使能(可以被复位,重新输出PWM) Bt_Pwm_Init(&USER_BT, &stcPwmConfig); // Set cycle and duty value // 这里PWM配置PwmPres1Div4, 从PCLK = 80MHZ四分频为20MHZ; // PWM clock = 20MHZ(0.05us), cycle = (1+pwm_cycle)*0.05us // PWM clock = 20MHZ(0.05us), duty = (1+pwm_duty)*0.05us Bt_Pwm_WriteCycleVal(&USER_BT, pwm_cycle); // Cycle = (1+m)*PWM clock cycle = 50us Bt_Pwm_WriteDutyVal(&USER_BT, pwm_duty); // Duty = (1+m)*PWM clock cycle = 5us // Enable Interrupt // 指定三个中断函数; stcPwmIntSel.bPwmTrigInt = 1; stcPwmIntSel.bPwmDutyMatchInt = 1; stcPwmIntSel.bPwmUnderflowInt = 1; stcPwmIntCallback.pfnPwmTrigIntCallback = PwmTrigIntHandler; stcPwmIntCallback.pfnPwmDutyMatchIntCallback = PwmDutyMatchIntHandler; stcPwmIntCallback.pfnPwmUnderflowIntCallback = PwmUnderflowIntHandler; Bt_Pwm_EnableInt(&USER_BT, &stcPwmIntSel, &stcPwmIntCallback); // Enable count operatoin // 计数使能 Bt_Pwm_EnableCount(&USER_BT); // Start triggered by software // 软件给出trigger信号,此时计时器才会开始计数; Bt_Pwm_EnableSwTrig(&USER_BT); }
/** ****************************************************************************** ** \brief Main function of PDL ** ** \return uint32_t return value, if needed ******************************************************************************/ int32_t main(void) { uint8_t u8Counter; stc_dstc_config_t stcDstcConfig; stc_bt_pwm_config_t stcPwmConfig; stc_pwm_irq_en_t stcPwmIrqEn; boolean_t bCompareError = FALSE; PDL_ZERO_STRUCT(stcDstcConfig); PDL_ZERO_STRUCT(stcPwmConfig); PDL_ZERO_STRUCT(stcPwmIrqEn); // Fill Source Data for (u8Counter = 0; u8Counter < DSTC_MAXDATA; u8Counter++) { // "Random" data au32SourceData[u8Counter] = ((u8Counter << 8u) ^ 0x12345678u) + u8Counter; } // Initialize BT interrupts stcPwmIrqEn.bPwmUnderflowIrq = TRUE; // Set requested BT I/O mode Bt_ConfigIOMode(&BT0, BtIoMode0); // Initialize BT as PWM timer stcPwmConfig.enPres = PwmPres1Div4; stcPwmConfig.enMode = PwmOneshot; stcPwmConfig.enExtTrig = PwmExtTrigDisable; stcPwmConfig.enOutputMask = PwmOutputNormal; stcPwmConfig.enOutputPolarity = PwmPolarityLow; stcPwmConfig.enRestartEn = PwmRestartDisable; stcPwmConfig.pstcPwmIrqEn = &stcPwmIrqEn; stcPwmConfig.bTouchNvic = TRUE; Bt_Pwm_Init(&BT0, &stcPwmConfig); Bt_Pwm_WriteCycleVal(&BT0, 55655u); // just some values ... Bt_Pwm_WriteDutyVal(&BT0, 33u); // Enable BT count operatoin Bt_Pwm_EnableCount(&BT0); // Init Descriptor set for DES0, DES1, DES2, DES3, DES4, DES6 // DES0 stcDstcExample.DES0.DV = 1u; stcDstcExample.DES0.ST = 0u; stcDstcExample.DES0.MODE = 0u; // Mode 0 stcDstcExample.DES0.ORL = 0u; // No reload from DES4, DES5, DES6. The descriptor only includes DES0, DES1, DES2, DES3. stcDstcExample.DES0.TW = 2u; // 32 Bit stcDstcExample.DES0.SAC = 1u; // The address is increased by TW¡Á1 at every transfer with InnerReload. stcDstcExample.DES0.DAC = 0u; // The address is increased by TW¡Á1 at every transfer without InnerReload. stcDstcExample.DES0.CHRS = 0x10u; // An interrupt flag has been set when IRM =1 and ORM = 1 stcDstcExample.DES0.DMSET = 0u; // Set BT0 mask bit stcDstcExample.DES0.ACK = 1u; // Send acknowledge to BT0 stcDstcExample.DES0.CHLK = 0u; stcDstcExample.DES0.PCHK = DSTC_PCHK_CALC(stcDstcExample.u32DES0); // DES1 stcDstcExample.DES1_mode0.ORM = 1u; stcDstcExample.DES1_mode0.IIN = DSTC_MAXDATA; // DES2 stcDstcExample.DES2 = (uint32_t)&au32SourceData[0]; // DES3 stcDstcExample.DES3 = (uint32_t)&au32DestinationData[0]; // Configure DSTC stcDstcConfig.u32Destp = (uint32_t)&stcDstcExample; stcDstcConfig.bSwInterruptEnable = FALSE; stcDstcConfig.bErInterruptEnable = TRUE; stcDstcConfig.bReadSkipBufferDisable = FALSE; stcDstcConfig.bErrorStopEnable = TRUE; stcDstcConfig.enSwTransferPriority = Priority1_31; stcDstcConfig.pfnErrorCallback = &Main_DstcErrorCallback; stcDstcConfig.pfnDstcBt0Irq0Callback = &Main_DstcBt0Callback; stcDstcConfig.bTouchNvic = TRUE; Dstc_Init(&stcDstcConfig); Dstc_SetCommand(CmdErclr); Dstc_SetCommand(CmdRbclr); Dstc_SetHwdesp(DSTC_IRQ_NUMBER_BT0_IRQ0, 0u); // BT0, DES Offset 0 Dstc_SetDreqenbBit(DSTC_IRQ_NUMBER_BT0_IRQ0); // Switch BT0 to DSTC // Start BT triggered by software Bt_Pwm_EnableSwTrig(&BT0); while(FALSE == bDtscEndNotify) {} if (TRUE == bDstcErrorFlasg) { // Error handling } else { for (u8Counter = 0; u8Counter < DSTC_MAXDATA; u8Counter++) { // Check destination data if (au32SourceData[u8Counter] != au32DestinationData[u8Counter]) { bCompareError = TRUE; break; } } } if (TRUE == bCompareError) { // Error handling here ... __NOP(); } while(1) {} }
/*! ****************************************************************************** ** \brief High-cr trimming procedure ** ** \param [in] f32ExpCrMinFreq CR minimum frequency after trimming, unit:MHz ** \param [in] f32ExpCrMaxFreq CR maximum frequency after trimming, unit:MHz ** \param [in] f32ExpCrFreq Expected CR value after trimming, unit:MHz ** \param [in] u8DefaultTempTrimData Temperature trim data, should be ** regulated according to current temperature. ** \param [out] pCrTrimmingData Pointer to final trimming data ** ** \return CR trimming status ** \retval CR_TRIMMING_RET_OK ** \reval CR_TRIMMING_RET_ERR ** ***************************************************************************** */ uint8_t CrTrimmingProcess(float32_t f32CrMinFreq, float32_t f32CrMaxFreq, float32_t f32ExpCrFreq, uint8_t u8DefaultTempTrimData, uint32_t* pCrTrimmingData) { uint8_t u8TrimState = CR_TRIMMING_PROC_INIT; stc_bt_pwc_config_t stcPwcConfig; stc_pwc_irq_en_t stcPwcIrqEn; stc_pwc_irq_cb_t stcPwcIrqCallback; uint8_t u8TempTrimData = u8DefaultTempTrimData, u8i; uint16_t u16CrTrimData; uint32_t u32MeasData; uint8_t u8CoarseData, u8FineData; float32_t f32TMaxCoarse, f32TMinCoarse, f32TMaxFine, f32TMinFine, f32FinalCycle; stc_coarse_cycle_t stcCoarseCycle; stc_fine_cycle_t stcFineCycle; PDL_ZERO_STRUCT(stcPwcConfig); PDL_ZERO_STRUCT(stcPwcIrqEn); PDL_ZERO_STRUCT(stcPwcIrqCallback); while(1) { switch(u8TrimState) { case CR_TRIMMING_PROC_INIT: /* Set CR dividor */ #if (PDL_MCU_TYPE == PDL_FM3_TYPE3) || (PDL_MCU_TYPE == PDL_FM3_TYPE7) || \ (PDL_MCU_CORE == PDL_FM0P_CORE) || (PDL_MCU_CORE == PDL_FM4_CORE) Cr_SetFreqDiv(CrFreqDivBy512); #else Cr_SetFreqDiv(CrFreqDivBy32); #endif /* Use CR as input of TIOB */ bFM_GPIO_EPFR04_TIOB0S0 = 1u; bFM_GPIO_EPFR04_TIOB0S1 = 1u; bFM_GPIO_EPFR04_TIOB0S2 = 1u; /* Init PWC mode of BT0 */ // Set IO Mode Bt_ConfigIOMode(&BT0, BtIoMode0); // PWC register initialization stcPwcConfig.enPres = PwcPresNone; stcPwcConfig.enMode = PwcContinuous; stcPwcConfig.enMeasureEdge = PwcMeasureRisingToRising; stcPwcConfig.enSize = PwcSize16Bit; Bt_Pwc_Init(&BT0, &stcPwcConfig); // Enable Irqerrupt stcPwcConfig.pstcPwcIrqEn = &stcPwcIrqEn; stcPwcConfig.pstcPwcIrqCb = &stcPwcIrqCallback; stcPwcConfig.bTouchNvic = TRUE; stcPwcConfig.pstcPwcIrqEn->bPwcMeasureCompleteIrq = TRUE; stcPwcConfig.pstcPwcIrqEn->bPwcMeasureOverflowIrq = TRUE; stcPwcIrqEn.bPwcMeasureCompleteIrq = 1u; stcPwcIrqEn.bPwcMeasureOverflowIrq = 1u; stcPwcIrqCallback.pfnPwcMeasureCompleteIrqCb = PwcMeasCmpIrqHandler; stcPwcIrqCallback.pfnPwcMeasureOverflowIrqCb = PwcOverflowIrqHandler; // Set PWC timer mode Bt_Pwc_Init(&BT0, &stcPwcConfig); u8TrimState++; break; case CR_TRIMMING_PROC_TMAXCOARSE_MEAS_INIT: case CR_TRIMMING_PROC_TMAXFINE_MEAS_INIT: if(CR_TRIMMING_PROC_TMAXCOARSE_MEAS_INIT == u8TrimState) { u8FineData = 0x00u; u8CoarseData = 0x00u; } else { u8FineData = 0x00u; } u16CrTrimData = (u8FineData & 0x1Fu) | ((u8CoarseData & 0x1Fu)<<5u); #if (PDL_MCU_TYPE == PDL_FM3_TYPE8) || (PDL_MCU_TYPE == PDL_FM3_TYPE9) || \ (PDL_MCU_TYPE == PDL_FM3_TYPE10) || (PDL_MCU_TYPE == PDL_FM3_TYPE11) || \ (PDL_MCU_TYPE == PDL_FM3_TYPE12) || (PDL_MCU_CORE == PDL_FM0P_CORE) || \ (PDL_MCU_CORE == PDL_FM4_CORE) Cr_SetTempTrimmingData(u8TempTrimData); #endif Cr_SetFreqTrimmingData(u16CrTrimData); u8TrimState++; break; case CR_TRIMMING_PROC_TMAXCOARSE_MEAS_START: case CR_TRIMMING_PROC_TMAXFINE_MEAS_START: m_u32CntIrqMeasure = 0; // Enable count operatoin Bt_Pwc_EnableCount(&BT0); u8TrimState++; break; case CR_TRIMMING_PROC_TMAXCOARSE_MEAS_ONGOING: case CR_TRIMMING_PROC_TMAXFINE_MEAS_ONGOING: while(MEAN_CNT > m_u32CntIrqMeasure) { if(m_u32CntIrqOverflow) { // Disable count operatoin Bt_Pwc_DisableCount(&BT0); return CR_TRIMMING_RET_ERR; } } // Disable count operatoin Bt_Pwc_DisableCount(&BT0); u8TrimState++; break; case CR_TRIMMING_PROC_TMAXCOARSE_MEAS_FINISH: case CR_TRIMMING_PROC_TMAXFINE_MEAS_FINISH: u32MeasData = 0u; for(u8i=0u;u8i<MEAN_CNT;u8i++) { u32MeasData += m_aMeasureResult[u8i]; } u32MeasData = u32MeasData/MEAN_CNT; if(CR_TRIMMING_PROC_TMAXCOARSE_MEAS_FINISH == u8TrimState) { f32TMaxCoarse = (float32_t)u32MeasData/(float32_t)(u32SysClk*PWC_CNT ); } else { f32TMaxFine = (float32_t)u32MeasData/(float32_t)(u32SysClk*PWC_CNT ); } u8TrimState++; break; case CR_TRIMMING_PROC_TMINCOARSE_MEAS_INIT: case CR_TRIMMING_PROC_TMINFINE_MEAS_INIT: if(CR_TRIMMING_PROC_TMINCOARSE_MEAS_INIT == u8TrimState) { u8FineData = 0x00u; u8CoarseData = 0x1Fu; } else { u8FineData = 0x1Fu; } u16CrTrimData = (u8FineData & 0x1Fu) | ((u8CoarseData & 0x1Fu)<<5u); #if (PDL_MCU_TYPE == PDL_FM3_TYPE8) || (PDL_MCU_TYPE == PDL_FM3_TYPE9) || \ (PDL_MCU_TYPE == PDL_FM3_TYPE10) || (PDL_MCU_TYPE == PDL_FM3_TYPE11) || \ (PDL_MCU_TYPE == PDL_FM3_TYPE12) || (PDL_MCU_CORE == PDL_FM0P_CORE) || \ (PDL_MCU_CORE == PDL_FM4_CORE) Cr_SetTempTrimmingData(u8TempTrimData); #endif Cr_SetFreqTrimmingData(u16CrTrimData); u8TrimState++; break; case CR_TRIMMING_PROC_TMINCOARSE_MEAS_START: case CR_TRIMMING_PROC_TMINFINE_MEAS_START: m_u32CntIrqMeasure = 0u; // Enable count operatoin Bt_Pwc_EnableCount(&BT0); u8TrimState++; break; case CR_TRIMMING_PROC_TMINCOARSE_MEAS_ONGOING: case CR_TRIMMING_PROC_TMINFINE_MEAS_ONGOING: while(MEAN_CNT > m_u32CntIrqMeasure) { if(m_u32CntIrqOverflow) { // Disable count operatoin Bt_Pwc_DisableCount(&BT0); return CR_TRIMMING_RET_ERR; } } // Disable count operatoin Bt_Pwc_DisableCount(&BT0); u8TrimState++; break; case CR_TRIMMING_PROC_TMINCOARSE_MEAS_FINISH: case CR_TRIMMING_PROC_TMINFINE_MEAS_FINISH: u32MeasData = 0u; for(u8i=0;u8i<MEAN_CNT;u8i++) { u32MeasData += m_aMeasureResult[u8i]; } u32MeasData = u32MeasData/MEAN_CNT; if(CR_TRIMMING_PROC_TMINCOARSE_MEAS_FINISH == u8TrimState) { f32TMinCoarse = (float32_t)u32MeasData/(float32_t)(u32SysClk*PWC_CNT ); } else { f32TMinFine = (float32_t)u32MeasData/(float32_t)(u32SysClk*PWC_CNT ); } u8TrimState++; break; case CR_TRIMMING_PROC_CAL_COARSE_VAL: case CR_TRIMMING_PROC_CAL_FINE_VAL: if(CR_TRIMMING_PROC_CAL_COARSE_VAL == u8TrimState) { stcCoarseCycle.f32TMaxCoarse = f32TMaxCoarse; stcCoarseCycle.f32TMinCoarse = f32TMinCoarse; stcCoarseCycle.f32TTarget = 1u/f32ExpCrFreq; CalCrCoarse(&u8CoarseData, &stcCoarseCycle); } else { stcFineCycle.f32TMaxFine = f32TMaxFine; stcFineCycle.f32TMinFine = f32TMinFine; stcFineCycle.f32TTarget = 1/f32ExpCrFreq; CalCrFine(&u8FineData, &stcFineCycle); } u8TrimState++; break; case CR_TRIMMING_PROC_SET_COARSE_VAL: case CR_TRIMMING_PROC_SET_FINE_VAL: if(CR_TRIMMING_PROC_SET_COARSE_VAL == u8TrimState) { u8FineData = 0x00u; u16CrTrimData = (u8FineData & 0x1Fu) | ((u8CoarseData & 0x1Fu)<<5u); } else { u16CrTrimData = (u8FineData & 0x1Fu) | ((u8CoarseData & 0x1Fu)<<5u); } #if (PDL_MCU_TYPE == PDL_FM3_TYPE8) || (PDL_MCU_TYPE == PDL_FM3_TYPE9) || \ (PDL_MCU_TYPE == PDL_FM3_TYPE10) || (PDL_MCU_TYPE == PDL_FM3_TYPE11) || \ (PDL_MCU_TYPE == PDL_FM3_TYPE12) || (PDL_MCU_CORE == PDL_FM0P_CORE) || \ (PDL_MCU_CORE == PDL_FM4_CORE) Cr_SetTempTrimmingData(u8TempTrimData); #endif Cr_SetFreqTrimmingData(u16CrTrimData); u8TrimState++; break; case CR_TRIMMING_PROC_TUNE_COARSE_VAL: case CR_TRIMMING_PROC_TUNE_FINE_VAL: m_u32CntIrqMeasure = 0u; // Enable count operatoin Bt_Pwc_EnableCount(&BT0); while(MEAN_CNT > m_u32CntIrqMeasure) { if(m_u32CntIrqOverflow) { // Disable count operatoin Bt_Pwc_DisableCount(&BT0); return CR_TRIMMING_RET_ERR; } } // Disable count operatoin Bt_Pwc_DisableCount(&BT0); u32MeasData = 0u; for(u8i=0u;u8i<MEAN_CNT;u8i++) { u32MeasData += m_aMeasureResult[u8i]; } u32MeasData = u32MeasData/MEAN_CNT; if(u8TrimState == CR_TRIMMING_PROC_TUNE_COARSE_VAL) { f32FinalCycle = (float32_t)u32MeasData/(float32_t)(u32SysClk*PWC_CNT ); if (f32FinalCycle < 1u / f32ExpCrFreq) /* Freq > 4MHz, continue to tune */ { if(u8CoarseData == 0u) { return CR_TRIMMING_RET_ERR; } u8CoarseData--; u8TrimState--; } else { u8TrimState = CR_TRIMMING_PROC_TMAXFINE_MEAS_INIT; } } else { f32FinalCycle = (float32_t)u32MeasData/(float32_t)(u32SysClk*PWC_CNT ); if(f32FinalCycle < 1u/f32ExpCrFreq) { if(0u == u8FineData) { return CR_TRIMMING_RET_ERR; } u8FineData--; /* Freq > 4MHz, sub fine data */ } else { if(0x1Fu == u8FineData) { return CR_TRIMMING_RET_ERR; } u8FineData++; /* Freq < 4MHz, add fine data */ } u8TrimState--; if((f32FinalCycle > 1u / f32CrMaxFreq) && (f32FinalCycle < 1u / f32CrMinFreq))/* Freq > 4MHz, continue to tune */ { u8TrimState = CR_TRIMMING_PROC_FINISH; } } break; case CR_TRIMMING_PROC_FINISH: u16CrTrimData = (u8FineData & 0x1Fu) | ((u8CoarseData & 0x1Fu)<<5u); #if (PDL_MCU_TYPE == PDL_FM3_TYPE8) || (PDL_MCU_TYPE == PDL_FM3_TYPE9) || \ (PDL_MCU_TYPE == PDL_FM3_TYPE10) || (PDL_MCU_TYPE == PDL_FM3_TYPE11) || \ (PDL_MCU_TYPE == PDL_FM3_TYPE12) || (PDL_MCU_CORE == PDL_FM0P_CORE) || \ (PDL_MCU_CORE == PDL_FM4_CORE) Cr_SetTempTrimmingData(u8TempTrimData); #endif Cr_SetFreqTrimmingData(u16CrTrimData); break; } if(u8TrimState == CR_TRIMMING_PROC_FINISH) { *pCrTrimmingData = u16CrTrimData | (u8TempTrimData << 16u) | (0x00u<<24u); break; } } return CR_TRIMMING_RET_OK; }