// PinChangeIntSpeedTest by GreyGnome aka Mike Schwager. Version numbers here refer to this sketch. // Version 1.0 - initial version // Version 1.1 - added code to test digitalRead() // Version 1.2 - added new comments for the #define's for the NO_PORTx_PINCHANGES. // Version 1.3 - includes cbiface.h with ooPinChangeInt, rather than cb.h // Version 1.4 - testing version 2.10Beta with robtillaart's optimization // Also added a #define/#undef INLINE_PCINTFUNC for inlining of the function called by the interrupt. // Default: #undef for using the function as per usual. Changed PCIVERSION so that // ooPinChangeInt starts at 1000 instead of 200. Modified the "Start" message to show "Start..", pause // for 1 second, show "*\n" (where \n is a newline), pause for 1 second, then run the test. // Version 1.4 - made this compatible with version 1.5 of PinChangeInt // Version 1.5 - modified it to use #define OOPCIVERSION for ooPinChangeInt // This version number is for ooPinChangeInt //#define OOPCIVERSION 1030 #ifndef OOPCIVERSION #define PCIVERSION 217 // 110 if using PinChangeInt-1.1, 120 for version 1.2 // 1000 for ooPinChangeIntversion 1.00, 1001 for ooPinChangeInt version 1.01, etc. #endif //-------- define these in your sketch, if applicable ---------------------------------------------------------- // You can reduce the memory footprint of this handler by declaring that there will be no pin change interrupts // on any one or two of the three ports. If only a single port remains, the handler will be declared inline // reducing the size and latency of the handler. #undef NO_PORTB_PINCHANGES // to indicate that port b will not be used for pin change interrupts #undef NO_PORTC_PINCHANGES // to indicate that port c will not be used for pin change interrupts // #define NO_PORTD_PINCHANGES // to indicate that port d will not be used for pin change interrupts // You can reduce the code size by 20-50 bytes, and you can speed up the interrupt routine // slightly by declaring that you don't care if the static variables PCintPort::pinState and/or // PCintPort::arduinoPin are set and made available to your interrupt routine. // #define NO_PIN_STATE // to indicate that you don't need the pinState // #define NO_PIN_NUMBER // to indicate that you don't need the arduinoPin // if there is only one PCInt vector in use the code can be inlined // reducing latency and code size // define DISABLE_PCINT_MULTI_SERVICE below to limit the handler to servicing a single interrupt per invocation. //#define DISABLE_PCINT_MULTI_SERVICE //-------- define the above in your sketch, if applicable ------------------------------------------------------ #if defined(OOPCIVERSION) #define LIBRARYUNDERTEST "ooPinChangeInt" #include #if PCIVERSION == 1001 #include #else #include #endif #else #define LIBRARYUNDERTEST "PinChangeInt" #include #endif #define SERIALSTUFF // undef to take out all serial statements. Default: #define for measuring time. #undef MEMTEST // undef to take out memory tests. Default: #undef for measuring time. #undef INLINE_PCINTFUNC // define to inline the function called from the interrupt. This should have no effect, // because the compiler will store the registers upon calling the interrupt routine, just // like calling a function. Still, we test all assumptions. //----------------------- // NOTE: BECAUSE OF COLLISIONS in these libraries, you CANNOT have both libraries: PinChangeInt // and ooPinChangeInt in the libraries directory at the same time. That said, under UNIX-y operating // systems, it's easy to move the library directory to a name such as "PinChangeInt-1.3", which the // Arduino will not recognize, and then create a symbolic link when you want to use a library. Such as: // cd ~/Documents/Arduino/libaries // mv PinChangeInt PinChangeInt-1.30 // mv ooPinChangeInt ooPinChangeInt-1.00 // ln -s PinChangeInt-1.30 PinChangeInt #undef FLASH // to flash LED on pin 13 during test #ifdef MEMTEST #include #endif #define TEST 6 #if TEST == 1 #define PTEST 2 // pin to trigger interrupt. pins 0 and 1 are used #define PLOW 2 // by Serial, so steer clear of them! #define PHIGH 2 // Interrupts are attached to these pins #elif TEST == 2 // see the #if TEST == 2 || TEST == 3 code, below #define PTEST 2 #define PLOW 2 #define PHIGH 2 // need to attachInterrupt to 5 in the code #elif TEST == 3 // see the #if TEST == 2 || TEST == 3 code, below #define PTEST 5 #define PLOW 2 #define PHIGH 2 // need to attachInterrupt to 5 in the code #elif TEST == 4 #define PTEST 2 #define PLOW 2 #define PHIGH 5 #elif TEST == 5 #define PTEST 3 #define PLOW 2 #define PHIGH 5 #elif TEST == 6 #define PTEST 4 #define PLOW 2 #define PHIGH 5 #elif TEST == 7 #define PTEST 5 #define PLOW 2 #define PHIGH 5 #endif uint8_t qf0; #ifdef INLINE_PCINTFUNC #define INLINE_PCINTFUNC inline #else #define INLINE_PCINTFUNC #endif INLINE_PCINTFUNC void quicfunc(); void quicfunc() { qf0=TCNT0; } #if defined(OOPCIVERSION) class speedy : public CallBackInterface { public: uint8_t id; static uint8_t var0; speedy () { id=0; }; speedy (uint8_t _i): id(_i) {}; void cbmethod() { speedy::var0=TCNT0; //Serial.print("Speedy method "); // debugging //Serial.println(id, DEC); }; }; uint8_t speedy::var0=0; #endif volatile uint8_t *led_port; volatile uint8_t *pinT_OP; volatile uint8_t *pinT_IP; uint8_t led_mask, not_led_mask; uint8_t pinT_M, not_pinT_M; volatile uint8_t pintest, pinIntLow, pinIntHigh; uint8_t totalpins; #if defined(OOPCIVERSION) speedy speedster[8]={speedy(0), speedy(1), speedy(2), speedy(3), speedy(4), speedy(5), speedy(6), speedy(7) }; #endif #ifdef MEMTEST int freemem; #endif int i=0; #define PINLED 13 void setup() { #ifdef SERIALSTUFF Serial.begin(115200); Serial.println("---------------------------------------"); #endif // SERIALSTUFF // set up ports for trigger pinMode(0, OUTPUT); digitalWrite(0, HIGH); pinMode(1, OUTPUT); digitalWrite(1, HIGH); pinMode(2, OUTPUT); digitalWrite(2, HIGH); pinMode(3, OUTPUT); digitalWrite(3, HIGH); pinMode(4, OUTPUT); digitalWrite(4, HIGH); pinMode(5, OUTPUT); digitalWrite(5, HIGH); pinMode(6, OUTPUT); digitalWrite(6, HIGH); pinMode(7, OUTPUT); digitalWrite(7, HIGH); #ifdef FLASH led_port=portOutputRegister(digitalPinToPort(PINLED)); led_mask=digitalPinToBitMask(PINLED); not_led_mask=led_mask^0xFF; pinMode(PINLED, OUTPUT); digitalWrite(PINLED, LOW); #endif // ***************************************************************************** // set up ports for output ************ PIN TO TEST IS GIVEN HERE ************** // ***************************************************************************** pintest=PTEST; pinIntLow=PLOW; pinIntHigh=PHIGH; // Interrupts are attached to these pins // ***************************************************************************** // ***************************************************************************** pinT_OP=portOutputRegister(digitalPinToPort(pintest)); // output port pinT_IP=portInputRegister(digitalPinToPort(pintest)); // input port pinT_M=digitalPinToBitMask(pintest); // mask not_pinT_M=pinT_M^0xFF; // not-mask *pinT_OP|=pinT_M; for (i=pinIntLow; i <= pinIntHigh; i++) { #if defined(OOPCIVERSION) PCintPort::attachInterrupt(i, &speedster[i], CHANGE); // C++ technique; v1.3 or better #endif #if defined(PCIVERSION) PCintPort::attachInterrupt((uint8_t) i, &quicfunc, CHANGE); // C technique; v1.2 or earlier #endif } #if TEST == 2 || TEST == 3 i=5; totalpins=2; #if defined(OOPCIVERSION) PCintPort::attachInterrupt(i, &speedster[i], CHANGE); // C++ technique; v1.3 or better #endif #if defined(PCIVERSION) PCintPort::attachInterrupt(i, &quicfunc, CHANGE); // C technique; v1.2 or earlier #endif #else totalpins=pinIntHigh - pinIntLow + 1; #endif i=0; } // end setup() uint8_t k=0; unsigned long milliStart, milliEnd, elapsed; void loop() { k=0; *pinT_OP|=pinT_M; // pintest to 1 #ifdef SERIALSTUFF Serial.print(LIBRARYUNDERTEST); Serial.print(" "); Serial.print("TEST: "); Serial.print(TEST, DEC); Serial.print(" "); #ifndef MEMTEST Serial.print("test pin mask: "); Serial.print(pinT_M, HEX); Serial.print(". Total of "); Serial.print(totalpins, DEC); Serial.println(" pins enabled."); #endif #ifdef MEMTEST freemem=freeMemory(); Serial.print("Free memory: "); Serial.println(freemem, DEC); #endif #endif delay(1000); Serial.print("Start.."); delay(1000); Serial.print("*"); #ifdef FLASH *led_port|=led_mask; #endif milliStart=millis(); while (k < 10) { i=0; while (i < 10000) { *pinT_OP&=not_pinT_M; // pintest to 0 ****************************** 16.8 us *pinT_OP|=pinT_M; // pintest to 1 ****************************** ...to get here i++; } k++; } milliEnd=millis(); #ifdef FLASH *led_port&=not_led_mask; #endif elapsed=milliEnd-milliStart; #ifndef MEMTEST Serial.print(" Elapsed: "); Serial.println(elapsed, DEC); #endif #ifdef SERIALSTUFF Serial.print("Interrupted pin: "); #if defined(OOPCIVERSION) Serial.println(speedster[pintest].id, DEC); #else Serial.println(PCintPort::arduinoPin, DEC); #endif #ifdef MEMTEST freemem=freeMemory(); Serial.print("END-Free memory: "); Serial.println(freemem, DEC); #endif #endif delay(500); }