5 Replies Latest reply on Oct 8, 2020 9:30 PM by MoTa_728816

    Capturing time PSoC4 using a timer

    EfAv_4380776

      Hello I need to measure a signal's period to calculate heartbeat.

      In order to achieve that, I'm trying to capture the time when the signal crosses the average of the signal so I can compare it with the next time it crosses the average and so on.

       

      In Arduino I could use the function "millis" for that. For PSoC, I've read I'd need to install "millis.h" and "millis.c" but I haven't found those files.
      Next, I read I can use a timer on continuous mode, here's where I get lost.

       

      I understand I need to connect a 1kHz clock to the timer's clock input so the timer count changes up/down every 1ms. Then I get lost.

       

      should I just use something like "uint32 currentCount = Timer_ReadCounter();"?

       

       

      I need it to run freely and store in a variable the time in ms in order to compare. How can I achieve that?

       

      Thanks!!

        • 1. Re: Capturing time PSoC4 using a timer
          MoTa_728816

          Hi,

           

          If all you need is ms order timing, I would recommend to use "SysTick".

          As it is already included in the Cortex-M and using it will not consume additional hardware resource.

          (IMHO, and also it is easier to use)

           

          So I made a sample project using CY8CKIT-044 (CY8C4247AZI-M485).

          As I don't have heartbeat sensor right now, I used the switch on the board.

          Every time the switch is pushed, ms count from the previous push will be printed to the serial output.

          And LED on the board toggles.

           

          Tera Term log

          001-TeraTerm-log.JPG

           

          schematic

          Note: To use "SysTick" none of the component below is necessary,

          but to make testing easier I added them.

          002-schematic.JPG

          Pins

          003-Pins.JPG

           

          main.c

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

          #include "project.h"

          #include "stdio.h"

           

          #define STR_LEN 64

          char    str[STR_LEN+1] ;

          void    print(char *str)

          {

          UART_UartPutString(str) ; /* PSoC 4 */

          // UART_PutString(str) ;     /* PSoC 5 */

          }

           

          void cls(void)

          {

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

              CyDelay(20) ;

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

              CyDelay(20) ;

          }

           

          void splash(char *prog_name)

          {

              cls() ;

              if (prog_name && *prog_name) {

                  print(prog_name) ;

              }

              print(" (") ;

              print(__DATE__) ;

              print(" ") ;

              print(__TIME__) ;

              print(")\n") ;

          }

           

          volatile uint32_t sw_tick_count = 0 ;

          volatile uint32_t sw_interval = 0 ;

          volatile int      sw_flag = 0 ;

           

          CY_ISR(SysTick_ISR)

          {

              sw_tick_count++ ;

          }

           

          int find_empty_slot(void)

          {

              int result = -1 ;

              uint32_t i ;

              for (i = 0 ; i < CY_SYS_SYST_NUM_OF_CALLBACKS ; i++ ) {

                  if (CySysTickGetCallback(i) == NULL) {

                      result = i ;

                      break ;

                  }

              }

              return(result) ;

          }

           

          CY_ISR(sw_isr)

          {

              sw_interval = sw_tick_count ;

              sw_tick_count = 0 ;

              sw_flag = 1 ;

              SW_ClearInterrupt() ;

          }

           

          void init_hardware(void)

          {

              CyGlobalIntEnable; /* Enable global interrupts. */

              UART_Start() ;

             

              sw_push_int_ClearPending() ;

              sw_push_int_StartEx(sw_isr) ;

          }

                 

          int main(void)

          {  

              int sys_tick_slot = 0 ;

             

              init_hardware() ; 

              splash("Interval Time Test using SysTick") ;

             

              sys_tick_slot = find_empty_slot() ;

              if (sys_tick_slot < 0) {

                  while(1) { } /* halting here */

              } else {

                  CySysTickStart() ;

                  CySysTickSetCallback(sys_tick_slot, SysTick_ISR) ;

              }

             

              CySysTickStart();

                   

              for(;;)

              {

                  if (sw_flag) {

                      snprintf(str, STR_LEN, "%d ms\n\r", sw_interval) ;

                      print(str) ;

                      LED_Write(!LED_Read()) ;

                      sw_flag = 0 ;

                  }

              }

          }

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

           

          moto

          • 2. Re: Capturing time PSoC4 using a timer
            EfAv_4380776

            Thanks for your answer!!

            Unfortunately for me, I don't understand much of the code you posted.
            Could you help me with my failed attempt?

             

            I'm trying to set up a timer, with a 1kHz clock it will count each 1ms without needing any triggers to start and it will run continuously.
            Then when I need to capture the time an event occurs on my signal of interest, I'd just call some macro of my timer to store how many ms has it counted so far.

             

            This is the code I'm trying but I don't get any value from contador_ms on my UART terminal.

             

             

            #include "project.h"

            #include <stdio.h>

             

            char uartline[250]; //caracteres para enviar por UART

            float contador_ms=0;

             

            int main(void){

              

                 CyGlobalIntEnable;

                 Timer_Start();

                UART_Start();

                UART_PutString("Comunicacion UART establecida correctamente");

                UART_PutCRLF();

             

                    contador_ms=Timer_ReadCapture();

                    sprintf(uartline,"El tiempo es %f",contador_ms);

                    UART_PutString(uartline); //Se imprime el contenido que llene en uartline

                    UART_PutCRLF();  //Se limpia uart

             

            }

             

            Thanks!!

            • 3. Re: Capturing time PSoC4 using a timer
              MiAu_3808196

              I do a similar thing to you for measuring the frequency of a sinusoidal signal - I'm measuring the time between zero crossings and calculating frequency from that. I use a Timer set up as follows to do this:

               

               

              This is then how I do it:

              1. I have an interrupt routine that gets triggered each time I detect a zero crossing.  This grabs the current count in my timer each time it is called

              2. Start my timer in readiness to do a measurement

              3. Wait for zero crossing to trigger my ISR.  In that ISR, I do this: TimeStart = Counter_ReadCounter();  This stores the count in my timer when the first zero-crossing occures

              4.  Wait for the next zero crossing.  I then do: TimeStop = Counter_ReadCounter();

              5.  I can then calculate the period by doing period = TimeStop - TimerStart;

              6.  Stop my timer and get ready for next time I need to do a measurement

              • 4. Re: Capturing time PSoC4 using a timer
                MoTa_728816

                Hi,

                 

                >This is the code I'm trying but I don't get any value from contador_ms on my UART terminal.

                There are some points you need to be aware of.

                Let's talk with your code.

                 

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

                #include "project.h"

                #include <stdio.h>

                 

                char uartline[250]; //caracteres para enviar por UART

                float contador_ms=0; // (A)

                 

                int main(void){

                 

                     CyGlobalIntEnable;

                     Timer_Start();

                    UART_Start();

                    UART_PutString("Comunicacion UART establecida correctamente");

                    UART_PutCRLF();

                 

                        contador_ms=Timer_ReadCapture(); // (B)

                        sprintf(uartline,"El tiempo es %f",contador_ms); // (C)

                        UART_PutString(uartline); //Se imprime el contenido que llene en uartline

                        UART_PutCRLF();  //Se limpia uart

                // (D)

                }

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

                 

                (A) Since the value type returned by the counter is an integer, you should use int or uint for the type of conador_ms.

                (B) Timer_ReadCapture() returns the "Captured" value, to make this value valid, you need to configure the timer "Capture" mode.

                     And after the Capture Event, you will get some reasonable value.

                     For the time being, if you want to test reading something from the Timer, may be you can use Timer_ReadCounter()

                (C) If you want to handle "%f", you need some additional setups in your project.

                     Please refer to a KBA (Knowledge Base Article) KBA231059

                Printing floating-point values in PSoC Creator - KBA231059

                     Or my old meme

                printf and float rhapsody (aka, yet another printf and floating topic)

                (D) Since you are in the wild "Embedded" world, you should not end main().

                     In the embedded programming without an OS, main() should have a style of

                 

                int main(void)

                {

                     /* initialization */

                     /* first or only 1 time execution process */

                 

                    /* infinite loop */

                   for (;;) {

                   }

                }

                 

                So the summary of this response, I would ask you to try below to see if it works or not

                (1) Change "float" to "int" or "uint16"

                (2) Change "%f" to "%d"

                (3) Add following line at the blank place of (D)

                for (;;) {

                }

                 

                So it will look like

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

                #include "project.h"

                #include <stdio.h>

                 

                char uartline[250]; //caracteres para enviar por UART

                int contador_ms=0; // (A)

                 

                int main(void){

                 

                     CyGlobalIntEnable;

                     Timer_Start();

                    UART_Start();

                    UART_PutString("Comunicacion UART establecida correctamente");

                    UART_PutCRLF();

                 

                        contador_ms=Timer_ReadCapture(); // (B)

                        sprintf(uartline,"El tiempo es %d",contador_ms); // (C)

                        UART_PutString(uartline); //Se imprime el contenido que llene en uartline

                        UART_PutCRLF();  //Se limpia uart

                // (D)

                     for (;;) {

                     }

                }

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

                 

                moto

                 

                 

                1 of 1 people found this helpful
                • 5. Re: Capturing time PSoC4 using a timer
                  MoTa_728816

                  Hi,

                   

                  After posting my previous response,

                  I tried using Timer/Counter (TCPWM) with CY8CKIT-044.

                  Again, I used the SW on the board as the trigger.

                   

                  The serial output looks like below.

                  When I don't push the switch more than 2.5sec, "." are printed.

                  And when I push the switch, time from the previous push is printed.

                  010-TeraTerm-log.JPG

                   

                  schematic

                  Note: I use the signal from the SW for capture and reload.

                  011-Schematic.JPG

                  Counter Config

                  012-Counter_config1.JPG

                   

                  Note: The switch on the board is low-active, so I set Mode of reload and capture as "Falling edge".

                  If you connect these pins to a high-active module, please set them to "Rising edge"

                  I also enabled Interrupt for "On compare/capture count"

                  I set the Period 2500, as you configured so, but may be it could be set longer.

                  013-Counter_Config2.JPG

                   

                  pins

                  014-Pins.JPG

                   

                  main.c

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

                  #include "project.h"

                  #include "stdio.h"

                   

                  #define STR_LEN 64

                  char    str[STR_LEN+1] ;

                  void    print(char *str) ;

                  void    cls(void) ;

                  void    splash(char *prog_name) ;

                   

                  volatile int capture_flag = 0 ;

                  volatile uint16_t count ;

                   

                  CY_ISR(counter_isr)

                  {

                      uint32_t interrupt_source ;

                      interrupt_source = Counter_GetInterruptSource() ;

                      if (interrupt_source & Counter_INTR_MASK_TC) { /* timer over flow */

                          capture_flag = -1 ; /* counter overflow, not a valid count */

                      }

                      if (interrupt_source & Counter_INTR_MASK_CC_MATCH) { /* capture event! */

                          count = Counter_ReadCapture() ;

                          capture_flag = 1 ;

                      }

                      Counter_ClearInterrupt(interrupt_source) ;

                  }

                   

                  void init_hardware(void)

                  {

                      CyGlobalIntEnable; /* Enable global interrupts. */

                   

                      UART_Start() ;

                     

                      isr_1_ClearPending() ;

                      Counter_ClearInterrupt(Counter_INTR_MASK_TC|Counter_INTR_MASK_CC_MATCH) ;

                      isr_1_StartEx(counter_isr) ;

                     

                      Counter_Start() ;

                  }

                   

                  int main(void)

                      init_hardware() ;

                   

                      splash("Interval Time Test using TCPWM") ;

                   

                      for(;;)

                      {

                          if (capture_flag) {

                              if (capture_flag > 0) { /* valid capture count */

                                  snprintf(str, STR_LEN, "%d ms\n\r", count) ;

                                  print(str) ;

                              } else { /* capture time overflow */

                                  print(".") ;

                              }

                              capture_flag = 0 ;

                          }

                      }

                  }

                   

                  void    print(char *str)

                  {

                      UART_UartPutString(str) ; /* PSoC 4 */

                  // UART_PutString(str) ;     /* PSoC 5 */

                  }

                   

                  void cls(void)

                  {

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

                      CyDelay(20) ;

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

                      CyDelay(20) ;

                  }

                   

                  void splash(char *prog_name)

                  {

                      cls() ;

                      if (prog_name && *prog_name) {

                          print(prog_name) ;

                      }

                   

                      print(" (") ;

                      print(__DATE__) ;

                      print(" ") ;

                      print(__TIME__) ;

                      print(")\n") ;

                  }

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

                   

                  moto