1

I am new to Arduino, and am trying to understand the following code. The question is: Is my understanding correct, or if not, what is happening here?

I have to reverse engineer an existing undocumented project, based on Marlin firmware for 3D Printers. The relevant lines from the source are:

#define DIO87_PIN               PINE2
#define DIO87_RPORT             PINE
#define DIO87_WPORT             PORTE
#define DIO87_DDR               DDRE
#define DIO87_PWM               NULL

#define MASK(PIN)  (1 << PIN)
#define _TOGGLE(IO)  do {DIO ##  IO ## _RPORT = MASK(DIO ## IO ## _PIN); } while (0)
#define TOGGLE(IO)  _TOGGLE(IO)

TOGGLE(87);

1) Reducing this code gives me:
DI087_RPORT = 1 << DI087_PIN

2) Which reduces further to:
PINE = 1 << PINE2
3) Which reduces further to:
PINE = 00000100

4) I understand this to mean that we are setting Pin 2 of the Inputs Register (of Port E) to "High". (and are setting the other 7 pins to low)

5) I understand this to mean, as we are writing to an "Input", that we are enabling the internal pull-up resistor on Port E Pin 2. (EDIT: I have made a mistake here in point 5: to enable a pull-up resister, you write to a pins OUTPUT register, not it's INPUT register. (but you must write to it's output register when it is in "input mode")

Questions:

  1. Is my understanding and work-through above correct?
  2. If yes, does this also mean that we are also disabling the pull-up resistors to the other 7 Input Pins at the same time?

I am confused by the "TOGGLE" code given above - it seems that it is "destructive" in the sense that by "toggling" the input resistor on one pin, you also disable the resistors on all other pins? Would it not make more sense to just toggle the one pin with a bitwise or.
e.g:
PINE = PINE | 1 << PINE2

  • Ah, now I understand a little more: IF DDRx is set so pin(x) is OUTPUT, then writing a 1 to a PINx will toggle the corresponding PORTx value. (i.e will indeed toggle the "output" of that pin) However, IF any pins are set to INPUT in the DDR, (and have pull up-resistor enabled), then wouldn't this TOGGLE macro still inadvertently turn off those pullup resistors? – Mtl Dev Feb 16 '17 at 16:25
  • Maybe it's not completely obvious from the datasheet, but it can be seen in the figure of an I/O pin: writing a logic zero to PINxn has no effect whatsoever. Writing to a PINx register affects only those pins where you write a logic one. – Edgar Bonet Feb 16 '17 at 16:47
  • Thanks. I understand that, when DDRx=1, that writing a logic zero to PINx has no effect. Does the same hold true when DDRx=0? (input mode)? If this also does nothing, then how does one turn off the pull-up resistor? – Mtl Dev Feb 16 '17 at 18:35
  • I believe I have a mistake in my reasoning, point (5). To enable a pull up resistor, one writes a 1 to PORTxn not PINxn. And to disable a pull-up, one writes a 0 to PORTxn. – Mtl Dev Feb 16 '17 at 19:00
1

As noted in the I/O-Ports – Introduction section of the ATmega2560 datasheet,

... 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.

Bits masked with a zero won't be affected. You can toggle several bits at once if the byte written to the PINx register has several 1's in it.

Pullups are on for an input bit when the data bit is high and the PUD bit in MCUCR is low. So as suggested in your comment, pullups for toggled bits would toggle too, if PUD is low.

Regarding the macro code, your reduction looks right. But note that use of _TOGGLE as an identifier in that code violates section 17.4.3.1.2 of the C++ Standard. Names beginning with an underscore followed by an uppercase letter are reserved for use by language-implementation software. They are off-limits for user code. See What are the rules about using an underscore in a C++ identifier? for discussion.

0

The feature is well documented in the datasheetss.

Just be aware that it is not available on all across chips. Atmega8 for example is a notable exception.

0

Now that I have improved my understanding, I provide a full answer here for completeness.

  1. To enable (or disable) a pull up resister, you write a 1 (or 0) to the PORTxn (data) register.
  2. Writing a 1 to a PINxn (input)register, toggles (bitflips) whatever value is in the PORTxn data register.
  3. Writing a 0 to PINxn does nothing, ever.
  4. The structure of the Macro means it is hardcoded to only write to a PINxn register - it is impossible (with this code structure) to call "TOGGLE" on a PORTxn (Data) register.
  5. Thus, this TOGGLE macro will never cause any issues, as writing zero's to PINx causes no action.

Specifically the answer is in the following two lines of code:

#define DIO87_RPORT             PINE
#define _TOGGLE(IO)  do {DIO ##  IO ## _RPORT = MASK(DIO ## IO ## _PIN); } while (0)

(TOGGLE is hardcoded to use "DIO_XX_RPORT" which is PINx)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.