/* * 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); } }
/* * 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); } }
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; }
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 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_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; } }