The information from Rubber Duck is correct but incomplete.
I need a huge amount of digital PWM output for hobby train control.
So I connected 4 x 74HC595 to my At Mega which must be fed with a 2 kHz bit pattern through 0,5 ms. interrupts.
My serial shift function that shifts 32 bits into the registers takes 562 us per cycle. Impossible.
I made an optimized version of digitalWrite and Read, which takes 328 us. Now it is possible to PWM with 2 kHz. The trick is that my optimized function remembers the last 2 Pins including its bitmasks and outports; and I skip the Timer check. It is thread safe. For a single digitalWrite this takes a tiny bit more time. With repeating writing to datapin and clockpin it improves the standard Arduino digitalWrite with about 42%.
By the way: With the digitalWriteFast library the result is 45,8 µs, a really enormous improvement. But this library handles only writes, if the pin number is known (and thus fixed!) at compile time. That is not the case with my LiquidCrystal library, where either 4 or 8 bits parallel are written to the shield via 4 sequential pins.
I got my optimized digitalWrite only working for my application including the LiquidDisplay when I copied the C:\Users\Dell\Downloads\arduino-1.8.5\hardware\arduino\avr\cores\arduino library to a subfolder in the folder of my application, called
C:\Users\Dell\Google Drive\ …\…..\AppFolder\libraries.
When I replaced in both folders the wiring_digital.c with my optimized version, it worked.
I could not get it at work, when I only replaced the wiring_digital.c in the Arduino library (the LiquidCrystal took the standard function somewhere else).
Adding only wiring_digital.c in de subfolder of my application generated a mass of linking errors.
Thus I copied the whole Arduino folder (which is not that large) to my subfolder in the application and it compiles without any problem. Not a very elegant solution, because there is a replication of the whole library; but it works.
Conclusion to override a core Arduino function:
• Put your changed function(s) (.c and/or .h) in the Arduino library, and copy this library entirely to the subfolder "libraries" in your application folder. Then all other libraries will also use your own changed function.
Conclusion performance digitalWrite in a real 32 bit serial shift :
• An optimized generic digitalWrite and Read easily outperforms the standard one with 42% if 2 pins are used in repetition.
• digitalWriteFast (with determined pins at compile time) outperforms the standard digitalWrite in a real 32 bit shift application with 92% (is 12,2 times faster).
Hope this helps other Arduino users…..
//**********************
void digitalWrite(uint8_t pin, uint8_t val)
//**********************
{
uint8_t
timer,
bit,
port;
volatile uint8_t *out; // volatile because bitmask may be changed by (higher) interrupt
uint8_t oldSREG;
static uint8_t pin1 = 0,
pin2 = 0;
static bool p1 = true; // boolean toggle memory
static uint8_t // Store 2 sets of port/out adresses static
// timer1, //now exclued. Safety threat?
bit1,
*out1,
// timer2,
bit2,
*out2;
oldSREG = SREG; // CLI for thread proof function
cli();
if ( (pin == pin1) || (pin == pin2) )
{
if (pin == pin1) //Compiler optimizes this excellent (see ASM listing)
{
if (val == LOW)
{
*out1 &= ~bit1;
} else
{
*out1 |= bit1;
}
}
else
if (pin == pin2)
{
if (val == LOW)
{
*out2 &= ~bit2;
} else
{
*out2 |= bit2;
}
}
SREG = oldSREG;
}
else //normal clumsy digitalWrite operation
{
SREG = oldSREG; //Enable interrupts again
timer = digitalPinToTimer(pin);
bit = digitalPinToBitMask(pin);
port = digitalPinToPort(pin);
if (port == NOT_A_PIN) return;
// If the pin that support PWM output, we need to turn it off
// before doing a digital write.
// if (timer != NOT_ON_TIMER) turnOffPWM(timer);
out = portOutputRegister(port);
oldSREG = SREG;
cli();
if (val == LOW) {
*out &= ~bit;
} else {
*out |= bit;
}
if (p1) // Save this port, bit and out, also atomic
{
pin1 = pin;
bit1 = bit;
out1 = out; // save the pointer, not the value
}
else
{
pin2 = pin;
bit2 = bit;
out2 = out; // save the pointer, not the value
}
p1 = !p1;
SREG = oldSREG; //enable interrupts
}
}
//**********************
int digitalRead(uint8_t pin)
//**********************
{
uint8_t
oldSREG,
timer,
bit,
port;
static uint8_t pin1 = 0;
bool readBit;
static uint8_t // Store 2 sets of port/out adresses static
// timer1, //now exclued. Safety threat?
port1,
bit1;
oldSREG = SREG;
cli();
if (pin == pin1)
{
readBit = (*portInputRegister(port1) & bit1);
SREG = oldSREG;
return readBit;
}
else
{
SREG = oldSREG;
timer = digitalPinToTimer(pin);
bit = digitalPinToBitMask(pin);
port = digitalPinToPort(pin);
if (port == NOT_A_PIN) return LOW;
// If the pin that support PWM output, we need to turn it off
// before getting a digital reading.
// if (timer != NOT_ON_TIMER) turnOffPWM(timer);
oldSREG = SREG;
cli();
pin1 = pin; //Atomic operation pin - bit combi must be correct
bit1 = bit;
port1 = port;
SREG = oldSREG;
if (*portInputRegister(port) & bit) return HIGH;
return LOW;
}
}