For my project, I'm emulating a quadrature encoder signal (A+B+index and 3 inverse). I use pwm signals for this with 50% dutycycle and a varying frequency dependent on the voltage read by pin A9 (analog channel 11). The phase shifts of the B signal I made with the deadtime generator. The Index signal is not yet implemented.
During the PWM period I want to trigger the ADC to read the voltage. This works, but when the voltage gets zero, the PWM doesnt trigger an event line and doesn't read anymore. Is there a way to manually trigger the ADC? Or other solutions to this problem? Thanks!
void pwmWrite(uint32_t ulFreq) {
static uint8_t PWMEnabled = 0;
static uint8_t ADCEnabled = 0;
static uint8_t pin6Enabled = 0;
static uint8_t pin7Enabled = 0;
static uint8_t pin8Enabled = 0;
static uint8_t pin9Enabled = 0;
int duty_100 = 255;
int duty_75 = (((duty_100+1)/4)*3)-1;
int duty_50 = ((duty_100+1)/2)-1;
int duty_25 = ((duty_100+1)/4)-1;
if (!ADCEnabled) {
pmc_enable_periph_clk(ID_ADC);
adc_init(ADC, VARIANT_MCK, ADC_FREQ_MAX, 0);
adc_configure_timing(ADC, 0, ADC_SETTLING_TIME_0, 0);
adc_stop_sequencer(ADC);
adc_enable_channel(ADC, (adc_channel_num_t)11);
adc_enable_interrupt(ADC, ADC_IER_DRDY);
NVIC_EnableIRQ(ADC_IRQn);
ADCEnabled = 1;
}
if (!PWMEnabled) {
pmc_enable_periph_clk(ID_PWM);
PWMC_ConfigureClocks(0, 0, VARIANT_MCK );
PWMEnabled = 1;
}
// SETUP PINS 6 T/M 9
uint32_t chan6 = g_APinDescription[6].ulPWMChannel;
uint32_t chan7 = g_APinDescription[7].ulPWMChannel;
uint32_t chan8 = g_APinDescription[8].ulPWMChannel;
uint32_t chan9 = g_APinDescription[9].ulPWMChannel;
if (!pin6Enabled || !pin7Enabled || !pin8Enabled || !pin9Enabled) {
PIO_Configure(g_APinDescription[6].pPort, g_APinDescription[6].ulPinType, g_APinDescription[6].ulPin, g_APinDescription[6].ulPinConfiguration);
PIO_Configure(g_APinDescription[7].pPort, g_APinDescription[7].ulPinType, g_APinDescription[7].ulPin, g_APinDescription[7].ulPinConfiguration);
PIO_Configure(g_APinDescription[8].pPort, g_APinDescription[8].ulPinType, g_APinDescription[8].ulPin, g_APinDescription[8].ulPinConfiguration);
PIO_Configure(g_APinDescription[9].pPort, g_APinDescription[9].ulPinType, g_APinDescription[9].ulPin, g_APinDescription[9].ulPinConfiguration);
// CONFIGURE CHANNELS
PWMC_ConfigureChannel(PWM, chan6, PWM_CMR_CPRE_CLKA, 0, 0);
PWMC_ConfigureChannel(PWM, chan7, PWM_CMR_CPRE_CLKA, 0, PWM_CMR_CPOL);
PWMC_ConfigureChannel(PWM, chan8, PWM_CMR_CPRE_CLKA, 0, 0);
PWMC_ConfigureChannel(PWM, chan9, PWM_CMR_CPRE_CLKA, 0, PWM_CMR_CPOL);
// SET PERIODS
PWMC_SetPeriod(PWM, chan6, duty_100);
PWMC_SetPeriod(PWM, chan7, duty_100);
PWMC_SetPeriod(PWM, chan8, duty_100);
PWMC_SetPeriod(PWM, chan9, duty_100); // PWM_MAX_DUTY_CYCLE (100%)
// SET DUTY CYCLES
PWMC_SetDutyCycle(PWM, chan6, duty_50);
PWMC_SetDutyCycle(PWM, chan7, duty_50);
PWMC_SetDutyCycle(PWM, chan8, duty_75);
PWMC_SetDutyCycle(PWM, chan9, duty_75);
//SET DEAD TIME
PWM->PWM_CH_NUM[chan8].PWM_CMR |= PWM_CMR_DTE; // added, enable channel dead time DTE=1
PWM->PWM_CH_NUM[chan9].PWM_CMR |= PWM_CMR_DTE;
PWMC_SetDeadTime(PWM, chan8, 0, duty_25);
PWMC_SetDeadTime(PWM, chan9, 0, duty_25);
//SYNC CHANNELS
PWMC_ConfigureSyncChannel(PWM, ( PWM_SCM_SYNC4 | PWM_SCM_SYNC5 | PWM_SCM_SYNC6 | PWM_SCM_SYNC7), PWM_SCM_UPDM_MODE2, 0, 0);
PWMC_SetSyncChannelUpdateUnlock(PWM); // PWM_SCUC set UPDULOCK to 1, update next period
PWMC_SetSyncChannelUpdatePeriod(PWM, duty_100); // update period of the synchronous channels PWM_SCUP
// EVENT LINES FOR ADC
PWMC_ConfigureEventLineMode( PWM, 0, 1 ) ;
PWMC_ConfigureComparisonUnit(PWM, 0, (duty_100/2), 1);
// SET CHANNEL 0 FOR SYNC
PWMC_ConfigureChannel(PWM, 0, PWM_CMR_CPRE_CLKA, 0, 0);
PWMC_SetPeriod(PWM, 0, duty_100);
PWMC_SetDutyCycle(PWM, 0, duty_50);
PWMC_EnableChannel(PWM, 0);
// CONFIGURE TRIGGER ON EVENT LINE
adc_configure_trigger(ADC, ADC_TRIG_PWM_EVENT_LINE_0, 0);
pin6Enabled = 1;
pin7Enabled = 1;
pin8Enabled = 1;
pin9Enabled = 1;
}
if (lastState == 0 && CW == 1) {
PWM->PWM_CH_NUM[chan8].PWM_CMR |= PWM_CMR_CPOL; // set CPOL 0
PWM->PWM_CH_NUM[chan9].PWM_CMR &= 0xFFFFFDFF;
lastState = 1;
}
if (lastState == 1 && CW == 0) {
PWM->PWM_CH_NUM[chan8].PWM_CMR &= 0xFFFFFDFF; // set CPOL 0
PWM->PWM_CH_NUM[chan9].PWM_CMR |= PWM_CMR_CPOL;
lastState = 0;
}
PWMC_ConfigureClocks(ulFreq * duty_100, 0, VARIANT_MCK );
return;
}
// ADC Interrupt handler.
void ADC_Handler(){
uint32_t ul_Value;
if ((adc_get_status(ADC) & ADC_ISR_DRDY) == ADC_ISR_DRDY) {
ul_Value = adc_get_latest_value(ADC);
//Serial.println(ul_Value);
}
PWMC_ConfigureClocks(ul_Value*255, 0, VARIANT_MCK );
}