hall effect tachometer

efftek
Thu Aug 03, 2017 10:47 pm
Hi,

I dont want to reinvent the wheel but have not found any code for the stm32duino using a hall effect sensor for measuring RPM, just code for the Arduinos.

Has anyone got a working code to calculate RPM from a hall effect sensor? typically, I want to sample for 3-5 seconds and calculate RPM from the number of pulses from the sensor.

Cheers, Steve.


RogerClark
Thu Aug 03, 2017 10:54 pm
Please use google to search the forum

At least one other person is doing something similar


Ollie
Fri Aug 04, 2017 2:40 pm
Efftek,

I am not planning to share any actual implementation code here because your arrangements can be so different compared to my solution that more effort is required for refactoring than for creating a solution from scratch.

Here is a list of solutions that you can use for the speed (and position measurement)

  • An interrupt that is triggered by the hall sensor. Increment a 32 or 64 bit counter in every interrupt.
    When calculating the RPM calculate the delta time and delta count.
    In the case of 32 bit counter, ignore the wraparound. The delta count will handle that inherently.
  • A timer is connected to the hall sensor. The timer counter is incremented by the sensor.
  • If a position is required in addition of the speed (RPM), then you have to use two hall sensors for quadrature encoding
    > Interrupts can be used to calculate the speed and positions
    > the timers have a special mode for quadrature encoding, but speed cannot be measured at the same time

I have developed DC motor controllers (30V, 15A) using the hall sensor quadrature encoders connected to interrupts in the following configurations
– 2 motors by Teensy 3.2
– 4 motors by Teensy 3.5
– 6 motors by STM32F407VE (blue pad)

With the inside knowledge of the magnets driving the hall sensors, I can have an accurate speed reading at the millisecond level, This requires a lot of special implementations that are not relevant for RPM readings at the 3-5 second intervals.


efftek
Fri Aug 04, 2017 4:18 pm
Thanks Ollie

Basically, I want to take a vibration reading from a variable speed machine. The fMax (maximum frequency in the FFT spectra) will depend on the machine’s speed. I only need to read the speed once every five minutes or so when a vibration reading is required. The way I thought about doing it is as follows

start looking (polling) at my input pin
wait until it goes high and set the start time
apply a small delay for debouncing
wait until it goes high again and set end time
calculate time taken for one revolution and therefore speed
do this several times and average

I have made a unit to display flow rate and cumulative flow for a peristaltic effluent pump at a manufacturers site and that has been installed about a year now – on that I used an arduino UNO and set up an interrupt which incrimented a counted each revolution. The screen updated avery 5 seconds and reset the counter to zero. I suppose I could do this in the same way, resetting the counter when I want to calculate speed and finding out how many pulses have been in a given time – as the speed is going to be about 20-25 revs/second, If I read for say 3 seconds, it should be reasonably accurate. However, until now, I have not used interrupts on the stm32’s

I’d appreciate your thoughts.

Steve


zoomx
Sat Aug 05, 2017 6:58 am
Get a non linear Hall sensor. In this application will work better than a linear Hall sensor.

Ollie
Sat Aug 05, 2017 3:42 pm
If you are using the normal hall sensor activated with a magnet, there is no debouncing. Here are some general comments:
1. Busy reading of an input is not a good idea. At that time, your application cannot react to anything else – unless you are using a genuine RTOS
2. Resetting counters/timers can have unexpected side effects. It is better to allow the counters to wrap around and just take the reading whenever required. By storing the old value is logically same as resetting the counter.
3. If you are doing any FFT type of analysis, then the average values are impacting the frequency information. For display purposes, a simple exponential filter can be used instead of the boxcar averages.
4. You should learn the interrupt handling in the 3 different Arduino platforms
– Atmel AVR, quite easy
– Teensy 2x/3x, similar with AVR
– STM32, the architecture “limitations” are visible to the application developer.
> some users do prefer to do it close to the iron
> some users like the additional library layers which are simplifying some things but adding some complexity

If you will do several apps on STM32, then the knowledge of interrupt handling is very useful.


Pito
Sat Aug 05, 2017 4:55 pm
With 20-25rev/sec you may timestamp each hallsensor’s rising (or falling) edge interrupt, ie. with micros().
With 25rev/sec you get ~40000micros difference each time, that might be precise enough..
For example (simplified):
volatile uint32_t current_rev_period, tstamp, old;
..
attachInterrupt(Hall_PIN_INPUT, Hall_interrupt, RISING);
..

void Hall_interrupt() {
tstamp = micros();
current_rev_period = tstamp - old;
old = tstamp;
}


dannyf
Sat Aug 05, 2017 11:27 pm
have not found any code for the stm32duino using a hall effect sensor for measuring RPM, just code for the Arduinos.

the two should be fairly easy to port to / from.

basically, set up an isr that’s called when the tachometer output changes state (or rising / falling). and calculate timing differentials and add oversampling if you wish.

that’s pretty much all you need.

something like this would work:

void tacho_isr(void) {
static uint8_t count=0;
static uint32_t time_elapsed=0; //time elapsed
uint32_t tmp;

count+=1; //increment counter
if (count == RPM_COUNT) {
tmp = time_now(); //save current time
time_elapsed = tmp - time_elapsed; //calculate time elapsed
//calculate rpm from time_elapsed, RPM_COUNT, and other parameters here
time_elapsed = tmp; // update time_elapsed for the next round of counting
count = 0;
}
}


RogerClark
Sun Aug 06, 2017 1:15 am
I’d be cautious about attempting microsecond timing in an ISR because of how its implemented

static inline uint32 micros(void) {
uint32 ms;
uint32 cycle_cnt;

do {
ms = millis();
cycle_cnt = systick_get_count();
asm volatile("nop"); //allow interrupt to fire
asm volatile("nop");
} while (ms != millis());

#define US_PER_MS 1000
/* SYSTICK_RELOAD_VAL is 1 less than the number of cycles it
* actually takes to complete a SysTick reload */
return ((ms * US_PER_MS) +
(SYSTICK_RELOAD_VAL + 1 - cycle_cnt) / CYCLES_PER_MICROSECOND);
#undef US_PER_MS
}


Pito
Sun Aug 06, 2017 5:41 am
In the ISR you may read the CPU counter with 13.88ns (F103) or 5.95ns (F407) resolution instead of micros() – see

http://www.stm32duino.com/viewtopic.php … nos#p26692

volatile uint32_t current_rev_period, tstamp, old;
..
attachInterrupt(Hall_PIN_INPUT, Hall_interrupt, RISING);
DWTEn();
CpuTicksEn();
..

double my_revs = 1.0 / (current_rev_period * 13.888889e-9); //Revs per second

// ISR
void Hall_interrupt() {
tstamp = CpuGetTicks();
current_rev_period = tstamp - old;
old = tstamp;
}


RogerClark
Sun Aug 06, 2017 7:19 am
@pito

Thanks

I don’t remember reading that thread

I see you defined

#define DWTEn() (*((uint32_t*)0xE000EDFC)) |= (1<<24)
#define CpuTicksEn() (*((uint32_t*)0xE0001000)) = 0x40000001
#define CpuTicksDis() (*((uint32_t*)0xE0001000)) = 0x40000000
#define CpuGetTicks() (*((uint32_t*)0xE0001004))


karwas
Fri Aug 11, 2017 9:15 am
Yes, as others are saying, Interrupts will be used for measuring RPM. Interrupt will be triggered on every time, when magnet is detected by Hall sensor.
I have also bought a STM board and learned interrupts, now trying to build the same RPM meter using hall sensor.

I have measured the RPM of simple DC motor with Arduino using below code. Now trying to use the same concept in STM. You can also look at the code:
void loop()
{
/*To drop to zero if vehicle stopped*/
if(millis()-dtime>1500) //no magnet found for 1500ms
{
rpm= v = 0; // make rpm and velocity as zero
Cycle_BT.write(v);
dtime=millis();
}
v = radius_of_wheel * rpm * 0.37699; //0.33 is the radius of the wheel in meter
}

void magnet_detect() //Called whenever a magnet is detected
{
rotation++;
dtime=millis();
if(rotation>=2)
{
timetaken = millis()-pevtime; //time in millisec for two rotations
rpm=(1000/timetaken)*60; //formulae to calculate rpm
pevtime = millis();
rotation=0;
Cycle_BT.write(v);
//Cycle_BT.println("Magnet detected...."); //enable while testing the hardware
}
}


ag123
Fri Aug 11, 2017 12:08 pm
i’m halfway wondering if a simple magnet on the wheel & a coil wound around ferrite (solenoid inductor) would basically do the same trick, i think many bicycle tachos does exactly that :lol:

Ollie
Fri Aug 11, 2017 2:44 pm
That would work. Special attention is required to clamp out the high voltage that is generated at high speed.

Pito
Fri Aug 11, 2017 5:06 pm
i'm halfway wondering if a simple magnet on the wheel & a coil

Leave a Reply

Your email address will not be published. Required fields are marked *