SAMD20 changing CC0 in match pwm mode with causing wraparound - Page 1
Forum section: electronics / general

author: snarkysparky
author_rank: Frequent Contributor
timestamp: February 20, 2020, 05:52:19 pm
content: CC0 is the TOP value in this mode. MPWM . The TOP value sets the PWM period. If a new TOP value is writtenwhen the counter has already passed that value then a wraparound occurs. IE. there is not another transition until the counter has passed maximum value.Later SAM devices have a preload register for this.So it seems the safest case is to write the new top value immediately after a counter reset.All i know to do is put this snip of code somewhere it is guaranteed to run with very little latency.Code:if(REG_TC7_INTFLAG & TC_INTFLAG_MC0) // check for MC0 match{REG_TC7_INTFLAG = TC_INTFLAG_MC0; // writing should clear..if(TC7CC0HasNewValueFlag) // must write new CC0 value immediately after rollover of MC1{TC7CC0HasNewValueFlag = 0;REG_TC7_COUNT16_CC0 = (FeedMotorRealTimeCCVal << 1); // period time is twice the CC1 value for 50% dutywhile(REG_TC7_STATUS & TC_STATUS_SYNCBUSY);REG_TC7_COUNT16_CC1 = FeedMotorRealTimeCCVal ;while(REG_TC7_STATUS & TC_STATUS_SYNCBUSY);}}Seems kinda KLUGE to do thisIs there a better way???

author: ataradov
author_rank: Super Contributor
timestamp: February 20, 2020, 06:26:09 pm
content: You can enable MC0 interrupt when there is a new value to be written. The interrupt handler will do the update and disable further interrupts. This will make the code much cleaner.It probably does not apply here, but if you can wait for maximum of a period, then I also used something like thisCode:uint32_t prev = 0;do{prev = TC3->COUNT16.COUNT.reg;} while (TC3->COUNT16.COUNT.reg >= prev);TC3->COUNT16.CC.reg = newValue;It is essentially equivalent to your solution with flags.

author: Nominal Animal
author_rank: Super Contributor
timestamp: February 20, 2020, 07:53:23 pm
content: Why not stop/disable TC7, update the registers, then re-enable it?Something likeCode:static uint16_t tc7_cc0; // Just a copy, to save a synchronization cyclestatic uint16_t tc7_cc1; // Just a copy, to save a synchronization cyclestatic uint16_t tc7_ctrla; // Also a copy, to save a synchronization cycleif (TC7CC0HasNewValueFlag) {const uint16_t cc0 = FeedMotorRealTimeCCVal << 1;const uint16_t cc1 = FeedMotorRealTimeCCVal;uint16_t counter;TC7CC0HasNewValueFlag = 0;// Disable/stop TC7REG_TC7_CTRLA = tc7_ctrla & (~TC_CTRLA_ENABLE);// Clear MC0 interrupt flagREG_TC7_INTFLAG = TC_INTFLAG_MC0;// Obtain current countercounter = REG_TC7_COUNTER16;// Update period and rangeREG_TC7_CC0 = cc0;REG_TC7_CC1 = cc1;// Remap counter positionif (counter >= tc7_cc1) {// Second half (or later)counter = cc1 + (counter + TC7_OVERHEAD - tc7_cc1) * cc0 / tc7_cc0;if (counter >= cc0) {// Ensure CC0 will triggercounter = cc0 - 1;}} else {// First halfcounter = (counter + TC7_OVERHEAD - tc7_cc1) * cc1 / tc7_cc1;if (counter >= cc1) {// Ensure CC1 will triggercounter = cc1 - 1;}}REG_TC7_COUNTER16 = counter;// Re-enable TC7REG_TC7_CTRLA = tc7_ctrla | TC_CTRLA_ENABLE;// Save updated valuestc7_cc0 = cc0;tc7_cc1 = cc1;}The purpose of theTC7_OVERHEADis to represent the number of TC7 cycles this update takes; should be between 1 and 8.Because the PWM output changes state at CC1 and CC0, you'll want to change the counter to the same phase in the new period. The aboveifclauses may look silly, but it ensures the CC1/CC0 states are not missed due to rounding (or because the state change should have occurred during this function). TheTC7_OVERHEADis the number of TC7 cycles the counter would have advanced during the period we keep it disabled.This period change actually tries hard to retain the PWM signal phase, with minimal jitter (with correctTC7_OVERHEADvalue); this is why it should be safe to do at any time, and not just as soon as possible after an interrupt.BTW, the SAM D20 Family Datasheet says (page 96), that you don't need to check for synchronization; the MCU will wait for synchronization automatically, if the operation needs it, and the last operation hasn't synchronized yet.