1. 用於步進電機的 PWM 斬波介紹 兩相四線步進電機驅動中使用的 PWM 斬波主要有: 1.ON(打開)+FastDecay(快衰減) 2.ON(打開)+SlowDecay(慢衰減) 3.ON(打開)+SlowDecay(慢衰減) +ON(打開)+SlowDecay(慢衰減) 4.ON(打開)+SlowDecay(慢衰減) +FastDecay(快衰減) +SlowDecay(慢衰減) 以上斬波模式在 H 橋中的上橋 PWM 信號和其生成的電流波形分別如下圖所示: 從上圖可以看出採用 ON(打開)+SlowDecay(慢衰減) +ON(打開)+SlowDecay(慢衰減) 模式時電流紋波最小,步進電機的電流會有比較好的正弦度,可以使電機超靜音運行,對提高細分數有很大的比重。 eFlexPWM 是一個很靈活的定時器外設,其包含 4 個子模塊,每個子模塊可以分別控制一個半橋,每個半橋的死區大小任意設置,可以實現中心對齊工作模式和邊緣對齊工作模式,上升沿和下降沿的位置可以任意設置,子模塊之間可以觸發同步等等,具體可以查看 RM 對應的章節,本文主要使用其可以在 counter 計數到模值和在半周期時刻時可以重載寄存器的功能實現 ON(打開)+SlowDecay(慢衰減) +ON(打開)+SlowDecay(慢衰減) 的功能,如下圖是 eFlexPWM 子模塊的框圖。 比較寄存器 VAL2 定義每路 PWM 的上升沿,VAL3 定義 PWM 的下升沿,INIT 寄存器和 VAL1 寄存器定義 counter 計數的範圍,由 PWM 的頻率計算得出,VAL0 定義半周期時重載的時刻,另一個時刻是 counter 計數到 VAL1 時發生重載, ON(打開)+SlowDecay(慢衰減) +ON(打開)+SlowDecay(慢衰減) PWM 斬波生成過程為: counter 計數到 VAL1 時發生中斷,計算下半周的 PWM 占空比,counter 計數到 VAL0 時再次發生中斷,計算上半周的 PWM 占空比,占空比根據實際需要來計算,各寄存器影響 PWM 波形如下圖所示: 初始化代碼: 其中主要是設置各個子模塊的 CTRL 寄存器的 11 位為 1,即使能 HalfReload。
/* All interrupts disabled, safe manual fault clearing, inversed logic (trigger level = high) */ #if 0 PWMBase->FCTRL &= ~(PWM_FCTRL_FLVL_MASK | PWM_FCTRL_FAUTO_MASK | PWM_FCTRL_FSAFE_MASK | PWM_FCTRL_FIE_MASK); /* clear FCTRL register prior further settings */ PWMBase->FCTRL |= PWM_FCTRL_FLVL(0x1UL); PWMBase->FCTRL |= PWM_FCTRL_FAUTO(0x1UL); PWMBase->FCTRL |= PWM_FCTRL_FSAFE(0x1UL); PWMBase->FCTRL |= PWM_FCTRL_FIE(0UL); /* FAULT 0 & FAULT 1 - Interrupt disable */ #endif /* Clear all fault flags */ PWMBase->FSTS = (PWMBase->FSTS & (uint16_t)(~PWM_FSTS_FFLAG_MASK)) | PWM_FSTS_FFLAG(0xFUL); PWMBase->MASK = 0;//UPDATE_MASK MASKA MASKB MASKx PWMBase->SWCOUT = 0; PWMBase->DTSRCSEL = 0;// PWMBase->SM[0].FRCTRL |= (uint16_t)((0UL << 4UL) | (0UL << 2UL) | (0UL << 1UL)) ;//FRAC45_EN 4,FRAC23_EN 2,FRAC1_EN1 PWMBase->SM[0].FRACVAL2 = (uint16_t)(0UL << 11UL); PWMBase->SM[0].FRACVAL3 = (uint16_t)(0UL << 11UL); PWMBase->SM[1].FRACVAL2 = (uint16_t)(0UL << 11UL); PWMBase->SM[1].FRACVAL3 = (uint16_t)(0UL << 11UL); PWMBase->SM[2].FRACVAL2 = (uint16_t)(0UL << 11UL); PWMBase->SM[2].FRACVAL3 = (uint16_t)(0UL << 11UL); PWMBase->SM[3].FRACVAL2 = (uint16_t)(0UL << 11UL); PWMBase->SM[3].FRACVAL3 = (uint16_t)(0UL << 11UL); PWMBase->SM[0].CTRL2 = (uint16_t)(( 0x0UL << 15UL ) //DBGEN |( 0x0UL << 14UL ) //WAITEN,Sleep Enable |( 0x1UL << 13UL ) //INDEP,0b - PWM_A and PWM_B form a complementary PWM pair. |( 0x1UL << 12UL ) //PWM23_INIT, |( 0x1UL << 11UL ) //PWM45_INIT |( 0x0UL << 10UL ) //PWMX_INIT |( 0x0UL << 8UL ) //INIT_SEL,counter load init value,00 Local sync,01 Master reload,10 Master sync,11 EXT_SYNC |( 0x0UL << 7UL ) //FRCEN |( 0x1UL << 6UL ) //FORCE |( 0x4UL << 3UL ) /* FORCE_SEL 000 local force 001 master force 010 local reload 011 master reload 100 local sync 101 master sync 110 external force 111 external sync */ |( 0x0UL << 2UL ) //RELOAD_SEL,0b - The local RELOAD signal |( 0x0UL << 0UL )); //CLK_SEL, //00b - The IPBus clock //01b - EXT_CLK //10b - Submodule 0’s clock (AUX_CLK) PWMBase->SM[1].CTRL2 = (uint16_t)(( 0x0UL << 15UL ) //DBGEN |( 0x0UL << 14UL ) //WAITEN,Sleep Enable |( 0x1UL << 13UL ) //INDEP,0b - PWM_A and PWM_B form a complementary PWM pair. |( 0x1UL << 12UL ) //PWM23_INIT, |( 0x1UL << 11UL ) //PWM45_INIT |( 0x0UL << 10UL ) //PWMX_INIT |( 0x2UL << 8UL ) //INIT_SEL,counter load init value,00 Local sync,01 Master reload,10 Master sync,11 EXT_SYNC |( 0x0UL << 7UL ) //FRCEN |( 0x1UL << 6UL ) //FORCE |( 0x5UL << 3UL ) /* FORCE_SEL 000 local force 001 master force 010 local reload 011 master reload 100 local sync 101 master sync 110 external force 111 external sync */ |( 0x1UL << 2UL ) //RELOAD_SEL,1b - The master RELOAD signal |( 0x0UL << 0UL )); //CLK_SEL, //00b - The IPBus clock //01b - EXT_CLK //10b - Submodule 0’s clock (AUX_CLK) PWMBase->SM[2].CTRL2 = (uint16_t)(( 0x0UL << 15UL ) //DBGEN |( 0x0UL << 14UL ) //WAITEN,Sleep Enable |( 0x1UL << 13UL ) //INDEP,0b - PWM_A and PWM_B form a complementary PWM pair. |( 0x1UL << 12UL ) //PWM23_INIT, |( 0x1UL << 11UL ) //PWM45_INIT |( 0x0UL << 10UL ) //PWMX_INIT |( 0x2UL << 8UL ) //INIT_SEL,counter load init value,00 Local sync,01 Master reload,10 Master sync,11 EXT_SYNC |( 0x0UL << 7UL ) //FRCEN |( 0x1UL << 6UL ) //FORCE |( 0x5UL << 3UL ) /* FORCE_SEL 000 local force 001 master force 010 local reload 011 master reload 100 local sync 101 master sync 110 external force 111 external sync */ |( 0x1UL << 2UL ) //RELOAD_SEL,1b - The master RELOAD signal |( 0x0UL << 0UL )); //CLK_SEL, //00b - The IPBus clock //01b - EXT_CLK //10b - Submodule 0’s clock (AUX_CLK) PWMBase->SM[3].CTRL2 = (uint16_t)(( 0x0UL << 15UL ) //DBGEN |( 0x0UL << 14UL ) //WAITEN,Sleep Enable |( 0x1UL << 13UL ) //INDEP,0b - PWM_A and PWM_B form a complementary PWM pair. |( 0x1UL << 12UL ) //PWM23_INIT, |( 0x1UL << 11UL ) //PWM45_INIT |( 0x0UL << 10UL ) //PWMX_INIT |( 0x2UL << 8UL ) //INIT_SEL,counter load init value,00 Local sync,01 Master reload,10 Master sync,11 EXT_SYNC |( 0x0UL << 7UL ) //FRCEN |( 0x1UL << 6UL ) //FORCE |( 0x5UL << 3UL ) /* FORCE_SEL 000 local force 001 master force 010 local reload 011 master reload 100 local sync 101 master sync 110 external force 111 external sync */ |( 0x1UL << 2UL ) //RELOAD_SEL,1b - The master RELOAD signal |( 0x0UL << 0UL )); //CLK_SEL, //00b - The IPBus clock //01b - EXT_CLK //10b - Submodule 0’s clock (AUX_CLK) /* Start PWMs (set load OK flags and run - we need to trigger the ADC) */ PWMBase->MCTRL = (PWMBase->MCTRL & (uint16_t)(~PWM_MCTRL_CLDOK_MASK)) | PWM_MCTRL_CLDOK(0xF); PWMBase->MCTRL = (PWMBase->MCTRL & (uint16_t)(~PWM_MCTRL_LDOK_MASK)) | PWM_MCTRL_LDOK(0xF); PWMBase->MCTRL = (PWMBase->MCTRL & (uint16_t)(~PWM_MCTRL_RUN_MASK)) | PWM_MCTRL_RUN(0xF); //PWMBase->OUTEN = 0xFF0;//0xFF0,11-8,PWMA3_EN ~ PWMA0_EN, 7-4 PWMB3_EN ~ PWMB0_EN, 3-0 PWMX3_EN ~ PWMX0_EN /* Enable & setup interrupt from PWMA */ // NVIC_SetPriority(FLEXPWM0_RELOAD0_IRQn, 1UL); // NVIC_EnableIRQ(FLEXPWM0_RELOAD0_IRQn); }
https://www.nxp.com.cn/docs/en/reference-manual/LPC553xRM.pdf |