Skip to content

Commit 8e375e0

Browse files
MCUdudefacchinm
authored andcommitted
Use TCB0 instead of TCB3 to generate accurate timing TCB0 is present on all megaAVR-0, tinyAVR-0 and tinyAVR-1 microcontrollers, but TCB3 is only available on ATmega3209/4809. Porting these core files to other hardware will be much easier if fundemental functionality like this 'just works' on simpler hardware too
1 parent 0b4b24f commit 8e375e0

File tree

3 files changed

+63
-45
lines changed

3 files changed

+63
-45
lines changed

cores/arduino/wiring.c

+34-34
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,25 @@
2222

2323
#include "wiring_private.h"
2424

25-
// the prescaler is set so that timerb3 ticks every 64 clock cycles, and the
25+
// the prescaler is set so that timerb0 ticks every 64 clock cycles, and the
2626
// the overflow handler is called every 256 ticks.
27-
volatile uint16_t microseconds_per_timerb3_overflow;
28-
volatile uint16_t microseconds_per_timerb3_tick;
27+
volatile uint16_t microseconds_per_timerb0_overflow;
28+
volatile uint16_t microseconds_per_timerb0_tick;
2929

3030
uint32_t F_CPU_CORRECTED = F_CPU;
3131

32-
// the whole number of milliseconds per timerb3 overflow
32+
// the whole number of milliseconds per timerb0 overflow
3333
uint16_t millis_inc;
3434

35-
// the fractional number of milliseconds per timerb3 overflow
35+
// the fractional number of milliseconds per timerb0 overflow
3636
uint16_t fract_inc;
3737
#define FRACT_MAX (1000)
3838

39-
// whole number of microseconds per timerb3 tick
39+
// whole number of microseconds per timerb0 tick
4040

41-
volatile uint32_t timerb3_overflow_count = 0;
42-
volatile uint32_t timerb3_millis = 0;
43-
static uint16_t timerb3_fract = 0;
41+
volatile uint32_t timerb0_overflow_count = 0;
42+
volatile uint32_t timerb0_millis = 0;
43+
static uint16_t timerb0_fract = 0;
4444

4545
inline uint16_t clockCyclesPerMicrosecondComp(uint32_t clk){
4646
return ( (clk) / 1000000L );
@@ -58,12 +58,12 @@ inline unsigned long microsecondsToClockCycles(unsigned long microseconds){
5858
return ( microseconds * clockCyclesPerMicrosecond() );
5959
}
6060

61-
ISR(TCB3_INT_vect)
61+
ISR(TCB0_INT_vect)
6262
{
6363
// copy these to local variables so they can be stored in registers
6464
// (volatile variables must be read from memory on every access)
65-
uint32_t m = timerb3_millis;
66-
uint16_t f = timerb3_fract;
65+
uint32_t m = timerb0_millis;
66+
uint16_t f = timerb0_fract;
6767

6868
m += millis_inc;
6969
f += fract_inc;
@@ -73,12 +73,12 @@ ISR(TCB3_INT_vect)
7373
m += 1;
7474
}
7575

76-
timerb3_fract = f;
77-
timerb3_millis = m;
78-
timerb3_overflow_count++;
76+
timerb0_fract = f;
77+
timerb0_millis = m;
78+
timerb0_overflow_count++;
7979

8080
/* Clear flag */
81-
TCB3.INTFLAGS = TCB_CAPT_bm;
81+
TCB0.INTFLAGS = TCB_CAPT_bm;
8282
}
8383

8484
unsigned long millis()
@@ -89,7 +89,7 @@ unsigned long millis()
8989
// inconsistent value (e.g. in the middle of a write to timer0_millis)
9090
uint8_t status = SREG;
9191
cli();
92-
m = timerb3_millis;
92+
m = timerb0_millis;
9393

9494
SREG = status;
9595

@@ -105,22 +105,22 @@ unsigned long micros() {
105105
cli();
106106

107107
/* Get current number of overflows and timer count */
108-
overflows = timerb3_overflow_count;
109-
ticks = TCB3.CNTL;
108+
overflows = timerb0_overflow_count;
109+
ticks = TCB0.CNTL;
110110

111111
/* If the timer overflow flag is raised, we just missed it,
112112
increment to account for it, & read new ticks */
113-
if(TCB3.INTFLAGS & TCB_CAPT_bm){
113+
if(TCB0.INTFLAGS & TCB_CAPT_bm){
114114
overflows++;
115-
ticks = TCB3.CNTL;
115+
ticks = TCB0.CNTL;
116116
}
117117

118118
/* Restore state */
119119
SREG = status;
120120

121121
/* Return microseconds of up time (resets every ~70mins) */
122-
microseconds = ((overflows * microseconds_per_timerb3_overflow)
123-
+ (ticks * microseconds_per_timerb3_tick));
122+
microseconds = ((overflows * microseconds_per_timerb0_overflow)
123+
+ (ticks * microseconds_per_timerb0_tick));
124124
return microseconds;
125125
}
126126

@@ -355,31 +355,31 @@ void init()
355355

356356
setup_timers();
357357

358-
/********************* TCB3 for system time tracking **************************/
358+
/********************* TCB0 for system time tracking **************************/
359359

360360
/* Calculate relevant time tracking values */
361-
microseconds_per_timerb3_overflow = clockCyclesToMicroseconds(TIME_TRACKING_CYCLES_PER_OVF);
362-
microseconds_per_timerb3_tick = microseconds_per_timerb3_overflow/TIME_TRACKING_TIMER_PERIOD;
361+
microseconds_per_timerb0_overflow = clockCyclesToMicroseconds(TIME_TRACKING_CYCLES_PER_OVF);
362+
microseconds_per_timerb0_tick = microseconds_per_timerb0_overflow/TIME_TRACKING_TIMER_PERIOD;
363363

364-
millis_inc = microseconds_per_timerb3_overflow / 1000;
365-
fract_inc = ((microseconds_per_timerb3_overflow % 1000));
364+
millis_inc = microseconds_per_timerb0_overflow / 1000;
365+
fract_inc = ((microseconds_per_timerb0_overflow % 1000));
366366

367367
/* Default Periodic Interrupt Mode */
368368
/* TOP value for overflow every 1024 clock cycles */
369-
TCB3.CCMP = TIME_TRACKING_TIMER_PERIOD;
369+
TCB0.CCMP = TIME_TRACKING_TIMER_PERIOD;
370370

371-
/* Enable TCB3 interrupt */
372-
TCB3.INTCTRL |= TCB_CAPT_bm;
371+
/* Enable TCB0 interrupt */
372+
TCB0.INTCTRL |= TCB_CAPT_bm;
373373

374374
/* Clock selection -> same as TCA (F_CPU/64 -- 250kHz) */
375-
TCB3.CTRLA = TCB_CLKSEL_CLKTCA_gc;
375+
TCB0.CTRLA = TCB_CLKSEL_CLKTCA_gc;
376376

377377
/* Enable & start */
378-
TCB3.CTRLA |= TCB_ENABLE_bm; /* Keep this last before enabling interrupts to ensure tracking as accurate as possible */
378+
TCB0.CTRLA |= TCB_ENABLE_bm; /* Keep this last before enabling interrupts to ensure tracking as accurate as possible */
379379

380380
/*************************** ENABLE GLOBAL INTERRUPTS *************************/
381381

382382
sei();
383383
}
384384

385-
void setup_timers(void) __attribute__((weak));
385+
void setup_timers(void) __attribute__((weak));

variants/uno2018/pins_arduino.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ const uint8_t PROGMEM digital_pin_to_timer[] = {
309309
NOT_ON_TIMER, // 8 PE3
310310
TIMERA0, // 9 PB0
311311
TIMERA0, // 10 PB1
312-
TIMERB2, // 11 PE0
312+
NOT_ON_TIMER, // 11 PE0
313313
NOT_ON_TIMER, // 12 PE1
314314
NOT_ON_TIMER, // 13 PE2
315315
NOT_ON_TIMER, // 14 PD0/AI0

variants/uno2018/variant.c

+28-10
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,35 @@ void setup_timers() {
2626
/* Use DIV64 prescaler (giving 250kHz clock), enable TCA timer */
2727
TCA0.SINGLE.CTRLA = (TCA_SINGLE_CLKSEL_DIV64_gc) | (TCA_SINGLE_ENABLE_bm);
2828

29-
3029
/* TYPE B TIMERS */
31-
32-
/* PORTMUX alternate location needed for TCB0 & 1, TCB2 is default location */
33-
PORTMUX.TCBROUTEA |= (PORTMUX_TCB0_bm | PORTMUX_TCB1_bm);
34-
35-
/* Start with TCB0 */
30+
31+
// Setup TCB0 routing
32+
#if defined(TCB0)
33+
PORTMUX.TCBROUTEA |= PORTMUX_TCB0_bm; // Route signal to PF4
34+
#endif
35+
36+
// Setup TCB1 routing
37+
#if defined(TCB1)
38+
PORTMUX.TCBROUTEA |= PORTMUX_TCB1_bm; // Route signal to PF5
39+
#endif
40+
41+
// Start with TCB0
3642
TCB_t *timer_B = (TCB_t *)&TCB0;
37-
38-
/* Timer B Setup loop for TCB[0:2] */
39-
do{
43+
44+
// Find end timer
45+
#if defined(TCB3)
46+
TCB_t *timer_B_end = (TCB_t *)&TCB3;
47+
#elif defined(TCB2)
48+
TCB_t *timer_B_end = (TCB_t *)&TCB2;
49+
#elif defined(TCB1)
50+
TCB_t *timer_B_end = (TCB_t *)&TCB1;
51+
#else
52+
TCB_t *timer_B_end = (TCB_t *)&TCB0;
53+
#endif
54+
55+
/* Timer B Setup loop for TCB[0:3] */
56+
do
57+
{
4058
/* 8 bit PWM mode, but do not enable output yet, will do in analogWrite() */
4159
timer_B->CTRLB = (TCB_CNTMODE_PWM8_gc);
4260

@@ -56,7 +74,7 @@ void setup_timers() {
5674
timer_B++;
5775

5876
/* Stop when pointing to TCB3 */
59-
} while (timer_B < (TCB_t *)&TCB3);
77+
} while (timer_B <= timer_B_end);
6078

6179
/* Stuff for synchronizing PWM timers */
6280
// /* Restart TCA to sync TCBs */

0 commit comments

Comments
 (0)