1 2 Previous Next 24 Replies Latest reply on Mar 18, 2020 7:56 AM by KeLa_4479261

    PWM period and duty cycle configuration

    KeLa_4479261

      Good Evening:

       

      I have been using the PWM component with the PSOC 5LP prototyping kit.  I put in the period and then based on the number of cycles at 64Mhz, I put in the duty cycle.  My system is running at 64Mhz with an XTAL crystal.  After adjusting the period to compensate for GPIO toggles and overhead processing I remove the development kit from the USB and attach it to my breadboard.

       

      I have not been able to determine why the duty cycle, which appeared good on the PC, is off by usually 4 microseconds. At 64Mhz that is a lot of cycles that have either been added or subtracted from the PWM component.  The period stays constant by the Duty changes considerably.

       

      Does anyone know how to correct this issue.

       

      Please and thanks,

      Ken.

        • 1. Re: PWM period and duty cycle configuration
          MoTa_728816

          Hi,

           

          > My system is running at 64Mhz with an XTAL crystal. 

          I hope that you are using 8MHz XTAL and PLL to 64MHz, correct?

           

          As in the datasheet of CY8C58LP, the external crystal supposed to be between 4MHz and 25MHz.

          000-Datasheet.JPG

          Now assuming that your XTAL is fine.

           

          Then another thing I have often encountered is the period.

          If we need a 1000 cycle period, we must set the period to 999 (0 - 999 = 1000).

          So I wonder if the difference you are seeing is because of this.

           

          > The period stays constant by the Duty changes considerably.

          This does not sound right.

          But I have no idea except the off by one problem above.

           

          BTW, just another thing I often care about is...

          Are you stopping PWM before you set period?

          We can change duty during the PWM is running

          but changing period requires PWM to be stopped.

          So Please stop the PWM, write period (and/or duty), then enable (or restart) the PWM.

           

          moto

           

          • 2. Re: PWM period and duty cycle configuration
            KeLa_4479261

            Hello Motoo:

             

            The XTAL cyrstal is 8Mhz as per the allowed crystals.

             

            I am enclosing a snapshot of the PWM_1 block from the design, I am also using the one shot multi tirgger mode as you showed me before.

             

            The pwm output is driving the GPIO pin.  (picture included).

             

            The same PWM_1 block gives me two different duty cycles.

            When I am connected to the PC and capture the analog signal from LED1, duty cycle is:12.0203%

            When I am connected to my target and capture the analog signal form LED1, duty cycle is: 12.7310%

             

            Your help is appreciated, thanks,

            Ken.PWM_1_configure_page.JPGPWM_1_advanced_page.JPGCapture_wiring_block.JPG

            • 3. Re: PWM period and duty cycle configuration
              MoTa_728816

              Dear Ken-san,

               

              So you trigger PWM_1 from PSoC firmware via Control_Reg_1_Write(), right?

              Then time from isr_1 to Control_Reg_1_Write() may not be exactly same.

               

              To test it, can you connect a GPIO output from Control_Reg_1?

              I think that the duty after the trigger would be the same,

              but delay after the period to the next trigger may be different.

               

              Although I can not remember why PWM_1 needed to be triggered by the Control_Reg_1,

              if you can, could you also try to configure PWM_1 mode as continuous and measure if the period/duty changes?

              If the duty and period will be stable when configured as continuous mode, then the clock and PWM will be fine.

              (Which I hope so)

               

              Best Regards,

              14-Mar-2020

              Motoo Tanaka

              • 4. Re: PWM period and duty cycle configuration
                KeLa_4479261

                Helllo Motoo:

                 

                PWM_1 and PWM_2 are used to make a custom waveform that in turns on lights.  The timings, hence the XTAL 8Mhz, are so that I can get these times to the decimal microsecond.

                I am using two different blocks to generate the following:

                1) 60.5 + 432.2

                2) 62.7 + 429.7

                All times need to be accurate to the first decimal microsecond.  Because of this I use the control register to trigger the PWM as required.

                 

                Would a timer be a better option?

                 

                Please and thanks,
                Ken.

                • 5. Re: PWM period and duty cycle configuration
                  MoTa_728816

                  Dear Ken-san,

                   

                  If you set PWM mode Continuous, each of PWMs will generate accurate wave.

                   

                  But if you use the interrupt to notice the firmware and firmware isr will take care of re-starting that PWM,

                  there will be some time delay.

                  (In other words, using isr and control_reg, "Exact" timing will be very difficult or impossible)

                   

                  From the schematic I understand that you have 2 kinds of PWM to drive a LED.

                  I hope that only 1 of 2 is active at any time, correct?

                  Then what is the timing of changing the PWM source from PWM_1 to PWM_2 and so on?

                   

                  Best Regards,

                  15-Mar-2020

                  Motoo Tanaka

                  • 6. Re: PWM period and duty cycle configuration
                    KeLa_4479261

                    Hello Motoo:

                     

                    I am including a snippet of code that I use to build the Waveform pulse.  I toggle between two modes.  PWM_1 and PWM_2 as required.  The GPIO signal out is or'd and only one of the PWM blocks is activate at one time.

                     

                            for(cycles=0; cycles<5; cycles++)

                            {

                                for (signals=0; signals<SIGNALS-1; signals++)

                                {

                                    if (TABLES[table].on.waveform[signals] == ON)       

                                    {

                                        //trigger_ON_waveform();        PWM_1          

                                        trigger_for_ON();

                                        flag_on = 0;

                                        while(!flag_on);

                                    }

                                    else

                                    {

                                        //trigger_OFF_waveform();            PWM_2       

                                        trigger_for_OFF();

                                        flag_off = 0;

                                        while(!flag_off);

                                    }

                                }

                                //trigger_EOS_waveform;            PWM_2

                                trigger_for_OFF();

                                flag_off = 0;

                                while(!flag_off);

                                CyDelayUs(2970);               // interpulse delay.

                            }

                     

                    I am looking for suggestions on generate some waveforms that require accuracy to the hundreds of nano-seconds.

                     

                    Any ideas?

                    Please and thanks,

                    ken.

                    • 7. Re: PWM period and duty cycle configuration
                      MoTa_728816

                      Dear Ken-san,

                       

                      If the most important requirement is the accuracy of the PWM

                      probably using Control_Reg and ISR to control the PWM is not a good idea.

                       

                      I just made a sample, which is, with each time the sw is pushed

                      the program change the PWM mode between set1 and set2.

                      So that there is a some delay between swithing set1 and set2,

                      each waveform must be accurate.

                       

                      I wonder if you can allow this delay between switching the mode (set1 and set2).

                      If you can not, may be we can have 2 set of PWMs and logically enable and disable the output.

                      (but each PWMs will run in continuous mode)

                       

                      schematic

                      011-Schematic.JPG

                      pins

                      012-pins.JPG

                       

                      mian.c

                      ====================

                      #include "project.h"

                      #include "stdio.h"

                       

                      volatile int sw_pushed = 0 ;

                       

                      CY_ISR(sw_pushed_isr)

                      {

                          isr_sw_ClearPending() ;

                          sw_pushed = 1 ;

                      }

                       

                      #define STR_LEN 64

                      char str[STR_LEN+1] ;

                      void print(char *str)

                      {

                          UART_PutString(str) ;

                      }

                       

                      void cls(void)

                      {

                          print("\033c") ; /* reset */

                          CyDelay(20) ;

                          print("\033[2J") ; /* clear screen */

                          CyDelay(20) ;

                      }

                       

                      void splash(void)

                      {

                          cls() ;

                          print("PWM Test ") ;

                          snprintf(str, STR_LEN, "(%s %s)\n\r", __DATE__, __TIME__) ;

                          print(str) ;

                      }

                       

                      void init_hardware(void)

                      {

                          CyGlobalIntEnable; /* Enable global interrupts. */  

                          UART_Start() ;

                          splash() ;

                        

                          PWM_1_Start() ;

                        

                          isr_sw_StartEx(sw_pushed_isr) ;

                      }

                       

                      void set_pwm(uint16_t period, uint16_t compare)

                      {

                          PWM_1_Stop() ;

                          PWM_1_WritePeriod(period) ;

                          PWM_1_WriteCompare(compare) ;

                          PWM_1_Enable() ;

                      }

                       

                      int main(void)

                      {

                          int mode = 0 ;

                        

                          init_hardware() ;

                       

                          for(;;)

                          {

                              if (sw_pushed) {

                                  if (mode == 0) {

                                      set_pwm(4322+605, 605) ;

                                      mode = 1 ;

                                      print("Mode: 1\n\r") ;

                                  } else {

                                      set_pwm(4297+627, 527) ;

                                      mode = 0 ;

                                      print("Mode: 0\n\r") ;

                                  }

                                  sw_pushed = 0 ;

                              }

                          }

                      }

                      ====================

                       

                      Tera Term log

                      010-TeraTerm-log.JPG

                      Best Regards,

                      15-Mar-2020

                      Motoo Tanaka

                      P.S. Oops, I forgot to attach the project

                      • 8. Re: PWM period and duty cycle configuration
                        MoTa_728816

                        Dear Ken-san,

                         

                        I was busy writing the sample and missed the last comment.

                         

                        It seems that you have exact sequence of Frequency Mode.

                         

                        Since it's after 1:00 AM here, let me read and think about it tomorrow.

                         

                        But meantime, please try my sample

                        and think if you can just re-configure the PWM

                        or you need a couple of PWMs to be switched.

                         

                        Best Regards,

                        15-Mar-2020

                        Motoo Tanaka

                        • 9. Re: PWM period and duty cycle configuration
                          MoTa_728816

                          Dear Ken-san,

                           

                          So I assumed that the change(s) of duty was caused by the various delay of the firmware.

                          Although there should be ways of doing it only by hardware,

                          doing it with hardware and ISR seems to be easier and simpler.

                           

                          So I did the following sample.

                          Could you test if the duty is more stable or not?

                           

                          schematic

                          020-schematic-1.JPG

                          pins

                          022-pins.JPG

                          main.c

                          Note: To simplify the hardware and isr, I assumed that the last signal is included in the last index of waveform.

                          =================

                          #include "project.h"

                          #include "stdio.h"

                           

                          #define NUM_CYCLES  5

                          #define NUM_SIGNALS 5

                          #define ON_VALUE    1u

                          #define OFF_VALUE   2u

                           

                          // for Next_Signal Control_Register

                          #define FW_TRIG_BIT 0x01

                          #define ON_BIT      0x02

                          #define OFF_BIT     0x04

                           

                          volatile int signal_index = 0 ;

                           

                          //TABLES[table].on.waveform[signals]

                          int waveform[NUM_SIGNALS] = { ON_VALUE, OFF_VALUE, ON_VALUE, OFF_VALUE, OFF_VALUE } ; /* test data */

                          volatile int cycle_busy = 1 ;

                           

                          CY_ISR(pwm_on_isr)

                          {

                              PWM_1_ReadStatusRegister() ;

                              signal_index++ ;

                              if (signal_index >= NUM_SIGNALS) {

                                  cycle_busy = 0 ;

                              } else {

                                  if (waveform[signal_index] == ON_VALUE) {

                                      Next_Signal_Write(ON_BIT | FW_TRIG_BIT) ;

                                      Next_Signal_Write(0x00) ;

                                  } else {

                                      Next_Signal_Write(OFF_BIT | FW_TRIG_BIT) ;

                                      Next_Signal_Write(0x00) ;

                                  }

                              }

                          }

                           

                          CY_ISR(pwm_off_isr)

                          {

                              PWM_2_ReadStatusRegister() ;

                              signal_index++ ;

                              if (signal_index >= NUM_SIGNALS) {

                                  cycle_busy = 0 ;

                              } else {

                                  if (waveform[signal_index] == ON_VALUE) {

                                      Next_Signal_Write(ON_BIT | FW_TRIG_BIT) ;

                                      Next_Signal_Write(0x00) ;

                                  } else {

                                      Next_Signal_Write(OFF_BIT | FW_TRIG_BIT) ;

                                      Next_Signal_Write(0x00) ;

                                  }

                              }   

                          }

                           

                          #define STR_LEN 64

                          char str[STR_LEN+1] ;

                          void print(char *str)

                          {

                              UART_PutString(str) ;

                          }

                           

                          void cls(void)

                          {

                              print("\033c") ; /* reset */

                              CyDelay(20) ;

                              print("\033[2J") ; /* clear screen */

                              CyDelay(20) ;

                          }

                           

                          void splash(void)

                          {

                              cls() ;

                              print("PWM Test ") ;

                              snprintf(str, STR_LEN, "(%s %s)\n\r", __DATE__, __TIME__) ;

                              print(str) ;

                          }

                           

                          void init_hardware(void)

                          {

                              CyGlobalIntEnable; /* Enable global interrupts. */   

                              UART_Start() ;

                              splash() ;

                             

                              PWM_1_Start() ;

                              PWM_2_Start() ;

                             

                              isr_1_StartEx(pwm_on_isr) ;

                              isr_2_StartEx(pwm_off_isr) ;

                          }

                           

                          void set_pwm(uint16_t period, uint16_t compare)

                          {

                              PWM_1_Stop() ;

                              PWM_1_WritePeriod(period) ;

                              PWM_1_WriteCompare(compare) ;

                              PWM_1_Enable() ;

                          }

                           

                           

                          int main(void)

                          {

                              int cycles = 0 ;

                             

                              init_hardware() ;

                           

                              for(;;) {

                                  for (cycles = 0 ; cycles < NUM_CYCLES ; cycles++ ) {

                                      signal_index = 0 ;

                                      cycle_busy = 1 ;

                                      /* firmware takes care of the first signal */

                                      if (waveform[signal_index] == ON_VALUE) {

                                          Next_Signal_Write(ON_BIT |  FW_TRIG_BIT) ;

                                      } else {

                                          Next_Signal_Write(OFF_BIT | FW_TRIG_BIT) ;

                                      }

                                      Next_Signal_Write(0x00) ;

                                      /* signal_index 2 to the last will be taken care of by hardware */

                                      while(cycle_busy) ;

                                      CyDelayUs(2970) ;

                                  }

                              }

                          }

                          =================

                           

                          Best Regards,

                          15-Mar-2020

                          Motoo Tanaka

                          • 10. Re: PWM period and duty cycle configuration
                            KeLa_4479261

                            Hello Motoo:

                             

                            Testing just commenced.

                             

                            Thank you,

                            Ken.

                            • 11. Re: PWM period and duty cycle configuration
                              KeLa_4479261

                              Hello Motoo:

                               

                              I have tested your archive example and the hardware solution provides repeatable results.

                               

                              Testing on PC with prototyping kit, tweaked the PWM to 60.3 microseconds ON + 432.2 microseconds OFF.  I processed 30 million samples and found that the drift was restricted to 500 nanoseconds.  PERFECT.

                               

                              I then took the prototype board and plugged it into the working customer target.  I processed 30 million samples and found that the drift was restricted to 500 nanoseconds.

                              PROBLEM:  The PWM block is now providing me with 56.7 microsecond ON + 435.7 microsecond OFF.

                               

                              The period is is identical in both the samples from the PC and the customer's target. 

                               

                              Do you have any idea why the ON / OFF times have drifted this far?

                               

                              Please and thanks.

                              Ken.

                              • 12. Re: PWM period and duty cycle configuration
                                MoTa_728816

                                Dear Ken-san,

                                 

                                When we run the board with PC, especially with debugger,

                                there is/are communication between the board and PC

                                which affect the time of the main loop in the main() function.

                                 

                                But this time all the necessary handling is done in ISRs

                                so the timing is not (or should not be) affected by other

                                activity in the program.

                                 

                                > PROBLEM:  The PWM block is now providing me with 56.7 microsecond ON + 435.7 microsecond OFF.

                                As I wrote above may be some uart communication and/or debug communication

                                between PC and Board is causing this difference.

                                 

                                I wonder if the numbers shown in the standalone configuration is closer to the calculated value?

                                (If so you need to adjust the PWM period/compare to fit with the standalone configuration.)

                                 

                                Best Regards,

                                16-Mar-2020

                                Motoo Tanaka

                                • 13. Re: PWM period and duty cycle configuration
                                  LePo_1062026

                                  Ken,

                                   

                                  I've been trying to follow this discussion.   I hope I didn't misunderstand it.

                                   

                                  It looks from the information you have shared with this forum that you are SW triggering each PWM cycle.  If this is true, you might be exhibiting a SW latency issue that varies with PWM period.  This variance can be because you are processing interrupts (such as communication) and they occur asynchronously.  Due to this asynchronicity the latency can be erratic and not always predictable.

                                   

                                  Is there a way to modify your design to eliminate the external triggering of the PWMs?   Even if you were to temporarily change the PWMs to continuous mode just to verify that the XTAL clock source is NOT the root cause of the problem of duty-cycle variance.

                                   

                                  Len

                                  • 14. Re: PWM period and duty cycle configuration
                                    KeLa_4479261

                                    Good Morning:

                                     

                                    With the example from Motoo's note I have been able to reproduce my waveform exactly.  The microsecond accuracy is repeatable.

                                     

                                    As he suggested, trigger the waveform in software, and let the hardware block do the rest.  I do have to adjust the duty cycle slightly but with the hardware version I can reproduce a waveform that is useable. 

                                     

                                    I have put this into continuous mode and my XTAL 8Mhz, 30ppm crystal is producing timings to the nanoseconds.

                                     

                                    Testing is still ongoing and I am getting closer to a solution.

                                     

                                    Regards,

                                    Ken.

                                    1 2 Previous Next