Measuring a signal using GPT

Hi all,

Maybe it's a silly question, but I've been stuck for several days and I think I need help.

I am using TB-S3A6. I have written a small program that generates a frequency of 420kHz using the GPT162 and outputs at the P500 pin. This works well.

On the other hand, I want to measure the time between the activation of an output (P015) and the positive edge of a signal that enters through P104 (using GPT321):

 
Green: output / Blue: input

Basically, I activate the output, I start the timer, I wait 500 msg and I am going to read the counter (the positive edge has already been received and the counter must be stopped). The problem is that the counter must not stop and I always read the value corresponding to the software delay.

This is the hal_entry.c file:

--------------------------------------------------------------------------------------------------------------------
/* HAL-only entry function */
#include "hal_data.h"

#define BINH IOPORT_PORT_00_PIN_14
#define INI_PUL IOPORT_PORT_00_PIN_15
#define ECHO_INPUT IOPORT_PORT_01_PIN_04

// VARIABLES -------------------------------------------------------------------
ssp_err_t ssp_err; // Error.

static gpt_instance_ctrl_t *gp_ctrl; // Puntero a instancia de control GPT.
static R_GPTB0_Type *gp_gpt321; // Puntero a registros GPT1.
static R_GPTB0_Type *gp_gpt162; // Puntero a registros GPT2.
static timer_size_t contadorUS; // Contiene los ticks entre el pulso transmitido y el recibido.

// -----------------------------------------------------------------------------

void hal_entry(void)
{
/* Se abre el timer 162 para sacar 420 kHz por P500. */
ssp_err = g_gpt162.p_api->open (g_gpt162.p_ctrl, g_gpt162.p_cfg);
if (SSP_SUCCESS != ssp_err)
{
__BKPT (1);
}

R_MSTP->MSTPCRD_b.MSTPD14 = 0; /* disables module stop for Port Output Enable for GPT */
R_POEG->POEGGB_b.PIDE = 1; /* Port Input Detection can now be enabled */

/* Se abre el timer 321 que se utiliza para contar los clocks que hay entre que se emite el pulso US
y se recibe el eco. */
ssp_err = g_gpt321.p_api->open (g_gpt321.p_ctrl, g_gpt321.p_cfg);
if (SSP_SUCCESS != ssp_err)
{
__BKPT (1);
}

gp_ctrl = g_gpt321.p_ctrl;
gp_gpt321 = gp_ctrl->p_reg;
/* Se configura gpt321 para que se pare con el flanco positivo de GTIOCB (P104, ECHO del TL851) */
gp_gpt321->GTPSR_b.PSGTRGBR = 1;
gp_gpt321->GTPR = 0xffffffff; // Límite máximo del contador 321.

while (1)
{
ssp_err = g_gpt321.p_api->stop (g_gpt321.p_ctrl); /* Se para el timer. */
if (SSP_SUCCESS != ssp_err)
{
__BKPT (1);
}
ssp_err = g_gpt321.p_api->reset (g_gpt321.p_ctrl); /* Se resetea el timer. */
if (SSP_SUCCESS != ssp_err)
{
__BKPT (1);
}
ssp_err = g_gpt321.p_api->counterGet (g_gpt321.p_ctrl, &contadorUS); /* Se lee el timer. */
if (SSP_SUCCESS != ssp_err)
{
__BKPT (1);
}
g_ioport.p_api->pinWrite (INI_PUL, IOPORT_LEVEL_HIGH); /* Se emite el pulso. */
ssp_err = g_gpt321.p_api->start (g_gpt321.p_ctrl); /* Se arranca el timer. */
if (SSP_SUCCESS != ssp_err)
{
__BKPT (1);
}

R_BSP_SoftwareDelay (500, BSP_DELAY_UNITS_MILLISECONDS);
g_ioport.p_api->pinWrite (INI_PUL, IOPORT_LEVEL_LOW); /* Se deja listo para un nuevo pulso. */
ssp_err = g_gpt321.p_api->counterGet (g_gpt321.p_ctrl, &contadorUS); /* Se lee el timer. */
if (SSP_SUCCESS != ssp_err)
{
__BKPT (1);
}
}
}
--------------------------------------------------------------------------------------------------------------------

And these are the GPT321 properties:



Any help is appreciated...

Thanks!
Víctor.
  • A solution would be far easier if you could use a different pin other than P104. P104 only supports GPT - GTETRGB functionality. If you could use P102, P103, P106, P107 then you could use the GPT - GTIOC pins. You could then use the input capture feature of the GPT, where the GPT GTCNT value is stored automatically when an edge occurs on the GTIOC pin.

    And it is not clear. When the event occurs on P104 you do want the GPT to stop or you want it to keep running?

    And I need to check, but I think it may be possible to start the GPT timer automatically when you write to the I/O pin, using the ELC. I'll check this and verify.

    Richard
  • In reply to Richard:

    Richard,

    Thanks for fast answer!

    Unfortunely, I can't use P106 & P107 because the application board uses the R7FS3A6783A01CFL and this package doen't have P102 and P103 pins.

    I want to stop the GPT when the rise edge appears. I need to measure the time between the activation of output and the rise edge of input signal (0.6ms - 16ms).

    I haven't use the ELC, but your propose seems very elegance :-)

    Thanks for your help. I wait your comments.

    Víctor.
  • In reply to vmarcos:

    Sorry, I had missed that you were using a smaller package variant.
    Unfortunately I'm not in the office today so not able to investigate further today, but I will look into this tomorrow.
    I think that the ELC could also be used to generate an event on P104 that could be used to stop the GPT and generate an ISR that could read the GPT.
    What resolution of accuracy to you require? Passing events from peripheral to peripheral and interrupt service routines can all add latency, but if us accuracy rather then ns accuracy is required then I think a solution will be possible.

    Richard.
  • In reply to Richard:

    I need a resolution better than 30µs so, I think ther is no problem using ISR, right?

    Víctor
  • In reply to vmarcos:

    Hello Victor,

    I've had a chance to look at this.

    I think your code would have worked OK but you had missed enabling the GTETGRB pin in the pin config

     

    This can be done in the pin configuration Timer: POEG

     

    I have also added the code that will enable you to generate an interrupt from the PEOG GTETRGB pin or via the IOPORT interrupt detecting an edge on P104.

    I use the ISR to read the timer value

    I think these code examples (and the pin setting) will get your application working

    Regards,

    Richard

     

    /* HAL-only entry function */
    #include "hal_data.h"

    #define INI_PUL IOPORT_PORT_00_PIN_15

    #if(0)
    /* Manually define the IOPORT1 interrupt and ISR name */
    SSP_VECTOR_DEFINE(ioport1_isr, IOPORT, EVENT_1);
    void ioport1_isr(void);
    #endif


    #if(0)
    SSP_VECTOR_DEFINE_CHAN(poeg_group1, POEG, EVENT, 1);
    void poeg_group1(void);
    #endif


    static gpt_instance_ctrl_t *gp_ctrl;    // Puntero a instancia de control GPT.
    static R_GPTB0_Type *gp_gpt321;         // Puntero a registros GPT321.
    static R_GPTB0_Type *gp_gpt162;         // Puntero a registros GPT162.
    static timer_size_t contadorUS;         // Contiene los ticks entre el pulso transmitido y el recibido.
                                            // - It contains the ticks between the transmitted pulse and the received one.



    void hal_entry(void)
    {
        /* TODO: add your own code here */
        ssp_err_t ssp_err;

        ssp_err = g_gpt162.p_api->open(g_gpt162.p_ctrl, g_gpt162.p_cfg);
        if(SSP_SUCCESS != ssp_err)
        {
            __BKPT(1);
        }


        R_MSTP->MSTPCRD_b.MSTPD14 = 0; /* disables module stop for Port Output Enable for GPT */
        R_POEG->POEGGB_b.PIDE = 1; /* Port Input Detection can now be enabled */

        /* Se abre el timer 321 que se utiliza para contar los clocks que hay entre que se emite el pulso US
         * se recibe el eco.
         * - The timer 321 is opened and used to count the clocks between the US pulse.
         *   and the echo is received.
         */
        ssp_err = g_gpt321.p_api->open (g_gpt321.p_ctrl, g_gpt321.p_cfg);
        if (SSP_SUCCESS != ssp_err)
        {
            __BKPT (1);
        }

        gp_ctrl = g_gpt321.p_ctrl;
        gp_gpt321 = gp_ctrl->p_reg;

        /* Se configura gpt321 para que se pare con el flanco positivo de GTIOCB (P104, ECHO del TL851)
         * - Gpt321 is configured to stop with the positive edge of GTIOCB (P104, ECHO of TL851)
         */
        gp_gpt321->GTPSR_b.PSGTRGBR = 1;    /* GPT will be stopped by edge on GTETRGB (P104) */
        gp_gpt321->GTPR = 0xffffffff; /* Límite máximo del contador 321 - Maximum limit of the counter 321. */

    #if(0)
        /* Enable access to the PFS registers */
        R_PMISC->PWPR = 0x00;
        R_PMISC->PWPR = 0x40;

        /* Set the Event on Falling/Event on Rising control
         * Set to detect a rising edge
         */
        R_PFS->P104PFS_b.EOFR = 1;  /* Detect rising edge and generate ELC event */

        /* Disable access to the PFS */
        R_PMISC->PWPR = 0x00;
        R_PMISC->PWPR = 0x80;

        /* P104 will now generate a IOPORT1 EVENT
         * Use this to generate an IOPRT1 Interrupt
         * Enable the interrupt here
         * Note: Define the interrupt manually (see top of file for definition)
         */
        ssp_feature_t ssp_feature = {{(ssp_ip_t) 0}};
        fmi_event_info_t event_info = {(IRQn_Type) 0U};

        ssp_feature.channel = 0;    /* refer to ssp_features for definitions */
        ssp_feature.unit = 0U;
        ssp_feature.id = SSP_IP_IOPORT;

        g_fmi_on_fmi.eventInfoGet(&ssp_feature, SSP_SIGNAL_IOPORT_EVENT_1, &event_info);

        NVIC_SetPriority(event_info.irq, 2);        /* Set priority 0 - 15 on S3 */
        R_BSP_IrqStatusClear(event_info.irq);
        NVIC_ClearPendingIRQ(event_info.irq);
        NVIC_EnableIRQ(event_info.irq);
    #endif

    #if(1)
        /*Enable the POEG Group 1 interrupt (POEG Group B interrupt) */
        ssp_feature_t ssp_feature = {{(ssp_ip_t) 0}};
        fmi_event_info_t event_info = {(IRQn_Type) 0U};

        ssp_feature.channel = 1;    /* refer to ssp_features for definitions */
        ssp_feature.unit = 0U;
        ssp_feature.id = SSP_IP_POEG;

        g_fmi_on_fmi.eventInfoGet(&ssp_feature, SSP_SIGNAL_POEG_EVENT, &event_info);

        NVIC_SetPriority(event_info.irq, 2);        /* Set priority 0 - 15 on S3 */
        R_BSP_IrqStatusClear(event_info.irq);
        NVIC_ClearPendingIRQ(event_info.irq);
        NVIC_EnableIRQ(event_info.irq);
    #endif

        while(1)
        {
            ssp_err = g_gpt321.p_api->stop (g_gpt321.p_ctrl); /* Se para el timer. */
            if (SSP_SUCCESS != ssp_err)
            {
                __BKPT (1);
            }

            ssp_err = g_gpt321.p_api->reset (g_gpt321.p_ctrl); /* Se resetea el timer. */
            if (SSP_SUCCESS != ssp_err)
            {
                __BKPT (1);
            }

            g_ioport.p_api->pinWrite (INI_PUL, IOPORT_LEVEL_HIGH); /* Se emite el pulso - The pulse is emitted */
            ssp_err = g_gpt321.p_api->start (g_gpt321.p_ctrl); /* Se arranca el timer. */
            if (SSP_SUCCESS != ssp_err)
            {
                __BKPT (1);
            }

            R_BSP_SoftwareDelay (500, BSP_DELAY_UNITS_MILLISECONDS);

            g_ioport.p_api->pinWrite (INI_PUL, IOPORT_LEVEL_LOW); /* Se deja listo para un nuevo pulso. */

        }
    }




    #if(0)
    void ioport1_isr(void)
    {
        ssp_err_t ssp_err;

        ssp_err = g_gpt321.p_api->counterGet (g_gpt321.p_ctrl, &contadorUS); /* Se lee el timer. */
        if (SSP_SUCCESS != ssp_err)
        {
            __BKPT (1);
        }

        __DMB();                    /* use DMB to ensure the ordering of clearing of the ICU */

        /* Clear pending IRQ to make sure it doesn't fire again after exiting */
        R_BSP_IrqStatusClear(R_SSP_CurrentIrqGet());
    }
    #endif


    #if(1)
    void poeg_group1(void)
    {
        ssp_err_t ssp_err;

        ssp_err = g_gpt321.p_api->counterGet (g_gpt321.p_ctrl, &contadorUS); /* Se lee el timer. */
        if (SSP_SUCCESS != ssp_err)
        {
            __BKPT (1);
        }

        /* Clear flag in POEG */
        R_POEG->POEGGB_b.PIDF = 0;

        __DMB();                    /* use DMB to ensure the ordering of clearing of the ICU */

        /* Clear pending IRQ to make sure it doesn't fire again after exiting */
        R_BSP_IrqStatusClear(R_SSP_CurrentIrqGet());

    }
    #endif
  • In reply to Richard:

    Hi Richard,

    I 've changed the pin configuration following your instructions and my code works! :-)

    I've tested your proposals. The IOPORT_ISR solution works , but when I test the POEG version, it only works well the first time.
    I've two breakpoints:
    - Main loop (when I start init pulse)
    - poeg_group1 ISR (after CounterGet calling)
    The main loop breakpoint only stops one time, and the poeg breakpoint stops the ejecution again and again. I've seen that you clear IRQ statuts to avoid the re-entry...

    Thans again!
    Víctor.