G120 vs. USBizi RLP Interrupt Code

I’m migrating to a new board design that replaces the USBizi processor with the G120 module. I’m monitoring a pendant encoder using simple RLP code that will detect the direction of rotation and update a counter value. The same code is used on both designs (besides pin number modifications). I’m seeing an issue with the G120 board, where when the encoder is rotated quickly, it doesn’t seem to be picking up all the edges. I’m using P0.4 and P0.5 to detect the edges on Chan A and B of the encoder.

Are there any differences between the G120 and USBizi that I need to consider in this scenario? The code is working with the G120, as I am getting count changes and the outputs are correctly toggling with direction change, but high speed edges aren’t being counted.

My RLP code is shown below. Let me know if more details are needed. Thanks!

#include "RLP.h"

 #define CHAN_A 5		// pins used for pendant encoder
 #define CHAN_B 4
 #define OUT_13 70
 #define OUT_14 73


int counter;

// channel A ISR quadrature decoding
//
// a rising edge when channel B is high means one count in positive direction
//               when channel B is low it means a count in the negative direction.
// 
// etc
//
     
void chan_A_ISR(unsigned int Pin, unsigned int PinState, void* Param)
{
	
	if(RLPext->GPIO.ReadPin(CHAN_B))
	{
		RLPext->GPIO.WritePin(OUT_13, RLP_FALSE);
		RLPext->GPIO.WritePin(OUT_14, RLP_TRUE);
		counter++;
		return;
	}
	else
	{
		RLPext->GPIO.WritePin(OUT_13, RLP_TRUE);
		RLPext->GPIO.WritePin(OUT_14, RLP_FALSE);
		counter--;
		return;
	}	
}

void chan_B_ISR(unsigned int Pin, unsigned int PinState, void* Param)
{
	if(RLPext->GPIO.ReadPin(CHAN_A))
	{
		RLPext->GPIO.WritePin(OUT_13, RLP_TRUE);
		RLPext->GPIO.WritePin(OUT_14, RLP_FALSE);
		counter--;
		return;
	}
	else
	{
		RLPext->GPIO.WritePin(OUT_13, RLP_FALSE);
		RLPext->GPIO.WritePin(OUT_14, RLP_TRUE);
		counter++;
		return;
	}	
}


int initEncoder(unsigned int *generalArray, void **args, unsigned int argsCount, unsigned int *argSize)
{
	RLP_InterruptInputPinArgs InputPinArgs;
	
	counter = 0;
	
	InputPinArgs.GlitchFilterEnable = RLP_TRUE;
	InputPinArgs.IntEdge = RLP_GPIO_INT_EDGE_HIGH;
	InputPinArgs.ResistorState = RLP_GPIO_RESISTOR_PULLUP;

	if(!RLPext->GPIO.EnableInterruptInputMode(CHAN_A,&InputPinArgs,chan_A_ISR,(void*) 0)) return 0; // ERROR
    if(!RLPext->GPIO.EnableInterruptInputMode(CHAN_B,&InputPinArgs,chan_B_ISR,(void*) 0)) return 0; // ERROR

	RLPext->GPIO.EnableOutputMode(OUT_13, RLP_FALSE); // up count diagnostic LED
	RLPext->GPIO.EnableOutputMode(OUT_14, RLP_FALSE); // down count diagnostic LED

    return 1; // OK
}


int readCounter(unsigned int *generalArray, void **args, unsigned int argsCount, unsigned int *argSize)
{
	return counter;
}

So it works on G120 but it is not fast enough?

Correct. When I do slow ticks on the encoder the count increments as expected, but as you increase speed, the count rate increase to a certain point and drops to a consistently slow rate.

If this was managed code, I would have an explanation. This would involve interrupt queueing.
There is a delay between the hardware interrupt and when the interrupt handler is called. Reading the opposite edge state via a direct read would result in a missing pulse if an interrupt for the opposite edge was queued. I am not sure about interrupt queueing with RLP.

I suggest that you maintain a variable for the A and B states. When an interrupt occurs, update the state of the edge using the passed PinState, and use the stored variable for the other edge state. This will avoid possible problems with pending interrupt race conditions.

Thanks for the suggestion Mike. I tried to implement your recommendation but the result still wasn’t correct. If I went slow things were ok, but if rotated quickly the increments weren’t consistent. Sometimes it would add and sometimes it would subtract even when the rotation direction was the same. My modified RLP code is shown below.

#include "RLP.h"

 #define CHAN_A 5		// pins used for pendant encoder
 #define CHAN_B 4
 #define OUT_13 70
 #define OUT_14 73


int counter;
unsigned int a_state = 0;
unsigned int b_state = 0;

// channel A ISR quadrature decoding
//
// a rising edge when channel B is high means one count in positive direction
//               when channel B is low it means a count in the negative direction.
// 
// etc
//
     
void chan_A_ISR(unsigned int Pin, unsigned int PinState, void* Param)
{
	a_state = PinState; 

	if (a_state == 1)
	{
		if(RLPext->GPIO.ReadPin(CHAN_B))
		{
			RLPext->GPIO.WritePin(OUT_13, RLP_FALSE);
			RLPext->GPIO.WritePin(OUT_14, RLP_TRUE);
			counter++;
			return;
		}
		else
		{
			RLPext->GPIO.WritePin(OUT_13, RLP_TRUE);
			RLPext->GPIO.WritePin(OUT_14, RLP_FALSE);
			counter--;
			return;
		}	
	}
}

void chan_B_ISR(unsigned int Pin, unsigned int PinState, void* Param)
{
	b_state = PinState; 

	if (b_state == 1)
	{
		if(RLPext->GPIO.ReadPin(CHAN_A))
		{
			RLPext->GPIO.WritePin(OUT_13, RLP_TRUE);
			RLPext->GPIO.WritePin(OUT_14, RLP_FALSE);
			counter--;
			return;
		}
		else
		{
			RLPext->GPIO.WritePin(OUT_13, RLP_FALSE);
			RLPext->GPIO.WritePin(OUT_14, RLP_TRUE);
			counter++;
			return;
		}	
	}
}


int initEncoder(unsigned int *generalArray, void **args, unsigned int argsCount, unsigned int *argSize)
{
	RLP_InterruptInputPinArgs InputPinArgs;
	
	counter = 0;
	
	InputPinArgs.GlitchFilterEnable = RLP_TRUE;
	InputPinArgs.IntEdge = RLP_GPIO_INT_EDGE_BOTH;
	InputPinArgs.ResistorState = RLP_GPIO_RESISTOR_PULLUP;

	if(!RLPext->GPIO.EnableInterruptInputMode(CHAN_A,&InputPinArgs,chan_A_ISR,(void*) 0)) return 0; // ERROR
    if(!RLPext->GPIO.EnableInterruptInputMode(CHAN_B,&InputPinArgs,chan_B_ISR,(void*) 0)) return 0; // ERROR

	RLPext->GPIO.EnableOutputMode(OUT_13, RLP_FALSE); // up count diagnostic LED
	RLPext->GPIO.EnableOutputMode(OUT_14, RLP_FALSE); // down count diagnostic LED

    return 1; // OK
}


int readCounter(unsigned int *generalArray, void **args, unsigned int argsCount, unsigned int *argSize)
{
	return counter;
}

you are still reading the other pot state via hardware. In the A interrupt use the b_state variable. And the a_state in the B handler.

My apologies. I tried a lot of different things before responding to the post, and I didn’t grab the right version of the code. This is the code that matches your suggestion. The result that I described in the previous post is still valid for this code.

#include "RLP.h"

 #define CHAN_A 5		// pins used for pendant encoder
 #define CHAN_B 4
 #define OUT_13 70
 #define OUT_14 73


int counter;
unsigned int a_state = 0;
unsigned int b_state = 0;

// channel A ISR quadrature decoding
//
// a rising edge when channel B is high means one count in positive direction
//               when channel B is low it means a count in the negative direction.
// 
// etc
//
     
void chan_A_ISR(unsigned int Pin, unsigned int PinState, void* Param)
{
	a_state = PinState; 

	if (a_state == 1)
	{
		if (b_state == 1)
		{
			RLPext->GPIO.WritePin(OUT_13, RLP_FALSE);
			RLPext->GPIO.WritePin(OUT_14, RLP_TRUE);
			counter++;
			return;
		}
		else
		{
			RLPext->GPIO.WritePin(OUT_13, RLP_TRUE);
			RLPext->GPIO.WritePin(OUT_14, RLP_FALSE);
			counter--;
			return;
		}	
	}
}

void chan_B_ISR(unsigned int Pin, unsigned int PinState, void* Param)
{
	b_state = PinState; 

	if (b_state == 1)
	{
		if (a_state == 1)
		{
			RLPext->GPIO.WritePin(OUT_13, RLP_TRUE);
			RLPext->GPIO.WritePin(OUT_14, RLP_FALSE);
			counter--;
			return;
		}
		else
		{
			RLPext->GPIO.WritePin(OUT_13, RLP_FALSE);
			RLPext->GPIO.WritePin(OUT_14, RLP_TRUE);
			counter++;
			return;
		}	
	}
}


int initEncoder(unsigned int *generalArray, void **args, unsigned int argsCount, unsigned int *argSize)
{
	RLP_InterruptInputPinArgs InputPinArgs;
	
	counter = 0;
	
	InputPinArgs.GlitchFilterEnable = RLP_TRUE;
	InputPinArgs.IntEdge = RLP_GPIO_INT_EDGE_BOTH;
	InputPinArgs.ResistorState = RLP_GPIO_RESISTOR_PULLUP;

	if(!RLPext->GPIO.EnableInterruptInputMode(CHAN_A,&InputPinArgs,chan_A_ISR,(void*) 0)) return 0; // ERROR
    if(!RLPext->GPIO.EnableInterruptInputMode(CHAN_B,&InputPinArgs,chan_B_ISR,(void*) 0)) return 0; // ERROR

	RLPext->GPIO.EnableOutputMode(OUT_13, RLP_FALSE); // up count diagnostic LED
	RLPext->GPIO.EnableOutputMode(OUT_14, RLP_FALSE); // down count diagnostic LED

    return 1; // OK
}


int readCounter(unsigned int *generalArray, void **args, unsigned int argsCount, unsigned int *argSize)
{
	return counter;
}

how do you know that you are missing counts? I don’t know if watching LEDs blinking is a valid method.

The LED’s are only for a quick visual reference that the code is running. I’m printing out the count value from my managed code that calls the “readCounter” procedure, so I’m able to see the rate at which the count is being updated as the encoder rotates.

So, I finally dug back into this issue. I never figured out why the RLP method wasn’t working, but I did find a code share entry that did the trick.

https://www.ghielectronics.com/community/codeshare/entry/790

And its all in managed code, so it’s much easier to deal with. Thanks for everyone’s suggestions!

@ jfox3721 -

Remove glitch filter will fix your issue.