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

PPI

Hi,

I'm trying to do something (seemingly) VERY simple:

I want to increment the count in Timer 2 every time a GPIO pin (17) goes from high to low, without using the CPU and / or interrupts...

I am using S110; SDK 7.2.0 (I know, old, but quite sufficient for my needs)

To this end, this is my code:

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

#define VIBE_CHANNEL_NUMBER 0

#define VIBE_SWITCH_PIN_NUM 17

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void Timer2Init(void)
{
  NRF_TIMER2->MODE = TIMER_MODE_MODE_Counter;
  NRF_TIMER2->TASKS_CLEAR = 1;
  NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos;
  NRF_TIMER2->TASKS_START = 1;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void gpiote_init(void)
{
  nrf_gpiote_event_config(VIBE_CHANNEL_NUMBER, VIBE_SWITCH_PIN_NUM, NRF_GPIOTE_POLARITY_HITOLO);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

static void ppi_init(void)
{
  // Configure PPI channel 0 to count every time Vibe Switch input goes from High to Low
  NRF_PPI->CH[VIBE_CHANNEL_NUMBER].EEP  = (uint32_t)&NRF_GPIOTE->EVENTS_IN;
  NRF_PPI->CH[VIBE_CHANNEL_NUMBER].TEP  = (uint32_t)&NRF_TIMER2->TASKS_COUNT;
  // Enable PPI channel 0
  NRF_PPI->CHEN = PPI_CHEN_CH0_Msk;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

int main(void)
{
  timer0_init();
  gpiote_init();
  Timer2Init();
  ppi_init();
  while (true)
  {
    ;
  }
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

When I run this code using the emulator, I see the proper register values in the PPI:

CH[0] EEP = 0x40006100, which is the address of GPIOTE EVENTS_IN[0] and

CH[0] TEP = 0x4000A008, which is the address of TIMER2 TASKS_COUNT

The TIMER2 is setup correctly with a value of 1 in the MODE

The GPIOTE is setup correctly with a value of 0x00021101 (MODE = 1 (event); PSEL = 0x11 (port 17); POLARITY = 2 (High to low) and OUTINIT = 0 (initial low))

I even get an event notification on GPIOTE EVENTS_IN[0] when I twiddle the input pin!

But the TASKS_COUNT doesn't count!!!

I try reading the counter but that doesn't produce a non-zero number either....

I've tried using TIMER 1 with no success....

What am I doing wrong???

Thanks for your answer in advance!

Parents
  • NRF_PPI->CH[VIBE_CHANNEL_NUMBER].EEP  = (uint32_t)&NRF_GPIOTE->EVENTS_IN

    I think it should be:

    NRF_PPI->CH[VIBE_CHANNEL_NUMBER].EEP  = (uint32_t)&NRF_GPIOTE->IN[VIBE_CHANNEL_NUMBER]

    Also, you need to make sure that the channel number for both GPIOTE and PPI is actually available. I believe the PPI driver has a function for finding a free channel at run-time, at least in SDK 9: nrf_drv_ppi_channel_alloc 

  • Hi, Haakonsh,

    You're right, but that didn't help to get a count increase in the Timer2 TASKS_COUNT register...

    Am I not enabling something?

    I DO get a notification in the GPIOTE EVENTS_IN[0] register when I twiddle the input pin...

  • You need to trigger a capture task to get the value of the TIMER. 

    If you trigger the CAPTURE[1] task the value of the TIMER will be loaded into the CC[1] register. 

    The use of a Capture task enables real-time periodic sampling of the TIMER in counter mode.
    F. ex. if you want to know how many times a pin has gone from low to high position every 625µs(arbitrary number) you can set up another TIMER to trigger the Capture task every 625µs. You're then guaranteed that the value read by the CPU is correct regardless of its load at the time, as long as you read the register before the next 625µs period that is. 

Reply
  • You need to trigger a capture task to get the value of the TIMER. 

    If you trigger the CAPTURE[1] task the value of the TIMER will be loaded into the CC[1] register. 

    The use of a Capture task enables real-time periodic sampling of the TIMER in counter mode.
    F. ex. if you want to know how many times a pin has gone from low to high position every 625µs(arbitrary number) you can set up another TIMER to trigger the Capture task every 625µs. You're then guaranteed that the value read by the CPU is correct regardless of its load at the time, as long as you read the register before the next 625µs period that is. 

Children
No Data
Related