Skip to content

Commit a8da890

Browse files
author
oclyke
committed
fix analogWrite duty cycle preservation
now if the secondary output is started first it will maintain duty cycle when the primary output comes online
1 parent 11cc17a commit a8da890

File tree

1 file changed

+39
-6
lines changed

1 file changed

+39
-6
lines changed

cores/arduino/ard_sup/analog/ap3_analog.cpp

+39-6
Original file line numberDiff line numberDiff line change
@@ -546,22 +546,55 @@ ap3_err_t ap3_pwm_output(uint8_t pin, uint32_t th, uint32_t fw, uint32_t clk)
546546
if (segment == AM_HAL_CTIMER_TIMERB)
547547
{
548548
ui32ConfigVal = ((ui32ConfigVal & 0xFFFF) << 16);
549-
masterPeriod = (uint32_t)(*(pui32CompareRegA) & CTIMER_CMPRA0_CMPR1A0_Msk) >> CTIMER_CMPRA0_CMPR1A0_Pos;
550-
masterRisingTrigger = (uint32_t)(*(pui32CompareRegA) & CTIMER_CMPRA0_CMPR0A0_Msk) >> CTIMER_CMPRA0_CMPR0A0_Pos;
549+
masterPeriod = (uint32_t)(*(pui32CompareRegB) & CTIMER_CMPRB0_CMPR1B0_Msk) >> CTIMER_CMPRB0_CMPR1B0_Pos;
550+
masterRisingTrigger = (uint32_t)(*(pui32CompareRegA) & CTIMER_CMPRB0_CMPR0B0_Msk) >> CTIMER_CMPRB0_CMPR0B0_Pos;
551551
}
552552
ui32WriteVal |= ui32ConfigVal;
553553
AM_REGVAL(pui32ConfigReg) = ui32WriteVal;
554554

555-
// enable the non-auxiliary timer b/c without it the auxialiary timer won't work
556-
uint32_t masterTH = ((masterPeriod - masterRisingTrigger) * fw) / masterPeriod; // try to compensate in case _analogWriteWidth was changed
557-
am_hal_ctimer_period_set(timer, segment, fw, masterTH); // but this overwrites the non-aux compare regs for this timer / segment
555+
if(masterPeriod != fw){
556+
// the master output fw dictates the secondary fw... so if they are different try to change the master while preserving duty cycle
557+
uint32_t masterTH = ((masterPeriod - masterRisingTrigger) * fw) / masterPeriod; // try to compensate in case _analogWriteWidth was changed
558+
if(masterPeriod == 0){ // if masterPeriod was 0 then masterTH will be invalid (divide by 0). This usually means that the master timer output did not have a set duty cycle. This also means the output is probably not configured and so it is okay to choose an arbitrary duty cycle
559+
masterTH = fw - 1;
560+
}
561+
am_hal_ctimer_period_set(timer, segment, fw, masterTH); // but this overwrites the non-aux compare regs for this timer / segment
562+
// Serial.printf("th = %d, fw = %d, (masterPeriod - masterRisingTrigger) = (%d - %d) = %d\n", th, fw, masterPeriod, masterRisingTrigger, (masterPeriod - masterRisingTrigger));
563+
}
558564

559565
// then set the duty cycle with the 'aux' function
560566
am_hal_ctimer_aux_period_set(timer, segment, fw, th);
561567
}
562568
else
563569
{
564-
// Otherwise simply set the primary duty cycle
570+
// Try to preserve settings of the secondary output
571+
uint32_t *pui32ConfigReg = NULL;
572+
pui32ConfigReg = (uint32_t *)CTIMERADDRn(CTIMER, timer, AUX0);
573+
volatile uint32_t *pui32CompareRegA = (uint32_t*)CTIMERADDRn(CTIMER, timer, CMPRAUXA0);
574+
volatile uint32_t *pui32CompareRegB = (uint32_t*)CTIMERADDRn(CTIMER, timer, CMPRAUXB0);
575+
uint32_t slavePeriod = (uint32_t)(*(pui32CompareRegA) & CTIMER_CMPRA0_CMPR1A0_Msk) >> CTIMER_CMPRA0_CMPR1A0_Pos;
576+
uint32_t slaveRisingTrigger = (uint32_t)(*(pui32CompareRegA) & CTIMER_CMPRA0_CMPR0A0_Msk) >> CTIMER_CMPRA0_CMPR0A0_Pos;
577+
578+
uint32_t auxEnabled = (AM_REGVAL(pui32ConfigReg) & CTIMER_AUX0_TMRA0EN23_Msk);
579+
580+
if (segment == AM_HAL_CTIMER_TIMERB)
581+
{
582+
auxEnabled = (AM_REGVAL(pui32ConfigReg) & (CTIMER_AUX0_TMRA0EN23_Msk << 16));
583+
slavePeriod = (uint32_t)(*(pui32CompareRegB) & CTIMER_CMPRB0_CMPR1B0_Msk) >> CTIMER_CMPRB0_CMPR1B0_Pos;
584+
slaveRisingTrigger = (uint32_t)(*(pui32CompareRegA) & CTIMER_CMPRB0_CMPR0B0_Msk) >> CTIMER_CMPRB0_CMPR0B0_Pos;
585+
}
586+
587+
if( auxEnabled ){ // if secondary outputs are enabled
588+
if( slavePeriod != fw ){ // and if fw is different from previous slavePeriod
589+
uint32_t slaveTH = ((slavePeriod - slaveRisingTrigger) * fw) / slavePeriod; // try to compensate in case _analogWriteWidth was changed
590+
if(slavePeriod == 0){ // if masterPeriod was 0 then masterTH will be invalid (divide by 0). This usually means that the master timer output did not have a set duty cycle. This also means the output is probably not configured and so it is okay to choose an arbitrary duty cycle
591+
slaveTH = fw - 1;
592+
}
593+
am_hal_ctimer_aux_period_set(timer, segment, fw, slaveTH); // but this overwrites the non-aux compare regs for this timer / segment
594+
}
595+
}
596+
597+
// Now set the primary duty cycle
565598
am_hal_ctimer_period_set(timer, segment, fw, th);
566599
}
567600

0 commit comments

Comments
 (0)