using 2 TIMMERS

Hi, the question is simple: How can i generate a variable-FREQUENCY-square wave without any library ??

Before you answer i'll give you some details:

1) My goal is create a FUNCTION that can generate variable frequency square wave because i want to implement a personalized acceleration profile using Stepper Motors.

2) I know there is the AccelStepper library that works very well, but i have specific requirements so i would like to do my own code.

3) I have satrted using the Arduino Timers, the Timer1 (16 bits) works in CTC mode with a defined TOP value that i can change.
The Timer0 (8 bits) also in CTC mode has to change the TOP value of Timer1 everytime an interrupt occurs.

4) This system should generate a reliable signal since i'm using timmers directly (at least that's what I expect). But when I upload the code and see with the Oscilloscope there are some rebounds that affects the square wave while it's changing it's frequency.

This is a problem beacuse the stepper motor loses steps or even stops due to the rebounds.

I thought that could be some timing problem between both Timers while one afects the other.
This problem produces a stop or missing steps effect on the stepper motors.

5) I'm using direct register acces or modification instead of the arduino functions, because i want to make a very optimized and fast code that doesn't distorts or affect the resulting signal.

6) The maximum frequency that i would like to use (for timer1) is less than 10 kHz, so everything between 0 and 10 kHz would be nice. For the second timer i should use frequencies between 0 and 5 kHz if its possible.

7) Sorry if I forgot any other info that could be important. I'll post the code used and some picts (i hpe they appear) of the oscilloscope results, but it's difficult to me to post a video of the oscilloscope that would be more illustrative.

byte PULSE = 9;     // pulse signal that motor driver needs
byte DIR = 8;       // direction of motor rotation


void setup() {
  pinMode(PULSE, OUTPUT);   // pin 9 (OC1A) configured as an OUTPUT
  pinMode(DIR, OUTPUT);     // 
  digitalWrite(DIR, HIGH);

  cli();    // disable global interrupts while seting up timers
  
  //----------------------------------------------------------------------------- TIMER 0
  // Set CTC Mode
  TCCR0B &= ~(1 << WGM02); //   WGM02 = 0
  TCCR0A |= (1 << WGM01); //   WGM01 = 1
  TCCR0A &= ~(1 << WGM00); //   WGM00 = 0

  // Prescaler of 256
  TCCR0B |= (1 << CS02);   // CS02 = 1
  TCCR0B &= ~(1 << CS01);    // CS01 = 0
  TCCR0B &= ~(1 << CS00);   // CS00 = 0

  // Enable CTC timer interrupts
  TIMSK0 |= (1 << OCIE0A);


  //----------------------------------------------------------------------------- TIMER 1
  // Set CTC Mode
  TCCR1B &= ~(1 << WGM13); //   WGM13 = 0
  TCCR1B |= (1 << WGM12); //   WGM12 = 1
  TCCR1A &= ~(1 << WGM11); //   WGM11 = 0
  TCCR1A &= ~(1 << WGM10); //   WGM10 = 0

  // set toggle mode for pin 9 (OC1A)
  TCCR1A &= ~(1 << COM1A1); // COM1A1 = 0
  TCCR1A |= (1 << COM1A0);  // COM1A0 = 1

  // Set Prescaler of 8
  TCCR1B &= ~(1 << CS12);   // CS12 = 0
  TCCR1B |= (1 << CS11);    // CS11 = 1
  TCCR1B &= ~(1 << CS10);   // CS10 0 0


  // Maximum count values
  OCR0A = 254;  // For timer0
  OCR1A = 999;  // For timer1
  
  TCNT1 = 0;    //Initialize timer/counter 1 value to 0
  TCNT0 = 0;    //Initialize timer/counter 0 value to 0
  
  sei();  // Enable global interrupts
}


// Timer 0 ISR that changes Top count value of Timer1, hence it's frequency
ISR(TIMER0_COMPA_vect) {

  if (OCR1A >= 249) {   // 249 set the max count value for Timer0
    OCR1A--;
  }
}



void loop() {

}

Timer0 is used by the Arduino core to implement the millis() and micros() timers. I would recommend using the OTHER 8-bit timer: Timer2.

You set the frequency of Timer1 with a combination of the TOP value and the 'prescale' value. You are setting the Waveform Generation Mode (WGM) to 4. That uses the OCR1A register for TOP. The prescale is set with the Clock Select (CS) bits in TCCR1B. The choices are 1, 8, 64, 256, and 1024. The maximum frequency is prescale=1, TOP=0 for a frequency of 8 MHz. The lowest is prescale=1024, TOP=65535 for a frequency of 0.23841... Hz.

Timer2 works very much like Timer0.

Thanks Jhon for your reply!

I will change the Timer0 and use Timer2 instead, and I'll see if my problem disappears.

I used Timer0 for no reason but i thought that i wouldn't have any problem because i'm not using any Arduino function in my code like millis() or delay().

Do you also think the way i'm trying to make a variable frequency signal it's correct? Or should I try another way to solve it?

martin_uib:
Do you also think the way i'm trying to make a variable frequency signal it's correct? Or should I try another way to solve it?

It looks like it should work at changing OCR1A from 999 to 248 over time. I think that would be 62.5 Hz to 251 Hz or maybe 31.25 to 125.5 Hz.
Does it produce the effect you want?

Hi John again!

Well, first of all i have to say that i tried to use Timer2 instead of Timer0 and i still have some rebounds, less than using timer0 but maybe it's the same...

If i could solve those rebounds i would be able to continue with my code, but it seems that it's not the case.

Does it produce the effect you want?

And yes, it does. When i see the signal with the oscilloscope the effect is correct, but the rebounds are the problem.

I still don't know how to avoid them, and i don't know what are the causes.

What do you means by a "rebound". That word has no meaning to me in this context.

Personally, changing the TOP value in an interrupt handler is, to me, the only right way to go. It will allow you to program any acceleration profile you want, and won't interfere with whatever else you're doing. I use that approach all the time, and have never had a problem.

If i could solve those rebounds

Can you please explain more about what is a "rebound". I'm not familiar with that terminology.

If by "rebound" you mean a long Timer1 cycle beyond OCR1A up to 0xFFFF top then perhaps this note in the data sheet is relevant

Note: Changing TOP to a value close to BOTTOM while the counter is running must be done with care,
since the CTC mode does not provide double buffering. If the new value written to OCR1A is lower than
the current value of TCNT1, the counter will miss the compare match. The counter will then count to its
maximum value (0xFF for a 8-bit counter, 0xFFFF for a 16-bit counter) and wrap around starting at 0x00
before the compare match will occur.
In many cases this feature is not desirable. An alternative will then be to use the Fast PWM mode using
OCR1A for defining TOP (WGM1[3:0]=0xF), since the OCR1A then will be double buffered.

For example, If you just happen to be changing OCR1A from 500 to 499 at the time the count is in the process of changing from 499 to 500 you will miss the compare match and carry on to the top.

Sorry if I have not expressed myself correctly, i'm spanish and i don't know the right words to explain what i want.

I understand a rebound as a "vibration" in the signal, sometimes the signal make a little "jump" up and down, and when this happens the motors vibrates or even stops if its running at high speeds.

It seems that it's a voltage fluctuation, not a frecuency problem.

I tried to change the power supply of the Arduino UNO, i used the USB cable, the 9V battery, a power supply at 9V...
Then i tried the same code using an Arduino MEGA and i have the same problem...

I also noticed something curious, when i first tried the code in the Arduino MEGA just using the oscilloscope, those "voltage fluctuations" didn't appear, but when i tried using the motor the problem came again. And then it seems that affected the Arduino and even if i try to see through the oscilloscope again, the "fluctuations" stay and never disappears.

cattledog:
Can you please explain more about what is a "rebound". I'm not familiar with that terminology.

If by "rebound" you mean a long Timer1 cycle beyond OCR1A up to 0xFFFF top then perhaps this note in the data sheet is relevant

For example, If you just happen to be changing OCR1A from 500 to 499 at the time the count is in the process of changing from 499 to 500 you will miss the compare match and carry on to the top.

And yes! I saw this in the Atmel datasheet, and i have considered it, but i think if this happens the motor will not find out about the little change, probably it would be insignificant.
Correct me please if i'm wrong !
Thanks everyone !!

martin_uib:
I also noticed something curious, when i first tried the code in the Arduino MEGA just using the oscilloscope, those "voltage fluctuations" didn't appear, but when i tried using the motor the problem came again. And then it seems that affected the Arduino and even if i try to see through the oscilloscope again, the "fluctuations" stay and never disappears.

It sounds to me like a power problem. If it works without the motors and not with the motors it may be that the motors are drawing more power than the power supply can handle and causing the power voltage to drop.

Well, it works fine the first time i try without the motor connected, then when I connect it the signal starts to fail.
I use the Arduino with separated supply voltage from the motor driver, so it shouldn't be affected.
Also, the driver input signal is optical isolated.

Another fact that i realized is the signal generated by AccelStepper library, when i check it with the oscilloscope the square wave generated uses a lower duty cycle, maybe 20% HIGH 80% LOW.

Could this affect the driver performance? I'm using the DM556 driver if someone wants to know.

Thanks for your reply.

I understand a rebound as a "vibration" in the signal, sometimes the signal make a little "jump" up and down, and when this happens the motors vibrates or even stops if its running at high speeds.

Can you catch one of these "rebounds" on the scope and show us the image?

Your problem may be mid-band resonance, rather than a mis-timed step, though you should rule out mis-timed steps first. There are several ways of counter-acting that, some electrical, some mechanical. Have you tried both slower and faster accelerations? Sometimes you can avoid resonance by simply getting through the resonance band quickly. Sometimes accelerating more slowly will do it. Are you using a micro-stepping driver? A micro-stepping driver will greatly reduced resonance effects, at the expense of higher maximum step rate. If you are attempting to operate IN the resonance band you may have a big problem.

cattledog:
Can you catch one of these "rebounds" on the scope and show us the image?

Hi! i uploaded a video on YOUTUBE so you should see the problem perfectly.

If you have any problem, tell me!

RayLivingston:
Your problem may be mid-band resonance, rather than a mis-timed step, though you should rule out mis-timed steps first. There are several ways of counter-acting that, some electrical, some mechanical. Have you tried both slower and faster accelerations? Sometimes you can avoid resonance by simply getting through the resonance band quickly. Sometimes accelerating more slowly will do it. Are you using a micro-stepping driver? A micro-stepping driver will greatly reduced resonance effects, at the expense of higher maximum step rate. If you are attempting to operate IN the resonance band you may have a big problem.

Hi RayLivingston, I'm a little bit confused, i'm not using high speeds or accelerations because i think that using higher values could be problematic.
How could I find the resonance band you mention? And should I accelerate slowly first and then faster?
And yes, i'm using a micro-stepping driver, the DM556 that allows me to use up to 25600 pulses/rev.
Thanks for your reply!

Finally i tried again the same code, with the same Arduino that had the problem and now it's working fine ...

Why? I don't know, i have changed nothing, first i tried using only the Arduino board, the results were ok.

Second, i tried using Arduino connected to the Driver without the motor, everything ok again.

And finally, I added the motor and no problems, magic, the problem dissappeared for now ...

i'll post the links to the videos i made showing the results, if someone is interested.

Test 1: https://youtu.be/nId2PiL-xqo

Test 2: Test 2 Arduino and Driver - YouTube

Test 3: Test 3 Arduino, Driver and Motor - YouTube

I'm not satisfied with the result as the problem reoccur at any time.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.