Nithin Varghese
Nithin Varghese

Reputation: 923

Not able to read the pin value from Arduino Mega using PINxn

Using the register of an Arduino Mega 2560, I am trying to grab the information of the PORTA. I have referred to the datasheet (pages 69-72) and understood that I've to use PINxn (PINA) for this. But all I am getting is 0 as output. I have connected the pin to a LED.

The code and the output are mentioned below.

CODE

#define F_CPU 16000000
#include <avr/io.h>

int main(void) {
  DDRA = (1 << DDA0); // sets the pin OUTPUT
  __asm__("nop\n\t");
  PORTA = 0x01; // Sets it HIGH
  unsigned int i = PINA;
  Serial.println(i);
}

OUTPUT

0

Thanks in advance for your time – if I’ve missed out anything, over- or under-emphasised a specific point let me know in the comments.

Upvotes: 0

Views: 338

Answers (2)

AterLux
AterLux

Reputation: 4654

You should put the "nop" in between the "PORTA = " assignment and "PINA" read. Because the instruction of writing to the PORTx register updates the status of the output pins just at the end of the system clock cycle at the rising edge of the clock generator, but reading from the PINx register returns information which is latched in an intermediate buffer. The buffer latches at the middle (i.e. at the falling edge of the clock generator) of the previous clock cycle.

So, reading from the PINx is always delayed for from 0.5 to 1.5 clock cycles. If the logic level changed in some system clock just before it's middle (i.e. before the falling edge of the clock generator), then this value will be immediately latched, and available for read thru reading the PINx register at the next system clock cycle. Thus, the delay is 0.5 cycles If the logic level changed just after that latching moment, then, it will be latched only in the next cycle, and will be available for reading in the cycle next after that, thus introducing the delay of 1.5 cycles

The writing to PORTx register updates the output value at the end of the clock cycle, so, it only latched in the next cycle, and will be available for reading only in next cycle after that.

The C compiler is pretty good for optimizaion, so, two consequent lines with PORTA assignment and PINA reading were compiled to just two consequent out PORTA, rxx and in ryy, PINA instructions, which cause that effect

Upvotes: 0

Yunnosch
Yunnosch

Reputation: 26703

If you want to read back the value previously written to output, I recommend to read it from the register you wrote to, i.e. PORTA.

However according to provided docu (bold by me):

13.2.4 Independent of the setting of Data Direction bit DDxn, the port pin can be read through the PINxn Register bit.

A possible explanation for reading back the old value, immediatly after writing a different one, is probably the shortly following part in the same chapter:

PINxn Register bit and the preceding latch constitute a synchronizer. This is needed to avoid metastability if the physical pin changes value near the edge of the internal clock, but it also introduces a delay.

So you will have to account for that delay.
Have a look at timing features provided e.g. by available libraries and at available timer hardware.
But as a proof of concept, I propose to demonstrate by

  • print the value of PINA before writing the inverted value
  • write the inverted value to PORTA (inverting only the relevant bit of course)
  • read and print the value of PINA afterwards (hoping that your header uses volatile here) many times (say 1000)

I expect that you will see several old values, but then the new value.

Depending on how the printing is done (busy waiting?), once might be sufficient.
Your NOP (__asm__("nop\n\t");) might be designed to do the appropriate waiting. But I think it is misplaced (should be after writing new value) and it might be too short. If it is from example code, it should be sufficient. Move it, and maybe do it twice, to be sure for first try. That is likely to be effective.

Upvotes: 1

Related Questions