Capturing time PSoC4 using a timer

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
EfAv_4380776
Level 1
Level 1

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!!

0 Likes
1 Solution
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

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

View solution in original post

5 Replies
lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

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

0 Likes

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!!

0 Likes

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:

pastedImage_0.png

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

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

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

lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

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

0 Likes