static void avr_timer_write_ocr(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_timer_t * p = (avr_timer_t *)param; uint16_t oldv[AVR_TIMER_COMP_COUNT]; int target = -1; /* check to see if the OCR values actually changed */ for (int oi = 0; oi < AVR_TIMER_COMP_COUNT; oi++) oldv[oi] = _timer_get_ocr(p, oi); avr_core_watch_write(avr, addr, v); for (int oi = 0; oi < AVR_TIMER_COMP_COUNT; oi++) if (oldv[oi] != _timer_get_ocr(p, oi)) { target = oi; break; } switch (p->mode.kind) { case avr_timer_wgm_normal: avr_timer_reconfigure(p); break; case avr_timer_wgm_fc_pwm: // OCR is not used here avr_timer_reconfigure(p); break; case avr_timer_wgm_ctc: avr_timer_reconfigure(p); break; case avr_timer_wgm_pwm: if (p->mode.top != avr_timer_wgm_reg_ocra) { avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocr(p, AVR_TIMER_COMPA)); avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocr(p, AVR_TIMER_COMPB)); } break; case avr_timer_wgm_fast_pwm: if (target != -1) avr_timer_reconfigure(p); avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocr(p, AVR_TIMER_COMPA)); avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocr(p, AVR_TIMER_COMPB)); break; default: AVR_LOG(avr, LOG_WARNING, "TIMER: %s-%c mode %d UNSUPPORTED\n", __FUNCTION__, p->name, p->mode.kind); avr_timer_reconfigure(p); break; } }
static void avr_timer_write( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_timer_t * p = (avr_timer_t *)param; uint8_t as2 = avr_regbit_get(avr, p->as2); uint8_t cs = avr_regbit_get_array(avr, p->cs, ARRAY_SIZE(p->cs)); uint8_t mode = avr_regbit_get_array(avr, p->wgm, ARRAY_SIZE(p->wgm)); avr_core_watch_write(avr, addr, v); uint8_t new_as2 = avr_regbit_get(avr, p->as2); uint8_t new_cs = avr_regbit_get_array(avr, p->cs, ARRAY_SIZE(p->cs)); uint8_t new_mode = avr_regbit_get_array(avr, p->wgm, ARRAY_SIZE(p->wgm)); // only reconfigure the timer if "relevant" bits have changed // this prevent the timer reset when changing the edge detector // or other minor bits if (new_cs != cs || new_mode != mode || new_as2 != as2) { /* cs */ if (new_cs == 0) { // cancel everything avr_timer_cancel_all_cycle_timers(avr, p, 1); AVR_LOG(avr, LOG_TRACE, "TIMER: %s-%c clock turned off\n", __func__, p->name); return; } if (new_as2) { // AVR clock and external 32KHz source does not have // to be synced. To obtain better simulation results // p->tov_base type must be float or avr->frequency // must be multiple of 32768. p->cs_div_value = (uint32_t)((uint64_t)avr->frequency * (1 << p->cs_div[new_cs]) / 32768); } else { p->cs_div_value = 1 << p->cs_div[new_cs]; } /* mode */ p->mode = p->wgm_op[new_mode]; p->wgm_op_mode_kind = p->mode.kind; p->wgm_op_mode_size = (1 << p->mode.size) - 1; avr_timer_reconfigure(p, 1); } }
static void avr_timer_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_timer_t * p = (avr_timer_t *)param; uint8_t as2 = avr_regbit_get(avr, p->as2); uint8_t cs = avr_regbit_get_array(avr, p->cs, ARRAY_SIZE(p->cs)); uint8_t mode = avr_regbit_get_array(avr, p->wgm, ARRAY_SIZE(p->wgm)); avr_core_watch_write(avr, addr, v); // only reconfigure the timer if "relevant" bits have changed // this prevent the timer reset when changing the edge detector // or other minor bits if (avr_regbit_get_array(avr, p->cs, ARRAY_SIZE(p->cs)) != cs || avr_regbit_get_array(avr, p->wgm, ARRAY_SIZE(p->wgm)) != mode || avr_regbit_get(avr, p->as2) != as2) { avr_timer_reconfigure(p); } }
static void avr_timer_write_ocr( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_timer_comp_p comp = (avr_timer_comp_p)param; avr_timer_t *timer = comp->timer; uint16_t oldv; /* check to see if the OCR values actually changed */ oldv = _timer_get_comp_ocr(avr, comp); avr_core_watch_write(avr, addr, v); switch (timer->wgm_op_mode_kind) { case avr_timer_wgm_normal: avr_timer_reconfigure(timer, 0); break; case avr_timer_wgm_fc_pwm: // OCR is not used here avr_timer_reconfigure(timer, 0); break; case avr_timer_wgm_ctc: avr_timer_reconfigure(timer, 0); break; case avr_timer_wgm_pwm: if (timer->mode.top != avr_timer_wgm_reg_ocra) { avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocr(timer, AVR_TIMER_COMPA)); } else { avr_timer_reconfigure(timer, 0); // if OCRA is the top, reconfigure needed } avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocr(timer, AVR_TIMER_COMPB)); break; case avr_timer_wgm_fast_pwm: if (oldv != _timer_get_comp_ocr(avr, comp)) avr_timer_reconfigure(timer, 0); avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocr(timer, AVR_TIMER_COMPA)); avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocr(timer, AVR_TIMER_COMPB)); break; default: AVR_LOG(avr, LOG_WARNING, "TIMER: %s-%c mode %d UNSUPPORTED\n", __FUNCTION__, timer->name, timer->mode.kind); avr_timer_reconfigure(timer, 0); break; } }