martes, 13 de octubre de 2015

Arduino Port Manipulation


Depending on the application sometimes you need to read and write from pins very fast and with consistent timing, for example, when doing infrared reception and transmission. The incorporated digitalWrite() and digitalRead() are relatively slow and have variable latency ranging from a few microseconds to tens of them. Lucky us there's a way to access directly the registers where the values of pins are stored and written, so the latency to perform this operations is minimal and consistent.

Ports and Pin Mapping


https://www.arduino.cc/en/uploads/Hacking/32U4PinMapping.png
Pin mapping of an Arduino Leonardo (AtMega 32U4)
There are 3 main ports that store the input/output value of pins and also it's direction (input/output) with names B, C and D.  Every physical pin of an Arduino is mapped to a logical pin pertaining to one of the ports.
Each port has three 8-bit registers DDRx, PORTx and PINx where x is B, C or D:
DDRx - The Port x Data Direction Register - each bit tells if that pin is input or output.
PORTx - The Port x Data Register - read and write values of pins.
PINx - The Port x Input Pins Register - read only values of pins.
For example, on an Arduino Leonardo (image above) the digital pin 5 is the physical pin PC6 and that means the info about digital pin 5 is contained in the 6th bit of each register in port C. So then:

  • To change the mode of digital pin 5 without altering other pins:
        //OUTPUT mode on digital pin 5 (6th bit of port C)
        DDRC = DDRC | B01000000;

        //INPUT mode on digital pin 5 (6th bit of port C)
        DDRC = DDRC & B10111111;

! Careful if you are using TX and RX pins because this method could change the mode of those pins without you knowing (depending on the port they are in) and render them unuseful.
  • To change the output value of digital pin 5, without changing the value of other pins:
        //Output HIGH on digital pin 5 (6th bit of port C)
        PORTC = PORTC | B01000000;

        //Output LOW on digital pin 5 (6th bit of port C)
        PORTC = PORTC & B10111111;

 
  • Finally, to check the input value on digital pin 5:
        int pin_number = 6;
        value =   PINC & (1 << pin_number);

More information here: https://www.arduino.cc/en/Reference/PortManipulation

No hay comentarios:

Publicar un comentario