Quark D2000 PWM Signal Offset
cartejac Mar 2, 2017 8:44 PMHello all,
As part of my senior capstone for an Electrical Computer Engineering degree I am trying to use a Quark D2000 microcontroller to generate some PWM signals with fairly precise time offsets from one another (90 degrees of an 800kHz waveform, for example)
I have been struggling to get the PWM module to behave as I expect it to. I am trying to configure one of the PWM/Timers to generate an interrupt after a certain period and then reconfigure itself as a PWM signal generator. At the same time, I am delaying the start of the other PWM timer using a system wait function call. I understand that I might not be able to get the waveforms to start at precisely the same time given the single-threaded nature of this processor, but I cannot get nearly the accuracy that I expect. Using the code below:
void pwm_delay_cb(void* pwm_config, uint32_t timer_status)
{
send_string_log_pkt("Timer1 cb fired.");
qm_pwm_stop(QM_PWM_0, QM_PWM_ID_1); //TODO: Is this necessary? The timer might stop on overflow
qm_pwm_config_t* p = (qm_pwm_config_t *) pwm_config;
if (qm_pwm_set_config(QM_PWM_0, QM_PWM_ID_1, p) != 0){
return;
}
qm_pwm_start(QM_PWM_0, QM_PWM_ID_1);
qm_pmux_select(QM_PIN_ID_24, QM_PMUX_FN_2);
free(pwm_config);
}
/* There's just one space for interrupt callbacks, for some reason.
* and setting a configuration without interrupts or a callback clears
* previously set interrupts. BEWARE
* The delay appears to be controllable at scales larger than 15us,
* but when you try to compress the offset to less than that, the
* waveforms do not shift....
*/
uint8_t enable_pwm(uint32_t high_ticks, uint32_t low_ticks, uint32_t delay_ticks)
{
// Go for PWM enabled, no interrupt
qm_pwm_config_t delay_config;
qm_pwm_config_t *pwm_config = malloc(sizeof(qm_pwm_config_t));
pwm_config->hi_count = high_ticks;
pwm_config->lo_count = low_ticks;
pwm_config->mask_interrupt = true;
pwm_config->mode = QM_PWM_MODE_PWM;
// Set the configuration for PWM0
if (qm_pwm_set_config(QM_PWM_0, QM_PWM_ID_0, pwm_config) != 0){
return -1;
}
// Set it off!
// Set up the delay for the second PWM signal
delay_ticks = delay_ticks + 50; // Tack on additional delay for the pulses to start at the same time. //75 to 63, huge jump
/* Somewhere between 500 and 600, there's a huge jump... */
delay_config.hi_count = delay_ticks;
delay_config.lo_count = delay_ticks;
delay_config.mask_interrupt = false;
delay_config.callback = pwm_delay_cb;
delay_config.callback_data = pwm_config;
delay_config.mode = QM_PWM_MODE_TIMER_FREE_RUNNING;
if (qm_pwm_set_config(QM_PWM_0, QM_PWM_ID_1, &delay_config) != 0){
return -1;
}
/*qm_pwm_reg_t* r = QM_PWM;
r->timer[QM_PWM_ID_1].loadcount = delay_ticks;
QM_PWM->timer[QM_PWM_ID_1].controlreg |= 1; // Force delay_ticks into currentvalue field
QM_PWM->timer[QM_PWM_ID_1].controlreg &= ~1;
QM_PWM->timer[QM_PWM_ID_1].controlreg |= 1; // Force delay_ticks into currentvalue field
QM_PWM->timer[QM_PWM_ID_1].controlreg &= ~1;
QM_PWM->timer[QM_PWM_ID_1].controlreg |= 1; // Force delay_ticks into currentvalue field
QM_PWM->timer[QM_PWM_ID_1].controlreg &= ~1;*/
// Request the routing of the timer interrupt signal
qm_irq_request(QM_IRQ_PWM_0, qm_pwm_isr_0);
// Turn on Timer 1
qm_pwm_start(QM_PWM_0, QM_PWM_ID_1);
clk_sys_udelay(1);
qm_pwm_start(QM_PWM_0, QM_PWM_ID_0);
clk_sys_udelay(1000);
// Change the pin multiplexing to put the signal on the physical pin
qm_pmux_select(QM_PIN_ID_19, QM_PMUX_FN_2);
return 0;
}