Arduino Uno - 62.5kHz PWM issues

Hi

I have been toying with Arduino for a couple of years but never really got stuck into finishing a project using Arduino.

Anyway, I have a need for a PWM generator at 62.5 kHz with duty cycles selectable from using a BCD rotary switch. I wrote and compiled the sketch using this info to get 62.5kHz

https://playground.arduino.cc/Main/TimerPWMCheatsheet/

Using an Oscilloscope, i checked the PWM signal and it looks OK (attached PWM-OK jpeg), until I expanded the time scale (PWM-longer timespan - Not-OK jpeg). As you can see from the attached the PWM is not consistent. there are repeated intervals where there is no acivity on the output pin.

Now, I dont know nearly enough about the timer/PWM signal setup to solve this. I have also searched the web and other posts but im not sure if im searching for the right thing and thus is have not been able to solve this problem.

Is this maybe pushing the limits of the UNO?

Some advice would be greatly appreciated

Thanks

wedm-uno-pwm.ino (2.04 KB)

Please read the how to use this forum and follow the instructions for posting code and pictures. I’m on my iPad and I’m unable to view your code and don’t want to download your pictures.

My Apologies, re-post images and code below

// this constant won't change:
const int  bcd0Pin = 8;    // bit0
const int  bcd1Pin = 9;    // bit1
const int  bcd2Pin = 10;    // bit2
const int  bcd3Pin = 11;    // bit3
const int ledPin = 13;       // the pin that the LED is attached to
const int enaPin = 4;

const int  pwmPin = 6;    //pwmout
const int interval = 200; //time to check for input state change

// Variables will change:

unsigned long prev_time=0; //previous time of state check for inputs
unsigned long current_time=0; //current time
int value=0; //bcd valye
int duty=0; 

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(bcd0Pin, INPUT_PULLUP);
  pinMode(bcd1Pin, INPUT_PULLUP);
  pinMode(bcd2Pin, INPUT_PULLUP);
  pinMode(bcd3Pin, INPUT_PULLUP);
  pinMode(pwmPin, OUTPUT);
  pinMode(enaPin,OUTPUT);
//Serial.begin(9600);


//set pwm freq to maximum - 64kHz, pin 5,6
TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00); 
TCCR0B = _BV(CS00); 

  
}

// the loop function runs over and over again forever
void loop() {

current_time=millis();
  //store curr time as prev time and call function to check input bcd state
  if ((current_time - prev_time)>= interval) {
    duty=bcdvalue();
    prev_time=current_time;
  }
           

//Serial.println(duty);
//delay(300);

analogWrite(pwmPin, duty*5+10);
digitalWrite(enaPin, HIGH);    
}



int bcdvalue() { //check input state and change bcd value


value=0;

if (digitalRead(bcd0Pin) == LOW) { //bit0
  value=value+1;
 }

if (digitalRead(bcd1Pin) == LOW) { //bit1
  value=value+2;
 }

if (digitalRead(bcd2Pin) == LOW) { //bit2
  value=value+4;
 }

if (digitalRead(bcd3Pin) == LOW) { //bit3
  value=value+8;
 }

return value;
//Serial.println(value);
 
}

Scale - 5us per div : This looks OK

Scale 2.5ms - Not continuous

Thanks for the quick reply

Use analogWrite() only if the duty cycle changes. More care and low level coding is required to prevent gaps when changing the duty cycle - new compare value should not be lower than current count.

Thanks for the reply.

I get the same result without the changing duty cycle function and nothing in the main loop except "analogWrite(pwmPin,45)" for example.

The "gaps" become smaller with higher duty cycles and vice versa...

It is almost as if the pulses are disabled when the compare register triggers and only enables again when the counter resets and begin the next cycle...

Thanks
Henk

You should not call analogWrite() with the same duty cycle. It can restart the signal generator in an unwanted state.

Ok understood, i have added this to the main loop to ensure analogWrite is only called when the duty changes:

if (duty != prev_duty) {

analogWrite(pwmPin, value*5+10);

prev_duty=duty;

}

I still get the same behaviour.

Thanks for the assistance

Henk

Where is prev_duty declared? What is its scope?

Should you not be using "duty5+10" rather than "value5+10"? The variable "value" should be local to bcdvalue() I think.

Hi
Thanks for pointing out that mistake. This is the full code.

I still have the same result. but im starting to think this is a scope issue. Is that possible?

I monitored the execution of the 2nd "if" loop and it does only run when i change duty cycle so analogWrite will also only run once when the duty changes.

Thanks for the help so far, much apreceated.

// this constant won't change:
const int  bcd0Pin = 8;    // bit0
const int  bcd1Pin = 9;    // bit1
const int  bcd2Pin = 10;    // bit2
const int  bcd3Pin = 11;    // bit3
const int ledPin = 13;       // the pin that the LED is attached to
const int enaPin = 4;

const int  pwmPin = 6;    //pwmout
const int interval = 200; //time to check for input state change

// Variables will change:

unsigned long prev_time=0; //previous time of state check for inputs
unsigned long current_time=0; //current time
int value=0; //bcd valye
int duty=0; 
int prev_duty=0;

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(bcd0Pin, INPUT_PULLUP);
  pinMode(bcd1Pin, INPUT_PULLUP);
  pinMode(bcd2Pin, INPUT_PULLUP);
  pinMode(bcd3Pin, INPUT_PULLUP);
  pinMode(pwmPin, OUTPUT);
  pinMode(enaPin,OUTPUT);
Serial.begin(9600);
  digitalWrite(enaPin, HIGH);

//set pwm freq to maximum - 64kHz, pin 5,6
TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM01) | _BV(WGM00); 
TCCR0B = _BV(CS00); 

  
}

// the loop function runs over and over again forever
void loop() {

current_time=millis();
  //store curr time as prev time and call function to check input bcd state
  if ((current_time - prev_time)>= interval) {
    duty=bcdvalue();
    prev_time=current_time;

    
  }

if (duty != prev_duty) {
 
  analogWrite(pwmPin, duty*5+10);
Serial.println(duty*5+10);
  prev_duty=duty;
  
}


           





    
}



int bcdvalue() { //check input state and change bcd value


value=0;

if (digitalRead(bcd0Pin) == LOW) { //bit0
  value=value+1;
 }

if (digitalRead(bcd1Pin) == LOW) { //bit1
  value=value+2;
 }

if (digitalRead(bcd2Pin) == LOW) { //bit2
  value=value+4;
 }

if (digitalRead(bcd3Pin) == LOW) { //bit3
  value=value+8;
 }

return value;
//Serial.println(value);
 
}

the 2nd "if" loop

Its not a loop, just an "if" or conditional statement.

I can't see a fault in your code that would cause what you describe. Lots of ways to improve the code, but nothing that will fix your problem.

What is attached to the pwm pin? A led, motor? Can you perceive any flickering/fluttering in that?


Can you take these again, using the latest code? You should be able to capture the scope screen direct to usb stick memory, I think, but if not, please take pictures square-on to the screen and check focus is sharp.

The top picture looks like one signal modulating a second, much higher frequency signal. But I can't read the time scales.

Nothing at the moment but it is intended for a wire EDM machine.

I'll connect an led and check.

Thanks
Henk

"Electronic Dance Music"? I guess not, but you should not assume people will know you mean Electrical Discharge Machining. Almost every TLA has multiple meaning these days!

Trial Lawyers' Association ?

Tektronix Logic Analyser ?

Throttle Level Angle ?

a7

PaulRB:
You should be able to capture the scope screen direct to usb stick memory,

Scope looks like a differently badged version of mine, on which doing that is a pain in the backside, what with having to use the multi-purpose knob to scroll through file name letters like a Dymo labeller ;). But yes, it’s doable.

It should / could also have a usb printer socket on the back, for direct connection to the PC with EasyScope. My EasyScope stopped working when I upgraded to a W10 laptop and I can’t find the right driver anywhere. So, and apologies for going OT, if anyone has the right ones for W10 I’m keen to get a copy please.