Lost interrupts T4.1 ?

Gadget999

Well-known member
I have 6 encoders and count the pulses with a T4.1

It appears 2 of the encoders are loosing pulses over time

Do all pins have the same prority ?

What happens if 2 interrupts or more happen at the same time ?
 
I have 6 encoders and count the pulses with a T4.1

It appears 2 of the encoders are loosing pulses over time

Do all pins have the same prority ?

What happens if 2 interrupts or more happen at the same time ?

Interrupts can be set to different priorities, generally independent of pin numbers. Interrupts on multiples pins at once should not be a problem unless you cannot process them before another edge comes in on those same pins. In other words, as long at the T4.1 can handle the total interrupt rate, you should not lose any data. If you can you more about what you are doing and how you are doing it, and share your code, someone will be able to provide more help. For example, do you know the frequencies of all 6 encoder inputs?
 
The frequencies can get quite high, but the encoders loosing pulses are not the highest.

I am using 1k resistors and 3.3 v to pull them high, the encoders pull them to gnd, all fed from the same 3.3v power feed

Is it worth trying a different value resistor ?
 
T_4.1 pins put into fast mode share a single interrupt for all pins on all ports: void irq_gpio6789(void)

That single interrupt response code parses the ports/pins in a programmatic order.

When the first active pin is identified its _isr() is given a call.

I suppose other pins with standing interrupts would be handled and not lost ... but a triggering/pending interrupt again parses in the same order and if another pin parsed earlier shows activity - it will be serviced as above.

This repeats - and any pins at the end of the parse chain will only get processed when all preceding pins show no activity.

Perhaps the pins at the end of the parse order are the ones losing their counts as the prior pins are too active?
 
Sorry hard to know what is going on, without information.

Like: 6 encoders counting pulses with what? Are you using a library? What interrupts? How do you know if you are losing interrupts?

Things like do these encoders have two IO pins on each? Are you using 0, 1, or 2 interrupt per encoder?
https://www.pjrc.com/teensy/td_libs_Encoder.html

Note: on T4.x, by default all IO pin interrupts: attachInterrupt(pin, ...) funnel through one Interrupt: IRQ_GPIO6789 = 157, // RT1060 only
That is all GPIO pins which are set to run at the high speed (Ports6-9) all use this one interrupt vector.

The one interrupt will try to process all of the pins which triggered before it returns... That is:
Code:
FASTRUN static inline __attribute__((always_inline))
inline void irq_anyport(volatile uint32_t *gpio, voidFuncPtr *table)
{
	uint32_t status = gpio[ISR_INDEX] & gpio[IMR_INDEX];
	if (status) {
		gpio[ISR_INDEX] = status;
		while (status) {
			uint32_t index = __builtin_ctz(status);
			table[index]();
			status = status & ~(1 << index);
			//status = status & (status - 1);
		}
	}
}

FASTRUN
void irq_gpio6789(void)
{
	irq_anyport(&GPIO6_DR, isr_table_gpio1);
	irq_anyport(&GPIO7_DR, isr_table_gpio2);
	irq_anyport(&GPIO8_DR, isr_table_gpio3);
	irq_anyport(&GPIO9_DR, isr_table_gpio4);
}

At one point I experimented with switching some of the IO pins back to normal mode (Ports 1-4), This is controlled by 4 IOMUXC registers that we set in startup.c
Code:
	// Use fast GPIO6, GPIO7, GPIO8, GPIO9
	IOMUXC_GPR_GPR26 = 0xFFFFFFFF;
	IOMUXC_GPR_GPR27 = 0xFFFFFFFF;
	IOMUXC_GPR_GPR28 = 0xFFFFFFFF;
	IOMUXC_GPR_GPR29 = 0xFFFFFFFF;
Now if some/all of these pins are switched back to these modes, then there are more interrupt vectors that can bet setup and used:
Code:
        IRQ_GPIO1_INT0 =        72,
        IRQ_GPIO1_INT1 =        73,
        IRQ_GPIO1_INT2 =        74,
        IRQ_GPIO1_INT3 =        75,
        IRQ_GPIO1_INT4 =        76,
        IRQ_GPIO1_INT5 =        77,
        IRQ_GPIO1_INT6 =        78,
        IRQ_GPIO1_INT7 =        79,
        IRQ_GPIO1_0_15 =        80,
        IRQ_GPIO1_16_31 =       81,
        IRQ_GPIO2_0_15 =        82,
        IRQ_GPIO2_16_31 =       83,
        IRQ_GPIO3_0_15 =        84,
        IRQ_GPIO3_16_31 =       85,
        IRQ_GPIO4_0_15 =        86,
        IRQ_GPIO4_16_31 =       87,
        IRQ_GPIO5_0_15 =        88,
        IRQ_GPIO5_16_31 =       89,
But all of the core code is setup for the 6-9.
I have had some luck playing with ones like: IRQ_GPIO1_0_15 = 80
but in my short time playing with them, not with the couple specific ones like: IRQ_GPIO1_INT1

Like I believe I should be able to
1 AD_B0_02 1.02 Serial1(6) TX SPI1(3) MISO PWM1_X0 2_TX IO-16
0 AD_B0_03 1.03 Serial1(6) RX SPI1(3) CS0 PWM1_X1 2_RX IO-17

Pin 0 is GPIO1 pin 3 SO maybe: IRQ_GPIO1_INT3 should work and dito for Pin 1 IRQ_GPIO1_INT2

But I probably missed setting something up for them.
 
A bit more info

6 rotary encoders
They have 2 pins each to determine if the rotation is cw or acw
There is no libary

I will take a look at the code in a few days time

Merry Xmas :)
 
Interrupt code is quite simple

// encoder 1

void doEncoder0A(){

// look for a low-to-high on channel A
if (digitalRead(encoder0PinA) == HIGH) {
// check channel B to see which way encoder is turning
if (digitalRead(encoder0PinB) == LOW) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
else // must be a high-to-low edge on channel A
{
// check channel B to see which way encoder is turning
if (digitalRead(encoder0PinB) == HIGH) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
}

void doEncoder0B(){

// look for a low-to-high on channel B
if (digitalRead(encoder0PinB) == HIGH) {
// check channel A to see which way encoder is turning
if (digitalRead(encoder0PinA) == HIGH) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
// Look for a high-to-low on channel B
else {
// check channel B to see which way encoder is turning
if (digitalRead(encoder0PinA) == LOW) {
encoder0Pos = encoder0Pos + 1; // CW
}
else {
encoder0Pos = encoder0Pos - 1; // CCW
}
}
}
 
I'm assuming this means you have interrupt on change of each A and B pin. For 6 encoders, that's a lot of interrupts if the frequencies are high. You could replace digitalRead() with digitalReadFast(), which should help, but instead of interrupts on every edge, you could let the hardware do the quadrature counting (with no interrupts). Try the encoder library examples. It's included with TeensyDuino.
 
Can you explain how the hardware quadrature counting works ? Is it part of the encoder library ?

ok - i found it

looks pretty simple to use

if you define as below it uses assemble to make the code super fast :)

#define ENCODER_OPTIMIZE_INTERRUPTS
#include <Encoder.h>

i will try it out after xmas

Code:
Basic Usage
Encoder myEnc(pin1, pin2);
Create an Encoder object, using 2 pins. You may create mulitple Encoder objects, where each uses its own 2 pins. The first pin should be capable of interrupts. If both pins have interrupt capability, both will be used for best performance. Encoder will also work in low performance polling mode if neither pin has interrupts.

myEnc.read();
Returns the accumulated position. This number can be positive or negative.

myEnc.write(newPosition);
Set the accumulated position to a new number.


thanks everyone for the support - much appreciated :cool:
 
if you define as below it uses assemble to make the code super fast :)

Since you are using T4.1, if your frequencies are very high, you can access the hardware quadrature capability using the QuadEncoder library by @mjs513. This library lets you choose from a limited set of pins that support the 4 x QuadTimer modules in T4.x. With these timers, the hardware does the quadrature counting, with no interrupts, and you can simply read the running count value periodically to get position or speed (delta position / time).
 
Since you are using T4.1, if your frequencies are very high, you can access the hardware quadrature capability using the QuadEncoder library by @mjs513. This library lets you choose from a limited set of pins that support the 4 x QuadTimer modules in T4.x. With these timers, the hardware does the quadrature counting, with no interrupts, and you can simply read the running count value periodically to get position or speed (delta position / time).

i will hunt down the libary - i used Encoder.h and i think the performance is worse than using my own interrupts !

it must still be using interrupts in the background - the main loop is getting interrupted so much the later lines of code are not getting executed as often. The motor control on the last motors is lagging behind the others

i guess i could execute the code on the motors in a random order to share the lag around !
 
Back
Top