GithubHelp home page GithubHelp logo

electricrcaircraftguy / ercaguy_timercounter Goto Github PK

View Code? Open in Web Editor NEW
31.0 11.0 13.0 53 KB

An Arduino micros()-like function (encapsulated in a library) with 0.5us precision (since the built-in Arduino micros() function has only 4us precision)

Home Page: http://www.electricrcaircraftguy.com/2014/02/Timer2Counter-more-precise-Arduino-micros-function.html

C++ 100.00%

ercaguy_timercounter's Introduction

THIS LIBRARY IS IN THE PROCESS OF BEING UPGRADED. IT MAY NOT CURRENTLY BE IN A WORKING CONDITION, THOUGH THE ONE AT THE GUMROAD LINK BELOW IS.

Readme for eRCaGuy_TimerCounter

My Gabriel Staples
Readme last updated: 4 Aug. 2015

License: GPLv3 or later (ignore whatever the files say; it is GPLv3)

-I'll correct the license in the files later.

Readme Update History (newest on top)
-20150804 - updated links & formatting
-20140517 - readme written

Instructions

Donate and download above. Install the library into the Arduino IDE (using Sketch --> Include Library --> Add .ZIP Library), then run the examples to see how to use the library. You may view the examples in the IDE under File --> Examples --> eRCaGuy_TimerCounter.

Basic Summary

I wrote a libary to get 0.5us precision on a "micros()" replacement function, so that I can get repeatable results reading a PWM or PPM signal, to within 1us. I searched all around the internet and could not find something comparable (or that was easy to use, and maintained the Arduino's ability to write PWM signals via the Servo Libary (which uses the ATmega328's only 16-bit timer/counter, Timer1), so I think this is my first real contribution to the world of Arduino and Radio Control.

Description

  • This Timer2_Counter code is a very generic timer tool to be used in Arduino boards in conjunction with, or in replacement of the built-in Arduino micros() function. I decided to write this code because I needed a really precise timer to be able to measure Radio Control pulse width signals using external interrupts and pin change interrupts, and the built-in Arduino micros() function only has 4 microsecond precision, which allows for a lot of variability, or "noise" in the readings. To avoid this variability, while keeping the Atmel 16-bit Timer1 free to continue powering the Servo library, I wrote this code to utilize the 8-bit Timer2. This created a significant challenge, however, in carefully counting timer overflows while ensuring that no overflow count is missed. Through some careful coding I now have it functioning perfectly, counting all overflow interrupts. It works well.
  • I'll be adding the ability to use other timers instead of Timer2 next, for more versatility and compatibility with other libraries. This way, you can ensure you're not trying to use the same timer that another library uses.

Be sure to check out the links above. I hope you find this useful.
Sincerely,
Gabriel Staples
http://www.ElectricRCAircraftGuy.com

ercaguy_timercounter's People

Contributors

electricrcaircraftguy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ercaguy_timercounter's Issues

Improve `eRCaGuy_Timer2_Counter::get_count()`

Current code:

//get total count for Timer2
unsigned long eRCaGuy_Timer2_Counter::get_count()
{
  uint8_t SREG_old = SREG; //back up the AVR Status Register; see example in datasheet on pg. 14, as well as Nick Gammon's "Interrupts" article - http://www.gammon.com.au/forum/?id=11488
  noInterrupts(); //prepare for critical section of code
  uint8_t tcnt2_save = TCNT2; //grab the counter value from Timer2
  boolean flag_save = bitRead(TIFR2,0); //grab the timer2 overflow flag value; see datasheet pg. 160
  if (flag_save) { //if the overflow flag is set
    tcnt2_save = TCNT2; //update variable just saved since the overflow flag could have just tripped between previously saving the TCNT2 value and reading bit 0 of TIFR2.  
                        //If this is the case, TCNT2 might have just changed from 255 to 0, and so we need to grab the new value of TCNT2 to prevent an error of up 
                        //to 127.5us in any time obtained using the T2 counter (ex: T2_micros). (Note: 255 counts / 2 counts/us = 127.5us)
                        //Note: this line of code DID in fact fix the error just described, in which I periodically saw an error of ~127.5us in some values read in
                        //by some PWM read code I wrote.
    _overflow_count++; //force the overflow count to increment
    TIFR2 |= 0b00000001; //reset Timer2 overflow flag since we just manually incremented above; see datasheet pg. 160; this prevents execution of Timer2's overflow ISR
  }
  _total_count = _overflow_count*256 + tcnt2_save; //get total Timer2 count
  //interrupts(); //allow interrupts again; [updated 20140709] <--WARNING, DO ****NOT**** USE THIS METHOD AFTERALL, OR ELSE IT WILL RE-ENABLE GLOBAL INTERRUPTS IF YOU CALL THIS FUNCTION
                  //DURING AN INTERRUPT SERVICE ROUTINE, THEREBY CAUSING NESTED INTERRUPTS, WHICH CAN REALLY SCREW THINGS UP.
  SREG = SREG_old; //use this method instead, to re-enable interrupts if they were enabled before, or to leave them disabled if they were disabled before
  return _total_count;
}

Potential new code (should result in less jitter due to a shorter period of time where interrupts are off):

unsigned long eRCaGuy_Timer2_Counter::get_count()
{
  // back up the AVR Status Register; see example in datasheet on pg. 14, as well as Nick Gammon's 
  // "Interrupts" article - http://www.gammon.com.au/forum/?id=11488
  uint8_t SREG_old = SREG;
  noInterrupts();
  uint8_t tcnt2_save = TCNT2; // grab the counter value from Timer2
  unsigned long overflow_count = _overflow_count;
  SREG = SREG_old; // restore interrupt state

  _total_count = overflow_count*256 + tcnt2_save; // get total Timer2 count
  // OR (same thing)
  // _total_count = (overflow_count << 8) | tcnt2_save;

  return _total_count;
}

I need to dig back into the git history though and see if that was a prior, broken solution I already had before.

Update: I don't have the git history to know. I'll have to dig up the copy/pasted dirs in my old computer's files instead. The first commit I have with the code is d6987d8, and it already had the bulk of the function content above in it.

The new code will produce a slightly "older" timestamp, but who cares. It should have less jitter, shorter time with interrupts off, and probably even less latency due to being faster.

Timer not very accurate.

Hi, I tried your library and it seems to be not accurate at all. I tried read PPM from my Spektrum dx6i and drift of values is big enough, see screenshot of port monitor.
Do you have plans for improve your lib, or it's already pushed to it's limit? If you have any advice - please let me know! Thanks for your work!

ppm

test.zip

Can I use this library to take timestamps to debounce button presses?

I'm building an electronic instrument with an Uno I had lying about. To create tones I'm using the Mozzi library which I think hijacks the internal timer for PWM because when I poll millis I always get a return of 0.
I saw your post in an old thread from about a decade ago which mentioned a similar issue and thought I'd try it out.
My particular use case is trying to software debounce a button press but I'm not sure how I would go about it using your library.
Is there a way of utilising the lib in this way?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.