Tool/software: Code Composer Studio
I am having trouble finding how to correctly use an up counter.
I am using a reed switch as an input for each revolution. I just need to use a timer to get the time in between inputs.
-Matt
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Tool/software: Code Composer Studio
I am having trouble finding how to correctly use an up counter.
I am using a reed switch as an input for each revolution. I just need to use a timer to get the time in between inputs.
-Matt
Matt Cowler said:I just need to use a timer to get the time in between inputs.
Perhaps not! Would it not be FAR simpler to:
You'll need to review the MCU manual to determine if "Edge Count" mode accepts "up or down" (one only) captures. If you employ "down count" you simply determine the "difference" in counts between "Count: Start & End." Usually - but not always - "Down Counting" is simpler to program & more broad-based in MCU implementations.
The above is a demonstration of KISS - which most always yields, "Faster, Easier & Enhanced" results.
Your motor - thus your "Time Log of Edge Captures" (as you propose) is likely to experience great variances. How then can you "know" which "time delta" was valid? Method presented is far more forgiving as it accumulates edge captures over a 1 Second period. Nothing prevents you from either increasing or decreasing the capture period - based upon your requirements.
Thank you for your response and the information that you have given.
cb1_mobile said:Perhaps not! Would it not be FAR simpler to:
- configure a Timer to run for 1 second
- configure a 2nd Timer to capture either the rising or falling edge of your reed switch
- Clear the "Counting Timer" and the (separate) 1 Second Timer - then enable both
- Disable the "Counting Timer" when the 1 Second Timer "times out"
- the "number of edges" captured w/in Timer 2 is your result - but in RPS
- Multiply by 60 to convert RPS to RPM
Would something like this be what you mean?
//#include "driverlib/debug.h"
#include <stdbool.h>
#include <stdint.h>
#include "inc/tm4c123gh6pm.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/sysctl.h"
#include "driverlib/interrupt.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
//global - used in interrupt - value from timer oa
unsigned long timer;
int main(void)
{
//CPU at 40MHz
SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
// Enable the peripherals used
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); //used to generate interrupt every 100ms
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1); //used to measure leading edge from signal
// Enable the D peripheral used by the TIMER 1 - CPP
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
/**********************************************************************************************
PinTypeTimer(CCP2); //find Timer pin and configure it for Timer functionality
**********************************************************************************************/
GPIOPinTypeTimer(GPIO_PORTD_BASE, GPIO_PIN_1);// Configure GPIO Port D pin 1 to be used as timer pin
GPIOPinConfigure(GPIO_PD1_WT2CCP1); // Enable ccp functionality on GPIO Port D pin 1
// Enable processor interrupts.
IntMasterEnable();
//interrupt for the Timer0A timeouts - evert 100ms
IntEnable(INT_TIMER0A);
TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
// Configure the two 32-bit periodic timers.
TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC); //Full-width periodic timer
TimerConfigure(TIMER1_BASE, TIMER_CFG_A_CAP_COUNT); //Half-width edge count capture
// Configure the timer load value
TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet()/10); //40MHz/10= 4000000...(Clock Period)(4000000)=100 ms period count
TimerLoadSet(TIMER1_BASE, TIMER_A, 10000); //Timer1 loaded with a value (10000) as it counts down for every positive edge
// Configure the signal edge that triggers the timer in capture mode
TimerControlEvent(TIMER1_BASE,TIMER_A,TIMER_EVENT_POS_EDGE); //sets Timer1A to trigger on positive going edges.
// Enable the timers.
TimerEnable(TIMER0_BASE, TIMER_A);
TimerEnable(TIMER1_BASE, TIMER_A);
while(1)
{
float freq;
float RPM;
freq = (10000 - timer) * 1000; // *1000 converts to Hz
RPM = freq * 60;
}
}
//*****************************************************************************
//
// The interrupt handler for the first timer interrupt.
//
//*****************************************************************************
void Timer0IntHandler(void) //Timer 0A
{
// Clear timer interrupt
TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
// Get counter value
timer=TimerValueGet(TIMER1_BASE,TIMER_A);
// Reset counter value to 10000
TimerLoadSet(TIMER1_BASE, TIMER_A, 10000);
}
//*****************************************************************************
//
// The interrupt handler for the second timer interrupt.
//
//*****************************************************************************
void Timer1IntHandler(void) //Timer 1A
{
}
Matt Cowler said:Would something like this be what you mean?
You've clearly made good progress - yet firm/I (always) prefer "KISS" - and you've deviated from my "KISS-based" tech outline. (NOT a big deal - I'll justify my methods/madness for your consideration)
We agree that TWO Timers are to be employed:
To comply w/KISS - should not Timer 1 be configured as a, "One-Shot?" (your experience/knowledge is unknown - if necessary use the net to assist) Beauty of the One-Shot is the "Automatic & Proper Enabling of "Counting" Timer 2 - for ONLY the desired (1 Sec) time-frame. When Timer 1 (time-base) "expires" the content of Timer 2 (Edge Counter) is "frozen" - which enables your eased "read" of that Timer. You achieve that (desired) "freeze of Timer 2" by disabling it - which is prompted by the "time-out" of Timer 1. After you've "read Timer 2's content" - and performed your "RPS to RPM" calculation/display - you should "clear" the Counter Timer (Timer 2) and Re-Trigger the "One Shot" (time-base) Timer. (Timer 1)
Note that you chose a "Periodic Timer" - which forces extra complexity upon your process - as you must IMMEDIATELY read the Counter Timer - before the next (illegal) input pulse arrives! In stark contrast - the One-Shot Timer is quite ok at "sitting idle" until you've read your counter - performed your calcs - displayed and/or taken control action. That One-Shot Timer (then) is re-triggered - enabling your "next" speed measure. You've thus "escaped" all rush to, "Perform your next Speed Measurement." And that's the hallmark of a good, KISS Design. (nothing prevents you from launching the (next) KISS "speed capture" very quickly - but that should flow from your DESIRE - not "Design Necessity." (i.e. Anti-KISS)
We note that you've chosen a 32 bit Timer for the Edge Counter. Is that capacity (really) needed? (especially if you employ a 100mS timebase!) (ANS: of course not - 16 bit (even 8 bit) is sufficient) 32 bits (may) be required for the 1Sec time-base - should you (now) decide to accept that suggestion... (and HOW did you arrive at a 1/10Sec time-frame?)
Consider this guidance - do promote KISS - and we'll see what your next iteration reveals...
I was trying to see if modifying a frequency counter found for Stellaris could work.
I will be using this to calculate low RPM - less than 120, which is why i chose a 32 bit timer because of the longer period.
The configuration of the CCP for the timer is also an issue for me.
Would the below be the correct configuration for the input pulses to be on PFO for Timer1A
GPIOPinConfigure(GPIO_PF0_T1CCP0); GPIOPinTypeTimer(GPIO_PORTF_BASE, GPIO_PIN_0);
Matt Cowler said:I was trying to see if modifying a frequency counter found for Stellaris could work.
That desire was never presented and as "Stellaris" is (long) since "dead/buried" seems of little use to those here. (my preference is to offer general solutions - to the benefit of many - I'll leave (to others) the fulfillment of your (unique - and just presented) desire.)
Matt Cowler said:I will be using this to calculate low RPM - less than 120, which is why i chose a 32 bit timer because of the longer period.
Thus you are NOT employing the, "KISS-based Solution" which I detailed - in your behalf. And - this is the "first" mention you've made of such, "Low-Speed" requirement. At "very low rotational speeds" the key advantage of the technique I presented was, "Code Speed & Ease." The "Gate-Time" of my previous implementation must be extended to properly accommodate (more) of those (just now admitted) low frequency signal arrivals.
You have not addressed the issue of, "Expected variation in the "delta" between successive pulse arrivals." It is expected that your capture of (beyond) "back to back" pulse time separations would improve measurement accuracy. (i.e. capture the time between (say) 5 consecutive pulses (that delta between the arrival of pulse 1 and pulse 5.)) Dividing the duration of, "Pulse 5's edge - Pulse 1's edge" by 4 (not 5) tends to reduce errors caused by speed change. (we divide by 4 instead of 5 as we have (just) 4 "Signal-Edge "Deltas".") (i.e. T2-T1, T3-T2, T4-T3 and T5-T4.) Again - there is NOT a need to capture the "time of arrival" of "each" pulse (although that method will work.) Left for the reader is the "How" of capturing the "time of arrival" of (just) Pulse 1 and then Pulse 5, or 10 etc... Hint: ARM MCUs have MANY Timers. Extra Credit - capture & log the time of Signal Arrival #1 & 5 (only) - employing (just one) Timer...
Your choice of PF0 is especially unfortunate as that pin (and one other) are, "specially challenged." (thus more Anti-KISS is introduced - for no (apparent) reason) Forum search will reveal that pin's "gotcha" and required action.
My recommendation would be to investigate, find & employ a motor-shaft driven device (possibly an encoder) w/superior, "Pulse Number per Revolution output." Such would (even) better support the Speed Measurement method previously detailed here...