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

nRF51: Timer Capture Task

Hello,

I want to measure a frequency of a PWM signal like this:

GPIOTE-Event --> PPI --> Timer1-Capture-Task

So every time the event occurs, the counter value is copied into the respective CC-Register (in my case channel 0).

Question: Where is the ideal place to copy the content of the CC-Register into, lets say a data array? Normally, I would assume, that the Timer gererates an interrupt as soon as it has finished the capture. So my first idea is to use the timer ISR to copy the value. BUT: What is the advantage of that technique compared to a normal GPIO-Interrupt-ISR and reading/capturing the timer value manually in that ISR? (without using GPIOTE and PPI)?

Second question: How can I achive a timer clear as soon as the capture is done?

This is my code so far:

  uint32_t err_code;
  
  err_code = nrf_drv_ppi_init();
  APP_ERROR_CHECK(err_code);
  
  err_code = nrf_drv_gpiote_init();
  APP_ERROR_CHECK(err_code);
  
  nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
  err_code = nrf_drv_timer_init(&timer, &timer_cfg, timer_dummy_handler);
  APP_ERROR_CHECK(err_code);
  
  
  #ifdef NRF51
    //Workaround for PAN-73.
    *(uint32_t *)0x40008C0C = 1;
  #endif
  
  
  uint32_t gpiote_evt_addr;
  uint32_t capture_task_addr;
  nrf_ppi_channel_t ppi_channel;
  nrf_drv_gpiote_in_config_t config;
  
  config.sense = NRF_GPIOTE_POLARITY_LOTOHI;
  config.pull = NRF_GPIO_PIN_NOPULL;
  config.is_watcher = false;
  config.hi_accuracy = true;
  
  nrf_drv_gpiote_in_init(SIG_PIN,&config, gpiote_evt_handler);
  APP_ERROR_CHECK(err_code);
  
  err_code = nrf_drv_ppi_channel_alloc(&ppi_channel);
  APP_ERROR_CHECK(err_code);
  
  capture_task_addr = nrf_drv_timer_task_address_get(&timer, NRF_TIMER_TASK_CAPTURE0);
  gpiote_evt_addr = nrf_drv_gpiote_in_event_addr_get(SIG_PIN);
  
  err_code = nrf_drv_ppi_channel_assign(ppi_channel, gpiote_evt_addr, capture_task_addr);
  APP_ERROR_CHECK(err_code);
  
  err_code = nrf_drv_ppi_channel_enable(ppi_channel);
  APP_ERROR_CHECK(err_code);
  
  nrf_drv_gpiote_in_event_enable(SIG_PIN, true);
  
  nrf_drv_timer_enable(&timer);
  
  while(1)
  {
    
  };

Thank you very much in advance!

Parents
  • FormerMember
    0 FormerMember

    There is no specific ideal place to copy the content of the CC register, typically, the content in the CC register can be copied to a variable, a data array should work fine.

    The benefit of using PPI instead of normal GPIO interrupt handling is that when using PPI, the CPU is not being used:

    The Programmable Peripheral Interconnect (PPI) enables different peripherals to interact autonomously with each other using tasks and events without use of the CPU. The PPI provides a mechanism to automatically trigger a task in one peripheral as a result of an event occurring in another. A task is connected to an event through a PPI channel.

    (nRF51 series reference manual chapter 3.3.4)

    Clearing timer as soon as the capture is done:

    1. Capture value (will be copied to the CC register).

    2. Clear timer

    3. Read captured value from the CC register.

    This should work as long as every reading of captured values is finished before the next captured value.

  • FormerMember
    0 FormerMember in reply to FormerMember

    Unfortunately, there is no event when the capture is finished, so I would think that it will be executed immediately. If you are not using the softdevice, the GPIOTE event can be set to have the highest priority, and you know that you won't have any other interrupt.

    You can check if the following will work:

    1. GPIOTE event --> PPI --> TASKS_CAPTURE

    2. GPIOTE event handler: clear timer, then read the CC register.

    If the above doesn't work, i.e the capture has not finished before clearing the timer, you can test the following:

    1. GPIOTE event --> PPI --> TASKS_CAPTURE

    2. GPIOTE event handler: dummy read CC values, clear timer, then read the CC register.

    Even though the capture/clear timing may be a little delayed, this delay will always be the same, so it should be possible to measure the frequency.

Reply
  • FormerMember
    0 FormerMember in reply to FormerMember

    Unfortunately, there is no event when the capture is finished, so I would think that it will be executed immediately. If you are not using the softdevice, the GPIOTE event can be set to have the highest priority, and you know that you won't have any other interrupt.

    You can check if the following will work:

    1. GPIOTE event --> PPI --> TASKS_CAPTURE

    2. GPIOTE event handler: clear timer, then read the CC register.

    If the above doesn't work, i.e the capture has not finished before clearing the timer, you can test the following:

    1. GPIOTE event --> PPI --> TASKS_CAPTURE

    2. GPIOTE event handler: dummy read CC values, clear timer, then read the CC register.

    Even though the capture/clear timing may be a little delayed, this delay will always be the same, so it should be possible to measure the frequency.

Children
No Data
Related