Directly check pin for HIGH or LOW

Hey everybody,

I am only used to program ATmega uC’s so I’m new to direct port access on the arduion due. I did some research but I couldn’t quiet find an example for checking a digital I/O Pin for HIGH or LOW. I want to check pin 51 on the due for HIGHs and LOWs. The ATmega equivalent would be e. g. if(PINA&(1<<PINA51)) or if(~PINA&(1<<PINA51)).
I’m guessing something like if(PIO_PDSR&(1<<P0)) from page 645 in the SAM3X8E datasheet.

I hope someone can help me, thanks!

Jannik

Since pin 51 is PC12 (See Graynomad pinout diagram), you’ll have to read PIOC->PIO_PDSR bit 12. Beforehand, you have to power PIOC so that you can read input state on any PIOC pin.

An example sketch:

void setup() {
  PMC->PMC_PCER0 |= PMC_PCER0_PID13;  // PIOC power ON to read PIOC input level
}

void loop() {

  while (PIOC->PIO_PDSR & PIO_PDSR_P12) {  // As long as pin 51 (PC12) is High
   //Do something
  }

}

Not quite. The input registers only have 8 bits. On the Arduino MEGA 2650, for example, the look-up table to translate Arduino pin numbers to Port and Bit are found in “hardware/arduino/avr/variants/mega/pins_arduino.h”

In the table it says that Pin 51 is Bit 2 of Port B so the code to read it would be more like:

if(PINB&(1<<PB2)) or if(~PINB&(1<<PB2))

Hey everybody,

I am only used to program ATmega uC’s so I’m new to direct port access on the arduion due. I did some research but I couldn’t quiet find an example for checking a digital I/O Pin for HIGH or LOW. I want to check pin 51 on the due for HIGHs and LOWs. The ATmega equivalent would be e. g. if(PINA&(1<<PINA51)) or if(~PINA&(1<<PINA51)).
I’m guessing something like if(PIO_PDSR&(1<<P0)) from page 645 in the SAM3X8E datasheet.

I hope someone can help me, thanks!

Jannik

1 Like

just connect LED with 300 ohm resistor in series to your pin and run blink program

How does that help?

inline void digitalWriteDirect(int pin, boolean val)
{
  if (val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
  else    g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
}
// example: digitalReadDirect(12)
inline int digitalReadDirect(int pin)
{
  return !!(g_APinDescription[pin].pPort -> PIO_PDSR & g_APinDescription[pin].ulPin);
}

First you have to determine the translation of Pin 51. The pin mapping is in hardware/sam/1.6.12/varients/arduino_due_x/variant.cpp

  { PIOC, PIO_PC12,          ID_PIOC, PIO_OUTPUT_0, PIO_DEFAULT, PIN_ATTR_DIGITAL,                  NO_ADC, NO_ADC, NOT_ON_PWM,  NOT_ON_TIMER }, // PIN 51

Then all you have to do is figure out how to read a pin with the information provided. digitalRead() punts on that question, calling the function PIO_Get().

The meanings of the fields in the pin descriptor might be helpful. You can find that struct defined in Arduino.h:

/* Types used for the tables below */
typedef struct _PinDescription
{
  Pio* pPort ;
  uint32_t ulPin ;
  uint32_t ulPeripheralId ;
  EPioType ulPinType ;
  uint32_t ulPinConfiguration ;
  uint32_t ulPinAttribute ;
  EAnalogChannel ulAnalogChannel ; /* Analog pin in the Arduino context (label on the board) */
  EAnalogChannel ulADCChannelNumber ; /* ADC Channel number in the SAM device */
  EPWMChannel ulPWMChannel ;
  ETCChannel ulTCChannel ;
} PinDescription ;
1 Like

@jannik_b, do not cross-post. Threads merged.

Surely, the arduino Core has already powered PIOC?
There was a complication with direct WRITE because the chip “protects” the full register, and the core had not set PIO_OWER (Output Write Enable Register) to permit writes: portOutputRegister and portInputRegister are useless
(This was corrected a long time ago: portOutputRegister is now writeable. · arduino/ArduinoCore-sam@f4a5479 · GitHub )

Thanks for the tip, I found some interesting threads by searching for digitalReadDirect!
But I’m not quiet sure how to use this, do I put the inline code into the setup() or do I need to include a library?
I also need it only for one pin, so to safe some time can I write like :
bool myState = !!(g_APinDescription[12].pPort → PIO_PDSR & g_APinDescription[12].ulPin); because Pin51 = PC12 and then I check the pin like: if(myState==true)?

I think PIO_Get() is a bit overkill for my application. I only want to know if the pin is high or low but really fast.

The ‘g_APinDescription’ table is indexed by ARDUINO pin number so for Arduino Pin 51 you would use 51, not 12:
bool myState = !!(g_APinDescription[51].pPort->PIO_PDSR & g_APinDescription[51].ulPin);
And I already gave you the contents of that table entry (above) so you can avoid the two look-ups:
bool myState = !!(PIOC->PIO_PDSR & PIO_PC12);

Post # 5
Simple, HIGH or LOW = LED on LED off

Post # 14