2

I am currently using arduino library to logically set my digital pins high or low, but I just realized how slowly it actually sets those pins, which is especially problem as i am doing this in a ISR routine. Can't this be done faster by actually acessing the direct port, and setting the current pin?

How do I convert something like this

  digitalWrite(11, !digitalRead(11));

To something faster?

I am using a Arduino UNO..

migrated from electronics.stackexchange.com Oct 10 '16 at 12:48

This question came from our site for electronics and electrical engineering professionals, students, and enthusiasts.

5

Yes, it is possible

The atmel chip at the core of the arduinos can set or clear individual pin output levels in a single operation. There are special instructions to do so SBI and CBI- you just need to figure out what C compiles down to those instructions.

Each pin is represented by one bit of a port byte, for pin 11 it's bit 3 on port B. So you can toggle it with

PORTB ^= _BV(PB3);

or set it with

PORTB |= _BV(PB3);

or clear it with

PORTB &= ~_BV(PB3);

Probably the last two will compile to a single SBI/CBI instruction while the toggle one may or may not, depending on the code and how the compiler optimises it.

  • hmm.. I just tested it with an logic level analyzer and can't see the signal togglin anymore.. It seem high.. it is a 24mHz logic level analyzer, so it should be fast enough to see the toggling? – Carlton Banks Oct 10 '16 at 11:28
  • I wrote the answer from memory, you may want to check that 1) that is the correct pin, and 2) I have the correct syntax. Also, if the Arduino is doing nothing else, just toggling, then 24mHz will be nowhere near fast enough. – Jack B Oct 10 '16 at 11:31
  • sorry I meant 24 MHz – Carlton Banks Oct 10 '16 at 11:33
  • Also, I just edited the answer, I originally used PINB but it should be PORTB because the pin is configured as an output, not an input. – Jack B Oct 10 '16 at 11:36
  • 3
    Normally you just read from the PINB register, but it has an alternate function, in that it will toggle the pin if you write a 1 to that bit. From the datasheet: Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn. Note that the SBI instruction can be used to toggle one single bit in a port. – Gerben Oct 10 '16 at 15:38
4

Yes there is!
You can directly manipulate the port. The Arduino website has a pretty good explanation for it here.

Togelling a pin as asked by you can be simply done by something like this:

  PORTB ^= _BV(PINNUMBER)

A simplified way is the digitalWriteFast library.

This library consists of a complex header file that translates digitalWriteFast, pinModeFast, digitalReadFast into the corresponding PORT commands. It provides syntax that is as novice-friendly as the arduino's pin manipulation commands but an order of magnitude faster.

4

Since pin 11 on the ATmega328P is PB3:

PINB |= _BV(PB3);
2

The fastest way may be to use assembly from your C++ code:

asm volatile("SBI %[IOREG], %[BIT] \n\t"::[IOREG] "I" (&PINB), [BIT] "I" (PB3));

This forces a 1 to the bit for pin 11 (bit 3 on port B of the ATmega328), which, as per the Atmel datasheet, will simply toggle output (1 to 0 or 0 to 1) on that pin (provided it was initially setup as output).

As far as I remember the assemby instruction SBI used above cannot be generated by g++ (the C++ compiler used by Arduino IDE), hence you have to code it yourself.

You won't be able to achive a better performance as this single assembly instruction takes exactly 2 clock cycles to execute (ie 125 ns on an Arduino UNO).

  • You remember wrong. The answer from Ignacio Vazquez-Abrams compiles into the same assembly instruction. – Edgar Bonet Oct 11 '16 at 12:50
  • Then that's very good news! Is that a change of latest arduino toolchain? – jfpoilpret Oct 11 '16 at 12:52
  • Seems gcc does that since at least 2002, but I don't know how much the Arduino toolchain is lagging behind gcc. – Edgar Bonet Oct 11 '16 at 13:41
0

Yes that can be done by manipulating the ports directly. Here is the link to Arduino https://www.arduino.cc/en/Reference/PortManipulation

  • Whilst this may theoretically answer the question, it would be preferable to include the essential parts of the answer here, and provide the link for reference. Feel free to add a more complete answer that directly answers the question. – Nick Gammon Oct 12 '16 at 3:25
0

The Arduino GPIO library has been developed to allow high performance digital pin access. Most access functions are compiled to a single instruction and execute in 1-2 clock cycles. The library functions are more than 10 times faster than the Arduino digital pin functions. In some cases as much as 100 times faster.

Additional support classes are available for Shift Register Input/Output, and Software Serial. These also demonstrate how the GPIO template class may be used to construct additional libraries.

This library supports boards based on SAM3X8E, ATmega168, ATmega328P, ATmega32U4, ATmega1280, ATmega2560, ATtinyX4 and ATtinyX5.

The classical blink sketch looks like this:

GPIO<BOARD::D13> led;

void setup() 
{
  led.output();
}

void loop()
{
  led = HIGH;
  delay(1000);
  led = LOW;
  delay(1000);
}

Please see github for benchmarks and further documentation and examples.

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.