Skip to content

Commit 28ea145

Browse files
committed
Safer PWM_PRESCALER and fix up some dox
1 parent 5330f22 commit 28ea145

File tree

2 files changed

+29
-9
lines changed

2 files changed

+29
-9
lines changed

ledpwm.cpp

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,14 @@
2525
void setup_ledpwm() {
2626
cli();
2727
// Clear registers
28+
TCCR2B = 0; // ensure the timer starts disabled. We call enable_ledpwm() at the end
2829
TCCR2A = 0;
29-
TCCR2B = 0;
3030

3131
// The correct formula here is (F_CPU / ((OCR2A+1)*PRESCALER)) - google why
3232
OCR2A = PWM_OVERFLOW_VALUE - 1; // 24 for 10kHz with prescaler 64, 199 for 10kHz with prescaler 8
33-
OCR2B = PWM_DUTY_VALUE; // duty cycle 10% of OCR2A
33+
OCR2B = PWM_DUTY_VALUE; // duty cycle, usually ~10% of OCR2A
3434

35-
// CTC
35+
// CTC mode
3636
TCCR2A = (1 << WGM21);
3737

3838
// Output Compare Match A & B Interrupt Enable
@@ -46,19 +46,35 @@ void setup_ledpwm() {
4646
sei();
4747
}
4848

49+
/*
50+
* disable the timer entirely, then make sure the lights are off.
51+
*
52+
* *NOTE* this also disables the sampler and end-of-frame flag, so calling this
53+
* is not recommended unless you're doing your own loop outside of the main loop.
54+
*/
4955
void disable_ledpwm() {
50-
// disable the timer entirely, then make sure the lights are off.
56+
cli();
5157
TCCR2B = 0;
5258
PORTB = 0;
59+
sei();
5360
}
5461

62+
/*
63+
* enable the pwm interrupt timer.
64+
*
65+
* Starts the timer at an offset so that PWM interrupts don't coincide with other interrupts.
66+
* Without this, sometimes we get unstable PWM when interrupts pile up.
67+
*/
5568
void enable_ledpwm() {
56-
// start at an offset so that PWM interrupts don't coincide with Sampler interrupts
57-
// Without this, sometimes we get unstable PWM when interrupts pile up.
58-
TCNT2 = 70;
69+
TCNT2 = PWM_STARTING_OFFSET;
5970

60-
TCCR2B = (1 << CS21); // re-enable the timer (with pre-scaler 8) - change PWM_PRESCALER if you change this
61-
// TCCR2B = (1 << CS22); // re-enable the timer (with pre-scaler 64) - change PWM_PRESCALER if you change this
71+
#if (PWM_PRESCALER == 8)
72+
TCCR2B = (1 << CS21); // enable the timer (with pre-scaler 8)
73+
#elif (PWM_PRESCALER == 64)
74+
TCCR2B = (1 << CS22); // enable the timer (with pre-scaler 64)
75+
#else
76+
# error PWM_PRESCALER must be 8 or 64
77+
#endif
6278
}
6379

6480
/*

pwm_constants.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
// e.g. at 16MHz and 10% duty, this will be 180. At 20Mhz, 225. At 8MHz, 90.
3333
#define PWM_DUTY_VALUE (PWM_OVERFLOW_VALUE - (PWM_OVERFLOW_VALUE / (100 / PWM_DUTY_PERCENT)))
3434

35+
// starts the timer at an offset so that PWM interrupts don't coincide with other interrupts.
36+
// offset should not be between PWM_DUTY_VALUE and PWM_OVERFLOW_VALUE, and preferably quite far from them
37+
#define PWM_STARTING_OFFSET (PWM_DUTY_VALUE / 2)
38+
3539
/* definition to expand macro then apply to pragma message */
3640
/* from https://stackoverflow.com/questions/1562074/how-do-i-show-the-value-of-a-define-at-compile-time */
3741
#define VALUE_TO_STRING(x) #x

0 commit comments

Comments
 (0)