Hello,
So I searched the forums and found multiple threads on this, but I just cannot make it work.
I am making a small motor controller which I want to be current controlled. I am using a MC33926 H-bridge and a Due to to this. Using pins C3 (35) and C5 (37) for PWM signals (PWM0H and PWM1H) and arduino-analog 0 (A7) for current measurement.
The idea is to use an event line to trigger ADC conversions in sync with PWM. As far as I understand the datasheet, this is the way it works: A comparison trigger (ref page 993 sam3x8e) can be set to trigger at a given value for PWM channel 0. This trigger can be used to trigger the ADC to measure the motor current at this point. I am using PWM0H for one channel and PWM1H for the other channel. My idea is to use 4 comparison triggers per period of the PWM (symmetrical pwm). One for duty cycle 1 and one for duty cycle 2 when the counter is incrementing and the same when it is decrementing. I have verified (with an oscilloscope) that the current signal I measure is correct.
Problem: I have configured one comparison trigger and it triggers about 12 times every period. This gives me a good description of the current, but I would like to measure the minimum and maximum value and take the average of the two to represent the current. Now I get way to many readings, and I just can't see why.
I have attached a plot of the current I measure and a plot showing my switching pattern and where to measure current (Red circles).
My Code:
/* PWM is connected to pins C3 and C5.
* PWMH0: C3 (peripheral B)
* PWMH1: C5 (peripheral B)
*
*
*/
#define DATASIZE 100
uint16_t testduty = 8000;
volatile uint16_t testdata[DATASIZE] = {0};
volatile uint16_t testdataIndex = 0;
volatile bool dataReady = false;
volatile uint16_t testdata2[DATASIZE] = {0};
volatile uint16_t lastData = 0;
void setup() {
Serial.begin(9600);
// ************ Setup PWM ******************
// disable PIO for C3 and C5
REG_PIOC_PDR = REG_PIOC_PSR | PIO_PER_P3 | PIO_PER_P5;
//B101000, Peripheral AB Select Register (select b)
REG_PIOC_ABSR = REG_PIOC_ABSR | PIO_ABSR_P3 | PIO_ABSR_P5 ;
//Peripheral Clock Enable Register 1 (activate clock for PWM, id36, bit5 of PMC_PCSR1)
REG_PMC_PCER1 = REG_PMC_PCER1 | 16;
// Set channel 0 and 1 as synchrnous channels
REG_PWM_SCM = PWM_SCM_SYNC0 | PWM_SCM_SYNC1;
REG_PWM_CMR0 |= PWM_CMR_CALG; // Set symmetrical pwm alignment
//*********** PWM EVENT LINES ******************
// Initial value for event line compares
REG_PWM_CMPV0 = 8000;
// Set CTR to 0 and CPR to 0
REG_PWM_CMPM0 |= PWM_CMPM_CTR(0);
REG_PWM_CMPM0 |= PWM_CMPM_CPR(0);
// Select comparision 0 for event line 1
PWM->PWM_ELMR[1] = PWM_ELMR_CSEL0;
// Enable event lines
REG_PWM_CMPM0 |= PWM_CMPM_CEN;
//*********************************************************
REG_PWM_ENA = REG_PWM_SR | PWM_ENA_CHID0 | PWM_ENA_CHID1; //PWM Enable Register | PWM Status Register (activate channels 0,1)
REG_PWM_CPRD0 = 16000; //Channe0 Period Register (84mhz/4200/2 = 20kHz)
set_duty_cycle(testduty);
// ************ Setup ADC ******************
PMC->PMC_PCER1 |= PMC_PCER1_PID37; // ADC power on
ADC->ADC_CR = ADC_CR_SWRST; // Reset ADC
ADC->ADC_MR |= ADC_MR_TRGEN_EN; // Hardware trigger selected by TRGSEL field is enabled
ADC->ADC_MR |= ADC_MR_TRGSEL_ADC_TRIG5; // Set trigger to pwm event line 1
ADC->ADC_MR |= 0x7f00; // Speed
ADC->ADC_IER |= ADC_IER_EOC7; // Enable interrupt for A7
ADC->ADC_CHER |= ADC_CHER_CH7; //enable ADC on pin A7
NVIC_EnableIRQ (ADC_IRQn) ; // enable ADC interrupt vector
}
void loop() {
// *** Serial control routine ****
if(Serial.available() > 0){
char c = Serial.read();
switch(c){
case 'q': testduty+= 200; Serial.println(testduty); break;
case 'w': testduty-= 200; Serial.println(testduty); break;
case 'a': testduty = 8000; break;
case 'z': turn_on_pwm(); break;
case 'x': turn_off_pwm(); break;
case 'c': testduty = 12000; break;
case 'v': testduty = 3000; break;
case 'o': doADCtest(); Serial.println(" ** DO test ** "); break;
}
set_duty_cycle(testduty);
Serial.println(c);
}
if(dataReady){
printTestData();
}
}
void turn_on_pwm(){
REG_PWM_ENA = REG_PWM_SR | PWM_ENA_CHID0 | PWM_ENA_CHID1;
}
void turn_off_pwm(){
REG_PWM_DIS = REG_PWM_SR | PWM_ENA_CHID0 | PWM_ENA_CHID1;
}
void set_duty_cycle(uint16_t duty){
REG_PWM_CDTY0 = duty;
REG_PWM_CDTY1 = 16000-duty;
// Update ADC Triggers
REG_PWM_CMPVUPD0 = duty & 0xFFFFFF;
//REG_PWM_CMPVUPD1 = (16000-duty) & 0xFFFFFF;
}
void ADC_Handler(void) {
if (ADC->ADC_ISR & ADC_ISR_EOC7){
int val = *(ADC->ADC_CDR+7);
testdata[testdataIndex++] = val;
if(testdataIndex == DATASIZE){
dataReady = true;
testdataIndex = 0;
ADC->ADC_IDR |= ADC_IER_EOC7; // Disable adc interrupts
}
}
}
void doADCtest(){
ADC->ADC_IER |= ADC_IER_EOC7; // enable interrupts for adc 0
}
void printTestData(){
dataReady = false;
Serial.println("------------- Raw Data ---------------");
for (int i = 0; i<DATASIZE; i++){
Serial.println(testdata[i]);
}
Serial.println("------------- Done ---------------");
}