Direct port access I/O - write OK but can't read

Hi,

I'm trying to do digital I/O by accessing the registers in my UNO R4 Minima as described in this post and her sample file on github:

I can get it to write on on Pin 2 (verified on 'scope) and have connected the output to Pin 7 but just getting zeros on the serial monitor and PuTTy

My code is:


void loop()
  {
    *PFS_P105PFS_BY = 0x04;  // D2 low

    char_val = *PFS_P107PFS_BY; //d7
    Serial.println(char_val, HEX); 

    delayMicroseconds(10000);
    *PFS_P105PFS_BY = 0x05;      //  d2 high
   
    delayMicroseconds(10000);
    }


I just included the loop as all the rest is as per the github file. For printing the output I tried BIn, HEX and no formatting.

Thanks :slight_smile:

It has been awhile since I played with my UNO R4 boards, but you might take a look
at my quick and dirty digitalWriteFast, digitalToggleFast, digitalReadFast functions:

UNOR4-stuff/libraries/UNOR4_digitalWriteFast/UNOR4_digitalWriteFast.h at main · KurtE/UNOR4-stuff

They worked a lot faster than the normal digital functions...

@heyheywhatcanido you need to read twice in loop():

// Code to demonstrate direct reading of a port-pin

#define PORTBASE 0x40040000 /* Port Base */
#define PFS_P105PFS_BY ((volatile unsigned char  *)(PORTBASE + 0x0843 + ( 5 * 4))) // D2
#define PFS_P107PFS_BY ((volatile unsigned char  *)(PORTBASE + 0x0843 + ( 7 * 4))) // D7

#define SERIAL_BAUD       115200    // Serial COM port speed

void setup()
  {
  Serial.begin(SERIAL_BAUD);    // connect to the serial port
  }

void loop()
  {
  *PFS_P105PFS_BY = 0x04;  // D2 low

  char char_val = *PFS_P107PFS_BY; //d7
  Serial.println(char_val, HEX); 

  delay(500);
  *PFS_P105PFS_BY = 0x05;      //  d2 high

  char_val = *PFS_P107PFS_BY; //d7
  Serial.println(char_val, HEX); 

  delay(500);
  }

Many thanks, I'll have a look at that!

That's great, it appears to be working with a 50 microsecond delay, what do you think the min I could use is?

And thank you for the code!

Hi @heyheywhatcanido
From https://github.com/TriodeGirl/Arduino_Direct_Register_Operations

  *PFS_P107PFS_BY = 0x05;      // Each Port Output bit clear to set takes c. 82nS 
  *PFS_P107PFS_BY = 0x04;      // Each Port Output bit set to clear takes c. 85nS 
  *PFS_P107PFS_BY = 0x05;      // Set HIGH
  char_val = *PFS_P107PFS_BY;  // Port State Input read - takes about 165nS
  *PFS_P107PFS_BY = 0x04;      // Read plus Set LOW = c. 250nS

Fantastic, many thanks Susan.

I misread your first answer, just copied your code. I see now my mistake of just doing the read once per loop, no wonder it never changed :slight_smile:

Cool, it's got all the timings:

But how do the fast port operations compare to the standard speeds on the Uno R4?

I see some 1000X on-off toggling timings in code in this post:

...to give Uno R4 write timings as :

  • digitalWrite(): 1515us/(1000*2)= 757ns
  • fasterDigitalWrite: 1515us/(1000*2)= 590ns
  • digitalWriteFast: 179us/(1000*2)= 90ns
  • POSR/PORR: 179us/(1000*2)= 90ns

I don't have an R4, but I am curious about the Arduino basic digitalRead() speed versus the direct port access Port State Input Read speed of ~165ns.

Could someone try this on an R4?

void setup(){
Serial.begin(115200);
  uint32_t start_time = micros();
  for (int i = 0; i < 1000; i++) {
    digitalRead(13);
  }
  uint32_t delta_time = micros() - start_time;
  Serial.print("digitalRead: ");
  Serial.println(delta_time, DEC);
}

void loop(){}

Hi @DaveX - just to mention that my timings were derived using an oscilloscope and looking at the actual individual pin changing states.
So there may be some small nS differences between my measured values and the code timed ones :slight_smile: