timer: Reconfigure the timer in fast pwm mode
[simavr] / simavr / sim / avr_timer.c
index b01b76f..7606c41 100644 (file)
@@ -6,7 +6,7 @@
        + CDC
        + Fast PWM
 
-       Copyright 2008, 2009 Michel Pollet <buserror@gmail.com>
+       Copyright 2008-2012 Michel Pollet <buserror@gmail.com>
 
        This file is part of simavr.
 
@@ -62,7 +62,7 @@ static avr_cycle_count_t avr_timer_comp(avr_timer_t *p, avr_cycle_count_t when,
                case avr_timer_com_toggle: // Toggle OCnA on compare match
                        if (p->comp[comp].com_pin.reg)  // we got a physical pin
                                avr_raise_irq(irq,
-                                               0x100 + (avr_regbit_get(avr, p->comp[comp].com_pin) ? 0 : 1));
+                                               AVR_IOPORT_OUTPUT | (avr_regbit_get(avr, p->comp[comp].com_pin) ? 0 : 1));
                        else // no pin, toggle the IRQ anyway
                                avr_raise_irq(irq,
                                                p->io.irq[TIMER_IRQ_OUT_COMP + comp].value ? 0 : 1);
@@ -75,8 +75,9 @@ static avr_cycle_count_t avr_timer_comp(avr_timer_t *p, avr_cycle_count_t when,
                        break;
        }
 
-       return p->tov_cycles ? 0 : p->comp[comp].comp_cycles ? when
-               + p->comp[comp].comp_cycles : 0;
+       return p->tov_cycles ? 0 :
+                               p->comp[comp].comp_cycles ?
+                                               when + p->comp[comp].comp_cycles : 0;
 }
 
 static avr_cycle_count_t avr_timer_compa(struct avr_t * avr, avr_cycle_count_t when, void * param)
@@ -94,6 +95,7 @@ static avr_cycle_count_t avr_timer_compc(struct avr_t * avr, avr_cycle_count_t w
        return avr_timer_comp((avr_timer_t*)param, when, AVR_TIMER_COMPC);
 }
 
+// timer overflow
 static avr_cycle_count_t avr_timer_tov(struct avr_t * avr, avr_cycle_count_t when, void * param)
 {
        avr_timer_t * p = (avr_timer_t *)param;
@@ -188,18 +190,23 @@ static void avr_timer_configure(avr_timer_t * p, uint32_t clock, uint32_t top)
        p->tov_top = top;
 
        p->tov_cycles = frequency / t; // avr_hz_to_cycles(frequency, t);
-       printf("%s-%c TOP %.2fHz = %d cycles\n", __FUNCTION__, p->name, t, (int)p->tov_cycles);
+
+       if (p->trace_flags)
+               printf("%s-%c TOP %.2fHz = %d cycles\n", __FUNCTION__, p->name, t, (int)p->tov_cycles);
 
        for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) {
+               if (!p->comp[compi].r_ocr)
+                       continue;
                uint32_t ocr = _timer_get_ocr(p, compi);
                float fc = clock / (float)(ocr+1);
 
                p->comp[compi].comp_cycles = 0;
-//             printf("%s-%c clock %d top %d OCR%c %d\n", __FUNCTION__, p->name, clock, top, 'A'+compi, ocr);
+       //      printf("%s-%c clock %d top %d OCR%c %d\n", __FUNCTION__, p->name, clock, top, 'A'+compi, ocr);
 
                if (ocr && ocr <= top) {
                        p->comp[compi].comp_cycles = frequency / fc; // avr_hz_to_cycles(p->io.avr, fa);
-                       printf("%s-%c %c %.2fHz = %d cycles\n", __FUNCTION__, p->name,
+                       if (p->trace_flags /*& (1 << compi)*/)
+                               printf("%s-%c %c %.2fHz = %d cycles\n", __FUNCTION__, p->name,
                                        'A'+compi, fc, (int)p->comp[compi].comp_cycles);
                }
        }
@@ -251,6 +258,9 @@ static void avr_timer_reconfigure(avr_timer_t * p)
                case avr_timer_wgm_normal:
                        avr_timer_configure(p, f, (1 << p->mode.size) - 1);
                        break;
+               case avr_timer_wgm_fc_pwm:
+                       avr_timer_configure(p, f, (1 << p->mode.size) - 1);
+                       break;
                case avr_timer_wgm_ctc: {
                        avr_timer_configure(p, f, _timer_get_ocr(p, AVR_TIMER_COMPA));
                }       break;
@@ -262,19 +272,43 @@ static void avr_timer_reconfigure(avr_timer_t * p)
                        avr_timer_configure(p, f, (1 << p->mode.size) - 1);
                        break;
                default:
-                       printf("%s-%c unsupported timer mode wgm=%d (%d)\n", __FUNCTION__, p->name, mode, p->mode.kind);
+                       printf("%s-%c unsupported timer mode wgm=%d (%d)\n", __FUNCTION__, p->name,
+                                       mode, p->mode.kind);
        }       
 }
 
 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;
+
+       /* vheck to see if the OCR values actualy 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;
+               }
+       uint16_t otrace = p->trace_flags;
 
+       if (target != -1) {
+               p->trace_flags = 1 << target;
+       } else {
+               p->trace_flags = 0;
+       }
        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));
@@ -282,14 +316,17 @@ static void avr_timer_write_ocr(struct avr_t * avr, avr_io_addr_t addr, uint8_t
                        }
                        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:
-                       printf("%s-%c mode %d UNSUPORTED\n", __FUNCTION__, p->name, p->mode.kind);
+                       printf("%s-%c mode %d UNSUPPORTED\n", __FUNCTION__, p->name, p->mode.kind);
                        avr_timer_reconfigure(p);
                        break;
        }
+       p->trace_flags = otrace;
 }
 
 static void avr_timer_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param)
@@ -331,11 +368,11 @@ static void avr_timer_write_pending(struct avr_t * avr, avr_io_addr_t addr, uint
        avr_core_watch_write(avr, addr, v);
 
        // clear any interrupts & flags
-       avr_clear_interupt_if(avr, &p->overflow, ov);
-       avr_clear_interupt_if(avr, &p->icr, ic);
+       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_interupt_if(avr, &p->comp[compi].interrupt, cp[compi]);
+               avr_clear_interrupt_if(avr, &p->comp[compi].interrupt, cp[compi]);
 }
 
 static void avr_timer_irq_icp(struct avr_irq_t * irq, uint32_t value, void * param)
@@ -399,9 +436,18 @@ static void avr_timer_reset(avr_io_t * port)
 
 }
 
+static const char * irq_names[TIMER_IRQ_COUNT] = {
+       [TIMER_IRQ_OUT_PWM0] = "8>pwm0",
+       [TIMER_IRQ_OUT_PWM1] = "8>pwm1",
+       [TIMER_IRQ_OUT_COMP + 0] = ">compa",
+       [TIMER_IRQ_OUT_COMP + 1] = ">compb",
+       [TIMER_IRQ_OUT_COMP + 2] = ">compc",
+};
+
 static avr_io_t        _io = {
        .kind = "timer",
        .reset = avr_timer_reset,
+       .irq_names = irq_names,
 };
 
 void avr_timer_init(avr_t * avr, avr_timer_t * p)
@@ -442,4 +488,5 @@ void avr_timer_init(avr_t * avr, avr_timer_t * p)
        }
        avr_register_io_write(avr, p->r_tcnt, avr_timer_tcnt_write, p);
        avr_register_io_read(avr, p->r_tcnt, avr_timer_tcnt_read, p);
+       p->trace_flags = 0xf;
 }