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 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 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); } }
/** * 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; }
/* this is called uppon RETI. */ void avr_interrupt_reti( struct avr_t * avr) { avr_int_table_p table = &avr->interrupts; if (table->running_ptr) { avr_int_vector_t * vector = table->running[--table->running_ptr]; avr_raise_irq(vector->irq + AVR_INT_IRQ_RUNNING, 0); } avr_raise_irq(table->irq + AVR_INT_IRQ_RUNNING, table->running_ptr > 0 ? table->running[table->running_ptr-1]->vector : 0); avr_raise_irq(avr->interrupts.irq + AVR_INT_IRQ_PENDING, avr_has_pending_interrupts(avr)); }
static void avr_timer_write_ocr( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_timer_comp_p comp = (avr_timer_comp_p)param; avr_timer_t *timer = comp->timer; uint16_t oldv; /* check to see if the OCR values actually changed */ oldv = _timer_get_comp_ocr(avr, comp); avr_core_watch_write(avr, addr, v); switch (timer->wgm_op_mode_kind) { case avr_timer_wgm_normal: avr_timer_reconfigure(timer, 0); break; case avr_timer_wgm_fc_pwm: // OCR is not used here avr_timer_reconfigure(timer, 0); break; case avr_timer_wgm_ctc: avr_timer_reconfigure(timer, 0); break; case avr_timer_wgm_pwm: if (timer->mode.top != avr_timer_wgm_reg_ocra) { avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocr(timer, AVR_TIMER_COMPA)); } else { avr_timer_reconfigure(timer, 0); // if OCRA is the top, reconfigure needed } avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocr(timer, AVR_TIMER_COMPB)); break; case avr_timer_wgm_fast_pwm: if (oldv != _timer_get_comp_ocr(avr, comp)) avr_timer_reconfigure(timer, 0); avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocr(timer, AVR_TIMER_COMPA)); avr_raise_irq(timer->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocr(timer, AVR_TIMER_COMPB)); break; default: AVR_LOG(avr, LOG_WARNING, "TIMER: %s-%c mode %d UNSUPPORTED\n", __FUNCTION__, timer->name, timer->mode.kind); avr_timer_reconfigure(timer, 0); break; } }
/* * called when the ADC could use a new value * The value returned is NOT in "ADC" mode, it's in millivolts */ static void thermistor_in_hook (struct avr_irq_t *irq, uint32_t value, void *param) { thermistor_p p = (thermistor_p) param; avr_adc_mux_t v = *((avr_adc_mux_t *) & value); // printf("%s(%2d/%2d)\n", __func__, p->adc_mux_number, v.src); if (v.src != p->adc_mux_number) return; short *t = p->table; for (int ei = 0; ei < p->table_entries; ei++, t += 2) { if (t[1] <= p->current) { // printf("%s(%2d) %.2f matches %3dC is %d adc\n", __func__, v.src, // p->current, t[1], t[0] / p->oversampling); avr_raise_irq (p->irq + IRQ_TERM_ADC_VALUE_OUT, ((t[0] / p->oversampling) * 5000) / 0x3ff); return; } } printf ("%s(%d) temperature out of range (%.2f), we're screwed\n", __func__, p->adc_mux_number, p->current); }
/* * called when a SPI byte is sent */ static void hc595_spi_in_hook(struct avr_irq_t * irq, uint32_t value, void * param) { hc595_t * p = (hc595_t*)param; // send "old value" to any chained one.. avr_raise_irq(p->irq + IRQ_HC595_SPI_BYTE_OUT, p->value); p->value = (p->value << 8) | (value & 0xff); }
void thermistor_set_temp (thermistor_p p, float temp) { uint32_t value = temp * 256; p->current = temp; avr_raise_irq (p->irq + IRQ_TERM_TEMP_VALUE_OUT, value); }
/* * called when a LATCH signal is sent */ static void hc595_latch_hook(struct avr_irq_t * irq, uint32_t value, void * param) { hc595_t * p = (hc595_t*)param; if (irq->value && !value) { // falling edge p->latch = p->value; avr_raise_irq(p->irq + IRQ_HC595_OUT, p->latch); } }
/** * Raises the card presence signal. * The clock signal is expected to already have stopped, * and the data buffer for the DATA pin will be reset. * * @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_raise_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), 1); self->swipe_buffer_pos = 0; return 0; }
static void thermistor_value_in_hook (struct avr_irq_t *irq, uint32_t value, void *param) { thermistor_p p = (thermistor_p) param; float fv = ((float) value) / 256; p->current = fv; avr_raise_irq (p->irq + IRQ_TERM_TEMP_VALUE_OUT, value); }
void avr_clear_interrupt( avr_t * avr, avr_int_vector_t * vector) { if (!vector) return; if (vector->trace) printf("%s cleared %d\n", __FUNCTION__, vector->vector); vector->pending = 0; avr_raise_irq(vector->irq + AVR_INT_IRQ_PENDING, 0); avr_raise_irq(avr->interrupts.irq + AVR_INT_IRQ_PENDING, avr_has_pending_interrupts(avr)); if (vector->raised.reg && !vector->raise_sticky) avr_regbit_clear(avr, vector->raised); }
static void avr_usb_udcon_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_usb_t * p = (avr_usb_t *)param; if(avr->data[addr]&1 && !(v&1)) avr_raise_irq(p->io.irq + USB_IRQ_ATTACH, !(v&1)); avr_core_watch_write(avr, addr, v); }
static void avr_timer_write_ocr(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_timer_t * p = (avr_timer_t *)param; uint16_t oldv[AVR_TIMER_COMP_COUNT]; int target = -1; /* check to see if the OCR values actually changed */ for (int oi = 0; oi < AVR_TIMER_COMP_COUNT; oi++) oldv[oi] = _timer_get_ocr(p, oi); avr_core_watch_write(avr, addr, v); for (int oi = 0; oi < AVR_TIMER_COMP_COUNT; oi++) if (oldv[oi] != _timer_get_ocr(p, oi)) { target = oi; break; } switch (p->mode.kind) { case avr_timer_wgm_normal: avr_timer_reconfigure(p); break; case avr_timer_wgm_fc_pwm: // OCR is not used here avr_timer_reconfigure(p); break; case avr_timer_wgm_ctc: avr_timer_reconfigure(p); break; case avr_timer_wgm_pwm: if (p->mode.top != avr_timer_wgm_reg_ocra) { avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocr(p, AVR_TIMER_COMPA)); avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocr(p, AVR_TIMER_COMPB)); } break; case avr_timer_wgm_fast_pwm: if (target != -1) avr_timer_reconfigure(p); avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocr(p, AVR_TIMER_COMPA)); avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocr(p, AVR_TIMER_COMPB)); break; default: AVR_LOG(avr, LOG_WARNING, "TIMER: %s-%c mode %d UNSUPPORTED\n", __FUNCTION__, p->name, p->mode.kind); avr_timer_reconfigure(p); break; } }
static avr_cycle_count_t switch_auto(struct avr_t * avr, avr_cycle_count_t when, void * param) { ac_input_t * b = (ac_input_t *) param; b->value = !b->value; //printf("ac=%d\n", b->value); avr_raise_irq(b->irq + IRQ_AC_OUT, b->value); return when + avr_usec_to_cycles(avr, 100000 / 50); }
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 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 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 inline void _avr_twi_status_set( avr_twi_t * p, uint8_t v, int interrupt) { avr_regbit_setto_raw(p->io.avr, p->twsr, v); #if AVR_TWI_DEBUG AVR_TRACE(p->io.avr, "%s %02x\n", __func__, v); #endif avr_raise_irq(p->io.irq + TWI_IRQ_STATUS, v); if (interrupt) avr_raise_interrupt(p->io.avr, &p->twi); }
/* * Called when the uart has room in it's input buffer. This is called repeateadly * if necessary, while the xoff is called only when the uart fifo is FULL */ static void uart_udp_xon_hook(struct avr_irq_t * irq, uint32_t value, void * param) { uart_udp_t * p = (uart_udp_t*)param; // if (!p->xon) // printf("uart_udp_xon_hook\n"); p->xon = 1; // try to empty our fifo, the uart_udp_xoff_hook() will be called when // other side is full while (p->xon && !uart_udp_fifo_isempty(&p->out)) { uint8_t byte = uart_udp_fifo_read(&p->out); // printf("uart_udp_xon_hook send %02x\n", byte); avr_raise_irq(p->irq + IRQ_UART_UDP_BYTE_OUT, byte); } }
void avr_clear_interrupt( avr_t * avr, avr_int_vector_t * vector) { if (!vector) return; if (vector->trace) printf("%s cleared %d\n", __FUNCTION__, vector->vector); vector->pending = 0; avr_raise_irq(&vector->irq, 0); if (vector->raised.reg && !vector->raise_sticky) avr_regbit_clear(avr, vector->raised); }
static avr_cycle_count_t avr_adc_int_raise(struct avr_t * avr, avr_cycle_count_t when, void * param) { avr_adc_t * p = (avr_adc_t *)param; if (avr_regbit_get(avr, p->aden)) { // if the interrupts are not used, still raised the UDRE and TXC flag avr_raise_interrupt(avr, &p->adc); avr_regbit_clear(avr, p->adsc); p->first = 0; p->read_status = 0; if( p->adts_mode == avr_adts_free_running ) avr_raise_irq(p->io.irq + ADC_IRQ_IN_TRIGGER, 1); } return 0; }
int avr_clear_interrupt_if( avr_t * avr, avr_int_vector_t * vector, uint8_t old) { avr_raise_irq(avr->interrupts.irq + AVR_INT_IRQ_PENDING, avr_has_pending_interrupts(avr)); if (avr_regbit_get(avr, vector->raised)) { avr_clear_interrupt(avr, vector); return 1; } avr_regbit_setto(avr, vector->raised, old); return 0; }
static uint8_t avr_ioport_read( struct avr_t * avr, avr_io_addr_t addr, void * param) { avr_ioport_t * p = (avr_ioport_t *)param; uint8_t ddr = avr->data[p->r_ddr]; uint8_t v = (avr->data[p->r_pin] & ~ddr) | (avr->data[p->r_port] & ddr); avr->data[addr] = v; // made to trigger potential watchpoints v = avr_core_watch_read(avr, addr); avr_raise_irq(p->io.irq + IOPORT_IRQ_REG_PIN, v); D(if (avr->data[addr] != v) printf("** PIN%c(%02x) = %02x\r\n", p->name, addr, v);) return v;
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]); } }
/* * Set a register (r < 256) * if it's an IO register (> 31) also (try to) call any callback that was * registered to track changes to that register. */ static inline void _avr_set_r(avr_t * avr, uint8_t r, uint8_t v) { REG_TOUCH(avr, r); if (r == R_SREG) { avr->data[R_SREG] = v; // unsplit the SREG SET_SREG_FROM(avr, v); SREG(); } if (r > 31) { uint8_t io = AVR_DATA_TO_IO(r); if (avr->io[io].w.c) avr->io[io].w.c(avr, r, v, avr->io[io].w.param); else avr->data[r] = v; if (avr->io[io].irq) { avr_raise_irq(avr->io[io].irq + AVR_IOMEM_IRQ_ALL, v); for (int i = 0; i < 8; i++) avr_raise_irq(avr->io[io].irq + i, (v >> i) & 1); }
int main(int argc, char *argv[]) { elf_firmware_t f; const char *fname="../src/binw2.elf"; const char *mmcu="attiny13"; elf_read_firmware(fname, &f); snprintf(f.mmcu, sizeof(f.mmcu) - 1, "%s", mmcu); f.frequency = 4800000; printf("firmware %s f=%d mmcu=%s\n", fname, (int)f.frequency, f.mmcu); avr = avr_make_mcu_by_name(f.mmcu); if (!avr) { fprintf(stderr, "%s: AVR '%s' not known\n", argv[0], f.mmcu); exit(1); } avr_init(avr); avr_load_firmware(avr, &f); // initialize our 'peripheral' button_init(avr, &button, "button"); // "connect" the output irq of the button to the port pin of the AVR avr_connect_irq( button.irq + IRQ_BUTTON_OUT, avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), IOPORT_IRQ_PIN4)); avr_irq_register_notify( avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), IOPORT_IRQ_DIRECTION_ALL), ddr_hook, NULL); avr_irq_register_notify( avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), IOPORT_IRQ_PIN_ALL), pin_changed_hook, "portb"); // even if not setup at startup, activate gdb if crashing avr->gdb_port = 1234; //if (0) { // //avr->state = cpu_Stopped; // avr_gdb_init(avr); //} /* * VCD file initialization * * This will allow you to create a "wave" file and display it in gtkwave * Pressing "r" and "s" during the demo will start and stop recording * the pin changes */ avr_vcd_init(avr, "gtkwave_output.vcd", &vcd_file, 100000 /* usec */); avr_vcd_add_signal(&vcd_file, avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), IOPORT_IRQ_PIN_ALL), 8 /* bits */ , "portb" ); avr_vcd_add_signal(&vcd_file, button.irq + IRQ_BUTTON_OUT, 1 /* bits */ , "button" ); // 'raise' it, it's a "pullup" avr_raise_irq(button.irq + IRQ_BUTTON_OUT, 0); printf( "Launching binw2 simulation\n" " Press 'space' to press virtual button attached to pin %d\n" " Press 'q' to quit\n" " Press 'r' to start recording a 'wave' file\n" " Press 's' to stop recording\n", IOPORT_IRQ_PIN4); /* * OpenGL init, can be ignored */ glutInit(&argc, argv); /* initialize GLUT system */ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutInitWindowSize(5 * SZ_PIXSIZE, 7 * SZ_PIXSIZE); window = glutCreateWindow("Glut"); /* create window */ // Set up projection matrix glMatrixMode(GL_PROJECTION); // Select projection matrix glLoadIdentity(); // Start with an identity matrix glOrtho(0, 5 * SZ_PIXSIZE, 0, 7 * SZ_PIXSIZE, 0, 10); //glScalef(1, -1, 1); //glTranslatef(0, -7 * SZ_PIXSIZE, 0); glutDisplayFunc(displayCB); /* set window's display callback */ glutKeyboardFunc(keyCB); /* set window's key callback */ glutTimerFunc(1000 / 24, timerCB, 0); // the AVR run on it's own thread. it even allows for debugging! pthread_t run; pthread_create(&run, NULL, avr_run_thread, NULL); glutMainLoop(); }
int main(int argc, char *argv[]) { elf_firmware_t f; //const char * fname = "atmega48_ledramp.axf"; const char * fname = argv[1]; char path[256]; // sprintf(path, "%s/%s", dirname(argv[0]), fname); // printf("Firmware pathname is %s\n", path); elf_read_firmware(fname, &f); printf("firmware %s f=%d mmcu=%s\n", fname, (int)f.frequency, f.mmcu); avr = avr_make_mcu_by_name(f.mmcu); if (!avr) { fprintf(stderr, "%s: AVR '%s' now known\n", argv[0], f.mmcu); exit(1); } avr_init(avr); avr_load_firmware(avr, &f); // initialize our 'peripheral' button_init(avr, &button, "button"); // "connect" the output irw of the button to the port pin of the AVR avr_connect_irq( button.irq + IRQ_BUTTON_OUT, avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('C'), 0)); // connect all the pins on port B to our callback for (int i = 0; i < 8; i++) avr_irq_register_notify( avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), i), pin_changed_hook, NULL); // even if not setup at startup, activate gdb if crashing avr->gdb_port = 1234; if (0) { //avr->state = cpu_Stopped; avr_gdb_init(avr); } /* * VCD file initialization * * This will allow you to create a "wave" file and display it in gtkwave * Pressing "r" and "s" during the demo will start and stop recording * the pin changes */ avr_vcd_init(avr, "gtkwave_output.vcd", &vcd_file, 100000 /* usec */); avr_vcd_add_signal(&vcd_file, avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('B'), IOPORT_IRQ_PIN_ALL), 8 /* bits */ , "portb" ); avr_vcd_add_signal(&vcd_file, avr_io_getirq(avr, AVR_IOCTL_IOPORT_GETIRQ('C'), IOPORT_IRQ_PIN0), 1, "portc"); avr_vcd_add_signal(&vcd_file, button.irq + IRQ_BUTTON_OUT, 1 /* bits */ , "button" ); // 'raise' it, it's a "pullup" avr_raise_irq(button.irq + IRQ_BUTTON_OUT, 1); printf( "Demo launching: 'LED' bar is PORTB, updated every 1/64s by the AVR\n" " firmware using a timer. If you press 'space' this presses a virtual\n" " 'button' that is hooked to the virtual PORTC pin 0 and will\n" " trigger a 'pin change interrupt' in the AVR core, and will 'invert'\n" " the display.\n" " Press 'q' to quit\n\n" " Press 'r' to start recording a 'wave' file\n" " Press 's' to stop recording\n" ); /* * OpenGL init, can be ignored */ glutInit(&argc, argv); /* initialize GLUT system */ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutInitWindowSize(8 * pixsize, 1 * pixsize); /* width=400pixels height=500pixels */ window = glutCreateWindow("Glut"); /* create window */ // Set up projection matrix glMatrixMode(GL_PROJECTION); // Select projection matrix glLoadIdentity(); // Start with an identity matrix glOrtho(0, 8 * pixsize, 0, 1 * pixsize, 0, 10); glScalef(1,-1,1); glTranslatef(0, -1 * pixsize, 0); glutDisplayFunc(displayCB); /* set window's display callback */ glutKeyboardFunc(keyCB); /* set window's key callback */ glutTimerFunc(1000 / 24, timerCB, 0); // the AVR run on it's own thread. it even allows for debugging! pthread_t run; pthread_create(&run, NULL, avr_run_thread, NULL); glutMainLoop(); }