AM32 电调学习–换相
#define INTERVAL_TIMER TIM2 ; 过零时间测量
#define TEN_KHZ_TIMER TIM6 ;tenKhzRoutine frq=1M load=1M/20k
#define UTILITY_TIMER TIM17
#define COM_TIMER TIM14 //PeriodElapsedCallback 过零后等待时间中断
3. 换相
(0)换相过程简述
(1)六步换相定义
step1 2 3 4 5 6 ab cb ca ba bc ac
(2)过零点
a. 比较器设置
void changeCompInput()
{
if (step == 1 || step == 4) { // c floating ba xx xx ab xx xx
#ifdef N_VARIANT
current_EXTI_LINE = PHASE_C_EXTI_LINE;
active_COMP = PHASE_C_COMP_NUMBER;
#endif
LL_COMP_ConfigInputs(active_COMP, PHASE_C_COMP, LL_COMP_INPUT_PLUS_IO3);
}
if (step == 2 || step == 5) { // a floating ba bc xx ab cb xx
#ifdef N_VARIANT
current_EXTI_LINE = PHASE_A_EXTI_LINE;
active_COMP = PHASE_A_COMP_NUMBER;
#endif
LL_COMP_ConfigInputs(active_COMP, PHASE_A_COMP, LL_COMP_INPUT_PLUS_IO3);
}
if (step == 3 || step == 6) { // b floating ba bc ac ab cb ca
#ifdef N_VARIANT
current_EXTI_LINE = PHASE_B_EXTI_LINE;
active_COMP = PHASE_B_COMP_NUMBER;
#endif
LL_COMP_ConfigInputs(active_COMP, PHASE_B_COMP, LL_COMP_INPUT_PLUS_IO3);
}
if (rising) {
LL_EXTI_DisableRisingTrig_0_31(LL_EXTI_LINE_18);
LL_EXTI_DisableRisingTrig_0_31(LL_EXTI_LINE_17);
LL_EXTI_EnableFallingTrig_0_31(current_EXTI_LINE);
} else { // falling bemf
LL_EXTI_EnableRisingTrig_0_31(current_EXTI_LINE);
LL_EXTI_DisableFallingTrig_0_31(LL_EXTI_LINE_17);
LL_EXTI_DisableFallingTrig_0_31(LL_EXTI_LINE_18);
}
}
b. 过零点后阻塞换相
void zcfoundroutine()
{ // only used in polling mode, blocking routine.
thiszctime = INTERVAL_TIMER_COUNT;
SET_INTERVAL_TIMER_COUNT(0);
commutation_interval = (thiszctime + (3 * commutation_interval)) / 4;
advance = commutation_interval / advancedivisor;
waitTime = commutation_interval / 2 - advance;
while ((INTERVAL_TIMER_COUNT) < (waitTime)) {
if (zero_crosses < 10) {
break;
}
}
#ifdef MCU_GDE23
TIMER_CAR(COM_TIMER) = waitTime;
#endif
#ifdef MCU_F051
COM_TIMER->ARR = waitTime;
#endif
commutate();
bemfcounter = 0;
bad_count = 0;
zero_crosses++;
if (stall_protection || RC_CAR_REVERSE) {
if (zero_crosses >= 20 && commutation_interval <= 2000) {
old_routine = 0;
enableCompInterrupts(); // enable interrupt
}
} else {
if (zero_crosses > 30) {
old_routine = 0;
enableCompInterrupts(); // enable interrupt
}
}
}
c.过零点中断处理
void interruptRoutine()
{
if (average_interval > 125) {
if ((INTERVAL_TIMER_COUNT < 125) && (duty_cycle < 600) && (zero_crosses < 500)) { // should be impossible, desync?exit anyway
return;
}
if (INTERVAL_TIMER_COUNT < (commutation_interval >> 1)) {
return;
}
stuckcounter++; // stuck at 100 interrupts before the main loop happens
// again.
if (stuckcounter > 100) {
maskPhaseInterrupts();
zero_crosses = 0;
return;
}
}
thiszctime = INTERVAL_TIMER_COUNT;
if (rising) {
for (int i = 0; i < filter_level; i++) {
#ifdef MCU_F031
if ((current_GPIO_PORT->IDR & current_GPIO_PIN) == (uint32_t)GPIO_PIN_RESET) {
#else
if (getCompOutputLevel()) {
#endif
return;
}
}
} else {
for (int i = 0; i < filter_level; i++) {
#ifdef MCU_F031
if ((current_GPIO_PORT->IDR & current_GPIO_PIN) != (uint32_t)GPIO_PIN_RESET) {
#else
if (!getCompOutputLevel()) {
#endif
return;
}
}
}
maskPhaseInterrupts();
__disable_irq();
if (INTERVAL_TIMER_COUNT > thiszctime) {
SET_INTERVAL_TIMER_COUNT(INTERVAL_TIMER_COUNT - thiszctime);
} else {
SET_INTERVAL_TIMER_COUNT(0);
}
waitTime = waitTime >> fast_accel;
SET_AND_ENABLE_COM_INT(waitTime); // enable COM_TIMER interrupt
__enable_irq();
}
/**
* @brief This function handles ADC1, COMP1 and COMP2 interrupts (COMP
* interrupts through EXTI lines 17 and 18).
*/
void ADC1_COMP_IRQHandler(void)
{
if (LL_EXTI_IsActiveFallingFlag_0_31(LL_EXTI_LINE_18)) {
LL_EXTI_ClearFallingFlag_0_31(LL_EXTI_LINE_18);
interruptRoutine();
return;
}
if (LL_EXTI_IsActiveRisingFlag_0_31(LL_EXTI_LINE_18)) {
LL_EXTI_ClearRisingFlag_0_31(LL_EXTI_LINE_18);
interruptRoutine();
return;
}
if (LL_EXTI_IsActiveFallingFlag_0_31(LL_EXTI_LINE_17)) {
LL_EXTI_ClearFallingFlag_0_31(LL_EXTI_LINE_17);
interruptRoutine();
return;
}
if (LL_EXTI_IsActiveRisingFlag_0_31(LL_EXTI_LINE_17)) {
LL_EXTI_ClearRisingFlag_0_31(LL_EXTI_LINE_17);
interruptRoutine();
return;
}
}
(d) 换相等待中断(tim14)
void PeriodElapsedCallback()
{
DISABLE_COM_TIMER_INT(); // disable interrupt
commutate();
commutation_interval = ((3 * commutation_interval) + thiszctime) >> 2;
advance = (commutation_interval >> 3) * advance_level; // 60 divde 8 7.5 degree increments
waitTime = (commutation_interval >> 1) - advance;
if (!old_routine) {
enableCompInterrupts(); // enable comp interrupt
}
if (zero_crosses < 10000) {
zero_crosses++;
}
}
(3)换相过程
(a) 换相动作:
获取了每个过零点的时间 commutation_intervals[step - 1]= thiszctime,以0.5us为单位
void commutate()
{
if (forward == 1) {
step++;
if (step > 6) {
step = 1;
desync_check = 1;
}
rising = step % 2;
} else {
step--;
if (step < 1) {
step = 6;
desync_check = 1;
}
rising = !(step % 2);
}
__disable_irq(); // don't let dshot interrupt
if (!prop_brake_active) {
comStep(step);
}
__enable_irq();
changeCompInput();
if (stall_protection || RC_CAR_REVERSE) {
if (average_interval > 2000) {
old_routine = 1;
}
}
bemfcounter = 0;
zcfound = 0;
commutation_intervals[step - 1] = thiszctime; // just used to calulate average
}
void comStep(int newStep)
{
switch (newStep) {
case 1: // A-B
phaseCFLOAT();
phaseBLOW();
phaseAPWM();
break;
case 2: // C-B
phaseAFLOAT();
phaseBLOW();
phaseCPWM();
break;
case 3: // C-A
phaseBFLOAT();
phaseALOW();
phaseCPWM();
break;
case 4: // B-A
phaseCFLOAT();
phaseALOW();
phaseBPWM();
break;
case 5: // B-C
phaseAFLOAT();
phaseCLOW();
phaseBPWM();
break;
case 6: // A-C
phaseBFLOAT();
phaseCLOW();
phaseAPWM();
break;
}
}
(b) 换相后旋转参数获取(6次换相时间,05us为间隔)
commutation_intervals[x]以0.5us为单位 e_com_time 以1us为单位 控制输入值duty_cycle ,以us为单位? input值的范围 47–2047,map 到 deadtime–max_arr
e_com_time = ((commutation_intervals[0] + commutation_intervals[1] + commutation_intervals[2] + commutation_intervals[3] + commutation_intervals[4] + commutation_intervals[5]) + 4) >> 1; // COMMUTATION INTERVAL IS 0.5US INCREMENTS
average_interval = e_com_time / 3;
duty_cycle = duty_cycle_setpoint;
if (use_sin_start) {
duty_cycle_setpoint = map(input, 137, 2047, minimum_duty_cycle, TIMER1_MAX_ARR);
} else {
duty_cycle_setpoint = map(input, 47, 2047, minimum_duty_cycle, TIMER1_MAX_ARR);
}
uint16_t minimum_duty_cycle = DEAD_TIME;
#define DEAD_TIME 60
uint16_t TIMER1_MAX_ARR = TIM1_AUTORELOAD; // maximum auto reset register value
#define TIM1_AUTORELOAD 2667