Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 4 of 4

Thread: digitalReadFast() why does it need __builtin_constant_p

  1. #1

    digitalReadFast() why does it need __builtin_constant_p

    Hi all, just wondering why the pin must be known at compile time?

    I was looking at the source code and it has if-else for each pin so i'm wondering why the pin needs to be know at compile when it's still doing an if-else.

    With that in mind, would the function below have the same or similar effect for code that has a variable pin number?

    Code:
    uint8_t readPin(uint8_t pin){
      switch(pin){
        case 0: return digitalReadFast(0);
        case 1: return digitalReadFast(1);
        case 2: return digitalReadFast(2);
        case 3: return digitalReadFast(3);
        case 4: return digitalReadFast(4);
        // all pins
      }
      return digitalReadFast(pin);
    }
    I'm assuming it's more involved than that, otherwise the Teensy Core would just implement the digitalReadFast as the default and then check if the pin is a constant and if not default to the standard way to read pins. I'm guessing digitalReadFast is not the default because that adds an additional "if" to see if the pin is a constant.

    Additionally would digitalReadFast() work the same way if the pin number is coming from a #define? like this:

    Code:
    #define MY_PIN_0 7
    #define MY_PIN_1 5
    #define MY_PIN_2 1
    #define MY_PIN_3 6
    #define MY_PIN_4 4
    
    uint8_t readPin(uint8_t pin){
      switch(pin){
        case MY_PIN_0: return digitalReadFast(MY_PIN_0);
        case MY_PIN_1: return digitalReadFast(MY_PIN_1);
        case MY_PIN_2: return digitalReadFast(MY_PIN_2);
        case MY_PIN_3: return digitalReadFast(MY_PIN_3);
        case MY_PIN_4: return digitalReadFast(MY_PIN_4);
        // all pins
      }
      return digitalReadFast(pin);
    }
    This is mostly curiosity Teensy's are so fast that digitalRead is still really fast, I don't actually need to read pins extremely fast or anything like that but if i can speed it up further then might as well.

    Thank you in advance.

  2. #2
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    10,925
    Just showing the first pin when a constant pin is supplied :
    Code:
    	if (__builtin_constant_p(pin)) {
    		if (pin == 0) {
    			return (CORE_PIN0_PINREG & CORE_PIN0_BITMASK) ? 1 : 0;
    This codes the read at compile time. And the compiler being smart recognizes the constant and should actually discard all the IF() overhead that would be 30+ pins of code bloat - and just uses the single return as appropriate. And if not a constant it could not do that so then the alternate method is applied - that takes longer.

    If not a constant as above this is delayed until RUNTIME to look up and find and apply the masking:
    Code:
    	} else {
    		#if defined(KINETISK)
    		return *portInputRegister(pin);
    		#else
    		return (*portInputRegister(pin) & digitalPinToBitMask(pin)) ? 1 : 0;
    		#endif

  3. #3
    Senior Member
    Join Date
    Apr 2014
    Location
    Germany
    Posts
    798
    To visualize what defragster has just written here a simple example:

    Code:
    void setup()
    {
      constexpr double x = 15.4;
    
      if(x > 15)
      {
        digitalWriteFast(13,HIGH);
      }
      else
      {
        digitalWriteFast(13,LOW);
      }
    }
    
    void loop()
    {}
    The compiler knows that 15.4 is larger than 15.0 and optimizes the else branch (x <= 15) completely away. It also optimizes all the conditionals in digitalWriteFast away and ends up with the following simple machine code (have a look at the generated *.lst file).

    Basically it loads the address of the corresponding port C set register (0x400F'F084) in R3, sets bit number 6 in R2 (= #32 which corresponds to the pin 13). It then copies R2 to the address stored in R3 (i.e. to the PortC set register). After that it simply returns.

    Code:
    0000046c <setup>:
         46c:	ldr	r3, [pc, #4]	; (474 <setup+0x8>)
         46e:	movs	r2, #32
         470:	str	r2, [r3, #0]
         472:	bx	lr
         474:	.word	0x400ff084
    
    
    void loop()
         478:	bx	lr
         47a:	nop
    Last edited by luni; 02-14-2020 at 06:59 PM.

  4. #4
    It makes more sense now!

    Thank you!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •