1

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

4

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
3
  • 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
    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
    Jul 3, 2023 at 16:15
  • @awado added changes for classic uno (pinMode omitted)
    – KIIV
    Jul 3, 2023 at 16:33
0

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);
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.