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_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_watchdog_reset(avr_io_t * port) { avr_watchdog_t * p = (avr_watchdog_t *)port; avr_t * avr = p->io.avr; if (p->reset_context.wdrf) { p->reset_context.wdrf = 0; /* * if watchdog reset kicked, then watchdog gets restarted at * fastest interval */ avr->run = p->reset_context.avr_run; avr_regbit_set(avr, p->wde); avr_regbit_set(avr, p->wdrf); avr_regbit_set_array_from_value(avr, p->wdp, 4, 0); avr_watchdog_set_cycle_count_and_timer(avr, p, 0, 0); } /* TODO could now use the two pending/running IRQs to do the same * as before */ avr_irq_register_notify(p->watchdog.irq, avr_watchdog_irq_notify, p); }
static void avr_watchdog_reset (avr_io_t * port) { avr_watchdog_t *p = (avr_watchdog_t *) port; avr_t *avr = p->io.avr; if (p->reset_context.wdrf) { /* * if watchdog reset kicked, then watchdog gets restated at fastest interval */ avr->run = p->reset_context.avr_run; avr_regbit_set (avr, p->wde); avr_regbit_set (avr, p->wdrf); avr_regbit_set_array_from_value (avr, p->wdp, 4, 0); avr_watchdog_set_cycle_count_and_timer (avr, p, 0, 0); } avr_irq_register_notify (&p->watchdog.irq, avr_watchdog_irq_notify, p); }
int avr_raise_interrupt( avr_t * avr, avr_int_vector_t * vector) { if (!vector || !vector->vector) return 0; if (vector->trace) printf("%s raising %d (enabled %d)\n", __FUNCTION__, vector->vector, avr_regbit_get(avr, vector->enable)); if (vector->pending) { if (vector->trace) printf("%s trying to double raise %d (enabled %d)\n", __FUNCTION__, vector->vector, avr_regbit_get(avr, vector->enable)); return 0; } // always mark the 'raised' flag to one, even if the interrupt is disabled // this allow "polling" for the "raised" flag, like for non-interrupt // driven UART and so so. These flags are often "write one to clear" if (vector->raised.reg) avr_regbit_set(avr, vector->raised); avr_raise_irq(vector->irq + AVR_INT_IRQ_PENDING, 1); avr_raise_irq(avr->interrupts.irq + AVR_INT_IRQ_PENDING, 1); // If the interrupt is enabled, attempt to wake the core if (avr_regbit_get(avr, vector->enable)) { // Mark the interrupt as pending vector->pending = 1; avr_int_table_p table = &avr->interrupts; avr_int_pending_write(&table->pending, vector); if (avr->sreg[S_I] && avr->interrupt_state == 0) avr->interrupt_state = 1; if (avr->state == cpu_Sleeping) { if (vector->trace) printf("Waking CPU due to interrupt\n"); avr->state = cpu_Running; // in case we were sleeping } } // return 'raised' even if it was already pending return 1; }