static void avr_timer_reconfigure(avr_timer_t * p) { avr_t * avr = p->io.avr; avr_timer_wgm_t zero={0}; p->mode = zero; // cancel everything p->comp[AVR_TIMER_COMPA].comp_cycles = 0; p->comp[AVR_TIMER_COMPB].comp_cycles = 0; p->comp[AVR_TIMER_COMPC].comp_cycles = 0; p->tov_cycles = 0; avr_cycle_timer_cancel(avr, avr_timer_tov, p); avr_cycle_timer_cancel(avr, avr_timer_compa, p); avr_cycle_timer_cancel(avr, avr_timer_compb, p); avr_cycle_timer_cancel(avr, avr_timer_compc, p); long clock = avr->frequency; // only can exists on "asynchronous" 8 bits timers if (avr_regbit_get(avr, p->as2)) clock = 32768; uint8_t cs = avr_regbit_get_array(avr, p->cs, ARRAY_SIZE(p->cs)); if (cs == 0) { AVR_LOG(avr, LOG_TRACE, "TIMER: %s-%c clock turned off\n", __FUNCTION__, p->name); return; } uint8_t mode = avr_regbit_get_array(avr, p->wgm, ARRAY_SIZE(p->wgm)); uint8_t cs_div = p->cs_div[cs]; uint32_t f = clock >> cs_div; p->mode = p->wgm_op[mode]; //printf("%s-%c clock %d, div %d(/%d) = %d ; mode %d\n", __FUNCTION__, p->name, clock, cs, 1 << cs_div, f, mode); switch (p->mode.kind) { case avr_timer_wgm_normal: avr_timer_configure(p, f, (1 << p->mode.size) - 1); break; case avr_timer_wgm_fc_pwm: avr_timer_configure(p, f, (1 << p->mode.size) - 1); break; case avr_timer_wgm_ctc: { avr_timer_configure(p, f, _timer_get_ocr(p, AVR_TIMER_COMPA)); } break; case avr_timer_wgm_pwm: { uint16_t top = p->mode.top == avr_timer_wgm_reg_ocra ? _timer_get_ocr(p, AVR_TIMER_COMPA) : _timer_get_icr(p); avr_timer_configure(p, f, top); } break; case avr_timer_wgm_fast_pwm: avr_timer_configure(p, f, (1 << p->mode.size) - 1); break; default: AVR_LOG(avr, LOG_WARNING, "TIMER: %s-%c unsupported timer mode wgm=%d (%d)\n", __FUNCTION__, p->name, mode, p->mode.kind); } }
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; } }
static void avr_timer_configure( avr_timer_t * p, uint32_t clock, uint32_t top, uint8_t reset) { p->tov_cycles = 0; p->tov_top = top; p->tov_cycles = clock * (top+1); AVR_LOG(p->io.avr, LOG_TRACE, "TIMER: %s-%c TOP %.2fHz = %d cycles = %dusec\n", __FUNCTION__, p->name, (p->io.avr->frequency / (float)p->tov_cycles), (int)p->tov_cycles, (int)avr_cycles_to_usec(p->io.avr, p->tov_cycles)); for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { if (!p->comp[compi].r_ocr) continue; uint32_t ocr = _timer_get_ocr(p, compi); uint32_t comp_cycles = clock * (ocr + 1); p->comp[compi].comp_cycles = 0; if (p->trace & (avr_timer_trace_compa << compi)) printf("%s-%c clock %f top %d OCR%c %d\n", __FUNCTION__, p->name, (float)(p->io.avr->frequency / clock), top, 'A'+compi, ocr); if (ocr && ocr <= top) { p->comp[compi].comp_cycles = comp_cycles; // avr_hz_to_cycles(p->io.avr, fa); if (p->trace & (avr_timer_trace_compa << compi)) printf( "TIMER: %s-%c %c %.2fHz = %d cycles\n", __FUNCTION__, p->name, 'A'+compi, (float)(p->io.avr->frequency / ocr), (int)p->comp[compi].comp_cycles); } } if (p->tov_cycles > 1) { if (reset) { avr_cycle_timer_register(p->io.avr, p->tov_cycles, avr_timer_tov, p); // calling it once, with when == 0 tells it to arm the A/B/C timers if needed p->tov_base = 0; avr_timer_tov(p->io.avr, p->io.avr->cycle, p); } else { uint64_t orig_tov_base = p->tov_base; avr_cycle_timer_register(p->io.avr, p->tov_cycles - (p->io.avr->cycle - orig_tov_base), avr_timer_tov, p); // calling it once, with when == 0 tells it to arm the A/B/C timers if needed p->tov_base = 0; avr_timer_tov(p->io.avr, orig_tov_base, p); } } }
static void avr_timer_reconfigure( avr_timer_t * p, uint8_t reset) { avr_t * avr = p->io.avr; // cancel everything avr_timer_cancel_all_cycle_timers(avr, p, 1); switch (p->wgm_op_mode_kind) { case avr_timer_wgm_normal: avr_timer_configure(p, p->cs_div_value, p->wgm_op_mode_size, reset); break; case avr_timer_wgm_fc_pwm: avr_timer_configure(p, p->cs_div_value, p->wgm_op_mode_size, reset); break; case avr_timer_wgm_ctc: { avr_timer_configure(p, p->cs_div_value, _timer_get_ocr(p, AVR_TIMER_COMPA), reset); } break; case avr_timer_wgm_pwm: { uint16_t top = (p->mode.top == avr_timer_wgm_reg_ocra) ? _timer_get_ocr(p, AVR_TIMER_COMPA) : _timer_get_icr(p); avr_timer_configure(p, p->cs_div_value, top, reset); } break; case avr_timer_wgm_fast_pwm: avr_timer_configure(p, p->cs_div_value, p->wgm_op_mode_size, reset); break; case avr_timer_wgm_none: avr_timer_configure(p, p->cs_div_value, p->wgm_op_mode_size, reset); break; default: { uint8_t mode = avr_regbit_get_array(avr, p->wgm, ARRAY_SIZE(p->wgm)); AVR_LOG(avr, LOG_WARNING, "TIMER: %s-%c unsupported timer mode wgm=%d (%d)\n", __FUNCTION__, p->name, mode, p->mode.kind); } } }
static void avr_timer_configure(avr_timer_t * p, uint32_t clock, uint32_t top) { float t = clock / (float)(top+1); float frequency = p->io.avr->frequency; p->tov_cycles = 0; p->tov_top = top; p->tov_cycles = frequency / t; // avr_hz_to_cycles(frequency, t); AVR_LOG(p->io.avr, LOG_TRACE, "TIMER: %s-%c TOP %.2fHz = %d cycles = %dusec\n", __FUNCTION__, p->name, t, (int)p->tov_cycles, (int)avr_cycles_to_usec(p->io.avr, p->tov_cycles)); for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { if (!p->comp[compi].r_ocr) continue; uint32_t ocr = _timer_get_ocr(p, compi); float fc = clock / (float)(ocr+1); p->comp[compi].comp_cycles = 0; // printf("%s-%c clock %d top %d OCR%c %d\n", __FUNCTION__, p->name, clock, top, 'A'+compi, ocr); if (ocr && ocr <= top) { p->comp[compi].comp_cycles = frequency / fc; // avr_hz_to_cycles(p->io.avr, fa); AVR_LOG(p->io.avr, LOG_TRACE, "TIMER: %s-%c %c %.2fHz = %d cycles\n", __FUNCTION__, p->name, 'A'+compi, fc, (int)p->comp[compi].comp_cycles); } } if (p->tov_cycles > 1) { avr_cycle_timer_register(p->io.avr, p->tov_cycles, avr_timer_tov, p); // calling it once, with when == 0 tells it to arm the A/B/C timers if needed p->tov_base = 0; avr_timer_tov(p->io.avr, p->io.avr->cycle, p); } }
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; } }