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); } } }
// timer overflow static avr_cycle_count_t avr_timer_tov(struct avr_t * avr, avr_cycle_count_t when, void * param) { avr_timer_t * p = (avr_timer_t *)param; int start = p->tov_base == 0; if (!start) avr_raise_interrupt(avr, &p->overflow); p->tov_base = when; static const avr_cycle_timer_t dispatch[AVR_TIMER_COMP_COUNT] = { avr_timer_compa, avr_timer_compb, avr_timer_compc }; for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { if (p->comp[compi].comp_cycles) { if (p->comp[compi].comp_cycles < p->tov_cycles) avr_cycle_timer_register(avr, p->comp[compi].comp_cycles, dispatch[compi], p); else if (p->tov_cycles == p->comp[compi].comp_cycles && !start) dispatch[compi](avr, when, param); } } return when + p->tov_cycles; }
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_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); } }
/** * Lowers the card presence signal. * This causes the clock to start, which initiates * the clock-and-data transfer. * * @param struct avr_t *avr The AVR this card reader is interfacing with. * @param avr_cycle_count_t when The number of cycles since this function call was registered. * @param void *param The card_reader struct to raise the card presence signal on. * @return avr_cycle_count_t The value of the card presence pin. */ avr_cycle_count_t card_reader_lower_presence_signal(struct avr_t *avr, avr_cycle_count_t when, void *param) { card_reader_t *self = (card_reader_t *) param; avr_raise_irq(avr_io_getirq(self->avr, AVR_IOCTL_IOPORT_GETIRQ('D'), 2), 0); avr_raise_irq(avr_io_getirq(self->avr, AVR_IOCTL_IOPORT_GETIRQ('D'), 3), 0); avr_cycle_timer_register(avr, self->clock->signal_time, card_reader_clock_tick, self->clock); return 0; }
void avr_cycle_timer_register_usec( avr_t * avr, uint32_t when, avr_cycle_timer_t timer, void * param) { avr_cycle_timer_register(avr, avr_usec_to_cycles(avr, when), timer, param); }
static void avr_flash_write(avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_flash_t * p = (avr_flash_t *)param; avr_core_watch_write(avr, addr, v); // printf("** avr_flash_write %02x\n", v); if (avr_regbit_get(avr, p->selfprgen)) avr_cycle_timer_register(avr, 4, avr_progen_clear, p); // 4 cycles is very little! }
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_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); }
/* * called by the core when a WTD instruction is found */ static int avr_watchdog_ioctl(struct avr_io_t * port, uint32_t ctl, void * io_param) { avr_watchdog_t * p = (avr_watchdog_t *)port; int res = -1; if (ctl == AVR_IOCTL_WATCHDOG_RESET) { if (avr_regbit_get(p->io.avr, p->wde)) avr_cycle_timer_register(p->io.avr, p->cycle_count, avr_watchdog_timer, p); res = 0; } return res; }
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; uint8_t old_wde = avr_regbit_get (avr, p->wde); uint8_t old_wdie = avr_regbit_get (avr, p->watchdog.enable); uint8_t old_wdce = avr_regbit_get (avr, p->wdce); uint8_t was_enabled = (old_wde || old_wdie); uint8_t old_v = avr->data[addr]; // allow gdb to see write... avr_core_watch_write (avr, addr, v); if (old_wdce) { uint8_t old_wdp = avr_regbit_get_array (avr, p->wdp, 4); // wdrf (watchdog reset flag) must be cleared before wde can be cleared. if (avr_regbit_get (avr, p->wdrf)) avr_regbit_set (avr, p->wde); avr_watchdog_set_cycle_count_and_timer (avr, p, was_enabled, old_wdp); } else { /* easier to change only what we need rather than check and reset * locked/read-only bits. */ avr->data[addr] = old_v; uint8_t wdce_v = avr_regbit_from_value (avr, p->wdce, v); uint8_t wde_v = avr_regbit_from_value (avr, p->wde, v); if (wdce_v && wde_v) { avr_regbit_set (avr, p->wdce); avr_cycle_timer_register (avr, 4, avr_wdce_clear, p); } else { if (wde_v) // wde can be set but not cleared avr_regbit_set (avr, p->wde); avr_regbit_setto_raw (avr, p->watchdog.enable, v); avr_watchdog_set_cycle_count_and_timer (avr, p, was_enabled, -1); } } }
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); } }