Transferring Code from UNO to Nano Every

Hello all,
I was prototyping a project using an old Uno board I had, but now I am trying to implement it using a Nano Every I am realizing it's not going to work without modification, and I am having a hard time narrowing down what I need to do.
I am following this general guide for the UNO: https://www.hackster.io/Buechner/4-wired-fan-control-pwm-bb29ac
And I had everything working. Now those registers do not exist, and it seems the Nano has a faster clock speed which I assume might change the calculations too?

In short can someone help me port this UNO code:

   // generate 25kHz PWM pulse rate on Pin 3
   pinMode(pwmPin, OUTPUT);   // OCR2B sets duty cycle
   // Set up Fast PWM on Pin 3
   TCCR2A = 0x23;     // COM2B1, WGM21, WGM20 
   // Set prescaler  
   TCCR2B = 0x0A;   // WGM21, Prescaler = /8
   // Set TOP and initialize duty cycle to zero(0)
   OCR2A = 79;    // TOP DO NOT CHANGE, SETS PWM PULSE RATE
   OCR2B = 0;    // duty cycle for Pin 3 (0-79) generates 1 500nS pulse even when 0 :

To something that works on a Nano Every at 25kHz?

It would be great if you could help me figure out what registers I need to change for the Nano, and the math I need to generate the 25kHz.

I am sure that I have already seen this query in the forum today

I just browsed through the topics from today, and did not see anything related. I have been Googling and trying to figure out the timers for awhile too.

Have you read the processor data sheet?

codemonkeyx:
I just browsed through the topics from today, and did not see anything related. I have been Googling and trying to figure out the timers for awhile too.

This is the thread that I had seen
https://forum.arduino.cc/?topic=699858#msg4703201
Not quite the same, but very similar

Ok I have been reading up, and I have a test file that’s working by following the PWM examples for the ATMEGA chip in the Nano Every. But it introduced a new issue that I am is getting further out of my knowledge, and I hit a bit of a wall.

In the following code I scale the clock down to 1Mhz, then I figured that I can use the counter to count to 40 (40 microseconds) that will give me a 25KHz pulse. It seems to work I can ramp the fan up and down just fine. BUT because I am modifying the clock divider Serial no longer works, millis() is 16 times slower, and I assume other serial coms like I2C will stop working. Is there a way to get the everything to play nice with the new clock divider? Or a different way to change the clock for TCB?

// 1Mhz Clock
#define CCMPL 0x0028 // 40 steps.

void CLOCK_init () {
    /* Enable writing to protected register */
    CPU_CCP = CCP_IOREG_gc;

    // Set 16MHz Clock / 16 = 1MHz
    CLKCTRL.MCLKCTRLB = CLKCTRL_PDIV_16X_gc | CLKCTRL_PEN_bm;
    
    /* Wait for system oscillator changing to finish */
    while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm)
    {
        ;
    }
}

void PORT_init (void)
{
    PORTB_DIR |= PIN3_bm;
    PORTB_OUT |= PIN3_bm;
}

void setspeed(int speed ) {
  if( speed > 0 && speed <= CCMPL ) {
    speed <<= 8;
    TCB1.CCMP = speed | CCMPL;
    TCB1.CTRLA |= TCB_ENABLE_bm;
    TCB1.CTRLB |= TCB_CCMPEN_bm;
    TCB1.CTRLB |= TCB_CNTMODE_PWM8_gc;
  }
}

Never mind I think I found it like five minutes after posting this.
I noticed I can make TCA0 the clock for TCB1 instead of the system or peripheral clocks. So I setup TCA0 with a divider of 16 to make my 1Mhz clock, then fed that into TCB. Now the serial port seems to be working again, and millis seems good too.

Hi CodeMonkeyx,

Can your code by dynamically updated that will allow PWM changes to 2 PWM output (independent) on-the-fly thru a User Interface ??

Thanks,
Dave

One of the few ways that the megaAVR 0-series is worse is how they took away all the independent prescalers that we used to get - we only get the one freely adjustable prescaler on TCA0 now (though - at least in MegaCoreX (not sure if the mess that is the official core has picked up on this - you don’t need to burn it to get millis to work - you can use a TCB and clock it from peripheral clock / 2).

They made this less bad in the AVR DA-series, since - at least in the 48/64-pin versions - there’s a second Type A timer, and the TCBs can use either TCA as their clock source, plus you get a TCD, though configuring that one can be a real adventure (it’s a really powerful timer, granted, and you can run it faster than the system clock too via an on-chip PLL - but the async nature of it, as well as it’s not-like-anything-else PWM operation made getting it set up on the first chips that had it (The tinyAVR 1-series, which lacked the PLL) a real adventure… it was almost a year after I released the core for it that I was able to make PWM and millis work off TCD at the same time (and on the tinyAVR 1-series, that’s very desirable, as most of them only have 1 of the incredibly useful type B timers, and you’d like to be able to use that for tone, servo, or other useful functions). I still miss the “good” timer from the classic AVRs though…

codemonkeyx:
Never mind I think I found it like five minutes after posting this.
I noticed I can make TCA0 the clock for TCB1 instead of the system or peripheral clocks. So I setup TCA0 with a divider of 16 to make my 1Mhz clock, then fed that into TCB. Now the serial port seems to be working again, and millis seems good too.

Would you please share your solution? I am also trying to control a 25KHz PWM fan with Nano Every and can't find a proper solution.

1 Like