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

nRF52 Timer Code Help

Hi

I'm working on a project in which I use a timer to generate two signals that I need to phase shift each other, but at the beginning and at the end it cuts, can anyone advise me how to solve this problem ?. I'm attaching my code and a video to see my issue.

https://www.youtube.com/watch?v=HNIGHqlCFf0

#include <stdbool.h>
#include "nrf.h"
#include "nrf_gpio.h"
#include "boards.h"
#include "nrf_delay.h"

int Frequency = 200;
int Phase_Set = 1;

int Phase[4] = {1, 1, 0, 0};

int cnt = 0;

#define GPIO_OUT_1         NRF_GPIO_PIN_MAP(0,6)
#define GPIO_OUT_2         NRF_GPIO_PIN_MAP(0,8)

void timer_init(int frequency, int phase)
{		
    NRF_TIMER2->SHORTS      = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);
    NRF_TIMER2->MODE        = TIMER_MODE_MODE_Timer;
    NRF_TIMER2->BITMODE     = (TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos);
    NRF_TIMER2->PRESCALER   = 0;
	  NRF_TIMER2->CC[0] = frequency;                             
	  NRF_TIMER2->CC[1] = phase;  
 	
  	NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos) | (TIMER_INTENSET_COMPARE1_Enabled << TIMER_INTENSET_COMPARE1_Pos);
	
    NVIC_EnableIRQ(TIMER2_IRQn);		
    NRF_TIMER2->TASKS_START = 1;               
}

void TIMER2_IRQHandler(void)
{
	 if(NRF_TIMER2->EVENTS_COMPARE[0]){
		 	nrf_gpio_pin_toggle(GPIO_OUT_1);           
		  NRF_TIMER2->EVENTS_COMPARE[0] = 0;           
  }
	
	 if(NRF_TIMER2->EVENTS_COMPARE[1]){
		 cnt++;
		 nrf_gpio_pin_write(GPIO_OUT_2,Phase[cnt]);
	   if(cnt == 4)
     cnt = 0;
		 NRF_TIMER2->EVENTS_COMPARE[1] = 0;           
  }
}

int main(void)
{
	NRF_CLOCK->TASKS_HFCLKSTART = 1;
	nrf_gpio_cfg_output(GPIO_OUT_1);       
	nrf_gpio_cfg_output(GPIO_OUT_2);
	timer_init(Frequency,Phase_Set);                              
	
	while(1){
 	Phase_Set++;
  if (Phase_Set == Frequency){
		  Phase_Set = 1;
  }
	NRF_TIMER2->CC[1] = Phase_Set;
	nrf_delay_ms(50); 
	}
}

Parents Reply Children
  • I have no experience with PPI and GPIOTE, I'm new and I started programming nRF just a few months ago, it would be great if you could help me with that and write at least a few lines of code.

  • Basically, I just need what you see in my video, the upper curve on the oscilloscope can be generated using GPIOTE and the lower curve runs in IRQ and only needs a full phase shift.

  • Please read this article about tasks, events and PPI. 

    I don't see a reason to run lower curve in IRQ - you will loose all advantages of GPIOTE and your channels will not be synchronized. Here are "a few lines of code" to start with (maybe it's not exactly what you need, but hope you will understand what to do next).

    First, configure your pins to be controlled by GPIOTE:

    #define GPIOTE_TASK(ch, pin, initstate) do { NRF_GPIOTE->CONFIG[ch] = ((3UL << 0) | ((pin) << 8) | (3UL << 16) | ((initstate) << 20)); } while (0)

    GPIOTE_TASK(0, GPIO_OUT_1, 0);
    GPIOTE_TASK(1, GPIO_OUT_2, 0);

    For upper curve, configure GPIOTE channel 0 to toggle on CC[0] event:

    NRF_PPI->CH[0].EEP = &NRF_TIMER2->EVENTS_COMPARE[0];
    NRF_PPI->CH[0].TEP = &NRF_GPIOTE->TASKS_OUT[0];
    NRF_PPI->CHENSET = (1UL << 0);

    For lower curve, configure GPIOTE channel 1 to rise on CC[1] and fall on CC[2]:

    NRF_PPI->CH[1].EEP = &NRF_TIMER2->EVENTS_COMPARE[1];
    NRF_PPI->CH[1].TEP = &NRF_GPIOTE->TASKS_SET[1];
    NRF_PPI->CHENSET = (1UL << 1);
    NRF_PPI->CH[2].EEP = &NRF_TIMER2->EVENTS_COMPARE[2];
    NRF_PPI->CH[2].TEP = &NRF_GPIOTE->TASKS_CLR[1];
    NRF_PPI->CHENSET = (1UL << 2);

    Now you can adjust phase shift of lower curve by changing CC[1] and CC[2] in your loop:

    NRF_TIMER2->CC[1] = phase;
    NRF_TIMER2->CC[2] = (phase + frequency/2) % frequency;

    If you need to sample ADC value at some point, you can configure channel 3 to start a SAMPLE task:

    NRF_PPI->CH[3].EEP = &NRF_TIMER2->EVENTS_COMPARE[3];
    NRF_PPI->CH[3].TEP = &NRF_SAADC->TASKS_SAMPLE;
    NRF_PPI->CHENSET = (1UL << 3);

  • Thanks for your advice, I set up the code this way and it looks like it's working properly.

    #include <stdbool.h>
    #include "nrf.h"
    #include "nrf_gpio.h"
    #include "boards.h"
    #include "nrf_delay.h"
    
    #define GPIOTE_TASK(ch, pin, initstate) do { NRF_GPIOTE->CONFIG[ch] = ((3UL << 0) | ((pin) << 8) | (3UL << 16) | ((initstate) << 20)); } while (0)
    	
    int Frequency = 400;
    int Phase_Set = 0; //set phase 0-100
    
    //int Phase[4] = {1, 1, 0, 0};
    
    //int cnt = 0;
    
    #define GPIO_OUT_1         NRF_GPIO_PIN_MAP(0,6)
    #define GPIO_OUT_2         NRF_GPIO_PIN_MAP(0,8)
    
    void timer_init(int frequency, int phase){	
    
        NRF_TIMER2->BITMODE                 = TIMER_BITMODE_BITMODE_24Bit << TIMER_BITMODE_BITMODE_Pos;
        NRF_TIMER2->PRESCALER               = 0;
        NRF_TIMER2->SHORTS                  = TIMER_SHORTS_COMPARE0_CLEAR_Msk << 0;
        NRF_TIMER2->MODE                    = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos;
    	NRF_TIMER2->CC[0] = frequency;
    	NRF_TIMER2->CC[1] = phase+1;
        NRF_TIMER2->CC[2] = ((phase+1) + frequency/2) % frequency;  
     	
      	//NRF_TIMER2->INTENSET = (TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos) | (TIMER_INTENSET_COMPARE1_Enabled << TIMER_INTENSET_COMPARE1_Pos);
    	
        //NVIC_EnableIRQ(TIMER2_IRQn);		
        NRF_TIMER2->TASKS_START = 1;               
    }
    
    /*
    void TIMER2_IRQHandler(void){
    
    	if(NRF_TIMER2->EVENTS_COMPARE[0]){
    	nrf_gpio_pin_toggle(GPIO_OUT_1);           
        NRF_TIMER2->EVENTS_COMPARE[0] = 0;           
      }
    	
    	if(NRF_TIMER2->EVENTS_COMPARE[1]){
    	cnt++;
        nrf_gpio_pin_write(GPIO_OUT_2,Phase[cnt]);
    	if(cnt == 4)
        cnt = 0;
    	NRF_TIMER2->EVENTS_COMPARE[1] = 0;           
      }
    }
    */
    
    int main(void){
    
      NRF_CLOCK->TASKS_HFCLKSTART = 1;
      nrf_gpio_cfg_output(GPIO_OUT_1);       
      nrf_gpio_cfg_output(GPIO_OUT_2);
    	
      GPIOTE_TASK(0, GPIO_OUT_1, 0);
      GPIOTE_TASK(1, GPIO_OUT_2, 0);
    	
      NRF_PPI->CH[0].EEP = (uint32_t)&NRF_TIMER2->EVENTS_COMPARE[0];
      NRF_PPI->CH[0].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[0];
      NRF_PPI->CHENSET = (1UL << 0);
    	
      NRF_PPI->CH[1].EEP =(uint32_t)& NRF_TIMER2->EVENTS_COMPARE[1];
      NRF_PPI->CH[1].TEP = (uint32_t)&NRF_GPIOTE->TASKS_SET[1];
      NRF_PPI->CHENSET = (1UL << 1);
      NRF_PPI->CH[2].EEP = (uint32_t)&NRF_TIMER2->EVENTS_COMPARE[2];
      NRF_PPI->CH[2].TEP = (uint32_t)&NRF_GPIOTE->TASKS_CLR[1];
      NRF_PPI->CHENSET = (1UL << 2);
    	
      timer_init(Frequency,Phase_Set*2);                              
    	
    	while(1){
     	Phase_Set++;
      if(Phase_Set == Frequency){
    	 Phase_Set = 1;
      }
      NRF_TIMER2->CC[1] = Phase_Set+1;
      NRF_TIMER2->CC[2] = ((Phase_Set+1) + Frequency/2) % Frequency;
      nrf_delay_ms(50); 
      }
    }

Related