Commit cbb7a3d8a50a1452d06d5fc39e2f5c7d66188455
authorhovercraft-github <hovercraft@yandex.ru>
Tue, 8 Nov 2016 01:51:43 +0000 (09:51 +0800)
committerhovercraft-github <hovercraft@yandex.ru>
Tue, 8 Nov 2016 01:51:43 +0000 (09:51 +0800)
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.

16 files changed:
Makefile.common
simavr/cores/sim_90usb162.c
simavr/cores/sim_mega128.c
simavr/cores/sim_mega1280.c
simavr/cores/sim_mega1281.c
simavr/cores/sim_mega128rfa1.c
simavr/cores/sim_mega128rfr2.c
simavr/cores/sim_mega169.c
simavr/cores/sim_mega2560.c
simavr/cores/sim_megax4.h
simavr/cores/sim_megax8.h
simavr/cores/sim_megaxm1.h
simavr/cores/sim_tiny2313.c
simavr/cores/sim_tinyx4.h
simavr/sim/avr_timer.c
simavr/sim/avr_timer.h

index e7cee3d36c7165ec2e43704df22427720c926ea0..edbd49c96f318c7decb7cc393de3f6e7b58812cb 100644 (file)
@@ -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 
 
index 574c2ec66b6c0b57e7429cd12fc19f0890ff81d9..bfc05d4f4de1ff559faf4e5cd01edd0bd66cbf60 100644 (file)
@@ -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,
index ea48aec17917d76816fed3b56c7956a0716f766f..0570c64b68ee92533754c0bff6a03bf4a8871c5e 100644 (file)
@@ -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,
index f5c0cfd55bca50aeca99d4fb8831b57c3f5901a0..b3353c5ee8a352b63a12bc9305361565548a9854 100644 (file)
@@ -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,
index 866e58d3ba88bf4889cd8c5937d05825ca9bee19..986e989c700421f632a5b5086bda682bc9a46c77 100644 (file)
@@ -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,
index 6a2937adde8391f7e69d34b680b42f1bc9744706..8e62fbfac8e281a50b98a2329c12c165532e74f2 100644 (file)
@@ -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,
index 0fe003506add9d3e0f447fa63948416d652dce8d..62271df5abf2a95ad673665511dfe82ba0ed7ba5 100644 (file)
@@ -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,
index 30b387d3b53776b5f4cd08a5d1c1e8476b25f16a..4af93a6a3b65041d2c569698f305309216a25558 100644 (file)
@@ -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 = {
index b29544052e5b30a1e55752fea1147139bfc2530d..c1383a2385aeb49161cc81df2fc1df89f84bdf8c 100644 (file)
@@ -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,
index 2fdef5aa19e909959e3ab82d02aa0fbeb8e305a5..c1b59ecd492a3d1d9c8cb01a7554511d56f5c811 100644 (file)
@@ -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,
index d7d08b8c0031b131731c54eeba35d77cac058603..06723ea8abbda52fc06283640fa33d71400bbb4d 100644 (file)
@@ -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,
index cebceeaefafdcf9bc117388052f2afe91b58eb40..6890fb50850cf0d5a1ac2e18676a4cecd5520df2 100644 (file)
@@ -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,
index 159612e2f6cd1c8755ad0ee43168513279ab6a16..43d254375bab033399a054d9635b02ed87d718a5 100644 (file)
@@ -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,
index 879239b1e630e1ccf2d4ef278e1b4163522ee816..291cce10946f4e11d584bd1acafb01f7ca7cd924 100644 (file)
@@ -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,
index fc5e4953baaf56a0686927a683faaf545456723d..f82e096e3183187063ce267e580ac520ee9b67de 100644 (file)
@@ -25,6 +25,8 @@
  */
 
 #include <stdio.h>
+#include <math.h>
+
 #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;
+       }
 }
index 0b64207f614deed4febf19765c14e673739ee671..16c4636ea48fb3902ff4743d7aa07300bab4fb73 100644 (file)
@@ -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;