From cbb7a3d8a50a1452d06d5fc39e2f5c7d66188455 Mon Sep 17 00:00:00 2001 From: hovercraft-github Date: Tue, 8 Nov 2016 09:51:43 +0800 Subject: [PATCH] Timers: added support for external clock input via a pin (Tn, TOSC1), a variable frequency for virtual external clock sources including as2 asynchronous clock, IO control for selecting external clock source and frequency, external clock pin definition for most cores. --- Makefile.common | 2 +- simavr/cores/sim_90usb162.c | 6 +- simavr/cores/sim_mega128.c | 9 +- simavr/cores/sim_mega1280.c | 15 +- simavr/cores/sim_mega1281.c | 10 +- simavr/cores/sim_mega128rfa1.c | 9 +- simavr/cores/sim_mega128rfr2.c | 9 +- simavr/cores/sim_mega169.c | 9 +- simavr/cores/sim_mega2560.c | 15 +- simavr/cores/sim_megax4.h | 9 +- simavr/cores/sim_megax8.h | 6 +- simavr/cores/sim_megaxm1.h | 6 +- simavr/cores/sim_tiny2313.c | 6 +- simavr/cores/sim_tinyx4.h | 6 +- simavr/sim/avr_timer.c | 378 +++++++++++++++++++++++++++------ simavr/sim/avr_timer.h | 24 ++- 16 files changed, 416 insertions(+), 103 deletions(-) diff --git a/Makefile.common b/Makefile.common index e7cee3d..edbd49c 100644 --- a/Makefile.common +++ b/Makefile.common @@ -120,7 +120,7 @@ SHELL := ${shell which bash} OBJ := obj-${shell $(CC) -dumpmachine} LIBDIR := ${shell pwd}/${SIMAVR}/${OBJ} -LDFLAGS += -L${LIBDIR} -lsimavr +LDFLAGS += -L${LIBDIR} -lsimavr -lm LDFLAGS += -lelf diff --git a/simavr/cores/sim_90usb162.c b/simavr/cores/sim_90usb162.c index 574c2ec..bfc05d4 100644 --- a/simavr/cores/sim_90usb162.c +++ b/simavr/cores/sim_90usb162.c @@ -133,7 +133,8 @@ const struct mcu_t { [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 */ }, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 7), /* External clock pin */ .r_tcnt = TCNT0, @@ -181,7 +182,8 @@ const struct mcu_t { [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 */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTB, 4), /* External clock pin */ .r_tcnt = TCNT1L, .r_tcnth = TCNT1H, diff --git a/simavr/cores/sim_mega128.c b/simavr/cores/sim_mega128.c index ea48aec..0570c64 100644 --- a/simavr/cores/sim_mega128.c +++ b/simavr/cores/sim_mega128.c @@ -253,7 +253,8 @@ const struct mcu_t { [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 */ /* TODO: 2 External clocks */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 6), /* External clock pin */ .r_tcnt = TCNT1L, .r_icr = ICR1L, @@ -320,7 +321,8 @@ const struct mcu_t { [3] = AVR_TIMER_WGM_FASTPWM8(), }, .cs = { AVR_IO_REGBIT(TCCR2, CS20), AVR_IO_REGBIT(TCCR2, CS21), AVR_IO_REGBIT(TCCR2, CS22) }, - .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ /* TODO external clock */ }, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 7), /* External clock pin */ .r_tcnt = TCNT2, @@ -364,7 +366,8 @@ const struct mcu_t { [15] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR3B, CS30), AVR_IO_REGBIT(TCCR3B, CS31), AVR_IO_REGBIT(TCCR3B, CS32) }, - .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ /* TODO: 2 External clocks */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTE, 6), /* External clock pin */ .r_tcnt = TCNT3L, .r_icr = ICR3L, diff --git a/simavr/cores/sim_mega1280.c b/simavr/cores/sim_mega1280.c index f5c0cfd..b3353c5 100644 --- a/simavr/cores/sim_mega1280.c +++ b/simavr/cores/sim_mega1280.c @@ -317,7 +317,8 @@ const struct mcu_t { [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 */ }, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 7), /* External clock pin */ .r_tcnt = TCNT0, @@ -369,7 +370,8 @@ const struct mcu_t { [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 */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 7), /* External clock pin */ .r_tcnt = TCNT1L, .r_tcnth = TCNT1H, @@ -494,7 +496,8 @@ const struct mcu_t { [15] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR3B, CS30), AVR_IO_REGBIT(TCCR3B, CS31), AVR_IO_REGBIT(TCCR3B, CS32) }, - .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ /* TODO: 2 External clocks */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTE, 6), /* External clock pin */ .r_tcnt = TCNT3L, .r_icr = ICR3L, @@ -570,7 +573,8 @@ const struct mcu_t { [15] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR4B, CS40), AVR_IO_REGBIT(TCCR4B, CS41), AVR_IO_REGBIT(TCCR4B, CS42) }, - .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ /* External clock T1 is not handled */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTH, 7), /* External clock pin */ .r_tcnt = TCNT4L, .r_tcnth = TCNT4H, @@ -647,7 +651,8 @@ const struct mcu_t { [15] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR5B, CS50), AVR_IO_REGBIT(TCCR5B, CS51), AVR_IO_REGBIT(TCCR5B, CS52) }, - .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ /* External clock T1 is not handled */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTL, 2), /* External clock pin */ .r_tcnt = TCNT5L, .r_tcnth = TCNT5H, diff --git a/simavr/cores/sim_mega1281.c b/simavr/cores/sim_mega1281.c index 866e58d..986e989 100644 --- a/simavr/cores/sim_mega1281.c +++ b/simavr/cores/sim_mega1281.c @@ -225,7 +225,9 @@ const struct mcu_t { [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 */ }, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 7), /* External clock pin */ .r_tcnt = TCNT0, @@ -277,7 +279,8 @@ const struct mcu_t { [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 */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE}, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 6), /* External clock pin */ .r_tcnt = TCNT1L, .r_tcnth = TCNT1H, @@ -402,7 +405,8 @@ const struct mcu_t { [15] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR3B, CS30), AVR_IO_REGBIT(TCCR3B, CS31), AVR_IO_REGBIT(TCCR3B, CS32) }, - .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ /* TODO: 2 External clocks */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTE, 6), /* External clock pin */ .r_tcnt = TCNT3L, .r_icr = ICR3L, diff --git a/simavr/cores/sim_mega128rfa1.c b/simavr/cores/sim_mega128rfa1.c index 6a2937a..8e62fbf 100644 --- a/simavr/cores/sim_mega128rfa1.c +++ b/simavr/cores/sim_mega128rfa1.c @@ -239,7 +239,8 @@ const struct mcu_t { [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 */ }, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 7), /* External clock pin */ .r_tcnt = TCNT0, @@ -291,7 +292,8 @@ const struct mcu_t { [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 */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 6), /* External clock pin */ .r_tcnt = TCNT1L, .r_tcnth = TCNT1H, @@ -416,7 +418,8 @@ const struct mcu_t { [15] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR3B, CS30), AVR_IO_REGBIT(TCCR3B, CS31), AVR_IO_REGBIT(TCCR3B, CS32) }, - .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ /* TODO: 2 External clocks */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTE, 6), /* External clock pin */ .r_tcnt = TCNT3L, .r_icr = ICR3L, diff --git a/simavr/cores/sim_mega128rfr2.c b/simavr/cores/sim_mega128rfr2.c index 0fe0035..62271df 100644 --- a/simavr/cores/sim_mega128rfr2.c +++ b/simavr/cores/sim_mega128rfr2.c @@ -265,7 +265,8 @@ const struct mcu_t { [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 */ }, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 7), /* External clock pin */ .r_tcnt = TCNT0, @@ -317,7 +318,8 @@ const struct mcu_t { [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 */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 6), /* External clock pin */ .r_tcnt = TCNT1L, .r_tcnth = TCNT1H, @@ -442,7 +444,8 @@ const struct mcu_t { [15] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR3B, CS30), AVR_IO_REGBIT(TCCR3B, CS31), AVR_IO_REGBIT(TCCR3B, CS32) }, - .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ /* TODO: 2 External clocks */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTE, 6), /* External clock pin */ .r_tcnt = TCNT3L, .r_icr = ICR3L, diff --git a/simavr/cores/sim_mega169.c b/simavr/cores/sim_mega169.c index 30b387d..4af93a6 100644 --- a/simavr/cores/sim_mega169.c +++ b/simavr/cores/sim_mega169.c @@ -199,7 +199,8 @@ const struct mcu_t { [7] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR0A, CS00), AVR_IO_REGBIT(TCCR0A, CS01), AVR_IO_REGBIT(TCCR0A, CS02) }, - .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ }, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTG, 4), /* External clock pin */ .r_tcnt = TCNT0, @@ -241,7 +242,8 @@ const struct mcu_t { [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 */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTG, 3), /* External clock pin */ .r_tcnt = TCNT1L, .r_tcnth = TCNT1H, @@ -297,8 +299,7 @@ const struct mcu_t { [3] = AVR_TIMER_WGM_FASTPWM8(), }, .cs = { AVR_IO_REGBIT(TCCR2A, CS20), AVR_IO_REGBIT(TCCR2A, CS21), AVR_IO_REGBIT(TCCR2A, CS22) }, - //.cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ }, - .cs_div = { 0, 0, 3 /* 8 */, 5 /* 32 */, 6 /* 64 */, 7 /* 128 */, 8 /* 256 */, 10 /* 1024 */ /* TODO external clock */ }, + .cs_div = { 0, 0, 3 /* 8 */, 5 /* 32 */, 6 /* 64 */, 7 /* 128 */, 8 /* 256 */, 10 /* 1024 */ }, .as2 = AVR_IO_REGBIT(ASSR, AS2), .r_tcnt = TCNT2, .overflow = { diff --git a/simavr/cores/sim_mega2560.c b/simavr/cores/sim_mega2560.c index b295440..c1383a2 100644 --- a/simavr/cores/sim_mega2560.c +++ b/simavr/cores/sim_mega2560.c @@ -319,7 +319,8 @@ const struct mcu_t { [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 */ }, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 7), /* External clock pin */ .r_tcnt = TCNT0, @@ -371,7 +372,8 @@ const struct mcu_t { [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 */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 7), /* External clock pin */ .r_tcnt = TCNT1L, .r_tcnth = TCNT1H, @@ -496,7 +498,8 @@ const struct mcu_t { [15] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR3B, CS30), AVR_IO_REGBIT(TCCR3B, CS31), AVR_IO_REGBIT(TCCR3B, CS32) }, - .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ /* TODO: 2 External clocks */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTE, 6), /* External clock pin */ .r_tcnt = TCNT3L, .r_icr = ICR3L, @@ -572,7 +575,8 @@ const struct mcu_t { [15] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR4B, CS40), AVR_IO_REGBIT(TCCR4B, CS41), AVR_IO_REGBIT(TCCR4B, CS42) }, - .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ /* External clock T1 is not handled */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTH, 7), /* External clock pin */ .r_tcnt = TCNT4L, .r_tcnth = TCNT4H, @@ -649,7 +653,8 @@ const struct mcu_t { [15] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR5B, CS50), AVR_IO_REGBIT(TCCR5B, CS51), AVR_IO_REGBIT(TCCR5B, CS52) }, - .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ /* External clock T1 is not handled */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTL, 2), /* External clock pin */ .r_tcnt = TCNT5L, .r_tcnth = TCNT5H, diff --git a/simavr/cores/sim_megax4.h b/simavr/cores/sim_megax4.h index 2fdef5a..c1b59ec 100644 --- a/simavr/cores/sim_megax4.h +++ b/simavr/cores/sim_megax4.h @@ -252,7 +252,8 @@ const struct mcu_t SIM_CORENAME = { [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 */ }, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTB, 0), /* External clock pin */ .r_tcnt = TCNT0, @@ -303,7 +304,8 @@ const struct mcu_t SIM_CORENAME = { [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 */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTB, 1), /* External clock pin */ .r_tcnt = TCNT1L, .r_tcnth = TCNT1H, @@ -414,7 +416,8 @@ const struct mcu_t SIM_CORENAME = { [15] = AVR_TIMER_WGM_OCPWM(), }, .cs = { AVR_IO_REGBIT(TCCR3B, CS30), AVR_IO_REGBIT(TCCR3B, CS31), AVR_IO_REGBIT(TCCR3B, CS32) }, - .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */ /* External clock T1 is not handled */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 0), /* External clock pin */ .r_tcnt = TCNT3L, .r_tcnth = TCNT3H, diff --git a/simavr/cores/sim_megax8.h b/simavr/cores/sim_megax8.h index d7d08b8..06723ea 100644 --- a/simavr/cores/sim_megax8.h +++ b/simavr/cores/sim_megax8.h @@ -204,7 +204,8 @@ const struct mcu_t SIM_CORENAME = { [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 */ }, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 4), /* External clock pin */ .r_tcnt = TCNT0, @@ -254,7 +255,8 @@ const struct mcu_t SIM_CORENAME = { [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 */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 5), /* External clock pin */ .r_tcnt = TCNT1L, .r_tcnth = TCNT1H, diff --git a/simavr/cores/sim_megaxm1.h b/simavr/cores/sim_megaxm1.h index cebceea..6890fb5 100644 --- a/simavr/cores/sim_megaxm1.h +++ b/simavr/cores/sim_megaxm1.h @@ -217,7 +217,8 @@ const struct mcu_t SIM_CORENAME = { [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 */ }, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTC, 2), /* External clock pin */ .r_tcnt = TCNT0, @@ -265,7 +266,8 @@ const struct mcu_t SIM_CORENAME = { [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 */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTC, 3), /* External clock pin */ .r_tcnt = TCNT1L, .r_tcnth = TCNT1H, diff --git a/simavr/cores/sim_tiny2313.c b/simavr/cores/sim_tiny2313.c index 159612e..43d2543 100644 --- a/simavr/cores/sim_tiny2313.c +++ b/simavr/cores/sim_tiny2313.c @@ -112,7 +112,8 @@ static const struct mcu_t { [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 */ }, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 4), /* External clock pin */ .r_tcnt = TCNT0, @@ -160,7 +161,8 @@ static const struct mcu_t { [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 */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTD, 5), /* External clock pin */ .r_tcnt = TCNT1L, .r_icr = ICR1L, diff --git a/simavr/cores/sim_tinyx4.h b/simavr/cores/sim_tinyx4.h index 879239b..291cce1 100644 --- a/simavr/cores/sim_tinyx4.h +++ b/simavr/cores/sim_tinyx4.h @@ -151,7 +151,8 @@ const struct mcu_t SIM_CORENAME = { [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 */ }, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTA, 3), /* External clock pin */ .r_tcnt = TCNT0, @@ -199,7 +200,8 @@ const struct mcu_t SIM_CORENAME = { [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 */}, + .cs_div = { 0, 0, 3 /* 8 */, 6 /* 64 */, 8 /* 256 */, 10 /* 1024 */, AVR_TIMER_EXTCLK_CHOOSE, AVR_TIMER_EXTCLK_CHOOSE }, + .ext_clock_pin = AVR_IO_REGBIT(PORTA, 4), /* External clock pin */ .r_tcnt = TCNT1L, .r_tcnth = TCNT1H, diff --git a/simavr/sim/avr_timer.c b/simavr/sim/avr_timer.c index fc5e495..f82e096 100644 --- a/simavr/sim/avr_timer.c +++ b/simavr/sim/avr_timer.c @@ -25,6 +25,8 @@ */ #include +#include + #include "avr_timer.h" #include "avr_ioport.h" #include "sim_time.h" @@ -159,6 +161,120 @@ avr_timer_compc( return avr_timer_comp((avr_timer_t*)param, when, AVR_TIMER_COMPC); } +static void +avr_timer_irq_ext_clock( + struct avr_irq_t * irq, + uint32_t value, + void * param) +{ + avr_timer_t * p = (avr_timer_t *)param; + avr_t * avr = p->io.avr; + + if ((p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_VIRT) || !p->tov_top) + return; // we are clocked internally (actually should never come here) + + int bing = 0; + if (p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_EDGE) { // clock on rising edge + if (!irq->value && value) + bing++; + } else { // clock on falling edge + if (irq->value && !value) + bing++; + } + if (!bing) + return; + + //AVR_LOG(avr, LOG_TRACE, "%s Timer%c tick, tcnt=%i\n", __func__, p->name, p->tov_base); + + p->ext_clock_flags |= AVR_TIMER_EXTCLK_FLAG_STARTED; + + static const avr_cycle_timer_t dispatch[AVR_TIMER_COMP_COUNT] = + { avr_timer_compa, avr_timer_compb, avr_timer_compc }; + + int overflow = 0; + /** + * + * Datasheet excerpt (Compare Match Output Unit): + * "The 16-bit comparator continuously compares TCNT1 with the Output Compare Regis- + ter (OCR1x). If TCNT equals OCR1x the comparator signals a match. A match will set + the Output Compare Flag (OCF1x) at the next timer clock cycle. If enabled (OCIE1x = + 1), the Output Compare Flag generates an output compare interrupt." + Thus, comparators should go before incementing the counter to use counter value + from the previous cycle. + */ + for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { + if (p->wgm_op_mode_kind != avr_timer_wgm_ctc) { + if ((p->mode.top == avr_timer_wgm_reg_ocra) && (compi == 0)) + continue; // ocra used to define TOP + } + if (p->comp[compi].comp_cycles && (p->tov_base == p->comp[compi].comp_cycles)) { + dispatch[compi](avr, avr->cycle, param); + if (p->wgm_op_mode_kind == avr_timer_wgm_ctc) + p->tov_base = 0; + } + } + + switch (p->wgm_op_mode_kind) { + case avr_timer_wgm_fc_pwm: // in the avr_timer_write_ocr comment "OCR is not used here" - why? + case avr_timer_wgm_pwm: + if ((p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_REVDIR) != 0) { + --p->tov_base; + if (p->tov_base == 0) { + // overflow occured + p->ext_clock_flags &= ~AVR_TIMER_EXTCLK_FLAG_REVDIR; // restore forward count direction + overflow = 1; + } + } + else { + if (++p->tov_base >= p->tov_top) { + p->ext_clock_flags |= AVR_TIMER_EXTCLK_FLAG_REVDIR; // prepare to count down + } + } + break; + case avr_timer_wgm_fast_pwm: + if (++p->tov_base == p->tov_top) { + overflow = 1; + if (p->mode.top == avr_timer_wgm_reg_icr) + avr_raise_interrupt(avr, &p->icr); + else if (p->mode.top == avr_timer_wgm_reg_ocra) + avr_raise_interrupt(avr, &p->comp[0].interrupt); + } + else if (p->tov_base > p->tov_top) { + p->tov_base = 0; + } + break; + case avr_timer_wgm_ctc: + { + int max = (1 << p->wgm_op[0].size)-1; + if (++p->tov_base > max) { + // overflow occured + p->tov_base = 0; + overflow = 1; + } + } + break; + default: + if (++p->tov_base > p->tov_top) { + // overflow occured + p->tov_base = 0; + overflow = 1; + } + break; + } + + if (overflow) { + for (int compi = 0; compi < AVR_TIMER_COMP_COUNT; compi++) { + if (p->comp[compi].comp_cycles) { + if (p->mode.top == avr_timer_wgm_reg_ocra && compi == 0) + continue; + avr_timer_comp_on_tov(p, 0, compi); + } + } + avr_raise_interrupt(avr, &p->overflow); + } + +} + // timer overflow static avr_cycle_count_t avr_timer_tov( @@ -169,6 +285,19 @@ avr_timer_tov( avr_timer_t * p = (avr_timer_t *)param; int start = p->tov_base == 0; + avr_cycle_count_t next = when; + if (((p->ext_clock_flags & (AVR_TIMER_EXTCLK_FLAG_AS2 | AVR_TIMER_EXTCLK_FLAG_TN)) != 0) + && (p->tov_cycles_fract != 0.0f)) { + p->phase_accumulator += p->tov_cycles_fract; + if (p->phase_accumulator >= 1.0f) { + ++next; + p->phase_accumulator -= 1.0f; + } else if (p->phase_accumulator <= -1.0f) { + --next; + p->phase_accumulator += 1.0f; + } + } + if (!start) avr_raise_interrupt(avr, &p->overflow); p->tov_base = when; @@ -181,14 +310,14 @@ avr_timer_tov( if (p->comp[compi].comp_cycles < p->tov_cycles && p->comp[compi].comp_cycles >= (avr->cycle - when)) { avr_timer_comp_on_tov(p, when, compi); avr_cycle_timer_register(avr, - p->comp[compi].comp_cycles - (avr->cycle - when), + p->comp[compi].comp_cycles - (avr->cycle - next), dispatch[compi], p); } else if (p->tov_cycles == p->comp[compi].comp_cycles && !start) dispatch[compi](avr, when, param); } } - return when + p->tov_cycles; + return next + p->tov_cycles; } static uint16_t @@ -196,10 +325,18 @@ _avr_timer_get_current_tcnt( avr_timer_t * p) { avr_t * avr = p->io.avr; - if (p->tov_cycles) { - uint64_t when = avr->cycle - p->tov_base; + if (!(p->ext_clock_flags & (AVR_TIMER_EXTCLK_FLAG_TN | AVR_TIMER_EXTCLK_FLAG_AS2)) || + (p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_VIRT) + ) { + if (p->tov_cycles) { + uint64_t when = avr->cycle - p->tov_base; - return (when * (((uint32_t)p->tov_top)+1)) / p->tov_cycles; + return (when * (((uint32_t)p->tov_top)+1)) / p->tov_cycles; + } + } + else { + if (p->tov_top) + return p->tov_base; } return 0; } @@ -257,84 +394,160 @@ avr_timer_tcnt_write( if (tcnt >= p->tov_top) tcnt = 0; - - // this involves some magicking - // cancel the current timers, recalculate the "base" we should be at, reset the - // timer base as it should, and re-schedule the timers using that base. - - avr_timer_cancel_all_cycle_timers(avr, p, 0); - uint64_t cycles = (tcnt * p->tov_cycles) / p->tov_top; + if (!(p->ext_clock_flags & (AVR_TIMER_EXTCLK_FLAG_TN | AVR_TIMER_EXTCLK_FLAG_AS2)) || + (p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_VIRT) + ) { + // internal or virtual clock -// printf("%s-%c %d/%d -- cycles %d/%d\n", __FUNCTION__, p->name, tcnt, p->tov_top, (uint32_t)cycles, (uint32_t)p->tov_cycles); + // this involves some magicking + // cancel the current timers, recalculate the "base" we should be at, reset the + // timer base as it should, and re-schedule the timers using that base. - // this reset the timers bases to the new base - if (p->tov_cycles > 1) { - avr_cycle_timer_register(avr, p->tov_cycles - cycles, avr_timer_tov, p); - p->tov_base = 0; - avr_timer_tov(avr, avr->cycle - cycles, p); - } + avr_timer_cancel_all_cycle_timers(avr, p, 0); + + uint64_t cycles = (tcnt * p->tov_cycles) / p->tov_top; + + // printf("%s-%c %d/%d -- cycles %d/%d\n", __FUNCTION__, p->name, tcnt, p->tov_top, (uint32_t)cycles, (uint32_t)p->tov_cycles); + + // this reset the timers bases to the new base + if (p->tov_cycles > 1) { + avr_cycle_timer_register(avr, p->tov_cycles - cycles, avr_timer_tov, p); + p->tov_base = 0; + avr_timer_tov(avr, avr->cycle - cycles, p); + } -// tcnt = ((avr->cycle - p->tov_base) * p->tov_top) / p->tov_cycles; -// printf("%s-%c new tnt derive to %d\n", __FUNCTION__, p->name, tcnt); + // tcnt = ((avr->cycle - p->tov_base) * p->tov_top) / p->tov_cycles; + // printf("%s-%c new tnt derive to %d\n", __FUNCTION__, p->name, tcnt); + } + else { + // clocked externally + p->tov_base = tcnt; + } } static void avr_timer_configure( avr_timer_t * p, - uint32_t clock, + uint32_t prescaler, uint32_t top, uint8_t reset) { - p->tov_cycles = 0; p->tov_top = top; - p->tov_cycles = clock * (top+1); + avr_t * avr = p->io.avr; + float resulting_clock = 0.0f; // used only for trace + float tov_cycles_exact; + + uint8_t as2 = p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_AS2; + uint8_t use_ext_clock = as2 || (p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_TN); + uint8_t virt_ext_clock = use_ext_clock && (p->ext_clock_flags & AVR_TIMER_EXTCLK_FLAG_VIRT); + + if (!use_ext_clock) { + if (prescaler != 0) + resulting_clock = (float)avr->frequency / prescaler; + p->tov_cycles = prescaler * (top+1); + p->tov_cycles_fract = 0.0f; + tov_cycles_exact = p->tov_cycles; + } else { + if (!virt_ext_clock) { + p->tov_cycles = 0; + p->tov_cycles_fract = 0.0f; + } else { + if (prescaler != 0) + resulting_clock = p->ext_clock / prescaler; + tov_cycles_exact = (float)avr->frequency / p->ext_clock * prescaler * (top+1); + p->tov_cycles = round(tov_cycles_exact); + p->tov_cycles_fract = tov_cycles_exact - p->tov_cycles; + } + } - AVR_LOG(p->io.avr, LOG_TRACE, "TIMER: %s-%c TOP %.2fHz = %d cycles = %dusec\n", - __FUNCTION__, p->name, (p->io.avr->frequency / (float)p->tov_cycles), - (int)p->tov_cycles, (int)avr_cycles_to_usec(p->io.avr, p->tov_cycles)); + if (p->trace) { + if (!use_ext_clock || virt_ext_clock) { + // clocked internally + AVR_LOG(avr, LOG_TRACE, "TIMER: %s-%c TOP %.2fHz = %d cycles = %dusec\n", // TOP there means Timer Overflows Persec ? + __FUNCTION__, p->name, ((float)avr->frequency / tov_cycles_exact), + (int)p->tov_cycles, (int)avr_cycles_to_usec(avr, p->tov_cycles)); + } else { + // clocked externally from the Tn pin + AVR_LOG(avr, LOG_TRACE, "TIMER: %s-%c use ext clock, TOP=%d\n", + __FUNCTION__, p->name, (int)p->tov_top + ); + } + } 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); - uint32_t comp_cycles = clock * (ocr + 1); + //uint32_t comp_cycles = clock * (ocr + 1); + uint32_t comp_cycles; + if (virt_ext_clock) + comp_cycles = (uint32_t)((float)avr->frequency / p->ext_clock * prescaler * (ocr+1)); + else + comp_cycles = prescaler * (ocr + 1); p->comp[compi].comp_cycles = 0; - if (p->trace & (avr_timer_trace_compa << compi)) - printf("%s-%c clock %f top %d OCR%c %d\n", __FUNCTION__, p->name, - (float)(p->io.avr->frequency / clock), top, 'A'+compi, ocr); - + if (p->trace & (avr_timer_trace_compa << compi)) { + if (!use_ext_clock || virt_ext_clock) { + printf("%s-%c clock %f top %d OCR%c %d\n", __FUNCTION__, p->name, + resulting_clock, top, 'A'+compi, ocr); + } else { + AVR_LOG(avr, LOG_TRACE, "%s timer%c clock via ext pin, TOP=%d OCR%c=%d\n", + __FUNCTION__, p->name, top, 'A'+compi, ocr); + } + } if (ocr && ocr <= top) { - p->comp[compi].comp_cycles = comp_cycles; // avr_hz_to_cycles(p->io.avr, fa); + p->comp[compi].comp_cycles = comp_cycles; if (p->trace & (avr_timer_trace_compa << compi)) printf( "TIMER: %s-%c %c %.2fHz = %d cycles\n", __FUNCTION__, p->name, - 'A'+compi, (float)(p->io.avr->frequency / ocr), - (int)p->comp[compi].comp_cycles); + 'A'+compi, resulting_clock / ocr, + (int)comp_cycles); } } - if (p->tov_cycles > 1) { - if (reset) - { - avr_cycle_timer_register(p->io.avr, p->tov_cycles, avr_timer_tov, p); - // calling it once, with when == 0 tells it to arm the A/B/C timers if needed - p->tov_base = 0; - avr_timer_tov(p->io.avr, p->io.avr->cycle, p); + if (!use_ext_clock || virt_ext_clock) { + if (p->tov_cycles > 1) { + if (reset) { + avr_cycle_timer_register(avr, p->tov_cycles, avr_timer_tov, p); + // calling it once, with when == 0 tells it to arm the A/B/C timers if needed + p->tov_base = 0; + avr_timer_tov(avr, avr->cycle, p); + p->phase_accumulator = 0.0f; + } else { + uint64_t orig_tov_base = p->tov_base; + avr_cycle_timer_register(avr, p->tov_cycles - (avr->cycle - orig_tov_base), avr_timer_tov, p); + // calling it once, with when == 0 tells it to arm the A/B/C timers if needed + p->tov_base = 0; + avr_timer_tov(avr, orig_tov_base, p); + } } - else - { - uint64_t orig_tov_base = p->tov_base; - avr_cycle_timer_register(p->io.avr, p->tov_cycles - (p->io.avr->cycle - orig_tov_base), avr_timer_tov, p); - // calling it once, with when == 0 tells it to arm the A/B/C timers if needed + } else { + if (reset) p->tov_base = 0; - avr_timer_tov(p->io.avr, orig_tov_base, p); + } + + if (reset) { + avr_ioport_getirq_t req = { + .bit = p->ext_clock_pin + }; + if (avr_ioctl(p->io.avr, AVR_IOCTL_IOPORT_GETIRQ_REGBIT, &req) > 0) { + // got an IRQ for the Tn input clock pin + if (use_ext_clock && !virt_ext_clock) { + if (p->trace) + AVR_LOG(p->io.avr, LOG_TRACE, "%s: timer%c connecting T%c pin IRQ %d\n", __FUNCTION__, p->name, p->name, req.irq[0]->irq); + avr_irq_register_notify(req.irq[0], avr_timer_irq_ext_clock, p); + } else { + if (p->trace) + AVR_LOG(p->io.avr, LOG_TRACE, "%s: timer%c disconnecting T%c pin IRQ %d\n", __FUNCTION__, p->name, p->name, req.irq[0]->irq); + avr_irq_unregister_notify(req.irq[0], avr_timer_irq_ext_clock, p); + } } } + } static void @@ -457,14 +670,19 @@ avr_timer_write( return; } - if (new_as2) { - // AVR clock and external 32KHz source does not have - // to be synced. To obtain better simulation results - // p->tov_base type must be float or avr->frequency - // must be multiple of 32768. - p->cs_div_value = (uint32_t)((uint64_t)avr->frequency * (1 << p->cs_div[new_cs]) / 32768); + p->ext_clock_flags &= ~(AVR_TIMER_EXTCLK_FLAG_TN | AVR_TIMER_EXTCLK_FLAG_EDGE + | AVR_TIMER_EXTCLK_FLAG_AS2 | AVR_TIMER_EXTCLK_FLAG_STARTED); + if (p->ext_clock_pin.reg + && (p->cs_div[new_cs] == AVR_TIMER_EXTCLK_CHOOSE)) { + // Special case: external clock source chosen, prescale divider irrelevant. + p->cs_div_value = 1; + p->ext_clock_flags |= AVR_TIMER_EXTCLK_FLAG_TN | (new_cs & AVR_TIMER_EXTCLK_FLAG_EDGE); } else { p->cs_div_value = 1 << p->cs_div[new_cs]; + if (new_as2) { + //p->cs_div_value = (uint32_t)((uint64_t)avr->frequency * (1 << p->cs_div[new_cs]) / 32768); + p->ext_clock_flags |= AVR_TIMER_EXTCLK_FLAG_AS2 | AVR_TIMER_EXTCLK_FLAG_EDGE; + } } /* mode */ @@ -497,7 +715,7 @@ avr_timer_write_pending( cp[compi] = avr_regbit_get(avr, p->comp[compi].interrupt.raised); // write the value - avr_core_watch_write(avr, addr, v); + avr_core_watch_write(avr, addr, v); // clear any interrupts & flags avr_clear_interrupt_if(avr, &p->overflow, ov); @@ -546,12 +764,42 @@ avr_timer_ioctl( avr_timer_t * p = (avr_timer_t *)port; int res = -1; - /* Allow setting individual trace flags */ if (ctl == AVR_IOCTL_TIMER_SET_TRACE(p->name)) { + /* Allow setting individual trace flags */ p->trace = *((uint32_t*)io_param); res = 0; + } else if (ctl == AVR_IOCTL_TIMER_SET_FREQCLK(p->name)) { + float new_freq = *((float*)io_param); + if (new_freq >= 0.0f) { + if (p->as2.reg) { + if (new_freq <= port->avr->frequency/4) { + p->ext_clock = new_freq; + res = 0; + } + } else if (p->ext_clock_pin.reg) { + if (new_freq <= port->avr->frequency/2) { + p->ext_clock = new_freq; + res = 0; + } + } + } + } else if (ctl == AVR_IOCTL_TIMER_SET_VIRTCLK(p->name)) { + uint8_t new_val = *((uint8_t*)io_param); + if (!new_val) { + avr_ioport_getirq_t req_timer_clock_pin = { + .bit = p->ext_clock_pin + }; + if (avr_ioctl(p->io.avr, AVR_IOCTL_IOPORT_GETIRQ_REGBIT, &req_timer_clock_pin) > 0) { + p->ext_clock_flags &= ~AVR_TIMER_EXTCLK_FLAG_VIRT; + res = 0; + } + } else { + p->ext_clock_flags |= AVR_TIMER_EXTCLK_FLAG_VIRT; + res = 0; + } } - + if (res >= 0) + avr_timer_reconfigure(p, 0); // virtual clock: attempt to follow frequency change preserving the phase return res; } @@ -574,8 +822,8 @@ avr_timer_reset( }; if (avr_ioctl(port->avr, AVR_IOCTL_IOPORT_GETIRQ_REGBIT, &req) > 0) { // cool, got an IRQ -// printf("%s-%c COMP%c Connecting PIN IRQ %d\n", -// __func__, p->name, 'A'+compi, req.irq[0]->irq); + //printf("%s-%c COMP%c Connecting PIN IRQ %d\n", + // __func__, p->name, 'A'+compi, req.irq[0]->irq); avr_connect_irq(&port->irq[TIMER_IRQ_OUT_COMP + compi], req.irq[0]); } } @@ -584,9 +832,11 @@ avr_timer_reset( }; if (avr_ioctl(port->avr, AVR_IOCTL_IOPORT_GETIRQ_REGBIT, &req) > 0) { // cool, got an IRQ for the input capture pin -// printf("%s-%c ICP Connecting PIN IRQ %d\n", __func__, p->name, req.irq[0]->irq); + //printf("%s-%c ICP Connecting PIN IRQ %d\n", __func__, p->name, req.irq[0]->irq); avr_irq_register_notify(req.irq[0], avr_timer_irq_icp, p); } + p->ext_clock_flags &= ~(AVR_TIMER_EXTCLK_FLAG_STARTED | AVR_TIMER_EXTCLK_FLAG_TN | + AVR_TIMER_EXTCLK_FLAG_AS2 | AVR_TIMER_EXTCLK_FLAG_REVDIR); } @@ -675,4 +925,12 @@ avr_timer_init( } 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); + + if (p->as2.reg) { + p->ext_clock_flags = AVR_TIMER_EXTCLK_FLAG_VIRT; + p->ext_clock = 32768.0f; + } else { + p->ext_clock_flags = 0; + p->ext_clock = 0.0f; + } } diff --git a/simavr/sim/avr_timer.h b/simavr/sim/avr_timer.h index 0b64207..16c4636 100644 --- a/simavr/sim/avr_timer.h +++ b/simavr/sim/avr_timer.h @@ -49,6 +49,10 @@ enum { // add timer number/name (character) to set tracing flags #define AVR_IOCTL_TIMER_SET_TRACE(_number) AVR_IOCTL_DEF('t','m','t',(_number)) +// enforce using virtual clock generator when external clock is chosen by firmware +#define AVR_IOCTL_TIMER_SET_VIRTCLK(_number) AVR_IOCTL_DEF('t','m','v',(_number)) +// set frequency of the virtual clock generator +#define AVR_IOCTL_TIMER_SET_FREQCLK(_number) AVR_IOCTL_DEF('t','m','f',(_number)) // Waveform generation modes enum { @@ -79,6 +83,14 @@ typedef struct avr_timer_wgm_t { uint32_t top: 8, bottom: 8, size : 8, kind : 8; } avr_timer_wgm_t; +#define AVR_TIMER_EXTCLK_CHOOSE 0x80 // marker value for cs_div specifying ext clock selection +#define AVR_TIMER_EXTCLK_FLAG_TN 0x80 // Tn external clock chosen +#define AVR_TIMER_EXTCLK_FLAG_STARTED 0x40 // peripheral started +#define AVR_TIMER_EXTCLK_FLAG_REVDIR 0x20 // reverse counting (decrement) +#define AVR_TIMER_EXTCLK_FLAG_AS2 0x10 // asynchronous external clock chosen +#define AVR_TIMER_EXTCLK_FLAG_VIRT 0x08 // don't use the input pin, generate clock internally +#define AVR_TIMER_EXTCLK_FLAG_EDGE 0x01 // use the rising edge + #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, .top = avr_timer_wgm_reg_ocra } @@ -128,10 +140,14 @@ typedef struct avr_timer_t { uint32_t wgm_op_mode_size; avr_regbit_t as2; // asynchronous clock 32khz - avr_regbit_t cs[4]; - uint8_t cs_div[16]; + avr_regbit_t cs[4]; // specify control register bits choosing clock sourcre + uint8_t cs_div[16]; // translate control register value to clock prescaler (orders of 2 exponent) uint32_t cs_div_value; + avr_regbit_t ext_clock_pin; // external clock input pin, to link IRQs + uint8_t ext_clock_flags; // holds AVR_TIMER_EXTCLK_FLAG_ON, AVR_TIMER_EXTCLK_FLAG_EDGE and other ext. clock mode flags + float ext_clock; // external clock frequency, e.g. 32768Hz + avr_regbit_t icp; // input capture pin, to link IRQs avr_regbit_t ices; // input capture edge select @@ -141,7 +157,9 @@ typedef struct avr_timer_t { avr_int_vector_t icr; // input capture uint64_t tov_cycles; // number of cycles from zero to overflow - uint64_t tov_base; // when we last were called + float tov_cycles_fract; // fractional part for external clock with non int ratio to F_CPU + float phase_accumulator; + uint64_t tov_base; // MCU cycle when the last overflow occured; when clocked externally holds external clock count uint16_t tov_top; // current top value to calculate tnct } avr_timer_t; -- 2.39.5