From 358619f222d2a3610168eb34a0db2c4b09e4e618 Mon Sep 17 00:00:00 2001 From: Michel Pollet Date: Tue, 22 Dec 2009 16:24:35 +0000 Subject: [PATCH] timer: Implemented some of the ICR based timers Also made a PWM and a Fast PWM mode. Fast pwm doesm't use the interrupts, as most of the time it's never used. Aldo it kills performanves when calling a timer every 400 cycles. Signed-off-by: Michel Pollet --- simavr/cores/sim_megax4.h | 20 +++++++------ simavr/cores/sim_megax8.h | 20 +++++++------ simavr/cores/sim_tiny13.c | 4 +-- simavr/cores/sim_tiny2313.c | 16 +++++++---- simavr/cores/sim_tinyx5.h | 4 +-- simavr/sim/avr_timer.c | 57 ++++++++++++++++++++++++++++++------- simavr/sim/avr_timer.h | 16 +++++++++-- 7 files changed, 98 insertions(+), 39 deletions(-) diff --git a/simavr/cores/sim_megax4.h b/simavr/cores/sim_megax4.h index f851097..1b25257 100644 --- a/simavr/cores/sim_megax4.h +++ b/simavr/cores/sim_megax4.h @@ -197,8 +197,8 @@ struct mcu_t SIM_CORENAME = { .wgm_op = { [0] = AVR_TIMER_WGM_NORMAL8(), [2] = AVR_TIMER_WGM_CTC(), - [3] = AVR_TIMER_WGM_FASTPWM(), - [7] = AVR_TIMER_WGM_FASTPWM(), + [3] = AVR_TIMER_WGM_FASTPWM8(), + [7] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR0B, CS00), AVR_IO_REGBIT(TCCR0B, CS01), AVR_IO_REGBIT(TCCR0B, CS02) }, .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ }, @@ -231,9 +231,12 @@ struct mcu_t SIM_CORENAME = { .wgm_op = { [0] = AVR_TIMER_WGM_NORMAL16(), [4] = AVR_TIMER_WGM_CTC(), - [5] = AVR_TIMER_WGM_FASTPWM(), - [6] = AVR_TIMER_WGM_FASTPWM(), - [7] = AVR_TIMER_WGM_FASTPWM(), + [5] = AVR_TIMER_WGM_FASTPWM8(), + [6] = AVR_TIMER_WGM_FASTPWM9(), + [7] = AVR_TIMER_WGM_FASTPWM10(), + [12] = AVR_TIMER_WGM_ICCTC(), + [14] = AVR_TIMER_WGM_ICPWM(), + [15] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR1B, CS10), AVR_IO_REGBIT(TCCR1B, CS11), AVR_IO_REGBIT(TCCR1B, CS12) }, .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ /* External clock T1 is not handled */}, @@ -241,7 +244,8 @@ struct mcu_t SIM_CORENAME = { .r_ocra = OCR1AL, .r_ocrb = OCR1BL, .r_tcnt = TCNT1L, - + .r_icr = ICR1L, + .r_icrh = ICR1H, .r_ocrah = OCR1AH, // 16 bits timers have two bytes of it .r_ocrbh = OCR1BH, .r_tcnth = TCNT1H, @@ -273,8 +277,8 @@ struct mcu_t SIM_CORENAME = { .wgm_op = { [0] = AVR_TIMER_WGM_NORMAL8(), [2] = AVR_TIMER_WGM_CTC(), - [3] = AVR_TIMER_WGM_FASTPWM(), - [7] = AVR_TIMER_WGM_FASTPWM(), + [3] = AVR_TIMER_WGM_FASTPWM8(), + [7] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR2B, CS20), AVR_IO_REGBIT(TCCR2B, CS21), AVR_IO_REGBIT(TCCR2B, CS22) }, .cs_div = { 0, 0, 3 /* 8 */, 5 /* 32 */, 6 /* 64 */, 7 /* 128 */, 8 /* 256 */, 10 /* 1024 */ }, diff --git a/simavr/cores/sim_megax8.h b/simavr/cores/sim_megax8.h index b18293c..ed2ac02 100644 --- a/simavr/cores/sim_megax8.h +++ b/simavr/cores/sim_megax8.h @@ -161,8 +161,8 @@ struct mcu_t SIM_CORENAME = { .wgm_op = { [0] = AVR_TIMER_WGM_NORMAL8(), [2] = AVR_TIMER_WGM_CTC(), - [3] = AVR_TIMER_WGM_FASTPWM(), - [7] = AVR_TIMER_WGM_FASTPWM(), + [3] = AVR_TIMER_WGM_FASTPWM8(), + [7] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR0B, CS00), AVR_IO_REGBIT(TCCR0B, CS01), AVR_IO_REGBIT(TCCR0B, CS02) }, .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ }, @@ -195,9 +195,12 @@ struct mcu_t SIM_CORENAME = { .wgm_op = { [0] = AVR_TIMER_WGM_NORMAL16(), [4] = AVR_TIMER_WGM_CTC(), - [5] = AVR_TIMER_WGM_FASTPWM(), - [6] = AVR_TIMER_WGM_FASTPWM(), - [7] = AVR_TIMER_WGM_FASTPWM(), + [5] = AVR_TIMER_WGM_FASTPWM8(), + [6] = AVR_TIMER_WGM_FASTPWM9(), + [7] = AVR_TIMER_WGM_FASTPWM10(), + [12] = AVR_TIMER_WGM_ICCTC(), + [14] = AVR_TIMER_WGM_ICPWM(), + [15] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR1B, CS10), AVR_IO_REGBIT(TCCR1B, CS11), AVR_IO_REGBIT(TCCR1B, CS12) }, .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ /* External clock T1 is not handled */}, @@ -205,7 +208,8 @@ struct mcu_t SIM_CORENAME = { .r_ocra = OCR1AL, .r_ocrb = OCR1BL, .r_tcnt = TCNT1L, - + .r_icr = ICR1L, + .r_icrh = ICR1H, .r_ocrah = OCR1AH, // 16 bits timers have two bytes of it .r_ocrbh = OCR1BH, .r_tcnth = TCNT1H, @@ -238,8 +242,8 @@ struct mcu_t SIM_CORENAME = { .wgm_op = { [0] = AVR_TIMER_WGM_NORMAL8(), [2] = AVR_TIMER_WGM_CTC(), - [3] = AVR_TIMER_WGM_FASTPWM(), - [7] = AVR_TIMER_WGM_FASTPWM(), + [3] = AVR_TIMER_WGM_FASTPWM8(), + [7] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR2B, CS20), AVR_IO_REGBIT(TCCR2B, CS21), AVR_IO_REGBIT(TCCR2B, CS22) }, diff --git a/simavr/cores/sim_tiny13.c b/simavr/cores/sim_tiny13.c index 3335c10..d1a936b 100644 --- a/simavr/cores/sim_tiny13.c +++ b/simavr/cores/sim_tiny13.c @@ -75,8 +75,8 @@ static struct mcu_t { .wgm_op = { [0] = AVR_TIMER_WGM_NORMAL8(), [2] = AVR_TIMER_WGM_CTC(), - [3] = AVR_TIMER_WGM_FASTPWM(), - [7] = AVR_TIMER_WGM_FASTPWM(), + [3] = AVR_TIMER_WGM_FASTPWM8(), + [7] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR0B, CS00), AVR_IO_REGBIT(TCCR0B, CS01), AVR_IO_REGBIT(TCCR0B, CS02) }, .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ }, diff --git a/simavr/cores/sim_tiny2313.c b/simavr/cores/sim_tiny2313.c index cead7f0..4bb3288 100644 --- a/simavr/cores/sim_tiny2313.c +++ b/simavr/cores/sim_tiny2313.c @@ -105,8 +105,8 @@ static struct mcu_t { .wgm_op = { [0] = AVR_TIMER_WGM_NORMAL8(), [2] = AVR_TIMER_WGM_CTC(), - [3] = AVR_TIMER_WGM_FASTPWM(), - [7] = AVR_TIMER_WGM_FASTPWM(), + [3] = AVR_TIMER_WGM_FASTPWM8(), + [7] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR0B, CS00), AVR_IO_REGBIT(TCCR0B, CS01), AVR_IO_REGBIT(TCCR0B, CS02) }, .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ }, @@ -139,9 +139,12 @@ static struct mcu_t { .wgm_op = { [0] = AVR_TIMER_WGM_NORMAL16(), [4] = AVR_TIMER_WGM_CTC(), - [5] = AVR_TIMER_WGM_FASTPWM(), - [6] = AVR_TIMER_WGM_FASTPWM(), - [7] = AVR_TIMER_WGM_FASTPWM(), + [5] = AVR_TIMER_WGM_FASTPWM8(), + [6] = AVR_TIMER_WGM_FASTPWM9(), + [7] = AVR_TIMER_WGM_FASTPWM10(), + [12] = AVR_TIMER_WGM_ICCTC(), + [14] = AVR_TIMER_WGM_ICPWM(), + [15] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR1B, CS10), AVR_IO_REGBIT(TCCR1B, CS11), AVR_IO_REGBIT(TCCR1B, CS12) }, .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ /* External clock T1 is not handled */}, @@ -149,7 +152,8 @@ static struct mcu_t { .r_ocra = OCR1AL, .r_ocrb = OCR1BL, .r_tcnt = TCNT1L, - + .r_icr = ICR1L, + .r_icrh = ICR1H, .r_ocrah = OCR1AH, // 16 bits timers have two bytes of it .r_ocrbh = OCR1BH, .r_tcnth = TCNT1H, diff --git a/simavr/cores/sim_tinyx5.h b/simavr/cores/sim_tinyx5.h index 8d42268..9dda7ed 100644 --- a/simavr/cores/sim_tinyx5.h +++ b/simavr/cores/sim_tinyx5.h @@ -108,8 +108,8 @@ struct mcu_t SIM_CORENAME = { .wgm_op = { [0] = AVR_TIMER_WGM_NORMAL8(), [2] = AVR_TIMER_WGM_CTC(), - [3] = AVR_TIMER_WGM_FASTPWM(), - [7] = AVR_TIMER_WGM_FASTPWM(), + [3] = AVR_TIMER_WGM_FASTPWM8(), + [7] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR0B, CS00), AVR_IO_REGBIT(TCCR0B, CS01), AVR_IO_REGBIT(TCCR0B, CS02) }, .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ }, diff --git a/simavr/sim/avr_timer.c b/simavr/sim/avr_timer.c index 4f0ac93..10bf174 100644 --- a/simavr/sim/avr_timer.c +++ b/simavr/sim/avr_timer.c @@ -47,6 +47,11 @@ static uint16_t _timer_get_tcnt(avr_timer_t * p) return p->io.avr->data[p->r_tcnt] | (p->r_tcnth ? (p->io.avr->data[p->r_tcnth] << 8) : 0); } +static uint16_t _timer_get_icr(avr_timer_t * p) +{ + return p->io.avr->data[p->r_icr] | + (p->r_tcnth ? (p->io.avr->data[p->r_icrh] << 8) : 0); +} static avr_cycle_count_t avr_timer_compa(struct avr_t * avr, avr_cycle_count_t when, void * param) { @@ -156,15 +161,15 @@ static void avr_timer_configure(avr_timer_t * p, uint32_t clock, uint32_t top) printf("%s-%c clock %d top %d a %d b %d\n", __FUNCTION__, p->name, clock, top, ocra, ocrb); p->tov_cycles = frequency / t; // avr_hz_to_cycles(frequency, t); - printf("%s-%c TOP %.2fHz = cycles = %d\n", __FUNCTION__, p->name, t, (int)p->tov_cycles); + printf("%s-%c TOP %.2fHz = %d cycles\n", __FUNCTION__, p->name, t, (int)p->tov_cycles); if (ocra && ocra <= top) { p->compa_cycles = frequency / fa; // avr_hz_to_cycles(p->io.avr, fa); - printf("%s-%c A %.2fHz = cycles = %d\n", __FUNCTION__, p->name, fa, (int)p->compa_cycles); + printf("%s-%c A %.2fHz = %d cycles\n", __FUNCTION__, p->name, fa, (int)p->compa_cycles); } if (ocrb && ocrb <= top) { p->compb_cycles = frequency / fb; // avr_hz_to_cycles(p->io.avr, fb); - printf("%s-%c B %.2fHz = cycles = %d\n", __FUNCTION__, p->name, fb, (int)p->compb_cycles); + printf("%s-%c B %.2fHz = %d cycles\n", __FUNCTION__, p->name, fb, (int)p->compb_cycles); } if (p->tov_cycles > 1) { @@ -179,6 +184,8 @@ static void avr_timer_reconfigure(avr_timer_t * p) { avr_t * avr = p->io.avr; + avr_timer_wgm_t zero={0}; + p->mode = zero; // cancel everything p->compa_cycles = 0; p->compb_cycles = 0; @@ -204,23 +211,49 @@ static void avr_timer_reconfigure(avr_timer_t * p) uint8_t cs_div = p->cs_div[cs]; uint32_t f = clock >> cs_div; + p->mode = p->wgm_op[mode]; //printf("%s-%c clock %d, div %d(/%d) = %d ; mode %d\n", __FUNCTION__, p->name, clock, cs, 1 << cs_div, f, mode); - switch (p->wgm_op[mode].kind) { + switch (p->mode.kind) { case avr_timer_wgm_normal: - avr_timer_configure(p, f, (1 << p->wgm_op[mode].size) - 1); + avr_timer_configure(p, f, (1 << p->mode.size) - 1); break; case avr_timer_wgm_ctc: { avr_timer_configure(p, f, _timer_get_ocra(p)); } break; - case avr_timer_wgm_fast_pwm: { - avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocra(p)); - avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocra(p)); + case avr_timer_wgm_pwm: { + uint16_t top = p->mode.top == avr_timer_wgm_reg_ocra ? _timer_get_ocra(p) : _timer_get_icr(p); + avr_timer_configure(p, f, top); } break; + case avr_timer_wgm_fast_pwm: + // 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->wgm_op[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; + avr_core_watch_write(avr, addr, v); + switch (p->mode.kind) { + 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_ocra(p)); + avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocrb(p)); + } + break; + case avr_timer_wgm_fast_pwm: + avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM0, _timer_get_ocra(p)); + avr_raise_irq(p->io.irq + TIMER_IRQ_OUT_PWM1, _timer_get_ocrb(p)); + break; + default: + printf("%s-%c mode %d\n", __FUNCTION__, p->name, p->mode.kind); + avr_timer_reconfigure(p); + break; + } +} + static void avr_timer_write(struct avr_t * avr, avr_io_addr_t addr, uint8_t v, void * param) { avr_timer_t * p = (avr_timer_t *)param; @@ -246,7 +279,7 @@ static avr_io_t _io = { void avr_timer_init(avr_t * avr, avr_timer_t * p) { p->io = _io; - printf("%s timer%c created OCRA %02x OCRAH %02x\n", __FUNCTION__, p->name, p->r_ocra, p->r_ocrah); + //printf("%s timer%c created\n", __FUNCTION__, p->name); // allocate this module's IRQ p->io.irq_count = TIMER_IRQ_COUNT; @@ -258,6 +291,8 @@ void avr_timer_init(avr_t * avr, avr_timer_t * p) avr_register_io(avr, &p->io); avr_register_vector(avr, &p->compa); avr_register_vector(avr, &p->compb); + avr_register_vector(avr, &p->overflow); + avr_register_vector(avr, &p->icr); avr_register_io_write(avr, p->cs[0].reg, avr_timer_write, p); @@ -266,7 +301,7 @@ void avr_timer_init(avr_t * avr, avr_timer_t * p) * high bytes because the datasheet says that the low address is always * the trigger. */ - avr_register_io_write(avr, p->r_ocra, avr_timer_write, p); + avr_register_io_write(avr, p->r_ocra, avr_timer_write_ocr, p); avr_register_io_write(avr, p->r_ocrb, avr_timer_write, p); avr_register_io_write(avr, p->r_tcnt, avr_timer_tcnt_write, p); diff --git a/simavr/sim/avr_timer.h b/simavr/sim/avr_timer.h index d863532..3d0b575 100644 --- a/simavr/sim/avr_timer.h +++ b/simavr/sim/avr_timer.h @@ -37,16 +37,27 @@ enum { avr_timer_wgm_none = 0, // invalid mode avr_timer_wgm_normal, avr_timer_wgm_ctc, + avr_timer_wgm_pwm, avr_timer_wgm_fast_pwm, }; +enum { + avr_timer_wgm_reg_constant = 0, + avr_timer_wgm_reg_ocra, + avr_timer_wgm_reg_icr, +}; typedef struct avr_timer_wgm_t { uint32_t top: 8, bottom: 8, size : 8, kind : 8; } avr_timer_wgm_t; #define AVR_TIMER_WGM_NORMAL8() { .kind = avr_timer_wgm_normal, .size=8 } #define AVR_TIMER_WGM_NORMAL16() { .kind = avr_timer_wgm_normal, .size=16 } -#define AVR_TIMER_WGM_CTC() { .kind = avr_timer_wgm_ctc } -#define AVR_TIMER_WGM_FASTPWM() { .kind = avr_timer_wgm_fast_pwm } +#define AVR_TIMER_WGM_CTC() { .kind = avr_timer_wgm_ctc, .top = avr_timer_wgm_reg_ocra } +#define AVR_TIMER_WGM_ICCTC() { .kind = avr_timer_wgm_ctc, .top = avr_timer_wgm_reg_icr } +#define AVR_TIMER_WGM_FASTPWM8() { .kind = avr_timer_wgm_fast_pwm, .size=8 } +#define AVR_TIMER_WGM_FASTPWM9() { .kind = avr_timer_wgm_fast_pwm, .size=9 } +#define AVR_TIMER_WGM_FASTPWM10() { .kind = avr_timer_wgm_fast_pwm, .size=10 } +#define AVR_TIMER_WGM_OCPWM() { .kind = avr_timer_wgm_pwm, .top = avr_timer_wgm_reg_ocra } +#define AVR_TIMER_WGM_ICPWM() { .kind = avr_timer_wgm_pwm, .top = avr_timer_wgm_reg_icr } typedef struct avr_timer_t { avr_io_t io; @@ -68,6 +79,7 @@ typedef struct avr_timer_t { avr_int_vector_t overflow; // overflow avr_int_vector_t icr; // input capture + avr_timer_wgm_t mode; uint64_t compa_cycles; uint64_t compb_cycles; uint64_t tov_cycles; -- 2.39.5