From c31614b921f4c44eb2b1a2d19b7b2f172fcb6b86 Mon Sep 17 00:00:00 2001 From: landret christophe <19358486+landret@users.noreply.github.com> Date: Wed, 13 Oct 2021 21:24:27 -1000 Subject: [PATCH] Fix bug in analogWrite when accessing 16 bit register (#94) Fix bug in analogWrite when accessing 16 bit register --- cores/arduino/wiring_analog.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) 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);