Files
2025-10-12 09:13:56 +02:00

352 lines
10 KiB
C++

/*!
* @file Adafruit_seesaw.h
*
* This is part of Adafruit's seesaw driver for the Arduino platform. It is
* designed specifically to work with the Adafruit products that use seesaw
* technology.
*
* These chips use I2C to communicate, 2 pins (SCL+SDA) are required
* to interface with the board.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing
* products from Adafruit!
*
* Written by Dean Miller for Adafruit Industries.
*
* BSD license, all text here must be included in any redistribution.
*
*/
#ifndef LIB_SEESAW_H
#define LIB_SEESAW_H
#include "Adafruit_I2CDevice.h"
#include <Arduino.h>
#include <Wire.h>
/*=========================================================================
I2C ADDRESS/BITS
-----------------------------------------------------------------------*/
#define SEESAW_ADDRESS (0x49) ///< Default Seesaw I2C address
/*=========================================================================*/
/*=========================================================================
REGISTERS
-----------------------------------------------------------------------*/
/** Module Base Addreses
* The module base addresses for different seesaw modules.
*/
enum {
SEESAW_STATUS_BASE = 0x00,
SEESAW_GPIO_BASE = 0x01,
SEESAW_SERCOM0_BASE = 0x02,
SEESAW_TIMER_BASE = 0x08,
SEESAW_ADC_BASE = 0x09,
SEESAW_DAC_BASE = 0x0A,
SEESAW_INTERRUPT_BASE = 0x0B,
SEESAW_DAP_BASE = 0x0C,
SEESAW_EEPROM_BASE = 0x0D,
SEESAW_NEOPIXEL_BASE = 0x0E,
SEESAW_TOUCH_BASE = 0x0F,
SEESAW_KEYPAD_BASE = 0x10,
SEESAW_ENCODER_BASE = 0x11,
SEESAW_SPECTRUM_BASE = 0x12,
SEESAW_SOIL_BASE = 0x13,
};
/** GPIO module function address registers
*/
enum {
SEESAW_GPIO_DIRSET_BULK = 0x02,
SEESAW_GPIO_DIRCLR_BULK = 0x03,
SEESAW_GPIO_BULK = 0x04,
SEESAW_GPIO_BULK_SET = 0x05,
SEESAW_GPIO_BULK_CLR = 0x06,
SEESAW_GPIO_BULK_TOGGLE = 0x07,
SEESAW_GPIO_INTENSET = 0x08,
SEESAW_GPIO_INTENCLR = 0x09,
SEESAW_GPIO_INTFLAG = 0x0A,
SEESAW_GPIO_PULLENSET = 0x0B,
SEESAW_GPIO_PULLENCLR = 0x0C,
};
/** status module function address registers
*/
enum {
SEESAW_STATUS_HW_ID = 0x01,
SEESAW_STATUS_VERSION = 0x02,
SEESAW_STATUS_OPTIONS = 0x03,
SEESAW_STATUS_TEMP = 0x04,
SEESAW_STATUS_SWRST = 0x7F,
};
/** timer module function address registers
*/
enum {
SEESAW_TIMER_STATUS = 0x00,
SEESAW_TIMER_PWM = 0x01,
SEESAW_TIMER_FREQ = 0x02,
};
/** ADC module function address registers
*/
enum {
SEESAW_ADC_STATUS = 0x00,
SEESAW_ADC_INTEN = 0x02,
SEESAW_ADC_INTENCLR = 0x03,
SEESAW_ADC_WINMODE = 0x04,
SEESAW_ADC_WINTHRESH = 0x05,
SEESAW_ADC_CHANNEL_OFFSET = 0x07,
};
/** Sercom module function address registers
*/
enum {
SEESAW_SERCOM_STATUS = 0x00,
SEESAW_SERCOM_INTEN = 0x02,
SEESAW_SERCOM_INTENCLR = 0x03,
SEESAW_SERCOM_BAUD = 0x04,
SEESAW_SERCOM_DATA = 0x05,
};
/** neopixel module function address registers
*/
enum {
SEESAW_NEOPIXEL_STATUS = 0x00,
SEESAW_NEOPIXEL_PIN = 0x01,
SEESAW_NEOPIXEL_SPEED = 0x02,
SEESAW_NEOPIXEL_BUF_LENGTH = 0x03,
SEESAW_NEOPIXEL_BUF = 0x04,
SEESAW_NEOPIXEL_SHOW = 0x05,
};
/** touch module function address registers
*/
enum {
SEESAW_TOUCH_CHANNEL_OFFSET = 0x10,
};
/** keypad module function address registers
*/
enum {
SEESAW_KEYPAD_STATUS = 0x00,
SEESAW_KEYPAD_EVENT = 0x01,
SEESAW_KEYPAD_INTENSET = 0x02,
SEESAW_KEYPAD_INTENCLR = 0x03,
SEESAW_KEYPAD_COUNT = 0x04,
SEESAW_KEYPAD_FIFO = 0x10,
};
/** keypad module edge definitions
*/
enum {
SEESAW_KEYPAD_EDGE_HIGH = 0,
SEESAW_KEYPAD_EDGE_LOW,
SEESAW_KEYPAD_EDGE_FALLING,
SEESAW_KEYPAD_EDGE_RISING,
};
/** encoder module edge definitions
*/
enum {
SEESAW_ENCODER_STATUS = 0x00,
SEESAW_ENCODER_INTENSET = 0x10,
SEESAW_ENCODER_INTENCLR = 0x20,
SEESAW_ENCODER_POSITION = 0x30,
SEESAW_ENCODER_DELTA = 0x40,
};
/** Audio spectrum module function address registers
*/
enum {
SEESAW_SPECTRUM_RESULTS_LOWER = 0x00, // Audio spectrum bins 0-31
SEESAW_SPECTRUM_RESULTS_UPPER = 0x01, // Audio spectrum bins 32-63
// If some future device supports a larger spectrum, can add additional
// "bins" working upward from here. Configurable setting registers then
// work downward from the top to avoid collision between spectrum bins
// and configurables.
SEESAW_SPECTRUM_CHANNEL = 0xFD,
SEESAW_SPECTRUM_RATE = 0xFE,
SEESAW_SPECTRUM_STATUS = 0xFF,
};
/** soil moisture module function address registers
*/
enum {
// 0x00..0x0F Global Settings
SEESAW_SOIL_STATUS = 0x00,
SEESAW_SOIL_RATE = 0x01,
// 0x10..0xF0 Sensor Settings
// lower four bits = sensor number
// upper four bits = setting type
SEESAW_SOIL_VALUE = 0x10,
SEESAW_SOIL_SAMPLES = 0x20,
SEESAW_SOIL_XDELAY = 0x30,
SEESAW_SOIL_TIMEOUT = 0x40,
};
#define ADC_INPUT_0_PIN 2 ///< default ADC input pin
#define ADC_INPUT_1_PIN 3 ///< default ADC input pin
#define ADC_INPUT_2_PIN 4 ///< default ADC input pin
#define ADC_INPUT_3_PIN 5 ///< default ADC input pin
#define PWM_0_PIN 4 ///< default PWM output pin
#define PWM_1_PIN 5 ///< default PWM output pin
#define PWM_2_PIN 6 ///< default PWM output pin
#define PWM_3_PIN 7 ///< default PWM output pin
#ifndef INPUT_PULLDOWN
#define INPUT_PULLDOWN \
0x03 ///< for compatibility with platforms that do not already define
///< INPUT_PULLDOWN
#endif
/*=========================================================================*/
// clang-format off
#define SEESAW_HW_ID_CODE_SAMD09 0x55 ///< seesaw HW ID code for SAMD09
#define SEESAW_HW_ID_CODE_TINY806 0x84 ///< seesaw HW ID code for ATtiny806
#define SEESAW_HW_ID_CODE_TINY807 0x85 ///< seesaw HW ID code for ATtiny807
#define SEESAW_HW_ID_CODE_TINY816 0x86 ///< seesaw HW ID code for ATtiny816
#define SEESAW_HW_ID_CODE_TINY817 0x87 ///< seesaw HW ID code for ATtiny817
#define SEESAW_HW_ID_CODE_TINY1616 0x88 ///< seesaw HW ID code for ATtiny1616
#define SEESAW_HW_ID_CODE_TINY1617 0x89 ///< seesaw HW ID code for ATtiny1617
// clang-format on
/** raw key event stucture for keypad module */
union keyEventRaw {
struct {
uint8_t EDGE : 2; ///< the edge that was triggered
uint8_t NUM : 6; ///< the event number
} bit; ///< bitfield format
uint8_t reg; ///< register format
};
/** extended key event stucture for keypad module */
union keyEvent {
struct {
uint8_t EDGE : 2; ///< the edge that was triggered
uint16_t NUM : 14; ///< the event number
} bit; ///< bitfield format
uint16_t reg; ///< register format
};
/** key state struct that will be written to seesaw chip keypad module */
union keyState {
struct {
uint8_t STATE : 1; ///< the current state of the key
uint8_t ACTIVE : 4; ///< the registered events for that key
} bit; ///< bitfield format
uint8_t reg; ///< register format
};
/**************************************************************************/
/*!
@brief Class that stores state and functions for interacting with seesaw
helper IC
*/
/**************************************************************************/
class Adafruit_seesaw : public Print {
public:
// constructors
Adafruit_seesaw(TwoWire *Wi = NULL);
~Adafruit_seesaw(void){};
bool begin(uint8_t addr = SEESAW_ADDRESS, int8_t flow = -1,
bool reset = true);
uint32_t getOptions();
uint32_t getVersion();
bool getProdDatecode(uint16_t *pid, uint8_t *year, uint8_t *mon,
uint8_t *day);
bool SWReset();
void pinMode(uint8_t pin, uint8_t mode);
void pinModeBulk(uint32_t pins, uint8_t mode);
void pinModeBulk(uint32_t pinsa, uint32_t pinsb, uint8_t mode);
virtual void analogWrite(uint8_t pin, uint16_t value, uint8_t width = 8);
void digitalWrite(uint8_t pin, uint8_t value);
void digitalWriteBulk(uint32_t port_values);
void digitalWriteBulk(uint32_t pins, uint8_t value);
void digitalWriteBulk(uint32_t pinsa, uint32_t pinsb, uint8_t value);
bool digitalRead(uint8_t pin);
uint32_t digitalReadBulk(uint32_t pins);
uint32_t digitalReadBulkB(uint32_t pins);
void setGPIOInterrupts(uint32_t pins, bool enabled);
virtual uint16_t analogRead(uint8_t pin);
uint16_t touchRead(uint8_t pin);
virtual void setPWMFreq(uint8_t pin, uint16_t freq);
void enableSercomDataRdyInterrupt(uint8_t sercom = 0);
void disableSercomDataRdyInterrupt(uint8_t sercom = 0);
char readSercomData(uint8_t sercom = 0);
void EEPROMWrite8(uint8_t addr, uint8_t val);
void EEPROMWrite(uint8_t addr, uint8_t *buf, uint8_t size);
uint8_t EEPROMRead8(uint8_t addr);
void setI2CAddr(uint8_t addr);
uint8_t getI2CAddr();
void UARTSetBaud(uint32_t baud);
void setKeypadEvent(uint8_t key, uint8_t edge, bool enable = true);
void enableKeypadInterrupt();
void disableKeypadInterrupt();
uint8_t getKeypadCount();
bool readKeypad(keyEventRaw *buf, uint8_t count);
float getTemp();
int32_t getEncoderPosition(uint8_t encoder = 0);
int32_t getEncoderDelta(uint8_t encoder = 0);
bool enableEncoderInterrupt(uint8_t encoder = 0);
bool disableEncoderInterrupt(uint8_t encoder = 0);
void setEncoderPosition(int32_t pos, uint8_t encoder = 0);
virtual size_t write(uint8_t);
virtual size_t write(const char *str);
protected:
TwoWire *_i2cbus; /*!< The I2C Bus used to communicate with the seesaw */
Adafruit_I2CDevice *_i2c_dev = NULL; ///< The BusIO device for I2C control
int8_t _flow; /*!< The flow control pin to use */
uint8_t _hardwaretype = 0; /*!< what hardware type is attached! */
uint8_t getI2CaddrEEPROMloc();
bool write8(byte regHigh, byte regLow, byte value);
uint8_t read8(byte regHigh, byte regLow, uint16_t delay = 250);
bool read(uint8_t regHigh, uint8_t regLow, uint8_t *buf, uint8_t num,
uint16_t delay = 250);
bool write(uint8_t regHigh, uint8_t regLow, uint8_t *buf, uint8_t num);
/*=========================================================================
REGISTER BITFIELDS
-----------------------------------------------------------------------*/
/** Sercom interrupt enable register
*/
union sercom_inten {
struct {
uint8_t DATA_RDY : 1; ///< this bit is set when data becomes available
} bit; ///< bitfields
uint8_t reg; ///< full register
};
sercom_inten _sercom_inten; ///< sercom interrupt enable register instance
/*=========================================================================*/
};
#endif