Migrating fast PMW code using timer 1 from Leonardo to NanoV3

Hello everyone!
I successfully managed to control a cheap motor that came with nearly zero spec vip fast PWM signal. This motor is a replacement for the motor that drives the water turbine of my broken sous-vide-stick from Unhold.
As I found out the motor needs PWM frequencies above 21kHz and I found code online using timer 1 that did the job.
I implemented this code on my Leonardo with the help of this forum while waiting for the Nano to be shipped.

Then I uploaded the following code to the Nano V3 and nothing happened with the motor >:( .

Any suggestions what needs to be changed in the code when going from Leonardo to Nano?

/**********************************************************
                Fast PWM Test

Demostrates the generation of high speed PWM
using timers 1
There are two pieces of code:

One for pins 91 using TIMER 1
with frequencies up to 62kHz

History:
  12/12/2014 - Version 1.0
  22/12/2014 - Adding a missing OCR4C value
  
  Works with Leonardo
  

***********************************************************/

/**********************************************************
   Fast PWM on pins 9, (TIMER 1)
   
   Do not use analogWrite to pins 9, 10 or 11 if using 
   this functions as they use the same timer.
   
   Those functions will probably conflict with the 
   servo library.
   
   Uses 5 PWM frequencies between 61Hz and 62.5kHz
   
**********************************************************/

// Frequency modes for TIMER1
#define PWM62k   1   //62500 Hz
#define PWM8k    2   // 7812 Hz
#define PWM1k    3   //  976 Hz
#define PWM244   4   //  244 Hz
#define PWM61    5   //   61 Hz

// Direct PWM change variables
#define PWM9   OCR1A


// Configure the PWM clock
// The argument is one of the 5 previously defined modes
void pwm91011configure(int mode)
{
// TCCR1A configuration
//  00 : Channel A disabled D9
//  00 : Channel B disabled D10
//  00 : Channel C disabled D11
//  01 : Fast PWM 8 bit
TCCR1A=1;

// TCCR1B configuration
// Clock mode and Fast PWM 8 bit
TCCR1B=mode|0x08;  

// TCCR1C configuration
TCCR1C=0;
}

// Set PWM to D9
// Argument is PWM between 0 and 255
void pwmSet9(int value)
{
OCR1A=value;   // Set PWM value
DDRB|=1<<5;    // Set Output Mode B5
TCCR1A|=0x80;  // Activate channel
}

// Generates 4 PWM signals, two constant and two variable

void setup()
{



// Configure Timer 1 (Pins 9)
// It will operate at 62kHz
// Valid options are: 
//      PWM62k, PWM8k, PWM1k, PWM244 and PWM61
pwm91011configure(PWM62k);



// Pins 9 will change value in the loop function
// We first configure them
// Prepare pin 9 to use PWM
// We need to call pwm91011configure
// For now, we set it at 0%
pwmSet9(0);
}

int value=255;
int steadyrpm=21; // =4900rpm
int steadytime=1200;   // Divide by 10 to get seconds here 2 min
int lowtime=150;      // Divide by 10 to get seconds here 15 sec
int counter=0;
int phase=1;


void loop()
{
// Set PWM at pins 9
// Those fast macros require a previous configuration
// of the channels using the pwmSet9
// functions
// The functions pwmSet9 acan be used
// instead, but the PWM9 and PWM6 macros are faster
// to execute
PWM9=value;
switch(phase){
  case 1:
    // Increment PWM value and return from 255 to steadyrpm=21
    value=(value-10)%256;
    if (value<steadyrpm)
      {
        phase=5;
      }
    // Small 100ms delay
    delay(100);
  break;
    
  case 2:
     value=(steadyrpm-15); // 5300 rmp = 21-15
     counter=counter+1;
     if (counter>lowtime)
      {
        phase=5;
        counter=0;
      }
    delay(100);
  break;
    
  default:
    value=(steadyrpm);
    counter=counter+1;
     if (counter>steadytime)
      {
        phase=2;
        counter=0;
      }
    delay(100);
    break;
  }
}

You better ask the experts in the other forum for incompatibilities between Leonardo and Nano controllers. Without a detailed description it's hard to understand what your code is assumed to do.

Thanks for the answer! I was also struggling to find the right place to post this question.

The code is supposed to do PWM signals with high frequencies above 21kHz which seems not to be the native frequency for an Arduino. They’re different posts and approaches to that on the Internet and I was actually very happy to find something that I got to work without my detailed Arduino programming knowledge.

What forum are you referencing to?

Thanks again.

Do I understand this right:

I found this:


The best way to think about the Arduino Nano timers is to think about the timers in the underlying chip: the ATmega328. It has three timers:

Timer 0: 8-bit, PWM on chip pins 11 and 12
Timer 1: 16-bit, PWM on chip pins 15 and 16
Timer 2: 8-bit, PWM on chip pins 17 and 5


So I guess that timer 1 affects not pin 9 but 25 and 16 on the Nano? Or does that reference to the pins on the CHP and not to the pins in the code/board?

So I guess that timer 1 affects not pin 9 but 25 and 16 on the Nano? Or does that reference to the pins on the CHP and not to the pins in the code/board?

Timer 1 affects pins 15 and 16 of the ATmega328 chip which are wired to the pins D9 and D10.

The problem is the code in the routines pwm91011configure() and pwmSet9(). Direct register manipulations are processor specific and the values chosen here are not correct for the ATmega328.

Fortunately most configurations are identical for the two processors but you have to change this line (at least):

DDRB|=1<<5;    // Set Output Mode B5

to

DDRB|=1<<1;    // Set Output Mode B2

The PWM frequency is determined by the timer prescaler mode (coarse), ICR or OCRA (fine), and the duty cycle by OCRA or OCRB. The datasheet pin numbers refer to chip pins, not board pins.

DrDiettrich you made my day! You are carrying your title not by accident.

With this tiny modification the code runs like a charm on my Nano.

Thanks a lot pal. That was great.

With this tiny modification the code runs like a charm on my Nano.

As DrDiettrich didn't provide any finished code it would be nice for any user with a similar problem to post the complete final code that runs on your Nano.

It's quite unlikely that hardware (timer...) related code can be used by copy&paste in some other project - see this thread. That's why I think that it's better to teach people how to master the hardware instead of presenting just another specialized code project.

At least for me it worked with copying something, trying to understand it a little and modify it to my needs. As log as you use the same chip you can get pretty far using this approach. Of course you need somewhere some people that have the full picture.

Here is my complete code also now having a litte extra code to listen to an input value that is used as a switch to turn the motor on (0V=on 5V=off).

/**********************************************************
                Fast PWM Test

Demostrates the generation of high speed PWM
using timers 1
There are two pieces of code:

One for pins 91 using TIMER 1
with frequencies up to 62kHz

History:
  12/12/2014 - Version 1.0
  22/12/2014 - Adding a missing OCR4C value
  
  Works with Leonardo
  

***********************************************************/

/**********************************************************
   Fast PWM on pins 9, (TIMER 1)
   
   Do not use analogWrite to pins 9, 10 or 11 if using 
   this functions as they use the same timer.
   
   Those functions will probably conflict with the 
   servo library.
   
   Uses 5 PWM frequencies between 61Hz and 62.5kHz
   
**********************************************************/

// Frequency modes for TIMER1
#define PWM62k   1   //62500 Hz
#define PWM8k    2   // 7812 Hz
#define PWM1k    3   //  976 Hz
#define PWM244   4   //  244 Hz
#define PWM61    5   //   61 Hz

int inPin = 7;     // PWM Signal from sous-vide-stick board to digital pin 7

// Direct PWM change variables
#define PWM9   OCR1A


// Configure the PWM clock
// The argument is one of the 5 previously defined modes
void pwm91011configure(int mode)
{
// TCCR1A configuration
//  00 : Channel A disabled D9
//  00 : Channel B disabled D10
//  00 : Channel C disabled D11
//  01 : Fast PWM 8 bit
TCCR1A=1;

// TCCR1B configuration
// Clock mode and Fast PWM 8 bit
TCCR1B=mode|0x08;  

// TCCR1C configuration
TCCR1C=0;
}

// Set PWM to D9
// Argument is PWM between 0 and 255
void pwmSet9(int value)
{
OCR1A=value;   // Set PWM value
//DDRB|=1<<5;    // Set Output Mode B5 for Leonardo
DDRB|=1<<1;    // Set Output Mode B5 for Nano
TCCR1A|=0x80;  // Activate channel
}


// Start of demostration code
// Generates 4 PWM signals, two constant and two variable

void setup()
{



// Configure Timer 1 (Pins 9)
// It will operate at 62kHz
// Valid options are: 
//      PWM62k, PWM8k, PWM1k, PWM244 and PWM61
pwm91011configure(PWM62k);



// Pins 9 will change value in the loop function
// We first configure them

// Prepare pin 9 to use PWM
// We need to call pwm91011configure
// For now, we set it at 0%
pwmSet9(0);
pinMode(inPin, INPUT);        // sets the digital pin 7 as input for the PWM Signal from the sous-vide-stick board
}

int value=255;
int steadyrpm=21; // =4900rpm
int steadytime=1200;   // Divide by 10 to get seconds here 2 min
int lowtime=150;      // Divide by 10 to get seconds here 15s
int counter=0;
int phase=1;


int switchon = 0;       // variable to store the read value



void loop()
{
// Set PWM at pins 9
// Those fast macros require a previous configuration
// of the channels using the pwmSet9
// functions
// The functions pwmSet9 acan be used
// instead, but the PWM9 and PWM6 macros are faster
// to execute
PWM9=value;

switchon = digitalRead(inPin);     // read if water turbine shoud spin

if (switchon==LOW)
{

switch(phase){
  case 1:
    // Increment PWM value and return to 0 after 255
    value=(value-10)%256;
    if (value<steadyrpm)
      {
        phase=5;
      }
    //value=RPM2PWM(3000);
    //value=70;
    // Small 10ms delay
    delay(100);
  break;
    
  case 2:
     value=(steadyrpm-15); // 5300 rmp = 21-15
     counter=counter+1;
     if (counter>lowtime)
      {
        phase=5;
        counter=0;
      }
    delay(100);
  break;
    
  default:
    value=(steadyrpm);
    counter=counter+1;
     if (counter>steadytime)
      {
        phase=2;
        counter=0;
      }
    delay(100);
    break;
  }
}
else
{
value=255;
phase=1;
}
}