Author Topic: Timer Interrupts  (Read 11969 times)

DiedS

  • RFduino Newbie
  • *
  • Posts: 2
  • Karma: +0/-0
    • View Profile
Timer Interrupts
« on: November 28, 2013, 06:08:14 AM »
I would like to use a timer interrupt to take samples at a fixed interval (10ms).

As mentioned by one of the software guys from RFD the interrupt code is in "core/Arduino/WInterrupts.c" . Combining this with the code found in "variant.h" and code found at the Nordic Dev zone I came up with this example:

Code: [Select]
#define TRIGGER_INTERVAL 1000      // 1s

const int ledPinGreen = 3;
int ledState = LOW;

void timer_config(void)
{
  NRF_TIMER0->TASKS_STOP = 1; // Stop timer
  NRF_TIMER0->MODE = TIMER_MODE_MODE_Timer;  // taken from Nordic dev zone
  NRF_TIMER0->PRESCALER = 0; // No prescaling => 1 tick = 1/32768Hz = 30.517us ?
  NRF_TIMER0->TASKS_CLEAR = 1; // Clear timer
  NRF_TIMER0->CC[0] = TRIGGER_INTERVAL * 33; // we need an event every TRIGGER_INTERVAL and there are 1000 / 30.517us ~ 33 ticks in every ms
  NRF_TIMER0->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;  // taken from Nordic dev zone
  attachInterrupt(TIMER0_IRQn, TIMER0_Interrupt);    // also used in variant.cpp to configure the RTC1
  NRF_TIMER0->TASKS_START = 1; // Start TIMER
}

void setup() {
  timer_config();
  pinMode(ledPinGreen, OUTPUT);
}

void loop() {
  // Do loop stuff..

}

void TIMER0_Interrupt(void)
{
  if (NRF_TIMER0->EVENTS_COMPARE[0] != 0)
  {
    // blinks a led just for testing
    ledState = !ledState;
    digitalWrite(ledPinGreen, ledState);
   
    NRF_TIMER0->EVENTS_COMPARE[0] = 0;
  }
}

« Last Edit: November 28, 2013, 06:19:25 AM by DiedS »

DiedS

  • RFduino Newbie
  • *
  • Posts: 2
  • Karma: +0/-0
    • View Profile
Re: Timer Interrupts
« Reply #1 on: November 28, 2013, 07:48:48 AM »
Got it working, I had to add the following line "NRF_TIMER0->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);" above the attachInterrupt function.

The new code looks like this:

Code: [Select]
#define TRIGGER_INTERVAL 1000      // 1s

const int ledPinGreen = 3;
int ledState = LOW;

void timer_config(void)
{
  NRF_TIMER0->TASKS_STOP = 1; // Stop timer
  NRF_TIMER0->MODE = TIMER_MODE_MODE_Timer;  // taken from Nordic dev zone
  NRF_TIMER0->BITMODE = (TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos);
  NRF_TIMER0->PRESCALER = 4; // 1us resolution
  NRF_TIMER0->TASKS_CLEAR = 1; // Clear timer
  NRF_TIMER0->CC[0] = TRIGGER_INTERVAL * 1000;
  NRF_TIMER0->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;  // taken from Nordic dev zone
  NRF_TIMER0->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);
  attachInterrupt(TIMER0_IRQn, TIMER0_Interrupt);    // also used in variant.cpp to configure the RTC1
  NRF_TIMER0->TASKS_START = 1; // Start TIMER
}

void setup() {
  timer_config();
  pinMode(ledPinGreen, OUTPUT);
}

void loop() {
  // Do loop stuff..

}

void TIMER0_Interrupt(void)
{
  if (NRF_TIMER0->EVENTS_COMPARE[0] != 0)
  {
    // blinks a led just for testing
    ledState = !ledState;
    digitalWrite(ledPinGreen, ledState);
   
    NRF_TIMER0->EVENTS_COMPARE[0] = 0;
  }
}

PS I found more documentation about the nrf51822 module at https://github.com/finnurtorfa/nrf51/blob/master/lib/nrf51sdk/Nordic/nrf51822/Include/nrf51_bitfields.h

lpercifield

  • RFduino Newbie
  • *
  • Posts: 6
  • Karma: +1/-0
    • View Profile
Re: Timer Interrupts
« Reply #2 on: January 30, 2014, 03:34:35 PM »
This works great... Until you enable BLE. Are there any timers that are available to use that do not interfere with the BLE stack? I've looked at the WInterrupts.c file and noticed that there are a whole bunch of timers that are reserved... Any way to access timer 0,1 or RTC0,1?

Leif

mkay

  • RFduino Team
  • *****
  • Posts: 405
  • Karma: +15/-0
    • View Profile
Re: Timer Interrupts
« Reply #3 on: February 03, 2014, 04:10:18 PM »
I believe timer 1 and 2 should be open, but timer 0 is used by the BLE stack

aabb

  • RFduino Newbie
  • *
  • Posts: 1
  • Karma: +0/-0
    • View Profile
Re: Timer Interrupts
« Reply #4 on: February 13, 2014, 06:32:29 AM »
I've tried the the example using TIMER0 and it works correctly, but as I need to enable the BLE stack too, I've tried to use TIMER1 or TIMER2, but I can't manage to make them work, I don't get called at the right time.
I simply modified the previous source code referring TIMER0, changing it in TIMER1 (or TIMER2), but in these cases I don't get called at the right time.
I'm quite a newbie regarding interrupts, so probably I've forgotten something, could you help me on that ?

The source code is:

#define TRIGGER_INTERVAL 5000      // ms

void timer_config(void)
{
  NRF_TIMER1->TASKS_STOP = 1;   // Stop timer
  NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer;  // taken from Nordic dev zone
  NRF_TIMER1->BITMODE = (TIMER_BITMODE_BITMODE_32Bit << TIMER_BITMODE_BITMODE_Pos);
  NRF_TIMER1->PRESCALER = 4;   // 1us resolution
  NRF_TIMER1->TASKS_CLEAR = 1; // Clear timer
  NRF_TIMER1->CC[0] = TRIGGER_INTERVAL * 1000;
  NRF_TIMER1->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;  // taken from Nordic dev zone
  NRF_TIMER1->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);
  attachInterrupt(TIMER1_IRQn, TIMER1_Interrupt);    // also used in variant.cpp to configure the RTC1
  NRF_TIMER1->TASKS_START = 1;   // Start TIMER
}

void setup() {
  Serial.begin(115200);
 
  timer_config();
}

void loop() {
  while(1);
}

void TIMER1_Interrupt(void)
{
  if (NRF_TIMER1->EVENTS_COMPARE[0] != 0)
  {
    Serial.println("Timer interrupt called");

    NRF_TIMER1->EVENTS_COMPARE[0] = 0;
  }
}

mkay

  • RFduino Team
  • *****
  • Posts: 405
  • Karma: +15/-0
    • View Profile
Re: Timer Interrupts
« Reply #5 on: February 14, 2014, 11:31:05 AM »
Hi, so TIMER1 and TIMER2 can only operate in 16bit mode. Regardless of what BITMODE you select, they will always operate in 16bit. Try this:

Code: [Select]
#define TRIGGER_INTERVAL 10      // ms

void timer_config(void)
{
  NRF_TIMER1->TASKS_STOP = 1;   // Stop timer
  NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer;  // taken from Nordic dev zone
  NRF_TIMER1->BITMODE = (TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos);
  NRF_TIMER1->PRESCALER = 4;   // SysClk/2^PRESCALER) =  16,000,000/16 = 1us resolution
  NRF_TIMER1->TASKS_CLEAR = 1; // Clear timer
  NRF_TIMER1->CC[0] = TRIGGER_INTERVAL * 1000; // Cannot exceed 16bits
  NRF_TIMER1->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;  // taken from Nordic dev zone
  NRF_TIMER1->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);
  attachInterrupt(TIMER1_IRQn, TIMER1_Interrupt);    // also used in variant.cpp to configure the RTC1
  NRF_TIMER1->TASKS_START = 1;   // Start TIMER
}

This will work with the BLE enabled. Also when using BLE it is recommended to keep the Serial baud rate at 9600.

mark_pdx

  • RFduino Newbie
  • *
  • Posts: 6
  • Karma: +0/-0
    • View Profile
Re: Timer Interrupts
« Reply #6 on: February 25, 2014, 11:59:44 AM »
Hi folks!

Ok, I used the above code (with either Timer1 or Timer2 rather than Timer0) to get a nice pulse train output from a GPIO pin. Swell!

But I also need i2c in this project.  And when I include wire.h, and after executing wire.begin(), the Timer Interrupt setup code hangs the RFDuino. By inserting debugging statements, I was able to determine that the hang occurs at this line of code:

NRF_TIMER1->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;  // taken from Nordic dev zone

This happens whether I use Timer1 or Timer2.  It seems strange that the hangup happens when setting the timer comparison, even before the new interrupt is attached.  This makes me believe there is an existing user of that timer.  Maybe the wire library, as modified for RFDuino, uses both these timers?  Anyone know?

Thanks!  Mark
« Last Edit: February 25, 2014, 12:02:21 PM by mark_pdx »

MrQuincle

  • RFduino Newbie
  • *
  • Posts: 12
  • Karma: +0/-0
    • View Profile
Re: Timer Interrupts
« Reply #7 on: March 04, 2014, 02:10:42 PM »
Hi folks!

Ok, I used the above code (with either Timer1 or Timer2 rather than Timer0) to get a nice pulse train output from a GPIO pin. Swell!

But I also need i2c in this project.  And when I include wire.h, and after executing wire.begin(), the Timer Interrupt setup code hangs the RFDuino. By inserting debugging statements, I was able to determine that the hang occurs at this line of code:

NRF_TIMER1->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;  // taken from Nordic dev zone

This happens whether I use Timer1 or Timer2.  It seems strange that the hangup happens when setting the timer comparison, even before the new interrupt is attached.  This makes me believe there is an existing user of that timer.  Maybe the wire library, as modified for RFDuino, uses both these timers?  Anyone know?

Thanks!  Mark

That might very well be the case. If you want to implement analogWrite, you will need something like a timer for the PWM. They might have chosen TIMER1. Maybe you can use the RTC1 instead? Or get rid of the RFduino stuff. :-)

lpercifield

  • RFduino Newbie
  • *
  • Posts: 6
  • Karma: +1/-0
    • View Profile
Re: Timer Interrupts
« Reply #8 on: March 13, 2014, 07:46:26 AM »
Ok, I have timer interrupts working with BLE and I2C!

I took some code from the github listed below

Hope it works for you

Code: [Select]
//https://github.com/finnurtorfa/nrf51/blob/master/lib/nrf51sdk/Nordic/nrf51822/Board/nrf6310/timer_example/main.c

#include <RFduinoBLE.h>
#include <Wire.h>
uint_fast16_t volatile number_of_ms = 2;     // ms

const int ledPinGreen = 3;
int ledState = LOW;

void timer_config(void)
{
  NRF_TIMER2->TASKS_STOP = 1; // Stop timer
  NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;  // taken from Nordic dev zone
  NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit;
  NRF_TIMER2->PRESCALER = 9; // 32us resolution
  NRF_TIMER2->TASKS_CLEAR = 1; // Clear timer
  // With 32 us ticks, we need to multiply by 31.25 to get milliseconds
  NRF_TIMER2->CC[0] = number_of_ms * 31;
  NRF_TIMER2->CC[0] += number_of_ms / 4;
  NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;  // taken from Nordic dev zone
  NRF_TIMER2->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);
  attachInterrupt(TIMER2_IRQn, TIMER2_Interrupt);    // also used in variant.cpp to configure the RTC1
  NRF_TIMER2->TASKS_START = 1; // Start TIMER
}

void setup() {
  // put your setup code here, to run once:
  //setup I2C on the pins of your choice
  Wire.beginOnPins(6, 5);
  // start the BLE stack
  RFduinoBLE.begin();
  //setup and start the timer
  timer_config();
 
  pinMode(ledPinGreen, OUTPUT);

}

void loop() {
  // put your main code here, to run repeatedly:
 
  //Do something in here with your I2C device

}

void TIMER2_Interrupt(void)
{
  if (NRF_TIMER2->EVENTS_COMPARE[0] != 0)
  {
    // blinks a led just for testing
    ledState = !ledState;
    digitalWrite(ledPinGreen, ledState);
   
    NRF_TIMER2->EVENTS_COMPARE[0] = 0;
  }
}

bhabrooo

  • RFduino Newbie
  • *
  • Posts: 3
  • Karma: +0/-0
    • View Profile
Re: Timer Interrupts
« Reply #9 on: December 11, 2014, 05:00:04 AM »
Well here's the basic info i know:
we have 3 timers
Timer 0                     (used by BLE stack) so not usable if you want use Bluetooth!
Timer 1
Timer 2
If you are using serial communication e.g i2c then another timer will be used up for it so you'll only have one timer available!
Another point to note is that Timer1 and Timer2 work only in 16 bit mode even if you try to change them
Timer0 can operate in 32 bit mode

Here's a working example code i made  in which timer2 is used to generate a square wave.
It pretty similar to one the codes above but this one is simplified
Code: [Select]
#include <RFduinoBLE.h>
#define out 1

int output = 1;


void timer(unsigned int ms)                                 // directly pass the value you want the cycle to be in mS
{
  NRF_TIMER2->TASKS_STOP = 1;                                    // Stop timer
  NRF_TIMER2->MODE = TIMER_MODE_MODE_Timer;                        // sets the timer to TIME mode (doesn't make sense but OK!)
  NRF_TIMER2->BITMODE = TIMER_BITMODE_BITMODE_16Bit;               // with BLE only Timer 1 and Timer 2 and that too only in 16bit mode
  NRF_TIMER2->PRESCALER = 9;                                    // Prescaler 9 produces 31250 Hz timer frequency => t = 1/f =>  32 uS
                                                                   // The figure 31250 Hz is generated by the formula (16M) / (2^n)
                                                                   // where n is the prescaler value
                                                                   // hence (16M)/(2^9)=31250
  NRF_TIMER2->TASKS_CLEAR = 1;                                     // Clear timer
 
  //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  //        Conversion to make cycle calculation easy
  //        Since the cycle is 32 uS hence to generate cycles in mS we need 1000 uS
  //        1000/32 = 31.25  Hence we need a multiplication factor of 31.25 to the required cycle time to achive it
  //        e.g to get a delay of 10 mS      we would do
  //        NRF_TIMER2->CC[0] = (10*31)+(10/4);
  //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
  NRF_TIMER2->CC[0] = (ms * 31) + (ms / 4);                                                                                  //CC[0] register holds interval count value i.e your desired cycle
  NRF_TIMER2->INTENSET = TIMER_INTENSET_COMPARE0_Enabled << TIMER_INTENSET_COMPARE0_Pos;                                     // Enable COMAPRE0 Interrupt
  NRF_TIMER2->SHORTS = (TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos);                             // Count then Complete mode enabled
  attachInterrupt(TIMER2_IRQn, TIMER2_Interrupt);                                                                            // also used in variant.cpp in the RFduino2.2 folder to configure the RTC1
  NRF_TIMER2->TASKS_START = 1;                                                                                              // Start TIMER
}

void setup()
{
  RFduinoBLE.begin();
  timer(10);                                                 //configure the whole process with 10 ms interval this will generate sqaure wave with period 20 mS and freq 50 Hz
 
  pinMode(out, OUTPUT);

}

void loop()
{

}

// generate the square wave
void TIMER2_Interrupt(void)
{
  if (NRF_TIMER2->EVENTS_COMPARE[0] != 0)
  {
    output = !output;
    digitalWrite(out, output);
    NRF_TIMER2->EVENTS_COMPARE[0] = 0;
  }
}



The timer_config() cofucntion generates the timer sequences for the desired value passed to it in mS e.g
timer_config(1)          Generates a cycle of of 1mS and throws an interrupt when count is  over
timer_config(5)          Generates a cycle of of 1mS and throws an interrupt when count is  over

Hence TIMER2_Interrupt () which is an Interrupt service routine (ISR) generates high for one cycle and low for the next one.
i've pretty much mentioned what every lines means/ does so there should be no problem now i guess :)



tolson

  • Global Moderator
  • *****
  • Posts: 811
  • Karma: +19/-0
    • View Profile
    • Thomas Olson Consulting
Re: Timer Interrupts
« Reply #10 on: December 11, 2014, 09:45:03 AM »
Good work guys.

Have you tested to see what happens when you have GZLL library and BLE library running?
And using Servo library for example.

mtnscott

  • RFduino Jr. Member
  • **
  • Posts: 37
  • Karma: +0/-0
    • View Profile
Re: Timer Interrupts
« Reply #11 on: April 01, 2015, 10:49:03 AM »
Thanks for this example of how to use a nordic timer.  I was curious what timers are used for PWM signals?  If I have an application that uses I2C, BTLE, and PWM do I still have a timer available for my own needs - like changing the PWM output on a pin?


bhabrooo

  • RFduino Newbie
  • *
  • Posts: 3
  • Karma: +0/-0
    • View Profile
Re: Timer Interrupts
« Reply #12 on: May 06, 2015, 02:34:22 AM »
Thanks for this example of how to use a nordic timer.  I was curious what timers are used for PWM signals?  If I have an application that uses I2C, BTLE, and PWM do I still have a timer available for my own needs - like changing the PWM output on a pin?



Well the thing is whether you a timer available or not depends on the code you've implemented!
If you're using a timer solely for PWM then NO you don't have any timers left for use.
However what you could do is that use the timer which is being used in PWM to do some other task also .... i.e make an ISR (interrupt service routine)  that not only generates your required PWM control signal but performs tasks in parallel (not really parallel though)

ALternatively, you could Stop the i2c protocol after you've read your data from the device e.g accelerometer and use that timer for another purpose and keep switching back and forth.

lastly, (i don't recommend this if time precision is required) use a new count variable that updates periodically and use that (make your own timer)
Just be careful that whatever code is written in the ISR executes completely before the next interrupt is thrown otherwise you'd overload the stack as in:

uncompleted task1--->interrupt--->uncompleted task2--->interrupt--->uncompleted task3 ...... ad infinitum :/

petroval

  • RFduino Newbie
  • *
  • Posts: 2
  • Karma: +0/-0
    • View Profile
Re: Timer Interrupts
« Reply #13 on: March 06, 2017, 02:41:31 AM »
Hello guys,

I have a suggestion for using one more timer. I haven't used it myself yet, but it is listed in the data sheet. There is a 24-bit RTC (Real Time Counter) module, supplied with a 32.768 kHz frequency. You can find more information about it in section 4.3 of the specification manual or in chapter 19 of the reference manual. I'll let you know when I get it to run and share my example code.

Regards,
Alex

 

anything