Go Down

### Topic: [SOLVED] Getting 50hz PWM from timer0 (Read 632 times)previous topic - next topic

#### surepic

##### Mar 10, 2019, 05:26 amLast Edit: Mar 12, 2019, 04:05 am by surepic
I have servo motor working with 2x555 timer setup....decide to switch timers with attiny. Problem I`m running into with math is I cant generate 50hz with timer0 in FastPWM or PhaseCorrect PWM mode.

Tried with cpu clock prescalers too from 62.5khz to 16mhz(I`m testing on Arduino uno).

from fastPWM mode 3 equation: Fclk/((TOP+1)*N) where N is prescaler.

Solving for N with 50hz is:
50hz=16M/(256*N)
N=16M/(50x256)=1250prescaler

Manipulating with all standard clocks and prescaler the closest I can get is 61hz.

I need 2 positions for servo to go central and +90.

duty cycle 7.5% and 10% for 50hz.

solving duty cycle for 61hz I`m getting

duty cycle= ((OCR+1)/(TOP+1))*100 for non inverted mode

duty cycle= ((TOP-OCR0)/(TOP+1))*100 for inverted mode

converting 7.5% of 50hz to 61hz I need 2.5% duty cycle in non inverted mode OCR0A value of 5.4
10% of 50hz to 61hz            3.3%                                                 OCR0A value of 8.44

Code: [Select]

#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#include <avr/power.h>

void setup() {
TCCR0A=_BV(COM0A1) | _BV(WGM01) | _BV(WGM00);//compare match non inverting mode fast pwm mode 3
TCCR0B=_BV(CS02) | _BV(CS00);// 1024 prescaler
TIMSK0=_BV(OCIE0A) | _BV(TOIE0);//enable ocr interrupt and overflow interrupt
sei();//global I on

}

void loop() {
OCR0A=5;//~1.5MS on time;
//OCR0A=8;//~2MS on time
}

in code I`m just trying to get servo shaft to rotate no logic needed. but nothing is happening. Currently im without oscilloscope. Also I`m not sure if I need to explicitly declare ISR for overflow and ocr interrupts thought that in fastpwm mode it must be done totally in hardware.

don't want to make this post boring by adding code and equations for phase correct mode cos that one is not working too.

would like to know where I`m wrong in math or in code or its just impossible to get 50hz in this modes with timer0;

Thanks.

#### DrAzzy

#1
##### Mar 10, 2019, 08:20 amLast Edit: Mar 10, 2019, 08:22 am by DrAzzy
Uh - why not just use the Servo library (which uses timer1, not timer0 - since using timer0 would break millis() and other timekeeping functions)?

My ATTinyCore includes a version of Servo library that works with all the supported ATTiny chips except the attiny43, and provides the same interface as the normal Servo library - so you don't need to reinvent the wheel yourself.

Depending on which ATTiny you plan to use, if you need to do it manually for some reason, you're probably better off using timer1 - on the tiny85/861, that's a high-speed timer with a very flexible set of prescale options, while on other tinies that's a 16-bit timer (like the one on the Uno) which would also give you more flexibility with setting the frequency.
ATTinyCore for x4/x5/x61/x7/x8/x41/1634/828/x313 megaTinyCore for the megaavr ATtinies - Board Manager:
http://drazzy.com/package_drazzy.com_index.json
ATtiny breakouts, mosfets, awesome prototyping board in my store http://tindie.com/stores/DrAzzy

#### GolamMostafa

#2
##### Mar 10, 2019, 08:45 amLast Edit: Mar 10, 2019, 08:47 am by GolamMostafa
@OP

1.  It is very very difficult to generate low frequency 50 Hz PWM signal using 8-bit TCs like TC0 and TC2.

2.  To generate accurate low/high frequency PWM signal, one has to take the help of TC1 Module which supports frequency change by N (TC1 clock prescaler) and ICR1 Register; PW (pulse width) change by OCR1 Register. Before you ask for a short tutorial, please go through the data sheets to get the meanings of the BOTTOM and TOP parameters.

3.  In the meantime, you can create 50 Hz PWM signal at any valid DPin of the UNO using Servo.h Library as suggested by @DrAzzy in Post#1.

#### Juraj

#3
##### Mar 10, 2019, 10:18 am
is 50Hz PWM? i think it doesn't have the properties of PWM
You can't write an Arduino sketch if you didn't learn programming. Not the language, but the concepts of programming - algorithms and data types.

#### GolamMostafa

#4
##### Mar 10, 2019, 01:13 pm
is 50Hz PWM? i think it doesn't have the properties of PWM
You may execute the following short sketch and check on an oscilloscope if the wave at DPin-2 does posses some properties of 50Hz PWM wave.

Code: [Select]
#include<Servo.h>
Servo myServo;
int pw=0;

void setup()
{
Serial.begin(9600);
myServo.attach(2);
}

void loop()
{
myServo.write(pw);
pw = pw + 0x20;
delay(1000);
}

#### Juraj

#5
##### Mar 10, 2019, 01:40 pmLast Edit: Mar 10, 2019, 01:41 pm by Juraj
You may execute the following short sketch and check on an oscilloscope if the wave at DPin-2 does posses some properties of 50Hz PWM wave.

Code: [Select]
#include<Servo.h>
Servo myServo;
int pw=0;

void setup()
{
Serial.begin(9600);
myServo.attach(2);
}

void loop()
{
myServo.write(pw);
pw = pw + 0x20;
delay(1000);
}

the Servo libro doesn't use PWM support of the MCU. it uses a timer to create pulses
You can't write an Arduino sketch if you didn't learn programming. Not the language, but the concepts of programming - algorithms and data types.

#### GolamMostafa

#6
##### Mar 10, 2019, 02:01 pm
the Servo libro doesn't use PWM support of the MCU. it uses a timer to create pulses
Can we continuously change the ON-period of this pulses based on some kind of feedback? If yes, it is a PWM signal by definition.

#### surepic

#7
##### Mar 10, 2019, 03:45 pm
Sorry i missed the mcu model in my post. Its attiny13v.

So 16bit timer is not available or it would be very easy to generate 50hz with varible duty cycle for servo.

@Drazzy can please send a link to your library? I really dont want to spend time on reinventing anything:-).

If we are talking about softwareservo.h library which is indeed working on some attinys it wont fit into memory of attiny13. Besides i hardcoded pwm via delays in my code same as softwareservo is doing but thats not the one i would like to have.

For ex.
For 1.5ms pulse i did

Pin-high
_delay_us(1500)
Pin-low
_delay_us(18000)

Wrapped in a function with high pulse attribute. Its very short code and doing its job.

But i want to do it in hardware without mcu going line by line in the code in function.

And i cant make fastpwm work so wanted to know if im off in my math or in my code. I dont think that 61hz vs 50hz will prevent servo recognizing the pulse if im feeding it with right duty cycle.

#### cattledog

#8
##### Mar 10, 2019, 03:59 pm
With a prescaler of 1024 and an 8 bit timer, you need 312.5 timer ticks for a 50 hz period. You can use the the phase mode 5 PWM to OCR0A with OCR0A set to 312/2 = 156. You will have to use the pwm on output B.

Obviously you will loose some resolution on the PWM duty cycle setting.

#### surepic

#9
##### Mar 10, 2019, 07:00 pmLast Edit: Mar 10, 2019, 07:11 pm by surepic Reason: attachment update
I didnt quite get idea of using mode 5 if top value is ocr value. I never used mode 5 before.

@cattledog if i got you right in mode 1 then i have 510 ticks total. With prescaler of 1024 and 16mhz clock i have 64us per tick.

20ms/64us is 312.5ticks needed.

312/2=156 for ocr

In mode 1 upcounting 0-156 ocr is set. From 156 to down counting to 156 is giving (255-156)*2=198ticks =12672us.

From 156 to bottom and up to 156 is giving 312ticks i.e. ~20ms. Meanwhile signal is low.

If i fit second ocr with value of 11 i will set high for duriation of 11+11=22tics*64=1.4ms .

And then again long pause for clock to reach to 156 at downcounting.

Will attach drawing.

#### cattledog

#10
##### Mar 10, 2019, 08:33 pmLast Edit: Mar 10, 2019, 08:36 pm by cattledog
Quote
I didnt quite get idea of using mode 5 if top value is ocr value. I never used mode 5 before.
You need to use this mode if you want to get a 20ms period. Mode 5 uses the OCR0A value as top, so top will be OCR0A = 156 not 255. Your image still indicate you are using a mode with 255 top.

Then the PWM  output will be on B. Duty cycle will be set with OCR0B.

Set COM0B1 and COM0B0 to 11.   I think that is set rising, clear falling. Otherwise the setting will be 10. Duty cycle values may be reversed, with small numbers higher duty cycle values. If you want to have it as normal, then you will need to use an output setting which clears rising and sets falling.

#### surepic

#11
##### Mar 10, 2019, 08:46 pmLast Edit: Mar 11, 2019, 11:25 pm by surepic
Thanks will update the topic if any success on mode 5.

#### surepic

#12
##### Mar 11, 2019, 11:25 pm
UPDATE:
didn't work on mode 5;

20ms/64us=23us;

156-23/2=144; for central position

Code: [Select]

#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#include <avr/power.h>

void setup() {
DDRB|=_BV(DDB2) | _BV(DDB1); // pins 9 and 10 out
TCCR0A=_BV(WGM02) | _BV(WGM00) | _BV(COM0B1) | _BV(COM0B0);// mode5 , set on rising clear on falling
TCCR0B=_BV(CS02) | _BV(CS00);//1024 prescaler
OCR0A=156; // 156*2=312=20ms period
//TIMSK0=_BV(OCIE0B) | _BV(OCIE0A);

}

void loop() {
OCR0B=144; //1.5ms
// OCR0B=140;//for 2ms
}

#### cattledog

#13
##### Mar 11, 2019, 11:42 pmLast Edit: Mar 11, 2019, 11:45 pm by cattledog
Quote
UPDATE:
didn't work on mode 5;

WGM02 is on TCCR0B in the AT328.

Are you using an ATtiny? What processor? Do you have a data sheet in front of you?

I'm not certain about your timer default presets, so it's always good to have TCCRxA and TCCRxB initialized to 0 before adding bits to where you want them. The timers are usually have presets for the millis()/micros() and the default pwm settings.

#### surepic

#14
##### Mar 12, 2019, 01:37 amLast Edit: Mar 12, 2019, 02:08 am by surepic
You are right about wgm02 bit ... went many times through code and didnt even think of checking where it belongs. No im testing on 328p(uno) . Currently no oscilloscope so its realy hard to see what the signal is thats why got back to pen and paper method.

Im initializing timer registers with 0.
Im not OR ing tccrb.

Tccr= (1<<bit) will set all zeros except the mentioned bit.

Same as
tccrb=0
Tccrb|= set bit.

Will test wgm02 in correct register and will update.

UPDATE: same thing servo is not recognizing the pulse.

servo is attached to pin 10 which is pb2.
code edited with wgm02 in tccr0b register.

rechecked servo with _delay_us routines its working.

Go Up