I have attached TLE4935L Hall bipolar latching sensor output to pin 3 of mega2560 in my bicycle to measure wheel speed and distance.
But I get too many interrupts. The simplified program to demonstrate the situation is below:
/* for Arduino mega2560 only
Bipolar latching Hall sensor TLE4935L is sensing coin-shaped magnets, with poles on
the flat sides. At least 2 magnets are on a bicycle wheel and have poles N and S alternating towards the sensor.
the sensor. "Latching" means there should be no bouncing according to the datasheet.
Sensor connections: GND, 5V, signal to pin 3 with 50 K resistor to 5 V, 2.2 nF capacitor
between signal and ground, and 2.2 nF capacitor between 5 V and ground.
Magnets 10 mm x 2 mm neodymium, distance to sensor about 2 mm, signal is very clean
Mega2560 has some peculiarity with attachInterrupt: see
http://rcarduino.blogspot.fi/2013/04/the-problem-and-solutions-with-arduino.html
there the chapter "Differences in External Interrupts"
*/
#define bufmax 32
#define bufmask 0x1F
const int sensorPin = 3; // external interrupt 1 (not 0)
byte isr_reading_ind = 0; // index when reading the buffer
volatile byte isr_writing_ind = 0; // index when writing the buffer in isroutine
volatile byte isr_changes[bufmax] = {bufmax*0}; // 1 is up, 0 is down
void isroutine(){
byte change ; // 1 = up, 0 = down
change = bitRead(PINE, 5); //sensorPin=3 is port E pin 5 in mega2560
isr_changes[isr_writing_ind] = change;
isr_writing_ind = (isr_writing_ind + 1) & bufmask; // circular buffer
}
void collectdata() { // from a bicycle wheel: about 6 edges/second in test
int p = 0;
while(true){ // forever here
while(isr_writing_ind == isr_reading_ind){}; // wait for interrupt
Serial.print(p);
Serial.print(F("\t"));
Serial.println(isr_changes[isr_reading_ind]);
isr_reading_ind = (isr_reading_ind +1) & bufmask;
p++; //
}
}
void collectdata_withoutinterrupt(){
Serial.println(F("Read 32 changed values from the hall sensor without interrupt"));
Serial.println(F("Rotate the bicycle wheel "));
int p = 0;
static byte change = 0, oldchange = 0;
while (p < bufmax){
change = bitRead(PINE, 5);
if (change != oldchange){
isr_changes[p] = change;
oldchange = change;
p++;
}
}
for (p = 0; p < bufmax;p++){
Serial.print(p);
Serial.print(F("\t"));
Serial.println(isr_changes[p]);
}
}
void setup(){
Serial.begin(115200);
Serial.println(F("#debugging: why extra interrupts? "));
pinMode(sensorPin, INPUT); // latching hall sensor TLE-4935L with pull up resistor 50 K
collectdata_withoutinterrupt();
attachInterrupt(1, isroutine, CHANGE);
//attachInterrupt(1, isroutine, FALLING);
//attachInterrupt(1, isroutine, RISING);
Serial.println(F("Now we read with interrupt for ever:"));
collectdata();
}
void loop(){
}
/* example output:
#debugging: why extra interrupts?
Read 32 changed values from the hall sensor without interrupt
Rotate the bicycle wheel
0 1
1 0
2 1
3 0
4 1
5 0
6 1
7 0
8 1
9 0
10 1
... etc
Now we read with interrupt for ever:
0 1
1 1
2 0
3 1
4 1
5 1
6 0
7 0
8 1
9 1
10 0
11 1
12 1
13 1
14 0
15 0
16 1
17 1
18 0
19 1
20 1
21 0
22 1
23 1
... etc
I was expecting the same output in both routines.
*/
According to the TLE4935L datasheet, there is no need for debouncing. I have no oscilloscope so I cannot be sure how the signal looks like. In the multimeter the levels are very clean. In any case, if there were rapid oscillations, should the output show alternating up and down values in any case?
(it is easy to eliminate extra interrupts in the program, but very curious to know, why they happen).
There are currently 2 magnets on the wheel, one has south face towards the sensor, and the second north face. Therefore, I expect to get one rising edge and/or one falling edge per revolution. Or 2 changes in the CHANGE mode of attachInterrupt(..,..,CHANGE).
I copied your program (thanks!), and run it with parameter "RISING". There were 2 interrupts per revolution (I expected one). With the parameter "CHANGE" there were irregularly 1 or 2 interrupts per revolution (expected two). With parameter "FALLING" 1,2, or 3 ints/rev.
When rotating very very slowly the results were the same.
First the magnets were about 4 cm apart, then on the opposite sides of the wheel: no difference in behavior in short tests.
From earlier tests with timers involved I have seen that the extra interrupts precede the "normal ones" about 16-24 microseconds , and their probablity might depend on the length of the interrupt routine.
Therefore I thought this might be programming error , but now with your program results it seems that there is something strange with the sensor arrangement. Perhaps the pull up resistor of 50 K is too high (say Allegro pages, perhaps; although this sensor is from Infineon).
Your probably getting the equivalent of switch contact bounce on the interrupt as the field is wavering on the edge of detection. What you could do is mark the time the interrupt fires and if it's less than x time since the last fire then ignore it.
When you ran the test without the interrupt and saw the 32 predictable changes 0-1-0-1... did you see the expected one rising edge and one falling edge per revolution?
Are you certain that the magnet polarity is correct?
Robin2:
If you reliably get 2 interrupts per revolution using RISING isn't that the problem solved?
...R
Yes. In fact with a similar method which Riva described I have (temporarily) solved the problem. But this mystery bothers me anyhow. Later this unknown phenomenon may lead to even more puzzling problems.
PS. In some more tests even the parameter "RISING" gave few wrong values. I have to measure and check the directions ja strengths of the magnetic fields more accurately. I made relatively thorough tests about distances and directions on my desk, but after moving the equipment to my bicycle some things may have changed. More tests can easily be done, because the bicycle is behind me hanging from the ceiling :). An oscilloscope would be useful.
cattledog:
When you ran the test without the interrupt and saw the 32 predictable changes 0-1-0-1... did you see the expected one rising edge and one falling edge per revolution?
Are you certain that the magnet polarity is correct?
Good question! No, I did not check :-[
Polarity ? The polarities are definitely opposite directions (I tried with a third magnet). But which is south and which is north, I
do not know. I thougth the order does not matter. Ahaa, I could check by rotating the wheel backwards. If results are different, I report here in half an hour.
After half an hour ;)
Ok, test without interrupt (in my own program) gave exactly one falling edge and one rising edge per revolution, when rotating the wheel by hand slowly.
Good questions here from you all! Now I am even more puzzled than at the start: if the sensor gives correct values when not using interrupts, then the error cannot be in the hardware signal, or can it be?
Backward rotation was not necessary: by changing the starting location of the wheel we get different order of flux transitions ... I conclude that the starting location does not matter.
That is true. The same link, a little later states:
The Arduino team have hidden some of the differences between the ATMega328 and ATM2560 so that attaching INT0 using the attachInterrupt function will attach an interrupt to digital pin 2 on both chips even though on the Mega digital pin2 is actually INT4.
I think the same applies correspondingly to digital pin 3 and INT5 (or does it?):
The Arduino IDE module Winterrupts.c contains these for me mysterious lines:
The Arduino IDE is 1.0.5 and mega2560 is earlier than Rev3 (no revision marking), genuine Arduino board .afaik.
But anyhow, if the signal pin were not supported, how come that everything "almost works"?
Perhaps I should test the whole setup with an UNO board, if there is the least uncertainty here?
A logic analyser would tell you whether you are getting bounces or not. Various models of the Saleae brand would do it, some of them have analog as well nowadays.
optimistx:
Perhaps I should test the whole setup with an UNO board, if there is the least uncertainty here?
You're not using a pin change interrupt. And clearly you're reading the correct pin and it's generating interrupts.
You should be getting two edges, one rising and one falling, each time either of the magnets passes the sensor. It seems unlikely that this pulse would be so short that you'd partially miss it due to ISR latency. But it would be worth tagging the reads of the level with 16-bit timer values as a kind of poor man's logical analyzer.
Previously you posted:
From earlier tests with timers involved I have seen that the extra interrupts
precede the "normal ones" about 16-24 microseconds , and their probablity*
might depend on the length of the interrupt routine.*
From earlier tests with timers involved I have seen that the extra interrupts
precede the "normal ones" about 16-24 microseconds , and their probablity*
might depend on the length of the interrupt routine.*
What does this mean?
In a not_simplified program version there is a call to micros() during interrupt service routine. If the value is less than the previous micros() + 28 microseconds, the interrupt is not stored to the rotating buffer. This acts as a debouncing program with a suitable time constant.
(With this type of debouncing the same setup connected to a reed switch had worked tens of kilometers without obvious errors. I wanted to use hall sensors to get more accurate measurements to find out acceleration e.g. having tens of magnets in the wheel )
When a constant of 28 microseconds was used, no spurious interrupts were visible for the program, which reads the rotating buffer.
Printing is slow, its blocking and uses its own interrupts (I believe). I would collect the data without printing, then print the results after a desired block of data has been collected, then repeat.
optimistx:
When a constant of 28 microseconds was used, no spurious interrupts were visible for the program, which reads the rotating buffer.
How did you deduce that you were getting spurious interrupts instead of missing interrupts?
What I think would be worth doing would be to correlate a time stamp with each reading, for both the non-interrupt and interrupt cases. That is, call micros and then store the value in an array that uses the same index as the data value. I think it would give you valuable information.
jboyton:
How did you deduce that you were getting spurious interrupts instead of missing interrupts?
What I think would be worth doing would be to correlate a time stamp with each reading, for both the non-interrupt and interrupt cases. That is, call micros and then store the value in an array that uses the same index as the data value. I think it would give you valuable information.
Good question! In fact, there might be anyone of those possibilities. When the interrupting pin (port E, pin 5)
is read during the ISR, its value can be the same as in the next interrupt, althought the mode is CHANGE. That is not logical. There might be an interrupt missing in between them.
I try now implement a faster version of the program which dlloyd proposes above: polling the pin port E, pin 5 as fast as possible, without using interrupts. And timestamp every change. Store the the results to an array, then print when ready.
Riva:
Have you tried turning on internal (or external) pullup resistor on the interrupt pin? Maybe the pin is floating and causing the multiple triggers.
Yes, I was suspecting that too. Turning on the internal pull up resistor on pin 3 did not make any difference in short tests.
I have perhaps "too strong" magnets, because the tail of the green curve in the above image goes under the x-axis so much, that it sometimes exceeds the negative threshold, but not always.
The magnets are the shape of a coin, with poles on the heads and tails sides. One can see images of bar magnet field lines in the net: imagine them shortened to a thickness of a coin and think of the field lines at the side of the coin. They are opposite direction compared to the field lines just above the flat face.
In "head on operation" there is no such flux reversal at the sensor:
Thus there has been extra signal changes of very short duration every now and then.
I am sorry to have posted this problem in the programming section instead of sensors.
Thank you for the questions and ideas which helped to solve this problem!
I have perhaps "too strong" magnets, because the tail of the green curve in the above image goes under the x-axis so much,
that it sometimes exceeds the negative threshold, but not always.
Have you connected the TLE4935L sensor as per Figure 8 here?