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;
}
}
}
-static void avr_adc_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
+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_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_core_watch_write(avr, addr, v);
}
+static void avr_adc_write_adcsrb(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
+{
+ avr_adc_configure_trigger(avr, addr, v, param);
+}
+
static void avr_adc_irq_notify(struct avr_irq_t * irq, uint32_t value, void * param)
{
avr_adc_t * p = (avr_adc_t *)param;
} break;
case ADC_IRQ_IN_TRIGGER: {
if (avr_regbit_get(avr, p->adate)) {
- // start a conversion
+ // 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;
}
// allocate this module's IRQ
avr_io_setirqs(&p->io, AVR_IOCTL_ADC_GETIRQ, ADC_IRQ_COUNT, NULL);
- avr_register_io_write(avr, p->r_adcsra, avr_adc_write, p);
+ avr_register_io_write(avr, p->r_adcsra, avr_adc_write_adcsra, p);
+ avr_register_io_write(avr, p->r_adcsrb, avr_adc_write_adcsrb, p);
avr_register_io_read(avr, p->r_adcl, avr_adc_read_l, p);
avr_register_io_read(avr, p->r_adch, avr_adc_read_h, p);
}