This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

100us counter

OS in development environment :Windows7
HARD :(Taiyo Yuden)EBSHSN Series Evaluation Board : Central / Peripherals
CPU :(Nordic) nRF52832 / ARMR Cortex?-M4F 32 bit processor 28-pin Land Grid Array / 15GPIOs / SWD
Soft Ver:nRF5_SDK_15.2.0_9412b96

Please tell me the processing method to count variables by 100us without generating interrupt.

Please let me know if there is a sample program

Thank you very much.

Parents
  • Hello,

    What is it that you want to count? Is it a pulse with a period of 100µs?

    That would be possible to count using PPI and a timer. This way, it will work in the background without interrupting the CPU, and you can read out the TIMER registers from your application. 

    We don't have an example doing exactly this, but attached is another project that uses PPI. This can be modified to do what you want. I will try to give a brief explanation on what you have to do.

    So the attached project is a project that uses PPI + TIMER + GPIOTE to generate a PWM signal.

    PPI has two essential elements. EEP and TEP. EEP is the Event that triggers the PPI, while TEP is the task that is performed when the EEP occurs. 

    What you need is to have a PPI set up to trigger an EEP when the signal e.g. goes Low to High, and use the TEP to increment the timer.

    So in this case, you would also need PPI + GPIOTE + TIMER, but unlike the attached example, your GPIOTE is the input/EEP, and the timer is the task/TEP. So you would want to set the timer in counter mode instead of timer mode, and trigger the PPI with EEP = GPIOTE event, and perform the counting on the timer.

    Play around with the project, and see if you can see how it works, and how to modify it, and let me know if you are stuck.

    ppi_double_channel_pwm.zip

    Note: The project contains only a Keil file, and is written in SDK14.0.0, but it doesn't use any drivers, only the registers. So the main.c file should work in any compiler and any SDK. Just take any example from the SDK that you are using (SDK\examples\peripheral\...) and replace the main.c file.

    Best regards,

    Edvin

  • Counting the timer with a 100us interrupt will shift the timer without an interrupt.
    The following processing is performed without generating an interrupt. Please tell me what to do.
    1) Timer counts up every 100 μs
    2) Reset the timer (clear timer 0 at any timing)
    3) Addition to timer (offset addition to timer value)
    Thank you very much.

  • I want a timer that counts in a cycle of 100 μs.
    I do not want an external trigger.

    I was counting with the following interrupt program, but sometimes I did not get an interrupt, so I asked a question.

    -------------------------------------------------------------

    #include <stdbool.h>
    #include <stdint.h>
    #include "nrf.h"
    #include "nrf_drv_timer.h"
    #include "bsp.h"
    #include "app_error.h"

    #define CONTROL_SAMPLE_RATE 100 /* Control counter sampling rate 100us */
    static const nrf_drv_timer_t Ctl_timer = NRF_DRV_TIMER_INSTANCE(4); /* Timer 4 setting */

    extern uint16_t Control_counter; /* Control counter [0-65535(0-6553.5ms)] (1count:100us) */


    *------------------------------*/
    /* Proguram Proc */
    /*------------------------------*/
    /** @brief Handler for timer4 (100us) events. */
    void timer4_event_handler(nrf_timer_event_t event_type, void* p_context)
    {
     switch (event_type)
     {
     case NRF_TIMER_EVENT_COMPARE4: /* timer 4 events */
      Control_counter ++; /* Control_counter update */
      break;

     default:
      break;
     }
    }

    void Conterl_timer_init(void)
    {
    uint32_t time_ticks;
    uint32_t err_code = NRF_SUCCESS;

     nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
     err_code = nrf_drv_timer_init(&Ctl_timer, &timer_cfg, timer4_event_handler);
     APP_ERROR_CHECK(err_code);

     time_ticks = nrf_drv_timer_us_to_ticks(&Ctl_timer, CONTROL_SAMPLE_RATE);

      nrf_drv_timer_extended_compare(
      &Ctl_timer, NRF_TIMER_CC_CHANNEL4, time_ticks, NRF_TIMER_SHORT_COMPARE4_CLEAR_MASK, true);
     nrf_drv_timer_enable(&Ctl_timer);
    }

    -------------------------------------------------------------

  • Ok, so you want to get an interrupt, but sometimes you do not get them?

    100µs is kind of fast, so it may be that you don't see your interrupts because they are not called due to a higher performance task? How do you determine that you don't get all the interrupts? 

    Do you use the softdevice in your project?

  • The presence or absence of an interrupt was confirmed by port output.
    I use soft devices.
    You need a timer that counts in less than 100 microseconds.

    Counting less than 100us in 1ms divisor


    I want to use a timer that is controlled by hardware, but I do not know how to use it.

  • Ok. so you have the timer set up, which fires every 100ms, and then you increment a counter in the interrupt, right?

    So if you have the timer events,  you can use PPI to connect your timer events to a counter. You need to use another timer, e.g. TIMER3 in counter mode, and have the PPI task to increment this counter. 

    So using PPI, you want to have the PPI.EEP (event end point) to be the timer 4 event, and the PPI.TEP (task end point) to be incrementing the timer.

    Did you examine the PPI example that I sent?

  • Is there a problem with the attached program?
    /**
    
    **/
    #include <stdint.h>
    
    #include "nrf_delay.h"
    #include "app_error.h"
    
    #include "nrf_drv_ppi.h"
    #include "nrf_drv_timer.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #define PPI_EXAMPLE_TIMER0_INTERVAL			(100)	/* Timer interval in 100us */
    
    static const nrf_drv_timer_t m_timer0 = NRF_DRV_TIMER_INSTANCE(0);
    
    static nrf_ppi_channel_t m_ppi_channel1;
    
    static volatile uint32_t m_counter;
    
    
    static void timer0_event_handler(nrf_timer_event_t event_type, void * p_context)
    {
        ++m_counter;
    }
    
    /** @brief Function for initializing the PPI peripheral.	*/
    static void ppi_init(void)
    {
        uint32_t err_code = NRF_SUCCESS;
    
        err_code = nrf_drv_ppi_init();
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel1);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_ppi_channel_assign(m_ppi_channel1,
                                              nrf_drv_timer_event_address_get(&m_timer0,
                                                                              NRF_TIMER_EVENT_COMPARE0),
                                              nrf_drv_timer_task_address_get(&m_timer0,
                                                                             NRF_TIMER_TASK_START));
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_enable(m_ppi_channel1);
        APP_ERROR_CHECK(err_code);
    }
    
    /** @brief Function for Timer 0 initialization.	*/
    static void timer0_init(void)
    {
        nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
        timer_cfg.frequency = NRF_TIMER_FREQ_31250Hz;
        ret_code_t err_code = nrf_drv_timer_init(&m_timer0, &timer_cfg, timer0_event_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_timer_extended_compare(&m_timer0,
                                       NRF_TIMER_CC_CHANNEL0,
                                       nrf_drv_timer_us_to_ticks(&m_timer0,
                                                                 PPI_EXAMPLE_TIMER0_INTERVAL),
                                       NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                       true);
    }
    
    
    /**
     * @brief Function for application main entry.
     */
    int main(void)
    {
        uint32_t old_val = 0;
        uint32_t err_code;
    
        ppi_init();
        timer0_init(); 
    
         /* Start */
        nrf_drv_timer_enable(&m_timer0);
    	
        while (true)
        {
    		/**/
        }
    }
    
    /** @} */
    

Reply
  • Is there a problem with the attached program?
    /**
    
    **/
    #include <stdint.h>
    
    #include "nrf_delay.h"
    #include "app_error.h"
    
    #include "nrf_drv_ppi.h"
    #include "nrf_drv_timer.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #define PPI_EXAMPLE_TIMER0_INTERVAL			(100)	/* Timer interval in 100us */
    
    static const nrf_drv_timer_t m_timer0 = NRF_DRV_TIMER_INSTANCE(0);
    
    static nrf_ppi_channel_t m_ppi_channel1;
    
    static volatile uint32_t m_counter;
    
    
    static void timer0_event_handler(nrf_timer_event_t event_type, void * p_context)
    {
        ++m_counter;
    }
    
    /** @brief Function for initializing the PPI peripheral.	*/
    static void ppi_init(void)
    {
        uint32_t err_code = NRF_SUCCESS;
    
        err_code = nrf_drv_ppi_init();
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel1);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_ppi_channel_assign(m_ppi_channel1,
                                              nrf_drv_timer_event_address_get(&m_timer0,
                                                                              NRF_TIMER_EVENT_COMPARE0),
                                              nrf_drv_timer_task_address_get(&m_timer0,
                                                                             NRF_TIMER_TASK_START));
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_ppi_channel_enable(m_ppi_channel1);
        APP_ERROR_CHECK(err_code);
    }
    
    /** @brief Function for Timer 0 initialization.	*/
    static void timer0_init(void)
    {
        nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
        timer_cfg.frequency = NRF_TIMER_FREQ_31250Hz;
        ret_code_t err_code = nrf_drv_timer_init(&m_timer0, &timer_cfg, timer0_event_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_timer_extended_compare(&m_timer0,
                                       NRF_TIMER_CC_CHANNEL0,
                                       nrf_drv_timer_us_to_ticks(&m_timer0,
                                                                 PPI_EXAMPLE_TIMER0_INTERVAL),
                                       NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                       true);
    }
    
    
    /**
     * @brief Function for application main entry.
     */
    int main(void)
    {
        uint32_t old_val = 0;
        uint32_t err_code;
    
        ppi_init();
        timer0_init(); 
    
         /* Start */
        nrf_drv_timer_enable(&m_timer0);
    	
        while (true)
        {
    		/**/
        }
    }
    
    /** @} */
    

Children
  • You tell me. Does it work?

    It doesn't look like it does what you want it to. You don't need the ppi to use the timeout event handler, timer0_event_handler. The issue is that this is called very frequently, but if the CPU doesn't have time to handle every timer interrupt, then your m_counter will not be incremented correctly. This may happen if you e.g. use the softdevice, which will some times use the CPU, and it has a higher interrupt priority than the timer. But as far as I can tell you are not using the softdevice?

    If you want to use the PPI, to increment a counter without the CPU, let me know, and I can try to explain.

  • Please check the contents of the program.
    If you count timers correctly in 100 μs, is there any problem with the following process?
    1) Create 100 us with "timer0".
    2) Set "timer1" to "count mode".
    3) Execute "timer1" "COUNT task" at "timer 0" timing with PPI.

  • I don't see that your program (the one you attached in your previous reply) contains anything about timer 1. Is that the program you are referring to?

    However, this setup:

    yokokawa said:
    1) Create 100 us with "timer0".
    2) Set "timer1" to "count mode".
    3) Execute "timer1" "COUNT task" at "timer 0" timing with PPI.

    seems good. Did you implement this?

  • I created a program but it doesn't work. Please point out the problem.
    /**
    
    **/
    #include <stdint.h>
    
    #include "nrf_delay.h"
    #include "app_error.h"
    
    #include "nrf_drv_ppi.h"
    #include "nrf_drv_timer.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #define PPI_COUNT_TIMER2_INTERVAL	(100)									/* timer4 interval in 100us */
    
    static const nrf_drv_timer_t t1_counter = NRF_DRV_TIMER_INSTANCE(1);		/* timer2 counter mode */
    static const nrf_drv_timer_t t2_cycle = NRF_DRV_TIMER_INSTANCE(2);			/* timer4 100us */
    
    static nrf_ppi_channel_t m_ppi_channel2;
    
    
    /*-----------------------------------------*/
    /*--< Program operation processing area >--*/
    /*-----------------------------------------*/
    
    /*-< Timer event handler. Not used since Timer1 and Timer2 are used only for PPI. >-*/
    static void empty_timer_handler(nrf_timer_event_t event_type, void * p_context)
    {
    }
    
    /*-< Set timer1:CC1 to counter mode		(timer 1 initialization)	>-*/
    static void timer1_counter_init(void)
    {
    	nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    /*-< Configuration change of timer_cfg >-*/
    //	timer_cfg.frequency = NRF_TIMER_FREQ_16MHz		/* DEFAULT	*/
    	timer_cfg.mode = NRF_TIMER_MODE_COUNTER;		/* NRF_TIMER_MODE_TIMER -> NRF_TIMER_MODE_COUNTER	*/
    	timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;	/* NRF_TIMER_BIT_WIDTH_24 -> NRF_TIMER_BIT_WIDTH_32	*/
    //	timer_cfg.interrupt_priority = 6;				/* DEFAULT	*/
    //	timer_cfg.p_context = NULL;						/* DEFAULT	*/
    
    	ret_code_t err_code = nrf_drv_timer_init(&t1_counter, &timer_cfg, empty_timer_handler);
    	APP_ERROR_CHECK(err_code);
    
    	nrfx_timer_capture(&t1_counter, NRF_TIMER_CC_CHANNEL1);
    
    }
    
    /*-< Set timer2:CC2 to 100us timer mode		(timer 2 initialization)	>-*/
    static void timer2_cycle_init(void)
    {
        nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    	
    	ret_code_t err_code = nrf_drv_timer_init(&t2_cycle, &timer_cfg, empty_timer_handler);
        APP_ERROR_CHECK(err_code);
    
        nrf_drv_timer_extended_compare(&t2_cycle,
    									NRF_TIMER_CC_CHANNEL2,
    									nrf_drv_timer_us_to_ticks(&t2_cycle, PPI_COUNT_TIMER2_INTERVAL),
    									NRF_TIMER_SHORT_COMPARE2_CLEAR_MASK, false);
    }
    
    /*-< PPI controls the process of counting at 100us	(PPI 100us(timer1) counter(timer2) initialization)	>-*/
    static void ppi_Sync_counter_init(void)
    {
    	uint32_t err_code = NRF_SUCCESS;
    
    	err_code = nrf_drv_ppi_init();
    	APP_ERROR_CHECK(err_code);
    
    	err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel2);
    	APP_ERROR_CHECK(err_code);
    
    	err_code = nrf_drv_ppi_channel_assign(m_ppi_channel2,
                                              nrf_drv_timer_event_address_get(&t2_cycle, NRF_TIMER_EVENT_COMPARE2),
                                              nrf_drv_timer_task_address_get(&t1_counter,  NRF_TIMER_TASK_COUNT));
    	APP_ERROR_CHECK(err_code);
    
    	err_code = nrf_drv_ppi_channel_enable(m_ppi_channel2);
    	APP_ERROR_CHECK(err_code);
    }
    
    /*--------------------*/
    /*-< Main process	>-*/
    /*--------------------*/
    int main(void)
    {
    	/* Initialize */
    	ppi_Sync_counter_init();	
    	timer1_counter_init();
    	timer2_cycle_init();	
    	
    	/* Start */
    	nrf_drv_timer_enable(&t1_counter);
    	nrf_drv_timer_enable(&t2_cycle);
    	
    	while (true)
    	{
    		/**/
    	}
    }
    
    /** @} */
    
  • Does any of your err_codes return != NRF_SUCCESS?

Related