T3.6 Interrupts Problem

Narrowboater

Active member
My project is to move the head of a metal-working mill using a stepper motor controlled by a T3.6, using the mill's built-in DRO to know where the head has got to. (This is not the usual way of doing it.)
The DRO display provides power to the Scale which reports the movement by changing the high/low level of 3 output lines A, B, Z, (which I will denote as uppercase for going high and lowercase for going low).
These lines go back to the DRO display which counts them and displays the changing position.
I have intercepted these lines and feed them into the T3.6 as well.
The lines are long, of the order of 2 metres.
Each line goes into a pair of Teensy pins, to one of which I have attached a RISING ISR and the other a FALLING ISR. The "rising" pin of each pair is set as INPUT_PULLUP and the other, the "falling" pin as INPUT. They go in via a SN74AHCT125 to convert the DRO 5V to 3V3 for the T3.6 and have a 0.1 microfarad capacitor across the 125 supply.
I need to catch both as each constitutes a movement (5 microns).
The normal pattern of responses is ABabABabABab… etc or BAbaBAbaBAba… depending on the direction of movement.
My problem is that occasionally (after a lot of good events) I get eg BAaba where I have got two consecutive "falling" interrupts without an intervening "rising" interrupt on a single line. The pattern suggests that one of these (the first, immediately after the line rising) is spurious rather than a "rising" interrupt being lost. This happens on any of the 3 lines.
I have not seen consecutive "rising" events but cannot rule out that they may occur.
I am a retired programmer with only a basic knowledge of electronics.

I would appreciate answers to the following questions:
1. Is my pairing of input pins legal?
2. Can poor signal quality result in consecutive falling interrupts without an intervening rising interrupt?
3. Is the INPUT_PULLUP/INPUT setting affecting the problem?
4. Is there anything else unsatisfactory about what I have described?
I am asking if there any elephants here, before submitting huge quantities of code!
 
The T3.6 (and other Teensy boards) have the capability to do quadrature (AB and ABZ) counting in hardware, so you could entirely avoid the dual inputs and interrupt-based counting. With that said, the things that I wonder about are how fast are your signals changing, are you missing edges due to your interrupt processing taking too long, might you have a problem with multiple ISRs changing the same variable, and are interrupts being disabled sometimes. Do you know the frequency of the encoder signals? Can you show one of your counting ISRs?
 
Would help to know additional stuff, like:

what how fast are your interrupts?
What are you using to capture them? First guess attachInterrupt(pin...)
On what pins?

Reasons I am asking some of this, is that when you do an attachInterrupt, it actually has setup an interrupt for the IO port on which the pin resides. So all pins on that port use the same interrupt. When that interrupt is triggered, the actual system installed interrupt (attachInterruptVector) then scans the ports interrupt flags and calls off to each of those which were triggered...

So sometimes you can reduce this overhead, if you can setup your sketch such that all of the pins you wish to detect interrupts on are on different ports, then you can set your own interrupt handler and bypass this little extra overhead.

But as mentioned, there may be better solutions.
 
The T3.6 (and other Teensy boards) have the capability to do quadrature (AB and ABZ) counting in hardware, so you could entirely avoid the dual inputs and interrupt-based counting. With that said, the things that I wonder about are how fast are your signals changing, are you missing edges due to your interrupt processing taking too long, might you have a problem with multiple ISRs changing the same variable, and are interrupts being disabled sometimes. Do you know the frequency of the encoder signals? Can you show one of your counting ISRs?

T3.6 built-in quadrature is not appropriate since the project needs to be aware of signal patterns, it is not just a counting exercise.

The patterns observed indicate an extra, spurious, edge, not a missing edge.

Multiple ISRs do change the same variable, but the source is not supposed to be able to generate multiple edges at the same time.

Yes, interrupts are disabled outside the ISRs briefly in my code, but I don't know what goes on in Libraries.

Here are 2 ISRs (of 6 in total, all of the same pattern).
Code:
FASTRUN void DROARiseIsr() { // 'A' 
  if (lastDROEventAa == 'A') {abendCode = 4011;} // Previous A/a must not be same level
  // Handle Direction 
  // (Aa or aA) or (Bb or bB), with no intervening (B/b) or (Aa) is always a change of direction
  // which we can handle without knowing what that direction is!
  if (lastDROEvent == LINE_Aa) {DRODir = !DRODir; codCnt++;} // and count change of direction
  // Otherwise we do do need to work out what the direction currently is
  else {if (DROBLineHIGH) {DRODir = UP;} else {DRODir = DOWN;}} 
  // Update Our Position
  if (DRODir == UP) {absPosition64un+=UNITS_PER_EDGE;} else {absPosition64un-=UNITS_PER_EDGE;}
  // Housekeeping
  DROALineHIGH = true;
  DROARiseCnt++;
  AaBbSinceLastZz++;
  lastDROEvent = LINE_Aa;
  lastDROEventAa = 'A';  
  if (traceIx >= traceSize) {traceIx = 0;} trace[traceIx++]='A';
} // ***
FASTRUN void DROBRiseIsr() { // 'B' // ***
  if (lastDROEventBb == 'B')  {abendCode = 4021;} // Previous B/b must not be same level
  if (lastDROEvent == LINE_Bb) {DRODir = !DRODir; codCnt++;} 
  else {if (DROALineHIGH) {DRODir = DOWN;} else {DRODir = UP;}}    
  if (DRODir == UP) {absPosition64un+=UNITS_PER_EDGE;} else {absPosition64un-=UNITS_PER_EDGE;}
  DROBLineHIGH = true;
  DROBRiseCnt++;
  AaBbSinceLastZz++;  
  lastDROEvent = 'B';
  lastDROEventBb = LINE_Bb;  
  if (traceIx >= traceSize) {traceIx = 0;} trace[traceIx++]='B';
} // ***

All relevant variables are defined as volatile.

Lastly, I have done quite a lot of work to try and find the input signal frequency, which is difficult since the signals have a mechanical not electrical origin, and have had a major equipment failure in the process, so it will be a couple of weeks before I have a system working sufficiently to generate data, again.

Yes, I am using attachInterrupt. I have changed the code to spread the pins over the ports, but can't test it yet!

I will come back when I have the failing component replaced.
 
T3.6 built-in quadrature is not appropriate since the project needs to be aware of signal patterns, it is not just a counting exercise.

The patterns observed indicate an extra, spurious, edge, not a missing edge.

Multiple ISRs do change the same variable, but the source is not supposed to be able to generate multiple edges at the same time.

Yes, interrupts are disabled outside the ISRs briefly in my code, but I don't know what goes on in Libraries.

All relevant variables are defined as volatile.

Lastly, I have done quite a lot of work to try and find the input signal frequency, which is difficult since the signals have a mechanical not electrical origin, and have had a major equipment failure in the process, so it will be a couple of weeks before I have a system working sufficiently to generate data, again.

Yes, I am using attachInterrupt. I have changed the code to spread the pins over the ports, but can't test it yet!

I will come back when I have the failing component replaced.

I don't know what you mean by signal patterns, other than the phase relationship between A and B, but if you can't use the quadrature hardware, I wonder if you have thought of using level-triggered interrupts rather than edge-triggered? That would reduce the number of inputs from 6 to 3 and simplify the code. I can't provide any help on the hardware design, but I think I can say that yes, it could be a signal quality problem. One suggestion I would make is to use the EncSim (encoder simulator) library to test your code. With this library you can generate the ABZ signals and should be able to test all of your software with known good signals. If it works correctly with EncSim but not with the real sensor/wiring, it doesn't pinpoint your issue, but at least you would know the software is okay. You would also be able to test with increasing signal frequency and see where the interrupt rate becomes too high for the processor.
 
Don't know if it matters, but I do see one difference between your two ISRs that looks suspicious. Is it correct?

In DROARiseIsr() you have

Code:
  lastDROEvent = LINE_Aa;
  lastDROEventAa = 'A';

but in DROBRiseIsr() it looks like you have those assignments backwards

Code:
  lastDROEvent = 'B';
  lastDROEventBb = LINE_Bb;
 
After a major rebuild of the hardware I discovered that the problem was caused by a defective 74HCT125 that was being used to translate the scale signal from 5V to 3V3. It was hard to discover because 90% of the time it worked correctly. The good aspect was that it was simple to correct.
 
Back
Top