10 Replies Latest reply on Oct 16, 2019 6:05 AM by LePo_1062026

    PWM duty cycle + freq measurement


      I followed this thread: https://community.cypress.com/servlet/JiveServlet/download/134688-28018/Pulse%20Width%20and%20Period%20Measurement%20Met… and use this example on PSoC 5 (using CYKIT-059). I checked that PWM ~1kHZ and removed from code lcd display and add UARt  TX component to see output. When capturing I get strange values like:























      any ideas how to check that? I also plan to monitor 5 PWm input signals is there enough resources on this dev board? Thanks.





        • 1. Re: PWM duty cycle + freq measurement



          I just downloaded the project and will get back to you if I can reproduce your results.


          Is this your application design?


          I noticed you are using a 16bit counter with a 100KHz clock.  This means the count value wraps back to 0 every 65536/100000 = 0.65536 seconds.  I see there is counter rollover compensation.  Therefore this shouldn't be an issue if your frequency is not too slow.


          "I also plan to monitor 5 PWm input signals is there enough resources on this dev board?"

          Using an ISR for each PWM input you could support an infinite number of inputs.  You're only limited by the CPU processing frequency and RAM resources.



          • 2. Re: PWM duty cycle + freq measurement



            FYI, in the following topic, I tried something similar.

            PSoC 5LP Duty Cycle


            But I'm afraid that my approach won't allow you to measure 5 PWMs.



            • 3. Re: PWM duty cycle + freq measurement

              Hi Len,


              I've pushed modified project here: Pulse Width Period Dutry Cycle.zip - Google Drive

              it's original project where there is 1kHz pwm generator and for capturing I'm getting this strange results. I'm not sure yet if I need to monitor them in parallel or not but thanks for hint.


              For monitoring values I connected USB->serial converter (TX ping is P1.7) and GND and get this values. Also duty cycle is 0 which is not good. Thanks.



              • 4. Re: PWM duty cycle + freq measurement

                Thanks. I think original approach should work just there is some issue why it's not working always. Anyway thanks for sharing.



                • 5. Re: PWM duty cycle + freq measurement



                  I've modified the original program intended for the 050 eval board with LCD for your 059-KIT and the USB-UART.


                  Here is a summary of the modifications:

                  • I added 4 additional stimulus sources
                    • (see the schematic snippet below).  The stimulus outputs are on P3.0, P3.1, P3.2 and P3.3.  The original test stim is on P0.7.

                  • I deleted the LCD code references and added the UART calls to the USB_UART.
                  • I converted the ISR calls to cyapicallbacks.  I believe this is a 'safer' way to implement component level ISRs.


                  When you were performing your original measurements, were you externally connecting the test stim output (P0.7) to the pulse monitor input (P0.5)?   I get similar 'floating' reads if I don't connect P0.5 to a stimulus source.   Otherwise, when I connect the 5 stimulus sources to P0.5 (one at a time) I get a reasonably value period and duty cycle.



                  • If the output frequency is too close to the sampling frequency (100KHz), the SW can't keep up reliably.  As I get closer to the sampling frequency, the period is not as accurate.  Eventually as the measure frequency is much nearer the sampling frequency, the SW appears to lockup (spending too much time in the ISRs) until I open up the input or switch to another slower stimulus.
                  • If the output frequency is too low, the wrap-around effect appears to become more significant and the period is not correct and/or the duty cycle reads greater than 100% which is definitely wrong.


                  Attached is my modified code if you want to check it out.


                  If you need to support frequency/period and duty-cycle measurements with more accuracy and reliability, you should set up HW counters with capture inputs.  This allows the Counter HW to save the count value on the capture edge.  Using the SW ISRs as being used in the project, is good if the inputs are relatively slow (not too slow) and you can support all the inputs you need with enough CPU speed.


                  Using the capture counters allow for more accurate results.  This is because the counter count is loaded into a FIFO storage at the edge of capture.   This lowers CPU usage and since there are four FIFO'd capture counts, the time criticality is not as bad.  Using the ISRs means that the CPU tries to read the counter value as quickly as possible but the count might advance before the CPU can read it in the ISR.



                  • 6. Re: PWM duty cycle + freq measurement



                    OK, I tried with your strategy.


                    To take care of roll over I added another interrupt for TC



                    As I want to have ISRs in my source file I modified main.c as below


                    #include <project.h>

                    #include <stdio.h>

                    #include <stdlib.h>

                    #include <cytypes.h>


                    volatile uint16 PulseHighTime      = 0; // pulsetime capture

                    volatile uint16 PulsePeriodStart    = 0; // period time capture start

                    volatile uint16 PulsePeriodEnd      = 0; // period time capture end


                    volatile uint8 flgPerdstart        = 0;    // Flag indicating + edge of pulse in has occured

                    volatile uint8 flgPerdend          = 0;    // Flag indicating + edge of next pulse has occured, signifying end of pepriod


                    char dispbuff[8];                        // LCD display buffer 8 bytes long

                    uint8 lenstrg;                        // result of string length

                    uint8 i                            = 0; // loop index

                    float dutycycle                    = 0.0;  // Variable to hold duty cycle computation

                    float pulseperd                    = 0.0;  // Pulse period in mS


                    uint16 perdcalc                    = 0;    // Intermediate value to aid in period measurement

                    float dutycalc                      = 0;    // Intermediate value to aid in duty cycle measurement


                    volatile uint32_t tc_count                    = 0 ;

                    volatile uint32_t duty_count                  = 0 ;

                    volatile uint32_t duty_tc                    = 0 ;

                    uint32_t          duty_cycle                  = 0 ;

                    volatile uint32_t period_count                = 0 ;

                    volatile uint32_t period_tc                  = 0 ;

                    uint32_t          period_cycle                = 0 ;

                    volatile int      measuring                  = 0 ;

                    #define STR_LEN 128

                    char              str[STR_LEN+1] ; /* print buffer */




                        Counter_ReadStatusRegister() ;

                        tc_count++ ;





                        PeriodISR_ClearPending() ;

                        if (measuring) { /* end measure */

                            period_count = Counter_ReadCounter() ;

                            period_tc    = tc_count ;

                            measuring = 0 ;

                            Counter_Stop() ;

                            Counter_WriteCounter(0) ;

                        } else {        /* start measure */

                            measuring = 1 ;

                            tc_count = 0 ;

                            Counter_Enable() ;






                        PulsehiISR_ClearPending() ;

                        if (measuring) {

                            duty_count = Counter_ReadCounter() ;

                            duty_tc = tc_count ;




                    int main()


                        int prev_measuring = 0 ;

                        uint16_t period  ;


                        UART_Start() ;


                        PeriodISR_StartEx(rising_isr);    // Start period time ISR

                        PulsehiISR_StartEx(falling_isr);    // Start high pulse time ISR

                        isr_tc_StartEx(counter_tc_isr) ;        // tc counter ISR

                        Counter_Init();                // Init measurement counter, but not start


                        CyGlobalIntEnable;                      // Uncomment this line to enable global interrupts


                        UART_PutString("Period, High, Duty\n") ;


                        for(;;) {                // Infinite for-loop

                            if ((prev_measuring == 1)&&(measuring == 0)) { // measuring done

                                period = Counter_ReadPeriod() ;

                                period_cycle = (period - period_count) + period_tc * period ;

                                duty_cycle    = (period - duty_count) -  duty_tc * period ;

                                snprintf(str, STR_LEN, "Cycle = %d ", period_cycle) ;

                                UART_PutString(str) ;

                                snprintf(str, STR_LEN, "High = %d ", duty_cycle) ;

                                UART_PutString(str) ;

                                snprintf(str, STR_LEN, "Duty = %d.%02 %\n",

                                    100 * duty_cycle / period_cycle,

                                    (10000 * duty_cycle / period_cycle) % 100

                                ) ;

                                UART_PutString(str) ;




                    prev_measuring = measuring ;

                        } // end of infinity for-loop


                    i='F'; //  for debugging only

                    } // end of main



                    Then when I ran with Clock_1 = 1kHz, I got around 21.0%, although expected 25.0%


                    Then I changed Clock_1 to 1MHz, the duty is now 24.0% (getting close to 25.0%)


                    Then I tried Clock_1 = 12MHz, but duty accuracy did not get improved



                    So I think that either the ramp slope of the signal or the overhead of isr()s makes the accuracy not as good.

                    The sample I posted in the earlier response had accuracy of .01 % but required much more resource(s).


                    Attached is your project with my modification.



                    • 7. Re: PWM duty cycle + freq measurement



                      Make sure you connect P0.7 (test stimulus output) to the input P0.5 (PWMxIN) externally.  The results you posted might be a floating P0.5.  One way to confirm this is to configure PWMxIN as an input with pull-up or pull-down.  If PWMxIN is left unconnected, then the output will always be constant.



                      • 8. Re: PWM duty cycle + freq measurement



                        thanks for update. Hmm I didn't have anything connected on P0.5 (PWM input). I think test generator from P0.7 would be used for that purpose? But I have no clue how to connect those 2 pins.  But when put input signal from external PWM to P0.5 then it works . Thanks a lot.



                        • 9. Re: PWM duty cycle + freq measurement



                          OK this works then but when PWM is not at input then program report random values. I think maybe code should be extended that if IRQ is not happening then disable capturing or is there other way how to detect if signal is present on pin? Thanks.

                          • 10. Re: PWM duty cycle + freq measurement



                            A floating P0.5 input.  That would explain the results.


                            Since you are using the CY8CKIT-059, see the diagram below.  (Note:  In this case, GND is already internally connected on the Kit)


                            I'm glad you got it working.



                            1 of 1 people found this helpful