This suggestion is an improvement for the core of Arduino library to allow unified GPIO pin access of the chip itself and certain expansion chips, in the same style as WiringPi does on Raspberry Pi.
Flexible Pin Interface (FPI) changes the behavior of pinMode(), digitalRead(), digitalWrite(), analogRead() and analogWrite() functions to place GPIO pins on the main chip and on expansion chips into a unified namespace. To do this, FPI adds one layer of abstraction between the aforementioned functions and the underlying hardware, allowing the appropriate GPIO driver of the pin to be resolved at run time.
Benefits of FPI interface:
- This will allow most existing libraries work with both IO pins on the chip itself and on expansion chips without modifying it (like NewLiquidCrystal did to LiquidCrystal library.)
- This will provide an unified, easy-to-understand interface for GPIO expanders (e.g. MCP23017), ADCs (e.g. ADC0832) and DACs (e.g. TLC5615)
A new function is introduced to insert GPIO drivers into the runtime:
class GPIO;
void insertGPIO(GPIO chip, uint8_t base);
extern GPIO Arduino;
All GPIO drivers, including the MCU GPIO pins represented by the global variable Arduino, inherits from a common base class:
class GPIO
{
// Housekeeping
virtual void begin(void);
virtual uint8_t pinCount(void);
// Pin manipulation methods
virtual int32_t analogRead(uint8_t pin); // int32_t instead of int to allow more precision, for the DACs and ADCs
virtual void analogWrite(uint8_t pin, int32_t value);
virtual bool digitalRead(uint8_t pin);
virtual void digitalWrite(uint8_t pin, int value);
virtual void pinMode(uint8_t pin, uint8_t mode); // uint8_t instead of an enum to allow custom modes
};
The pin-related methods in this class and its derivitives are called with a pin number offset - the pin number given by the user, minus the pin umber base set when inserting the driver. When a driver is inserted, its begin method is called.
By default, the GPIO driver for the board is inserted at base address 0 to allow compatibility with legacy code.
Code examples:
- TLC5615 DAC
#include <SPI.h>
#include <TLC5615.h>
#define DAC_PIN 64
#define DAC_SS 10
TLC5615 dac(DAC_SS);
void setup()
{
SPI.begin();
insertGPIO(dac, DAC_PIN); // pin 64 = DAC output, can be manipulated by analogWrite()
}
void loop()
{
analogWrite(DAC_PIN, (millis() & 0x3ff) << 2);
}
- PCF8574 IO expander and LCD
#include <Wire.h>
#include <LiquidCrystal.h>
#include <PCF8574.h>
#define EGPIO_ADDR 0x20
#define EGPIO_BASE 64
#define EGPIO(x) (EGPIO_BASE + (x))
PCF8574 egpio(EGPIO_ADDR);
#define LCD_RS EGPIO(0)
#define LCD_RW EGPIO(1)
#define LCD_EN EGPIO(2)
#define LCD_D4 EGPIO(7)
#define LCD_D5 EGPIO(6)
#define LCD_D6 EGPIO(5)
#define LCD_D7 EGPIO(4)
LiquidCrystal lcd(LCD_RS, LCD_RW, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7);
void setup()
{
Wire.begin();
insertGPIO(egpio, EGPIO_BASE); // Now we have GPIO pins 64 through 71 (inclusive) and LCD is there.
lcd.begin(); // This is normal LiquidCrystal which is using new FPI interface.
lcd.clear();
}
void loop()
{
}