Pages: [1]   Go Down
Author Topic: How about adding digitalToggle(pin)?  (Read 1658 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1485
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is a neat feature of AVR I/O ports:
Quote
The Port Input Pins I/O location is read only. 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
This means that you could implement an efficient atomic digitalToggle(pin) function.  It should be faster than digitalWrite().  

It would be handy when you need to pulse a pin.  You just call digitalToggle(pin) twice.

I implemented toggle() like this as an inline function in a digital I/O class:
Code:
 void toggle() {*pinReg_ = bit_;}
This function executes in 8 cycles or 500 ns on a 16 MHz CPU.  This allows generation of a 500 ns pulse.

Not as good as the 125 ns that is possible when a pin number is a constant but is about 8 times faster than digitalWrite() which takes about 4 us.
« Last Edit: July 28, 2012, 11:03:30 am by fat16lib » Logged

0
Offline Offline
God Member
*****
Karma: 24
Posts: 587
Always making something...
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Single instruction (with const inputs) digitalWrite has existed since late 2009.  The idea was originally proposed by Ben Combee on the Arduino developer mail list in early 2009.  Before Ben's message, I was not aware of gcc's _builting_const_p().  Ben deserves much of the credit.  I saved his message and used his idea.

I wrote the first implementation in October-November 2009 and posted it to the list.  I started shipping it as part of Teensyduino in December 2009.  Originally I used static inline functions.  The Arduino developers asked for a macro, which I wrote.  They then asked if someone would create a macro for Arduino Mega, which I did within a matter of days.  It's been sitting unused on the issue tracker ever since:

http://code.google.com/p/arduino/issues/detail?id=140

Actually, as you can see, others have attempted to pick this up and use it over the years.  At one point it was even committed to a branch of Arduino, but of course it's never made its way into an official release.

I'm not saying a toggle function isn't a good idea.

But if digitalToggle's main purpose it to facilitate faster output, a far better solution has existed and sat unused for since November 2009.
« Last Edit: July 28, 2012, 12:38:09 pm by Paul Stoffregen » Logged

0
Offline Offline
God Member
*****
Karma: 24
Posts: 587
Always making something...
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I believe SAM3 chip planned for Arduino Due lacks a pin toggle register.  If this does become an official Arduino function, it will need to be implemented in as a read-modify-write sequence with interrupts disabled on Due.
« Last Edit: July 28, 2012, 01:04:24 pm by Paul Stoffregen » Logged

0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1485
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Paul,

Of course the case of fast write for a constant pin number has been around for years.  I have posted several versions based on classes and static functions that compile to a single sbi or cbi.  I like using static const arrays which the compiler optimizes out.  I did that in December 2009 for software SPI in SdFat but didn't post it until I saw your macros. 

For classes I use templates which forces a constant pin number without the gcc __builtin_constant_p(pin).

Toggle is useful for a constant pin number since it will toggle a pin in 125 ns.  You don't need to know the state of a pin to toggle it.

For a variable pin number it is fast since you don't need to do the atomic stuff.  You just write the bit you want to toggle to the PIN register.

As for digital I/O on SAM3X or ARM Cortex M in general, I hope I am not limited to the least common subset between AVR and ARM.  This is another reason I can't believe in AVR/ARM compatibility.

I don't expect to see toggle In the Arduino core but I added it to my digital libraries and was surprised how useful it can be.  I will be posting a new version of these libraries soon.
Logged

0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1485
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Guess I didn't make my case for toggle very well.  Here is an example where toggle is very useful.

In protocols like SPI, clock can have a polarity and signals have a phase.  This leads to the four SPI modes and makes handling clock messy in a general software SPI library.

There were lot of hard to understand lines like this where all I really wanted to do was toggle clock:
Code:
  fastDigitalWrite(SckPin, MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
The code is much cleaner when write is replaced with toggle:
Code:
  fastDigitalToggle(SckPin);
I am finding far more cases than I expected like the above where toggle is useful.

There was no speedup in the above case since all arguments are constant but in many cases you get a speedup and simpler code.
Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 121
Posts: 8458
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I believe SAM3 chip planned for Arduino Due lacks a pin toggle register.
True AFAIK.

I think a toggle function is good, even if it does degrade to a read-modify-write sequence on some processors.

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 106
Posts: 6381
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
I believe SAM3 chip planned for Arduino Due lacks a pin toggle register.
That's surprising, since Atmel has been putting that function in their newer AVRs, and many competing ARM chips have a toggle function.  (Although that's frequently to address otherwise poor pin manipulation rates...)  (Hmm.  Perhaps not.  I was pretty sure STM32F had this, but I can't find it in the manual.)

I hadn't thought about how useful a pin toggle function would be when implementing a bit-banged serial protocol with arbitrary clock polarity.  Thanks for pointing that out!
Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 121
Posts: 8458
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

LPCs have pin toggling.

______
Rob
Logged

Rob Gray aka the GRAYnomad www.robgray.com

SF Bay Area (USA)
Offline Offline
Tesla Member
***
Karma: 106
Posts: 6381
Strongly opinionated, but not official!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It occurs to me that adding pin toggling to a device that doesn't support it in hardware could be particularly expensive, depending on what primitive are available.
Logged

nr Bundaberg, Australia
Offline Offline
Tesla Member
***
Karma: 121
Posts: 8458
Scattered showers my arse -- Noah, 2348BC.
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I guess it's basically

Code:
get bit mask
get port address
read port
XOR with bit mask
write port

as opposed to

Code:
get bit mask
get port address
write port

EDIT:

On an LPC is would be this

Code:
LPC_GPIO0->NOT = 4;

To toggle pin 2 on port 0. So if you hard code the values that's it, but of course a generic function that works on logical pins needs more than that because it has to index into an array or whatever to get the port address and bit mask.

My code does this

Code:
port = pinPort(pin);
*gpio_regs[gpio_reg][port] |= word_bits[pin - (32 * port)];

I don't know how fast it is and will probably look at optimising later.

______
Rob
« Last Edit: July 30, 2012, 04:07:36 am by Graynomad » Logged

Rob Gray aka the GRAYnomad www.robgray.com

Offline Offline
Edison Member
*
Karma: 17
Posts: 1041
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have seen the lazy do:
Code:
digitalWrite(pin, !digitalRead(pin));

I think toggling is a good idea.
Logged

0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1485
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I posted a new version of fast I/O libraries with toggle() as DigitalPinBeta20120804.zip http://code.google.com/p/beta-lib/downloads/list.

The libraries support standard 168/328 Arduino, Mega, Leonardo, Teensy, Teensy++, and Sanguino.

The DigitalPin class provides very fast inline functions. DigitalPin is a template class and pin numbers must be specified at compile time. 

For 328 pins and low address Mega pins read(), toggle(), and write() execute in two cycles or 125 ns for a 16 MHz CPU.

The main member functions for the DigitalPin class are:
Code:
void config (bool mode, bool level);
void high ();
void low ();
void mode (bool pinMode);
bool read ();
void toggle ();
void write (bool value);

The library also contains these static inline functions similar to digitalRead()/digitalWrite().  Pin number must be a constant.
Code:
static bool fastDigitalRead (uint8_t pin);
static void fastDigitalToggle (uint8_t pin);
static void fastDigitalWrite (uint8_t pin, bool level);
static void fastPinConfig (uint8_t pin, bool mode, bool level);
static void fastPinMode (uint8_t pin, bool mode);

There is also a Software SPI class that runs at about 2 MHz.  It is also a template class with compile time pin numbers and SPI mode.  Modes 0 - 3 are supported MSB first.  LSB first would be easy to implement.

The member functions are:
Code:
void begin ();
uint8_t receive ();
void send (uint8_t data);
uint8_t transfer (uint8_t txData);
Logged

Pages: [1]   Go Up
Jump to: