chicken 630 Posted September 2, 2015 Share Posted September 2, 2015 From time to time, threads pop up where someone tries to count very fast pulses in the hundreds of kHz or even MHz range. There is a solution for the hardcore C-coders among us, but to my surprise there was no Energia library for this simple problem. I herewith present the CounterLib for Energia Download Source code and detailed instructions are also available on GitHub: https://github.com/astuder/CounterLib-Energia Currently the library supports MSP430G2553, MSP430F5529 and MSP430FR5969. To create an instance of the counter, simply declare it as a global variable like this: Counter<> MyCounter; // create a counter that counts pulses on pin P1.0Once created, the counter has 5 functions:start() initializes the timer peripheral and I/O pin and starts the counter stop() stops the counter, but does not reset the counter value read() reads the current value of the counter reset() resets the counter to 0, the counter keeps running readAndReset() reads the current value and resets the counter to 0 And a basic example, which should work for signals lower than 65 kHz: Counter<> MyCounter; // create counter that counts pulses on pin P1.0 void setup() { Serial.begin(9600); MyCounter.start(); // start counter } void loop() { MyCounter.reset(); // reset counter to zero delay(1000); // wait one second Serial.println(MyCounter.read()); // read number of pulses during the last second delay(1000); // wait another second } The library also supports dividers to measure much faster signals. For more detailed instructions see GitHub. The library uses the external clock input of the timer peripheral. This enables the library to measure very fast signals (MHz range). On the downside, each timer only has a specific pin assigned, and the G2553 only has one timer with an external pin. It is also possible, that other Energia libraries or built-in functionality use the same timer, which won't work. Here's a list of the timers supported by the library and their pins: | Timer | G2553,| | | | | | G2452,| F5529 | FR5969 | FR6989 | | | G2231 | | | | |------------|-------|-------|--------|--------| | CL_TimerA0 | P1.0 | P1.0 | P1.2 | P1.2* | | CL_TimerA1 | n/a | P1.6 | P1.1* | P1.1* | | CL_TimerA2 | n/a | P2.2 | n/a | n/a | | CL_TimerB0 | n/a | P7.7*| P2.0* | P2.0 |Pins marked with * are not broken out on the LaunchPad or are difficult to access. The library probably works on many other MSP430's, but you'll need to adjust the #defines in the library. Please report back if you successfully tested with other devices, so that I can extend the library. Please report any bugs. And also let me know if you break any speed records. So far I only tested it up to 750 kHz. Edit 9/3/15: Added support for FR5969. Thanks @@Fmilburn Edit 9/4/15: Refactored to make it easier to add more MCUs. Several bug fixes, thanks to all the eagle-eyed members of 43oh Edit 3/13/16: Replaced attached ZIP file with link to GitHub to always give up-to-date version yyrkoon, Rickta59, yosh and 8 others 11 Quote Link to post Share on other sites
Lgbeno 189 Posted September 2, 2015 Share Posted September 2, 2015 Very cool, this library would be very useful for interfacing to one of these https://www.tindie.com/products/limpkin/hb100-doppler-module-with-backpack-1/ Sent from my iPhone using Tapatalk Quote Link to post Share on other sites
Lgbeno 189 Posted September 2, 2015 Share Posted September 2, 2015 PIR sensors too Sent from my iPhone using Tapatalk Quote Link to post Share on other sites
Fmilburn 446 Posted September 2, 2015 Share Posted September 2, 2015 Hello @@chicken Very elegant and nicely documented. I did a quick and dirty test to see what I could see... Staying with the Energia theme, I wrote this little sketch and ran it on a EK-TM4C123GXL LaunchPad running at 80 MHz: // toggles a pin LOW to HIGH over and over... const int pin = 10; void setup() { pinMode(pin, OUTPUT); digitalWrite(pin, LOW); } void loop() { digitalWrite(pin, HIGH); digitalWrite(pin, LOW); } Here is what I saw on the oscilloscope: The reading is 623.7 kHz on the oscilloscope so your speed record is still safe . Then I loaded the many kilohertz example and changed to timer A1 on pin 1.6 just to be different. CounterLib gives me a steady 632 kHz, an error of about 1% so not too bad. At lower frequencies I get even more accurate results of course. Great work. I may have a go at implementing this on another device and will let you know if I am successful. dubnet, bluehash, chicken and 1 other 4 Quote Link to post Share on other sites
chicken 630 Posted September 2, 2015 Author Share Posted September 2, 2015 @@Fmilburn thanks for testing Timer A1. As long as you avoid overflow of the 16bit counter, you can improve precision by lengthening the measurement period. Alternatively reducing the divider might also help some, as it increases the "resolution" of the measurement. Quote Link to post Share on other sites
Fmilburn 446 Posted September 2, 2015 Share Posted September 2, 2015 As long as you avoid overflow of the 16bit counter, you can improve precision by lengthening the measurement period You are right of course. I nominate you for the honorific title of "Count Chicken" I rewrote my signal generation sketch to run on the F5529: // toggles a pin LOW to HIGH over and over... // test on MSP-EXP30F5529LP // #include <msp430.h> void setup() { P1DIR |= 0x01; // Set P1.0 to output } void loop() { P1OUT ^= 0x01; // Toggle P1.0 using exclusive OR } By getting a bit closer to the metal and getting rid of some Energia overhead it is running faster than before, even on a slower device. On the oscilloscope I see: 811 kHz! We are in new territory. I doubled the count time and halved the clock (also changed to Timer A2 just to test it). Here is the new counting sketch for the F5529: #include "CounterLib_t.h" Counter<CL_TimerA2> MyCounter; // create counter that counts pulses on pin P2.2 void setup() { Serial.begin(9600); MyCounter.start(CL_Div8,2); // start counter, divide clock by 16 } void loop() { MyCounter.reset(); // reset counter to zero delay(200); // wait 200 milliseconds Serial.print((MyCounter.read() + 5) / 200 * 16); // read counter, calculate kHz Serial.println(" kHz"); delay(1000); // wait one second I get a very regular 816 kHz. That is a new speed record and around 0.6 % error. I'm sure it could be improved with some more tweaking of the parameters. Alternatively, if the pulses are regular it wouldn't be difficult to put together a function with correction factors. dubnet and chicken 2 Quote Link to post Share on other sites
dubnet 238 Posted September 2, 2015 Share Posted September 2, 2015 You are right of course. I nominate you for the honorific title of "Count Chicken" @@bluehash This sounds like an new award category. yyrkoon and tripwire 2 Quote Link to post Share on other sites
Fmilburn 446 Posted September 2, 2015 Share Posted September 2, 2015 This sounds like an new award category. I agree @@dubnet. You should never count your chickens before they hatch, and as far as I can tell, @@chicken never does. tripwire 1 Quote Link to post Share on other sites
chicken 630 Posted September 2, 2015 Author Share Posted September 2, 2015 @@Fmilburn you're cracking me up Re increasing precision: You moved both parameters at once. Given that 800 kHz / 8 creates only 10K pulses per 100 ms, you could have gone to 200 ms or more without adjusting the divider. Pushing it past 320 ms will be interesting to see whether there's a singed/unsigned int mess-up. I will have to do the math, but I think there's a way to determine and cancel out the overhead with two measurements: A = count at interval t B = count at interval 2 * t If we assume that the overhead X is the same for all intervals, and call C the number of cycles during t we get: A = X + C B = X + 2 * C Solve for C. B = A - C + 2CB - A = 2C - CB - A = C Well dooh! Seems so obvious now, but at least we have the mathematical proof tripwire and Fmilburn 2 Quote Link to post Share on other sites
Rickta59 589 Posted September 2, 2015 Share Posted September 2, 2015 Source code and detailed instructions are also available on GitHub: https://github.com/astuder/CounterLib-Energia Currently the library only supports MSP430G2533 and MSP430F5529. To create an instance of the counter, simply declare it as a global variable like this: Counter<> MyCounter; // create a counter that counts pulses on pin P1.0 Nice to see someone else using C++ templates. +1 -rick chicken 1 Quote Link to post Share on other sites
chicken 630 Posted September 4, 2015 Author Share Posted September 4, 2015 @@Fmilburn contributed support for the MSP430FR5969 Launchpad. So the supported devices table now looks like this: | Timer | G2553 | F5529 | FR5969 | |------------|-------|-------|--------| | CL_TimerA0 | P1.0 | P1.0 | P1.2 | | CL_TimerA1 | n/a | P1.6 | P1.1 | | CL_TimerA2 | n/a | P2.2 | n/a | | CL_TimerB0 | n/a | P7.7 | P2.0 | Updated GitHub and original post. Edit: Fixed typo tripwire 1 Quote Link to post Share on other sites
B@tto 51 Posted September 4, 2015 Share Posted September 4, 2015 Hi, Is it really for G2533 or you wanted to say G2553 ? chicken 1 Quote Link to post Share on other sites
spirilis 1,265 Posted September 4, 2015 Share Posted September 4, 2015 2533 and 2553 are almost identical anyhow... I buy 2533's when I do purchase G2xx3's mostly b/c they're slightly cheaper. I think it's missing the Comparator_A peripheral or something similar. Quote Link to post Share on other sites
chicken 630 Posted September 4, 2015 Author Share Posted September 4, 2015 Gaah! G2553 of course, got it right in the code, but wrong in the documentation and comments. I'm working on a version that looks at the timer peripheral version anyways, so it should be easier to adapt for more MSP430's soon. yyrkoon 1 Quote Link to post Share on other sites
chicken 630 Posted September 5, 2015 Author Share Posted September 5, 2015 Pushed a new version to GitHub and updated the first port with the latest copy. - Refactored #defines to make it easier to add MCUs, especially when sharing the same peripheral versions and pin-outs as an already support MSP430. - Squashed numerous bugs in documentation and code, thanks to @@spirilis and @@Fmilburn Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.