static void avr_uart_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_uart_t * p = (avr_uart_t *)param; if (addr == p->r_udr) { avr_core_watch_write(avr, addr, v); if ( p->udrc.vector) avr_regbit_clear(avr, p->udrc.raised); avr_cycle_timer_register_usec(avr, p->usec_per_byte, avr_uart_txc_raise, p); // should be uart speed dependent if (p->flags & AVR_UART_FLAG_STDIO) { const int maxsize = 256; if (!p->stdio_out) p->stdio_out = malloc(maxsize); p->stdio_out[p->stdio_len++] = v < ' ' ? '.' : v; p->stdio_out[p->stdio_len] = 0; if (v == '\n' || p->stdio_len == maxsize) { p->stdio_len = 0; AVR_LOG(avr, LOG_TRACE, FONT_GREEN "%s\n" FONT_DEFAULT, p->stdio_out); } } TRACE(printf("UDR%c(%02x) = %02x\n", p->name, addr, v);) // tell other modules we are "outputting" a byte if (avr_regbit_get(avr, p->txen))
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); }
/* * 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 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_spi_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_spi_t * p = (avr_spi_t *)param; if (addr == p->r_spdr) { // printf("avr_spi_write = %02x\n", v); avr_core_watch_write(avr, addr, v); avr_cycle_timer_register_usec(avr, 100, avr_spi_raise, p); // should be speed dependent } }
static void avr_usb_uenum_write( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { assert(v < num_endpoints); avr_core_watch_write(avr, addr, v); }
static void avr_usb_udaddr_write( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { if (v & 0x80) AVR_LOG(avr, LOG_TRACE, "USB: Activate address %d\n", v & 0x7f); avr_core_watch_write(avr, addr, v); }
static void avr_usb_udaddr_write( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { if (v & 0x80) printf("Activate address %d\n", v & 0x7f); avr_core_watch_write(avr, addr, v); }
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_twi_write( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_twi_t * p = (avr_twi_t *)param; uint8_t twen = avr_regbit_get(avr, p->twen); uint8_t twsta = avr_regbit_get(avr, p->twsta); uint8_t twsto = avr_regbit_get(avr, p->twsto); uint8_t twint = avr_regbit_get(avr, p->twi.raised); avr_core_watch_write(avr, addr, v); #if AVR_TWI_DEBUG AVR_TRACE(avr, "%s %02x START:%d STOP:%d ACK:%d INT:%d TWSR:%02x (state %02x)\n", __func__, v, avr_regbit_get(avr, p->twsta), avr_regbit_get(avr, p->twsto), avr_regbit_get(avr, p->twea), avr_regbit_get(avr, p->twi.raised), avr_regbit_get_raw(p->io.avr, p->twsr), p->state); #endif if (twen != avr_regbit_get(avr, p->twen)) { twen = !twen; if (!twen) { // if we were running, now now are not avr_regbit_clear(avr, p->twea); avr_regbit_clear(avr, p->twsta); avr_regbit_clear(avr, p->twsto); avr_clear_interrupt(avr, &p->twi); avr_core_watch_write(avr, p->r_twdr, 0xff); _avr_twi_status_set(p, TWI_NO_STATE, 0); p->state = 0; p->peer_addr = 0; } AVR_TRACE(avr, "TWEN: %d\n", twen); if (avr->data[p->r_twar]) { AVR_TRACE(avr, "TWEN Slave: %02x&%02x\n", avr->data[p->r_twar] >> 1, avr->data[p->r_twamr] >> 1); p->state |= TWI_COND_SLAVE; }
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); }
/* * Write data to the latch, tell the system we have something * to send next */ static void avr_twi_write_data( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_twi_t * p = (avr_twi_t *)param; avr_core_watch_write(avr, addr, v); // tell system we have something in the write latch p->state |= TWI_COND_WRITE; }
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); } }
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; } }
static void avr_usb_ep_write( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_usb_t * p = (avr_usb_t *) param; struct _epstate * epstate = get_epstate(p, current_ep_to_cpu(p)); uint8_t laddr = addr - p->r_usbcon; switch (laddr) { case ueconx: if (v & 1 << 4) epstate->ueconx.stallrq = 0; if (v & 1 << 5) epstate->ueconx.stallrq = 1; epstate->ueconx.epen = (v & 1) != 0; break; case uecfg0x: epstate->uecfg0x.v = v; epstate->uesta0x.cfgok = 0; break; case uecfg1x: epstate->uecfg1x.v = v; epstate->uesta0x.cfgok = epstate->uecfg1x.alloc; if (epstate->uecfg0x.eptype == 0) epstate->ueintx.txini = 1; else if (epstate->uecfg0x.epdir) { epstate->ueintx.txini = 1; epstate->ueintx.rwal = 1; epstate->ueintx.fifocon = 1; } else epstate->ueintx.rxouti = 0; avr_core_watch_write(avr, p->r_usbcon + uesta0x, epstate->uesta0x.v); break; case uesta0x: v = (epstate->uesta0x.v & 0x9f) + (v & (0x60 & epstate->uesta0x.v)); epstate->uesta0x.v = v; break; case ueienx: epstate->ueienx.v = v; break; default: assert(0); } }
/* * 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... } }
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 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_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_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); }
static void avr_twi_write( struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_twi_t * p = (avr_twi_t *)param; uint8_t twen = avr_regbit_get(avr, p->twen); uint8_t twsta = avr_regbit_get(avr, p->twsta); uint8_t twsto = avr_regbit_get(avr, p->twsto); uint8_t twint = avr_regbit_get(avr, p->twi.raised); avr_core_watch_write(avr, addr, v); #if AVR_TWI_DEBUG printf("avr_twi_write %02x START:%d STOP:%d ACK:%d INT:%d TWSR:%02x (state %02x)\n", v, avr_regbit_get(avr, p->twsta), avr_regbit_get(avr, p->twsto), avr_regbit_get(avr, p->twea), avr_regbit_get(avr, p->twi.raised), avr_regbit_get_raw(p->io.avr, p->twsr), p->state); #endif if (twen != avr_regbit_get(avr, p->twen)) { twen = !twen; if (!twen) { // if we were running, now now are not avr_regbit_clear(avr, p->twea); avr_regbit_clear(avr, p->twsta); avr_regbit_clear(avr, p->twsto); avr_clear_interrupt(avr, &p->twi); avr_core_watch_write(avr, p->r_twdr, 0xff); _avr_twi_status_set(p, TWI_NO_STATE, 0); p->state = 0; p->peer_addr = 0; } printf("TWEN: %d\n", twen); } if (!twen) return; uint8_t cleared = avr_regbit_get(avr, p->twi.raised); /*int cleared = */avr_clear_interrupt_if(avr, &p->twi, twint); // printf("cleared %d\n", cleared); if (!twsto && avr_regbit_get(avr, p->twsto)) { // generate a stop condition #if AVR_TWI_DEBUG printf("<<<<< I2C stop\n"); #endif if (p->state) { // doing stuff if (p->state & TWI_COND_START) { avr_raise_irq(p->io.irq + TWI_IRQ_MOSI, avr_twi_irq_msg(TWI_COND_STOP, p->peer_addr, 1)); } } p->state = 0; } if (!twsta && avr_regbit_get(avr, p->twsta)) { #if AVR_TWI_DEBUG printf(">>>>> I2C %sstart\n", p->state & TWI_COND_START ? "RE" : ""); #endif // generate a start condition if (p->state & TWI_COND_START) _avr_twi_delay_state(p, 3, TWI_REP_START); else _avr_twi_delay_state(p, 3, TWI_START); p->peer_addr = 0; p->state = TWI_COND_START; } if (cleared && !avr_regbit_get(avr, p->twsta) && !avr_regbit_get(avr, p->twsto)) { // writing or reading a byte if (p->state & TWI_COND_ADDR) { int do_read = p->peer_addr & 1; #if AVR_TWI_DEBUG if (do_read) printf("I2C READ byte from %02x\n", p->peer_addr); else printf("I2C WRITE byte %02x to %02x\n", avr->data[p->r_twdr], p->peer_addr); #endif // a normal data byte uint8_t msgv = do_read ? TWI_COND_READ : TWI_COND_WRITE; if (avr_regbit_get(avr, p->twea)) msgv |= TWI_COND_ACK; p->state &= ~TWI_COND_ACK; // clear ACK bit // if the latch is ready... as set by writing/reading the TWDR if ((p->state & msgv)) { // we send an IRQ and we /expect/ a slave to reply // immediately via an IRQ to set the COND_ACK bit // otherwise it's assumed it's been nacked... avr_raise_irq(p->io.irq + TWI_IRQ_MOSI, avr_twi_irq_msg(msgv, p->peer_addr, avr->data[p->r_twdr])); if (do_read) { // read ? _avr_twi_delay_state(p, 9, msgv & TWI_COND_ACK ? TWI_MRX_DATA_ACK : TWI_MRX_DATA_NACK); } else { _avr_twi_delay_state(p, 9, p->state & TWI_COND_ACK ? TWI_MTX_DATA_ACK : TWI_MTX_DATA_NACK); } } #if AVR_TWI_DEBUG else printf("I2C latch is not ready, do nothing\n"); #endif } else { #if AVR_TWI_DEBUG printf("I2C Master address %02x\n", avr->data[p->r_twdr]); #endif // send the address p->state |= TWI_COND_ADDR; p->peer_addr = avr->data[p->r_twdr]; p->state &= ~TWI_COND_ACK; // clear ACK bit // we send an IRQ and we /expect/ a slave to reply // immediately via an IRQ tp set the COND_ACK bit // otherwise it's assumed it's been nacked... avr_raise_irq(p->io.irq + TWI_IRQ_MOSI, avr_twi_irq_msg(TWI_COND_START, p->peer_addr, 0)); if (p->peer_addr & 1) { // read ? p->state |= TWI_COND_READ; // always allow read to start with _avr_twi_delay_state(p, 9, p->state & TWI_COND_ACK ? TWI_MRX_ADR_ACK : TWI_MRX_ADR_NACK); } else { _avr_twi_delay_state(p, 9, p->state & TWI_COND_ACK ? TWI_MTX_ADR_ACK : TWI_MTX_ADR_NACK); } } p->state &= ~TWI_COND_WRITE; } }