Intel® Makers
Intel® Edison, Intel® Joule™, Intel® Curie™, Intel® Galileo
Announcements
Welcome - This is a Peer-to-Peer Forum only. Intel has discontinued these products but you may find support from other customers on this Forum
9868 Discussions

PWM on Galileo board in an arduino sketch

ELabs
Novice
2,174 Views

I looked up the example of PWM using the wire library. It seems like it sets frequency, duty cycle etc on the timers by setting bits in the timer. Is there a detailed description of which timer it is accessing?

 

Also I've noticed that it executes code lines written in void loop() only once and it exits. and I feel the board is stuck then.

Th

0 Kudos
10 Replies
ADRIAN_B_Intel
Employee
384 Views

have forwarded this to the IDE team, are you using analogWrite() to use the PWM, it should just work as it does for Arduino Uno, add code snippets so we can help you

-a

ELabs
Novice
384 Views

Sorry to get back late on this.

I'm using a continuous rotation servo from parallax http://www.parallax.com/product/900-00008 http://www.parallax.com/product/900-00008

According to the motor specs it works between pulse widths 1.3ms to 1.7ms. where 1.3 is fastest in one direction and 1.7 is fastest in another direction. and it stops at 1.5 ms.

I tried to set clock,freqnecy and period register in setup and I'm trying to change the duty cycle in loop.

But it does not behave as expected.

Also how to direct output of a timer to different pins in loop. Like for eg. I'mm using Pin 5 and 9. I'm trying to emulate something like servo.attach() usign analogWrite(Pin,1) and servo.detatch using analogWrite(Pin,254).

But doesn't seem to work.

Your help would be greatly appreciated.

 

# include "Wire.h"

int PIN1 = 5;

int PIN2 = 9;

int count = 0;

void setup() {

Wire.begin();

pinMode(PIN1,OUTPUT);

pinMode(PIN2,OUTPUT);

// analogWrite(PIN, 1);

//select programmable PWM CLK source

Wire.beginTransmission(0x20);

Wire.write(0x29); //config PWM register

Wire.write(0x04); //100b sets to programmable 367.6Hz clock

Wire.endTransmission();

//Set divider to get get 45Hz frequency

//freq = clock/divider i.e 367/45 = 8

Wire.beginTransmission(0x20);

Wire.write(0x2C);

Wire.write(0x08);

Wire.endTransmission();

//Set period register

Wire.beginTransmission(0x20);

Wire.write(0x2A);

Wire.write(0xFF);

Wire.endTransmission();

}

void loop() {

//rotate servo 1 anti clockwise

analogWrite(PIN1,1);

//full speed anti-clockwise

//Duty-Cycle = PulseWidth/Period

//for 1.3ms = (PulseWidth/255)*22.22

Wire.beginTransmission(0x20);

Wire.write(0x2B);

Wire.write(0x0F);

Wire.endTransmission();

delay(1000);

analogWrite(PIN1,254);

//stop

//Duty-Cycle = PulseWidth/Period

//for 1.5ms = (PulseWidth/255)*22.22

Wire.beginTransmission(0x20);

Wire.write(0x2B);

Wire.write(0x12);

Wire.endTransmission();

delay(1000);

//rotate servo 2 anti clockwise

analogWrite(PIN2,1);

//full speed anti-clockwise

//Duty-Cycle = PulseWidth/Period

//for 1.3ms = (PulseWidth/255)*22.22

Wire.beginTransmission(0x20);

Wire.write(0x2B);

Wire.write(0x0F);

Wire.endTransmission();

delay(1000);

//stop

//Duty-Cycle = PulseWidth/Period

//for 1.5ms = (PulseWidth/255)*22.22

Wire.beginTransmission(0x20);</span...

ELabs
Novice
384 Views

Also is it possible to change frequency of wave in the loop. as opposed to doing it in setup.

Lucas_A_Intel
Employee
384 Views

Hi- we also built a project using servos- not continuous rotation, but they expect a similar output- a cycle time of about 20ms with pulses ranging from 1-2ms. Here's how we approached it:

in setup() just include wire.begin();

then we made a function to write to the pins that we could call repeatedly in the loop()

here's our function, placed outside of everything else;

void setPwmI2C(int _iPinNum, int _iPwmVal)

{

// Select pin to write I2C commands to

analogWrite(_iPinNum,1);

// Set divider to get 64Hz freq.

Wire.beginTransmission(0x20);

Wire.write(0x2C);

////////////// this number changes clock frequency... 0x03 = 125hz, 0x06 = ~64hz, 0x07 = ~53hz//////

Wire.write(0x06);

////////////////////////////////////////////////////////////////////////////////////////////////////

Wire.endTransmission();

// Select programmable PWM CLK source

Wire.beginTransmission(0x20);

Wire.write(0x29);

Wire.write(0x04);

Wire.endTransmission();

// Set period register

Wire.beginTransmission(0x20);

Wire.write(0x2a);

Wire.write(0xff);

Wire.endTransmission();

// Set minimum duty cycle

Wire.beginTransmission(0x20);

Wire.write(0x2b);

////// this is the pulse width...0-255 where 255 is all "on" for one cycle (1/clock frequency)

Wire.write(_iPwmVal);

///////////////////////////////////////////////////////////////////////////////////////////////

Wire.endTransmission();

}

Then in your main loop() you just use:

setPwmI2C ( the pin number that you want to control, the value from 0-255);

One thing to note about this method- the servo is expecting pulses from 1-2ms every 20ms. If we slow down the clock to 53 hz- that gives us the ~20ms cycle, but 0-255 gives pusle widths from zero all the way up to 20ms. So in order to send 1-2ms, your functional PWM range is only about 13 - 26! Depending on what you need, this range may be fine, but for more finite control, you can speed up the signal and increase the steps (125hz = range from 34-66.) As you increase the frequency, your servo will probably become less and less happy with you, so you can experiment to find a nice balance of happy servos and finite control.

ELabs
Novice
384 Views

I'm still confused as how to generate a PWM.

 

It would be great if you could explain clock, divider, period and duty to get a specific pwm say for example.

What values should I have for a PWM wave of frequency 45Hz and duty cycle of 6%.

Also I'm confused with AnalogWrite(pin,1) will enable the PWM on the pin.

AnalogWrite(pin,0) does not disable the pwm. How do I output PWM on more than one pins.

The cypress data sheet says you can enable output by setting bits on select pwm register (1Ah)

and then select the port using the port select register (18h)

Thanks

Lucas_A_Intel
Employee
384 Views

I'm not an expert on the Cypress chip, but I'll try to be helpful with the basic functionality for setting frequencies and duty cycles on multiple pins…

/

If you just use AnalogWrite(pinNumber, duty-cycle->0-255); it sends a PWM signal at the default frequency (~600Hz.) But if you want to change the frequency (at least for now,) you need to manually change the clock using Wire and I2C commands every time you use AnalogWrite.

/

To avoid repeating code, we wrote a function called setPwmI2C that we use in place of AnalogWrite that does pretty much the same thing, but at a lower frequency for servos. If we wanted to do it on multiple pins we'd write (for example)

/

loop(){

setPwmI2C( 5, 255); // sets pin 5 to 255 (100% duty cycle)

setPwmI2C( 9, 127); // sets pin 9 to 128 (~50% duty cycle)

// only pins 3,5,6,9,10,11

}

/

Since we only use SetPwmI2C to control a servo, the frequency is hard-coded in our function to ~62Hz. If you wanted to change the frequency on the fly, you could pass a third variable, frequencyDivider into your function.

/

Within the SetPWMI2C function-

/

First you call AnalogWrite to turn on a signal to your pin. The I2C commands overwrite the duty-cycle value you send to AnalogWrite, so you only use this to declare the pin you want to write to- it doesn't matter the value you send, because you overwrite it with I2C.

/

Then there's the I2C commands: Changing the order from the last post so it makes more sense (to me)

/

First select the clock you want to use. Cypress has 5 to choose from, but only one is "programmable," the one that's 367.6 Hz. The command below selects that one. (The first "write" is the address of the thing you want to control, the second "write" sets the value)

// Select programmable PWM CLK source

Wire.beginTransmission(0x20);

Wire.write(0x29);

Wire.write(0x04);

Wire.endTransmission();

 

Then the period register. I don't know what this does. Voodoo. I leave it alone.

 

// Set period register

Wire.beginTransmission(0x20);

Wire.write(0x2a);

Wire.write(0xff);

Wire.endTransmission();

 

Next is the frequency divider, and this is the only way I know of to control the final signal frequency. The main clock (367.6 Hz) is divided by this number to set the output frequency. I've tested up to 8- I don't know how slow you can go… but dividing by 2 = 184Hz, 3 = 123Hz, 4 = 91Hz, 5 = 74Hz, 6 = 61Hz, 7 = 53Hz, 8 = 46 Hz.

 

// Set divider to get the output frequency.

Wire.beginTransmission(0x20);

<p style="margin...
DJuan1
Novice
384 Views

Thanks for your codes, but when I run it in my Galileo, the pins which I call the function serPwmI2C() are out of control, for example, when i call setPwmI2C(3,128), in my oscilloscope, the frequency is not stable and the duty cycle jumped all the time. Even when I want to digitalWrite(3,HIGH) delay(10) digitalWrite(3,LOW) delay(10) in my loop later, the pin 3 is out of control ,it's duty cycle is 2.0-2.1% all the time although i changed the parameter of delay.

my code is as follow:

# include "Wire.h"

int pin=3;

void setup() {

// put your setup code here, to run once:

Wire.begin();

pinMode(pin,OUTPUT);

Serial.begin(9600);

}

void loop() {

// put your main code here, to run repeatedly:

setPwmI2C(pin,130);

}

void setPwmI2C(int _iPinNum, int _iPwmVal){

//copy your

}

Could you tell me why ?

LBarr11
New Contributor I
384 Views

You can also look in the supplied x86 Arduino libraries in the Servo.h and Servo.cpp files, or you may find the Servo class already implements the functions you need.

On my Mac, they are on the path (inside the App bundle) Java/hardware/arduino/x86/libraries/Servo.

They will be on similar paths in Windows or Linux.

ELabs
Novice
384 Views

Thanks Nuke.

 

I thought Servo wasn't implemented. Thats what I was trying to do. But unfortunately same code on a previous version of arduino IDE works perfectly with the servo but in Galileo same code produces a different PWM.

For example

Servo myservo;

myservo.write(90) produces a clean pwm with 1.5ms high and 20 ms low pulse

but the same thing produces 1.5ms high and 3.5ms low pulse.

This makes the servo go crazy and makes so much of noise.

I'll try to dig deeper in the library and see how I can change this.

Lawrence_B_Intel
Employee
384 Views

The way Servo on Galileo is implemented allows for two different repetition rates, either 188hz, the default, or 48hz, closer to what most servos operate on. The faster rate offers finer control of angle (pulse width), but as a downside, some servos don't like it and they make noise. The slower 48hz (47.4) has a periodic rate of 22.17ms, but since the PWM is only 8-bit, the step size is 86-µsec, or about 10 degrees. At the faster rate, the pulse control granularity is 20.7 µsec, or about 2-degrees, if your servo can handle it.

Look in the Servo.h header, you'll find the two functions:

void set48hz(); // forces cypress to work in 47.8 hertz

void set188hz(); // forces cypress to work in 188 hertz (better angle resolution)

Reply