I am preparing a general conception of a IO module based on arduino MEGA.
To be able to dynamically configure and check inputs/outputs, I need to know if the pin has been configured as INPUT, INPUT/pull-up or OUTPUT. I would like to avoid keeping a structure that mirrors the pinMode information and be able to check that on the fly directly from the registers.
I do not see any high level function in the Arduino code that does that check. I've taken a look at the pinMode function and it looks I need to check these registers:
reg = portModeRegister(port);
out = portOutputRegister(port);
Could you suggest how to check this to know the current pinMode?
Thanks!
1 Like
I don't know exactly how to do this, but I know what you need to do to learn how.
The pin modes are set by changing bits of (i.e. writing values to) special control registers in the uC (microcontroller). One can also read those registers. You will need to:
- Look through the Arduino support code (at least Arduino.h, may be others) to see the name of the register(s) that are written to with the PinMode() function for the different pin modes.
- Read the datasheet for the specific uC of the Arduino board that you will be using to decipher what those registers are, and what the individual bit locations mean.
- Apply your new knowledge to be able to have your sketch read those registers, understand the results, and take the appropriate action.
Note that the Arduino platform hides many of those low-level details from the general user so one can use the same code on the various Atmega uCs as well as the (completely different at the lowest level) SAM uC on the Due. So, for such low-level control that you want you need to target your code for a specific uC, and possibly change your code if you change to a different uC.
The DDR, data direction register, contains the input/output information, so you can read DDRD for example to see how PortD is setup.
There's another register for the pullup resistors.
See Section 14 in the '328P datasheet:
Three I/O memory address locations are allocated for each port, one each for the Data Register – PORTx, Data Direction Register – DDRx, and the Port Input Pins – PINx. The Port Input Pins I/O location is read only, while the Data Register and the Data Direction Register are read/write. However, writing a logic one to a bit in the PINx Register, will result in a toggle in the corresponding bit in the Data Register. In addition, the Pull-up Disable – PUD bit in MCUCR disables the pull-up function for all pins in all ports when set.
Quick update. It looks like a piece of cake after some reading of the way the processor works.
#define UNKNOWN_PIN 0xFF
uint8_t getPinMode(uint8_t pin)
{
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
// I don't see an option for mega to return this, but whatever...
if (NOT_A_PIN == port) return UNKNOWN_PIN;
// Is there a bit we can check?
if (0 == bit) return UNKNOWN_PIN;
// Is there only a single bit set?
if (bit & bit - 1) return UNKNOWN_PIN;
volatile uint8_t *reg, *out;
reg = portModeRegister(port);
out = portOutputRegister(port);
if (*reg & bit)
return OUTPUT;
else if (*out & bit)
return INPUT_PULLUP;
else
return INPUT;
}
2 Likes