I need to drive a LED strip via MOSFET module. The module needs a high resolution PWM for very dim conditions. How can I set my pin to a 16 bit PWM resolution on an Arduino Nano Every?
2 Answers 2
It's possible for D5 (TCA0-WO2) + D9 (TCA0-WO0) + D10 (TCA0-WO1) all three of them will be 16bit if you change TCA0 top value, but you can't use analogWrite.
void setup() {
// change period of TCA0 (already configured and started by arduino core)
TCA0.SINGLE.PER = 0xFFFF; // change top value from 255 to 65535
// set PWM value of D9 (channel 0)
TCA0.SINGLE.CMP0 = 0; // initial value
// enable PWM output (needed only once in setup)
pinMode(9, OUTPUT); // setup pin as an output
TCA0.SINGLE.CTRLB |= TCA_SINGLE_CMP0EN_bm; // enable pwm->pin
// D5
TCA0.SINGLE.CMP2 = 1; // initial value
pinMode(5, OUTPUT);
TCA0.SINGLE.CTRLB |= TCA_SINGLE_CMP2EN_bm;
// D10
TCA0.SINGLE.CMP1 = 65530; // initial value
pinMode(10, OUTPUT);
TCA0.SINGLE.CTRLB |= TCA_SINGLE_CMP1EN_bm;
}
and in the code you'll use only TCA0.SINGLE.CMPn = val;
where n is 0..2
(untested, but should be working)
EDIT: I forgot the period will be 3.8Hz, so you'll need to change also TCA0 prescaller or use smaller precision like 10b or so. Changing prescaller will mess up the all the TCB counters periods along with the one used for millis counter so you'd need also change that
EDIT2: for classic UNO/nano it'll look like this:
TCCR1B = 0; // stop timer
ICR1 = 0xFFFF; // f = 16MHz / (2*N*ICR1) = 16MHz / (2*65536) => ~122Hz
OCR1A = 1; // PB2 -> D9 (PWM value)
TCCR1A = _BV(COM1A1); // enable PWM output on PB2
TCCR1B = _BV(WGM13) | _BV(CS10); // mode=8 (phase and freq correct, ICR1 as top) and start timer with prescaller /1
-
Thanks for the detailed code. Will try these days. I used an analogWrite function on the Uno, which wrote uint16_t to OCR1A (pin9). Is this still the same?awado– awado2023年07月03日 15:43:57 +00:00Commented Jul 3, 2023 at 15:43
-
No, classic uno/nano (with Atmega328) has different settings for timer1 - but on the other side it has independent prescaller, so you won't break anything.KIIV– KIIV2023年07月03日 16:15:20 +00:00Commented Jul 3, 2023 at 16:15
-
@awado added changes for classic uno (pinMode omitted)KIIV– KIIV2023年07月03日 16:33:41 +00:00Commented Jul 3, 2023 at 16:33
Thanks again for your help KIIV. I can confirm it works. This an example of a low light PWM for an LED on Pin 10. Maybe it helps others.
int brightness = 0; // how bright the LED is
int fadeAmount = 1; // how many points to fade the LED by
void setup() {
TCA0.SINGLE.PER = 0x4000;
TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV16_gc | 1 << TCA_SINGLE_ENABLE_bp
TCA0.SINGLE.CMP1 = 65530; // initial value
pinMode(10, OUTPUT);
TCA0.SINGLE.CTRLB |= TCA_SINGLE_CMP1EN_bm;
}
void loop() {
// set the brightness of LED pin:
TCA0.SINGLE.CMP1 = brightness;
// change the brightness for next time through the loop:
brightness = brightness + fadeAmount;
// reverse the direction of the fading at the ends of the fade:
if (brightness <= 0 || brightness >= 64) {
fadeAmount = -fadeAmount;
}
// wait to see the dimming effect
delay(50);
}