RLP - Cap0.0 interrupt input - for use with encoder

Hi, So I’m trying to get the best time resolution on an encoder. I saw the post about the C# code. But, I figured since I may have encoders with high ferquency that I should do it in native code and save the overhead and speed.

I tried using this function to set up cap0.0 ( I believe this is D47 on the Panda II?).

It should capture the input on a rising edge. and exwecute the interrupt function (cap0). But, when I run this nothing happens:( I test it by posting PostManagedEvent and displaying a number in the debug window when cap0 is executed.


static void cap0(void)
{
	RLPext->PostManagedEvent(3); //Am I running?
	
	long Ticks = 0;
	
    T1 = T0CR0;
	if(T1 > 0 && T2 > 0 && T1> T2)
	{
		long Ticks = T1 - T2;
	}
	T2 = T0CR0;
	
	RLPext->PostManagedEvent(Ticks);
	
    T0IR = 0xFF;       //Clear the timer interrupt
    T0TCR = 0x01;      // TIMER0 Enable

    VICVectAddr =0;    //Update the VIC priorities
}

void init_timer0() {

	T0TCR  = 0x3;	                        // Timer0 Enable and reset TC and PC (reset bit 1 before use!)
	T0PR   = 0x0;                           // Set Prescale to 1, so TC counts pclk clocks and is syncronized with PC
	T0CTCR = 1; 							// CTCR counter for CAP0.0 for Timer 0
	T0CCR  = 0x7;     						// generate interrupt on falling and rising edge of cap0.0
	PINSEL3|=(3<<20); 						// PIN SELECT FOR CAP0.0
	VICIntEnable = 0x10;                    // enable interrupt 4 / Timer 0  
	VICVectAddr0 = (unsigned long)cap0;     // set interrupt vector in 0 
	VICVectCntl0 = 0x20 | 4;                // listen to interrupt 4 and enable 
  
	T0TCR = 0x2; 							//RESET the timer
	T0TCR = 0x1; 							// Enabling the timer
}

int Main(unsigned int *generalArray, void **args, unsigned int argsCount, unsigned int *argData)
{
	init_timer0();

        return 0;
}

Hi there, welcome to the forums.

Using code tags will make your post more readable. This can be done in two ways:[ol]
Click the “101010” icon and paste your code between the

 tags or...
Select the code within your post and click the "101010" icon.[/ol]
(Generated by QuickReply)

Actually, if you click the pencil to edit your existing post, highlight the code section, then hit the 101010 button you'll make the code infinetly more readable :)

If I remeber correctly then Timer0 is used by NETMF itself. It might be safer to play with Timer1

Also, if I remember correctly then there is a function declared in rpl.h to set up and hook into an interrupt. I will see if I can find my code.

Edit:
This was the code I used. It was part of a Output Compare with hardware assist.

void SetupTimers(void)
{
        //setup timer1
        PCONP |= (1 << 2); // power up timer 1
        PCONP |= (1 << 22); // power up timer 2
        PCONP |= (1 << 23); // power up timer 3
        T1CTCR = 0;            // timer only mode 
        T2CTCR = 0;            // timer only mode 
        T3CTCR = 0;            // timer only mode 
        T1TCR = 0;                              // disable timer 0
        T2TCR = 0;                              // disable timer 0
        T3TCR = 0;                              // disable timer 0
        T1IR = 0xFF;                    // reset irq flag
        T1PR = 0x00;              // prescaler
        T2IR = 0xFF;                    // reset irq flag
        T2PR = 0x00;              // prescaler
        T3IR = 0xFF;                    // reset irq flag
        T3PR = 0x00;              // prescaler

	RLPext->Interrupt.Install(5, t1_irq, 0);
	RLPext->Interrupt.Enable(5);
	RLPext->Interrupt.Install(26, t2_irq, 0);
	RLPext->Interrupt.Enable(26);
	RLPext->Interrupt.Install(27, t3_irq, 0);
	RLPext->Interrupt.Enable(27);
}
void t1_irq(void* arg) 
{
        if(T1IR&1)
        {
			RLPext->GPIO.WritePin(Pins[StartPinIndex+0],0);
            T1IR=1;//reset irq
			T1MCR &= ~(1 << (3*0));//Turn off Match IRQ
        }
        if(T1IR&2)
        {
			RLPext->GPIO.WritePin(Pins[StartPinIndex+1],0);
            T1IR=2;//reset irq
			T1MCR &= ~(1 << (3*1));//Turn off Match IRQ
        }
        if(T1IR&4)
        {
			RLPext->GPIO.WritePin(Pins[StartPinIndex+2],0);
            T1IR=4;//reset irq
			T1MCR &= ~(1 << (3*2));//Turn off Match IRQ
        }
        if(T1IR&8)
        {
			RLPext->GPIO.WritePin(Pins[StartPinIndex+3],0);
            T1IR=8;//reset irq
			T1MCR &= ~(1 << (3*3));//Turn off Match IRQ
        }

		VICVectAddr = 0 ;      // Acknowledge Interrupt
		

}

1 Like

Hi Gmod,

That’s a great start. Based on what you were saying, is it best to just ignore timer0 in native code so that you dont effect the .net?

Also, I guess my next hurdle is getting a time stamped interrupt in native code from a pin. I know I should use Cap0.0. And I would use it on a rising edge. But my starting question would be:

What pin is cap0.0 on? Has anyone used this and have any sample code?

Thanks,
Ryan

Yes, leave Timer0 completely alone. It is set up to give an interrupt at, I think, 1us, used for the system tick in the lowest layers of the NETMF system.

Cap0[0] is also related to timer0, so I would rather use Cap10, which is connected to timer1.

I don’t know if you have the document, but the user manual for this chip is essential.
http://www.nxp.com/documents/user_manual/UM10211.pdf
I assume you are using one of the USBizi boards?(Panda, Panda2, Mini, Domino)

Ok, so I’m working with Timer1 now but I’m still not getting an interrupt of the cap1.0 pin (in35 on the panda). I guess I’m just missing something…?



static void Capture1(void)
{
	RLPext->PostManagedEvent(3);
	
	long Ticks = 0;
	
        T1 = T1CR0;
	if(T1 > 0 && T2 > 0 && T1> T2)
	{
		long Ticks = T1 - T2;
	}
	T2 = T1CR0;
	
	RLPext->PostManagedEvent(Ticks);
	
        T1IR = 0xFF;       //Clear the timer interrupt
        T1TCR = 0x01;      // TIMER0 Enable

    VICVectAddr =0;    //Update the VIC priorities
}

void init_timer1() {

	/*The TCR is used to control the Timer Counter functions. 
	The Timer Counter can be disabled or reset through the TCR. 
	
	Bit 1: When one, the Timer Counter and the Prescale Counter 
	are synchronously reset on the next positive edge of 
	PCLK. The counters remain reset until TCR[1] is 
	returned to zero
	pg 557 */
	T1TCR = 0x02;       						// TIMER1 Disable; reset T0TC & T0PC
	
	/*The Prescale Counter(below) is equal to this value, the next 
	clock increments the TC and clears the PC.*/
	T1PR = 0x00000000;  						// Reset T0PR
	
	T1IR = 0xFF; 
	
	/*The CTCR selects between Timer and Counter mode, and in 
	Counter mode selects the signal and edge(s) for counting.
	
	Bit0-1: Timer Mode: the TC is incremented when the Prescale 
	Counter matches the Prescale Register.
	Timer Mode: every rising PCLK edge
	pg 558 */
	T1CTCR = 0x00;      						// Timer Mode: every rising PCLK edge
	
	/*The CCR controls which edges of the capture inputs 
	are used to load the Capture Registers 
	and whether or not an interrupt is 
	when a capture takes place.
	pg 560 */ 
	T1CCR = 0x07;       						// Capture on CAPn.0 
	
	PINSEL3|=(3<<4); 							// PIN SELECT FOR CAP1.0 - Set bit 4 and 5
	
	VICVectAddr0 = (unsigned long)Capture1;     // set interrupt vector in 0 
	VICVectCntl0 = 0x20 | 5;                	// listen to interrupt 5 and enable 

	T1TCR = 0x1; 								// Enabling the timer
	
	RLPext->PostManagedEvent(2);
}

int StartLEDBlink(unsigned int *generalArray, void **args, unsigned int argsCount, unsigned int *argData)
{
	init_timer1();
	
	return 0;
}




In stead of doing this:


VICVectAddr0 = (unsigned long)Capture1;     // set interrupt vector in 0 
VICVectCntl0 = 0x20 | 5;    

Try this:

RLPext->Interrupt.Install(5, Capture1, 0);
RLPext->Interrupt.Enable(5);

I will admit that I don’t understand this line, and I don’t have time to scour the manual:

VICVectAddr0 = (unsigned long)Capture1;     // set interrupt vector in 0 

Thanks for the tip. That’s much cleaner.

But, unfortunately, I’m still dead in the water…

Something that may be a clue is that when I try to set some of the vaues they show up as 0.


Ex. If I set T1CCR
T1CCR = 0x07;
Then, I report the event and see what the value is:
RLPext->PostManagedEvent(T1CCR);
I get a 0 even when I write a value that is greater than 0.

Incidentally, I dont get this issue with PINSEL3:
ex.
PINSEL3|=(3<<4); 							// PIN SELECT FOR CAP1.0 - Set bit 4 and 5
RLPext->PostManagedEvent(PINSEL3); //Value gets returned as 48 as I had expected

Ok, going back to the basics, am I using the correct pin for cap1.0? Currently I’m using PWM1 and setting PINSEL3 4/5 = 3 (0x11)

I suggest you get an eval version of MDK or Keil, which has code size limits, but no time limit, if I remember correctly. I think I used MDK, it came with an emulator, which was a bit of a pain to get going, but it was a tremendous help to debug the code.

just as a side-note, I have been trying to use Di3 which maps to Pin 32 Cap1.0 and have unable to get it to work using the higher level PinCapture() Class.

CAP1.0 is on P1[18] IO35 on PANDA II its D10 or PWM1 as @ GMod(Errol) has stated

Interesting this I figured out during my journey:

When the RLP Externsion says “Pin” It means IO Number. So, if you want to set up an GPIO Interrupt on Pin46. You actually use 19 since this is the “IO” number given by GHI.

Example:
RLP.h says this:
void (*EnableOutputMode)( unsigned int Pin, unsigned int InitialState );

Notice that they say “Pin.” But you have to use it like this:

RLPext->GPIO.EnableInterruptInputMode(
19, //this is actually pin 46 but it’s called “IO19” on the panda II schematic. So, use 19 or you will beat your head against the desk for a while
&InputPinArgs,
PPS_Interrupt, // RLP_GPIO_INTERRUPT_SERVICE_ROUTINE ISR,
(void*)0 // void* ISR_Param
);

Ok, got it figured out. I am assuming that I needed to set the PCLK and enable the timer via PCONP. Not much else changed in my code.


void Timer_Interrupt( void* arg )
{
	RLPext->PostManagedEvent(T3CR0);	//Give .net the latest Capture time
 
 	// Blink to know we're running correctly
	state = !state;
	RLPext->GPIO.WritePin(pin, state);
	
    T3IR |= 1;
 
}

void init_Timer_Curr(){

	// timer 3 setup
	PCONP |= 1 << 23;		// power control bit :  timer 3
	PCLKSEL1 &=	~(14 | 15);	//Peripheral clock CCLK/4
	PINSEL1 |= (3 << 14);	//set bits 14 and 15 to use CAP3.0 on An0
	
	T3MR0 = 0 ;				//Don't need it but lets set the Match Reg to 0 anyway
 
	T3MCR = 0x00;           // No Match Interrupts
	T3CCR = 0x05;			//Tick on rising edge of Cap3.0
	
	T3CTCR = 0x00;			//Make sure ticks come from PCLK
	
	T3PR = 0;               // Set prescaler to 0
	
	T3TCR = 0x02;           // Reset timer
	T3TCR = 0x01;           // Start timer
	
	RLPext->Interrupt.Install(27, Timer_Interrupt, 0)
	RLPext->Interrupt.Enable(27);
	
	RLPext->PostManagedEvent(111); //Tell .net that we finished
} 

Glad you got it going.

Funny, I didn’t have to enaple PCLK, but I did have to power up the timer. See the code I posted earlier…

Ya, never powered it up in earlier attempts. So, could have also been it as well.

I was using yours as the basis for a lot of my testing. So, thanks for the comments and posts. Now I can do all kinds of high speed stuff like PID, encoders, pulse width calc!

So, food for thought…

How fast can you acquire the capn.0 input?

For giggles, I tried 80khz last night and it just about killed it.

I wonder if it is the PostManagedEvent that uses up the time, because, all things being equal, it should happily do 1MHz.