So, remember this really ugly implementation of DigitalWriteFast? It relied on gcc being able to optimize away long and complex ternary statements containing constants. It was fast, but it relied on awful-looking C macros that were completely separate from the main pins_arduino.c structures, and thus subject to maintenance nightmares.
Well, it turns out that gcc will also optimize indexing into static arrays with a constant, so we can get ALMOST as fast an implementation, using the code that already exists. No maintenance nightmare, and a pretty closely parallel implementation, and no particularly ugly macros.
variants/xxx/Board_Data.c gets a slight set of modifications so that it can make either global arrays (for pins_arduino.c) or static arrays that disappear when only indexed by constants:
Code:
+#if defined(OPT_BOARD_DATA_STATIC)
+#define MAYBESTATIC static
+#else
+#define MAYBESTATIC
+#endif
/* ------------------------------------------------------------ */
/* Data Tables */
@@ -56,7 +61,7 @@
** the TRIS register for the port. This is used for setting the
** pin direction.
*/
-const uint32_t port_to_tris_PGM[] = {
+MAYBESTATIC const uint32_t port_to_tris_PGM[] = {
NOT_A_PORT, //index value 0 is not used
#if defined(_PORTA)
@@ -108,7 +113,7 @@
/* This table is used to map the digital pin number to the port
** containing that pin.
*/
-const uint8_t digital_pin_to_port_PGM[] = {
+MAYBESTATIC const uint8_t digital_pin_to_port_PGM[] = {
And then fastio.h gets code to include the arrays, and uses inline functions that closely parallel wiring_digital.c. It even gets to include some of the sanity checking:
Code:
#define OPT_BOARD_DATA_STATIC 1
#define OPT_BOARD_DATA 1
#define OPT_BOARD_INTERNAL 1
#include <p32xxxx.h>
#include <WProgram.h>
#include <Board_Data.c>
/*
* This looks a lot like digitalWrite, but uses the static arrays and is inline.
* when called with constants, it should optimize down to the single instruct.
*/
static inline void _dwf(uint8_t pin, uint8_t val)
{
p32_ioport * iop;
unsigned int port;
unsigned int bit;
//* Get the port number for this pin.
if ((pin >= NUM_DIGITAL_PINS) ||
((port = digitalPinToPort(pin)) == NOT_A_PIN))
{
return;
}
//* Obtain pointer to the registers for this io port.
iop = (p32_ioport *)portRegisters(port);
//* Obtain bit mask for the specific bit for this pin.
bit = digitalPinToBitMask(pin);
//* Set the pin state
if (val == LOW)
{
iop->lat.clr = bit;
}
else
{
iop->lat.set = bit;
}
}
#define digitalWriteFast(P, V) \
if (__builtin_constant_p(P) && __builtin_constant_p(V)) { \
_dwf(P, V); \
} else { \
digitalWrite((P), (V)); \
}
This makes me feel a lot warmer and fuzzier than the previous implementation. It ought to be MUCH easier to add to the different variants, and could have "partial" support added to the core with no impact...