├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── githubci.yml ├── Adafruit_Crickit.cpp ├── Adafruit_Crickit.h ├── Adafruit_NeoKey_1x4.cpp ├── Adafruit_NeoKey_1x4.h ├── Adafruit_NeoTrellis.cpp ├── Adafruit_NeoTrellis.h ├── Adafruit_TFTShield18.cpp ├── Adafruit_TFTShield18.h ├── Adafruit_miniTFTWing.cpp ├── Adafruit_miniTFTWing.h ├── Adafruit_seesaw.cpp ├── Adafruit_seesaw.h ├── Doxyfile ├── README.md ├── examples ├── Crickit │ ├── basic │ │ └── basic.ino │ ├── cap_touch_demo │ │ └── cap_touch_demo.ino │ ├── drive │ │ ├── more_drivers │ │ │ └── more_drivers.ino │ │ └── test_drive │ │ │ └── test_drive.ino │ ├── fulltest │ │ └── fulltest.ino │ ├── motor │ │ └── dual_motor │ │ │ └── dual_motor.ino │ ├── servo │ │ ├── more_servos │ │ │ └── more_servos.ino │ │ └── test_servo │ │ │ └── test_servo.ino │ └── signal │ │ └── test_signal │ │ └── test_signal.ino ├── EEPROM │ └── EEPROM.ino ├── LEDArcade_1x4 │ └── LEDArcade_1x4.ino ├── Mini_I2C_Gamepad_QT │ └── Mini_I2C_Gamepad_QT.ino ├── NeoKey_1x4 │ ├── basic │ │ └── basic.ino │ ├── basic_callback │ │ └── basic_callback.ino │ ├── basic_multikey │ │ └── basic_multikey.ino │ └── basic_neoswirl │ │ └── basic_neoswirl.ino ├── NeoPixel │ └── NeoPixel_strandtest │ │ └── NeoPixel_strandtest.ino ├── NeoSlider │ ├── Dual_NeoSlider │ │ └── Dual_NeoSlider.ino │ └── NeoSlider │ │ └── NeoSlider.ino ├── NeoTrellis │ ├── basic │ │ └── basic.ino │ ├── interrupt │ │ └── interrupt.ino │ ├── multitrellis │ │ └── basic │ │ │ └── basic.ino │ ├── pattern_game │ │ └── pattern_game.ino │ └── ripples │ │ └── ripples.ino ├── PC_Joystick │ └── PC_Joystick.ino ├── analog │ ├── Fade │ │ └── Fade.ino │ └── analogRead │ │ └── analogRead.ino ├── audio_spectrum │ └── Audio_Spectrum │ │ └── Audio_Spectrum.ino ├── communication │ └── UART_loopback │ │ └── UART_loopback.ino ├── digital │ ├── attiny_blink │ │ └── attiny_blink.ino │ ├── blink │ │ └── blink.ino │ ├── gpio_interrupts │ │ └── gpio_interrupts.ino │ ├── multiblink │ │ └── multiblink.ino │ └── multiread │ │ └── multiread.ino ├── encoder │ ├── PID5740_ANOencoder_7Seg_demo │ │ ├── .pico_rp2040.test.only │ │ └── PID5740_ANOencoder_7Seg_demo.ino │ ├── PID5740_ANOencoder_demo │ │ └── PID5740_ANOencoder_demo.ino │ ├── PID5752_QuadEncoder_TFTDemo │ │ ├── .feather_esp32s2_tft.test.only │ │ └── PID5752_QuadEncoder_TFTDemo.ino │ ├── PID5752_QuadEncoder_demo │ │ └── PID5752_QuadEncoder_demo.ino │ ├── encoder_basic │ │ └── encoder_basic.ino │ └── multiple_encoders │ │ └── multiple_encoders.ino ├── encoder_delta │ └── encoder_delta.ino ├── joy_featherwing │ ├── joy_featherwing_ESP32 │ │ ├── .esp32.test.only │ │ └── joy_featherwing_ESP32.ino │ ├── joy_featherwing_example │ │ └── joy_featherwing_example.ino │ └── joy_wing_oled │ │ └── joy_wing_oled.ino └── soil_sensor │ └── soilsensor_example │ └── soilsensor_example.ino ├── library.properties ├── seesaw_motor.h ├── seesaw_neopixel.cpp ├── seesaw_neopixel.h ├── seesaw_servo.cpp ├── seesaw_servo.h ├── seesaw_spectrum.cpp └── seesaw_spectrum.h /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for opening an issue on an Adafruit Arduino library repository. To 2 | improve the speed of resolution please review the following guidelines and 3 | common troubleshooting steps below before creating the issue: 4 | 5 | - **Do not use GitHub issues for troubleshooting projects and issues.** Instead use 6 | the forums at http://forums.adafruit.com to ask questions and troubleshoot why 7 | something isn't working as expected. In many cases the problem is a common issue 8 | that you will more quickly receive help from the forum community. GitHub issues 9 | are meant for known defects in the code. If you don't know if there is a defect 10 | in the code then start with troubleshooting on the forum first. 11 | 12 | - **If following a tutorial or guide be sure you didn't miss a step.** Carefully 13 | check all of the steps and commands to run have been followed. Consult the 14 | forum if you're unsure or have questions about steps in a guide/tutorial. 15 | 16 | - **For Arduino projects check these very common issues to ensure they don't apply**: 17 | 18 | - For uploading sketches or communicating with the board make sure you're using 19 | a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes 20 | very hard to tell the difference between a data and charge cable! Try using the 21 | cable with other devices or swapping to another cable to confirm it is not 22 | the problem. 23 | 24 | - **Be sure you are supplying adequate power to the board.** Check the specs of 25 | your board and plug in an external power supply. In many cases just 26 | plugging a board into your computer is not enough to power it and other 27 | peripherals. 28 | 29 | - **Double check all soldering joints and connections.** Flakey connections 30 | cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. 31 | 32 | - **Ensure you are using an official Arduino or Adafruit board.** We can't 33 | guarantee a clone board will have the same functionality and work as expected 34 | with this code and don't support them. 35 | 36 | If you're sure this issue is a defect in the code and checked the steps above 37 | please fill in the following fields to provide enough troubleshooting information. 38 | You may delete the guideline and text above to just leave the following details: 39 | 40 | - Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE** 41 | 42 | - Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO 43 | VERSION HERE** 44 | 45 | - List the steps to reproduce the problem below (if possible attach a sketch or 46 | copy the sketch code in too): **LIST REPRO STEPS BELOW** 47 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Thank you for creating a pull request to contribute to Adafruit's GitHub code! 2 | Before you open the request please review the following guidelines and tips to 3 | help it be more easily integrated: 4 | 5 | - **Describe the scope of your change--i.e. what the change does and what parts 6 | of the code were modified.** This will help us understand any risks of integrating 7 | the code. 8 | 9 | - **Describe any known limitations with your change.** For example if the change 10 | doesn't apply to a supported platform of the library please mention it. 11 | 12 | - **Please run any tests or examples that can exercise your modified code.** We 13 | strive to not break users of the code and running tests/examples helps with this 14 | process. 15 | 16 | Thank you again for contributing! We will try to test and integrate the change 17 | as soon as we can, but be aware we have many GitHub repositories to manage and 18 | can't immediately respond to every request. There is no need to bump or check in 19 | on a pull request (it will clutter the discussion of the request). 20 | 21 | Also don't be worried if the request is closed or not integrated--sometimes the 22 | priorities of Adafruit's GitHub code (education, ease of use) might not match the 23 | priorities of the pull request. Don't fret, the open source community thrives on 24 | forks and GitHub makes it easy to keep your changes in a forked repo. 25 | 26 | After reviewing the guidelines above you can delete this text from the pull request. 27 | -------------------------------------------------------------------------------- /.github/workflows/githubci.yml: -------------------------------------------------------------------------------- 1 | name: Arduino Library CI 2 | 3 | on: [pull_request, push, repository_dispatch] 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | arduino-platform: ["uno", "leonardo", "mega2560", "zero", "esp8266", "esp32", "feather_esp32s2_tft", "metro_m4", "nrf52840"] 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/setup-python@v4 16 | with: 17 | python-version: '3.x' 18 | - uses: actions/checkout@v3 19 | - uses: actions/checkout@v3 20 | with: 21 | repository: adafruit/ci-arduino 22 | path: ci 23 | 24 | - name: pre-install 25 | run: bash ci/actions_install.sh 26 | 27 | - name: test platforms 28 | run: python3 ci/build_platform.py ${{ matrix.arduino-platform }} 29 | 30 | clang_and_doxy: 31 | runs-on: ubuntu-latest 32 | needs: build 33 | steps: 34 | - uses: actions/setup-python@v4 35 | with: 36 | python-version: '3.x' 37 | - uses: actions/checkout@v3 38 | 39 | - uses: actions/checkout@v3 40 | with: 41 | repository: adafruit/ci-arduino 42 | path: ci 43 | 44 | - name: pre-install 45 | run: bash ci/actions_install.sh 46 | 47 | - name: clang 48 | run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r . 49 | 50 | - name: doxygen 51 | env: 52 | GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }} 53 | PRETTYNAME : "Adafruit seesaw Library" 54 | run: bash ci/doxy_gen_and_deploy.sh 55 | 56 | -------------------------------------------------------------------------------- /Adafruit_Crickit.cpp: -------------------------------------------------------------------------------- 1 | #include "Adafruit_Crickit.h" 2 | 3 | // the pwm pins 4 | #define CRICKIT_NUM_PWM 12 5 | static const uint8_t CRICKIT_pwms[CRICKIT_NUM_PWM] = { 6 | CRICKIT_SERVO4, CRICKIT_SERVO3, CRICKIT_SERVO2, CRICKIT_SERVO1, 7 | CRICKIT_MOTOR_B1, CRICKIT_MOTOR_B2, CRICKIT_MOTOR_A1, CRICKIT_MOTOR_A2, 8 | CRICKIT_DRIVE4, CRICKIT_DRIVE3, CRICKIT_DRIVE2, CRICKIT_DRIVE1}; 9 | 10 | // the adc pin 11 | #define CRICKIT_NUM_ADC 8 12 | static const uint8_t CRICKIT_adc[CRICKIT_NUM_ADC] = { 13 | CRICKIT_SIGNAL1, CRICKIT_SIGNAL2, CRICKIT_SIGNAL3, CRICKIT_SIGNAL4, 14 | CRICKIT_SIGNAL5, CRICKIT_SIGNAL6, CRICKIT_SIGNAL7, CRICKIT_SIGNAL8}; 15 | 16 | void Adafruit_Crickit::analogWrite(uint8_t pin, uint16_t value, uint8_t width) { 17 | (void)width; 18 | 19 | int8_t p = -1; 20 | for (int i = 0; i < CRICKIT_NUM_PWM; i++) { 21 | if (CRICKIT_pwms[i] == pin) { 22 | p = i; 23 | break; 24 | } 25 | } 26 | 27 | if (p > -1) { 28 | uint8_t cmd[] = {(uint8_t)p, (uint8_t)(value >> 8), (uint8_t)value}; 29 | this->write(SEESAW_TIMER_BASE, SEESAW_TIMER_PWM, cmd, 3); 30 | } 31 | } 32 | 33 | uint16_t Adafruit_Crickit::analogRead(uint8_t pin) { 34 | uint8_t buf[2]; 35 | int8_t p = -1; 36 | for (int i = 0; i < CRICKIT_NUM_ADC; i++) { 37 | if (CRICKIT_adc[i] == pin) { 38 | p = i; 39 | break; 40 | } 41 | } 42 | 43 | if (p > -1) { 44 | this->read(SEESAW_ADC_BASE, SEESAW_ADC_CHANNEL_OFFSET + p, buf, 2, 500); 45 | uint16_t ret = ((uint16_t)buf[0] << 8) | buf[1]; 46 | delay(1); 47 | return ret; 48 | } else 49 | return 0; 50 | } 51 | 52 | void Adafruit_Crickit::setPWMFreq(uint8_t pin, uint16_t freq) { 53 | int8_t p = -1; 54 | for (int i = 0; i < CRICKIT_NUM_PWM; i++) { 55 | if (CRICKIT_pwms[i] == pin) { 56 | p = i; 57 | break; 58 | } 59 | } 60 | 61 | if (p > -1) { 62 | uint8_t cmd[] = {(uint8_t)p, (uint8_t)(freq >> 8), (uint8_t)freq}; 63 | this->write(SEESAW_TIMER_BASE, SEESAW_TIMER_FREQ, cmd, 3); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Adafruit_Crickit.h: -------------------------------------------------------------------------------- 1 | #ifndef _CRICKIT_TERSTER_H 2 | #define _CRICKIT_TERSTER_H 3 | 4 | #include "Adafruit_seesaw.h" 5 | 6 | #define CRICKIT_SIGNAL1 2 7 | #define CRICKIT_SIGNAL2 3 8 | #define CRICKIT_SIGNAL3 40 9 | #define CRICKIT_SIGNAL4 41 10 | #define CRICKIT_SIGNAL5 11 11 | #define CRICKIT_SIGNAL6 10 12 | #define CRICKIT_SIGNAL7 9 13 | #define CRICKIT_SIGNAL8 8 14 | 15 | #define CRICKIT_SERVO4 14 16 | #define CRICKIT_SERVO3 15 17 | #define CRICKIT_SERVO2 16 18 | #define CRICKIT_SERVO1 17 19 | 20 | #define CRICKIT_MOTOR_A1 22 21 | #define CRICKIT_MOTOR_A2 23 22 | #define CRICKIT_MOTOR_B1 19 23 | #define CRICKIT_MOTOR_B2 18 24 | #define CRICKIT_DRIVE1 13 25 | #define CRICKIT_DRIVE2 12 26 | #define CRICKIT_DRIVE3 43 27 | #define CRICKIT_DRIVE4 42 28 | 29 | #define CRICKIT_TOUCH1 0 30 | #define CRICKIT_TOUCH2 1 31 | #define CRICKIT_TOUCH3 2 32 | #define CRICKIT_TOUCH4 3 33 | 34 | #define CRICKIT_DUTY_CYCLE_OFF 0 35 | #define CRICKIT_DUTY_CYCLE_MAX 65535 36 | 37 | /**************************************************************************/ 38 | /*! 39 | @brief Class that stores state and functions for interacting with Crickit 40 | variant of seesaw helper IC 41 | */ 42 | /**************************************************************************/ 43 | class Adafruit_Crickit : public Adafruit_seesaw { 44 | public: 45 | Adafruit_Crickit(){}; 46 | ~Adafruit_Crickit(){}; 47 | 48 | void analogWrite(uint8_t pin, uint16_t value, uint8_t width = 8); 49 | uint16_t analogRead(uint8_t pin); 50 | void setPWMFreq(uint8_t pin, uint16_t freq); 51 | }; 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /Adafruit_NeoKey_1x4.cpp: -------------------------------------------------------------------------------- 1 | #include "Adafruit_NeoKey_1x4.h" 2 | 3 | /**************************************************************************/ 4 | /*! 5 | @brief Class constructor 6 | @param addr the I2C address this neotrellis object uses 7 | @param i2c_bus the I2C bus connected to this neokey, defaults to "Wire" 8 | */ 9 | /**************************************************************************/ 10 | Adafruit_NeoKey_1x4::Adafruit_NeoKey_1x4(uint8_t addr, TwoWire *i2c_bus) 11 | : Adafruit_seesaw(i2c_bus), pixels(NEOKEY_1X4_KEYS, NEOKEY_1X4_NEOPIN, 12 | NEO_GRB + NEO_KHZ800, i2c_bus) { 13 | for (int i = 0; i < NEOKEY_1X4_KEYS; i++) { 14 | _callbacks[i] = NULL; 15 | } 16 | this->_addr = addr; 17 | } 18 | 19 | /**************************************************************************/ 20 | /*! 21 | @brief Begin communication with the RGB trellis. 22 | @param addr optional i2c address where the device can be found. Defaults to 23 | NEOKEY_1X4_ADDR 24 | @param flow optional flow control pin 25 | @returns true on success, false on error. 26 | */ 27 | /**************************************************************************/ 28 | bool Adafruit_NeoKey_1x4::begin(uint8_t addr, int8_t flow) { 29 | _addr = addr; 30 | 31 | bool ret = pixels.begin(addr, flow); 32 | if (!ret) 33 | return ret; 34 | 35 | ret = Adafruit_seesaw::begin(addr, flow, false); 36 | if (!ret) 37 | return ret; 38 | 39 | pixels.setBrightness(40); 40 | pixels.show(); // Initialize all pixels to 'off' 41 | delay(5); 42 | pinModeBulk(NEOKEY_1X4_BUTTONMASK, INPUT_PULLUP); 43 | setGPIOInterrupts(NEOKEY_1X4_BUTTONMASK, 1); 44 | 45 | return ret; 46 | } 47 | 48 | /**************************************************************************/ 49 | /*! 50 | @brief register a callback function on the passed key. 51 | @param key the key number to register the callback on 52 | @param cb the callback function that should be called when an event on that 53 | key happens 54 | */ 55 | /**************************************************************************/ 56 | void Adafruit_NeoKey_1x4::registerCallback(uint8_t key, 57 | NeoKey1x4Callback (*cb)(keyEvent)) { 58 | _callbacks[key] = cb; 59 | } 60 | 61 | /**************************************************************************/ 62 | /*! 63 | @brief unregister a callback on a given key 64 | @param key the key number the callback is currently mapped to. 65 | */ 66 | /**************************************************************************/ 67 | void Adafruit_NeoKey_1x4::unregisterCallback(uint8_t key) { 68 | _callbacks[key] = NULL; 69 | } 70 | 71 | /**************************************************************************/ 72 | /*! 73 | @brief Read key GPIO pins, possibly generating callback events 74 | @returns Byte with the bottom 4 bits corresponding to each keypress status 75 | */ 76 | /**************************************************************************/ 77 | uint8_t Adafruit_NeoKey_1x4::read(void) { 78 | 79 | uint32_t buttons = digitalReadBulk(NEOKEY_1X4_BUTTONMASK); 80 | buttons ^= NEOKEY_1X4_BUTTONMASK; 81 | buttons &= NEOKEY_1X4_BUTTONMASK; 82 | buttons >>= NEOKEY_1X4_BUTTONA; 83 | 84 | uint8_t just_pressed = (buttons ^ last_buttons) & buttons; 85 | uint8_t just_released = (buttons ^ last_buttons) & ~buttons; 86 | if (just_pressed | just_released) { 87 | // Serial.print("pressed 0x"); Serial.println(just_pressed, HEX); 88 | // Serial.print("released 0x"); Serial.println(just_released, HEX); 89 | 90 | for (int b = 0; b < 4; b++) { 91 | if (just_pressed & (1 << b)) { // if button b is pressed 92 | if (_callbacks[b] != NULL) { 93 | keyEvent evt = {SEESAW_KEYPAD_EDGE_RISING, (uint16_t)b}; 94 | _callbacks[b](evt); 95 | } 96 | } 97 | 98 | if (just_released & (1 << b)) { // if button b is released 99 | if (_callbacks[b] != NULL) { 100 | keyEvent evt = {SEESAW_KEYPAD_EDGE_FALLING, (uint16_t)b}; 101 | _callbacks[b](evt); 102 | } 103 | } 104 | } 105 | } 106 | last_buttons = buttons; 107 | return buttons; 108 | } 109 | 110 | /**************************************************************************/ 111 | /*! 112 | @brief class constructor 113 | @param neokeys pointer to a multidimensional array of Adafruit_NeoKey_1x4 114 | objects. these object must have their I2C addresses specified in the class 115 | constructors. 116 | @param rows the number of individual neokey boards in the Y direction 117 | of your matrix. 118 | @param cols the number of individual neokey boards in the X direction 119 | of your matrix. 120 | */ 121 | /**************************************************************************/ 122 | Adafruit_MultiNeoKey1x4::Adafruit_MultiNeoKey1x4(Adafruit_NeoKey_1x4 *neokeys, 123 | uint8_t rows, uint8_t cols) { 124 | this->_rows = rows; 125 | this->_cols = cols; 126 | this->_neokeys = neokeys; 127 | } 128 | 129 | /**************************************************************************/ 130 | /*! 131 | @brief begin communication with the matrix of neotrellis boards. 132 | @returns true on success, false otherwise. 133 | */ 134 | /**************************************************************************/ 135 | bool Adafruit_MultiNeoKey1x4::begin() { 136 | Adafruit_NeoKey_1x4 *t; 137 | for (int n = 0; n < _rows; n++) { 138 | for (int m = 0; m < _cols; m++) { 139 | t = (_neokeys + n * _cols) + m; 140 | if (!t->begin(t->_addr)) 141 | return false; 142 | } 143 | } 144 | 145 | return true; 146 | } 147 | 148 | /**************************************************************************/ 149 | /*! 150 | @brief register a callback for a key addressed by key index. 151 | @param x the column index of the key. column 0 is on the lefthand side of 152 | the matix. 153 | @param y the row index of the key. row 0 is at the top of the matrix and 154 | the numbers increase downwards. 155 | @param cb the function to be called when an event from the specified key is 156 | detected. 157 | */ 158 | /**************************************************************************/ 159 | void Adafruit_MultiNeoKey1x4::registerCallback( 160 | uint8_t x, uint8_t y, NeoKey1x4Callback (*cb)(keyEvent)) { 161 | Adafruit_NeoKey_1x4 *t = 162 | (_neokeys + y / NEOKEY_1X4_ROWS * _cols) + x / NEOKEY_1X4_COLS; 163 | int xkey = NEOKEY_1X4_X(x); 164 | int ykey = NEOKEY_1X4_Y(y % NEOKEY_1X4_ROWS * NEOKEY_1X4_COLS); 165 | 166 | t->registerCallback(NEOKEY_1X4_XY(xkey, ykey), cb); 167 | } 168 | 169 | /**************************************************************************/ 170 | /*! 171 | @brief register a callback for a key addressed by key number. 172 | @param num the keynumber to set the color of. Key 0 is in the top left 173 | corner of the trellis matrix, key 1 is directly to the right of it, 174 | and the last key number is in the bottom righthand corner. 175 | @param cb the function to be called when an event from the specified key is 176 | detected. 177 | */ 178 | /**************************************************************************/ 179 | void Adafruit_MultiNeoKey1x4::registerCallback( 180 | uint16_t num, NeoKey1x4Callback (*cb)(keyEvent)) { 181 | uint8_t x = num % (NEOKEY_1X4_COLS * _cols); 182 | uint8_t y = num / (NEOKEY_1X4_COLS * _cols); 183 | 184 | registerCallback(x, y, cb); 185 | } 186 | 187 | /**************************************************************************/ 188 | /*! 189 | @brief Unregister a callback for a key addressed by key index. 190 | @param x the column index of the key. column 0 is on the lefthand side of 191 | the matix. 192 | @param y the row index of the key. row 0 is at the top of the matrix and 193 | the numbers increase downwards. 194 | */ 195 | /**************************************************************************/ 196 | void Adafruit_MultiNeoKey1x4::unregisterCallback(uint8_t x, uint8_t y) { 197 | Adafruit_NeoKey_1x4 *t = 198 | (_neokeys + y / NEOKEY_1X4_ROWS * _cols) + x / NEOKEY_1X4_COLS; 199 | int xkey = NEOKEY_1X4_X(x); 200 | int ykey = NEOKEY_1X4_Y(y % NEOKEY_1X4_ROWS * NEOKEY_1X4_COLS); 201 | 202 | t->unregisterCallback(NEOKEY_1X4_XY(xkey, ykey)); 203 | } 204 | 205 | /**************************************************************************/ 206 | /*! 207 | @brief Unregister a callback for a key addressed by key number. 208 | @param num the keynumber to set the color of. Key 0 is in the top left 209 | corner of the trellis matrix, key 1 is directly to the right of it, 210 | and the last key number is in the bottom righthand corner. 211 | */ 212 | /**************************************************************************/ 213 | void Adafruit_MultiNeoKey1x4::unregisterCallback(uint16_t num) { 214 | uint8_t x = num % (NEOKEY_1X4_COLS * _cols); 215 | uint8_t y = num / (NEOKEY_1X4_COLS * _cols); 216 | 217 | unregisterCallback(x, y); 218 | } 219 | 220 | /**************************************************************************/ 221 | /*! 222 | @brief set the color of a neopixel at a key index. 223 | @param x the column index of the key. column 0 is on the lefthand side of 224 | the matix. 225 | @param y the row index of the key. row 0 is at the top of the matrix and 226 | the numbers increase downwards. 227 | @param color the color to set the pixel to. This is a 24 bit RGB value. 228 | for example, full brightness red would be 0xFF0000, and full 229 | brightness blue would be 0x0000FF. 230 | */ 231 | /**************************************************************************/ 232 | void Adafruit_MultiNeoKey1x4::setPixelColor(uint8_t x, uint8_t y, 233 | uint32_t color) { 234 | Adafruit_NeoKey_1x4 *t = 235 | (_neokeys + y / NEOKEY_1X4_ROWS * _cols) + x / NEOKEY_1X4_COLS; 236 | int xkey = NEOKEY_1X4_X(x); 237 | int ykey = NEOKEY_1X4_Y(y % NEOKEY_1X4_ROWS * NEOKEY_1X4_COLS); 238 | 239 | t->pixels.setPixelColor(NEOKEY_1X4_XY(xkey, ykey), color); 240 | } 241 | 242 | /**************************************************************************/ 243 | /*! 244 | @brief set the color of a neopixel at a key number. 245 | @param num the keynumber to set the color of. Key 0 is in the top left 246 | corner of the trellis matrix, key 1 is directly to the right of it, 247 | and the last key number is in the bottom righthand corner. 248 | @param color the color to set the pixel to. This is a 24 bit RGB value. 249 | for example, full brightness red would be 0xFF0000, and full 250 | brightness blue would be 0x0000FF. 251 | */ 252 | /**************************************************************************/ 253 | void Adafruit_MultiNeoKey1x4::setPixelColor(uint16_t num, uint32_t color) { 254 | uint8_t x = num % (NEOKEY_1X4_COLS * _cols); 255 | uint8_t y = num / (NEOKEY_1X4_COLS * _cols); 256 | 257 | setPixelColor(x, y, color); 258 | } 259 | 260 | /**************************************************************************/ 261 | /*! 262 | @brief call show for all connected neotrellis boards to show all neopixels 263 | */ 264 | /**************************************************************************/ 265 | void Adafruit_MultiNeoKey1x4::show() { 266 | Adafruit_NeoKey_1x4 *t; 267 | for (int n = 0; n < _rows; n++) { 268 | for (int m = 0; m < _cols; m++) { 269 | t = (_neokeys + n * _cols) + m; 270 | t->pixels.show(); 271 | } 272 | } 273 | } 274 | 275 | /**************************************************************************/ 276 | /*! 277 | @brief read all events currently stored in the seesaw fifo and call any 278 | callbacks. 279 | */ 280 | /**************************************************************************/ 281 | void Adafruit_MultiNeoKey1x4::read() { 282 | Adafruit_NeoKey_1x4 *nk; 283 | 284 | for (int n = 0; n < _rows; n++) { 285 | for (int m = 0; m < _cols; m++) { 286 | // get the individual breakout 287 | nk = (_neokeys + n * _cols) + m; 288 | 289 | // query what buttons are pressed 290 | nk->digitalReadBulk( 291 | NEOKEY_1X4_BUTTONMASK); // not sure why we have to do it 2ce 292 | uint32_t buttons = nk->digitalReadBulk(NEOKEY_1X4_BUTTONMASK); 293 | 294 | // Serial.print("Neokey number "); Serial.print(n * _cols + m); 295 | // Serial.print(" buttons: 0x"); Serial.println(buttons, HEX); 296 | buttons ^= NEOKEY_1X4_BUTTONMASK; 297 | buttons &= NEOKEY_1X4_BUTTONMASK; 298 | buttons >>= NEOKEY_1X4_BUTTONA; 299 | 300 | // compared to last time 301 | uint8_t just_pressed = (buttons ^ nk->last_buttons) & buttons; 302 | uint8_t just_released = (buttons ^ nk->last_buttons) & ~buttons; 303 | // stash for next run 304 | nk->last_buttons = buttons; 305 | if (just_pressed | just_released) { 306 | // Serial.print("pressed 0x"); Serial.println(just_pressed, HEX); 307 | // Serial.print("released 0x"); Serial.println(just_released, HEX); 308 | 309 | // for each key, process the event 310 | for (int b = 0; b < 4; b++) { 311 | int x = b; // column is the button 312 | int y = 0; // a 1x4 neokey only has one row 313 | 314 | // extend into whole grid 315 | x = x + m * NEOKEY_1X4_COLS; 316 | y = y + n * NEOKEY_1X4_ROWS; 317 | 318 | int event_key = y * NEOKEY_1X4_COLS * _cols + x; 319 | 320 | if (just_pressed & (1 << b)) { // if button b is pressed 321 | if (nk->_callbacks[b] != NULL) { 322 | keyEvent evt = {SEESAW_KEYPAD_EDGE_RISING, (uint16_t)event_key}; 323 | nk->_callbacks[b](evt); 324 | } 325 | } 326 | if (just_released & (1 << b)) { // if button b is pressed 327 | if (nk->_callbacks[b] != NULL) { 328 | keyEvent evt = {SEESAW_KEYPAD_EDGE_FALLING, (uint16_t)event_key}; 329 | nk->_callbacks[b](evt); 330 | } 331 | } 332 | } 333 | } 334 | } 335 | } 336 | } 337 | -------------------------------------------------------------------------------- /Adafruit_NeoKey_1x4.h: -------------------------------------------------------------------------------- 1 | #ifndef _NEOKEY_1X4_H 2 | #define _NEOKEY_1X4_H 3 | 4 | #include "Adafruit_seesaw.h" 5 | #include "seesaw_neopixel.h" 6 | #include 7 | 8 | #define NEOKEY_1X4_ADDR 0x30 9 | 10 | #define NEOKEY_1X4_NEOPIN 3 11 | #define NEOKEY_1X4_BUTTONA 4 12 | #define NEOKEY_1X4_BUTTONB 5 13 | #define NEOKEY_1X4_BUTTONC 6 14 | #define NEOKEY_1X4_BUTTOND 7 15 | #define NEOKEY_1X4_BUTTONMASK ((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7)) 16 | 17 | #define NEOKEY_1X4_ROWS 1 18 | #define NEOKEY_1X4_COLS 4 19 | #define NEOKEY_1X4_KEYS (NEOKEY_1X4_ROWS * NEOKEY_1X4_COLS) 20 | 21 | #define NEOKEY_1X4_MAX_CALLBACKS 32 22 | 23 | /* NEOKEY_1X4_KEY depends on PCB routing */ 24 | // #define NEOKEY_1X4_KEY(x) (((x) / 4) * 8 + ((x) % 4)) 25 | #define NEOKEY_1X4_KEY(x) (((x) / 8) * 4 + ((x) % 8)) 26 | 27 | #define NEOKEY_1X4_X(k) ((k) % 4) 28 | #define NEOKEY_1X4_Y(k) ((k) / 4) 29 | 30 | #define NEOKEY_1X4_XY(x, y) ((y)*NEOKEY_1X4_ROWS + (x)) 31 | 32 | typedef void (*NeoKey1x4Callback)(keyEvent evt); 33 | 34 | /**************************************************************************/ 35 | /*! 36 | @brief Class that stores state and functions for interacting with the 37 | seesaw NeoKey module 38 | */ 39 | /**************************************************************************/ 40 | class Adafruit_NeoKey_1x4 : public Adafruit_seesaw { 41 | public: 42 | Adafruit_NeoKey_1x4(uint8_t addr = NEOKEY_1X4_ADDR, TwoWire *i2c_bus = &Wire); 43 | ~Adafruit_NeoKey_1x4(){}; 44 | 45 | bool begin(uint8_t addr = NEOKEY_1X4_ADDR, int8_t flow = -1); 46 | 47 | void registerCallback(uint8_t key, NeoKey1x4Callback (*cb)(keyEvent)); 48 | void unregisterCallback(uint8_t key); 49 | 50 | uint8_t read(void); 51 | 52 | seesaw_NeoPixel pixels; ///< the onboard neopixel matrix 53 | 54 | friend class Adafruit_MultiNeoKey1x4; ///< for allowing use of protected 55 | ///< methods by aggregate class 56 | 57 | protected: 58 | uint8_t last_buttons = 0; ///< The last reading for the buttons 59 | uint8_t _addr; ///< the I2C address of this board 60 | NeoKey1x4Callback (*_callbacks[NEOKEY_1X4_KEYS])( 61 | keyEvent); ///< the array of callback functions 62 | }; 63 | 64 | /**************************************************************************/ 65 | /*! 66 | @brief Class that stores state and functions for interacting with multiple 67 | neotrellis boards 68 | */ 69 | /**************************************************************************/ 70 | class Adafruit_MultiNeoKey1x4 { 71 | public: 72 | Adafruit_MultiNeoKey1x4(Adafruit_NeoKey_1x4 *neokeys, uint8_t rows, 73 | uint8_t cols); 74 | ~Adafruit_MultiNeoKey1x4(){}; 75 | 76 | bool begin(); 77 | 78 | void registerCallback(uint16_t num, NeoKey1x4Callback (*cb)(keyEvent)); 79 | void registerCallback(uint8_t x, uint8_t y, 80 | NeoKey1x4Callback (*cb)(keyEvent)); 81 | void unregisterCallback(uint16_t num); 82 | void unregisterCallback(uint8_t x, uint8_t y); 83 | 84 | void setPixelColor(uint8_t x, uint8_t y, uint32_t color); 85 | void setPixelColor(uint16_t num, uint32_t color); 86 | void show(); 87 | 88 | void read(); 89 | 90 | protected: 91 | uint8_t _rows; ///< the number of trellis boards in the Y direction 92 | uint8_t _cols; ///< the number of trellis boards in the X direction 93 | Adafruit_NeoKey_1x4 *_neokeys; ///< a multidimensional array of neokey objects 94 | }; 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /Adafruit_NeoTrellis.cpp: -------------------------------------------------------------------------------- 1 | #include "Adafruit_NeoTrellis.h" 2 | 3 | /**************************************************************************/ 4 | /*! 5 | @brief Class constructor 6 | @param addr the I2C address this neotrellis object uses 7 | @param i2c_bus the I2C bus connected to this neotrellis, defaults to "Wire" 8 | */ 9 | /**************************************************************************/ 10 | Adafruit_NeoTrellis::Adafruit_NeoTrellis(uint8_t addr, TwoWire *i2c_bus) 11 | : Adafruit_seesaw(i2c_bus), 12 | pixels(NEO_TRELLIS_NUM_KEYS, NEO_TRELLIS_NEOPIX_PIN, NEO_GRB + NEO_KHZ800, 13 | i2c_bus) { 14 | for (int i = 0; i < NEO_TRELLIS_NUM_KEYS; i++) { 15 | _callbacks[i] = NULL; 16 | } 17 | this->_addr = addr; 18 | } 19 | 20 | /**************************************************************************/ 21 | /*! 22 | @brief Begin communication with the RGB trellis. 23 | @param addr optional i2c address where the device can be found. Defaults to 24 | NEO_TRELLIS_ADDR 25 | @param flow optional flow control pin 26 | @returns true on success, false on error. 27 | */ 28 | /**************************************************************************/ 29 | bool Adafruit_NeoTrellis::begin(uint8_t addr, int8_t flow) { 30 | _addr = addr; 31 | 32 | bool ret = pixels.begin(addr, flow); 33 | 34 | ret = Adafruit_seesaw::begin(addr, flow, false); 35 | if (!ret) 36 | return ret; 37 | 38 | enableKeypadInterrupt(); 39 | 40 | return ret; 41 | } 42 | 43 | /**************************************************************************/ 44 | /*! 45 | @brief register a callback function on the passed key. 46 | @param key the key number to register the callback on 47 | @param cb the callback function that should be called when an event on that 48 | key happens 49 | */ 50 | /**************************************************************************/ 51 | void Adafruit_NeoTrellis::registerCallback(uint8_t key, 52 | TrellisCallback (*cb)(keyEvent)) { 53 | _callbacks[key] = cb; 54 | } 55 | 56 | /**************************************************************************/ 57 | /*! 58 | @brief unregister a callback on a given key 59 | @param key the key number the callback is currently mapped to. 60 | */ 61 | /**************************************************************************/ 62 | void Adafruit_NeoTrellis::unregisterCallback(uint8_t key) { 63 | _callbacks[key] = NULL; 64 | } 65 | 66 | /**************************************************************************/ 67 | /*! 68 | @brief activate or deactivate a given key event 69 | @param key the key number to map the event to 70 | @param edge the edge sensitivity of the event 71 | @param enable pass true to enable the passed event, false to disable it. 72 | */ 73 | /**************************************************************************/ 74 | void Adafruit_NeoTrellis::activateKey(uint8_t key, uint8_t edge, bool enable) { 75 | setKeypadEvent(NEO_TRELLIS_KEY(key), edge, enable); 76 | } 77 | 78 | /**************************************************************************/ 79 | /*! 80 | @brief read all events currently stored in the seesaw fifo and call any 81 | callbacks. 82 | @param polling pass true if the interrupt pin is not being used, false if 83 | it is. Defaults to true. 84 | */ 85 | /**************************************************************************/ 86 | void Adafruit_NeoTrellis::read(bool polling) { 87 | uint8_t count = getKeypadCount(); 88 | delayMicroseconds(500); 89 | if (count > 0) { 90 | if (polling) 91 | count = count + 2; 92 | keyEventRaw e[count]; 93 | readKeypad(e, count); 94 | for (int i = 0; i < count; i++) { 95 | // call any callbacks associated with the key 96 | e[i].bit.NUM = NEO_TRELLIS_SEESAW_KEY(e[i].bit.NUM); 97 | if (e[i].bit.NUM < NEO_TRELLIS_NUM_KEYS && 98 | _callbacks[e[i].bit.NUM] != NULL) { 99 | keyEvent evt = {e[i].bit.EDGE, e[i].bit.NUM}; 100 | _callbacks[e[i].bit.NUM](evt); 101 | } 102 | } 103 | } 104 | } 105 | 106 | /**************************************************************************/ 107 | /*! 108 | @brief class constructor 109 | @param trelli pointer to a multidimensional array of neotrellis objects. 110 | these object must have their I2C addresses specified in the class 111 | constructors. 112 | @param rows the number of individual neotrellis boards in the Y direction 113 | of your matrix. 114 | @param cols the number of individual neotrellis boards in the X direction 115 | of your matrix. 116 | */ 117 | /**************************************************************************/ 118 | Adafruit_MultiTrellis::Adafruit_MultiTrellis(Adafruit_NeoTrellis *trelli, 119 | uint8_t rows, uint8_t cols) { 120 | this->_rows = rows; 121 | this->_cols = cols; 122 | this->_trelli = trelli; 123 | } 124 | 125 | /**************************************************************************/ 126 | /*! 127 | @brief begin communication with the matrix of neotrellis boards. 128 | @returns true on success, false otherwise. 129 | */ 130 | /**************************************************************************/ 131 | bool Adafruit_MultiTrellis::begin() { 132 | Adafruit_NeoTrellis *t; 133 | for (int n = 0; n < _rows; n++) { 134 | for (int m = 0; m < _cols; m++) { 135 | t = (_trelli + n * _cols) + m; 136 | if (!t->begin(t->_addr)) 137 | return false; 138 | } 139 | } 140 | 141 | return true; 142 | } 143 | 144 | /**************************************************************************/ 145 | /*! 146 | @brief register a callback for a key addressed by key index. 147 | @param x the column index of the key. column 0 is on the lefthand side of 148 | the matix. 149 | @param y the row index of the key. row 0 is at the top of the matrix and 150 | the numbers increase downwards. 151 | @param cb the function to be called when an event from the specified key is 152 | detected. 153 | */ 154 | /**************************************************************************/ 155 | void Adafruit_MultiTrellis::registerCallback(uint8_t x, uint8_t y, 156 | TrellisCallback (*cb)(keyEvent)) { 157 | Adafruit_NeoTrellis *t = 158 | (_trelli + y / NEO_TRELLIS_NUM_ROWS * _cols) + x / NEO_TRELLIS_NUM_COLS; 159 | int xkey = NEO_TRELLIS_X(x); 160 | int ykey = NEO_TRELLIS_Y(y % NEO_TRELLIS_NUM_ROWS * NEO_TRELLIS_NUM_COLS); 161 | 162 | t->registerCallback(NEO_TRELLIS_XY(xkey, ykey), cb); 163 | } 164 | 165 | /**************************************************************************/ 166 | /*! 167 | @brief register a callback for a key addressed by key number. 168 | @param num the keynumber to set the color of. Key 0 is in the top left 169 | corner of the trellis matrix, key 1 is directly to the right of it, 170 | and the last key number is in the bottom righthand corner. 171 | @param cb the function to be called when an event from the specified key is 172 | detected. 173 | */ 174 | /**************************************************************************/ 175 | void Adafruit_MultiTrellis::registerCallback(uint16_t num, 176 | TrellisCallback (*cb)(keyEvent)) { 177 | uint8_t x = num % (NEO_TRELLIS_NUM_COLS * _cols); 178 | uint8_t y = num / (NEO_TRELLIS_NUM_COLS * _cols); 179 | 180 | registerCallback(x, y, cb); 181 | } 182 | 183 | /**************************************************************************/ 184 | /*! 185 | @brief Unregister a callback for a key addressed by key index. 186 | @param x the column index of the key. column 0 is on the lefthand side of 187 | the matix. 188 | @param y the row index of the key. row 0 is at the top of the matrix and 189 | the numbers increase downwards. 190 | */ 191 | /**************************************************************************/ 192 | void Adafruit_MultiTrellis::unregisterCallback(uint8_t x, uint8_t y) { 193 | Adafruit_NeoTrellis *t = 194 | (_trelli + y / NEO_TRELLIS_NUM_ROWS * _cols) + x / NEO_TRELLIS_NUM_COLS; 195 | int xkey = NEO_TRELLIS_X(x); 196 | int ykey = NEO_TRELLIS_Y(y % NEO_TRELLIS_NUM_ROWS * NEO_TRELLIS_NUM_COLS); 197 | 198 | t->unregisterCallback(NEO_TRELLIS_XY(xkey, ykey)); 199 | } 200 | 201 | /**************************************************************************/ 202 | /*! 203 | @brief Unregister a callback for a key addressed by key number. 204 | @param num the keynumber to set the color of. Key 0 is in the top left 205 | corner of the trellis matrix, key 1 is directly to the right of it, 206 | and the last key number is in the bottom righthand corner. 207 | */ 208 | /**************************************************************************/ 209 | void Adafruit_MultiTrellis::unregisterCallback(uint16_t num) { 210 | uint8_t x = num % (NEO_TRELLIS_NUM_COLS * _cols); 211 | uint8_t y = num / (NEO_TRELLIS_NUM_COLS * _cols); 212 | 213 | unregisterCallback(x, y); 214 | } 215 | 216 | /**************************************************************************/ 217 | /*! 218 | @brief Activate or deactivate a key by number. 219 | @param x the column index of the key. column 0 is on the lefthand side of 220 | the matix. 221 | @param y the row index of the key. row 0 is at the top of the matrix and 222 | the numbers increase downwards. 223 | @param edge the edge that the key triggers an event on. Use 224 | SEESAW_KEYPAD_EDGE_FALLING or SEESAW_KEYPAD_EDGE_RISING. 225 | @param enable pass true to enable the key on the passed edge, false to 226 | disable. 227 | */ 228 | /**************************************************************************/ 229 | void Adafruit_MultiTrellis::activateKey(uint8_t x, uint8_t y, uint8_t edge, 230 | bool enable) { 231 | Adafruit_NeoTrellis *t = 232 | (_trelli + y / NEO_TRELLIS_NUM_ROWS * _cols) + x / NEO_TRELLIS_NUM_COLS; 233 | int xkey = NEO_TRELLIS_X(x); 234 | int ykey = NEO_TRELLIS_Y(y % NEO_TRELLIS_NUM_ROWS * NEO_TRELLIS_NUM_COLS); 235 | 236 | t->activateKey(NEO_TRELLIS_XY(xkey, ykey), edge, enable); 237 | } 238 | 239 | /**************************************************************************/ 240 | /*! 241 | @brief Activate or deactivate a key by number. 242 | @param num the keynumber to set the color of. Key 0 is in the top left 243 | corner of the trellis matrix, key 1 is directly to the right of it, 244 | and the last key number is in the bottom righthand corner. 245 | @param edge the edge that the key triggers an event on. Use 246 | SEESAW_KEYPAD_EDGE_FALLING or SEESAW_KEYPAD_EDGE_RISING. 247 | @param enable pass true to enable the key on the passed edge, false to 248 | disable. 249 | */ 250 | /**************************************************************************/ 251 | void Adafruit_MultiTrellis::activateKey(uint16_t num, uint8_t edge, 252 | bool enable) { 253 | uint8_t x = num % (NEO_TRELLIS_NUM_COLS * _cols); 254 | uint8_t y = num / (NEO_TRELLIS_NUM_COLS * _cols); 255 | 256 | activateKey(x, y, edge, enable); 257 | } 258 | 259 | /**************************************************************************/ 260 | /*! 261 | @brief set the color of a neopixel at a key index. 262 | @param x the column index of the key. column 0 is on the lefthand side of 263 | the matix. 264 | @param y the row index of the key. row 0 is at the top of the matrix and 265 | the numbers increase downwards. 266 | @param color the color to set the pixel to. This is a 24 bit RGB value. 267 | for example, full brightness red would be 0xFF0000, and full 268 | brightness blue would be 0x0000FF. 269 | */ 270 | /**************************************************************************/ 271 | void Adafruit_MultiTrellis::setPixelColor(uint8_t x, uint8_t y, 272 | uint32_t color) { 273 | Adafruit_NeoTrellis *t = 274 | (_trelli + y / NEO_TRELLIS_NUM_ROWS * _cols) + x / NEO_TRELLIS_NUM_COLS; 275 | int xkey = NEO_TRELLIS_X(x); 276 | int ykey = NEO_TRELLIS_Y(y % NEO_TRELLIS_NUM_ROWS * NEO_TRELLIS_NUM_COLS); 277 | 278 | t->pixels.setPixelColor(NEO_TRELLIS_XY(xkey, ykey), color); 279 | } 280 | 281 | /**************************************************************************/ 282 | /*! 283 | @brief set the color of a neopixel at a key number. 284 | @param num the keynumber to set the color of. Key 0 is in the top left 285 | corner of the trellis matrix, key 1 is directly to the right of it, 286 | and the last key number is in the bottom righthand corner. 287 | @param color the color to set the pixel to. This is a 24 bit RGB value. 288 | for example, full brightness red would be 0xFF0000, and full 289 | brightness blue would be 0x0000FF. 290 | */ 291 | /**************************************************************************/ 292 | void Adafruit_MultiTrellis::setPixelColor(uint16_t num, uint32_t color) { 293 | uint8_t x = num % (NEO_TRELLIS_NUM_COLS * _cols); 294 | uint8_t y = num / (NEO_TRELLIS_NUM_COLS * _cols); 295 | 296 | setPixelColor(x, y, color); 297 | } 298 | 299 | /**************************************************************************/ 300 | /*! 301 | @brief call show for all connected neotrellis boards to show all neopixels 302 | */ 303 | /**************************************************************************/ 304 | void Adafruit_MultiTrellis::show() { 305 | Adafruit_NeoTrellis *t; 306 | for (int n = 0; n < _rows; n++) { 307 | for (int m = 0; m < _cols; m++) { 308 | t = (_trelli + n * _cols) + m; 309 | t->pixels.show(); 310 | } 311 | } 312 | } 313 | 314 | /**************************************************************************/ 315 | /*! 316 | @brief read all events currently stored in the seesaw fifo and call any 317 | callbacks. 318 | */ 319 | /**************************************************************************/ 320 | void Adafruit_MultiTrellis::read() { 321 | Adafruit_NeoTrellis *t; 322 | for (int n = 0; n < _rows; n++) { 323 | for (int m = 0; m < _cols; m++) { 324 | t = (_trelli + n * _cols) + m; 325 | 326 | uint8_t count = t->getKeypadCount(); 327 | delayMicroseconds(500); 328 | if (count > 0) { 329 | count = count + 2; 330 | keyEventRaw e[count]; 331 | t->readKeypad(e, count); 332 | for (int i = 0; i < count; i++) { 333 | // call any callbacks associated with the key 334 | e[i].bit.NUM = NEO_TRELLIS_SEESAW_KEY(e[i].bit.NUM); 335 | if (e[i].bit.NUM < NEO_TRELLIS_NUM_KEYS && 336 | t->_callbacks[e[i].bit.NUM] != NULL) { 337 | // update the event with the multitrellis number 338 | keyEvent evt = {e[i].bit.EDGE, e[i].bit.NUM}; 339 | int x = NEO_TRELLIS_X(e[i].bit.NUM); 340 | int y = NEO_TRELLIS_Y(e[i].bit.NUM); 341 | 342 | x = x + m * NEO_TRELLIS_NUM_COLS; 343 | y = y + n * NEO_TRELLIS_NUM_ROWS; 344 | 345 | evt.bit.NUM = y * NEO_TRELLIS_NUM_COLS * _cols + x; 346 | 347 | t->_callbacks[e[i].bit.NUM](evt); 348 | } 349 | } 350 | } 351 | } 352 | } 353 | } 354 | -------------------------------------------------------------------------------- /Adafruit_NeoTrellis.h: -------------------------------------------------------------------------------- 1 | #ifndef _NEO_TRELLIS_H 2 | #define _NEO_TRELLIS_H 3 | 4 | #include "Adafruit_seesaw.h" 5 | #include "seesaw_neopixel.h" 6 | #include 7 | 8 | #define NEO_TRELLIS_ADDR 0x2E 9 | 10 | #define NEO_TRELLIS_NEOPIX_PIN 3 11 | 12 | #define NEO_TRELLIS_NUM_ROWS 4 13 | #define NEO_TRELLIS_NUM_COLS 4 14 | #define NEO_TRELLIS_NUM_KEYS (NEO_TRELLIS_NUM_ROWS * NEO_TRELLIS_NUM_COLS) 15 | 16 | #define NEO_TRELLIS_MAX_CALLBACKS 32 17 | 18 | #define NEO_TRELLIS_KEY(x) (((x) / 4) * 8 + ((x) % 4)) 19 | #define NEO_TRELLIS_SEESAW_KEY(x) (((x) / 8) * 4 + ((x) % 8)) 20 | 21 | #define NEO_TRELLIS_X(k) ((k) % 4) 22 | #define NEO_TRELLIS_Y(k) ((k) / 4) 23 | 24 | #define NEO_TRELLIS_XY(x, y) ((y)*NEO_TRELLIS_NUM_COLS + (x)) 25 | 26 | typedef void (*TrellisCallback)(keyEvent evt); 27 | 28 | /**************************************************************************/ 29 | /*! 30 | @brief Class that stores state and functions for interacting with the 31 | seesaw keypad module 32 | */ 33 | /**************************************************************************/ 34 | class Adafruit_NeoTrellis : public Adafruit_seesaw { 35 | public: 36 | Adafruit_NeoTrellis(uint8_t addr = NEO_TRELLIS_ADDR, 37 | TwoWire *i2c_bus = &Wire); 38 | ~Adafruit_NeoTrellis(){}; 39 | 40 | bool begin(uint8_t addr = NEO_TRELLIS_ADDR, int8_t flow = -1); 41 | 42 | void registerCallback(uint8_t key, TrellisCallback (*cb)(keyEvent)); 43 | void unregisterCallback(uint8_t key); 44 | 45 | void activateKey(uint8_t key, uint8_t edge, bool enable = true); 46 | 47 | void read(bool polling = true); 48 | 49 | seesaw_NeoPixel pixels; ///< the onboard neopixel matrix 50 | 51 | friend class Adafruit_MultiTrellis; ///< for allowing use of protected methods 52 | ///< by aggregate class 53 | 54 | protected: 55 | uint8_t _addr; ///< the I2C address of this board 56 | TrellisCallback (*_callbacks[NEO_TRELLIS_NUM_KEYS])( 57 | keyEvent); ///< the array of callback functions 58 | }; 59 | 60 | /**************************************************************************/ 61 | /*! 62 | @brief Class that stores state and functions for interacting with multiple 63 | neotrellis boards 64 | */ 65 | /**************************************************************************/ 66 | class Adafruit_MultiTrellis { 67 | public: 68 | Adafruit_MultiTrellis(Adafruit_NeoTrellis *trelli, uint8_t rows, 69 | uint8_t cols); 70 | ~Adafruit_MultiTrellis(){}; 71 | 72 | bool begin(); 73 | 74 | void registerCallback(uint16_t num, TrellisCallback (*cb)(keyEvent)); 75 | void registerCallback(uint8_t x, uint8_t y, TrellisCallback (*cb)(keyEvent)); 76 | void unregisterCallback(uint16_t num); 77 | void unregisterCallback(uint8_t x, uint8_t y); 78 | 79 | void activateKey(uint16_t num, uint8_t edge, bool enable = true); 80 | void activateKey(uint8_t x, uint8_t y, uint8_t edge, bool enable = true); 81 | 82 | void setPixelColor(uint8_t x, uint8_t y, uint32_t color); 83 | void setPixelColor(uint16_t num, uint32_t color); 84 | void show(); 85 | 86 | void read(); 87 | 88 | protected: 89 | uint8_t _rows; ///< the number of trellis boards in the Y direction 90 | uint8_t _cols; ///< the number of trellis boards in the X direction 91 | Adafruit_NeoTrellis 92 | *_trelli; ///< a multidimensional array of neotrellis objects 93 | }; 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /Adafruit_TFTShield18.cpp: -------------------------------------------------------------------------------- 1 | #include "Adafruit_TFTShield18.h" 2 | 3 | /**************************************************************************/ 4 | /*! 5 | @brief set up the TFT shield 6 | @param addr optional address the seesaw chip can be found on 7 | @param flow optional flow control pin to use 8 | @returns true on success, false on error 9 | */ 10 | /**************************************************************************/ 11 | bool Adafruit_TFTShield18::begin(uint8_t addr, int8_t flow) { 12 | if (!Adafruit_seesaw::begin(addr, flow)) { 13 | return false; 14 | } 15 | 16 | pinMode(TFTSHIELD_RESET_PIN, OUTPUT); 17 | pinModeBulk(TFTSHIELD_BUTTON_ALL, INPUT_PULLUP); 18 | return true; 19 | } 20 | 21 | /**************************************************************************/ 22 | /*! 23 | @brief set the intensity of the backlight 24 | @param value to set the backlight to, 25 | 0x0000 = 0% (TFTSHIELD_BACKLIGHT_OFF) 26 | to 27 | 0xFFFF = 100% (TFTSHIELD_BACKLIGHT_ON) 28 | 29 | */ 30 | /**************************************************************************/ 31 | void Adafruit_TFTShield18::setBacklight(uint16_t value) { 32 | uint8_t cmd[] = {0x00, (uint8_t)(value >> 8), (uint8_t)value}; 33 | this->write(SEESAW_TIMER_BASE, SEESAW_TIMER_PWM, cmd, 3); 34 | } 35 | 36 | /**************************************************************************/ 37 | /*! 38 | @brief set the PWM frequency for the backlight 39 | @param freq the frequency to set the backlight to 40 | */ 41 | /**************************************************************************/ 42 | void Adafruit_TFTShield18::setBacklightFreq(uint16_t freq) { 43 | uint8_t cmd[] = {0x0, (uint8_t)(freq >> 8), (uint8_t)freq}; 44 | this->write(SEESAW_TIMER_BASE, SEESAW_TIMER_FREQ, cmd, 3); 45 | } 46 | 47 | /**************************************************************************/ 48 | /*! 49 | @brief reset the TFT screen by setting the value of the reset pin 50 | @param rst the value to set the reset pin to 51 | */ 52 | /**************************************************************************/ 53 | void Adafruit_TFTShield18::tftReset(bool rst) { 54 | digitalWrite(TFTSHIELD_RESET_PIN, rst); 55 | } 56 | 57 | /**************************************************************************/ 58 | /*! 59 | @brief read all buttons on the wing and return as a 32 bit integer 60 | @returns the value of the buttons 61 | */ 62 | /**************************************************************************/ 63 | uint32_t Adafruit_TFTShield18::readButtons() { 64 | return digitalReadBulk(TFTSHIELD_BUTTON_ALL); 65 | } -------------------------------------------------------------------------------- /Adafruit_TFTShield18.h: -------------------------------------------------------------------------------- 1 | #ifndef _TFT_SHIELD_18_H 2 | #define _TFT_SHIELD_18_H 3 | 4 | #include "Adafruit_seesaw.h" 5 | 6 | #define TFTSHIELD_ADDR 0x2E 7 | #define TFTSHIELD_RESET_PIN 3 8 | 9 | #define TFTSHIELD_BACKLIGHT_ON 0xFFFF 10 | #define TFTSHIELD_BACKLIGHT_OFF 0x0000 11 | 12 | #define TFTSHIELD_BUTTON_UP_PIN 5 13 | #define TFTSHIELD_BUTTON_UP (1UL << TFTSHIELD_BUTTON_UP_PIN) 14 | 15 | #define TFTSHIELD_BUTTON_DOWN_PIN 8 16 | #define TFTSHIELD_BUTTON_DOWN (1UL << TFTSHIELD_BUTTON_DOWN_PIN) 17 | 18 | #define TFTSHIELD_BUTTON_LEFT_PIN 6 19 | #define TFTSHIELD_BUTTON_LEFT (1UL << TFTSHIELD_BUTTON_LEFT_PIN) 20 | 21 | #define TFTSHIELD_BUTTON_RIGHT_PIN 9 22 | #define TFTSHIELD_BUTTON_RIGHT (1UL << TFTSHIELD_BUTTON_RIGHT_PIN) 23 | 24 | #define TFTSHIELD_BUTTON_IN_PIN 7 25 | #define TFTSHIELD_BUTTON_IN (1UL << TFTSHIELD_BUTTON_IN_PIN) 26 | 27 | #define TFTSHIELD_BUTTON_1_PIN 10 28 | #define TFTSHIELD_BUTTON_1 (1UL << TFTSHIELD_BUTTON_1_PIN) 29 | 30 | #define TFTSHIELD_BUTTON_2_PIN 11 31 | #define TFTSHIELD_BUTTON_2 (1UL << TFTSHIELD_BUTTON_2_PIN) 32 | 33 | #define TFTSHIELD_BUTTON_3_PIN 14 34 | #define TFTSHIELD_BUTTON_3 (1UL << TFTSHIELD_BUTTON_3_PIN) 35 | 36 | #define TFTSHIELD_BUTTON_ALL \ 37 | (TFTSHIELD_BUTTON_UP | TFTSHIELD_BUTTON_DOWN | TFTSHIELD_BUTTON_LEFT | \ 38 | TFTSHIELD_BUTTON_RIGHT | TFTSHIELD_BUTTON_IN | TFTSHIELD_BUTTON_1 | \ 39 | TFTSHIELD_BUTTON_2 | TFTSHIELD_BUTTON_3) 40 | 41 | /**************************************************************************/ 42 | /*! 43 | @brief Class that stores state and functions for interacting with 1.8" tft 44 | shield variant of seesaw helper IC 45 | */ 46 | /**************************************************************************/ 47 | class Adafruit_TFTShield18 : public Adafruit_seesaw { 48 | public: 49 | Adafruit_TFTShield18(){}; 50 | ~Adafruit_TFTShield18(){}; 51 | 52 | bool begin(uint8_t addr = TFTSHIELD_ADDR, int8_t flow = -1); 53 | 54 | void setBacklight(uint16_t value); 55 | void setBacklightFreq(uint16_t freq); 56 | void tftReset(bool rst = true); 57 | uint32_t readButtons(); 58 | }; 59 | 60 | #endif -------------------------------------------------------------------------------- /Adafruit_miniTFTWing.cpp: -------------------------------------------------------------------------------- 1 | #include "Adafruit_miniTFTWing.h" 2 | 3 | // These are the default SAMD09 version pins! (for back compatibility) 4 | uint8_t TFTWING_RESET_PIN = 8; 5 | 6 | uint8_t TFTWING_BUTTON_UP_PIN = 2; 7 | uint32_t TFTWING_BUTTON_UP = (1UL << TFTWING_BUTTON_UP_PIN); 8 | 9 | uint8_t TFTWING_BUTTON_DOWN_PIN = 4; 10 | uint32_t TFTWING_BUTTON_DOWN = (1UL << TFTWING_BUTTON_DOWN_PIN); 11 | 12 | uint8_t TFTWING_BUTTON_LEFT_PIN = 3; 13 | uint32_t TFTWING_BUTTON_LEFT = (1UL << TFTWING_BUTTON_LEFT_PIN); 14 | 15 | uint8_t TFTWING_BUTTON_RIGHT_PIN = 7; 16 | uint32_t TFTWING_BUTTON_RIGHT = (1UL << TFTWING_BUTTON_RIGHT_PIN); 17 | 18 | uint8_t TFTWING_BUTTON_SELECT_PIN = 11; 19 | uint32_t TFTWING_BUTTON_SELECT = (1UL << TFTWING_BUTTON_SELECT_PIN); 20 | 21 | uint8_t TFTWING_BUTTON_A_PIN = 10; 22 | uint32_t TFTWING_BUTTON_A = (1UL << TFTWING_BUTTON_A_PIN); 23 | 24 | uint8_t TFTWING_BUTTON_B_PIN = 9; 25 | uint32_t TFTWING_BUTTON_B = (1UL << TFTWING_BUTTON_B_PIN); 26 | 27 | uint32_t TFTWING_BUTTON_ALL = 28 | (TFTWING_BUTTON_UP | TFTWING_BUTTON_DOWN | TFTWING_BUTTON_LEFT | 29 | TFTWING_BUTTON_RIGHT | TFTWING_BUTTON_SELECT | TFTWING_BUTTON_A | 30 | TFTWING_BUTTON_B); 31 | 32 | /**************************************************************************/ 33 | /*! 34 | @brief set up the miniTFTWing 35 | @param addr optional address the seesaw chip can be found on 36 | @param Wi optional alternative I2C port to use, e.g. &Wire1 etc. Defaults 37 | to &Wire 38 | @returns true on success, false on error 39 | */ 40 | /**************************************************************************/ 41 | bool Adafruit_miniTFTWing::begin(uint8_t addr, TwoWire *Wi) { 42 | if (Wi != NULL) { 43 | Adafruit_seesaw::_i2cbus = Wi; 44 | } 45 | 46 | if (!Adafruit_seesaw::begin(addr, -1)) { 47 | return false; 48 | } 49 | 50 | if ((getVersion() >> 16) == 3322) { 51 | // check if we have a product ID burned in, if so its the ATtiny816 version! 52 | TFTWING_BUTTON_UP_PIN = 16; 53 | TFTWING_BUTTON_UP = (1UL << TFTWING_BUTTON_UP_PIN); 54 | 55 | TFTWING_BUTTON_DOWN_PIN = 13; 56 | TFTWING_BUTTON_DOWN = (1UL << TFTWING_BUTTON_DOWN_PIN); 57 | 58 | TFTWING_BUTTON_LEFT_PIN = 12; 59 | TFTWING_BUTTON_LEFT = (1UL << TFTWING_BUTTON_LEFT_PIN); 60 | 61 | TFTWING_BUTTON_RIGHT_PIN = 14; 62 | TFTWING_BUTTON_RIGHT = (1UL << TFTWING_BUTTON_RIGHT_PIN); 63 | 64 | TFTWING_BUTTON_SELECT_PIN = 15; 65 | TFTWING_BUTTON_SELECT = (1UL << TFTWING_BUTTON_SELECT_PIN); 66 | 67 | TFTWING_BUTTON_A_PIN = 11; 68 | TFTWING_BUTTON_A = (1UL << TFTWING_BUTTON_A_PIN); 69 | 70 | TFTWING_BUTTON_B_PIN = 10; 71 | TFTWING_BUTTON_B = (1UL << TFTWING_BUTTON_B_PIN); 72 | 73 | TFTWING_BUTTON_ALL = 74 | (TFTWING_BUTTON_UP | TFTWING_BUTTON_DOWN | TFTWING_BUTTON_LEFT | 75 | TFTWING_BUTTON_RIGHT | TFTWING_BUTTON_SELECT | TFTWING_BUTTON_A | 76 | TFTWING_BUTTON_B); 77 | 78 | TFTWING_RESET_PIN = 6; 79 | } 80 | this->pinMode(TFTWING_RESET_PIN, OUTPUT); 81 | this->pinModeBulk(TFTWING_BUTTON_ALL, INPUT_PULLUP); 82 | return true; 83 | } 84 | 85 | /**************************************************************************/ 86 | /*! 87 | @brief set the value of the backlight 88 | @param value the backlight value to set NOTE: 0xFFFF is all the way on 89 | 0x0000 is off. 90 | */ 91 | /**************************************************************************/ 92 | void Adafruit_miniTFTWing::setBacklight(uint16_t value) { 93 | 94 | if ((getVersion() >> 16) == 3322) { 95 | // this->analogWrite(7, value); 96 | this->pinMode(7, OUTPUT); 97 | if (value == TFTWING_BACKLIGHT_ON) { 98 | this->digitalWrite(7, LOW); 99 | } else { 100 | this->digitalWrite(7, HIGH); 101 | } 102 | } else { 103 | uint8_t cmd[] = {0x00, (uint8_t)(value >> 8), (uint8_t)value}; 104 | this->write(SEESAW_TIMER_BASE, SEESAW_TIMER_PWM, cmd, 3); 105 | } 106 | } 107 | 108 | /**************************************************************************/ 109 | /*! 110 | @brief set the PWM frequency for the backlight 111 | @param freq the frequency to set the backlight to 112 | */ 113 | /**************************************************************************/ 114 | void Adafruit_miniTFTWing::setBacklightFreq(uint16_t freq) { 115 | if ((getVersion() >> 16) == 3322) { 116 | } else { 117 | uint8_t cmd[] = {0x0, (uint8_t)(freq >> 8), (uint8_t)freq}; 118 | this->write(SEESAW_TIMER_BASE, SEESAW_TIMER_FREQ, cmd, 3); 119 | } 120 | } 121 | 122 | /**************************************************************************/ 123 | /*! 124 | @brief reset the TFT screen by setting the value of the reset pin 125 | @param rst the value to set the reset pin to 126 | */ 127 | /**************************************************************************/ 128 | void Adafruit_miniTFTWing::tftReset(bool rst) { 129 | this->digitalWrite(TFTWING_RESET_PIN, rst); 130 | } 131 | 132 | /**************************************************************************/ 133 | /*! 134 | @brief read all buttons on the wing and return as a 32 bit integer 135 | @returns the value of the buttons 136 | */ 137 | /**************************************************************************/ 138 | uint32_t Adafruit_miniTFTWing::readButtons() { 139 | return this->digitalReadBulk(TFTWING_BUTTON_ALL); 140 | } 141 | -------------------------------------------------------------------------------- /Adafruit_miniTFTWing.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef _MINI_TFT_WING_H 4 | #define _MINI_TFT_WING_H 5 | 6 | #include "Adafruit_seesaw.h" 7 | 8 | #define TFTWING_ADDR 0x5E 9 | 10 | #define TFTWING_BACKLIGHT_ON 0 // inverted output! 11 | #define TFTWING_BACKLIGHT_OFF 0xFFFF // inverted output! 12 | 13 | extern uint32_t TFTWING_BUTTON_UP, TFTWING_BUTTON_DOWN, TFTWING_BUTTON_LEFT, 14 | TFTWING_BUTTON_RIGHT, TFTWING_BUTTON_A, TFTWING_BUTTON_B, 15 | TFTWING_BUTTON_SELECT; 16 | 17 | /**************************************************************************/ 18 | /*! 19 | @brief Class that stores state and functions for interacting with mini tft 20 | wing variant of seesaw helper IC 21 | */ 22 | /**************************************************************************/ 23 | class Adafruit_miniTFTWing : public Adafruit_seesaw { 24 | public: 25 | Adafruit_miniTFTWing(){}; 26 | ~Adafruit_miniTFTWing(){}; 27 | 28 | bool begin(uint8_t addr = TFTWING_ADDR, TwoWire *Wi = NULL); 29 | 30 | void setBacklight(uint16_t value); 31 | void setBacklightFreq(uint16_t freq); 32 | void tftReset(bool rst = true); 33 | uint32_t readButtons(); 34 | }; 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /Adafruit_seesaw.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file Adafruit_seesaw.h 3 | * 4 | * This is part of Adafruit's seesaw driver for the Arduino platform. It is 5 | * designed specifically to work with the Adafruit products that use seesaw 6 | * technology. 7 | * 8 | * These chips use I2C to communicate, 2 pins (SCL+SDA) are required 9 | * to interface with the board. 10 | * 11 | * Adafruit invests time and resources providing this open source code, 12 | * please support Adafruit and open-source hardware by purchasing 13 | * products from Adafruit! 14 | * 15 | * Written by Dean Miller for Adafruit Industries. 16 | * 17 | * BSD license, all text here must be included in any redistribution. 18 | * 19 | */ 20 | 21 | #ifndef LIB_SEESAW_H 22 | #define LIB_SEESAW_H 23 | 24 | #include "Adafruit_I2CDevice.h" 25 | #include 26 | #include 27 | 28 | /*========================================================================= 29 | I2C ADDRESS/BITS 30 | -----------------------------------------------------------------------*/ 31 | #define SEESAW_ADDRESS (0x49) ///< Default Seesaw I2C address 32 | /*=========================================================================*/ 33 | 34 | /*========================================================================= 35 | REGISTERS 36 | -----------------------------------------------------------------------*/ 37 | 38 | /** Module Base Addreses 39 | * The module base addresses for different seesaw modules. 40 | */ 41 | enum { 42 | SEESAW_STATUS_BASE = 0x00, 43 | SEESAW_GPIO_BASE = 0x01, 44 | SEESAW_SERCOM0_BASE = 0x02, 45 | 46 | SEESAW_TIMER_BASE = 0x08, 47 | SEESAW_ADC_BASE = 0x09, 48 | SEESAW_DAC_BASE = 0x0A, 49 | SEESAW_INTERRUPT_BASE = 0x0B, 50 | SEESAW_DAP_BASE = 0x0C, 51 | SEESAW_EEPROM_BASE = 0x0D, 52 | SEESAW_NEOPIXEL_BASE = 0x0E, 53 | SEESAW_TOUCH_BASE = 0x0F, 54 | SEESAW_KEYPAD_BASE = 0x10, 55 | SEESAW_ENCODER_BASE = 0x11, 56 | SEESAW_SPECTRUM_BASE = 0x12, 57 | }; 58 | 59 | /** GPIO module function address registers 60 | */ 61 | enum { 62 | SEESAW_GPIO_DIRSET_BULK = 0x02, 63 | SEESAW_GPIO_DIRCLR_BULK = 0x03, 64 | SEESAW_GPIO_BULK = 0x04, 65 | SEESAW_GPIO_BULK_SET = 0x05, 66 | SEESAW_GPIO_BULK_CLR = 0x06, 67 | SEESAW_GPIO_BULK_TOGGLE = 0x07, 68 | SEESAW_GPIO_INTENSET = 0x08, 69 | SEESAW_GPIO_INTENCLR = 0x09, 70 | SEESAW_GPIO_INTFLAG = 0x0A, 71 | SEESAW_GPIO_PULLENSET = 0x0B, 72 | SEESAW_GPIO_PULLENCLR = 0x0C, 73 | }; 74 | 75 | /** status module function address registers 76 | */ 77 | enum { 78 | SEESAW_STATUS_HW_ID = 0x01, 79 | SEESAW_STATUS_VERSION = 0x02, 80 | SEESAW_STATUS_OPTIONS = 0x03, 81 | SEESAW_STATUS_TEMP = 0x04, 82 | SEESAW_STATUS_SWRST = 0x7F, 83 | }; 84 | 85 | /** timer module function address registers 86 | */ 87 | enum { 88 | SEESAW_TIMER_STATUS = 0x00, 89 | SEESAW_TIMER_PWM = 0x01, 90 | SEESAW_TIMER_FREQ = 0x02, 91 | }; 92 | 93 | /** ADC module function address registers 94 | */ 95 | enum { 96 | SEESAW_ADC_STATUS = 0x00, 97 | SEESAW_ADC_INTEN = 0x02, 98 | SEESAW_ADC_INTENCLR = 0x03, 99 | SEESAW_ADC_WINMODE = 0x04, 100 | SEESAW_ADC_WINTHRESH = 0x05, 101 | SEESAW_ADC_CHANNEL_OFFSET = 0x07, 102 | }; 103 | 104 | /** Sercom module function address registers 105 | */ 106 | enum { 107 | SEESAW_SERCOM_STATUS = 0x00, 108 | SEESAW_SERCOM_INTEN = 0x02, 109 | SEESAW_SERCOM_INTENCLR = 0x03, 110 | SEESAW_SERCOM_BAUD = 0x04, 111 | SEESAW_SERCOM_DATA = 0x05, 112 | }; 113 | 114 | /** neopixel module function address registers 115 | */ 116 | enum { 117 | SEESAW_NEOPIXEL_STATUS = 0x00, 118 | SEESAW_NEOPIXEL_PIN = 0x01, 119 | SEESAW_NEOPIXEL_SPEED = 0x02, 120 | SEESAW_NEOPIXEL_BUF_LENGTH = 0x03, 121 | SEESAW_NEOPIXEL_BUF = 0x04, 122 | SEESAW_NEOPIXEL_SHOW = 0x05, 123 | }; 124 | 125 | /** touch module function address registers 126 | */ 127 | enum { 128 | SEESAW_TOUCH_CHANNEL_OFFSET = 0x10, 129 | }; 130 | 131 | /** keypad module function address registers 132 | */ 133 | enum { 134 | SEESAW_KEYPAD_STATUS = 0x00, 135 | SEESAW_KEYPAD_EVENT = 0x01, 136 | SEESAW_KEYPAD_INTENSET = 0x02, 137 | SEESAW_KEYPAD_INTENCLR = 0x03, 138 | SEESAW_KEYPAD_COUNT = 0x04, 139 | SEESAW_KEYPAD_FIFO = 0x10, 140 | }; 141 | 142 | /** keypad module edge definitions 143 | */ 144 | enum { 145 | SEESAW_KEYPAD_EDGE_HIGH = 0, 146 | SEESAW_KEYPAD_EDGE_LOW, 147 | SEESAW_KEYPAD_EDGE_FALLING, 148 | SEESAW_KEYPAD_EDGE_RISING, 149 | }; 150 | 151 | /** encoder module edge definitions 152 | */ 153 | enum { 154 | SEESAW_ENCODER_STATUS = 0x00, 155 | SEESAW_ENCODER_INTENSET = 0x10, 156 | SEESAW_ENCODER_INTENCLR = 0x20, 157 | SEESAW_ENCODER_POSITION = 0x30, 158 | SEESAW_ENCODER_DELTA = 0x40, 159 | }; 160 | 161 | /** Audio spectrum module function address registers 162 | */ 163 | enum { 164 | SEESAW_SPECTRUM_RESULTS_LOWER = 0x00, // Audio spectrum bins 0-31 165 | SEESAW_SPECTRUM_RESULTS_UPPER = 0x01, // Audio spectrum bins 32-63 166 | // If some future device supports a larger spectrum, can add additional 167 | // "bins" working upward from here. Configurable setting registers then 168 | // work downward from the top to avoid collision between spectrum bins 169 | // and configurables. 170 | SEESAW_SPECTRUM_CHANNEL = 0xFD, 171 | SEESAW_SPECTRUM_RATE = 0xFE, 172 | SEESAW_SPECTRUM_STATUS = 0xFF, 173 | }; 174 | 175 | #define ADC_INPUT_0_PIN 2 ///< default ADC input pin 176 | #define ADC_INPUT_1_PIN 3 ///< default ADC input pin 177 | #define ADC_INPUT_2_PIN 4 ///< default ADC input pin 178 | #define ADC_INPUT_3_PIN 5 ///< default ADC input pin 179 | 180 | #define PWM_0_PIN 4 ///< default PWM output pin 181 | #define PWM_1_PIN 5 ///< default PWM output pin 182 | #define PWM_2_PIN 6 ///< default PWM output pin 183 | #define PWM_3_PIN 7 ///< default PWM output pin 184 | 185 | #ifndef INPUT_PULLDOWN 186 | #define INPUT_PULLDOWN \ 187 | 0x03 ///< for compatibility with platforms that do not already define 188 | ///< INPUT_PULLDOWN 189 | #endif 190 | 191 | /*=========================================================================*/ 192 | // clang-format off 193 | #define SEESAW_HW_ID_CODE_SAMD09 0x55 ///< seesaw HW ID code for SAMD09 194 | #define SEESAW_HW_ID_CODE_TINY806 0x84 ///< seesaw HW ID code for ATtiny806 195 | #define SEESAW_HW_ID_CODE_TINY807 0x85 ///< seesaw HW ID code for ATtiny807 196 | #define SEESAW_HW_ID_CODE_TINY816 0x86 ///< seesaw HW ID code for ATtiny816 197 | #define SEESAW_HW_ID_CODE_TINY817 0x87 ///< seesaw HW ID code for ATtiny817 198 | #define SEESAW_HW_ID_CODE_TINY1616 0x88 ///< seesaw HW ID code for ATtiny1616 199 | #define SEESAW_HW_ID_CODE_TINY1617 0x89 ///< seesaw HW ID code for ATtiny1617 200 | // clang-format on 201 | 202 | /** raw key event stucture for keypad module */ 203 | union keyEventRaw { 204 | struct { 205 | uint8_t EDGE : 2; ///< the edge that was triggered 206 | uint8_t NUM : 6; ///< the event number 207 | } bit; ///< bitfield format 208 | uint8_t reg; ///< register format 209 | }; 210 | 211 | /** extended key event stucture for keypad module */ 212 | union keyEvent { 213 | struct { 214 | uint8_t EDGE : 2; ///< the edge that was triggered 215 | uint16_t NUM : 14; ///< the event number 216 | } bit; ///< bitfield format 217 | uint16_t reg; ///< register format 218 | }; 219 | 220 | /** key state struct that will be written to seesaw chip keypad module */ 221 | union keyState { 222 | struct { 223 | uint8_t STATE : 1; ///< the current state of the key 224 | uint8_t ACTIVE : 4; ///< the registered events for that key 225 | } bit; ///< bitfield format 226 | uint8_t reg; ///< register format 227 | }; 228 | 229 | /**************************************************************************/ 230 | /*! 231 | @brief Class that stores state and functions for interacting with seesaw 232 | helper IC 233 | */ 234 | /**************************************************************************/ 235 | class Adafruit_seesaw : public Print { 236 | public: 237 | // constructors 238 | Adafruit_seesaw(TwoWire *Wi = NULL); 239 | ~Adafruit_seesaw(void){}; 240 | 241 | bool begin(uint8_t addr = SEESAW_ADDRESS, int8_t flow = -1, 242 | bool reset = true); 243 | uint32_t getOptions(); 244 | uint32_t getVersion(); 245 | bool getProdDatecode(uint16_t *pid, uint8_t *year, uint8_t *mon, 246 | uint8_t *day); 247 | 248 | bool SWReset(); 249 | 250 | void pinMode(uint8_t pin, uint8_t mode); 251 | void pinModeBulk(uint32_t pins, uint8_t mode); 252 | void pinModeBulk(uint32_t pinsa, uint32_t pinsb, uint8_t mode); 253 | virtual void analogWrite(uint8_t pin, uint16_t value, uint8_t width = 8); 254 | void digitalWrite(uint8_t pin, uint8_t value); 255 | void digitalWriteBulk(uint32_t port_values); 256 | void digitalWriteBulk(uint32_t pins, uint8_t value); 257 | void digitalWriteBulk(uint32_t pinsa, uint32_t pinsb, uint8_t value); 258 | 259 | bool digitalRead(uint8_t pin); 260 | uint32_t digitalReadBulk(uint32_t pins); 261 | uint32_t digitalReadBulkB(uint32_t pins); 262 | 263 | void setGPIOInterrupts(uint32_t pins, bool enabled); 264 | 265 | virtual uint16_t analogRead(uint8_t pin); 266 | 267 | uint16_t touchRead(uint8_t pin); 268 | 269 | virtual void setPWMFreq(uint8_t pin, uint16_t freq); 270 | 271 | void enableSercomDataRdyInterrupt(uint8_t sercom = 0); 272 | void disableSercomDataRdyInterrupt(uint8_t sercom = 0); 273 | 274 | char readSercomData(uint8_t sercom = 0); 275 | 276 | void EEPROMWrite8(uint8_t addr, uint8_t val); 277 | void EEPROMWrite(uint8_t addr, uint8_t *buf, uint8_t size); 278 | uint8_t EEPROMRead8(uint8_t addr); 279 | 280 | void setI2CAddr(uint8_t addr); 281 | uint8_t getI2CAddr(); 282 | 283 | void UARTSetBaud(uint32_t baud); 284 | 285 | void setKeypadEvent(uint8_t key, uint8_t edge, bool enable = true); 286 | void enableKeypadInterrupt(); 287 | void disableKeypadInterrupt(); 288 | uint8_t getKeypadCount(); 289 | bool readKeypad(keyEventRaw *buf, uint8_t count); 290 | 291 | float getTemp(); 292 | 293 | int32_t getEncoderPosition(uint8_t encoder = 0); 294 | int32_t getEncoderDelta(uint8_t encoder = 0); 295 | bool enableEncoderInterrupt(uint8_t encoder = 0); 296 | bool disableEncoderInterrupt(uint8_t encoder = 0); 297 | void setEncoderPosition(int32_t pos, uint8_t encoder = 0); 298 | 299 | virtual size_t write(uint8_t); 300 | virtual size_t write(const char *str); 301 | 302 | protected: 303 | TwoWire *_i2cbus; /*!< The I2C Bus used to communicate with the seesaw */ 304 | Adafruit_I2CDevice *_i2c_dev = NULL; ///< The BusIO device for I2C control 305 | 306 | int8_t _flow; /*!< The flow control pin to use */ 307 | 308 | uint8_t _hardwaretype = 0; /*!< what hardware type is attached! */ 309 | uint8_t getI2CaddrEEPROMloc(); 310 | 311 | bool write8(byte regHigh, byte regLow, byte value); 312 | uint8_t read8(byte regHigh, byte regLow, uint16_t delay = 250); 313 | 314 | bool read(uint8_t regHigh, uint8_t regLow, uint8_t *buf, uint8_t num, 315 | uint16_t delay = 250); 316 | bool write(uint8_t regHigh, uint8_t regLow, uint8_t *buf, uint8_t num); 317 | 318 | /*========================================================================= 319 | REGISTER BITFIELDS 320 | -----------------------------------------------------------------------*/ 321 | 322 | /** Sercom interrupt enable register 323 | */ 324 | union sercom_inten { 325 | struct { 326 | uint8_t DATA_RDY : 1; ///< this bit is set when data becomes available 327 | } bit; ///< bitfields 328 | uint8_t reg; ///< full register 329 | }; 330 | sercom_inten _sercom_inten; ///< sercom interrupt enable register instance 331 | 332 | /*=========================================================================*/ 333 | }; 334 | 335 | #endif 336 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Adafruit_Seesaw [![Build Status](https://github.com/adafruit/Adafruit_Seesaw/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_Seesaw/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit_Seesaw/html/index.html) 2 | 3 | Arduino driver for seesaw multi-use chip 4 | 5 | Check out the [documentation](https://adafruit.github.io/Adafruit_Seesaw/html/class_adafruit__seesaw.html) for a listing and explanation of the available methods! 6 | -------------------------------------------------------------------------------- /examples/Crickit/basic/basic.ino: -------------------------------------------------------------------------------- 1 | #include "Adafruit_Crickit.h" 2 | 3 | Adafruit_Crickit crickit; 4 | 5 | void setup() { 6 | Serial.begin(9600); 7 | 8 | if(!crickit.begin()){ 9 | Serial.println("ERROR!"); 10 | while(1) delay(1); 11 | } 12 | else Serial.println("seesaw started"); 13 | 14 | //set the PWM freq for all the servo pins 15 | crickit.setPWMFreq(CRICKIT_SERVO1, 50); 16 | } 17 | 18 | void loop() { 19 | 20 | //set some PWMS 21 | crickit.analogWrite(CRICKIT_SERVO1, 10000); 22 | crickit.analogWrite(CRICKIT_SERVO2, 5000); 23 | crickit.analogWrite(CRICKIT_SERVO3, 20000); 24 | crickit.analogWrite(CRICKIT_SERVO4, 45000); 25 | 26 | // read an ADC 27 | Serial.print(crickit.analogRead(CRICKIT_SIGNAL4)); 28 | Serial.print(","); 29 | 30 | // read a captouch 31 | Serial.println(crickit.touchRead(CRICKIT_TOUCH2)); 32 | 33 | delay(1); 34 | } 35 | -------------------------------------------------------------------------------- /examples/Crickit/cap_touch_demo/cap_touch_demo.ino: -------------------------------------------------------------------------------- 1 | // Adafruit Crickit Capacitive Touch Demo for Arduino 2 | // 3 | // Displays the value of Adafruit Crickit touchpad values when touched 4 | // 5 | // Tested with the Crickit + micro:bit, all good 6 | 7 | #include "Adafruit_Crickit.h" 8 | 9 | Adafruit_Crickit crickit; 10 | 11 | #define CRICKIT_NUM_TOUCH 4 12 | #define CAPTOUCH_THRESH 500 13 | 14 | void setup() { 15 | Serial.begin(9600); // Set up serial monitor - be sure it is set to 9600 16 | Serial.println("Cap Touch Demo"); 17 | if(!crickit.begin()) { // Check if Crickit is attached 18 | Serial.println("ERROR Starting crickit"); // If an error, print and 19 | while(1) ; // go to a infinite loop to stop 20 | } 21 | else Serial.println("seesaw started"); // success, we have a Crickit 22 | } 23 | 24 | void loop() { 25 | 26 | for(int i=0; i CAPTOUCH_THRESH){ // if the value read is > the threshold 30 | Serial.print("CT"); // print info to serial monitor 31 | Serial.print(i + 1); 32 | Serial.print(" touched! value: "); 33 | Serial.println(val); 34 | } 35 | } 36 | delay(100); // wait tiny bit between checks 37 | } 38 | -------------------------------------------------------------------------------- /examples/Crickit/drive/more_drivers/more_drivers.ino: -------------------------------------------------------------------------------- 1 | #include "Adafruit_Crickit.h" 2 | 3 | Adafruit_Crickit crickit; 4 | 5 | #define NUM_DRIVES 4 6 | int drives[] = {CRICKIT_DRIVE1, CRICKIT_DRIVE2, CRICKIT_DRIVE3, CRICKIT_DRIVE4}; 7 | 8 | void setup() { 9 | Serial.begin(115200); 10 | Serial.println("4 Drive demo!"); 11 | 12 | if(!crickit.begin()){ 13 | Serial.println("ERROR!"); 14 | while(1) delay(1); 15 | } 16 | else Serial.println("Crickit started"); 17 | 18 | //our default frequency is 1khz 19 | for(int i=0; i CAPTOUCH_THRESH){ 75 | crickit.analogWrite(crickit_drive[i], (1UL << 16) - 1); 76 | Serial.print("CT"); 77 | Serial.print(i + 1); 78 | Serial.print(" touched! value: "); 79 | Serial.println(val); 80 | } 81 | else 82 | crickit.analogWrite(crickit_drive[i], 0); 83 | } 84 | 85 | #ifdef USE_NEOPIX 86 | for(uint16_t i=0; iwrite(1000); 94 | } 95 | delay(500); 96 | 97 | #ifdef USE_NEOPIX 98 | for(uint16_t i=0; iwrite(2000); 106 | } 107 | delay(500); 108 | } 109 | -------------------------------------------------------------------------------- /examples/Crickit/motor/dual_motor/dual_motor.ino: -------------------------------------------------------------------------------- 1 | #include "Adafruit_Crickit.h" 2 | #include "seesaw_motor.h" 3 | 4 | Adafruit_Crickit crickit; 5 | 6 | seesaw_Motor motor_a(&crickit); 7 | seesaw_Motor motor_b(&crickit); 8 | 9 | void setup() { 10 | Serial.begin(115200); 11 | Serial.println("Dual motor demo!"); 12 | 13 | if(!crickit.begin()){ 14 | Serial.println("ERROR!"); 15 | while(1) delay(1); 16 | } 17 | else Serial.println("Crickit started"); 18 | 19 | //attach motor a 20 | motor_a.attach(CRICKIT_MOTOR_A1, CRICKIT_MOTOR_A2); 21 | 22 | //attach motor b 23 | motor_b.attach(CRICKIT_MOTOR_B1, CRICKIT_MOTOR_B2); 24 | } 25 | 26 | void loop() { 27 | motor_a.throttle(1); 28 | motor_b.throttle(-1); 29 | delay(1000); 30 | 31 | motor_a.throttle(.5); 32 | motor_b.throttle(-.5); 33 | delay(1000); 34 | 35 | motor_a.throttle(0); 36 | motor_b.throttle(0); 37 | delay(1000); 38 | 39 | motor_a.throttle(-.5); 40 | motor_b.throttle(.5); 41 | delay(1000); 42 | 43 | motor_a.throttle(-1); 44 | motor_b.throttle(1); 45 | delay(1000); 46 | 47 | motor_a.throttle(0); 48 | motor_b.throttle(0); 49 | delay(500); 50 | } 51 | 52 | -------------------------------------------------------------------------------- /examples/Crickit/servo/more_servos/more_servos.ino: -------------------------------------------------------------------------------- 1 | #include "Adafruit_Crickit.h" 2 | #include "seesaw_servo.h" 3 | 4 | Adafruit_Crickit crickit; 5 | 6 | #define NUM_SERVOS 4 7 | 8 | //create an array of 4 servos with our crickit object 9 | seesaw_Servo servos[] = { seesaw_Servo(&crickit), 10 | seesaw_Servo(&crickit), 11 | seesaw_Servo(&crickit), 12 | seesaw_Servo(&crickit) }; 13 | 14 | //these are the pins they will be attached to 15 | int servoPins[] = { CRICKIT_SERVO1, CRICKIT_SERVO2, CRICKIT_SERVO3, CRICKIT_SERVO4 }; 16 | 17 | void setup() { 18 | Serial.begin(115200); 19 | 20 | //begin the crickit 21 | if(!crickit.begin()){ 22 | Serial.println("ERROR!"); 23 | while(1) delay(1); 24 | } 25 | else Serial.println("Crickit started"); 26 | 27 | //attach the servos to their pins 28 | for(int i=0; i 7 | 8 | #define DEFAULT_I2C_ADDR 0x3A 9 | 10 | #define SWITCH1 18 // PA01 11 | #define SWITCH2 19 // PA02 12 | #define SWITCH3 20 // PA03 13 | #define SWITCH4 2 // PA06 14 | #define PWM1 12 // PC00 15 | #define PWM2 13 // PC01 16 | #define PWM3 0 // PA04 17 | #define PWM4 1 // PA05 18 | 19 | 20 | Adafruit_seesaw ss; 21 | 22 | void setup() { 23 | Serial.begin(115200); 24 | 25 | while (!Serial) delay(10); // wait until serial port is opened 26 | 27 | Serial.println(F("Adafruit PID 5296 I2C QT 4x LED Arcade Buttons test!")); 28 | 29 | if (!ss.begin(DEFAULT_I2C_ADDR)) { 30 | Serial.println(F("seesaw not found!")); 31 | while(1) delay(10); 32 | } 33 | 34 | uint16_t pid; 35 | uint8_t year, mon, day; 36 | 37 | ss.getProdDatecode(&pid, &year, &mon, &day); 38 | Serial.print("seesaw found PID: "); 39 | Serial.print(pid); 40 | Serial.print(" datecode: "); 41 | Serial.print(2000+year); Serial.print("/"); 42 | Serial.print(mon); Serial.print("/"); 43 | Serial.println(day); 44 | 45 | if (pid != 5296) { 46 | Serial.println(F("Wrong seesaw PID")); 47 | while (1) delay(10); 48 | } 49 | 50 | Serial.println(F("seesaw started OK!")); 51 | ss.pinMode(SWITCH1, INPUT_PULLUP); 52 | ss.pinMode(SWITCH2, INPUT_PULLUP); 53 | ss.pinMode(SWITCH3, INPUT_PULLUP); 54 | ss.pinMode(SWITCH4, INPUT_PULLUP); 55 | ss.analogWrite(PWM1, 127); 56 | ss.analogWrite(PWM2, 127); 57 | ss.analogWrite(PWM3, 127); 58 | ss.analogWrite(PWM4, 127); 59 | } 60 | 61 | uint8_t incr = 0; 62 | 63 | void loop() { 64 | if (! ss.digitalRead(SWITCH1)) { 65 | Serial.println("Switch 1 pressed"); 66 | ss.analogWrite(PWM1, incr); 67 | incr += 5; 68 | } else { 69 | ss.analogWrite(PWM1, 0); 70 | } 71 | 72 | if (! ss.digitalRead(SWITCH2)) { 73 | Serial.println("Switch 2 pressed"); 74 | ss.analogWrite(PWM2, incr); 75 | incr += 5; 76 | } else { 77 | ss.analogWrite(PWM2, 0); 78 | } 79 | 80 | if (! ss.digitalRead(SWITCH3)) { 81 | Serial.println("Switch 3 pressed"); 82 | ss.analogWrite(PWM3, incr); 83 | incr += 5; 84 | } else { 85 | ss.analogWrite(PWM3, 0); 86 | } 87 | 88 | if (! ss.digitalRead(SWITCH4)) { 89 | Serial.println("Switch 4 pressed"); 90 | ss.analogWrite(PWM4, incr); 91 | incr += 5; 92 | } else { 93 | ss.analogWrite(PWM4, 0); 94 | } 95 | delay(10); 96 | } 97 | -------------------------------------------------------------------------------- /examples/Mini_I2C_Gamepad_QT/Mini_I2C_Gamepad_QT.ino: -------------------------------------------------------------------------------- 1 | #include "Adafruit_seesaw.h" 2 | 3 | Adafruit_seesaw ss; 4 | 5 | #define BUTTON_X 6 6 | #define BUTTON_Y 2 7 | #define BUTTON_A 5 8 | #define BUTTON_B 1 9 | #define BUTTON_SELECT 0 10 | #define BUTTON_START 16 11 | uint32_t button_mask = (1UL << BUTTON_X) | (1UL << BUTTON_Y) | (1UL << BUTTON_START) | 12 | (1UL << BUTTON_A) | (1UL << BUTTON_B) | (1UL << BUTTON_SELECT); 13 | 14 | //#define IRQ_PIN 5 15 | 16 | 17 | void setup() { 18 | Serial.begin(115200); 19 | 20 | while(!Serial) { 21 | delay(10); 22 | } 23 | 24 | Serial.println("Gamepad QT example!"); 25 | 26 | if(!ss.begin(0x50)){ 27 | Serial.println("ERROR! seesaw not found"); 28 | while(1) delay(1); 29 | } 30 | Serial.println("seesaw started"); 31 | uint32_t version = ((ss.getVersion() >> 16) & 0xFFFF); 32 | if (version != 5743) { 33 | Serial.print("Wrong firmware loaded? "); 34 | Serial.println(version); 35 | while(1) delay(10); 36 | } 37 | Serial.println("Found Product 5743"); 38 | 39 | ss.pinModeBulk(button_mask, INPUT_PULLUP); 40 | ss.setGPIOInterrupts(button_mask, 1); 41 | 42 | #if defined(IRQ_PIN) 43 | pinMode(IRQ_PIN, INPUT); 44 | #endif 45 | } 46 | 47 | 48 | int last_x = 0, last_y = 0; 49 | 50 | void loop() { 51 | delay(10); // delay in loop to slow serial output 52 | 53 | // Reverse x/y values to match joystick orientation 54 | int x = 1023 - ss.analogRead(14); 55 | int y = 1023 - ss.analogRead(15); 56 | 57 | if ( (abs(x - last_x) > 3) || (abs(y - last_y) > 3)) { 58 | Serial.print("x: "); Serial.print(x); Serial.print(", "); Serial.print("y: "); Serial.println(y); 59 | last_x = x; 60 | last_y = y; 61 | } 62 | 63 | #if defined(IRQ_PIN) 64 | if(!digitalRead(IRQ_PIN)) { 65 | return; 66 | } 67 | #endif 68 | 69 | uint32_t buttons = ss.digitalReadBulk(button_mask); 70 | 71 | //Serial.println(buttons, BIN); 72 | 73 | if (! (buttons & (1UL << BUTTON_A))) { 74 | Serial.println("Button A pressed"); 75 | } 76 | if (! (buttons & (1UL << BUTTON_B))) { 77 | Serial.println("Button B pressed"); 78 | } 79 | if (! (buttons & (1UL << BUTTON_Y))) { 80 | Serial.println("Button Y pressed"); 81 | } 82 | if (! (buttons & (1UL << BUTTON_X))) { 83 | Serial.println("Button X pressed"); 84 | } 85 | if (! (buttons & (1UL << BUTTON_SELECT))) { 86 | Serial.println("Button SELECT pressed"); 87 | } 88 | if (! (buttons & (1UL << BUTTON_START))) { 89 | Serial.println("Button START pressed"); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /examples/NeoKey_1x4/basic/basic.ino: -------------------------------------------------------------------------------- 1 | #include "Adafruit_NeoKey_1x4.h" 2 | #include "seesaw_neopixel.h" 3 | 4 | Adafruit_NeoKey_1x4 neokey; // Create the NeoKey object 5 | 6 | void setup() { 7 | Serial.begin(115200); 8 | while (! Serial) delay(10); 9 | 10 | if (! neokey.begin(0x30)) { // begin with I2C address, default is 0x30 11 | Serial.println("Could not start NeoKey, check wiring?"); 12 | while(1) delay(10); 13 | } 14 | 15 | Serial.println("NeoKey started!"); 16 | 17 | // Pulse all the LEDs on to show we're working 18 | for (uint16_t i=0; i 2 | #define PIN 10 3 | 4 | // Parameter 1 = number of pixels in strip 5 | // Parameter 2 = Arduino pin number (most are valid) 6 | // Parameter 3 = pixel type flags, add together as needed: 7 | // NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) 8 | // NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) 9 | // NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) 10 | // NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) 11 | // NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products) 12 | seesaw_NeoPixel strip = seesaw_NeoPixel(12, PIN, NEO_GRB + NEO_KHZ800); 13 | 14 | // IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across 15 | // pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input 16 | // and minimize distance between Arduino and first pixel. Avoid connecting 17 | // on a live circuit...if you must, connect GND first. 18 | 19 | void setup() { 20 | Serial.begin(115200); 21 | 22 | while (!Serial) delay(10); // wait until serial port is opened 23 | 24 | if(!strip.begin()){ 25 | Serial.println("seesaw not found!"); 26 | while(1) delay(10); 27 | } 28 | 29 | Serial.println(F("seesaw started OK!")); 30 | 31 | strip.show(); // Initialize all pixels to 'off' 32 | } 33 | 34 | void loop() { 35 | // Some example procedures showing how to display to the pixels: 36 | colorWipe(strip.Color(255, 0, 0), 50); // Red 37 | colorWipe(strip.Color(0, 255, 0), 50); // Green 38 | colorWipe(strip.Color(0, 0, 255), 50); // Blue 39 | //colorWipe(strip.Color(0, 0, 0, 255), 50); // White RGBW 40 | // Send a theater pixel chase in... 41 | theaterChase(strip.Color(127, 127, 127), 50); // White 42 | theaterChase(strip.Color(127, 0, 0), 50); // Red 43 | theaterChase(strip.Color(0, 0, 127), 50); // Blue 44 | 45 | rainbow(20); 46 | rainbowCycle(20); 47 | theaterChaseRainbow(50); 48 | } 49 | 50 | // Fill the dots one after the other with a color 51 | void colorWipe(uint32_t c, uint8_t wait) { 52 | for(uint16_t i=0; i 10 | 11 | #define DEFAULT_I2C_ADDR 0x30 12 | #define ANALOGIN 18 13 | #define NEOPIXELOUT 14 14 | 15 | Adafruit_seesaw seesaw1; 16 | Adafruit_seesaw seesaw2; 17 | seesaw_NeoPixel pixels1 = seesaw_NeoPixel(4, NEOPIXELOUT, NEO_GRB + NEO_KHZ800); 18 | seesaw_NeoPixel pixels2 = seesaw_NeoPixel(4, NEOPIXELOUT, NEO_GRB + NEO_KHZ800); 19 | 20 | void setup() { 21 | Serial.begin(115200); 22 | 23 | //while (!Serial) delay(10); // wait until serial port is opened 24 | 25 | Serial.println(F("Adafruit PID 5295 I2C QT Slide Potentiometer test!")); 26 | 27 | if (!seesaw1.begin(DEFAULT_I2C_ADDR) || !seesaw2.begin(DEFAULT_I2C_ADDR+1)) { 28 | Serial.println(F("seesaws not found!")); 29 | while(1) delay(10); 30 | } 31 | 32 | uint16_t pid; 33 | uint8_t year, mon, day; 34 | 35 | seesaw1.getProdDatecode(&pid, &year, &mon, &day); 36 | Serial.print("seesaw found PID: "); 37 | Serial.print(pid); 38 | Serial.print(" datecode: "); 39 | Serial.print(2000+year); Serial.print("/"); 40 | Serial.print(mon); Serial.print("/"); 41 | Serial.println(day); 42 | 43 | if (pid != 5295) { 44 | Serial.println(F("Wrong seesaw PID")); 45 | while (1) delay(10); 46 | } 47 | 48 | if (!pixels1.begin(DEFAULT_I2C_ADDR) || !pixels2.begin(DEFAULT_I2C_ADDR+1)){ 49 | Serial.println("seesaw pixels not found!"); 50 | while(1) delay(10); 51 | } 52 | 53 | Serial.println(F("seesaw started OK!")); 54 | 55 | pixels1.setBrightness(255); // half bright 56 | pixels2.setBrightness(255); // half bright 57 | pixels1.show(); // Initialize all pixels to 'off' 58 | pixels2.show(); // Initialize all pixels to 'off' 59 | } 60 | 61 | 62 | 63 | void loop() { 64 | // read the potentiometer 65 | uint16_t slide1_val = seesaw1.analogRead(ANALOGIN); 66 | uint16_t slide2_val = seesaw2.analogRead(ANALOGIN); 67 | Serial.print(slide1_val); 68 | Serial.print(", "); 69 | Serial.println(slide2_val); 70 | 71 | for (uint8_t i=0; i< pixels1.numPixels(); i++) { 72 | pixels1.setPixelColor(i, Wheel(slide1_val / 4)); 73 | pixels2.setPixelColor(i, Wheel(slide2_val / 4)); 74 | } 75 | pixels1.show(); 76 | pixels2.show(); 77 | 78 | delay(50); 79 | } 80 | 81 | 82 | 83 | // Input a value 0 to 255 to get a color value. 84 | // The colours are a transition r - g - b - back to r. 85 | uint32_t Wheel(byte WheelPos) { 86 | WheelPos = 255 - WheelPos; 87 | if(WheelPos < 85) { 88 | return seesaw_NeoPixel::Color(255 - WheelPos * 3, 0, WheelPos * 3); 89 | } 90 | if(WheelPos < 170) { 91 | WheelPos -= 85; 92 | return seesaw_NeoPixel::Color(0, WheelPos * 3, 255 - WheelPos * 3); 93 | } 94 | WheelPos -= 170; 95 | return seesaw_NeoPixel::Color(WheelPos * 3, 255 - WheelPos * 3, 0); 96 | } 97 | -------------------------------------------------------------------------------- /examples/NeoSlider/NeoSlider/NeoSlider.ino: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries 2 | // SPDX-License-Identifier: MIT 3 | /* 4 | * This example shows how read the potentiometer on the I2C QT Slide Potentiometer 5 | * and make the NeoPixels change too! 6 | */ 7 | 8 | #include "Adafruit_seesaw.h" 9 | #include 10 | 11 | #define DEFAULT_I2C_ADDR 0x30 12 | #define ANALOGIN 18 13 | #define NEOPIXELOUT 14 14 | 15 | Adafruit_seesaw seesaw; 16 | seesaw_NeoPixel pixels = seesaw_NeoPixel(4, NEOPIXELOUT, NEO_GRB + NEO_KHZ800); 17 | 18 | void setup() { 19 | Serial.begin(115200); 20 | 21 | //while (!Serial) delay(10); // wait until serial port is opened 22 | 23 | Serial.println(F("Adafruit PID 5295 I2C QT Slide Potentiometer test!")); 24 | 25 | if (!seesaw.begin(DEFAULT_I2C_ADDR)) { 26 | Serial.println(F("seesaw not found!")); 27 | while(1) delay(10); 28 | } 29 | 30 | uint16_t pid; 31 | uint8_t year, mon, day; 32 | 33 | seesaw.getProdDatecode(&pid, &year, &mon, &day); 34 | Serial.print("seesaw found PID: "); 35 | Serial.print(pid); 36 | Serial.print(" datecode: "); 37 | Serial.print(2000+year); Serial.print("/"); 38 | Serial.print(mon); Serial.print("/"); 39 | Serial.println(day); 40 | 41 | if (pid != 5295) { 42 | Serial.println(F("Wrong seesaw PID")); 43 | while (1) delay(10); 44 | } 45 | 46 | if (!pixels.begin(DEFAULT_I2C_ADDR)){ 47 | Serial.println("seesaw pixels not found!"); 48 | while(1) delay(10); 49 | } 50 | 51 | Serial.println(F("seesaw started OK!")); 52 | 53 | pixels.setBrightness(255); // half bright 54 | pixels.show(); // Initialize all pixels to 'off' 55 | } 56 | 57 | 58 | 59 | void loop() { 60 | // read the potentiometer 61 | uint16_t slide_val = seesaw.analogRead(ANALOGIN); 62 | Serial.println(slide_val); 63 | 64 | for (uint8_t i=0; i< pixels.numPixels(); i++) { 65 | pixels.setPixelColor(i, Wheel(slide_val / 4)); 66 | } 67 | pixels.show(); 68 | 69 | delay(50); 70 | } 71 | 72 | 73 | 74 | // Input a value 0 to 255 to get a color value. 75 | // The colours are a transition r - g - b - back to r. 76 | uint32_t Wheel(byte WheelPos) { 77 | WheelPos = 255 - WheelPos; 78 | if(WheelPos < 85) { 79 | return seesaw_NeoPixel::Color(255 - WheelPos * 3, 0, WheelPos * 3); 80 | } 81 | if(WheelPos < 170) { 82 | WheelPos -= 85; 83 | return seesaw_NeoPixel::Color(0, WheelPos * 3, 255 - WheelPos * 3); 84 | } 85 | WheelPos -= 170; 86 | return seesaw_NeoPixel::Color(WheelPos * 3, 255 - WheelPos * 3, 0); 87 | } 88 | -------------------------------------------------------------------------------- /examples/NeoTrellis/basic/basic.ino: -------------------------------------------------------------------------------- 1 | /* This example shows basic usage of the NeoTrellis. 2 | The buttons will light up various colors when pressed. 3 | The interrupt pin is not used in this example. 4 | */ 5 | 6 | #include "Adafruit_NeoTrellis.h" 7 | 8 | Adafruit_NeoTrellis trellis; 9 | 10 | //define a callback for key presses 11 | TrellisCallback blink(keyEvent evt){ 12 | // Check is the pad pressed? 13 | if (evt.bit.EDGE == SEESAW_KEYPAD_EDGE_RISING) { 14 | trellis.pixels.setPixelColor(evt.bit.NUM, Wheel(map(evt.bit.NUM, 0, trellis.pixels.numPixels(), 0, 255))); //on rising 15 | } else if (evt.bit.EDGE == SEESAW_KEYPAD_EDGE_FALLING) { 16 | // or is the pad released? 17 | trellis.pixels.setPixelColor(evt.bit.NUM, 0); //off falling 18 | } 19 | 20 | // Turn on/off the neopixels! 21 | trellis.pixels.show(); 22 | 23 | return 0; 24 | } 25 | 26 | void setup() { 27 | Serial.begin(9600); 28 | // while(!Serial) delay(1); 29 | 30 | if (!trellis.begin()) { 31 | Serial.println("Could not start trellis, check wiring?"); 32 | while(1) delay(1); 33 | } else { 34 | Serial.println("NeoPixel Trellis started"); 35 | } 36 | 37 | //activate all keys and set callbacks 38 | for(int i=0; i -1){ 120 | update = true; 121 | 122 | //push all points out from the center 123 | point *p = ripples[i].points; 124 | 125 | p[0].x += RIPPLE_RATE; 126 | 127 | p[1].x += RIPPLE_RATE/2; 128 | p[1].y += RIPPLE_RATE/2; 129 | 130 | p[2].y += RIPPLE_RATE; 131 | 132 | p[3].x -= RIPPLE_RATE/2; 133 | p[3].y += RIPPLE_RATE/2; 134 | 135 | p[4].x -= RIPPLE_RATE; 136 | 137 | p[5].x -= RIPPLE_RATE/2; 138 | p[5].y -= RIPPLE_RATE/2; 139 | 140 | p[6].y -= RIPPLE_RATE; 141 | 142 | p[7].x += RIPPLE_RATE/2; 143 | p[7].y -= RIPPLE_RATE/2; 144 | 145 | for(int j=0; j= 0 && y < 4 && y >= 0){ 149 | byte red = min(255, matrix[x][y].bit.red + ripples[i].c.bit.red); 150 | byte green = min(255, matrix[x][y].bit.green + ripples[i].c.bit.green); 151 | byte blue = min(255, matrix[x][y].bit.blue + ripples[i].c.bit.blue); 152 | matrix[x][y].bit.red = red; 153 | matrix[x][y].bit.green = green; 154 | matrix[x][y].bit.blue = blue; 155 | } 156 | } 157 | 158 | 159 | ripples[i].t++; 160 | if(ripples[i].t >= FALLOFF_TIME) ripples[i].center = -1; 161 | } 162 | } 163 | 164 | if(update){ 165 | for(int x=0; x<4; x++){ 166 | for(int y=0; y<4; y++) 167 | trellis.pixels.setPixelColor(MATRIX_POINT(x,y), matrix[x][y].reg); 168 | } 169 | 170 | trellis.pixels.show(); 171 | } 172 | } 173 | 174 | void loop() { 175 | if(!digitalRead(INT_PIN)){ 176 | trellis.read(false); 177 | } 178 | processRipples(); 179 | delay(20); 180 | } 181 | -------------------------------------------------------------------------------- /examples/PC_Joystick/PC_Joystick.ino: -------------------------------------------------------------------------------- 1 | #include "Adafruit_seesaw.h" 2 | 3 | // creates seesaw on I2C0 port 4 | Adafruit_seesaw ss = Adafruit_seesaw(&Wire); 5 | // uncomment this for using I2C1, such as STEMMA port on QT Py RP2040 6 | // Adafruit_seesaw ss = Adafruit_seesaw(&Wire1); 7 | 8 | #define BUTTON_1 3 9 | #define BUTTON_2 13 10 | #define BUTTON_3 2 11 | #define BUTTON_4 14 12 | uint32_t button_mask = (1UL << BUTTON_1) | (1UL << BUTTON_2) | 13 | (1UL << BUTTON_3) | (1UL << BUTTON_4); 14 | #define JOY1_X 1 15 | #define JOY1_Y 15 16 | #define JOY2_X 0 17 | #define JOY2_Y 16 18 | 19 | //#define IRQ_PIN 5 20 | 21 | void setup() { 22 | Serial.begin(115200); 23 | 24 | while(!Serial) { 25 | delay(10); 26 | } 27 | 28 | Serial.println("PC Joystick QT example!"); 29 | ss.begin(0x49); 30 | Serial.println("seesaw started"); 31 | uint32_t version = ((ss.getVersion() >> 16) & 0xFFFF); 32 | if (version != 5753) { 33 | Serial.print("Wrong firmware loaded? "); 34 | Serial.println(version); 35 | while(1) delay(10); 36 | } 37 | Serial.println("Found Product 5753"); 38 | 39 | ss.pinModeBulk(button_mask, INPUT_PULLUP); 40 | ss.setGPIOInterrupts(button_mask, 1); 41 | 42 | #if defined(IRQ_PIN) 43 | pinMode(IRQ_PIN, INPUT); 44 | #endif 45 | } 46 | 47 | float last_x = 0, last_y = 0; 48 | 49 | void loop() { 50 | delay(10); // delay in loop to slow serial output 51 | 52 | float x = 0, y = 0; 53 | // These joysticks are really jittery so lets take 4 samples of each axis 54 | for (int s=0; s<4; s++) { 55 | x += ss.analogRead(JOY1_X); 56 | y += ss.analogRead(JOY1_Y); 57 | } 58 | x /= 4.0; // Take the average of the 4 samples 59 | y /= 4.0; 60 | // PC joysticks aren't "true" voltage divider, because we have a fixed 10K 61 | // we dont know the 'normalized' value so we're just going to give you 62 | // the result in 'Kohms' for easier printing 63 | x = (1024.0/(float)x - 1); 64 | y = (1024.0/(float)y - 1); 65 | 66 | if ( (fabs(x - last_x) > 0.1) || (fabs(y - last_y) > 0.1)) { 67 | Serial.print(x); Serial.print(", "); Serial.println(y); 68 | last_x = x; 69 | last_y = y; 70 | } 71 | 72 | #if defined(IRQ_PIN) 73 | if(!digitalRead(IRQ_PIN)) { 74 | return; 75 | } 76 | #endif 77 | 78 | uint32_t buttons = ss.digitalReadBulk(button_mask); 79 | //Serial.println(buttons, BIN); 80 | 81 | if (! (buttons & (1UL << BUTTON_1))) { 82 | Serial.println("Button 1 pressed"); 83 | } 84 | if (! (buttons & (1UL << BUTTON_2))) { 85 | Serial.println("Button 2 pressed"); 86 | } 87 | if (! (buttons & (1UL << BUTTON_3))) { 88 | Serial.println("Button 3 pressed"); 89 | } 90 | if (! (buttons & (1UL << BUTTON_4))) { 91 | Serial.println("Button 4 pressed"); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /examples/analog/Fade/Fade.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Fade 3 | 4 | This example shows how to fade an LED on pin 6 of a seesaw board using the analogWrite() 5 | function. 6 | 7 | The analogWrite() function uses PWM, so if you want to change the pin you're 8 | using, be sure to use another PWM capable pin. 9 | On the SAMD09 breakout these are pins 5, 6, and 7 10 | On the ATtinyxy7 breakout these are pins 0, 1, 9, 12, 13 11 | On the ATtinyxy6 breakout these are pins 0, 1, 7, 11, 16 12 | */ 13 | 14 | #include "Adafruit_seesaw.h" 15 | 16 | Adafruit_seesaw ss; 17 | 18 | int led = 6; // the PWM pin the LED is attached to 19 | int brightness = 0; // how bright the LED is 20 | int fadeAmount = 5; // how many points to fade the LED by 21 | 22 | // the setup routine runs once when you press reset: 23 | void setup() { 24 | Serial.begin(115200); 25 | 26 | while (!Serial) delay(10); // wait until serial port is opened 27 | 28 | if(!ss.begin()){ 29 | Serial.println("seesaw not found!"); 30 | while(1) delay(10); 31 | } 32 | } 33 | 34 | // the loop routine runs over and over again forever: 35 | void loop() { 36 | // set the brightness of the LED: 37 | ss.analogWrite(led, brightness); 38 | 39 | // change the brightness for next time through the loop: 40 | brightness = brightness + fadeAmount; 41 | 42 | // reverse the direction of the fading at the ends of the fade: 43 | if (brightness <= 0 || brightness >= 255) { 44 | fadeAmount = -fadeAmount; 45 | } 46 | // wait for 30 milliseconds to see the dimming effect 47 | delay(30); 48 | } 49 | -------------------------------------------------------------------------------- /examples/analog/analogRead/analogRead.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This example shows how read the ADC on a seesaw. 3 | * The default ADC pins on the SAMD09 Breakout are 2, 3, and 4. 4 | */ 5 | 6 | #include "Adafruit_seesaw.h" 7 | 8 | Adafruit_seesaw ss; 9 | // on SAMD09, analog in can be 2, 3, or 4 10 | // on Attinyxy7, analog in can be 0-3, 6, 7, 18-20 11 | // on Attinyxy6, analog in can be 0-5, 14-16 12 | #define ANALOGIN 2 13 | 14 | void setup() { 15 | Serial.begin(115200); 16 | 17 | while (!Serial) delay(10); // wait until serial port is opened 18 | 19 | if(!ss.begin()){ 20 | Serial.println(F("seesaw not found!")); 21 | while(1) delay(10); 22 | } 23 | 24 | Serial.println(F("seesaw started OK!")); 25 | } 26 | 27 | void loop() { 28 | Serial.println(ss.analogRead(ANALOGIN)); 29 | delay(50); 30 | } 31 | -------------------------------------------------------------------------------- /examples/audio_spectrum/Audio_Spectrum/Audio_Spectrum.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Audio Spectrum. 3 | 4 | This example shows how to set the audio sampling rate and read 5 | audio spectrum data from a compatible Seesaw device. 6 | */ 7 | 8 | #include 9 | 10 | seesaw_Audio_Spectrum ss; 11 | 12 | // The setup routine runs once when you press reset: 13 | void setup() { 14 | Serial.begin(115200); 15 | 16 | while (!Serial) delay(10); // wait until serial port is opened 17 | Serial.println("A"); 18 | 19 | if (!ss.begin()) { 20 | Serial.println("seesaw not found!"); 21 | while(1) delay(10); 22 | } 23 | Serial.println("B"); 24 | 25 | // Configure audio sampling rate, which determines the peak 26 | // frequency of the spectrum output. There are 32 possible values 27 | // (0-31), where lower numbers = higher frequency. 28 | // The corresponding frequency for each setting will depend on the 29 | // F_CPU frequency on the Seesaw device, which has not yet been 30 | // determined. 10 or 20 MHz would be ideal, but others may happen, 31 | // so specific numbers are not documented here yet. 32 | // If 10 or 20 MHz, value of 12 here maps to 6250 Hz: 33 | ss.setRate(12); 34 | } 35 | 36 | // The loop routine runs over and over again forever: 37 | void loop() { 38 | ss.getData(); // Pull audio spectrum data from device 39 | // Print contents of each of the 64 spectrum bins... 40 | for (uint8_t i=0; i<64; i++) { 41 | Serial.print(ss.getLevel(i)); 42 | Serial.write(' '); 43 | } 44 | Serial.println(); 45 | } 46 | -------------------------------------------------------------------------------- /examples/communication/UART_loopback/UART_loopback.ino: -------------------------------------------------------------------------------- 1 | //This example takes UART data given to the seesaw, reads it and then loops it back 2 | 3 | #include "Adafruit_seesaw.h" 4 | 5 | Adafruit_seesaw ss; 6 | 7 | void setup() 8 | { 9 | Serial.begin(9600); 10 | 11 | if(!ss.begin()){ 12 | Serial.println("ERROR!"); 13 | while(1) delay(1); 14 | } 15 | else Serial.println("seesaw started"); 16 | 17 | //enable interrupt 18 | ss.enableSercomDataRdyInterrupt(); 19 | } 20 | 21 | void loop() 22 | { 23 | if(!digitalRead(3)){ 24 | char c = ss.readSercomData(); 25 | Serial.print(c); //print to arduino console 26 | 27 | //delay after reading data 28 | delayMicroseconds(100); 29 | ss.print(c); //send back to the seesaw to print 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/digital/attiny_blink/attiny_blink.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This example shows how to blink a pin on a seesaw. 3 | * It is written to use the built-in LED on the ATtiny817 breakout with seesaw. 4 | */ 5 | 6 | #include "Adafruit_seesaw.h" 7 | 8 | Adafruit_seesaw ss; 9 | 10 | #define BLINK_PIN 5 11 | 12 | void setup() { 13 | Serial.begin(115200); 14 | 15 | while (!Serial) delay(10); // wait until serial port is opened 16 | 17 | if(!ss.begin()){ 18 | Serial.println("seesaw not found!"); 19 | while(1) delay(10); 20 | } 21 | 22 | Serial.println(F("seesaw started OK!")); 23 | 24 | ss.pinMode(BLINK_PIN, OUTPUT); 25 | } 26 | 27 | void loop() { 28 | ss.digitalWrite(BLINK_PIN, LOW); // turn the LED on (the LED is tied low) 29 | delay(1000); // wait for a second 30 | ss.digitalWrite(BLINK_PIN, HIGH); // turn the LED off 31 | delay(1000); 32 | } 33 | -------------------------------------------------------------------------------- /examples/digital/blink/blink.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This example shows how to blink a pin on a seesaw. 3 | * Attach the positive (longer lead) of the LED to pin 15 on the seesaw, and 4 | * the negative lead of the LED to ground through a 1k ohm resistor. 5 | */ 6 | 7 | #include "Adafruit_seesaw.h" 8 | 9 | Adafruit_seesaw ss; 10 | 11 | #define BLINK_PIN 15 12 | 13 | void setup() { 14 | Serial.begin(115200); 15 | 16 | while (!Serial) delay(10); // wait until serial port is opened 17 | 18 | if(!ss.begin()){ 19 | Serial.println("seesaw not found!"); 20 | while(1) delay(10); 21 | } 22 | 23 | Serial.println(F("seesaw started OK!")); 24 | 25 | ss.pinMode(BLINK_PIN, OUTPUT); 26 | } 27 | 28 | void loop() { 29 | ss.digitalWrite(BLINK_PIN, HIGH); // turn the LED on (HIGH is the voltage level) 30 | delay(100); // wait for a second 31 | ss.digitalWrite(BLINK_PIN, LOW); // turn the LED off by making the voltage LOW 32 | delay(100); 33 | } 34 | -------------------------------------------------------------------------------- /examples/digital/gpio_interrupts/gpio_interrupts.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This example shows how set GPIO interrupts on a seesaw. 3 | */ 4 | 5 | #include "Adafruit_seesaw.h" 6 | 7 | //connect the interrupt pin on the seesaw (pin 8 on samd09 breakout) to this pin on your arduino 8 | #define INT_PIN 3 9 | 10 | //the interrupt will fire when this pin on the seesaw changes state 11 | #define SCAN_PIN 9 12 | 13 | Adafruit_seesaw ss; 14 | 15 | uint32_t mask = ((uint32_t)0b1 << SCAN_PIN); 16 | 17 | void setup() { 18 | Serial.begin(115200); 19 | 20 | while (!Serial) delay(10); // wait until serial port is opened 21 | 22 | if(!ss.begin()){ 23 | Serial.println(F("seesaw not found!")); 24 | while(1) delay(10); 25 | } 26 | 27 | Serial.println(F("seesaw started OK!")); 28 | 29 | pinMode(INT_PIN, INPUT_PULLUP); 30 | ss.pinModeBulk(mask, INPUT_PULLUP); 31 | ss.setGPIOInterrupts(mask, 1); 32 | } 33 | 34 | void loop() { 35 | if(!digitalRead(INT_PIN)){ 36 | Serial.print(F("Interrupt fired! pin state: ")); 37 | Serial.println(ss.digitalRead(SCAN_PIN)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/digital/multiblink/multiblink.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This example shows how to blink multiple pins at once on a seesaw. 3 | * pin 13 is attached to the LED on the samd11 xplained board 4 | */ 5 | 6 | #include "Adafruit_seesaw.h" 7 | 8 | Adafruit_seesaw ss; 9 | 10 | //blink pins PA11, PA12, PA13 11 | uint32_t mask = ((uint32_t)0b111 << 11); 12 | 13 | void setup() { 14 | Serial.begin(115200); 15 | 16 | if(!ss.begin()){ 17 | Serial.println("ERROR!"); 18 | while(1) delay(1); 19 | } 20 | else Serial.println("seesaw started"); 21 | 22 | ss.pinModeBulk(mask, OUTPUT); //set pin modes 23 | } 24 | 25 | void loop() { 26 | ss.digitalWriteBulk(mask, HIGH); //set pins 27 | delay(1000); // wait for a second 28 | ss.digitalWriteBulk(mask, LOW); //clear pins 29 | delay(1000); 30 | } 31 | -------------------------------------------------------------------------------- /examples/digital/multiread/multiread.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This example shows how to read multiple pins at once on a seesaw. 3 | */ 4 | 5 | #include "Adafruit_seesaw.h" 6 | 7 | Adafruit_seesaw ss; 8 | 9 | //read pins A8, A9, A10 10 | uint32_t mask = ((uint32_t)0b111 << 8); 11 | 12 | void setup() { 13 | Serial.begin(9600); 14 | 15 | if(!ss.begin()){ 16 | Serial.println("ERROR!"); 17 | while(1) delay(1); 18 | } 19 | else Serial.println("seesaw started"); 20 | 21 | ss.pinModeBulk(mask, INPUT); 22 | } 23 | 24 | void loop() { 25 | Serial.println(ss.digitalReadBulk(mask), BIN); 26 | delay(500); 27 | } 28 | -------------------------------------------------------------------------------- /examples/encoder/PID5740_ANOencoder_7Seg_demo/.pico_rp2040.test.only: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/Adafruit_Seesaw/985b41efae3d9a8cba12a7b4d9ff0d226f9e0759/examples/encoder/PID5740_ANOencoder_7Seg_demo/.pico_rp2040.test.only -------------------------------------------------------------------------------- /examples/encoder/PID5740_ANOencoder_7Seg_demo/PID5740_ANOencoder_7Seg_demo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a demo for a QT Py RP2040 connected to an ANO encoder breakout and a 7-segment breakout 3 | * using the onboard Stemma QT Port 4 | * https://www.adafruit.com/product/878 5 | * https://www.adafruit.com/product/5740 6 | * 7 | */ 8 | #include "Adafruit_seesaw.h" 9 | #include "Adafruit_LEDBackpack.h" 10 | 11 | 12 | #define SS_SWITCH_SELECT 1 13 | #define SS_SWITCH_UP 2 14 | #define SS_SWITCH_LEFT 3 15 | #define SS_SWITCH_DOWN 4 16 | #define SS_SWITCH_RIGHT 5 17 | 18 | #define SEESAW_ADDR 0x49 19 | 20 | Adafruit_7segment seven = Adafruit_7segment(); 21 | Adafruit_seesaw ss = Adafruit_seesaw(&Wire1); 22 | int32_t encoder_position; 23 | 24 | void setup() { 25 | Serial.begin(115200); 26 | //while (!Serial) delay(10); 27 | 28 | seven.begin(0x70, &Wire1); 29 | 30 | Serial.println("Looking for seesaw!"); 31 | 32 | if (! ss.begin(SEESAW_ADDR)) { 33 | Serial.println("Couldn't find seesaw on default address"); 34 | while(1) delay(10); 35 | } 36 | Serial.println("seesaw started"); 37 | uint32_t version = ((ss.getVersion() >> 16) & 0xFFFF); 38 | if (version != 5740){ 39 | Serial.print("Wrong firmware loaded? "); 40 | Serial.println(version); 41 | while(1) delay(10); 42 | } 43 | Serial.println("Found Product 5740"); 44 | 45 | ss.pinMode(SS_SWITCH_UP, INPUT_PULLUP); 46 | ss.pinMode(SS_SWITCH_DOWN, INPUT_PULLUP); 47 | ss.pinMode(SS_SWITCH_LEFT, INPUT_PULLUP); 48 | ss.pinMode(SS_SWITCH_RIGHT, INPUT_PULLUP); 49 | ss.pinMode(SS_SWITCH_SELECT, INPUT_PULLUP); 50 | 51 | // get starting position 52 | encoder_position = ss.getEncoderPosition(); 53 | seven.print(encoder_position, DEC); 54 | seven.writeDisplay(); 55 | 56 | Serial.println("Turning on interrupts"); 57 | ss.enableEncoderInterrupt(); 58 | ss.setGPIOInterrupts((uint32_t)1 << SS_SWITCH_UP, 1); 59 | 60 | } 61 | 62 | void loop() { 63 | if (! ss.digitalRead(SS_SWITCH_UP)) { 64 | seven.println(" UP "); 65 | seven.writeDisplay(); 66 | Serial.println("UP pressed!"); 67 | } 68 | else if (! ss.digitalRead(SS_SWITCH_DOWN)) { 69 | seven.println("DOWN"); 70 | seven.writeDisplay(); 71 | Serial.println("DOWN pressed!"); 72 | } 73 | else if (! ss.digitalRead(SS_SWITCH_SELECT)) { 74 | seven.println("SELE"); 75 | seven.writeDisplay(); 76 | Serial.println("SELECT pressed!"); 77 | } 78 | else if (! ss.digitalRead(SS_SWITCH_LEFT)) { 79 | seven.println("LEFT"); 80 | seven.writeDisplay(); 81 | Serial.println("LEFT pressed!"); 82 | } 83 | else if (! ss.digitalRead(SS_SWITCH_RIGHT)) { 84 | seven.println("RIGT"); 85 | seven.writeDisplay(); 86 | Serial.println("RIGHT pressed!"); 87 | } else { 88 | seven.print(encoder_position, DEC); 89 | seven.writeDisplay(); 90 | } 91 | 92 | int32_t new_position = ss.getEncoderPosition(); 93 | // did we move around? 94 | if (encoder_position != new_position) { 95 | Serial.println(new_position); // display new position 96 | encoder_position = new_position; // and save for next round 97 | } 98 | 99 | // don't overwhelm serial port 100 | delay(10); 101 | } 102 | -------------------------------------------------------------------------------- /examples/encoder/PID5740_ANOencoder_demo/PID5740_ANOencoder_demo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This example shows how to read from a seesaw encoder module. 3 | * The available encoder API is: 4 | * int32_t getEncoderPosition(); 5 | int32_t getEncoderDelta(); 6 | void enableEncoderInterrupt(); 7 | void disableEncoderInterrupt(); 8 | */ 9 | #include "Adafruit_seesaw.h" 10 | 11 | #define SS_SWITCH_SELECT 1 12 | #define SS_SWITCH_UP 2 13 | #define SS_SWITCH_LEFT 3 14 | #define SS_SWITCH_DOWN 4 15 | #define SS_SWITCH_RIGHT 5 16 | 17 | #define SEESAW_ADDR 0x49 18 | 19 | Adafruit_seesaw ss; 20 | int32_t encoder_position; 21 | 22 | void setup() { 23 | Serial.begin(115200); 24 | while (!Serial) delay(10); 25 | 26 | Serial.println("Looking for seesaw!"); 27 | 28 | if (! ss.begin(SEESAW_ADDR)) { 29 | Serial.println("Couldn't find seesaw on default address"); 30 | while(1) delay(10); 31 | } 32 | Serial.println("seesaw started"); 33 | uint32_t version = ((ss.getVersion() >> 16) & 0xFFFF); 34 | if (version != 5740){ 35 | Serial.print("Wrong firmware loaded? "); 36 | Serial.println(version); 37 | while(1) delay(10); 38 | } 39 | Serial.println("Found Product 5740"); 40 | 41 | ss.pinMode(SS_SWITCH_UP, INPUT_PULLUP); 42 | ss.pinMode(SS_SWITCH_DOWN, INPUT_PULLUP); 43 | ss.pinMode(SS_SWITCH_LEFT, INPUT_PULLUP); 44 | ss.pinMode(SS_SWITCH_RIGHT, INPUT_PULLUP); 45 | ss.pinMode(SS_SWITCH_SELECT, INPUT_PULLUP); 46 | 47 | // get starting position 48 | encoder_position = ss.getEncoderPosition(); 49 | 50 | Serial.println("Turning on interrupts"); 51 | ss.enableEncoderInterrupt(); 52 | ss.setGPIOInterrupts((uint32_t)1 << SS_SWITCH_UP, 1); 53 | 54 | } 55 | 56 | void loop() { 57 | if (! ss.digitalRead(SS_SWITCH_UP)) { 58 | Serial.println("UP pressed!"); 59 | } 60 | if (! ss.digitalRead(SS_SWITCH_DOWN)) { 61 | Serial.println("DOWN pressed!"); 62 | } 63 | if (! ss.digitalRead(SS_SWITCH_SELECT)) { 64 | Serial.println("SELECT pressed!"); 65 | } 66 | if (! ss.digitalRead(SS_SWITCH_LEFT)) { 67 | Serial.println("LEFT pressed!"); 68 | } 69 | if (! ss.digitalRead(SS_SWITCH_RIGHT)) { 70 | Serial.println("RIGHT pressed!"); 71 | } 72 | 73 | int32_t new_position = ss.getEncoderPosition(); 74 | // did we move around? 75 | if (encoder_position != new_position) { 76 | Serial.println(new_position); // display new position 77 | 78 | encoder_position = new_position; // and save for next round 79 | } 80 | 81 | // don't overwhelm serial port 82 | delay(10); 83 | } 84 | -------------------------------------------------------------------------------- /examples/encoder/PID5752_QuadEncoder_TFTDemo/.feather_esp32s2_tft.test.only: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/Adafruit_Seesaw/985b41efae3d9a8cba12a7b4d9ff0d226f9e0759/examples/encoder/PID5752_QuadEncoder_TFTDemo/.feather_esp32s2_tft.test.only -------------------------------------------------------------------------------- /examples/encoder/PID5752_QuadEncoder_TFTDemo/PID5752_QuadEncoder_TFTDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a demo for a Feather ESP32-S2 TFT connected to a Quad 3 | * Rotary Encoder board 4 | * https://www.adafruit.com/product/5300 5 | * https://www.adafruit.com/product/5752 6 | * 7 | */ 8 | #include "Adafruit_seesaw.h" 9 | #include 10 | #include 11 | #include 12 | // we hvae loooots of PSRAM so lets use a GFX canvas for flicker-free graphics! 13 | GFXcanvas16 canvas(240, 135); 14 | Adafruit_ST7789 display = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST); 15 | 16 | 17 | #define SS_NEO_PIN 18 18 | #define SS_ENC0_SWITCH 12 19 | #define SS_ENC1_SWITCH 14 20 | #define SS_ENC2_SWITCH 17 21 | #define SS_ENC3_SWITCH 9 22 | 23 | #define SEESAW_ADDR 0x49 24 | 25 | Adafruit_seesaw ss = Adafruit_seesaw(&Wire); 26 | seesaw_NeoPixel pixels = seesaw_NeoPixel(4, SS_NEO_PIN, NEO_GRB + NEO_KHZ800); 27 | 28 | int32_t enc_positions[4] = {0, 0, 0, 0}; 29 | 30 | void setup() { 31 | Serial.begin(115200); 32 | //while (!Serial) delay(10); 33 | 34 | pinMode(TFT_BACKLITE, OUTPUT); 35 | digitalWrite(TFT_BACKLITE, LOW); 36 | 37 | // turn on the TFT / I2C power supply 38 | pinMode(TFT_I2C_POWER, OUTPUT); 39 | digitalWrite(TFT_I2C_POWER, HIGH); 40 | delay(10); 41 | 42 | Serial.println("Looking for seesaw!"); 43 | 44 | if (! ss.begin(SEESAW_ADDR) || !pixels.begin(SEESAW_ADDR)) { 45 | Serial.println("Couldn't find seesaw on default address"); 46 | while(1) delay(10); 47 | } 48 | Serial.println("seesaw started"); 49 | uint32_t version = ((ss.getVersion() >> 16) & 0xFFFF); 50 | if (version != 5752){ 51 | Serial.print("Wrong firmware loaded? "); 52 | Serial.println(version); 53 | while(1) delay(10); 54 | } 55 | Serial.println("Found Product 5752"); 56 | 57 | ss.pinMode(SS_ENC0_SWITCH, INPUT_PULLUP); 58 | ss.pinMode(SS_ENC1_SWITCH, INPUT_PULLUP); 59 | ss.pinMode(SS_ENC2_SWITCH, INPUT_PULLUP); 60 | ss.pinMode(SS_ENC3_SWITCH, INPUT_PULLUP); 61 | ss.setGPIOInterrupts(1UL << SS_ENC0_SWITCH | 1UL << SS_ENC1_SWITCH | 62 | 1UL << SS_ENC2_SWITCH | 1UL << SS_ENC3_SWITCH, 1); 63 | 64 | 65 | // get starting positions 66 | for (int e=0; e<4; e++) { 67 | enc_positions[e] = ss.getEncoderPosition(e); 68 | ss.enableEncoderInterrupt(e); 69 | } 70 | 71 | Serial.println("Turning on interrupts"); 72 | 73 | pixels.setBrightness(255); 74 | pixels.show(); // Initialize all pixels to 'off' 75 | 76 | display.init(135, 240); // Init ST7789 240x135 77 | display.setRotation(3); 78 | display.fillScreen(ST77XX_BLUE); 79 | digitalWrite(TFT_BACKLITE, HIGH); 80 | 81 | canvas.setFont(&FreeSans12pt7b); 82 | canvas.setTextColor(ST77XX_WHITE); 83 | } 84 | 85 | uint8_t switch_pins[] = {SS_ENC0_SWITCH, SS_ENC1_SWITCH, SS_ENC2_SWITCH, SS_ENC3_SWITCH}; 86 | 87 | void loop() { 88 | bool changed = false; 89 | canvas.fillScreen(ST77XX_BLACK); 90 | canvas.setCursor(0, 25); 91 | canvas.setTextColor(ST77XX_WHITE); 92 | //canvas.println("Quad Encoder QT Demo"); 93 | 94 | for (int e=0; e<4; e++) { 95 | int32_t new_enc_position = ss.getEncoderPosition(e); 96 | // did we move around? 97 | if (enc_positions[e] != new_enc_position) { 98 | Serial.print("Rot. #"); 99 | Serial.print(e); 100 | Serial.print(" -> "); 101 | Serial.println(new_enc_position); // display new position 102 | enc_positions[e] = new_enc_position; // and save for next round 103 | 104 | // change the neopixel color, mulitply the new positiion by 4 to speed it up 105 | pixels.setPixelColor(e, Wheel((new_enc_position*4) & 0xFF)); 106 | pixels.show(); 107 | changed = true; 108 | } 109 | canvas.setTextColor(ST77XX_WHITE); 110 | canvas.print("Rotary #"); 111 | canvas.print(e); 112 | canvas.print(": "); 113 | canvas.print(enc_positions[e]); 114 | 115 | if (! ss.digitalRead(switch_pins[e])) { 116 | Serial.print("ENC"); 117 | Serial.print("e"); 118 | Serial.println("pressed!"); 119 | canvas.setTextColor(ST77XX_RED); 120 | canvas.print(" DOWN"); 121 | changed = true; 122 | } 123 | canvas.println(); 124 | } 125 | 126 | if (changed) { 127 | display.drawRGBBitmap(0, 0, canvas.getBuffer(), 240, 135); 128 | } 129 | } 130 | 131 | 132 | uint32_t Wheel(byte WheelPos) { 133 | WheelPos = 255 - WheelPos; 134 | if (WheelPos < 85) { 135 | return seesaw_NeoPixel::Color(255 - WheelPos * 3, 0, WheelPos * 3); 136 | } 137 | if (WheelPos < 170) { 138 | WheelPos -= 85; 139 | return seesaw_NeoPixel::Color(0, WheelPos * 3, 255 - WheelPos * 3); 140 | } 141 | WheelPos -= 170; 142 | return seesaw_NeoPixel::Color(WheelPos * 3, 255 - WheelPos * 3, 0); 143 | } 144 | -------------------------------------------------------------------------------- /examples/encoder/PID5752_QuadEncoder_demo/PID5752_QuadEncoder_demo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a demo for a QT Py RP2040 connected to a quad rotary encoder breakout 3 | * using the onboard Stemma QT Port 4 | * https://www.adafruit.com/product/4900 5 | * https://www.adafruit.com/product/5752 6 | * 7 | */ 8 | #include "Adafruit_seesaw.h" 9 | #include 10 | 11 | #define SS_NEO_PIN 18 12 | #define SS_ENC0_SWITCH 12 13 | #define SS_ENC1_SWITCH 14 14 | #define SS_ENC2_SWITCH 17 15 | #define SS_ENC3_SWITCH 9 16 | 17 | #define SEESAW_ADDR 0x49 18 | 19 | Adafruit_seesaw ss = Adafruit_seesaw(&Wire); 20 | seesaw_NeoPixel pixels = seesaw_NeoPixel(4, SS_NEO_PIN, NEO_GRB + NEO_KHZ800); 21 | 22 | int32_t enc_positions[4] = {0, 0, 0, 0}; 23 | 24 | void setup() { 25 | Serial.begin(115200); 26 | while (!Serial) delay(10); 27 | 28 | Serial.println("Looking for seesaw!"); 29 | 30 | if (! ss.begin(SEESAW_ADDR) || !pixels.begin(SEESAW_ADDR)) { 31 | Serial.println("Couldn't find seesaw on default address"); 32 | while(1) delay(10); 33 | } 34 | Serial.println("seesaw started"); 35 | uint32_t version = ((ss.getVersion() >> 16) & 0xFFFF); 36 | if (version != 5752){ 37 | Serial.print("Wrong firmware loaded? "); 38 | Serial.println(version); 39 | while(1) delay(10); 40 | } 41 | Serial.println("Found Product 5752"); 42 | 43 | ss.pinMode(SS_ENC0_SWITCH, INPUT_PULLUP); 44 | ss.pinMode(SS_ENC1_SWITCH, INPUT_PULLUP); 45 | ss.pinMode(SS_ENC2_SWITCH, INPUT_PULLUP); 46 | ss.pinMode(SS_ENC3_SWITCH, INPUT_PULLUP); 47 | ss.setGPIOInterrupts(1UL << SS_ENC0_SWITCH | 1UL << SS_ENC1_SWITCH | 48 | 1UL << SS_ENC2_SWITCH | 1UL << SS_ENC3_SWITCH, 1); 49 | 50 | 51 | // get starting positions 52 | for (int e=0; e<4; e++) { 53 | enc_positions[e] = ss.getEncoderPosition(e); 54 | ss.enableEncoderInterrupt(e); 55 | } 56 | 57 | Serial.println("Turning on interrupts"); 58 | 59 | pixels.setBrightness(255); 60 | pixels.show(); // Initialize all pixels to 'off' 61 | } 62 | 63 | void loop() { 64 | 65 | if (! ss.digitalRead(SS_ENC0_SWITCH)) { 66 | Serial.println("ENC0 pressed!"); 67 | } 68 | if (! ss.digitalRead(SS_ENC1_SWITCH)) { 69 | Serial.println("ENC1 pressed!"); 70 | } 71 | if (! ss.digitalRead(SS_ENC2_SWITCH)) { 72 | Serial.println("ENC2 pressed!"); 73 | } 74 | if (! ss.digitalRead(SS_ENC3_SWITCH)) { 75 | Serial.println("ENC3 pressed!"); 76 | } 77 | 78 | 79 | for (int e=0; e<4; e++) { 80 | int32_t new_enc_position = ss.getEncoderPosition(e); 81 | // did we move around? 82 | if (enc_positions[e] != new_enc_position) { 83 | Serial.print("Encoder #"); 84 | Serial.print(e); 85 | Serial.print(" -> "); 86 | Serial.println(new_enc_position); // display new position 87 | enc_positions[e] = new_enc_position; // and save for next round 88 | 89 | // change the neopixel color, mulitply the new positiion by 4 to speed it up 90 | pixels.setPixelColor(e, Wheel((new_enc_position*4) & 0xFF)); 91 | pixels.show(); 92 | } 93 | } 94 | 95 | // don't overwhelm serial port 96 | delay(10); 97 | } 98 | 99 | 100 | uint32_t Wheel(byte WheelPos) { 101 | WheelPos = 255 - WheelPos; 102 | if (WheelPos < 85) { 103 | return seesaw_NeoPixel::Color(255 - WheelPos * 3, 0, WheelPos * 3); 104 | } 105 | if (WheelPos < 170) { 106 | WheelPos -= 85; 107 | return seesaw_NeoPixel::Color(0, WheelPos * 3, 255 - WheelPos * 3); 108 | } 109 | WheelPos -= 170; 110 | return seesaw_NeoPixel::Color(WheelPos * 3, 255 - WheelPos * 3, 0); 111 | } -------------------------------------------------------------------------------- /examples/encoder/encoder_basic/encoder_basic.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This example shows how to read from a seesaw encoder module. 3 | * The available encoder API is: 4 | * int32_t getEncoderPosition(); 5 | int32_t getEncoderDelta(); 6 | void enableEncoderInterrupt(); 7 | void disableEncoderInterrupt(); 8 | void setEncoderPosition(int32_t pos); 9 | */ 10 | #include "Adafruit_seesaw.h" 11 | #include 12 | 13 | #define SS_SWITCH 24 14 | #define SS_NEOPIX 6 15 | 16 | #define SEESAW_ADDR 0x36 17 | 18 | Adafruit_seesaw ss; 19 | seesaw_NeoPixel sspixel = seesaw_NeoPixel(1, SS_NEOPIX, NEO_GRB + NEO_KHZ800); 20 | 21 | int32_t encoder_position; 22 | 23 | void setup() { 24 | Serial.begin(115200); 25 | while (!Serial) delay(10); 26 | 27 | Serial.println("Looking for seesaw!"); 28 | 29 | if (! ss.begin(SEESAW_ADDR) || ! sspixel.begin(SEESAW_ADDR)) { 30 | Serial.println("Couldn't find seesaw on default address"); 31 | while(1) delay(10); 32 | } 33 | Serial.println("seesaw started"); 34 | 35 | uint32_t version = ((ss.getVersion() >> 16) & 0xFFFF); 36 | if (version != 4991){ 37 | Serial.print("Wrong firmware loaded? "); 38 | Serial.println(version); 39 | while(1) delay(10); 40 | } 41 | Serial.println("Found Product 4991"); 42 | 43 | // set not so bright! 44 | sspixel.setBrightness(20); 45 | sspixel.show(); 46 | 47 | // use a pin for the built in encoder switch 48 | ss.pinMode(SS_SWITCH, INPUT_PULLUP); 49 | 50 | // get starting position 51 | encoder_position = ss.getEncoderPosition(); 52 | 53 | Serial.println("Turning on interrupts"); 54 | delay(10); 55 | ss.setGPIOInterrupts((uint32_t)1 << SS_SWITCH, 1); 56 | ss.enableEncoderInterrupt(); 57 | } 58 | 59 | void loop() { 60 | if (! ss.digitalRead(SS_SWITCH)) { 61 | Serial.println("Button pressed!"); 62 | } 63 | 64 | int32_t new_position = ss.getEncoderPosition(); 65 | // did we move arounde? 66 | if (encoder_position != new_position) { 67 | Serial.println(new_position); // display new position 68 | 69 | // change the neopixel color 70 | sspixel.setPixelColor(0, Wheel(new_position & 0xFF)); 71 | sspixel.show(); 72 | encoder_position = new_position; // and save for next round 73 | } 74 | 75 | // don't overwhelm serial port 76 | delay(10); 77 | } 78 | 79 | 80 | uint32_t Wheel(byte WheelPos) { 81 | WheelPos = 255 - WheelPos; 82 | if (WheelPos < 85) { 83 | return sspixel.Color(255 - WheelPos * 3, 0, WheelPos * 3); 84 | } 85 | if (WheelPos < 170) { 86 | WheelPos -= 85; 87 | return sspixel.Color(0, WheelPos * 3, 255 - WheelPos * 3); 88 | } 89 | WheelPos -= 170; 90 | return sspixel.Color(WheelPos * 3, 255 - WheelPos * 3, 0); 91 | } -------------------------------------------------------------------------------- /examples/encoder/multiple_encoders/multiple_encoders.ino: -------------------------------------------------------------------------------- 1 | /* Demo with 128x64 OLED display and multiple I2C encoders wired up. The sketch will auto- 2 | * detect up to 4 encoder on the first 4 addresses. Twisting will display text on OLED 3 | * and change neopixel color. 4 | * set USE_OLED to true t 5 | */ 6 | 7 | #define USE_OLED false // set to false to skip the OLED, true to use it! 8 | 9 | 10 | #include "Adafruit_seesaw.h" 11 | #include 12 | 13 | #if USE_OLED 14 | #include 15 | #include 16 | Adafruit_SH1107 display = Adafruit_SH1107(64, 128, &Wire); 17 | #endif 18 | 19 | #define SS_SWITCH 24 // this is the pin on the encoder connected to switch 20 | #define SS_NEOPIX 6 // this is the pin on the encoder connected to neopixel 21 | 22 | #define SEESAW_BASE_ADDR 0x36 // I2C address, starts with 0x36 23 | 24 | 25 | // create 4 encoders! 26 | Adafruit_seesaw encoders[4]; 27 | // create 4 encoder pixels 28 | seesaw_NeoPixel encoder_pixels[4] = { 29 | seesaw_NeoPixel(1, SS_NEOPIX, NEO_GRB + NEO_KHZ800), 30 | seesaw_NeoPixel(1, SS_NEOPIX, NEO_GRB + NEO_KHZ800), 31 | seesaw_NeoPixel(1, SS_NEOPIX, NEO_GRB + NEO_KHZ800), 32 | seesaw_NeoPixel(1, SS_NEOPIX, NEO_GRB + NEO_KHZ800)}; 33 | 34 | int32_t encoder_positions[] = {0, 0, 0, 0}; 35 | bool found_encoders[] = {false, false, false, false}; 36 | 37 | void setup() { 38 | Serial.begin(115200); 39 | 40 | // wait for serial port to open 41 | while (!Serial) delay(10); 42 | 43 | Serial.println("128x64 OLED + seesaw Encoders test"); 44 | 45 | #if USE_OLED 46 | display.begin(0x3C, true); // Address 0x3C default 47 | Serial.println("OLED begun"); 48 | display.display(); 49 | delay(500); // Pause for half second 50 | display.setRotation(1); 51 | display.setFont(&FreeSans9pt7b); 52 | display.setTextColor(SH110X_WHITE); 53 | #endif 54 | 55 | Serial.println("Looking for seesaws!"); 56 | 57 | for (uint8_t enc=0; enc> 16) & 0xFFFF); 68 | if (version != 4991){ 69 | Serial.print("Wrong firmware loaded? "); 70 | Serial.println(version); 71 | while(1) delay(10); 72 | } 73 | Serial.println("Found Product 4991"); 74 | 75 | // use a pin for the built in encoder switch 76 | encoders[enc].pinMode(SS_SWITCH, INPUT_PULLUP); 77 | 78 | // get starting position 79 | encoder_positions[enc] = encoders[enc].getEncoderPosition(); 80 | 81 | Serial.println("Turning on interrupts"); 82 | delay(10); 83 | encoders[enc].setGPIOInterrupts((uint32_t)1 << SS_SWITCH, 1); 84 | encoders[enc].enableEncoderInterrupt(); 85 | 86 | // set not so bright! 87 | encoder_pixels[enc].setBrightness(30); 88 | encoder_pixels[enc].show(); 89 | 90 | found_encoders[enc] = true; 91 | } 92 | } 93 | 94 | Serial.println("Encoders started"); 95 | } 96 | 97 | void loop() { 98 | #if USE_OLED 99 | display.clearDisplay(); 100 | uint16_t display_line = 1; 101 | #endif 102 | 103 | for (uint8_t enc=0; enc "); 112 | Serial.println(new_position); // display new position 113 | encoder_positions[enc] = new_position; 114 | 115 | // change the neopixel color, mulitply the new positiion by 4 to speed it up 116 | encoder_pixels[enc].setPixelColor(0, Wheel((new_position*4) & 0xFF)); 117 | encoder_pixels[enc].show(); 118 | } 119 | 120 | #if USE_OLED 121 | // draw the display 122 | display.setCursor(0, 20*display_line++); 123 | display.print("Enc #"); 124 | display.print(enc); 125 | display.print(" : "); 126 | display.print(encoder_positions[enc]); 127 | #endif 128 | 129 | if (! encoders[enc].digitalRead(SS_SWITCH)) { 130 | Serial.print("Encoder #"); 131 | Serial.print(enc); 132 | Serial.println(" pressed"); 133 | #if USE_OLED 134 | display.print(" P"); 135 | #endif 136 | } 137 | } 138 | 139 | #if USE_OLED 140 | display.display(); 141 | #endif 142 | 143 | // don't overwhelm serial port 144 | yield(); 145 | delay(10); 146 | } 147 | 148 | 149 | uint32_t Wheel(byte WheelPos) { 150 | WheelPos = 255 - WheelPos; 151 | if (WheelPos < 85) { 152 | return seesaw_NeoPixel::Color(255 - WheelPos * 3, 0, WheelPos * 3); 153 | } 154 | if (WheelPos < 170) { 155 | WheelPos -= 85; 156 | return seesaw_NeoPixel::Color(0, WheelPos * 3, 255 - WheelPos * 3); 157 | } 158 | WheelPos -= 170; 159 | return seesaw_NeoPixel::Color(WheelPos * 3, 255 - WheelPos * 3, 0); 160 | } 161 | -------------------------------------------------------------------------------- /examples/encoder_delta/encoder_delta.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * This example helps demonstrates getEncoderDelta(). 3 | * 4 | * position = the current encoder position 5 | * delta = the change in position since last read 6 | * 7 | * With this sketch running, open the Serial Monitor. It may also help 8 | * to turn on "Show timestamp". Then play with turning the encoder between 9 | * print outs to see how the values change. 10 | * 11 | * If the encoder does ~not~ move between reads, then: 12 | * - position will be the same value 13 | * - delta will be zero 14 | * 15 | * NOTE: reading position or delta resets delta to zero 16 | */ 17 | 18 | #include "Adafruit_seesaw.h" 19 | #include 20 | 21 | #define SEESAW_ADDR 0x36 22 | 23 | Adafruit_seesaw ss; 24 | 25 | void setup() { 26 | Serial.begin(115200); 27 | while (!Serial) delay(10); 28 | 29 | Serial.println("Looking for seesaw!"); 30 | 31 | if (! ss.begin(SEESAW_ADDR)) { 32 | Serial.println("Couldn't find seesaw on default address"); 33 | while(1) delay(10); 34 | } 35 | Serial.println("seesaw started"); 36 | 37 | uint16_t pid; 38 | uint8_t year, mon, day; 39 | 40 | ss.getProdDatecode(&pid, &year, &mon, &day); 41 | Serial.print("PID: "); Serial.println(pid); 42 | Serial.print("Firmware:"); 43 | Serial.print(2000+year); Serial.print("/"); 44 | Serial.print(mon); Serial.print("/"); 45 | Serial.println(day); 46 | } 47 | 48 | void loop() { 49 | int32_t position; 50 | int32_t delta; 51 | 52 | // get delta and position 53 | delta = ss.getEncoderDelta(); // also resets delta to zero 54 | position = ss.getEncoderPosition(); // this also resets delta to zero 55 | // so getEncoderDelta() is called first 56 | 57 | // print info 58 | Serial.print("position: "); Serial.println(position); 59 | Serial.print(" delta: "); Serial.println(delta); 60 | 61 | // read once every two seconds 62 | // this is intentionally slow to allow user to easily turn encoder between reads 63 | delay(2000); 64 | } 65 | -------------------------------------------------------------------------------- /examples/joy_featherwing/joy_featherwing_ESP32/.esp32.test.only: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/Adafruit_Seesaw/985b41efae3d9a8cba12a7b4d9ff0d226f9e0759/examples/joy_featherwing/joy_featherwing_ESP32/.esp32.test.only -------------------------------------------------------------------------------- /examples/joy_featherwing/joy_featherwing_ESP32/joy_featherwing_ESP32.ino: -------------------------------------------------------------------------------- 1 | // This code is only for use with ESP chips and demonstrates how to perform background operations against the I2C bus to 2 | // communicate with the Joy Featherwing peripheral in a non-blocking fashion. As ESP's FreeRTOS does not play nicely with 3 | // performing operations against I2C from within an ISR, a queue is used to signal to a worker task that a button has been 4 | // pressed rather than reading from I2C within the ISR itself. To read from the analog controller, a separate task running 5 | // in a loop polls for changes. It also attempts to calibrate the controller and deterine a center point while compensating 6 | // for any controller drift. All operations over I2C are synchronized with a semaphore to prevent crashes or corruption 7 | // resulting from concurrent operations as the Wire library is not thread safe. 8 | 9 | #if !defined(ESP8266) && !defined(ESP32) 10 | #error This sketch only supports ESP32 and ESP8266 11 | #endif // ESP8266 / ESP32 12 | 13 | #include "Adafruit_seesaw.h" 14 | 15 | // This can be enabled to get extra logging about the position of the controller relative to the correction values 16 | //#define JOY_CALIBRATION_MODE 17 | 18 | // This sketch requires that one of the optional interrupt pins on the Joy Featherwing is soldered. This value should match the 19 | // complimentary GPIO pin on the ESP device. See: https://learn.adafruit.com/joy-featherwing/pinouts 20 | #define IRQ_PIN 14 // Pin 14 is the pin directly to the left of the SCL pin on an ESP32 21 | 22 | Adafruit_seesaw ss; 23 | 24 | // GPIO pins on the Joy Featherwing for reading button presses. These should not be changed. 25 | #define BUTTON_RIGHT 6 26 | #define BUTTON_DOWN 7 27 | #define BUTTON_LEFT 9 28 | #define BUTTON_UP 10 29 | #define BUTTON_SEL 14 30 | 31 | // GPIO Analog pins on the Joy Featherwing for reading the analog stick. These should not be changed. 32 | #define STICK_H 3 33 | #define STICK_V 2 34 | 35 | // When the analog stick is moved and returns to its center point there may be a deviation from the true center of 512. A calibration will 36 | // occur when the analog stick read task begins. Even after this calibration there may be some drift on the stick that can make determining 37 | // the center point error prone. In order to compensate for this, values can be specified to determine a reasonable center point. If you have 38 | // a use case where you don't care about drift or the center point of the stick, this can all be ignored entirely. 39 | #ifndef STICK_CENTER_POINT 40 | #define STICK_CENTER_POINT 512 // Analog stick will read 0...1024 along each axis 41 | #endif 42 | #ifndef STICK_L_CORRECTION 43 | #define STICK_L_CORRECTION -55 44 | #endif 45 | #ifndef STICK_R_CORRECTION 46 | #define STICK_R_CORRECTION 50 47 | #endif 48 | #ifndef STICK_U_CORRECTION 49 | #define STICK_U_CORRECTION 20 50 | #endif 51 | #ifndef STICK_D_CORRECTION 52 | #define STICK_D_CORRECTION -20 53 | #endif 54 | 55 | // Every time the analog values are read they will be slightly different. In order 56 | // to only detect movement when the stick is actually moved, these values can tune 57 | // the minimum amount of movement + or - before it is considered as moved. 58 | #ifndef MIN_STICK_H_MOVE 59 | #define MIN_STICK_H_MOVE 5 60 | #endif 61 | #ifndef MIN_STICK_V_MOVE 62 | #define MIN_STICK_V_MOVE 5 63 | #endif 64 | 65 | uint32_t button_mask = (1 << BUTTON_RIGHT) | (1 << BUTTON_DOWN) | 66 | (1 << BUTTON_LEFT) | (1 << BUTTON_UP) | (1 << BUTTON_SEL); 67 | 68 | QueueHandle_t buttonPressQueue; // Queue for notifying of button press changes 69 | SemaphoreHandle_t i2cSem = xSemaphoreCreateBinary(); // This semaphore is used to synchronize calls to I2C to prevent concurrent operations 70 | 71 | // ISR that gets triggered when a button is pressed. 72 | void IRAM_ATTR onButtonPress() 73 | { 74 | // The ISR just sends a signal to the queue. Value doesn't matter. 75 | uint8_t v = 0; 76 | if (!xQueueSend(buttonPressQueue, &v, portMAX_DELAY)) 77 | { 78 | Serial.println("WARNING: Could not queue message because queue is full."); 79 | } 80 | } 81 | 82 | // Log the pressed buttons to the serial port 83 | void outputPressedButtons(uint32_t mask) 84 | { 85 | #ifdef JOY_DEBUG 86 | Serial.print("Mask: "); 87 | Serial.println(mask, BIN); 88 | #endif 89 | 90 | if (!(mask & (1 << BUTTON_RIGHT))) 91 | { 92 | Serial.println(F("Button A pressed")); 93 | } 94 | if (!(mask & (1 << BUTTON_DOWN))) 95 | { 96 | Serial.println(F("Button B pressed")); 97 | } 98 | if (!(mask & (1 << BUTTON_LEFT))) 99 | { 100 | Serial.println(F("Button Y pressed")); 101 | } 102 | if (!(mask & (1 << BUTTON_UP))) 103 | { 104 | Serial.println(F("Button X pressed")); 105 | } 106 | if (!(mask & (1 << BUTTON_SEL))) 107 | { 108 | Serial.println(F("Button SEL pressed")); 109 | } 110 | } 111 | 112 | // Queue consumer for responding to button presses 113 | void buttonPressConsumer(void *) 114 | { 115 | Serial.println(F("buttonPressConsumer() begin")); 116 | uint32_t lastValue = 0; 117 | while (true) 118 | { 119 | void *p; // Don't care about this value, only that we get queued 120 | // This will yield until the queue gets signalled 121 | xQueueReceive(buttonPressQueue, &p, portMAX_DELAY); 122 | xSemaphoreTake(i2cSem, portMAX_DELAY); 123 | uint32_t v = ss.digitalReadBulk(button_mask); 124 | 125 | // Debounce by discarding duplicate reads 126 | if (lastValue != v) 127 | { 128 | outputPressedButtons(v); 129 | lastValue = v; 130 | } 131 | 132 | xSemaphoreGive(i2cSem); 133 | } 134 | 135 | vTaskDelete(NULL); 136 | } 137 | 138 | void analogStickTask(void *) 139 | { 140 | Serial.println(F("analogStickTask() begin")); 141 | 142 | int16_t x_ctr, y_ctr; 143 | xSemaphoreTake(i2cSem, portMAX_DELAY); 144 | x_ctr = ss.analogRead(STICK_H); 145 | y_ctr = ss.analogRead(STICK_V); 146 | xSemaphoreGive(i2cSem); 147 | 148 | Serial.printf("Initial center point x=%d y=%d\n", x_ctr, y_ctr); 149 | Serial.printf("Calibration values:\n\tCenter point: x=%d y=%d\n\tCorrections: u=%d d=%d l=%d r=%d\n\tCenter range: x=%d...%d y=%d...%d\n", 150 | x_ctr, 151 | y_ctr, 152 | STICK_U_CORRECTION, 153 | STICK_D_CORRECTION, 154 | STICK_L_CORRECTION, 155 | STICK_R_CORRECTION, 156 | x_ctr + STICK_L_CORRECTION, 157 | x_ctr + STICK_R_CORRECTION, 158 | y_ctr + STICK_U_CORRECTION, 159 | y_ctr + STICK_D_CORRECTION); 160 | 161 | int16_t x = -1; 162 | int16_t y = -1; 163 | bool isCentered = true; 164 | while (true) 165 | { 166 | xSemaphoreTake(i2cSem, portMAX_DELAY); 167 | int16_t new_x = ss.analogRead(STICK_H); 168 | int16_t new_y = ss.analogRead(STICK_V); 169 | xSemaphoreGive(i2cSem); 170 | 171 | // Ignore minute position changes as the values will change slightly with 172 | // every read. This can be tuned with MIN_STICK_H_MOVE and MIN_STICK_V_MOVE 173 | if (new_x <= x - MIN_STICK_H_MOVE || 174 | new_x >= x + MIN_STICK_H_MOVE || 175 | new_y <= y - MIN_STICK_V_MOVE || 176 | new_y >= y + MIN_STICK_V_MOVE) 177 | { 178 | 179 | #ifdef JOY_CALIBRATION_MODE 180 | Serial.printf("x=%d xc=%d x+c(L)=%d x+c(R)=%d <=%d >=%d\n", 181 | new_x, 182 | x_ctr, 183 | new_x + STICK_L_CORRECTION, 184 | new_x + STICK_R_CORRECTION, 185 | x_ctr >= new_x + STICK_L_CORRECTION, 186 | x_ctr <= new_x + STICK_R_CORRECTION); 187 | 188 | Serial.printf("y=%d yc=%d y+c(U)=%d y-c(D)=%d <=%d >=%d\n", 189 | new_y, 190 | y_ctr, 191 | new_y + STICK_U_CORRECTION, 192 | new_y + STICK_D_CORRECTION, 193 | y_ctr <= new_y + STICK_U_CORRECTION, 194 | y_ctr >= new_y + STICK_D_CORRECTION); 195 | #endif 196 | 197 | // Make a best effort guess as to if the stick is centered or not based on 198 | // initial calibration and corrections 199 | isCentered = x_ctr >= max(0, new_x + STICK_L_CORRECTION) && 200 | x_ctr <= max(0, new_x + STICK_R_CORRECTION) && 201 | y_ctr <= max(0, new_y + STICK_U_CORRECTION) && 202 | y_ctr >= max(0, new_y + STICK_D_CORRECTION); 203 | 204 | // Ensure value is always 0...1024 and account for any corrections and/or calibrations to prevent over/underflows 205 | x = new_x < 0 ? 0 : new_x > 1024 ? 1024 206 | : new_x; 207 | y = new_y < 0 ? 0 : new_y > 1024 ? 1024 208 | : new_y; 209 | 210 | double x_rad = x / 4 - 128; 211 | double y_rad = y / 4 - 128; 212 | double angle = -atan2(-x_rad, y_rad) * (180.0 / PI); 213 | double velocity = sqrt(pow(x_rad, 2) + pow(y_rad, 2)); 214 | 215 | // Log the position of the analog stick in various ways for different kinds of application 216 | Serial.printf("Analog stick position change!\n\tIs centered: %s\n\tPosition: X=%d Y=%d\n\tRadian: X=%f Y=%f\n\tDegrees: %f\n\tPosition from center: %f\n", 217 | isCentered ? "true" : "false", 218 | x, y, 219 | x_rad, y_rad, 220 | angle, 221 | velocity); 222 | } 223 | 224 | // Tune this to be quick enough to read the controller position in a reasonable amount of time but not so fast that it 225 | // saturates the I2C bus and delays or blocks other operations. 226 | delay(100); 227 | } 228 | 229 | vTaskDelete(NULL); 230 | } 231 | 232 | void setup() 233 | { 234 | Serial.begin(115200); 235 | 236 | while (!Serial) 237 | { 238 | delay(10); 239 | } 240 | 241 | Serial.println("Joy FeatherWing example!"); 242 | 243 | if (!ss.begin(0x49)) 244 | { 245 | Serial.println("ERROR! seesaw not found"); 246 | while (1) 247 | { 248 | delay(1); 249 | } 250 | } 251 | else 252 | { 253 | Serial.println("seesaw started"); 254 | Serial.print("version: "); 255 | Serial.println(ss.getVersion(), HEX); 256 | } 257 | 258 | ss.pinModeBulk(button_mask, INPUT_PULLUP); 259 | ss.setGPIOInterrupts(button_mask, 1); 260 | pinMode(IRQ_PIN, INPUT); 261 | 262 | xSemaphoreGive(i2cSem); // Initialize the semaphore to 0 (default state is uninitialized which will cause a crash) 263 | buttonPressQueue = xQueueCreate(10, sizeof(uint8_t)); 264 | 265 | // Task for listening to button presses 266 | xTaskCreate( 267 | buttonPressConsumer, 268 | "ButtonPressConsumer", 269 | 10000, // Stack size -- too low and ESP will eventually crash within the task 270 | NULL, 271 | 1, 272 | NULL); 273 | 274 | // Task for reading the analog stick value 275 | xTaskCreate( 276 | analogStickTask, 277 | "AnalogStickTask", 278 | 10000, // Stack size -- too low and ESP will eventually crash within the task 279 | NULL, 280 | 2, 281 | NULL); 282 | 283 | // Respond to changes from button presses 284 | attachInterrupt(IRQ_PIN, onButtonPress, FALLING); 285 | } 286 | 287 | void loop() 288 | { 289 | // Do nothing. Everything we're doing here is in a Task 290 | delay(10000); 291 | } 292 | -------------------------------------------------------------------------------- /examples/joy_featherwing/joy_featherwing_example/joy_featherwing_example.ino: -------------------------------------------------------------------------------- 1 | #include "Adafruit_seesaw.h" 2 | 3 | Adafruit_seesaw ss; 4 | 5 | #define BUTTON_RIGHT 6 6 | #define BUTTON_DOWN 7 7 | #define BUTTON_LEFT 9 8 | #define BUTTON_UP 10 9 | #define BUTTON_SEL 14 10 | uint32_t button_mask = (1 << BUTTON_RIGHT) | (1 << BUTTON_DOWN) | 11 | (1 << BUTTON_LEFT) | (1 << BUTTON_UP) | (1 << BUTTON_SEL); 12 | 13 | #if defined(ESP8266) 14 | #define IRQ_PIN 2 15 | #elif defined(ESP32) && !defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2) 16 | #define IRQ_PIN 14 17 | #elif defined(ARDUINO_NRF52832_FEATHER) 18 | #define IRQ_PIN 27 19 | #elif defined(TEENSYDUINO) 20 | #define IRQ_PIN 8 21 | #elif defined(ARDUINO_ARCH_WICED) 22 | #define IRQ_PIN PC5 23 | #else 24 | #define IRQ_PIN 5 25 | #endif 26 | 27 | void setup() { 28 | Serial.begin(115200); 29 | 30 | while(!Serial) { 31 | delay(10); 32 | } 33 | 34 | Serial.println("Joy FeatherWing example!"); 35 | 36 | if(!ss.begin(0x49)){ 37 | Serial.println("ERROR! seesaw not found"); 38 | while(1) delay(1); 39 | } else { 40 | Serial.println("seesaw started"); 41 | Serial.print("version: "); 42 | Serial.println(ss.getVersion(), HEX); 43 | } 44 | ss.pinModeBulk(button_mask, INPUT_PULLUP); 45 | ss.setGPIOInterrupts(button_mask, 1); 46 | 47 | pinMode(IRQ_PIN, INPUT); 48 | } 49 | 50 | 51 | int last_x = 0, last_y = 0; 52 | 53 | void loop() { 54 | int x = ss.analogRead(2); 55 | int y = ss.analogRead(3); 56 | 57 | if ( (abs(x - last_x) > 3) || (abs(y - last_y) > 3)) { 58 | Serial.print(x); Serial.print(", "); Serial.println(y); 59 | last_x = x; 60 | last_y = y; 61 | } 62 | 63 | /* if(!digitalRead(IRQ_PIN)) { // Uncomment to use IRQ */ 64 | 65 | uint32_t buttons = ss.digitalReadBulk(button_mask); 66 | 67 | //Serial.println(buttons, BIN); 68 | 69 | if (! (buttons & (1 << BUTTON_RIGHT))) { 70 | Serial.println("Button A pressed"); 71 | } 72 | if (! (buttons & (1 << BUTTON_DOWN))) { 73 | Serial.println("Button B pressed"); 74 | } 75 | if (! (buttons & (1 << BUTTON_LEFT))) { 76 | Serial.println("Button Y pressed"); 77 | } 78 | if (! (buttons & (1 << BUTTON_UP))) { 79 | Serial.println("Button X pressed"); 80 | } 81 | if (! (buttons & (1 << BUTTON_SEL))) { 82 | Serial.println("Button SEL pressed"); 83 | } 84 | /* } // Uncomment to use IRQ */ 85 | delay(10); 86 | } 87 | -------------------------------------------------------------------------------- /examples/joy_featherwing/joy_wing_oled/joy_wing_oled.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // Hardware-specific library 4 | #include 5 | #include "Adafruit_seesaw.h" 6 | 7 | Adafruit_seesaw ss; 8 | #define BUTTON_RIGHT 6 9 | #define BUTTON_DOWN 7 10 | #define BUTTON_LEFT 9 11 | #define BUTTON_UP 10 12 | #define BUTTON_START 14 13 | uint32_t button_mask = (1 << BUTTON_RIGHT) | (1 << BUTTON_DOWN) | 14 | (1 << BUTTON_LEFT) | (1 << BUTTON_UP) | (1 << BUTTON_START); 15 | #if defined(ESP8266) 16 | #define IRQ_PIN 2 17 | #elif defined(ESP32) && !defined(ARDUINO_ADAFRUIT_FEATHER_ESP32S2) 18 | #define IRQ_PIN 14 19 | #elif defined(ARDUINO_NRF52832_FEATHER) 20 | #define IRQ_PIN 27 21 | #elif defined(TEENSYDUINO) 22 | #define IRQ_PIN 8 23 | #elif defined(ARDUINO_ARCH_WICED) 24 | #define IRQ_PIN PC5 25 | #else 26 | #define IRQ_PIN 5 27 | #endif 28 | 29 | // For the breakout, you can use any 2 or 3 pins 30 | // These pins will also work for the 1.8" TFT shield 31 | #define TFT_CS 6 32 | #define TFT_DC 10 33 | #define TFT_RST 9 // you can also connect this to the Arduino reset 34 | // in which case, set this #define pin to -1! 35 | 36 | Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); 37 | 38 | void setup() { 39 | //while (!Serial); 40 | Serial.begin(115200); 41 | 42 | if(!ss.begin(0x49)){ 43 | Serial.println("ERROR!"); 44 | while(1) delay(1); 45 | } 46 | else{ 47 | Serial.println("seesaw started"); 48 | Serial.print("version: "); 49 | Serial.println(ss.getVersion(), HEX); 50 | } 51 | ss.pinModeBulk(button_mask, INPUT_PULLUP); 52 | ss.setGPIOInterrupts(button_mask, 1); 53 | pinMode(IRQ_PIN, INPUT); 54 | 55 | Serial.println(F("TFT TIME")); 56 | 57 | tft.initR(INITR_MINI160x80); // initialize a ST7735S chip, mini display 58 | Serial.println("Initialized"); 59 | tft.setRotation(1); 60 | 61 | uint16_t time = millis(); 62 | tft.fillScreen(ST7735_BLACK); 63 | time = millis() - time; 64 | 65 | Serial.println(time, DEC); 66 | delay(500); 67 | 68 | // large block of text 69 | tft.fillScreen(ST7735_BLACK); 70 | } 71 | 72 | int last_x = 0, last_y = 0; 73 | void loop() { 74 | int y = ss.analogRead(2); 75 | int x = ss.analogRead(3); 76 | 77 | if(x > 600 && last_x < 600){ 78 | tft.fillTriangle(120, 30, 120, 50, 110, 40, ST7735_WHITE); 79 | Serial.println(F("LEFT")); 80 | } 81 | else if(last_x > 600 && x < 600){ 82 | tft.fillTriangle(120, 30, 120, 50, 110, 40, ST7735_BLACK); 83 | } 84 | 85 | if(x < 400 && last_x > 400){ 86 | tft.fillTriangle(150, 30, 150, 50, 160, 40, ST7735_WHITE); 87 | Serial.println(F("RIGHT")); 88 | } 89 | else if(last_x < 400 && x > 400){ 90 | tft.fillTriangle(150, 30, 150, 50, 160, 40, ST7735_BLACK); 91 | } 92 | 93 | if(y > 600 && last_y < 600){ 94 | tft.fillTriangle(125, 26, 145, 26, 135, 16, ST7735_WHITE); 95 | Serial.println(F("DOWN")); 96 | } 97 | else if(last_y > 600 && y < 600){ 98 | tft.fillTriangle(125, 26, 145, 26, 135, 16, ST7735_BLACK); 99 | } 100 | 101 | if(y < 400 && last_y > 400){ 102 | tft.fillTriangle(125, 53, 145, 53, 135, 63, ST7735_WHITE); 103 | Serial.println(F("UP")); 104 | } 105 | else if(last_y < 400 && y > 400){ 106 | tft.fillTriangle(125, 53, 145, 53, 135, 63, ST7735_BLACK); 107 | } 108 | 109 | if ( (abs(x - last_x) > 3) || (abs(y - last_y) > 3)) { 110 | Serial.print(x); Serial.print(", "); Serial.println(y); 111 | last_x = x; 112 | last_y = y; 113 | } 114 | 115 | if(!digitalRead(IRQ_PIN)){ 116 | uint32_t buttons = ss.digitalReadBulk(button_mask); 117 | //Serial.println(buttons, BIN); 118 | if (! (buttons & (1 << BUTTON_DOWN))) { 119 | tft.fillCircle(30, 18, 10, ST7735_GREEN); 120 | Serial.println("B"); 121 | } 122 | else tft.fillCircle(30, 18, 10, ST7735_BLACK); 123 | 124 | if (! (buttons & (1 << BUTTON_RIGHT))) { 125 | tft.fillCircle(10, 40, 10, ST7735_RED); 126 | Serial.println("A"); 127 | } 128 | else tft.fillCircle(10, 40, 10, ST7735_BLACK); 129 | 130 | if (! (buttons & (1 << BUTTON_LEFT))) { 131 | tft.fillCircle(50, 40, 10, ST7735_BLUE); 132 | Serial.println("Y"); 133 | } 134 | else tft.fillCircle(50, 40, 10, ST7735_BLACK); 135 | 136 | if (! (buttons & (1 << BUTTON_UP))) { 137 | tft.fillCircle(30, 57, 10, ST7735_YELLOW); 138 | Serial.println("X"); 139 | } 140 | else tft.fillCircle(30, 57, 10, ST7735_BLACK); 141 | 142 | if (! (buttons & (1 << BUTTON_START))) { 143 | tft.fillCircle(80, 40, 7, ST7735_WHITE); 144 | Serial.println(F("START")); 145 | } 146 | else tft.fillCircle(80, 40, 7, ST7735_BLACK); 147 | } 148 | delay(10); 149 | } 150 | -------------------------------------------------------------------------------- /examples/soil_sensor/soilsensor_example/soilsensor_example.ino: -------------------------------------------------------------------------------- 1 | #include "Adafruit_seesaw.h" 2 | 3 | Adafruit_seesaw ss; 4 | 5 | void setup() { 6 | Serial.begin(115200); 7 | 8 | Serial.println("seesaw Soil Sensor example!"); 9 | 10 | if (!ss.begin(0x36)) { 11 | Serial.println("ERROR! seesaw not found"); 12 | while(1) delay(1); 13 | } else { 14 | Serial.print("seesaw started! version: "); 15 | Serial.println(ss.getVersion(), HEX); 16 | } 17 | } 18 | 19 | void loop() { 20 | float tempC = ss.getTemp(); 21 | uint16_t capread = ss.touchRead(0); 22 | 23 | Serial.print("Temperature: "); Serial.print(tempC); Serial.println("*C"); 24 | Serial.print("Capacitive: "); Serial.println(capread); 25 | delay(100); 26 | } 27 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Adafruit seesaw Library 2 | version=1.7.9 3 | author=Adafruit 4 | maintainer=Adafruit 5 | sentence=This is a library for the Adafruit seesaw helper IC. 6 | paragraph=This is a library for the Adafruit seesaw helper IC. 7 | category=Other 8 | url=https://github.com/adafruit/Adafruit_Seesaw 9 | architectures=* 10 | depends=Adafruit BusIO, Adafruit ST7735 and ST7789 Library 11 | -------------------------------------------------------------------------------- /seesaw_motor.h: -------------------------------------------------------------------------------- 1 | #ifndef _SEESAW_MOTOR_H 2 | #define _SEESAW_MOTOR_H 3 | 4 | #include "Adafruit_seesaw.h" 5 | 6 | /**************************************************************************/ 7 | /*! 8 | @brief Class that stores state and functions for seesaw motor interface 9 | */ 10 | /**************************************************************************/ 11 | class seesaw_Motor { 12 | public: 13 | /**************************************************************************/ 14 | /*! 15 | @brief class constructor 16 | @param ss the seesaw object to use 17 | */ 18 | /**************************************************************************/ 19 | seesaw_Motor(Adafruit_seesaw *ss) { 20 | _ss = ss; 21 | _pina = -1; 22 | _pinb = -1; 23 | _throttle = 0; 24 | } 25 | 26 | ~seesaw_Motor() {} 27 | 28 | /**************************************************************************/ 29 | /*! 30 | @brief attach the motor to the specified PWM pins 31 | @param pina the positive pin to use 32 | @param pinb the negative pin to use 33 | */ 34 | /**************************************************************************/ 35 | void attach(int pina, int pinb) { 36 | _pina = pina; 37 | _pinb = pinb; 38 | } 39 | 40 | /**************************************************************************/ 41 | /*! 42 | @brief set the throttle 43 | @param value the throttle value to set between -1 and 1. Passing 0 will turn 44 | the motor off. 45 | */ 46 | /**************************************************************************/ 47 | void throttle(float value) { 48 | if (_pina < 0 || _pinb < 0) 49 | return; 50 | 51 | value = constrain(value, -1.0, 1.0); 52 | _throttle = value; 53 | uint16_t absolute = fabs(value) * 65535; 54 | 55 | if (value > 0) { 56 | _ss->analogWrite(_pina, 0); 57 | _ss->analogWrite(_pinb, absolute); 58 | } else if (value < 0) { 59 | _ss->analogWrite(_pina, absolute); 60 | _ss->analogWrite(_pinb, 0); 61 | } else { 62 | // both are off 63 | _ss->analogWrite(_pina, 0); 64 | _ss->analogWrite(_pinb, 0); 65 | } 66 | } 67 | 68 | /**************************************************************************/ 69 | /*! 70 | @brief get the current throttle value 71 | @returns the current throttle value between -1 and 1 72 | */ 73 | /**************************************************************************/ 74 | float getThrottle() { return _throttle; } 75 | 76 | private: 77 | Adafruit_seesaw *_ss; 78 | int8_t _pina, _pinb; 79 | float _throttle; 80 | }; 81 | 82 | #endif -------------------------------------------------------------------------------- /seesaw_neopixel.cpp: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | Arduino library to control a wide variety of WS2811- and WS2812-based RGB 3 | LED devices such as Adafruit FLORA RGB Smart Pixels and NeoPixel strips. 4 | Currently handles 400 and 800 KHz bitstreams on 8, 12 and 16 MHz ATmega 5 | MCUs, with LEDs wired for various color orders. Handles most output pins 6 | (possible exception with upper PORT registers on the Arduino Mega). 7 | Written by Phil Burgess / Paint Your Dragon for Adafruit Industries, 8 | contributions by PJRC, Michael Miller and other members of the open 9 | source community. 10 | Adafruit invests time and resources providing this open source code, 11 | please support Adafruit and open-source hardware by purchasing products 12 | from Adafruit! 13 | ------------------------------------------------------------------------- 14 | This file is part of the Adafruit NeoPixel library. 15 | NeoPixel is free software: you can redistribute it and/or modify 16 | it under the terms of the GNU Lesser General Public License as 17 | published by the Free Software Foundation, either version 3 of 18 | the License, or (at your option) any later version. 19 | NeoPixel is distributed in the hope that it will be useful, 20 | but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | GNU Lesser General Public License for more details. 23 | You should have received a copy of the GNU Lesser General Public 24 | License along with NeoPixel. If not, see 25 | . 26 | -------------------------------------------------------------------------*/ 27 | 28 | #include "seesaw_neopixel.h" 29 | #include "Adafruit_seesaw.h" 30 | 31 | // Constructor when length, pin and type are known at compile-time: 32 | seesaw_NeoPixel::seesaw_NeoPixel(uint16_t n, uint8_t p, neoPixelType t, 33 | TwoWire *Wi) 34 | : Adafruit_seesaw(Wi), begun(false), numLEDs(n), pin(p), brightness(0), 35 | pixels(NULL), endTime(0), type(t) {} 36 | 37 | // via Michael Vogt/neophob: empty constructor is used when strand length 38 | // isn't known at compile-time; situations where program config might be 39 | // read from internal flash memory or an SD card, or arrive via serial 40 | // command. If using this constructor, MUST follow up with updateType(), 41 | // updateLength(), etc. to establish the strand type, length and pin number! 42 | seesaw_NeoPixel::seesaw_NeoPixel(TwoWire *Wi) 43 | : Adafruit_seesaw(Wi), 44 | #ifdef NEO_KHZ400 45 | is800KHz(true), 46 | #endif 47 | begun(false), numLEDs(0), numBytes(0), pin(-1), brightness(0), 48 | pixels(NULL), rOffset(1), gOffset(0), bOffset(2), wOffset(1), endTime(0) { 49 | } 50 | 51 | seesaw_NeoPixel::~seesaw_NeoPixel() { 52 | if (pixels) 53 | free(pixels); 54 | } 55 | 56 | bool seesaw_NeoPixel::begin(uint8_t addr, int8_t flow) { 57 | if (!Adafruit_seesaw::begin(addr, flow)) 58 | return false; 59 | 60 | updateType(type); 61 | updateLength(numLEDs); 62 | setPin(pin); 63 | 64 | return true; 65 | } 66 | 67 | void seesaw_NeoPixel::updateLength(uint16_t n) { 68 | if (pixels) 69 | free(pixels); // Free existing data (if any) 70 | 71 | // Allocate new data -- note: ALL PIXELS ARE CLEARED 72 | numBytes = n * ((wOffset == rOffset) ? 3 : 4); 73 | if ((pixels = (uint8_t *)malloc(numBytes))) { 74 | memset(pixels, 0, numBytes); 75 | numLEDs = n; 76 | } else { 77 | numLEDs = numBytes = 0; 78 | } 79 | 80 | uint8_t buf[] = {(uint8_t)(numBytes >> 8), (uint8_t)(numBytes & 0xFF)}; 81 | this->write(SEESAW_NEOPIXEL_BASE, SEESAW_NEOPIXEL_BUF_LENGTH, buf, 2); 82 | } 83 | 84 | void seesaw_NeoPixel::updateType(neoPixelType t) { 85 | boolean oldThreeBytesPerPixel = (wOffset == rOffset); // false if RGBW 86 | 87 | wOffset = (t >> 6) & 0b11; // See notes in header file 88 | rOffset = (t >> 4) & 0b11; // regarding R/G/B/W offsets 89 | gOffset = (t >> 2) & 0b11; 90 | bOffset = t & 0b11; 91 | is800KHz = (t < 256); // 400 KHz flag is 1<<8 92 | 93 | this->write8(SEESAW_NEOPIXEL_BASE, SEESAW_NEOPIXEL_SPEED, is800KHz); 94 | 95 | // If bytes-per-pixel has changed (and pixel data was previously 96 | // allocated), re-allocate to new size. Will clear any data. 97 | if (pixels) { 98 | boolean newThreeBytesPerPixel = (wOffset == rOffset); 99 | if (newThreeBytesPerPixel != oldThreeBytesPerPixel) 100 | updateLength(numLEDs); 101 | } 102 | } 103 | 104 | void seesaw_NeoPixel::show(void) { 105 | 106 | if (!pixels) 107 | return; 108 | 109 | // Data latch = 300+ microsecond pause in the output stream. Rather than 110 | // put a delay at the end of the function, the ending time is noted and 111 | // the function will simply hold off (if needed) on issuing the 112 | // subsequent round of data until the latch time has elapsed. This 113 | // allows the mainline code to start generating the next frame of data 114 | // rather than stalling for the latch. 115 | while (!canShow()) 116 | ; 117 | 118 | this->write(SEESAW_NEOPIXEL_BASE, SEESAW_NEOPIXEL_SHOW, NULL, 0); 119 | 120 | endTime = micros(); // Save EOD time for latch on next call 121 | } 122 | 123 | // Set the output pin number 124 | void seesaw_NeoPixel::setPin(uint8_t p) { 125 | this->write8(SEESAW_NEOPIXEL_BASE, SEESAW_NEOPIXEL_PIN, p); 126 | pin = p; 127 | } 128 | 129 | // Set pixel color from separate R,G,B components: 130 | void seesaw_NeoPixel::setPixelColor(uint16_t n, uint8_t r, uint8_t g, 131 | uint8_t b) { 132 | 133 | if (n < numLEDs) { 134 | if (brightness) { // See notes in setBrightness() 135 | r = (r * brightness) >> 8; 136 | g = (g * brightness) >> 8; 137 | b = (b * brightness) >> 8; 138 | } 139 | uint8_t *p; 140 | if (wOffset == rOffset) { // Is an RGB-type strip 141 | p = &pixels[n * 3]; // 3 bytes per pixel 142 | } else { // Is a WRGB-type strip 143 | p = &pixels[n * 4]; // 4 bytes per pixel 144 | p[wOffset] = 0; // But only R,G,B passed -- set W to 0 145 | } 146 | p[rOffset] = r; // R,G,B always stored 147 | p[gOffset] = g; 148 | p[bOffset] = b; 149 | 150 | uint8_t len = (wOffset == rOffset ? 3 : 4); 151 | uint16_t offset = n * len; 152 | 153 | uint8_t writeBuf[6]; 154 | writeBuf[0] = (offset >> 8); 155 | writeBuf[1] = offset; 156 | memcpy(&writeBuf[2], p, len); 157 | 158 | this->write(SEESAW_NEOPIXEL_BASE, SEESAW_NEOPIXEL_BUF, writeBuf, len + 2); 159 | } 160 | } 161 | 162 | void seesaw_NeoPixel::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, 163 | uint8_t w) { 164 | 165 | if (n < numLEDs) { 166 | if (brightness) { // See notes in setBrightness() 167 | r = (r * brightness) >> 8; 168 | g = (g * brightness) >> 8; 169 | b = (b * brightness) >> 8; 170 | w = (w * brightness) >> 8; 171 | } 172 | uint8_t *p; 173 | if (wOffset == rOffset) { // Is an RGB-type strip 174 | p = &pixels[n * 3]; // 3 bytes per pixel (ignore W) 175 | } else { // Is a WRGB-type strip 176 | p = &pixels[n * 4]; // 4 bytes per pixel 177 | p[wOffset] = w; // Store W 178 | } 179 | p[rOffset] = r; // Store R,G,B 180 | p[gOffset] = g; 181 | p[bOffset] = b; 182 | 183 | uint8_t len = (wOffset == rOffset ? 3 : 4); 184 | uint16_t offset = n * len; 185 | 186 | uint8_t writeBuf[6]; 187 | writeBuf[0] = (offset >> 8); 188 | writeBuf[1] = offset; 189 | memcpy(&writeBuf[2], p, len); 190 | 191 | this->write(SEESAW_NEOPIXEL_BASE, SEESAW_NEOPIXEL_BUF, writeBuf, len + 2); 192 | } 193 | } 194 | 195 | // Set pixel color from 'packed' 32-bit RGB color: 196 | void seesaw_NeoPixel::setPixelColor(uint16_t n, uint32_t c) { 197 | if (n < numLEDs) { 198 | uint8_t *p, r = (uint8_t)(c >> 16), g = (uint8_t)(c >> 8), b = (uint8_t)c; 199 | if (brightness) { // See notes in setBrightness() 200 | r = (r * brightness) >> 8; 201 | g = (g * brightness) >> 8; 202 | b = (b * brightness) >> 8; 203 | } 204 | if (wOffset == rOffset) { 205 | p = &pixels[n * 3]; 206 | } else { 207 | p = &pixels[n * 4]; 208 | uint8_t w = (uint8_t)(c >> 24); 209 | p[wOffset] = brightness ? ((w * brightness) >> 8) : w; 210 | } 211 | p[rOffset] = r; 212 | p[gOffset] = g; 213 | p[bOffset] = b; 214 | 215 | uint8_t len = (wOffset == rOffset ? 3 : 4); 216 | uint16_t offset = n * len; 217 | 218 | uint8_t writeBuf[6]; 219 | writeBuf[0] = (offset >> 8); 220 | writeBuf[1] = offset; 221 | memcpy(&writeBuf[2], p, len); 222 | 223 | this->write(SEESAW_NEOPIXEL_BASE, SEESAW_NEOPIXEL_BUF, writeBuf, len + 2); 224 | } 225 | } 226 | 227 | // Convert separate R,G,B into packed 32-bit RGB color. 228 | // Packed format is always RGB, regardless of LED strand color order. 229 | uint32_t seesaw_NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b) { 230 | return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; 231 | } 232 | 233 | // Convert separate R,G,B,W into packed 32-bit WRGB color. 234 | // Packed format is always WRGB, regardless of LED strand color order. 235 | uint32_t seesaw_NeoPixel::Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { 236 | return ((uint32_t)w << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; 237 | } 238 | 239 | // Query color from previously-set pixel (returns packed 32-bit RGB value) 240 | uint32_t seesaw_NeoPixel::getPixelColor(uint16_t n) const { 241 | if (n >= numLEDs) 242 | return 0; // Out of bounds, return no color. 243 | 244 | uint8_t *p; 245 | 246 | if (wOffset == rOffset) { // Is RGB-type device 247 | p = &pixels[n * 3]; 248 | if (brightness) { 249 | // Stored color was decimated by setBrightness(). Returned value 250 | // attempts to scale back to an approximation of the original 24-bit 251 | // value used when setting the pixel color, but there will always be 252 | // some error -- those bits are simply gone. Issue is most 253 | // pronounced at low brightness levels. 254 | return (((uint32_t)(p[rOffset] << 8) / brightness) << 16) | 255 | (((uint32_t)(p[gOffset] << 8) / brightness) << 8) | 256 | ((uint32_t)(p[bOffset] << 8) / brightness); 257 | } else { 258 | // No brightness adjustment has been made -- return 'raw' color 259 | return ((uint32_t)p[rOffset] << 16) | ((uint32_t)p[gOffset] << 8) | 260 | (uint32_t)p[bOffset]; 261 | } 262 | } else { // Is RGBW-type device 263 | p = &pixels[n * 4]; 264 | if (brightness) { // Return scaled color 265 | return (((uint32_t)(p[wOffset] << 8) / brightness) << 24) | 266 | (((uint32_t)(p[rOffset] << 8) / brightness) << 16) | 267 | (((uint32_t)(p[gOffset] << 8) / brightness) << 8) | 268 | ((uint32_t)(p[bOffset] << 8) / brightness); 269 | } else { // Return raw color 270 | return ((uint32_t)p[wOffset] << 24) | ((uint32_t)p[rOffset] << 16) | 271 | ((uint32_t)p[gOffset] << 8) | (uint32_t)p[bOffset]; 272 | } 273 | } 274 | } 275 | 276 | // Returns pointer to pixels[] array. Pixel data is stored in device- 277 | // native format and is not translated here. Application will need to be 278 | // aware of specific pixel data format and handle colors appropriately. 279 | uint8_t *seesaw_NeoPixel::getPixels(void) const { return pixels; } 280 | 281 | uint16_t seesaw_NeoPixel::numPixels(void) const { return numLEDs; } 282 | 283 | void seesaw_NeoPixel::clear() { 284 | // Clear local pixel buffer 285 | memset(pixels, 0, numBytes); 286 | 287 | // Now clear the pixels on the seesaw 288 | uint8_t writeBuf[32]; 289 | memset(writeBuf, 0, 32); 290 | for (uint8_t offset = 0; offset < numBytes; offset += 32 - 4) { 291 | writeBuf[0] = (offset >> 8); 292 | writeBuf[1] = offset; 293 | this->write(SEESAW_NEOPIXEL_BASE, SEESAW_NEOPIXEL_BUF, writeBuf, 32); 294 | } 295 | } 296 | 297 | void seesaw_NeoPixel::setBrightness(uint8_t b) { brightness = b; } 298 | -------------------------------------------------------------------------------- /seesaw_neopixel.h: -------------------------------------------------------------------------------- 1 | /*-------------------------------------------------------------------- 2 | This file is part of the Adafruit NeoPixel library. 3 | NeoPixel is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU Lesser General Public License as 5 | published by the Free Software Foundation, either version 3 of 6 | the License, or (at your option) any later version. 7 | NeoPixel is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU Lesser General Public License for more details. 11 | You should have received a copy of the GNU Lesser General Public 12 | License along with NeoPixel. If not, see 13 | . 14 | --------------------------------------------------------------------*/ 15 | 16 | #ifndef SEESAW_NEOPIXEL_H 17 | #define SEESAW_NEOPIXEL_H 18 | 19 | #include "Adafruit_seesaw.h" 20 | #include 21 | 22 | // The order of primary colors in the NeoPixel data stream can vary 23 | // among device types, manufacturers and even different revisions of 24 | // the same item. The third parameter to the seesaw_NeoPixel 25 | // constructor encodes the per-pixel byte offsets of the red, green 26 | // and blue primaries (plus white, if present) in the data stream -- 27 | // the following #defines provide an easier-to-use named version for 28 | // each permutation. e.g. NEO_GRB indicates a NeoPixel-compatible 29 | // device expecting three bytes per pixel, with the first byte 30 | // containing the green value, second containing red and third 31 | // containing blue. The in-memory representation of a chain of 32 | // NeoPixels is the same as the data-stream order; no re-ordering of 33 | // bytes is required when issuing data to the chain. 34 | 35 | // Bits 5,4 of this value are the offset (0-3) from the first byte of 36 | // a pixel to the location of the red color byte. Bits 3,2 are the 37 | // green offset and 1,0 are the blue offset. If it is an RGBW-type 38 | // device (supporting a white primary in addition to R,G,B), bits 7,6 39 | // are the offset to the white byte...otherwise, bits 7,6 are set to 40 | // the same value as 5,4 (red) to indicate an RGB (not RGBW) device. 41 | // i.e. binary representation: 42 | // 0bWWRRGGBB for RGBW devices 43 | // 0bRRRRGGBB for RGB 44 | 45 | // RGB NeoPixel permutations; white and red offsets are always same 46 | // Offset: W R G B 47 | #define NEO_RGB ((0 << 6) | (0 << 4) | (1 << 2) | (2)) 48 | #define NEO_RBG ((0 << 6) | (0 << 4) | (2 << 2) | (1)) 49 | #define NEO_GRB ((1 << 6) | (1 << 4) | (0 << 2) | (2)) 50 | #define NEO_GBR ((2 << 6) | (2 << 4) | (0 << 2) | (1)) 51 | #define NEO_BRG ((1 << 6) | (1 << 4) | (2 << 2) | (0)) 52 | #define NEO_BGR ((2 << 6) | (2 << 4) | (1 << 2) | (0)) 53 | 54 | // RGBW NeoPixel permutations; all 4 offsets are distinct 55 | // Offset: W R G B 56 | #define NEO_WRGB ((0 << 6) | (1 << 4) | (2 << 2) | (3)) 57 | #define NEO_WRBG ((0 << 6) | (1 << 4) | (3 << 2) | (2)) 58 | #define NEO_WGRB ((0 << 6) | (2 << 4) | (1 << 2) | (3)) 59 | #define NEO_WGBR ((0 << 6) | (3 << 4) | (1 << 2) | (2)) 60 | #define NEO_WBRG ((0 << 6) | (2 << 4) | (3 << 2) | (1)) 61 | #define NEO_WBGR ((0 << 6) | (3 << 4) | (2 << 2) | (1)) 62 | 63 | #define NEO_RWGB ((1 << 6) | (0 << 4) | (2 << 2) | (3)) 64 | #define NEO_RWBG ((1 << 6) | (0 << 4) | (3 << 2) | (2)) 65 | #define NEO_RGWB ((2 << 6) | (0 << 4) | (1 << 2) | (3)) 66 | #define NEO_RGBW ((3 << 6) | (0 << 4) | (1 << 2) | (2)) 67 | #define NEO_RBWG ((2 << 6) | (0 << 4) | (3 << 2) | (1)) 68 | #define NEO_RBGW ((3 << 6) | (0 << 4) | (2 << 2) | (1)) 69 | 70 | #define NEO_GWRB ((1 << 6) | (2 << 4) | (0 << 2) | (3)) 71 | #define NEO_GWBR ((1 << 6) | (3 << 4) | (0 << 2) | (2)) 72 | #define NEO_GRWB ((2 << 6) | (1 << 4) | (0 << 2) | (3)) 73 | #define NEO_GRBW ((3 << 6) | (1 << 4) | (0 << 2) | (2)) 74 | #define NEO_GBWR ((2 << 6) | (3 << 4) | (0 << 2) | (1)) 75 | #define NEO_GBRW ((3 << 6) | (2 << 4) | (0 << 2) | (1)) 76 | 77 | #define NEO_BWRG ((1 << 6) | (2 << 4) | (3 << 2) | (0)) 78 | #define NEO_BWGR ((1 << 6) | (3 << 4) | (2 << 2) | (0)) 79 | #define NEO_BRWG ((2 << 6) | (1 << 4) | (3 << 2) | (0)) 80 | #define NEO_BRGW ((3 << 6) | (1 << 4) | (2 << 2) | (0)) 81 | #define NEO_BGWR ((2 << 6) | (3 << 4) | (1 << 2) | (0)) 82 | #define NEO_BGRW ((3 << 6) | (2 << 4) | (1 << 2) | (0)) 83 | 84 | // If 400 KHz support is enabled, the third parameter to the constructor 85 | // requires a 16-bit value (in order to select 400 vs 800 KHz speed). 86 | // If only 800 KHz is enabled (as is default on ATtiny), an 8-bit value 87 | // is sufficient to encode pixel color order, saving some space. 88 | 89 | #define NEO_KHZ800 0x0000 // 800 KHz datastream 90 | #define NEO_KHZ400 0x0100 // 400 KHz datastream 91 | 92 | typedef uint16_t neoPixelType; 93 | 94 | /** Adafruit_NeoPixel-compatible 'wrapper' for LED control over seesaw 95 | */ 96 | class seesaw_NeoPixel : public Adafruit_seesaw { 97 | 98 | public: 99 | seesaw_NeoPixel(uint16_t n, uint8_t p = 6, 100 | neoPixelType t = NEO_GRB + NEO_KHZ800, TwoWire *Wi = NULL); 101 | seesaw_NeoPixel(TwoWire *Wi = NULL); 102 | ~seesaw_NeoPixel(); 103 | 104 | bool begin(uint8_t addr = SEESAW_ADDRESS, int8_t flow = -1); 105 | void show(void), setPin(uint8_t p), 106 | setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b), 107 | setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w), 108 | setPixelColor(uint16_t n, uint32_t c), setBrightness(uint8_t), clear(), 109 | updateLength(uint16_t n), updateType(neoPixelType t); 110 | uint8_t *getPixels(void) const, getBrightness(void) const; 111 | int8_t getPin(void) { return pin; }; 112 | uint16_t numPixels(void) const; 113 | static uint32_t Color(uint8_t r, uint8_t g, uint8_t b), 114 | Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w); 115 | uint32_t getPixelColor(uint16_t n) const; 116 | inline bool canShow(void) { return (micros() - endTime) >= 300L; } 117 | 118 | protected: 119 | boolean is800KHz, // ...true if 800 KHz pixels 120 | begun; // true if begin() previously called 121 | uint16_t numLEDs, // Number of RGB LEDs in strip 122 | numBytes; // Size of 'pixels' buffer below (3 or 4 bytes/pixel) 123 | int8_t pin; 124 | uint8_t brightness, 125 | *pixels, // Holds LED color values (3 or 4 bytes each) 126 | rOffset, // Index of red byte within each 3- or 4-byte pixel 127 | gOffset, // Index of green byte 128 | bOffset, // Index of blue byte 129 | wOffset; // Index of white byte (same as rOffset if no white) 130 | uint32_t endTime; // Latch timing reference 131 | 132 | uint16_t type; 133 | }; 134 | 135 | #endif // seesaw_NeoPixel_H 136 | -------------------------------------------------------------------------------- /seesaw_servo.cpp: -------------------------------------------------------------------------------- 1 | #include "seesaw_servo.h" 2 | 3 | #define MIN_PULSE 3277 4 | #define MAX_PULSE 6554 5 | 6 | /**************************************************************************/ 7 | /*! 8 | @brief begin the seesaw. This is only necessary if the seesaw is not 9 | already started 10 | @param addr the address to begin on 11 | @param flow the flow control pin to use 12 | @returns true on success, false otherwise 13 | */ 14 | /**************************************************************************/ 15 | bool seesaw_Servo::begin(uint8_t addr, int8_t flow) { 16 | return _ss->begin(addr, flow); 17 | } 18 | 19 | /**************************************************************************/ 20 | /*! 21 | @brief attach the given pin to the next free channel, sets pinMode. 22 | @param pin the pin to use 23 | 24 | @returns 0 25 | */ 26 | /**************************************************************************/ 27 | uint8_t seesaw_Servo::attach(int pin) { 28 | _pin = pin; 29 | // set frequency to 50 hz 30 | _ss->setPWMFreq(_pin, 50); 31 | _attached = true; 32 | min = MIN_PULSE; 33 | max = MAX_PULSE; 34 | return 0; 35 | } 36 | 37 | /**************************************************************************/ 38 | /*! 39 | @brief attach the given pin to the next free channel but also sets min and 40 | max values for writes. 41 | @param pin the pin to use 42 | @param min the minimum pulse width value in microseconds 43 | @param max the maximum pulse width value in microseconds 44 | @returns 0 45 | */ 46 | /**************************************************************************/ 47 | uint8_t seesaw_Servo::attach(int pin, int min, int max) { 48 | attach(pin); 49 | this->min = min * 3.2767; 50 | this->max = max * 3.2767; 51 | 52 | return 0; 53 | } 54 | 55 | /**************************************************************************/ 56 | /*! 57 | @brief write a value. if value is < 200 its treated as an angle, otherwise 58 | as pulse width in microseconds 59 | @param value the value to write 60 | */ 61 | /**************************************************************************/ 62 | void seesaw_Servo::write(int value) { 63 | if (value < 200) { 64 | // angle 65 | uint16_t val = map(value, 0, 180, min, max); 66 | val = constrain(val, min, max); 67 | _ss->analogWrite(_pin, val); 68 | _sval = val; 69 | } else 70 | writeMicroseconds(value); 71 | } 72 | 73 | /**************************************************************************/ 74 | /*! 75 | @brief get current value 76 | @returns current pulse width as an angle between 0 and 180 degrees 77 | */ 78 | /**************************************************************************/ 79 | int seesaw_Servo::read() { return map(_sval, MIN_PULSE, MAX_PULSE, 0, 180); } 80 | 81 | /**************************************************************************/ 82 | /*! 83 | @brief Write pulse width in microseconds 84 | @param value the value to write 85 | */ 86 | /**************************************************************************/ 87 | void seesaw_Servo::writeMicroseconds(int value) { 88 | uint16_t val = 3.2767 * value; 89 | _ss->analogWrite(_pin, val); 90 | _sval = val; 91 | } -------------------------------------------------------------------------------- /seesaw_servo.h: -------------------------------------------------------------------------------- 1 | #ifndef _SEESAW_SERVO_H 2 | #define _SEESAW_SERVO_H 3 | 4 | #include "Adafruit_seesaw.h" 5 | 6 | /**************************************************************************/ 7 | /*! 8 | @brief Class that stores state and functions for seesaw servo interface 9 | */ 10 | /**************************************************************************/ 11 | class seesaw_Servo { 12 | 13 | public: 14 | /**************************************************************************/ 15 | /*! 16 | @brief class constructor 17 | @param ss the seesaw object to use 18 | */ 19 | /**************************************************************************/ 20 | seesaw_Servo(Adafruit_seesaw *ss) { 21 | _ss = ss; 22 | _attached = false; 23 | } 24 | 25 | ~seesaw_Servo() {} 26 | bool begin(uint8_t addr = SEESAW_ADDRESS, int8_t flow = -1); 27 | 28 | uint8_t attach(int pin); 29 | uint8_t attach(int pin, int min, int max); 30 | 31 | /**************************************************************************/ 32 | /*! 33 | @brief set attached to false 34 | */ 35 | /**************************************************************************/ 36 | void detach() { _attached = false; } 37 | void write(int value); 38 | void writeMicroseconds(int value); 39 | int read(); 40 | 41 | /**************************************************************************/ 42 | /*! 43 | @brief get current value in microseconds 44 | @returns current pulse width in microseconds for this servo 45 | */ 46 | /**************************************************************************/ 47 | int readMicroseconds() { return _sval / 3.2768; } 48 | 49 | /**************************************************************************/ 50 | /*! 51 | @brief check if the servo is attached yet 52 | @returns true if this servo is attached, otherwise false 53 | */ 54 | /**************************************************************************/ 55 | bool attached() { return _attached; } 56 | 57 | private: 58 | Adafruit_seesaw *_ss; 59 | bool _attached; 60 | uint16_t _sval; 61 | uint8_t _pin; 62 | uint16_t min; 63 | uint16_t max; 64 | }; 65 | 66 | #endif -------------------------------------------------------------------------------- /seesaw_spectrum.cpp: -------------------------------------------------------------------------------- 1 | #include "seesaw_spectrum.h" 2 | 3 | /**************************************************************************/ 4 | /*! 5 | @brief Pull latest audio spectrum data from device. 6 | */ 7 | /**************************************************************************/ 8 | void seesaw_Audio_Spectrum::getData(void) { 9 | read(SEESAW_SPECTRUM_BASE, SEESAW_SPECTRUM_RESULTS_LOWER, bins, 32, 0); 10 | read(SEESAW_SPECTRUM_BASE, SEESAW_SPECTRUM_RESULTS_UPPER, &bins[32], 32, 0); 11 | } 12 | 13 | /**************************************************************************/ 14 | /*! 15 | @brief Set the audio sampling rate. 16 | @param value Sampling rate index, 0-31. Values outside this range 17 | will be clipped on the Seesaw device side. 18 | */ 19 | /**************************************************************************/ 20 | void seesaw_Audio_Spectrum::setRate(uint8_t value) { 21 | write8(SEESAW_SPECTRUM_BASE, SEESAW_SPECTRUM_RATE, value); 22 | } 23 | 24 | /**************************************************************************/ 25 | /*! 26 | @brief Set the analog input channel. 27 | @param value Channel index, 0-TBD (probably 1). Values outside the 28 | valid range will be clipped on the Seesaw device side. 29 | */ 30 | /**************************************************************************/ 31 | void seesaw_Audio_Spectrum::setChannel(uint8_t value) { 32 | write8(SEESAW_SPECTRUM_BASE, SEESAW_SPECTRUM_CHANNEL, value); 33 | } 34 | 35 | /**************************************************************************/ 36 | /*! 37 | @brief Query the current audio sampling rate. 38 | @return Sampling rate index, 0-31. 39 | */ 40 | /**************************************************************************/ 41 | uint8_t seesaw_Audio_Spectrum::getRate(void) { 42 | return read8(SEESAW_SPECTRUM_BASE, SEESAW_SPECTRUM_RATE); 43 | } 44 | 45 | /**************************************************************************/ 46 | /*! 47 | @brief Query the current analog input channel. 48 | @return Active ADC channel, 0-TBD (probably 1). 49 | */ 50 | /**************************************************************************/ 51 | uint8_t seesaw_Audio_Spectrum::getChannel(void) { 52 | return read8(SEESAW_SPECTRUM_BASE, SEESAW_SPECTRUM_CHANNEL); 53 | } 54 | -------------------------------------------------------------------------------- /seesaw_spectrum.h: -------------------------------------------------------------------------------- 1 | #ifndef _SEESAW_SPECTRUM_H 2 | #define _SEESAW_SPECTRUM_H 3 | 4 | #include "Adafruit_seesaw.h" 5 | #include 6 | 7 | /**************************************************************************/ 8 | /*! 9 | @brief Class that stores state and functions for seesaw audio spectrum 10 | interface 11 | */ 12 | /**************************************************************************/ 13 | class seesaw_Audio_Spectrum : public Adafruit_seesaw { 14 | public: 15 | /**************************************************************************/ 16 | /*! 17 | @brief seesaw_Audio_Spectrum class constructor. 18 | @param Wi TwoWire interface this works through. 19 | */ 20 | /**************************************************************************/ 21 | seesaw_Audio_Spectrum(TwoWire *Wi = NULL) : Adafruit_seesaw(Wi) {} 22 | 23 | ~seesaw_Audio_Spectrum() {} 24 | 25 | /**************************************************************************/ 26 | /*! 27 | @brief Begin communication with Seesaw audio spectrum device. 28 | @param addr Optional i2c address where the device can be found. 29 | Defaults to SEESAW_ADDRESS. 30 | @param flow Optional flow control pin. 31 | @return true on success, false on error. 32 | */ 33 | /**************************************************************************/ 34 | bool begin(uint8_t addr = SEESAW_ADDRESS, int8_t flow = -1) { 35 | if (Adafruit_seesaw::begin(addr, flow)) { 36 | memset(bins, 0, sizeof bins); 37 | return true; 38 | } 39 | return false; 40 | } 41 | 42 | void getData(void); // Fetch latest audio spectrum data 43 | void setRate(uint8_t value); // Set audio sampling rate 0-31 44 | void setChannel(uint8_t value); // Set ADC input channel 45 | uint8_t getRate(void); // Query current audio sampling rate 0-31 46 | uint8_t getChannel(void); // Query current ADC channel 47 | 48 | /**************************************************************************/ 49 | /*! 50 | @brief Get value of individual spectrum bin, as determined during 51 | most recent get_data() call. 52 | @param idx Spectrum bin index (0-63) to query. 53 | @return Level: 0 (silent) to 255 (loudest) for bin. 54 | */ 55 | /**************************************************************************/ 56 | uint8_t getLevel(uint8_t idx) const { return bins[idx < 64 ? idx : 63]; } 57 | 58 | /**************************************************************************/ 59 | /*! 60 | @brief Get pointer to spectrum bin buffer directly. Use with caution! 61 | @return uint8_t base pointer to 64 spectrum bins. 62 | */ 63 | /**************************************************************************/ 64 | uint8_t *getBuffer(void) const { return (uint8_t *)bins; } 65 | 66 | private: 67 | uint8_t bins[64]; // Audio spectrum "bins" 68 | }; 69 | 70 | #endif // end _SEESAW_SPECTRUM_H 71 | --------------------------------------------------------------------------------