diff --git a/cores/arduino/wiring_analog.c b/cores/arduino/wiring_analog.c index cda2b4da..36ddc680 100644 --- a/cores/arduino/wiring_analog.c +++ b/cores/arduino/wiring_analog.c @@ -145,6 +145,8 @@ void analogWrite(uint8_t pin, int val) uint16_t* timer_cmp_out; TCB_t *timer_B; + uint8_t savedSREG; + /* Find out Port and Pin to correctly handle port mux, and timer. */ switch (digital_pin_timer) { @@ -153,7 +155,10 @@ void analogWrite(uint8_t pin, int val) timer_cmp_out = ((uint16_t*) (&TCA0.SINGLE.CMP0BUF)) + bit_pos; /* Configure duty cycle for correct compare channel */ - (*timer_cmp_out) = (val); + savedSREG = SREG; + cli(); + (*timer_cmp_out) = (val); // non-atomic 16-bit write operation + SREG = savedSREG; /* Enable output on pin */ TCA0.SINGLE.CTRLB |= (1 << (TCA_SINGLE_CMP0EN_bp + bit_pos)); @@ -170,7 +175,12 @@ void analogWrite(uint8_t pin, int val) timer_B = ((TCB_t *)&TCB0 + (digital_pin_timer - TIMERB0)); /* set duty cycle */ - timer_B->CCMPH = val; + // (16-bit read/write operation are non-atomic and use a temporary register) + savedSREG = SREG; + cli(); + timer_B->CCMPL = timer_B->CCMPL; // copy CCMPL into temporary register + timer_B->CCMPH = val; // set CCMPH value + copy temporary register content into CCMPL + SREG = savedSREG; /* Enable Timer Output */ timer_B->CTRLB |= (TCB_CCMPEN_bm);