return v;
}
+static void avr_ioport_update_irqs(avr_ioport_t * p)
+{
+ avr_t * avr = p->io.avr;
+ uint8_t ddr = avr->data[p->r_ddr];
+ // Set the PORT value if the pin is marked as output
+ // otherwise, if there is an 'external' pullup, set it
+ // otherwise, if the PORT pin was 1 to indicate an
+ // internal pullup, set that.
+ for (int i = 0; i < 8; i++) {
+ if (ddr & (1 << i))
+ avr_raise_irq(p->io.irq + i, (avr->data[p->r_port] >> i) & 1);
+ else if (p->external.pull_mask & (1 << i))
+ avr_raise_irq(p->io.irq + i, (p->external.pull_value >> i) & 1);
+ else if ((avr->data[p->r_port] >> i) & 1)
+ avr_raise_irq(p->io.irq + i, 1);
+ }
+ uint8_t pin = (avr->data[p->r_pin] & ~ddr) | (avr->data[p->r_port] & ddr);
+ pin = (pin & ~p->external.pull_mask) | p->external.pull_value;
+ avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, pin);
+}
+
static void avr_ioport_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
{
avr_ioport_t * p = (avr_ioport_t *)param;
avr_core_watch_write(avr, addr, v);
// printf("PORT%c(%02x) = %02x (was %02x)\n", p->name, addr, v, oldv);
- // raise the internal IRQ callbacks
- for (int i = 0; i < 8; i++)
- avr_raise_irq(p->io.irq + i, (v >> i) & 1);
- avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, v);
+ avr_ioport_update_irqs(p);
}
/*
avr_raise_irq(p->io.irq + IOPORT_IRQ_DIRECTION_ALL, v);
avr_core_watch_write(avr, addr, v);
- const uint8_t oldpin = avr->data[p->r_pin];
- const uint8_t pin = (oldpin & ~v) | (avr->data[p->r_port] & v);
- avr_core_watch_write(avr, p->r_pin, pin);
- for (int i = 0; i < 8; i++)
- if (((oldpin ^ pin) >> i) & 1)
- avr_raise_irq(p->io.irq + i, (pin >> i) & 1);
- avr_raise_irq(p->io.irq + IOPORT_IRQ_PIN_ALL, pin);
+ avr_ioport_update_irqs(p);
}
/*
static void avr_ioport_reset(avr_io_t * port)
{
avr_ioport_t * p = (avr_ioport_t *)port;
- for (int i = 0; i < IOPORT_IRQ_PIN_ALL; i++)
+ for (int i = 0; i < IOPORT_IRQ_PIN_ALL; i++)
avr_irq_register_notify(p->io.irq + i, avr_ioport_irq_notify, p);
}
*((avr_ioport_state_t*)io_param) = state;
res = 0;
}
+ /*
+ * Set the default IRQ values when pin is set as input
+ */
+ if (ctl == AVR_IOCTL_IOPORT_SET_EXTERNAL(p->name)) {
+ avr_ioport_external_t * m = (avr_ioport_external_t*)io_param;
+ p->external.pull_mask = m->mask;
+ p->external.pull_value = m->value;
+ res = 0;
+ }
}
}
// p->name, p->r_pin,
// p->name, p->r_ddr,
// p->name, p->r_port);
-
+
avr_register_io(avr, &p->io);
avr_register_vector(avr, &p->pcint);
// allocate this module's IRQ
// add port name (uppercase) to get the port state
#define AVR_IOCTL_IOPORT_GETSTATE(_name) AVR_IOCTL_DEF('i','o','s',(_name))
+/*
+ * ioctl used to set default port state when set as input.
+ *
+ */
+typedef struct avr_ioport_external_t {
+ unsigned long name : 7,
+ mask : 8, value : 8;
+} avr_ioport_external_t;
+
+// add port name (uppercase) to set default input pin IRQ values
+#define AVR_IOCTL_IOPORT_SET_EXTERNAL(_name) AVR_IOCTL_DEF('i','o','p',(_name))
+
/**
* pin structure
*/
avr_int_vector_t pcint; // PCINT vector
avr_io_addr_t r_pcint; // pcint 8 pins mask
+
+ // this represent the default IRQ value when
+ // the port is set as input.
+ // If the mask is not set, no output value is sent
+ // on the output IRQ. If the mask is set, the specified
+ // value is sent.
+ struct {
+ uint8_t pull_mask, pull_value;
+ } external;
} avr_ioport_t;
void avr_ioport_init(avr_t * avr, avr_ioport_t * port);