You can get pretty close if you program the Timer 1 directly (not through the library), and have it run with the prescaler set to 1. Ideally, you want the period of the timer in clock cycles to be:
F_CPU / 15 kHz = 16,000 kHz / 15 kHz ≈ 1066.67 CPU cycles
If you round this to the nearest integer, you get
F_CPU / 1,067 = 16,000 kHz / 1,067 ≈ 14.9953 kHz
This is about 0.03% totoo slow, well within the tolerance of the ceramic resonator clocking the Uno.
Here is my attempt at this. TestedI have tested it.
constexpr float PWM_FREQUENCY = 15e3; // 15 kHz
constexpr uint16_t PERIOD = round(F_CPU / PWM_FREQUENCY);
void setup() {
// Configure Timer 1 for 15 kHz PWM on pin 9 = PB1 = OC1A.
DDRB |= _BV(PB1); // set pin as output
TCCR1B = 0; // stop timer
TCCR1A = _BV(COM1A1) // non-inverting PWN on OC1A
| _BV(WGM11); // mode 14: fast PWM, TOP = ICR1
TCCR1B = _BV(WGM12) // ditto
| _BV(WGM13) // ditto
| _BV(CS10); // clock @ F_CPU
ICR1 = PERIOD - 1; // period
OCR1A = PERIOD / 4; // duty cycle
}
void loop(){}
You can get pretty close if you program the Timer 1 directly (not through the library), and have it run with the prescaler set to 1. Ideally, you want the period of the timer in clock cycles to be:
F_CPU / 15 kHz = 16,000 kHz / 15 kHz ≈ 1066.67 CPU cycles
If you round this to the nearest integer, you get
F_CPU / 1,067 = 16,000 kHz / 1,067 ≈ 14.9953 kHz
This is about 0.03% to slow, well within the tolerance of the ceramic resonator clocking the Uno.
Here is my attempt at this. Tested.
constexpr float PWM_FREQUENCY = 15e3; // 15 kHz
constexpr uint16_t PERIOD = round(F_CPU / PWM_FREQUENCY);
void setup() {
// Configure Timer 1 for 15 kHz PWM on pin 9 = PB1 = OC1A.
DDRB |= _BV(PB1); // set pin as output
TCCR1B = 0; // stop timer
TCCR1A = _BV(COM1A1) // non-inverting PWN on OC1A
| _BV(WGM11); // mode 14: fast PWM, TOP = ICR1
TCCR1B = _BV(WGM12) // ditto
| _BV(WGM13) // ditto
| _BV(CS10); // clock @ F_CPU
ICR1 = PERIOD - 1; // period
OCR1A = PERIOD / 4; // duty cycle
}
void loop(){}
You can get pretty close if you program Timer 1 directly (not through the library), and have it run with the prescaler set to 1. Ideally, you want the period of the timer in clock cycles to be:
F_CPU / 15 kHz = 16,000 kHz / 15 kHz ≈ 1066.67 CPU cycles
If you round this to the nearest integer, you get
F_CPU / 1,067 = 16,000 kHz / 1,067 ≈ 14.9953 kHz
This is about 0.03% too slow, well within the tolerance of the ceramic resonator clocking the Uno.
Here is my attempt at this. I have tested it.
constexpr float PWM_FREQUENCY = 15e3; // 15 kHz
constexpr uint16_t PERIOD = round(F_CPU / PWM_FREQUENCY);
void setup() {
// Configure Timer 1 for 15 kHz PWM on pin 9 = PB1 = OC1A.
DDRB |= _BV(PB1); // set pin as output
TCCR1B = 0; // stop timer
TCCR1A = _BV(COM1A1) // non-inverting PWN on OC1A
| _BV(WGM11); // mode 14: fast PWM, TOP = ICR1
TCCR1B = _BV(WGM12) // ditto
| _BV(WGM13) // ditto
| _BV(CS10); // clock @ F_CPU
ICR1 = PERIOD - 1; // period
OCR1A = PERIOD / 4; // duty cycle
}
void loop(){}
You can get pretty close if you program the Timer 1 directly (not through the library), and have it run with the prescaler set to 1. Ideally, you want the period of the timer in clock cycles to be:
F_CPU / 15 kHz = 16,000 kHz / 15 kHz ≈ 1066.67 CPU cycles
If you round this to the nearest integer, you get
F_CPU / 1,067 = 16,000 kHz / 1,067 ≈ 14.9953 kHz
This is about 0.03% to slow, well within the tolerance of the ceramic resonator clocking the Uno.
Here is my attempt at this. Not testedTested.
constexpr float PWM_FREQUENCY = 15e3; // 15 kHz
constexpr uint16_t PERIOD = round(F_CPU / PWM_FREQUENCY);
void setup() {
// Configure Timer 1 for 15 kHz PWM on pin 9 = PB1 = OC1A.
DDRDDDRB |= _BV(PB1); // set pin as output
TCCR1B = 0; // stop timer
TCCR1A = _BV(COM1A1) // non-inverting PWN on OC1A
| _BV(WGM11); // mode 14: fast PWM, TOP = ICR1
TCCR1B = _BV(WGM12) // ditto
| _BV(WGM13) // ditto
| _BV(CS10); // clock @ F_CPU
ICR1 = PERIOD - 1; // period
OCR1A = PERIOD / 4; // duty cycle
}
void loop(){}
You can get pretty close if you program the Timer 1 directly (not through the library), and have it run with the prescaler set to 1. Ideally, you want the period of the timer in clock cycles to be:
F_CPU / 15 kHz = 16,000 kHz / 15 kHz ≈ 1066.67 CPU cycles
If you round this to the nearest integer, you get
F_CPU / 1,067 = 16,000 kHz / 1,067 ≈ 14.9953 kHz
This is about 0.03% to slow, well within the tolerance of the ceramic resonator clocking the Uno.
Here is my attempt at this. Not tested.
constexpr float PWM_FREQUENCY = 15e3; // 15 kHz
constexpr uint16_t PERIOD = round(F_CPU / PWM_FREQUENCY);
void setup() {
// Configure Timer 1 for 15 kHz PWM on pin 9 = PB1 = OC1A.
DDRD |= _BV(PB1); // set pin as output
TCCR1B = 0; // stop timer
TCCR1A = _BV(COM1A1) // non-inverting PWN on OC1A
| _BV(WGM11); // mode 14: fast PWM, TOP = ICR1
TCCR1B = _BV(WGM12) // ditto
| _BV(WGM13) // ditto
| _BV(CS10); // clock @ F_CPU
ICR1 = PERIOD - 1; // period
OCR1A = PERIOD / 4; // duty cycle
}
void loop(){}
You can get pretty close if you program the Timer 1 directly (not through the library), and have it run with the prescaler set to 1. Ideally, you want the period of the timer in clock cycles to be:
F_CPU / 15 kHz = 16,000 kHz / 15 kHz ≈ 1066.67 CPU cycles
If you round this to the nearest integer, you get
F_CPU / 1,067 = 16,000 kHz / 1,067 ≈ 14.9953 kHz
This is about 0.03% to slow, well within the tolerance of the ceramic resonator clocking the Uno.
Here is my attempt at this. Tested.
constexpr float PWM_FREQUENCY = 15e3; // 15 kHz
constexpr uint16_t PERIOD = round(F_CPU / PWM_FREQUENCY);
void setup() {
// Configure Timer 1 for 15 kHz PWM on pin 9 = PB1 = OC1A.
DDRB |= _BV(PB1); // set pin as output
TCCR1B = 0; // stop timer
TCCR1A = _BV(COM1A1) // non-inverting PWN on OC1A
| _BV(WGM11); // mode 14: fast PWM, TOP = ICR1
TCCR1B = _BV(WGM12) // ditto
| _BV(WGM13) // ditto
| _BV(CS10); // clock @ F_CPU
ICR1 = PERIOD - 1; // period
OCR1A = PERIOD / 4; // duty cycle
}
void loop(){}
You can get pretty close if you program the Timer 1 directly (not through the library), and have it run with the prescaler set to 1. Ideally, you want the period of the timer in clock cycles to be:
F_CPU / 15 kHz = 16,000 kHz / 15 kHz ≈ 1066.67 CPU cycles
If you round this to the nearest integer, you get
F_CPU / 1,067 = 16,000 kHz / 1,067 ≈ 14.9953 kHz
This is about 0.03% to slow, well within the tolerance of the ceramic resonator clocking the Uno.
Here is my attempt at this. Not tested.
constexpr float PWM_FREQUENCY = 15e3; // 15 kHz
constexpr uint16_t PERIOD = round(F_CPU / PWM_FREQUENCY);
void setup() {
// Configure Timer 1 for 15 kHz PWM on pin 9 = PB1 = OC1A.
DDRD |= _BV(PB1); // set pin as output
TCCR1B = 0; // stop timer
TCCR1A = _BV(COM1A1) // non-inverting PWN on OC1A
| _BV(WGM11); // mode 14: fast PWM, TOP = ICR1
TCCR1B = _BV(WGM12) // ditto
| _BV(WGM13) // ditto
| _BV(CS10); // clock @ F_CPU
ICR1 = PERIOD - 1; // period
OCR1A = PERIOD / 4; // duty cycle
}
void loop(){}