chipKIT® Development Platform

Inspired by Arduino™

Timer Interrupt doesn't return

Created Mon, 05 Aug 2013 22:38:04 +0000 by mnskll


mnskll

Mon, 05 Aug 2013 22:38:04 +0000

Hi, I'm trying to get Timerinterrupts to work on my DP32 board (or rather a homebuilt board with a PIC32MX250F128B with caroper's bootloader, but it works with the DP32 setting in MPIDE) I'm trying to understand how to work with Timerinterrupts, but something's wrong. The code compiles and it finds the interuptroutine "T4()", but then it gets stuck. I't doesn't seem to get back to the loop() function or trigger the Timerinterrupt again.

this is just a scaled down version of the code to nail down the problem (I'm really trying to talk to a DAC by I2S, that's a different story)

in this example LED 14 is supposed to be toggled in the main loop() and LED 13 in the interruptroutine T4(), but instead both led's turn on and after a short time, when the timer triggers the T4() routine, LED 13 is turned off and then nothing happens. I clear the interruptflag but the code doesn't seem to return to the loop().

I'm using Timer 4 here but I've also tried Timer 2 and 3 with the same result.

What have I missed?

void T4()
{
 digitalWrite(13, !digitalRead(13)); //Toggle Led, Just a test.
IFS0CLR = 0x80000;// Clear the T4 interrupt flag Bit 19

}
void setup()
{
  Serial.begin(19200);
 pinMode(13, OUTPUT); //LED
 pinMode(14, OUTPUT);//LED

 digitalWrite(14, HIGH);
 digitalWrite(13, HIGH);
   
 setIntVector(16, T4); //16 is the vector for Timer 4, T4 my interrupt handler
 T4CON=0x0; //Stop timer and clear registers

 T4CONSET = 0x0070; // set prescalar 1:256
 TMR4 = 0x0; //Clear Timer 4 register
 PR4 = 0xEFFFF; // set timer to 61439 
 IFS0CLR = 0x80000;// Clear the T4 interrupt flag Bit 19

IPC4SET = 0x00000016;// Interrupt priority 5, 2
IEC0SET = 0x80000;// Enable T4 interrupt Bit 19
T4CONSET = 0x8000;// Enable Timer4  

}

void loop()
{
delay(500);
digitalWrite(14, !digitalRead(14)); //Just Toggle LED
}

Thanks MÃ¥ns


mnskll

Tue, 06 Aug 2013 21:13:20 +0000

Ok, solved it. Still don't know what's wrong with my code, but maybe the setIntVector() routine doesn't work properly. I tried another way of calling the vector handling routineI read about in this forum, using a "C" routine, and that worked, like this

#include <sys/attribs.h>
/*   This interruptvectorfunction doesn't work, it won't release back to loop()
void T4()
{
 digitalWrite(13, !digitalRead(13)); //Toggle Led, Just a test.  //Just moved this stuff to the function below
IFS0CLR = 0x80000;// Clear the T4 interrupt flag Bit 19

}
*/
void setup()
{
  Serial.begin(19200);
 pinMode(13, OUTPUT); //LED
 pinMode(14, OUTPUT);//LED

 digitalWrite(14, HIGH);
 digitalWrite(13, HIGH);
     
 //setIntVector(16, T4); //16 is the vector for Timer 4, T4 my interrupt handler, doesn't work properly
 T4CON=0x0; //Stop timer and clear registers

 T4CONSET = 0x0070; // set prescalar 1:256
 TMR4 = 0x0; //Clear Timer 4 register
 PR4 = 0x0FFF; // set timer to 61439 
 IFS0CLR = 0x80000;// Clear the T4 interrupt flag Bit 19

IPC4SET = 0x00000016;// Interrupt priority 5, 2
IEC0SET = 0x80000;// Enable T4 interrupt Bit 19
T4CONSET = 0x8000;// Enable Timer4  

}

void loop()
{
delay(500);
digitalWrite(14, !digitalRead(14)); //Just Toggle LED
}

//Another way to call interrupt handling vector
extern "C" {

void __ISR(16, ipl6) int1Handler(void) 
{
   digitalWrite(13, !digitalRead(13)); //Toggle Led, Just a test. Same as above, but this works
IFS0CLR = 0x80000;// Clear the T4 interrupt flag Bit 19
}

}

:roll: ..so I'll stick to that then I suppose. MÃ¥ns


w5uxh

Thu, 10 Jul 2014 01:37:59 +0000

I recently had help from majenko related to configuring interrupts for the internal timers in the Max 32. I originally had used the same method as mnskll with the external "C" isr setup and was able to get the interrupt working. When I tried the suggestion from majenko to use setIntVector() setIntPrioroty() and setIntEnable(), I was not able to get it to work and believe I have the same result that mnskll had with his original approach trying to use setIntVector().

I set up a test that I believe demonstrates (to me, using a scope on a test pin) the same behavior as mnskll. I set up the interrupt, the handler is called after the correct interval, and I verify that the handler is entered. But the main loop appears to never be entered.

Comments at the end of the code describe what I see on the scope.

// For scope probe:
#define TEST_PIN 23

void setup() {                
  Serial.begin(9600);
 // Serial.println("Start in setup()");

  pinMode(TEST_PIN, OUTPUT); 

  // make sure test pin starts off low 
  digitalWrite(TEST_PIN, LOW);

  // generate an initial pulse to trigger the scope 
  digitalWrite(TEST_PIN, HIGH);
  delay(5);
  digitalWrite(TEST_PIN, LOW); 

  delay(500);

  // Try to use commands provided by Majenko
  setIntVector(_TIMER_2_VECTOR,  (isrFunc)myTimer2Handler);
  setIntPriority(_TIMER_2_VECTOR, 3, 0);

  // Use OpenTimer to set the interval parameter
  // 2*6.250 produces a 40 msec interval when pre-scale is 1:256
  OpenTimer2(T2_ON | T2_PS_1_256 | T2_SOURCE_INT, 2*6250);

  setIntEnable(_TIMER_2_IRQ); 
  // and set scope test point high here, timer interrupt handler will set it low again
  digitalWrite(TEST_PIN, HIGH);
}

void loop() {
    delay(500);
    Serial.println("In main loop");  // never get here
}

void myTimer2Handler()
{
  // set scope test point back low here
  digitalWrite(TEST_PIN, LOW);
  //Serial.println("In handler"); // for debug only!!!!
  clearIntFlag(_TIMER_2_IRQ);
}

/*
 * After downloading the program and then subsequently hitting the reset switch 
 * to restart the program,  for each reset, I see one 5 msec pulse quickly 
 * followed by one 40 msec pulse, and the main idle loop the Serial.println 
 * never happens.
 * When I uncomment the Serial.println in the interrupt handler, that does show up on the console.
*/

I do not know if OpenTimer is appropriate to use for initializing the timer registers but it looks reasonable.

Although I may have figured out how to use the core timer service for my primary timer requirements, I really would like to learn how to make use of the internal timer peripherals also.

Guidance / help would be appreciate.

Thanks,

Chuck


majenko

Thu, 10 Jul 2014 09:11:17 +0000

I have created a small timer library which handles all 5 timers for you:

[url]https://github.com/majenkotech/Timer[/url]


w5uxh

Thu, 10 Jul 2014 11:43:19 +0000

Thanks, I will try out the example first of course, and then see if I can study the code to add classes for Timer23 and Timer45. That will take some work since I am not a C++ programmer. I programmed in assembly and C for 25 years when I was younger, and in recent years (in retirement) I have just barely touched C++ so it is still a black box to me.

Should be good experience for me to try to add the 32 bit timers.


majenko

Thu, 10 Jul 2014 12:07:30 +0000

Yeah, I was pondering adding those classes too. Should be doable.


w5uxh

Sun, 21 Sep 2014 01:59:41 +0000

I have created a small timer library which handles all 5 timers for you: [url]https://github.com/majenkotech/Timer[/url]

Matt, this library was a great help when I got started on my projects a few months ago, but I am having a problem now. I had extended the library to include 32 bit timers and it has been working fine in UECIDE.

But when I discovered the other day that the project did not compile with MPIDE, because of the standard queue class I was using, I rolled my own per your recommendation, based on my old MBED Fifo class, and after fighting some interrupt conflicts, I thought I was home free. But today I found that the Timer library does not compile under Mpide 0023-macosx-20140821 but does compile under Mpide 0023-macosx-20140316. (The standard queue class did not compile under either one.)

The errors are all of this nature:

Timer.cpp: In constructor 'Timer1::Timer1()': Timer.cpp:105:9: error: invalid conversion from 'volatile unsigned int*' to 'volatile uint32_t*' Timer.cpp: In constructor 'Timer1::Timer1(int)': Timer.cpp:115:9: error: invalid conversion from 'volatile unsigned int*' to 'volatile uint32_t*'

I have not been able to figure out how to deal with this. Although I will not be using mpide myself, I would still like to be able to compile any project with either IDE so I can pass the project to others who might still be using MPIDE.

Is this something easy to deal with? I would guess it should be, but it is beyond me so far.


w5uxh

Sun, 21 Sep 2014 18:01:58 +0000

I can get it to compile with one version or the other with one simple change (seen below). But when I download my full program it does not run with either version. I suppose I still have more problems under MPIDE that are not showing up as errors. I think for now I will abandon trying to get my project to work under MPIDE and wait until you switch to the new compiler in UECIDE and then see how it goes. I assume it will fail to run then, but maybe it magically will :D

// This one compiles and displays the proper address in version 20140821
volatile  unsigned int *_pr;

// This one compiles and displays the proper address in version 20140316
//volatile  uint32_t *_pr;

void setup()
{
  Serial.begin(115200);
  Serial.println("Starting..."); 
  Serial.println((uint32_t)&PR1, HEX);

  _pr = &PR1;
  Serial.println((unsigned int)_pr,HEX);
}


void loop()
{
 delay(1000); 
}

michastro

Fri, 07 Nov 2014 10:12:22 +0000

Hello, Just for your information I have made a small program to show the use of timer23 and timer45. This program can be compiled with MPIDE and UECIDE without any change. I don't use any library. LED1 1Hz LED2 0.5Hz The important thing is to use: void attribute((interrupt)) T23() and not void T23() attribute((interrupt)) allow the compiler to generate function entry and exit sequences suitable for use in an interrupt handler.

const int LED1 = 13;      // LED on Uno32
const int LED2 = 43;      // LED on Uno32

void __attribute__((interrupt)) T23()
{
	mT23ClearIntFlag(); // Clear interrupt flag
	digitalWrite(LED1, !digitalRead(LED1)); //Just Toggle LED
}

void __attribute__((interrupt)) T45()
{
	mT45ClearIntFlag(); // Clear interrupt flag
	digitalWrite(LED2, !digitalRead(LED2)); //Just Toggle LED
}



void setup()
{
	pinMode(LED1,OUTPUT);
	pinMode(LED2,OUTPUT);
	setIntVector(_TIMER_23_VECTOR,T23);
	OpenTimer23( T23_ON | T23_PS_1_1 | T23_SOURCE_INT, 0x0001);
	ConfigIntTimer23((T23_INT_OFF | T23_INT_PRIOR_3));
	PR2=0xB400;	
	PR3=0x04C4;	//0x04C4B400=80000000-> 1Hz timer
	setIntVector(_TIMER_45_VECTOR,T45);
	OpenTimer45( T45_ON | T45_PS_1_1 | T45_SOURCE_INT, 0x0001);
	ConfigIntTimer45((T45_INT_OFF | T45_INT_PRIOR_2));
	PR4=0x5A00;	
	PR5=0x0262;	//0x02625A00=40000000-> 2Hz timer	
	mT23IntEnable(1);  
	mT45IntEnable(1);  
}

void loop()
{
}