Odd results when using digitalReadFast.....

HI,
I’m having difficulty getting proper results when using digitalReadFast.
The attached program works fine with digitalRead, but when I switch (uncomment) digitalRead with digitalReadFast I get unpredictable results. ( No change to wiring or ports used )

I added the <digitalWriteFast.h> library and the results shown at the bottom show the difference between toggling the DigitalRead and digitalReadFast lines.

This original code is courtesy of Ryan Boland from.

The code was tested on an Arduino UNO using pins D2 and D3 connect to my Futaba RC Receiver. ( INT0 and INT1)

Things that I have tried to no avail:

  1. removed the EnableInterrupt.h and went back to attachinterrupts.
  2. tried a 10K resistor on the input pin.
  3. changed the digitalwrite and pinmode to the “Fast” version.
  4. changed the interrupt to RISING
  5. changed the pinmode to INPUT_PULLUP

I’m sure I’m just doing something dumb, but I would appreciate some guidance.

thanks Brian

Results with digitalRead: ( Looks Good, as expected )

CH1:1524 CH2:1536
CH1:1512 CH2:1524
CH1:1512 CH2:1520
CH1:1524 CH2:1536
CH1:1512 CH2:1524

Results with digitalReadFast:

CH1:64216 CH2:62692
CH1:9024 CH2:9032
CH1:6380 CH2:4856
CH1:16732 CH2:16724
CH1:14080 CH2:12556
CH1:24424 CH2:24432
CH1:21780 CH2:20264

DigitalReadTest.ino (1.33 KB)

#include <EnableInterrupt.h>
#include <digitalWriteFast.h> // DigitalWriteFast Library

#define SERIAL_PORT_SPEED 57600
#define RC_NUM_CHANNELS  2

#define RC_CH1  0
#define RC_CH2  1


#define RC_CH1_INPUT  2
#define RC_CH2_INPUT  3


uint16_t rc_values[RC_NUM_CHANNELS];
uint32_t rc_start[RC_NUM_CHANNELS];
volatile uint16_t rc_shared[RC_NUM_CHANNELS];

void rc_read_values() {
  noInterrupts();
  memcpy(rc_values, (const void *)rc_shared, sizeof(rc_shared));
  interrupts();
}

void calc_input(uint8_t channel, uint8_t input_pin) {
  if (digitalRead(input_pin) == HIGH) {
  // if (digitalReadFast(input_pin) == HIGH) { 
    rc_start[channel] = micros();
  } else {
    uint16_t rc_compare = (uint16_t)(micros() - rc_start[channel]);
    rc_shared[channel] = rc_compare;
  }
}

void calc_ch1() { calc_input(RC_CH1, RC_CH1_INPUT); }
void calc_ch2() { calc_input(RC_CH2, RC_CH2_INPUT); }


void setup() {
  Serial.begin(SERIAL_PORT_SPEED);

  pinMode(RC_CH1_INPUT, INPUT);
  pinMode(RC_CH2_INPUT, INPUT);


  enableInterrupt(RC_CH1_INPUT, calc_ch1, CHANGE);
  enableInterrupt(RC_CH2_INPUT, calc_ch2, CHANGE);

}

void loop() {
  rc_read_values();

  Serial.print("CH1:"); Serial.print(rc_values[RC_CH1]); Serial.print("  ");
  Serial.print("CH2:"); Serial.println(rc_values[RC_CH2]);

  delay(200);
}

When you are complaining about a library, please include the exact information about the library; like if you installed it from the IDE library manager or grabbed it from GitHub, version etc.
For the purposes of this post, I will assume you are using this version of digitalWriteFast, since then I can probably explain what is going wrong.

From the README on that GitHub page:

digitalReadFast(pinNum)(reads the state of pin/port faster)

Parameters:

pinNum is the number written on the Arduino board.

In order to toggle fast, all the three parameters above must be constant or defined by the macro for ease in changes during compilation.

For example:

use ‘#define pinNum 10’ instead of int pinNum = 10;
use ‘const int pinNum 10’ instead of int pinNum = 10;

It goes on to say that a compile error will be generated if a variable is used…but that is false, the code does something different.

In fact, if you don’t make the pin number a constant, the digitalReadFast macro returns a magic number - presumably this is designed to confuse and confound you. The magic number is 0b10101010.
So, in your code, every time you call digitalReadFast you get the magic number, which is never equal to HIGH.
This means that you never write to rc_start[channel] and because this line:

uint16_t rc_compare = (uint16_t)(micros() - rc_start[channel]);

slices the 32 bit integer into a 16 bit integer, you get a rapid wrap around and lots of seemingly random numbers.

I also think the library has a minor but significant error in it. It reads the port register with this line:

# define BIT_READ(value, bit) ((value) & (1UL << (bit)))

This will be the return value of digitalReadFast, but that return value may not be HIGH (=1) - it could be any non-zero value for HIGH.
To use the library as is, you should write:

if (digitalReadFast(...)) { ... }

Thanks arduarn - Your fix worked!!

if (digitalReadFast(...)) { ... }

I'll also double check that my library files are what you referenced.

thanks again!!

BrianTrueman: Thanks arduarn - Your fix worked!!

if (digitalReadFast(...)) { ... }

Don't forget the parameter to digitalReadFast must be a constant at compile time (though it probably wouldn't have worked otherwise).

Edit: Another version of the library also has the BIT_READ error so that library could also fail.