static void avr_timer_tcnt_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_timer_t * p = (avr_timer_t *)param; avr_core_watch_write(avr, addr, v); uint16_t tcnt = _timer_get_tcnt(p); if (!p->tov_top) return; if (tcnt >= p->tov_top) tcnt = 0; // this involves some magicking // cancel the current timers, recalculate the "base" we should be at, reset the // timer base as it should, and re-schedule the timers using that base. 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); uint64_t cycles = (tcnt * p->tov_cycles) / p->tov_top; // printf("%s-%c %d/%d -- cycles %d/%d\n", __FUNCTION__, p->name, tcnt, p->tov_top, (uint32_t)cycles, (uint32_t)p->tov_cycles); // this reset the timers bases to the new base if (p->tov_cycles > 1) { avr_cycle_timer_register(avr, p->tov_cycles - cycles, avr_timer_tov, p); p->tov_base = 0; avr_timer_tov(avr, avr->cycle - cycles, p); } // tcnt = ((avr->cycle - p->tov_base) * p->tov_top) / p->tov_cycles; // printf("%s-%c new tnt derive to %d\n", __FUNCTION__, p->name, tcnt); }
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 int avr_flash_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_param) { if (ctl != AVR_IOCTL_FLASH_SPM) return -1; avr_flash_t * p = (avr_flash_t *)port; avr_t * avr = p->io.avr; avr_flashaddr_t z = avr->data[R_ZL] | (avr->data[R_ZH] << 8); if (avr->rampz) z |= avr->data[avr->rampz] << 16; uint16_t r01 = avr->data[0] | (avr->data[1] << 8); // printf("AVR_IOCTL_FLASH_SPM %02x Z:%04x R01:%04x\n", avr->data[p->r_spm], z,r01); avr_cycle_timer_cancel(avr, avr_progen_clear, p); avr_regbit_clear(avr, p->selfprgen); if (avr_regbit_get(avr, p->pgers)) { z &= ~1; AVR_LOG(avr, LOG_TRACE, "FLASH: Erasing page %04x (%d)\n", (z / p->spm_pagesize), p->spm_pagesize); for (int i = 0; i < p->spm_pagesize; i++) avr->flash[z++] = 0xff; } else if (avr_regbit_get(avr, p->pgwrt)) { z &= ~1; AVR_LOG(avr, LOG_TRACE, "FLASH: Writing page %04x (%d)\n", (z / p->spm_pagesize), p->spm_pagesize); } else if (avr_regbit_get(avr, p->blbset)) { AVR_LOG(avr, LOG_TRACE, "FLASH: Setting lock bits (ignored)\n"); } else { z &= ~1; avr->flash[z++] = r01; avr->flash[z] = r01 >> 8; } return 0; }
static void avr_watchdog_set_cycle_count_and_timer (avr_t * avr, avr_watchdog_t * p, uint8_t was_enabled, int8_t old_wdp) { // If nothing else, always ensure we have a valid cycle count... uint8_t wdp = avr_regbit_get_array (avr, p->wdp, 4); p->cycle_count = 2048 << wdp; p->cycle_count = (p->cycle_count * avr->frequency) / 128000; uint8_t wde = avr_regbit_get (avr, p->wde); uint8_t wdie = avr_regbit_get (avr, p->watchdog.enable); uint8_t enable_changed = (was_enabled != (wde || wdie)); uint8_t wdp_changed = ((old_wdp >= 0) ? (wdp != old_wdp) : 0); if (!enable_changed && !wdp_changed) return; static char *message[2][2] = { {0, "reset"}, {"enabled", "enabled and set"} }; if (wde || wdie) { AVR_LOG (avr, LOG_TRACE, "WATCHDOG: %s to %d cycles @ 128kz (* %d) = %d CPU cycles.\n", message[enable_changed][wdp_changed], 2048 << wdp, 1 << wdp, (int) p->cycle_count); avr_cycle_timer_register (avr, p->cycle_count, avr_watchdog_timer, p); } else if (enable_changed) { AVR_LOG (avr, LOG_TRACE, "WATCHDOG: disabled\n"); avr_cycle_timer_cancel (avr, avr_watchdog_timer, p); } }
static inline void avr_timer_cancel_all_cycle_timers( struct avr_t * avr, avr_timer_t *timer, const uint8_t clear_timers) { if(clear_timers) { for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) timer->comp[compi].comp_cycles = 0; timer->tov_cycles = 0; } avr_cycle_timer_cancel(avr, avr_timer_tov, timer); avr_cycle_timer_cancel(avr, avr_timer_compa, timer); avr_cycle_timer_cancel(avr, avr_timer_compb, timer); avr_cycle_timer_cancel(avr, avr_timer_compc, timer); }
static void avr_adc_reset(avr_io_t * port) { avr_adc_t * p = (avr_adc_t *)port; // stop ADC avr_cycle_timer_cancel(p->io.avr, avr_adc_int_raise, p); avr_regbit_clear(p->io.avr, p->adsc); for (int i = 0; i < ADC_IRQ_COUNT; i++) avr_irq_register_notify(p->io.irq + i, avr_adc_irq_notify, p); }
static void avr_adc_write_adcsra( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_adc_configure_trigger(avr, addr, v, param); avr_adc_t * p = (avr_adc_t *)param; uint8_t adsc = avr_regbit_get(avr, p->adsc); uint8_t aden = avr_regbit_get(avr, p->aden); avr->data[p->adsc.reg] = v; // can't write zero to adsc if (adsc && !avr_regbit_get(avr, p->adsc)) { avr_regbit_set(avr, p->adsc); v = avr->data[p->adsc.reg]; } if (!aden && avr_regbit_get(avr, p->aden)) { // first conversion p->first = 1; AVR_LOG(avr, LOG_TRACE, "ADC: Start AREF %d AVCC %d\n", avr->aref, avr->avcc); } if (aden && !avr_regbit_get(avr, p->aden)) { // stop ADC avr_cycle_timer_cancel(avr, avr_adc_int_raise, p); avr_regbit_clear(avr, p->adsc); v = avr->data[p->adsc.reg]; // Peter Ross [email protected] } if (!adsc && avr_regbit_get(avr, p->adsc)) { // start one! uint8_t muxi = avr_regbit_get_array(avr, p->mux, ARRAY_SIZE(p->mux)); union { avr_adc_mux_t mux; uint32_t v; } e = { .mux = p->muxmode[muxi] }; avr_raise_irq(p->io.irq + ADC_IRQ_OUT_TRIGGER, e.v); // clock prescaler are just a bit shift.. and 0 means 1 uint32_t div = avr_regbit_get_array(avr, p->adps, ARRAY_SIZE(p->adps)); if (!div) div++; div = avr->frequency >> div; if (p->first) AVR_LOG(avr, LOG_TRACE, "ADC: starting at %uKHz\n", div / 13 / 100); div /= p->first ? 25 : 13; // first cycle is longer avr_cycle_timer_register(avr, avr_hz_to_cycles(avr, div), avr_adc_int_raise, p); } avr_core_watch_write(avr, addr, v); }
void avr_cycle_timer_register( avr_t * avr, avr_cycle_count_t when, avr_cycle_timer_t timer, void * param) { avr_cycle_timer_pool_t * pool = &avr->cycle_timers; // remove it if it was already scheduled avr_cycle_timer_cancel(avr, timer, param); if (!pool->timer_free) { AVR_LOG(avr, LOG_ERROR, "CYCLE: %s: pool is full (%d)!\n", __func__, MAX_CYCLE_TIMERS); return; } avr_cycle_timer_insert(avr, when, timer, param); avr_cycle_timer_reset_sleep_run_cycles_limited(avr); }
static void avr_watchdog_write(avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_watchdog_t * p = (avr_watchdog_t *)param; // backup the registers // uint8_t wd = avr->data[p->wdce.reg]; uint8_t wdce_o = avr_regbit_get(avr, p->wdce); // old uint8_t wde_o = avr_regbit_get(avr, p->wde); uint8_t wdp_o[4]; // printf("avr_watchdog_write %02x\n", v); for (int i = 0; i < 4; i++) wdp_o[i] = avr_regbit_get(avr, p->wdp[i]); avr->data[p->wdce.reg] = v; uint8_t wdce_n = avr_regbit_get(avr, p->wdce); // new if (wdce_o /* || wdce_n */) { // make sure bit gets reset eventually if (wdce_n) avr_cycle_timer_register(avr, 4, avr_wdce_clear, p); uint8_t wdp = avr_regbit_get_array(avr, p->wdp, 4); p->cycle_count = 2048 << wdp; p->cycle_count = (p->cycle_count * avr->frequency) / 128000; if (avr_regbit_get(avr, p->wde)) { printf("Watchdog reset to %d cycles @ 128kz (* %d) = %d CPU cycles)\n", 2048 << wdp, 1 << wdp, (int)p->cycle_count); avr_cycle_timer_register(avr, p->cycle_count, avr_watchdog_timer, p); } else { printf("Watchdog disabled\n"); avr_cycle_timer_cancel(avr, avr_watchdog_timer, p); } } else { // reset old values avr_regbit_setto(avr, p->wde, wde_o); for (int i = 0; i < 4; i++) avr_regbit_setto(avr, p->wdp[i], wdp_o[i]); v = avr->data[p->wdce.reg]; } avr_core_watch_write(avr, addr, v); }
static void avr_timer_reset(avr_io_t * port) { avr_timer_t * p = (avr_timer_t *)port; avr_cycle_timer_cancel(p->io.avr, avr_timer_tov, p); avr_cycle_timer_cancel(p->io.avr, avr_timer_compa, p); avr_cycle_timer_cancel(p->io.avr, avr_timer_compb, p); avr_cycle_timer_cancel(p->io.avr, avr_timer_compc, p); // check to see if the comparators have a pin output. If they do, // (try) to get the ioport corresponding IRQ and connect them // they will automagically be triggered when the comparator raises // it's own IRQ for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { p->comp[compi].comp_cycles = 0; avr_ioport_getirq_t req = { .bit = p->comp[compi].com_pin }; if (avr_ioctl(port->avr, AVR_IOCTL_IOPORT_GETIRQ_REGBIT, &req) > 0) { // cool, got an IRQ // printf("%s-%c COMP%c Connecting PIN IRQ %d\n", __FUNCTION__, p->name, 'A'+compi, req.irq[0]->irq); avr_connect_irq(&port->irq[TIMER_IRQ_OUT_COMP + compi], req.irq[0]); } } avr_ioport_getirq_t req = { .bit = p->icp }; if (avr_ioctl(port->avr, AVR_IOCTL_IOPORT_GETIRQ_REGBIT, &req) > 0) { // cool, got an IRQ for the input capture pin // printf("%s-%c ICP Connecting PIN IRQ %d\n", __FUNCTION__, p->name, req.irq[0]->irq); avr_irq_register_notify(req.irq[0], avr_timer_irq_icp, p); } } static const char * irq_names[TIMER_IRQ_COUNT] = { [TIMER_IRQ_OUT_PWM0] = "8>pwm0", [TIMER_IRQ_OUT_PWM1] = "8>pwm1", [TIMER_IRQ_OUT_COMP + 0] = ">compa", [TIMER_IRQ_OUT_COMP + 1] = ">compb", [TIMER_IRQ_OUT_COMP + 2] = ">compc", }; static avr_io_t _io = { .kind = "timer", .reset = avr_timer_reset, .irq_names = irq_names, }; void avr_timer_init(avr_t * avr, avr_timer_t * p) { p->io = _io; avr_register_io(avr, &p->io); avr_register_vector(avr, &p->overflow); avr_register_vector(avr, &p->icr); // allocate this module's IRQ avr_io_setirqs(&p->io, AVR_IOCTL_TIMER_GETIRQ(p->name), TIMER_IRQ_COUNT, NULL); // marking IRQs as "filtered" means they don't propagate if the // new value raised is the same as the last one.. in the case of the // pwm value it makes sense not to bother. p->io.irq[TIMER_IRQ_OUT_PWM0].flags |= IRQ_FLAG_FILTERED; p->io.irq[TIMER_IRQ_OUT_PWM1].flags |= IRQ_FLAG_FILTERED; if (p->wgm[0].reg) // these are not present on older AVRs avr_register_io_write(avr, p->wgm[0].reg, avr_timer_write, p); avr_register_io_write(avr, p->cs[0].reg, avr_timer_write, p); // this assumes all the "pending" interrupt bits are in the same // register. Might not be true on all devices ? avr_register_io_write(avr, p->overflow.raised.reg, avr_timer_write_pending, p); /* * Even if the timer is 16 bits, we don't care to have watches on the * high bytes because the datasheet says that the low address is always * the trigger. */ for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { avr_register_vector(avr, &p->comp[compi].interrupt); if (p->comp[compi].r_ocr) // not all timers have all comparators avr_register_io_write(avr, p->comp[compi].r_ocr, avr_timer_write_ocr, p); } avr_register_io_write(avr, p->r_tcnt, avr_timer_tcnt_write, p); avr_register_io_read(avr, p->r_tcnt, avr_timer_tcnt_read, p); }