The standard Libraries for Arduino by Espressif are very limiting. Previously I had to fix the Sync Function. Now the problem is Frequency, resolution and updating the duty cycle in an interrupt. There is an argument to make on getting the interrupt sub-routine very short. All of my motor commutation code (and SPI reads) are within an 5KHz timer. It consumes 5-10% CPU time. By default the Arduino code runs out of FLASH and running FLASH code in an interrupt causes problems (more info on why is needed).
MCPWM Initialization code
#define TIMER_CLK_PRESCALE 1
#define MCPWM_CLK_PRESCALE 0
#define MCPWM_PERIOD_PRESCALE 4
#define MCPWM_PERIOD_PERIOD 2048
static void IRAM_ATTR setup_mcpwm()
{
setup_mcpwm_pins();
mcpwm_config_t pwm_config;
pwm_config.frequency = 4000000; //frequency = 20000Hz
pwm_config.cmpr_a = 0; //duty cycle of PWMxA = 50.0%
pwm_config.cmpr_b = 0; //duty cycle of PWMxB = 50.0%
pwm_config.counter_mode = MCPWM_UP_DOWN_COUNTER; // Up-down counter (triangle wave)
pwm_config.duty_mode = MCPWM_DUTY_MODE_0; // Active HIGH
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); //Configure PWM0A & PWM0B with above settings
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_1, &pwm_config); //Configure PWM0A & PWM0B with above settings
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_2, &pwm_config); //Configure PWM0A & PWM0B with above settings
Serial.print("clk_cfg.prescale = ");
Serial.println( MCPWM0.clk_cfg.prescale);
Serial.print("timer[0].period.prescale = ");
Serial.println( MCPWM0.timer[0].period.prescale);
Serial.print("timer[0].period.period = ");
Serial.println( MCPWM0.timer[0].period.period);
Serial.print("timer[0].period.upmethod = ");
Serial.println( MCPWM0.timer[0].period.upmethod);
mcpwm_stop(MCPWM_UNIT_0, MCPWM_TIMER_0);
mcpwm_stop(MCPWM_UNIT_0, MCPWM_TIMER_1);
mcpwm_stop(MCPWM_UNIT_0, MCPWM_TIMER_2);
MCPWM0.clk_cfg.prescale = MCPWM_CLK_PRESCALE;
MCPWM0.timer[0].period.prescale = MCPWM_PERIOD_PRESCALE;
MCPWM0.timer[1].period.prescale = MCPWM_PERIOD_PRESCALE;
MCPWM0.timer[2].period.prescale = MCPWM_PERIOD_PRESCALE;
delay(1);
MCPWM0.timer[0].period.period = MCPWM_PERIOD_PERIOD;
MCPWM0.timer[1].period.period = MCPWM_PERIOD_PERIOD;
MCPWM0.timer[2].period.period = MCPWM_PERIOD_PERIOD;
delay(1);
MCPWM0.timer[0].period.upmethod =0;
MCPWM0.timer[1].period.upmethod =0;
MCPWM0.timer[2].period.upmethod =0;
delay(1);
Serial.print("clk_cfg.prescale = ");
Serial.println( MCPWM0.clk_cfg.prescale);
Serial.print("timer[0].period.prescale = ");
Serial.println( MCPWM0.timer[0].period.prescale);
Serial.print("timer[0].period.period = ");
Serial.println( MCPWM0.timer[0].period.period);
mcpwm_start(MCPWM_UNIT_0, MCPWM_TIMER_0);
mcpwm_start(MCPWM_UNIT_0, MCPWM_TIMER_1);
mcpwm_start(MCPWM_UNIT_0, MCPWM_TIMER_2);
mcpwm_sync_enable(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_SELECT_SYNC_INT0, 0);
mcpwm_sync_enable(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_SELECT_SYNC_INT0, 0);
mcpwm_sync_enable(MCPWM_UNIT_0, MCPWM_TIMER_2, MCPWM_SELECT_SYNC_INT0, 0);
delayMicroseconds(1000);
MCPWM0.timer[0].sync.out_sel = 1;
delayMicroseconds(1000);
MCPWM0.timer[0].sync.out_sel = 0;
} // setup_mcpwm
Some rules
STOP MCPWM before period, etc update
START MCPWM before SYNC
Delay long enough for at least one period before disabling sync .
Use IRAM_ATTR to change the code from FLASH based to RAM based for putting into the Interrupt
void IRAM_ATTR Three_Phases(void)
{
if (Motor_on==0)
{
PWMUU = 0;
PWMVV = 0;
PWMWW = 0;
}
MCPWM0.channel[0].cmpr_value[MCPWM_OPR_A].cmpr_val = PWMUU;
MCPWM0.channel[1].cmpr_value[MCPWM_OPR_A].cmpr_val = PWMVV;
MCPWM0.channel[2].cmpr_value[MCPWM_OPR_A].cmpr_val = PWMWW;
}
Because MCPWM0.timer[2].period.upmethod =0; is instant update this code update Duty cycle right away.
May have to check for glitches or change upmethod to start of period.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.