Commit 70cd616a05fe8333827d569cd5843c81105b8559
authorcskarai <cskarai@freemail.hu>
Tue, 6 Jan 2015 21:13:40 +0000 (22:13 +0100)
committercskarai <cskarai@freemail.hu>
Tue, 6 Jan 2015 21:13:40 +0000 (22:13 +0100)
2 files changed:
simavr/sim/avr_adc.c
simavr/sim/avr_adc.h

index a88f335679697ae2c67468bb2c0633038b77d230..64fbcd1c30ddf2a3f150e24d203435d262c59292 100644 (file)
@@ -34,6 +34,8 @@ static avr_cycle_count_t avr_adc_int_raise(struct avr_t * avr, avr_cycle_count_t
                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;
 }
@@ -139,8 +141,64 @@ static uint8_t avr_adc_read_h(struct avr_t * avr, avr_io_addr_t addr, void * par
        }
 }
 
-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);
@@ -188,6 +246,11 @@ static void avr_adc_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, voi
        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;
@@ -202,7 +265,18 @@ static void avr_adc_irq_notify(struct avr_irq_t * irq, uint32_t value, void * pa
                }       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;
        }
@@ -257,7 +331,8 @@ void avr_adc_init(avr_t * avr, avr_adc_t * p)
        // 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);
 }
index 4257312e3b56e9705c07b5f310886b5026864f56..91247f2bf8745f45ec59b6d8896719b941e90a42 100644 (file)
@@ -82,7 +82,7 @@ enum {
 
 // ADC trigger sources
 typedef enum {
-       avr_adrs_invalid = 0,
+       avr_adts_none = 0,
        avr_adts_free_running,
        avr_adts_analog_comparator_0,
        avr_adts_analog_comparator_1,
@@ -124,6 +124,7 @@ typedef struct avr_adc_t {
        uint8_t                 r_adcsrb;       // ADC Control and Status Register B
        avr_regbit_t    adts[4];        // Timing Source
        avr_adts_type   adts_op[16];    // ADTS type
+       uint8_t         adts_mode;      // the extracted ADTS mode
        avr_regbit_t    bin;            // Bipolar Input Mode (tinyx5 have it)
        avr_regbit_t    ipr;            // Input Polarity Reversal (tinyx5 have it)