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_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); }
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_extint_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param) { avr_extint_t * p = (avr_extint_t *)param; avr_t * avr = p->io.avr; int up = !irq->value && value; int down = irq->value && !value; uint8_t isc_bits = p->eint[irq->irq + 1].isc->reg ? 2 : 1; uint8_t mode = avr_regbit_get_array(avr, p->eint[irq->irq].isc, isc_bits); // Asynchronous interrupts, eg int2 in m16, m32 etc. support only down/up if (isc_bits == 1) mode +=2; switch (mode) { case 0: // unsupported break; case 1: if (up || down) avr_raise_interrupt(avr, &p->eint[irq->irq].vector); break; case 2: if (down) avr_raise_interrupt(avr, &p->eint[irq->irq].vector); break; case 3: if (up) avr_raise_interrupt(avr, &p->eint[irq->irq].vector); break; } }
static void avr_extint_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param) { avr_extint_t * p = (avr_extint_t *)param; avr_t * avr = p->io.avr; uint8_t mode = avr_regbit_get_array(avr, p->eint[irq->irq].isc, 2); int up = !irq->value && value; int down = irq->value && !value; switch (mode) { case 0: // unsupported break; case 1: if (up || down) avr_raise_interrupt(avr, &p->eint[irq->irq].vector); break; case 2: if (down) avr_raise_interrupt(avr, &p->eint[irq->irq].vector); break; case 3: if (up) avr_raise_interrupt(avr, &p->eint[irq->irq].vector); break; } }
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 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_adc_configure_trigger( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_adc_t * p = (avr_adc_t *)param; uint8_t adate = avr_regbit_get(avr, p->adate); uint8_t old_adts = p->adts_mode; static char * auto_trigger_names[] = { "none", "free_running", "analog_comparator_0", "analog_comparator_1", "analog_comparator_2", "analog_comparator_3", "external_interrupt_0", "timer_0_compare_match_a", "timer_0_compare_match_b", "timer_0_overflow", "timer_1_compare_match_b", "timer_1_overflow", "timer_1_capture_event", "pin_change_interrupt", "psc_module_0_sync_signal", "psc_module_1_sync_signal", "psc_module_2_sync_signal", }; if( adate ) { uint8_t adts = avr_regbit_get_array(avr, p->adts, ARRAY_SIZE(p->adts)); p->adts_mode = p->adts_op[adts]; switch(p->adts_mode) { case avr_adts_free_running: { // do nothing at free running mode } break; // TODO: implement the other auto trigger modes default: { AVR_LOG(avr, LOG_WARNING, "ADC: unimplemented auto trigger mode: %s\n", auto_trigger_names[p->adts_mode]); p->adts_mode = avr_adts_none; } break; } } else { // TODO: remove previously configured auto triggers p->adts_mode = avr_adts_none; } if( old_adts != p->adts_mode ) AVR_LOG(avr, LOG_TRACE, "ADC: auto trigger configured: %s\n", auto_trigger_names[p->adts_mode]); }
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_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_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 uint8_t avr_adc_read_l( struct avr_t * avr, avr_io_addr_t addr, void * param) { avr_adc_t * p = (avr_adc_t *)param; if (p->read_status) // conversion already done return avr_core_watch_read(avr, addr); uint8_t refi = avr_regbit_get_array(avr, p->ref, ARRAY_SIZE(p->ref)); uint16_t ref = p->ref_values[refi]; uint8_t muxi = avr_regbit_get_array(avr, p->mux, ARRAY_SIZE(p->mux)); avr_adc_mux_t mux = p->muxmode[muxi]; // optional shift left/right uint8_t shift = avr_regbit_get(avr, p->adlar) ? 6 : 0; // shift LEFT uint32_t reg = 0; switch (mux.kind) { case ADC_MUX_SINGLE: reg = p->adc_values[mux.src]; break; case ADC_MUX_DIFF: if (mux.gain == 0) mux.gain = 1; reg = ((uint32_t)p->adc_values[mux.src] * mux.gain) - ((uint32_t)p->adc_values[mux.diff] * mux.gain); break; case ADC_MUX_TEMP: reg = p->temp; // assumed to be already calibrated somehow break; case ADC_MUX_REF: reg = mux.src; // reference voltage break; case ADC_MUX_VCC4: if ( !avr->vcc) { AVR_LOG(avr, LOG_WARNING, "ADC: missing VCC analog voltage\n"); } else reg = avr->vcc / 4; break; } uint32_t vref = 3300; switch (ref) { case ADC_VREF_VCC: if (!avr->vcc) AVR_LOG(avr, LOG_WARNING, "ADC: missing VCC analog voltage\n"); else vref = avr->vcc; break; case ADC_VREF_AREF: if (!avr->aref) AVR_LOG(avr, LOG_WARNING, "ADC: missing AREF analog voltage\n"); else vref = avr->aref; break; case ADC_VREF_AVCC: if (!avr->avcc) AVR_LOG(avr, LOG_WARNING, "ADC: missing AVCC analog voltage\n"); else vref = avr->avcc; break; default: vref = ref; } // printf("ADCL %d:%3d:%3d read %4d vref %d:%d=%d\n", // mux.kind, mux.diff, mux.src, // reg, refi, ref, vref); reg = (reg * 0x3ff) / vref; // scale to 10 bits ADC // printf("ADC to 10 bits 0x%x %d\n", reg, reg); if (reg > 0x3ff) { AVR_LOG(avr, LOG_WARNING, "ADC: channel %d clipped %u/%u VREF %d\n", mux.kind, reg, 0x3ff, vref); reg = 0x3ff; } reg <<= shift; // printf("ADC to 10 bits %x shifted %d\n", reg, shift); avr->data[p->r_adcl] = reg; avr->data[p->r_adch] = reg >> 8; p->read_status = 1; return avr_core_watch_read(avr, addr); }