/* * write to the TIFR register. Watch for code that writes "1" to clear * pending interrupts. */ static void avr_timer_write_pending( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_timer_t * p = (avr_timer_t *)param; // save old bits values uint8_t ov = avr_regbit_get(avr, p->overflow.raised); uint8_t ic = avr_regbit_get(avr, p->icr.raised); uint8_t cp[AVR_TIMER_COMP_COUNT]; for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) cp[compi] = avr_regbit_get(avr, p->comp[compi].interrupt.raised); // write the value avr_core_watch_write(avr, addr, v); // clear any interrupts & flags avr_clear_interrupt_if(avr, &p->overflow, ov); avr_clear_interrupt_if(avr, &p->icr, ic); for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) avr_clear_interrupt_if(avr, &p->comp[compi].interrupt, cp[compi]); }
static uint8_t avr_uart_rxc_read(struct avr_t * avr, avr_io_addr_t addr, void * param) { avr_uart_t * p = (avr_uart_t *)param; uint8_t v = avr_core_watch_read(avr, addr); //static uint8_t old = 0xff; if (v != old) printf("UCSRA read %02x\n", v); old = v; // // if RX is enabled, and there is nothing to read, and // the AVR core is reading this register, it's probably // to poll the RXC TXC flag and spinloop // so here we introduce a usleep to make it a bit lighter // on CPU and let data arrive // uint8_t ri = !avr_regbit_get(avr, p->rxen) || !avr_regbit_get(avr, p->rxc.raised); uint8_t ti = !avr_regbit_get(avr, p->txen) || !avr_regbit_get(avr, p->txc.raised); if (p->flags & AVR_UART_FLAG_POOL_SLEEP) { if (ri && ti) usleep(1); } // if reception is idle and the fifo is empty, tell whomever there is room if (avr_regbit_get(avr, p->rxen) && uart_fifo_isempty(&p->input)) { avr_raise_irq(p->io.irq + UART_IRQ_OUT_XOFF, 0); avr_raise_irq(p->io.irq + UART_IRQ_OUT_XON, 1); } return v; }
static avr_cycle_count_t avr_watchdog_timer( struct avr_t * avr, avr_cycle_count_t when, void * param) { avr_watchdog_t * p = (avr_watchdog_t *)param; if (avr_regbit_get(avr, p->watchdog.enable)) { AVR_LOG(avr, LOG_TRACE, "WATCHDOG: timer fired.\n"); avr_raise_interrupt(avr, &p->watchdog); return when + p->cycle_count; } else if (avr_regbit_get(avr, p->wde)) { AVR_LOG(avr, LOG_TRACE, "WATCHDOG: timer fired without interrupt. Resetting\n"); p->reset_context.avr_run = avr->run; p->reset_context.wdrf = 1; /* Ideally we would perform a reset here via 'avr_reset' * However, returning after reset would result in an unconsistent state. * It seems our best (and cleanest) solution is to set a temporary call * back which can safely perform the reset for us... During reset, * the previous callback can be restored and safely resume. */ avr->run = avr_watchdog_run_callback_software_reset; } return 0; }
static void avr_adc_irq_notify( struct avr_irq_t * irq, uint32_t value, void * param) { avr_adc_t * p = (avr_adc_t *)param; avr_t * avr = p->io.avr; switch (irq->irq) { case ADC_IRQ_ADC0 ... ADC_IRQ_ADC7: { p->adc_values[irq->irq] = value; } break; case ADC_IRQ_TEMP: { p->temp = value; } break; case ADC_IRQ_IN_TRIGGER: { if (avr_regbit_get(avr, p->adate)) { // start a conversion only if it's not running // otherwise ignore the trigger if(!avr_regbit_get(avr, p->adsc) ) { uint8_t addr = p->adsc.reg; if (addr) { uint8_t val = avr->data[addr] | (1 << p->adsc.bit); // write ADSC to ADCSRA avr_adc_write_adcsra(avr, addr, val, param); } } } } 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 avr_cycle_count_t avr_timer_comp(avr_timer_t *p, avr_cycle_count_t when, uint8_t comp) { avr_t * avr = p->io.avr; avr_raise_interrupt(avr, &p->comp[comp].interrupt); // check output compare mode and set/clear pins uint8_t mode = avr_regbit_get(avr, p->comp[comp].com); avr_irq_t * irq = &p->io.irq[TIMER_IRQ_OUT_COMP + comp]; switch (mode) { case avr_timer_com_normal: // Normal mode OCnA disconnected break; case avr_timer_com_toggle: // Toggle OCnA on compare match if (p->comp[comp].com_pin.reg) // we got a physical pin avr_raise_irq(irq, AVR_IOPORT_OUTPUT | (avr_regbit_get(avr, p->comp[comp].com_pin) ? 0 : 1)); else // no pin, toggle the IRQ anyway avr_raise_irq(irq, p->io.irq[TIMER_IRQ_OUT_COMP + comp].value ? 0 : 1); break; case avr_timer_com_clear: avr_raise_irq(irq, 0); break; case avr_timer_com_set: avr_raise_irq(irq, 1); break; } return p->tov_cycles ? 0 : p->comp[comp].comp_cycles ? when + p->comp[comp].comp_cycles : 0; }
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 avr_cycle_count_t avr_spi_raise(struct avr_t * avr, avr_cycle_count_t when, void * param) { avr_spi_t * p = (avr_spi_t *)param; if (avr_regbit_get(avr, p->spe)) { // in master mode, any byte is sent as it comes.. if (avr_regbit_get(avr, p->mstr)) { avr_raise_interrupt(avr, &p->spi); avr_raise_irq(p->io.irq + SPI_IRQ_OUTPUT, avr->data[p->r_spdr]); } } return 0; }
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_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); } }
/* * 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_regbit_get (p->io.avr, p->watchdog.enable)) avr_cycle_timer_register (p->io.avr, p->cycle_count, avr_watchdog_timer, p); res = 0; } return res; }
int avr_is_interrupt_enabled( avr_t * avr, avr_int_vector_t * vector) { return avr_regbit_get(avr, vector->enable); }
static uint8_t avr_uart_read(struct avr_t * avr, avr_io_addr_t addr, void * param) { avr_uart_t * p = (avr_uart_t *)param; // clear the rxc bit in case the code is using polling avr_regbit_clear(avr, p->rxc.raised); if (!avr_regbit_get(avr, p->rxen)) { avr->data[addr] = 0; // made to trigger potential watchpoints avr_core_watch_read(avr, addr); return 0; } uint8_t v = uart_fifo_read(&p->input); // TRACE(printf("UART read %02x %s\n", v, uart_fifo_isempty(&p->input) ? "EMPTY!" : "");) avr->data[addr] = v; // made to trigger potential watchpoints v = avr_core_watch_read(avr, addr); // trigger timer if more characters are pending if (!uart_fifo_isempty(&p->input)) avr_cycle_timer_register_usec(avr, p->usec_per_byte, avr_uart_rxc_raise, p); return v; }
static void avr_timer_irq_icp(struct avr_irq_t * irq, uint32_t value, void * param) { avr_timer_t * p = (avr_timer_t *)param; avr_t * avr = p->io.avr; // input capture disabled when ICR is used as top if (p->mode.top == avr_timer_wgm_reg_icr) return; int bing = 0; if (avr_regbit_get(avr, p->ices)) { // rising edge if (!irq->value && value) bing++; } else { // default, falling edge if (irq->value && !value) bing++; } if (!bing) return; // get current TCNT, copy it to ICR, and raise interrupt uint16_t tcnt = _avr_timer_get_current_tcnt(p); avr->data[p->r_icr] = tcnt; if (p->r_icrh) avr->data[p->r_icrh] = tcnt >> 8; avr_raise_interrupt(avr, &p->icr); }
static void avr_twi_irq_input( struct avr_irq_t * irq, uint32_t value, void * param) { avr_twi_t * p = (avr_twi_t *)param; avr_t * avr = p->io.avr; // check to see if we are enabled if (!avr_regbit_get(avr, p->twen)) return; avr_twi_msg_irq_t msg; msg.u.v = value; // receiving an acknowledge bit if (msg.u.twi.msg & TWI_COND_ACK) { #if AVR_TWI_DEBUG printf("I2C received ACK:%d\n", msg.u.twi.data & 1); #endif if (msg.u.twi.data & 1) p->state |= TWI_COND_ACK; else p->state &= ~TWI_COND_ACK; } // receive a data byte from a slave if (msg.u.twi.msg & TWI_COND_READ) { #if AVR_TWI_DEBUG printf("I2C received %02x\n", msg.u.twi.data); #endif avr->data[p->r_twdr] = msg.u.twi.data; } }
static avr_cycle_count_t avr_uart_rxc_raise(struct avr_t * avr, avr_cycle_count_t when, void * param) { avr_uart_t * p = (avr_uart_t *)param; if (avr_regbit_get(avr, p->rxen)) avr_raise_interrupt(avr, &p->rxc); return 0; }
static void avr_timer_comp_on_tov( avr_timer_t *p, avr_cycle_count_t when, uint8_t comp) { avr_t * avr = p->io.avr; // check output compare mode and set/clear pins uint8_t mode = avr_regbit_get(avr, p->comp[comp].com); avr_irq_t * irq = &p->io.irq[TIMER_IRQ_OUT_COMP + comp]; switch (mode) { case avr_timer_com_normal: // Normal mode break; case avr_timer_com_toggle: // toggle on compare match => on tov do nothing break; case avr_timer_com_clear: // clear on compare match => set on tov avr_raise_irq(irq, 1); break; case avr_timer_com_set: // set on compare match => clear on tov avr_raise_irq(irq, 0); break; } }
/* * check whether interrupts are pending. If so, check if the interrupt "latency" is reached, * and if so triggers the handlers and jump to the vector. */ void avr_service_interrupts( avr_t * avr) { if (!avr->sreg[S_I] || !avr->interrupt_state) return; if (avr->interrupt_state < 0) { avr->interrupt_state++; if (avr->interrupt_state == 0) avr->interrupt_state = avr_has_pending_interrupts(avr); return; } avr_int_table_p table = &avr->interrupts; // how many are pending... int cnt = avr_int_pending_get_read_size(&table->pending); // locate the highest priority one int min = 0xff; int mini = 0; for (int ii = 0; ii < cnt; ii++) { avr_int_vector_t * v = avr_int_pending_read_at(&table->pending, ii); if (v->vector < min) { min = v->vector; mini = ii; } } avr_int_vector_t * vector = avr_int_pending_read_at(&table->pending, mini); // now move the one at the front of the fifo in the slot of // the one we service table->pending.buffer[(table->pending.read + mini) % avr_int_pending_fifo_size] = avr_int_pending_read(&table->pending); avr_raise_irq(avr->interrupts.irq + AVR_INT_IRQ_PENDING, avr_has_pending_interrupts(avr)); // if that single interrupt is masked, ignore it and continue // could also have been disabled, or cleared if (!avr_regbit_get(avr, vector->enable) || !vector->pending) { vector->pending = 0; avr->interrupt_state = avr_has_pending_interrupts(avr); } else { if (vector && vector->trace) printf("%s calling %d\n", __FUNCTION__, (int)vector->vector); _avr_push_addr(avr, avr->pc); avr_sreg_set(avr, S_I, 0); avr->pc = vector->vector * avr->vector_size; avr_raise_irq(vector->irq + AVR_INT_IRQ_RUNNING, 1); avr_raise_irq(table->irq + AVR_INT_IRQ_RUNNING, vector->vector); if (table->running_ptr == ARRAY_SIZE(table->running)) { AVR_LOG(avr, LOG_ERROR, "%s run out of nested stack!", __func__); } else { table->running[table->running_ptr++] = vector; } avr_clear_interrupt(avr, vector); } }
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); } }
/* * prevent code from rewriting out status bits, since we actualy use them! */ static void avr_twi_write_status( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_twi_t * p = (avr_twi_t *)param; uint8_t sr = avr_regbit_get(avr, p->twsr); uint8_t c = avr_regbit_get(avr, p->twps); avr_core_watch_write(avr, addr, v); avr_regbit_setto(avr, p->twsr, sr); // force restore if (c != avr_regbit_get(avr, p->twps)) { // prescaler bits changed... } }
/* * check whether interrupts are pending. If so, check if the interrupt "latency" is reached, * and if so triggers the handlers and jump to the vector. */ void avr_service_interrupts( avr_t * avr) { if (!avr->sreg[S_I]) return; if (!avr_has_pending_interrupts(avr)) return; avr_int_table_p table = &avr->interrupts; if (!table->pending_wait) { table->pending_wait = 2; // for next one... return; } table->pending_wait--; if (table->pending_wait) return; // how many are pending... int cnt = table->pending_w > table->pending_r ? table->pending_w - table->pending_r : (table->pending_w + INT_FIFO_SIZE) - table->pending_r; // locate the highest priority one int min = 0xff; int mini = 0; for (int ii = 0; ii < cnt; ii++) { int vi = INT_FIFO_MOD(table->pending_r + ii); avr_int_vector_t * v = table->pending[vi]; if (v->vector < min) { min = v->vector; mini = vi; } } avr_int_vector_t * vector = table->pending[mini]; // now move the one at the front of the fifo in the slot of // the one we service table->pending[mini] = table->pending[table->pending_r++]; table->pending_r = INT_FIFO_MOD(table->pending_r); // if that single interrupt is masked, ignore it and continue // could also have been disabled, or cleared if (!avr_regbit_get(avr, vector->enable) || !vector->pending) { vector->pending = 0; } else { if (vector && vector->trace) printf("%s calling %d\n", __FUNCTION__, (int)vector->vector); _avr_push_addr(avr, avr->pc); avr->sreg[S_I] = 0; avr->pc = vector->vector * avr->vector_size; avr_clear_interrupt(avr, vector); } }
static void avr_spi_irq_input(struct avr_irq_t * irq, uint32_t value, void * param) { avr_spi_t * p = (avr_spi_t *)param; avr_t * avr = p->io.avr; // check to see if receiver is enabled if (!avr_regbit_get(avr, p->spe)) return; // double buffer the input.. ? p->input_data_register = value; avr_raise_interrupt(avr, &p->spi); // if in slave mode, // 'output' the byte only when we received one... if (!avr_regbit_get(avr, p->mstr)) { avr_raise_irq(p->io.irq + SPI_IRQ_OUTPUT, avr->data[p->r_spdr]); } }
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); } }
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; }
static avr_cycle_count_t avr_uart_txc_raise(struct avr_t * avr, avr_cycle_count_t when, void * param) { avr_uart_t * p = (avr_uart_t *)param; if (avr_regbit_get(avr, p->txen)) { // if the interrupts are not used, still raise the UDRE and TXC flag avr_raise_interrupt(avr, &p->udrc); avr_raise_interrupt(avr, &p->txc); } return 0; }
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_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; // 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); }
int avr_clear_interrupt_if( avr_t * avr, avr_int_vector_t * vector, uint8_t old) { if (avr_regbit_get(avr, vector->raised)) { avr_clear_interrupt(avr, vector); return 1; } avr_regbit_setto(avr, vector->raised, old); return 0; }
static void avr_uart_baud_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_uart_t * p = (avr_uart_t *)param; avr_core_watch_write(avr, addr, v); uint32_t val = avr->data[p->r_ubrrl] | (avr->data[p->r_ubrrh] << 8); uint32_t baud = avr->frequency / (val+1); if (avr_regbit_get(avr, p->u2x)) baud /= 8; else baud /= 16; const int databits[] = { 5,6,7,8, /* 'reserved', assume 8 */8,8,8, 9 }; int db = databits[avr_regbit_get(avr, p->ucsz) | (avr_regbit_get(avr, p->ucsz2) << 2)]; int sb = 1 + avr_regbit_get(avr, p->usbs); int word_size = 1 /* start */ + db /* data bits */ + 1 /* parity */ + sb /* stops */; AVR_LOG(avr, LOG_TRACE, "UART: %c configured to %04x = %d bps (x%d), %d data %d stop\n", p->name, val, baud, avr_regbit_get(avr, p->u2x)?2:1, db, sb); // TODO: Use the divider value and calculate the straight number of cycles p->usec_per_byte = 1000000 / (baud / word_size); AVR_LOG(avr, LOG_TRACE, "UART: Roughly %d usec per bytes\n", (int)p->usec_per_byte); }