arduino / arduino/ArduinoCore-API
Adding digitalToggle to core?
- Dominant language
- C++
- Stars
- 306
- Forks
- 150
- PR merge metrics
- No merged PRs in 30d
Description
### Description
The Arduino core has a digitalWrite() and a digitalRead() function.
In many sketches there is a need to toggle a pin, either for a blinking LED or a clock pin for swSPI etc.
There are two typical ways to invert a pin - see code below
```cpp
// using a state holding the value of the pin
digitalWrite(pin, state);
state = 1 - state;
// read pin, invert and write back
digitalWrite(pin, !digitalRead(pin));
```
The latter one is slower as it redo a lot of "pin math", so I implemented a version of **digitalToggle()** for AVR.
Attached test sketch shows the gain compared to the two methods.
### Results test on UNO
```
Time us 1000 calls
Reference: 7392 // read invert write
Var: 4784 // use state var
Toggle: 3964 // use digitalToggle returning state
Toggle: 3520 // use digitalToggle returning NO state
```
The gain of toggle returning state is 46% resp 16%
The gain of toggle returning NO state is 52% resp 26%
Imho these gains are interesting, esp for clocking data
### Implementation for AVR
**Arduino.h**
```cpp
uint8_t digitalToggle(uint8_t pin); // returns the new state of the pin
```
**wiring_digital.c**
```cpp
uint8_t digitalToggle(uint8_t pin)
{
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *out;
if (port == NOT_A_PIN) return 0;
uint8_t timer = digitalPinToTimer(pin);
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
uint8_t bit = digitalPinToBitMask(pin);
out = portOutputRegister(port);
uint8_t oldSREG = SREG;
cli();
*out ^= bit; // invert bit
SREG = oldSREG;
return ((*out & bit) != 0);
}
```
Note: a no state returning version is straightforward given the above code.
### Test sketch
[digitalToggle.zip](https://github.com/arduino/Arduino/files/5646909/digitalToggle.zip)
```cpp
uint32_t start, Tref, Tref2, Tnew;
const uint8_t pin = 13;
uint8_t state = LOW;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println(__FILE__);
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
start = micros();
for (int i = 0; i < 1000; i++) digitalWrite(pin, !digitalRead(pin));
Tref = micros() - start;
start = micros();
for (int i = 0; i < 1000; i++)
{
digitalWrite(pin, state);
state = 1 - state;
}
Tref2 = micros() - start;
start = micros();
for (int i = 0; i < 1000; i++) digitalToggle(pin);
Tnew = micros() - start;
Serial.print("Reference:\t");
Serial.println(Tref);
Serial.print(" Var:\t");
Serial.println(Tref2);
Serial.print(" Toggle:\t");
Serial.println(Tnew);
Serial.print(" Gain:\t");
Serial.println(Tref - Tnew);
Serial.print(" Perc:\t");
Serial.println(100.0 - (100.0 * Tnew) / Tref, 1);
pinMode(13, OUTPUT);
}
void loop()
{
static int cnt = 0;
if (cnt == 60)
{
cnt = 0;
Serial.println();
}
cnt++;
// digitalToggle(pin);
int x = digitalToggle(pin);
Serial.print(x);
delay(1000);
}
```
### Additional context
#### Additional requests
- https://github.com/arduino/ArduinoCore-API/issues/77#issue-494269676
- https://github.com/arduino/ArduinoCore-API/issues/77#issuecomment-287657867
- https://github.com/arduino/ArduinoCore-API/issues/77#issuecomment-287658811
- https://github.com/arduino/ArduinoCore-API/issues/77#issuecomment-287660708
- https://github.com/arduino/ArduinoCore-API/issues/77#issuecomment-287696536
- https://github.com/arduino/ArduinoCore-API/issues/77#issuecomment-287732174
- https://github.com/arduino/Arduino/pull/111
- https://github.com/arduino/Arduino/issues/11777
Contributor guide
No contributing guide indexed for this repository
Research direction
Start by reading the proposed Arduino.h declaration and wiring_digital.c AVR implementation, then review ArduinoCore-API issue 77 and the linked Arduino issues and pull request. Done requires deciding the API shape, including the return value, and determining whether the proposal is suitable beyond the shown AVR implementation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- embedded-iot
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100