10 Replies Latest reply on Feb 25, 2014 8:51 PM by Don_Fantom_Juan

    PWM on Galileo board in an arduino sketch

    eselabs@penn

      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

        • 1. Re: PWM on Galileo board in an arduino sketch
          ado

          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

          • 2. Re: PWM on Galileo board in an arduino sketch
            eselabs@penn

            Sorry to get back late on this.

            I'm using a continuous rotation servo from parallax 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);

                Wire.write(0x2B);

                Wire.write(0x12);

                Wire.endTransmission();  

             

                delay(1000);  

                analogWrite(PIN2,254);

                //stop

                //Duty-Cycle = PulseWidth/Period

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

                Wire.beginTransmission(0x20);

                Wire.write(0x2B);

                Wire.write(0x12);

                Wire.endTransmission();

              

            //rotate servo 1 clockwise

                analogWrite(PIN1,1);

                //full speed clockwise

                //Duty-Cycle = PulseWidth/Period

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

                Wire.beginTransmission(0x20);

                Wire.write(0x2B);

                Wire.write(0x14);

                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 servo2 clockwise

             

             

                analogWrite(PIN2,1);

                //full speed clockwise

                //Duty-Cycle = PulseWidth/Period

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

                Wire.beginTransmission(0x20);

                Wire.write(0x2B);

                Wire.write(0x14);

                Wire.endTransmission();

                

                delay(1000);

                analogWrite(PIN2,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);

             

            }

            • 3. Re: PWM on Galileo board in an arduino sketch
              eselabs@penn

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

              • 4. Re: PWM on Galileo board in an arduino sketch
                LucasAinsworth

                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.

                1 of 1 people found this helpful
                • 5. Re: PWM on Galileo board in an arduino sketch
                  eselabs@penn

                  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

                  • 6. Re: PWM on Galileo board in an arduino sketch
                    LucasAinsworth

                    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);

                      Wire.write(0x2C);

                      Wire.write(frequencyDivider);

                       Wire.endTransmission();


                    Finally, the last I2C command sets the duty cycle from 0-255.


                    // Set duty cycle

                      Wire.beginTransmission(0x20);

                      Wire.write(0x2b);

                      Wire.write(dutyCycle);

                      Wire.endTransmission();

                     

                    So to send a signal at 46Hz and 6% duty cycle, you’d set the frequencyDivider to 8, and the duty cycle to 255 * 6% = ~15

                    • 7. Re: PWM on Galileo board in an arduino sketch
                      nuke

                      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.

                      • 8. Re: PWM on Galileo board in an arduino sketch
                        eselabs@penn

                        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.

                        • 9. Re: PWM on Galileo board in an arduino sketch
                          larrysb

                          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)

                          • 10. Re: PWM on Galileo board in an arduino sketch
                            Don_Fantom_Juan

                            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 ?