├── .travis.yml ├── README.md ├── examples ├── battery │ └── battery.ino ├── demo │ └── demo.ino ├── pixels_pattern │ └── pixels_pattern.ino ├── rainbow │ └── rainbow.ino ├── sound │ └── sound.ino └── touch │ └── touch.ino ├── keywords.txt ├── pixels.cpp ├── pixels.h ├── platformio.ini ├── respeaker.cpp └── respeaker.h /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | 5 | # Cache PlatformIO packages using Travis CI container-based infrastructure 6 | sudo: false 7 | cache: 8 | directories: 9 | - "~/.platformio" 10 | 11 | install: 12 | - pip install -U platformio 13 | 14 | script: 15 | - platformio run -v -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ReSpeaker Arduino Library 2 | ========================= 3 | 4 | [![Build Status](https://travis-ci.org/respeaker/respeaker_arduino_library.svg?branch=master)](https://travis-ci.org/respeaker/respeaker_arduino_library) 5 | 6 | ### Features 7 | + supported capacitive touch sensing 8 | + implemented WS2812 RGB LED driver 9 | + built USB to Serial bridge and SPI bridge between Arduino (ATmega32U4) and linux based OpenWrt (MT7688) 10 | 11 | ### Requirements 12 | + Arduino IDE 1.6.8+. Please use Arduino IDE 1.6.8+ which has some useful new features 13 | 14 | ### Installation 15 | 1. Download [zip file](https://github.com/respeaker/respeaker_arduino_library/archive/master.zip) and extract it into Arduino's libraries directory. 16 | 2. Rename `respeaker_arduino_library-master` to `respeaker` 17 | 18 | ### Getting Started 19 | 1. Light - chasing colors 20 | 21 | ``` 22 | #include "respeaker.h" 23 | 24 | uint8_t offset = 0; 25 | 26 | void setup() { 27 | respeaker.begin(); 28 | respeaker.pixels().set_brightness(128); // set brightness level (from 0 to 255) 29 | } 30 | 31 | void loop() { 32 | respeaker.pixels().rainbow(offset++); 33 | delay(10); 34 | } 35 | ``` 36 | 37 | 2. Touch & Sound - touch to play 38 | 39 | ``` 40 | #include "respeaker.h" 41 | 42 | // wav or mp3 files on SD card 43 | const char *sound_map[] = {"a1.wav", "b1.wav", "c1.wav", "d1.wav", "e1.wav", "f1.wav", "g1.wav", "c2.wav"}; 44 | 45 | void setup() { 46 | respeaker.begin(); 47 | respeaker.attach_touch_handler(touch_event); // add touch event handler 48 | } 49 | void loop() {} 50 | 51 | // id: 0 ~ 7 - touch sensor id; event: 1 - touch, 0 - release 52 | void touch_event(uint8_t id, uint8_t event) { 53 | if (event) { 54 | respeaker.play(sound_map[id]); 55 | } 56 | } 57 | ``` 58 | 59 | 3. [connect to IFTTT maker channel](https://ifttt.com/maker) 60 | 61 | ``` 62 | #include "respeaker.h" 63 | 64 | #define IFTTT_MAKER_CHANNEL_KEY "" // add the key of your ifttt maker channel 65 | #define EVENT "ping" 66 | 67 | const char *ifttt_ping = "curl -X POST https://maker.ifttt.com/trigger/" EVENT "/with/key/" IFTTT_MAKER_CHANNEL_KEY; 68 | 69 | void setup() { 70 | respeaker.begin(); 71 | respeaker.attach_touch_handler(touch_event); // add touch event handler 72 | } 73 | void loop() {} 74 | 75 | // id: 0 ~ 7 - touch sensor id; event: 1 - touch, 0 - release 76 | void touch_event(uint8_t id, uint8_t event) { 77 | if (event == 1 && id == 0) { 78 | respeaker.exec(ifttt_ping); 79 | } 80 | } 81 | ``` 82 | 83 | 84 | -------------------------------------------------------------------------------- /examples/battery/battery.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Please use Arduino IDE 1.6.8+ 3 | 4 | Read battery voltage 5 | */ 6 | 7 | #include "respeaker.h" 8 | 9 | #define PIXELS_SPACE 128 10 | 11 | Pixels *pixels; 12 | volatile uint32_t color; 13 | volatile int pixels_state = -1; 14 | volatile uint8_t volume = 0; 15 | volatile uint32_t volume_changed_time = 0; 16 | 17 | 18 | void spi_event(uint8_t addr, uint8_t *data, uint8_t len) 19 | { 20 | if (0 == addr) { 21 | if (0 == data[0]) { // all off 22 | color = 0x000000; 23 | pixels_state = 0; 24 | } else if (1 == data[0]) { // specific color 25 | color = Pixels::RGB(data[3], data[2], data[1]); 26 | pixels_state = 0; 27 | } else if (2 == data[0] || 7 == data[0]) { // listening mode, all green 28 | color = Pixels::RGB(0, 0x40, 0); 29 | pixels_state = 0; 30 | } else if (3 == data[0]) { // waiting mode 31 | pixels_state = 1; 32 | } else if (4 == data[0]) { // speaking mode 33 | pixels_state = 2; 34 | } else if (5 == data[0]) { // volume mode 35 | pixels_state = 3; 36 | volume = data[3]; 37 | volume_changed_time = 0; 38 | } 39 | } else if (0xA0 == addr) { // spectrum data 40 | static uint8_t current[PIXELS_NUM] = {0,}; 41 | pixels_state = -1; 42 | Pixels pixels = respeaker.pixels(); 43 | for (int i = 0; i < PIXELS_NUM; i++) { 44 | // Serial.print(data[i]); 45 | // Serial.print(' '); 46 | if (data[i] > current[i]) { 47 | current[i] = data[i]; 48 | } else { 49 | current[i] = (data[i] + current[i]) >> 1; 50 | } 51 | pixels.set_color(i, change_brightness(b2r(i * 255 / (PIXELS_NUM - 1)), data[i])); 52 | // pixels.set_color(i, change_brightness(b2r(data[i]), data[i])); 53 | } 54 | pixels.update(); 55 | // Serial.print("\r\n"); 56 | } 57 | } 58 | 59 | void setup() { 60 | respeaker.begin(); 61 | 62 | pixels = &respeaker.pixels(); 63 | respeaker.attach_spi_handler(spi_event); 64 | 65 | pixels->set_brightness(10); 66 | 67 | pixels->rainbow(0); 68 | for (uint16_t i = 10; i <= 255; i++) { 69 | pixels->set_brightness(i); 70 | pixels->rainbow(0); 71 | pixels->update(); 72 | delay(10); 73 | } 74 | 75 | for (uint16_t i = 255; i > 10; i--) { 76 | respeaker.pixels().set_brightness(i); 77 | pixels->rainbow(0); 78 | pixels->update(); 79 | delay(10); 80 | } 81 | 82 | pixels->clear(); 83 | pixels->update(); 84 | 85 | pixels->set_brightness(255); 86 | 87 | pixels_state = 0; 88 | 89 | pinMode(A5, INPUT_PULLUP); 90 | pinMode(A1, INPUT); 91 | } 92 | 93 | uint8_t rainbow_offset = 0; 94 | 95 | void loop() { 96 | static uint32_t last_time = 0; 97 | if (pixels_state == 0) { 98 | if (color == 0x004000) { 99 | pixels->rainbow(rainbow_offset++); 100 | } else { 101 | pixels->set_color(color); 102 | pixels->update(); 103 | } 104 | pixels_state = -1; 105 | } else if (pixels_state == 1) { 106 | if ((uint32_t)(millis() - last_time) > 5) { 107 | last_time = millis(); 108 | 109 | pixels->rainbow(rainbow_offset++); 110 | } 111 | 112 | } else if (pixels_state == 2) { 113 | static uint32_t arc[PIXELS_NUM] = {0x10, 0x20, 0x30, 0x50, 0x80, 0xC0, 0xFF, 0xC0, 0x80, 0x50, 0x30, 0x20}; 114 | static uint8_t t = 0x80; 115 | static int8_t deta = 1; 116 | 117 | uint32_t current = millis(); 118 | if ((uint32_t)(current - last_time) > 5) { 119 | last_time = current; 120 | for (int i = 0; i < PIXELS_NUM; i++) { 121 | int16_t c = arc[i] - t; 122 | if (c < 0) { 123 | c = 0; 124 | } 125 | pixels->set_color(i, 0, c, 0); 126 | } 127 | pixels->update(); 128 | 129 | t += deta; 130 | if (t <= 0x40 || t >= 0xF0) { 131 | deta = -deta; 132 | } 133 | } 134 | } else if (pixels_state == 3) { 135 | if (0 == volume_changed_time) { 136 | uint8_t position = volume / 8; 137 | Serial.print("volume:"); 138 | Serial.println(volume); 139 | for (int i = 0; i < PIXELS_NUM; i++) { 140 | uint8_t c = 0; 141 | if (i < position) { 142 | c = 0x20; 143 | } 144 | pixels->set_color(i, 0, c, 0); 145 | } 146 | pixels->update(); 147 | volume_changed_time = millis(); 148 | } else if ((uint32_t)(millis() - volume_changed_time) > 3000) { 149 | pixels_state = -1; 150 | pixels->clear(); 151 | pixels->update(); 152 | } 153 | } else { 154 | static uint32_t last = 0; 155 | if ((uint32_t)(millis() - last) > 2000) { 156 | last = millis(); 157 | int16_t capacity = analogRead(A1) - 460; 158 | if (capacity > 255) { 159 | capacity = 255; 160 | } else if (capacity < 0) { 161 | capacity = 0; 162 | } 163 | 164 | pixels->clear(); 165 | if (digitalRead(A5) == 0) { 166 | static uint8_t on = 0; 167 | on = 1 - on; 168 | if (!on) { 169 | pixels->set_color(0, change_brightness(b2r(255 - capacity / 2), 0x20)); 170 | } 171 | } else { 172 | pixels->set_color(0, change_brightness(b2r(255 - capacity / 2), 0x20)); 173 | } 174 | 175 | pixels->update(); 176 | } 177 | } 178 | } 179 | 180 | uint32_t triangular_color(uint32_t t) { 181 | uint32_t c = 0; 182 | 183 | if (t < 256) { 184 | c = Pixels::RGB(0, t, 0); 185 | } else if (t < 512) { 186 | c = Pixels::RGB(0, 511 - t, 0); 187 | } 188 | 189 | return c; 190 | } 191 | 192 | uint32_t b2r(uint8_t position) { 193 | color_t color = {0}; 194 | if (position < 128) { 195 | color.b = 255 - position * 2; 196 | color.g = position * 2; 197 | } else { 198 | color.g = 255 - position * 2; 199 | color.r = position * 2; 200 | } 201 | 202 | return color.c; 203 | } 204 | 205 | uint32_t change_brightness(uint32_t rgb, uint8_t level) { 206 | color_t color; 207 | color.c = rgb; 208 | color.r = color.r * level / 255; 209 | color.g = color.g * level / 255; 210 | color.b = color.b * level / 255; 211 | 212 | if (color.r < 4) { 213 | color.r = 0; 214 | } 215 | if (color.g < 4) { 216 | color.g = 0; 217 | } 218 | if (color.b < 4) { 219 | color.b = 0; 220 | } 221 | 222 | return color.c; 223 | } 224 | 225 | -------------------------------------------------------------------------------- /examples/demo/demo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Please use Arduino IDE 1.6.8+ which has some useful new features 3 | */ 4 | 5 | #include "respeaker.h" 6 | 7 | #define PIXELS_SPACE 128 8 | 9 | uint32_t t = 0; 10 | 11 | void touch_event(uint8_t id, uint8_t event) { 12 | // id - touch sensor id (0 ~ 7), event - 1: touch, 0: release 13 | } 14 | 15 | void setup() { 16 | respeaker.begin(); 17 | respeaker.attach_touch_handler(touch_event); 18 | } 19 | 20 | void loop() { 21 | for (int i = 0; i < PIXELS_NUM; i++) { 22 | respeaker.pixels().set_color(i, triangular_color((t + i * PIXELS_SPACE) % (PIXELS_SPACE * PIXELS_NUM))); 23 | } 24 | respeaker.pixels().update(); 25 | 26 | t++; 27 | if (t >= (PIXELS_SPACE * PIXELS_NUM)) { 28 | t = 0; 29 | } 30 | } 31 | 32 | uint32_t triangular_color(uint32_t t) { 33 | uint32_t c = 0; 34 | 35 | if (t < 256) { 36 | c = Pixels::RGB(0, t, 0); 37 | } else if (t < 512) { 38 | c = Pixels::RGB(0, 511 - t, 0); 39 | } 40 | 41 | return c; 42 | } -------------------------------------------------------------------------------- /examples/pixels_pattern/pixels_pattern.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Please use Arduino IDE 1.6.8+ 3 | 4 | receive spi commands to change pixels pattern 5 | */ 6 | 7 | #include "respeaker.h" 8 | 9 | #define PIXELS_SPACE 128 10 | 11 | Pixels *pixels; 12 | volatile uint32_t color; 13 | volatile int pixels_state = 0; 14 | volatile uint8_t volume = 0; 15 | volatile uint32_t volume_changed_time = 0; 16 | 17 | void touch_event(uint8_t id, uint8_t event) { 18 | // id - touch sensor id (0 ~ 7), event - 1: touch, 0: release 19 | } 20 | 21 | void spi_event(uint8_t addr, uint8_t *data, uint8_t len) 22 | { 23 | if (0 == addr) { 24 | if (0 == data[0]) { // all off 25 | color = 0x000000; 26 | pixels_state = 0; 27 | } else if (1 == data[0]) { // specific color 28 | color = Pixels::RGB(data[3], data[2], data[1]); 29 | pixels_state = 0; 30 | } else if (2 == data[0] || 7 == data[0]) { // listening mode, all green 31 | color = Pixels::RGB(0, 0x40, 0); 32 | pixels_state = 0; 33 | } else if (3 == data[0]) { // waiting mode 34 | pixels_state = 1; 35 | } else if (4 == data[0]) { // speaking mode 36 | pixels_state = 2; 37 | } else if (5 == data[0]) { // volume mode 38 | pixels_state = 3; 39 | volume = data[3]; 40 | volume_changed_time = 0; 41 | } 42 | } else if (0xA0 == addr) { // spectrum data 43 | pixels_state = -1; 44 | for (int i = 0; i < PIXELS_NUM; i++) { 45 | // Serial.print(data[i]); 46 | // Serial.print(' '); 47 | pixels->set_color(i, change_brightness(b2r(i * 255 / (PIXELS_NUM - 1)), data[i])); 48 | // pixels->set_color(i, change_brightness(b2r(data[i]), data[i])); 49 | } 50 | pixels->update(); 51 | // Serial.print("\r\n"); 52 | } 53 | } 54 | 55 | void setup() { 56 | respeaker.begin(); 57 | 58 | pixels = &respeaker.pixels(); 59 | // respeaker.attach_touch_handler(touch_event); 60 | respeaker.attach_spi_handler(spi_event); 61 | for (int i = 0; i < 0x20; i++) { 62 | pixels->set_color(Pixels::RGB(i, 0, 0)); 63 | pixels->update(); 64 | delay(100); 65 | } 66 | for (int i = 0; i < 0x20; i++) { 67 | pixels->set_color(Pixels::RGB(0x1F - i, 0, 0)); 68 | pixels->update(); 69 | delay(100); 70 | } 71 | } 72 | 73 | void loop() { 74 | static uint32_t last_time = 0; 75 | 76 | if (pixels_state == 0) { 77 | pixels->set_color(color); 78 | pixels->update(); 79 | pixels_state = -1; 80 | } else if (pixels_state == 1) { 81 | static uint32_t t = 0; 82 | for (int i = 0; i < PIXELS_NUM; i++) { 83 | pixels->set_color(i, triangular_color((t + i * PIXELS_SPACE) % (PIXELS_SPACE * PIXELS_NUM))); 84 | } 85 | pixels->update(); 86 | 87 | t++; 88 | if (t >= (PIXELS_SPACE * PIXELS_NUM)) { 89 | t = 0; 90 | } 91 | } else if (pixels_state == 2) { 92 | static uint32_t arc[PIXELS_NUM] = {0x10, 0x20, 0x30, 0x50, 0x80, 0xC0, 0xFF, 0xC0, 0x80, 0x50, 0x30, 0x20}; 93 | static uint8_t t = 0x80; 94 | static int8_t deta = 1; 95 | 96 | uint32_t current = millis(); 97 | if ((uint32_t)(current - last_time) > 5) { 98 | last_time = current; 99 | for (int i = 0; i < PIXELS_NUM; i++) { 100 | int16_t c = arc[i] - t; 101 | if (c < 0) { 102 | c = 0; 103 | } 104 | pixels->set_color(i, 0, c, 0); 105 | } 106 | pixels->update(); 107 | 108 | t += deta; 109 | if (t <= 0x40 || t >= 0xF0) { 110 | deta = -deta; 111 | } 112 | } 113 | } else if (pixels_state == 3) { 114 | if (0 == volume_changed_time) { 115 | uint8_t position = volume / 8; 116 | Serial.print("volume:"); 117 | Serial.println(volume); 118 | for (int i = 0; i < PIXELS_NUM; i++) { 119 | uint8_t c = 0; 120 | if (i < position) { 121 | c = 0x20; 122 | } 123 | pixels->set_color(i, 0, c, 0); 124 | } 125 | pixels->update(); 126 | volume_changed_time = millis(); 127 | } else if ((uint32_t)(millis() - volume_changed_time) > 3000) { 128 | pixels_state = -1; 129 | pixels->clear(); 130 | pixels->update(); 131 | } 132 | } 133 | } 134 | 135 | uint32_t triangular_color(uint32_t t) { 136 | uint32_t c = 0; 137 | 138 | if (t < 256) { 139 | c = Pixels::RGB(0, t, 0); 140 | } else if (t < 512) { 141 | c = Pixels::RGB(0, 511 - t, 0); 142 | } 143 | 144 | return c; 145 | } 146 | 147 | uint32_t b2r(uint8_t position) { 148 | color_t color = {0}; 149 | if (position < 128) { 150 | color.b = 255 - position * 2; 151 | color.g = position * 2; 152 | } else { 153 | color.g = 255 - position * 2; 154 | color.r = position * 2; 155 | } 156 | 157 | return color.c; 158 | } 159 | 160 | uint32_t change_brightness(uint32_t rgb, uint8_t level) { 161 | color_t color; 162 | color.c = rgb; 163 | color.r = color.r * level / 255; 164 | color.g = color.g * level / 255; 165 | color.b = color.b * level / 255; 166 | 167 | if (color.r < 4) { 168 | color.r = 0; 169 | } 170 | if (color.g < 4) { 171 | color.g = 0; 172 | } 173 | if (color.b < 4) { 174 | color.b = 0; 175 | } 176 | 177 | return color.c; 178 | } 179 | -------------------------------------------------------------------------------- /examples/rainbow/rainbow.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Please use Arduino IDE 1.6.8+ which has some useful new features 3 | 4 | Chasing colors! 5 | */ 6 | 7 | #include "respeaker.h" 8 | 9 | uint8_t offset = 0; 10 | 11 | void setup() { 12 | respeaker.begin(); 13 | respeaker.pixels().set_brightness(128); // set brightness level (from 0 to 255) 14 | } 15 | 16 | void loop() { 17 | respeaker.pixels().rainbow(offset++); 18 | delay(10); 19 | } 20 | -------------------------------------------------------------------------------- /examples/sound/sound.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Please use Arduino IDE 1.6.8+ which has some useful new features 3 | 4 | Play sound 5 | Use capacitive touch sensors to trigger sound 6 | */ 7 | 8 | #include "respeaker.h" 9 | 10 | // use sound files which are able to be found on SD card, new mp3/wav files can be added to SD card 11 | const char *sound_map[] = {"this_is_touch_sensor.wav", "a1.wav", "b1.wav", "c1.wav", "d1.wav", "e1.wav", "f1.wav", "no_touch.wav"}; 12 | 13 | void setup() { 14 | respeaker.begin(); 15 | respeaker.attach_touch_handler(touch_event); // add touch event handler 16 | } 17 | 18 | void loop() {} 19 | 20 | // id: 0 ~ 7 - touch sensor id; event: 1 - touch, 0 - release 21 | void touch_event(uint8_t id, uint8_t event) { 22 | if (event) { 23 | respeaker.play(sound_map[id]); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/touch/touch.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Please use Arduino IDE 1.6.8+ 3 | 4 | Get touch with Touch 5 | Use 8 capacitive touch sensors to trigger onboard LEDs 6 | */ 7 | 8 | #include "respeaker.h" 9 | 10 | 11 | void setup() { 12 | respeaker.begin(); 13 | respeaker.attach_touch_handler(touch_event); // add touch event handler 14 | } 15 | 16 | void loop() {} 17 | 18 | // id: 0 ~ 7 - touch sensor id; event: 1 - touch, 0 - release 19 | void touch_event(uint8_t id, uint8_t event) { 20 | if (event) { 21 | respeaker.pixels().set_color(id, Pixels::wheel(id * 32)); 22 | } else { 23 | respeaker.pixels().set_color(id, 0); 24 | } 25 | respeaker.pixels().update(); 26 | } 27 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For ReSpeaker 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | ReSpeaker KEYWORD1 9 | Pixels KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | begin KEYWORD2 16 | play KEYWORD2 17 | exec KEYWORD2 18 | pixels KEYWORD2 19 | set_console KEYWORD2 20 | calibrate_touch KEYWORD2 21 | read_touch KEYWORD2 22 | detect_touch KEYWORD2 23 | set_touch_threshold KEYWORD2 24 | attach_touch_handler KEYWORD2 25 | attach_spi_handler KEYWORD2 26 | attach_spi_raw_handler KEYWORD2 27 | 28 | set_color KEYWORD2 29 | get_color KEYWORD2 30 | set_brightness KEYWORD2 31 | get_brightness KEYWORD2 32 | clear KEYWORD2 33 | update KEYWORD2 34 | number KEYWORD2 35 | RGB KEYWORD2 36 | rainbow KEYWORD2 37 | wheel KEYWORD2 38 | 39 | ####################################### 40 | # Instances (KEYWORD2) 41 | ####################################### 42 | respeaker KEYWORD2 43 | 44 | ####################################### 45 | # Constants (LITERAL1) 46 | ####################################### 47 | -------------------------------------------------------------------------------- /pixels.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * pixels.cpp 3 | * 4 | * WS2812 RGB LED library for ReSpeaker (ATmega32U4) 5 | * 6 | * Copyright (c) 2016 Seeed Technology Limited. 7 | * MIT license 8 | * 9 | */ 10 | 11 | #include "pixels.h" 12 | #include 13 | 14 | Pixels::Pixels(uint16_t num_leds) 15 | { 16 | leds_n = num_leds; 17 | pixels = new uint8_t[leds_n * 3]; 18 | brightness = 1.0; 19 | clear(); 20 | } 21 | 22 | void Pixels::begin(uint8_t pin) 23 | { 24 | pinMode(pin, OUTPUT); 25 | digitalWrite(pin, LOW); 26 | pin_mask = digitalPinToBitMask(pin); 27 | port = portOutputRegister(digitalPinToPort(pin)); 28 | } 29 | 30 | void Pixels::set_color(uint32_t rgb) 31 | { 32 | uint8_t r = ((rgb >> 16) & 0xff) * brightness; 33 | uint8_t g = ((rgb >> 8) & 0xff) * brightness; 34 | uint8_t b = (rgb & 0xff) * brightness; 35 | uint8_t *ptr = pixels; 36 | uint16_t index = 0; 37 | while (index < leds_n) { 38 | *ptr++ = g; 39 | *ptr++ = r; 40 | *ptr++ = b; 41 | index++; 42 | } 43 | } 44 | 45 | void Pixels::set_color(uint16_t index, uint32_t rgb) 46 | { 47 | if(index < leds_n) { 48 | uint8_t *ptr = pixels + index * 3; 49 | *ptr++ = ((rgb >> 8) & 0xff) * brightness; // green 50 | *ptr++ = ((rgb >> 16) & 0xff) * brightness; // red 51 | *ptr = (rgb & 0xff) * brightness; // blue 52 | } 53 | } 54 | 55 | void Pixels::set_color(uint16_t index, uint8_t r, uint8_t g, uint8_t b) 56 | { 57 | if(index < leds_n) { 58 | uint8_t *ptr = pixels + index * 3; 59 | *ptr++ = g * brightness; // green 60 | *ptr++ = r * brightness; // red 61 | *ptr = b * brightness; // blue 62 | } 63 | } 64 | 65 | uint32_t Pixels::get_color(uint16_t index) 66 | { 67 | uint8_t *ptr = pixels + index * 3; 68 | 69 | return RGB(ptr[1], ptr[0], ptr[2]); 70 | } 71 | 72 | void Pixels::set_brightness(uint8_t level) 73 | { 74 | brightness = level / 255.0; 75 | } 76 | 77 | uint8_t Pixels::get_brightness() 78 | { 79 | return brightness * 255; 80 | } 81 | 82 | void Pixels::clear() 83 | { 84 | memset(pixels, 0, leds_n * 3); 85 | update(); 86 | } 87 | 88 | void Pixels::scroll(uint32_t px_value, uint8_t time) 89 | { 90 | for(uint16_t i = 0; i < leds_n; i++){ 91 | clear(); 92 | set_color(i, px_value); 93 | update(); 94 | delay(time); 95 | } 96 | } 97 | 98 | void Pixels::scroll(uint8_t size, uint32_t px_value, uint8_t time) 99 | { 100 | if(size > leds_n){ 101 | return; 102 | } 103 | for(int i = 1; i < leds_n + size; i++){ 104 | if(i < size){ 105 | for(int j = 0; j < i; j++){ 106 | set_color(j, px_value); 107 | } 108 | }else if(i >= leds_n){ 109 | for(int k = i - size; k < leds_n; k++){ 110 | set_color(k, px_value); 111 | } 112 | }else{ 113 | for(int m = i-size; m < i; m++){ 114 | set_color(m, px_value); 115 | } 116 | } 117 | update(); 118 | delay(time); 119 | clear(); 120 | } 121 | 122 | } 123 | 124 | void Pixels::pass_by(uint8_t size, uint32_t px_value1, uint32_t px_value2, uint8_t time) 125 | { 126 | if(size > leds_n){ 127 | return; 128 | } 129 | for(int i = 1; i < leds_n + size; i++){ 130 | if(i < size){ 131 | for(int j = 0; j < i; j++){ 132 | set_color(j, px_value1); 133 | set_color(leds_n -1 - j, px_value2); 134 | } 135 | }else if(i >= leds_n){ 136 | for(int k = i - size; k < leds_n; k++){ 137 | set_color(k, px_value1); 138 | set_color(leds_n -1 - k, px_value2); 139 | } 140 | }else{ 141 | for(int m = i-size; m < i; m++){ 142 | set_color(m, px_value1); 143 | set_color(leds_n -1 - m, px_value2); 144 | } 145 | } 146 | update(); 147 | delay(time); 148 | clear(); 149 | } 150 | } 151 | 152 | void Pixels::blink(uint32_t px_value, uint8_t time, uint16_t index) 153 | { 154 | set_color(index, px_value); 155 | update(); 156 | delay(time); 157 | set_color(index, 0); 158 | update(); 159 | delay(time); 160 | } 161 | 162 | void Pixels::blink(uint32_t px_value, uint8_t time) 163 | { 164 | for(int i = 0; i < leds_n; i++){ 165 | set_color(i, px_value); 166 | } 167 | update(); 168 | delay(time); 169 | clear(); 170 | delay(time); 171 | } 172 | 173 | void Pixels::color_brush(uint32_t px_value, uint8_t time) 174 | { 175 | for(uint16_t index = 0; index < leds_n; index++) { 176 | set_color(index, px_value); 177 | update(); 178 | delay(time); 179 | } 180 | } 181 | 182 | void Pixels::rainbow(uint8_t offset) 183 | { 184 | uint16_t i; 185 | for(i = 0; i < leds_n; i++) { 186 | set_color(i, wheel(((i * 256 / leds_n) + offset) & 255)); 187 | } 188 | update(); 189 | } 190 | 191 | void Pixels::theater_chase(uint32_t px_value, uint8_t time) 192 | { 193 | for (int j = 0; j < 10; j++) { 194 | for (int q = 0; q < 3; q++) { 195 | for (int i = 0; i < leds_n; i = i+3) { 196 | set_color(i+q, px_value); 197 | } 198 | update(); 199 | delay(time); 200 | for (int i = 0; i < leds_n; i = i+3) { 201 | set_color(i+q, 0); 202 | } 203 | } 204 | } 205 | } 206 | 207 | void Pixels::theater_chase_rainbow(uint8_t time) 208 | { 209 | for (int j = 0; j < 256; j++) { 210 | for (int q = 0; q < 3; q++) { 211 | for (int i = 0; i < leds_n; i=i+3) { 212 | set_color(i+q, wheel( (i+j) % 255)); 213 | } 214 | update(); 215 | delay(time); 216 | for (int i = 0; i < leds_n; i = i+3) { 217 | set_color(i+q, 0); 218 | } 219 | } 220 | } 221 | } 222 | 223 | void Pixels::update() 224 | { 225 | if ((uint32_t)(micros() - end_time) < 50) { return; } 226 | 227 | noInterrupts(); 228 | 229 | volatile uint16_t i = leds_n * 3; 230 | volatile uint8_t *ptr = pixels; 231 | volatile uint8_t b = *ptr++; 232 | volatile uint8_t hi; 233 | volatile uint8_t lo; 234 | 235 | #if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) 236 | volatile uint8_t n1, n2 = 0; 237 | if(port == &PORTD){ 238 | hi = PORTD | pin_mask; 239 | lo = PORTD & ~pin_mask; 240 | n1 = lo; 241 | if(b & 0x80) n1 = hi; 242 | asm volatile( 243 | "headD:" "\n\t" 244 | // Bit 7: 245 | "out %[port] , %[hi]" "\n\t" 246 | "mov %[n2] , %[lo]" "\n\t" 247 | "out %[port] , %[n1]" "\n\t" 248 | "rjmp .+0" "\n\t" 249 | "sbrc %[byte] , 6" "\n\t" 250 | "mov %[n2] , %[hi]" "\n\t" 251 | "out %[port] , %[lo]" "\n\t" 252 | "rjmp .+0" "\n\t" 253 | // Bit 6: 254 | "out %[port] , %[hi]" "\n\t" 255 | "mov %[n1] , %[lo]" "\n\t" 256 | "out %[port] , %[n2]" "\n\t" 257 | "rjmp .+0" "\n\t" 258 | "sbrc %[byte] , 5" "\n\t" 259 | "mov %[n1] , %[hi]" "\n\t" 260 | "out %[port] , %[lo]" "\n\t" 261 | "rjmp .+0" "\n\t" 262 | // Bit 5: 263 | "out %[port] , %[hi]" "\n\t" 264 | "mov %[n2] , %[lo]" "\n\t" 265 | "out %[port] , %[n1]" "\n\t" 266 | "rjmp .+0" "\n\t" 267 | "sbrc %[byte] , 4" "\n\t" 268 | "mov %[n2] , %[hi]" "\n\t" 269 | "out %[port] , %[lo]" "\n\t" 270 | "rjmp .+0" "\n\t" 271 | // Bit 4: 272 | "out %[port] , %[hi]" "\n\t" 273 | "mov %[n1] , %[lo]" "\n\t" 274 | "out %[port] , %[n2]" "\n\t" 275 | "rjmp .+0" "\n\t" 276 | "sbrc %[byte] , 3" "\n\t" 277 | "mov %[n1] , %[hi]" "\n\t" 278 | "out %[port] , %[lo]" "\n\t" 279 | "rjmp .+0" "\n\t" 280 | // Bit 3: 281 | "out %[port] , %[hi]" "\n\t" 282 | "mov %[n2] , %[lo]" "\n\t" 283 | "out %[port] , %[n1]" "\n\t" 284 | "rjmp .+0" "\n\t" 285 | "sbrc %[byte] , 2" "\n\t" 286 | "mov %[n2] , %[hi]" "\n\t" 287 | "out %[port] , %[lo]" "\n\t" 288 | "rjmp .+0" "\n\t" 289 | // Bit 2: 290 | "out %[port] , %[hi]" "\n\t" 291 | "mov %[n1] , %[lo]" "\n\t" 292 | "out %[port] , %[n2]" "\n\t" 293 | "rjmp .+0" "\n\t" 294 | "sbrc %[byte] , 1" "\n\t" 295 | "mov %[n1] , %[hi]" "\n\t" 296 | "out %[port] , %[lo]" "\n\t" 297 | "rjmp .+0" "\n\t" 298 | // Bit 1: 299 | "out %[port] , %[hi]" "\n\t" 300 | "mov %[n2] , %[lo]" "\n\t" 301 | "out %[port] , %[n1]" "\n\t" 302 | "rjmp .+0" "\n\t" 303 | "sbrc %[byte] , 0" "\n\t" 304 | "mov %[n2] , %[hi]" "\n\t" 305 | "out %[port] , %[lo]" "\n\t" 306 | "sbiw %[count], 1" "\n\t" 307 | // Bit 0: 308 | "out %[port] , %[hi]" "\n\t" 309 | "mov %[n1] , %[lo]" "\n\t" 310 | "out %[port] , %[n2]" "\n\t" 311 | "ld %[byte] , %a[ptr]+" "\n\t" 312 | "sbrc %[byte] , 7" "\n\t" 313 | "mov %[n1] , %[hi]" "\n\t" 314 | "out %[port] , %[lo]" "\n\t" 315 | "brne headD" "\n" 316 | : [byte] "+r" (b), 317 | [n1] "+r" (n1), 318 | [n2] "+r" (n2), 319 | [count] "+w" (i) 320 | : [port] "I" (_SFR_IO_ADDR(PORTD)), 321 | [ptr] "e" (ptr), 322 | [hi] "r" (hi), 323 | [lo] "r" (lo)); 324 | } 325 | #elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) 326 | volatile uint8_t next; 327 | if(port == &PORTD) { 328 | hi = PORTD | pin_mask; 329 | lo = PORTD & ~pin_mask; 330 | next = lo; 331 | if(b & 0x80) next = hi; 332 | asm volatile( 333 | "headD:" "\n\t" 334 | "out %[port], %[hi]" "\n\t" 335 | "rcall bitTimeD" "\n\t" 336 | "out %[port], %[hi]" "\n\t" 337 | "rcall bitTimeD" "\n\t" 338 | "out %[port], %[hi]" "\n\t" 339 | "rcall bitTimeD" "\n\t" 340 | "out %[port], %[hi]" "\n\t" 341 | "rcall bitTimeD" "\n\t" 342 | "out %[port], %[hi]" "\n\t" 343 | "rcall bitTimeD" "\n\t" 344 | "out %[port], %[hi]" "\n\t" 345 | "rcall bitTimeD" "\n\t" 346 | "out %[port], %[hi]" "\n\t" 347 | "rcall bitTimeD" "\n\t" 348 | // Bit 0: 349 | "out %[port] , %[hi]" "\n\t" 350 | "rjmp .+0" "\n\t" 351 | "ld %[byte] , %a[ptr]+" "\n\t" 352 | "out %[port] , %[next]" "\n\t" 353 | "mov %[next] , %[lo]" "\n\t" 354 | "sbrc %[byte] , 7" "\n\t" 355 | "mov %[next] , %[hi]" "\n\t" 356 | "nop" "\n\t" 357 | "out %[port] , %[lo]" "\n\t" 358 | "sbiw %[count], 1" "\n\t" 359 | "brne headD" "\n\t" 360 | "rjmp doneD" "\n\t" 361 | "bitTimeD:" "\n\t" 362 | "out %[port], %[next]" "\n\t" 363 | "mov %[next], %[lo]" "\n\t" 364 | "rol %[byte]" "\n\t" 365 | "sbrc %[byte], 7" "\n\t" 366 | "mov %[next], %[hi]" "\n\t" 367 | "nop" "\n\t" 368 | "out %[port], %[lo]" "\n\t" 369 | "ret" "\n\t" 370 | "doneD:" "\n" 371 | : [byte] "+r" (b), 372 | [next] "+r" (next), 373 | [count] "+w" (i) 374 | : [port] "I" (_SFR_IO_ADDR(PORTD)), 375 | [ptr] "e" (ptr), 376 | [hi] "r" (hi), 377 | [lo] "r" (lo)); 378 | } 379 | #elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) 380 | volatile uint8_t next, bit; 381 | hi = *port | pin_mask; 382 | lo = *port & ~pin_mask; 383 | next = lo; 384 | bit = 8; 385 | asm volatile( 386 | "head20:" "\n\t" 387 | "st %a[port], %[hi]" "\n\t" 388 | "sbrc %[byte], 7" "\n\t" 389 | "mov %[next], %[hi]" "\n\t" 390 | "dec %[bit]" "\n\t" 391 | "st %a[port], %[next]" "\n\t" 392 | "mov %[next] , %[lo]" "\n\t" 393 | "breq nextbyte20" "\n\t" 394 | "rol %[byte]" "\n\t" 395 | "rjmp .+0" "\n\t" 396 | "nop" "\n\t" 397 | "st %a[port], %[lo]" "\n\t" 398 | "nop" "\n\t" 399 | "rjmp .+0" "\n\t" 400 | "rjmp head20" "\n\t" 401 | "nextbyte20:" "\n\t" 402 | "ldi %[bit] , 8" "\n\t" 403 | "ld %[byte] , %a[ptr]+" "\n\t" 404 | "st %a[port], %[lo]" "\n\t" 405 | "nop" "\n\t" 406 | "sbiw %[count], 1" "\n\t" 407 | "brne head20" "\n" 408 | : [port] "+e" (port), 409 | [byte] "+r" (b), 410 | [bit] "+r" (bit), 411 | [next] "+r" (next), 412 | [count] "+w" (i) 413 | : [ptr] "e" (ptr), 414 | [hi] "r" (hi), 415 | [lo] "r" (lo)); 416 | #else 417 | #error "CPU SPEED NOT SUPPORTED" 418 | #endif 419 | interrupts(); 420 | end_time = micros(); 421 | } 422 | -------------------------------------------------------------------------------- /pixels.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pixels.h 3 | * 4 | * WS2812 RGB LED library for ReSpeaker (ATmega32U4) 5 | * 6 | * Copyright (c) 2016 Seeed Technology Limited. 7 | * MIT license 8 | * 9 | */ 10 | 11 | #ifndef __PIXELS_H_ 12 | #define __PIXELS_H_ 13 | 14 | #include 15 | #include 16 | #ifndef F_CPU 17 | #define F_CPU 16000000UL 18 | #endif 19 | #include 20 | #include 21 | #include 22 | 23 | typedef union { 24 | struct { 25 | uint8_t b; 26 | uint8_t g; 27 | uint8_t r; 28 | uint8_t a; 29 | }; 30 | uint32_t c; 31 | } color_t; 32 | 33 | class Pixels { 34 | public: 35 | Pixels(uint16_t num_leds); 36 | void begin(uint8_t pin); 37 | void set_color(uint32_t rgb); 38 | void set_color(uint16_t index, uint32_t rgb); 39 | void set_color(uint16_t index, uint8_t r, uint8_t g, uint8_t b); 40 | uint32_t get_color(uint16_t index); 41 | void set_brightness(uint8_t level); 42 | uint8_t get_brightness(); 43 | void clear(); 44 | void update(); 45 | uint16_t number() { 46 | return leds_n; 47 | } 48 | 49 | static uint32_t RGB(uint8_t red, uint8_t green, uint8_t blue){ 50 | return ((uint32_t)red << 16) | ((uint32_t)green << 8) | blue; 51 | }; 52 | 53 | static uint32_t wheel(uint8_t position) { 54 | if(position < 85) { 55 | return RGB(position * 3, 255 - position * 3, 0); 56 | } else if(position < 170) { 57 | position -= 85; 58 | return RGB(255 - position * 3, 0, position * 3); 59 | } else { 60 | position -= 170; 61 | return RGB(0, position * 3, 255 - position * 3); 62 | } 63 | } 64 | 65 | void rainbow(uint8_t offset); 66 | 67 | void scroll(uint32_t px_value, uint8_t time); 68 | void scroll(uint8_t size, uint32_t px_value, uint8_t time); 69 | void pass_by(uint8_t size, uint32_t px_value1, uint32_t px_value2, uint8_t time); 70 | void blink(uint32_t px_value, uint8_t time, uint16_t index); 71 | void blink(uint32_t px_value, uint8_t time); 72 | void color_brush(uint32_t color, uint8_t time); 73 | void theater_chase(uint32_t color, uint8_t time); 74 | void theater_chase_rainbow(uint8_t time); 75 | 76 | private: 77 | uint8_t *pixels; 78 | float brightness; 79 | uint16_t leds_n; 80 | uint32_t end_time; 81 | const volatile uint8_t *port; 82 | uint8_t pin_mask; 83 | }; 84 | 85 | #endif /* __PIXELS_H_ */ 86 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; http://docs.platformio.org/page/projectconf.html 10 | 11 | [platformio] 12 | lib_dir = .. 13 | src_dir = examples/rainbow 14 | 15 | [env:leonardo] 16 | platform = atmelavr 17 | board = leonardo 18 | framework = arduino 19 | lib_ldf_mode = deep 20 | 21 | 22 | -------------------------------------------------------------------------------- /respeaker.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "respeaker.h" 3 | #include "SPI.h" 4 | 5 | 6 | ReSpeaker respeaker; 7 | 8 | // disorganize touch pins order to reduce interference {8, 9, 13, 10, 6, 2, 4, 3} 9 | const uint8_t ReSpeaker::touch_pins[TOUCH_NUM] = {9, 2, 10, 3, 8, 6, 13, 4}; 10 | const uint8_t ReSpeaker::touch_pins_id[TOUCH_NUM] = {1, 5, 3, 7, 0, 4, 2, 6}; 11 | 12 | ReSpeaker::ReSpeaker() 13 | { 14 | console = 1; 15 | 16 | touch_handler = 0; 17 | last_touch_detected = 0; 18 | touch_threshold = TOUCH_DEFAULT_THRESHOLD; 19 | 20 | spi_raw_handler = 0; 21 | spi_handler = 0; 22 | spi_state = 0; 23 | spi_buf_index = 0; 24 | } 25 | 26 | void ReSpeaker::begin(int touch, int pixels, int spi) 27 | { 28 | Serial.begin(57600); 29 | Serial1.begin(57600); 30 | 31 | if (touch) { 32 | touch_data = new uint8_t[TOUCH_NUM]; 33 | 34 | for (uint8_t i = 0; i < TOUCH_NUM; i++) { 35 | pinMode(touch_pins[i], OUTPUT); 36 | digitalWrite(touch_pins[i], LOW); 37 | } 38 | } 39 | 40 | if (pixels) { 41 | pixels_ptr = new Pixels(PIXELS_NUM); 42 | pixels_ptr->begin(PIXELS_PIN); 43 | pixels_ptr->update(); 44 | } 45 | 46 | if (spi) { 47 | spi_buf = new uint8_t[SPI_BUF_SIZE]; 48 | 49 | pinMode(MOSI, INPUT); 50 | pinMode(MISO, OUTPUT); 51 | pinMode(SCK, INPUT); 52 | pinMode(SS, INPUT); 53 | 54 | // use SPI slave mode 55 | SPCR |= _BV(SPE); 56 | 57 | SPI.attachInterrupt(); 58 | } 59 | } 60 | 61 | void ReSpeaker::play(const char *name) 62 | { 63 | Serial1.print("play "); 64 | Serial1.print(name); 65 | Serial1.print('\n'); 66 | } 67 | 68 | void ReSpeaker::exec(const char *cmd) 69 | { 70 | Serial1.print(cmd); 71 | Serial1.print('\n'); 72 | } 73 | 74 | uint8_t crc8(const uint8_t *data, uint8_t len) 75 | { 76 | uint16_t crc = 0x00; 77 | while (len--) { 78 | crc ^= (*data++ << 8); 79 | for(uint8_t i = 8; i; i--) { 80 | if (crc & 0x8000) { 81 | crc ^= (0x1070 << 3); 82 | } 83 | crc <<= 1; 84 | } 85 | } 86 | return (uint8_t)(crc >> 8); 87 | } 88 | 89 | void ReSpeaker::handle_spi_data(uint8_t data) 90 | { 91 | if (0 == spi_state) { 92 | if (SPI_DATA_PREFIX == data) { 93 | spi_state = 1; 94 | } 95 | } else if (1 == spi_state) { 96 | spi_data_address = data; 97 | spi_state = 2; 98 | } else if (2 == spi_state) { 99 | if (data <= SPI_BUF_SIZE) { 100 | spi_data_length = data; 101 | spi_buf_index = 0; 102 | spi_state = 3; 103 | } else { 104 | spi_state = 0; 105 | } 106 | } else if (3 == spi_state) { 107 | spi_buf[spi_buf_index] = data; 108 | spi_buf_index++; 109 | 110 | if (spi_data_length <= spi_buf_index) { 111 | spi_state = 4; 112 | } 113 | } else if (4 == spi_state) { 114 | uint8_t crc = crc8(spi_buf, spi_data_length); 115 | if (crc == data) { 116 | spi_handler(spi_data_address, spi_buf, spi_data_length); 117 | } else { 118 | Serial.print("crc check failed:"); 119 | Serial.println(crc); 120 | for (uint8_t i = 0; i < spi_data_length; i++) { 121 | Serial.print(spi_buf[i]); 122 | Serial.print(' '); 123 | } 124 | Serial.println(data); 125 | } 126 | spi_state = 0; 127 | } 128 | } 129 | 130 | uint16_t ReSpeaker::detect_touch() 131 | { 132 | uint16_t status; 133 | for (uint8_t i = 0; i < TOUCH_NUM; i++) { 134 | uint8_t count = 0; 135 | touch_data[i] <<= 1; 136 | pinMode(touch_pins[i], INPUT); 137 | while (!digitalRead(touch_pins[i])) { 138 | count++; 139 | if (count >= touch_threshold) { 140 | touch_data[i] |= 0x01; 141 | break; 142 | } 143 | } 144 | 145 | pinMode(touch_pins[i], OUTPUT); 146 | digitalWrite(touch_pins[i], LOW); 147 | 148 | if (0x01 == touch_data[i]) { 149 | status |= 1 << i; 150 | if (touch_handler) touch_handler(touch_pins_id[i], 1); 151 | } else if (0x80 == touch_data[i]) { 152 | status &= ~(1 << i); 153 | if (touch_handler) touch_handler(touch_pins_id[i], 0); 154 | } 155 | } 156 | 157 | return status; 158 | } 159 | 160 | uint16_t ReSpeaker::read_touch(uint8_t id) 161 | { 162 | uint16_t count; 163 | uint8_t index = 0; 164 | for (uint8_t i=0; i= 50) { 197 | last_touch_detected = current; 198 | 199 | detect_touch(); 200 | } 201 | } 202 | } 203 | 204 | void serialEventRun() 205 | { 206 | respeaker._loop(); 207 | } 208 | 209 | // SPI Interrupt Service Routine 210 | ISR (SPI_STC_vect) 211 | { 212 | uint8_t data = SPDR; // read SPI Data Register 213 | 214 | if (!respeaker.spi_raw_handler) { 215 | respeaker.handle_spi_data(data); 216 | } else { 217 | respeaker.spi_raw_handler(data); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /respeaker.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef __RESPEAKER_H__ 4 | #define __RESPEAKER_H__ 5 | 6 | #include "Arduino.h" 7 | #include "pixels.h" 8 | 9 | #define SPI_BUF_SIZE 64 10 | #define SPI_DATA_PREFIX 0xA5 11 | #define TOUCH_NUM 8 12 | #define TOUCH_DETECT_INTERVAL 4 // ms 13 | #define TOUCH_DEFAULT_THRESHOLD 32 14 | #define PIXELS_NUM 12 15 | #define PIXELS_PIN 11 16 | 17 | class ReSpeaker 18 | { 19 | public: 20 | ReSpeaker(); 21 | 22 | /** 23 | * setup touch buttons, full color pixels and spi bridge 24 | * 25 | * @param touch 1 - enable touch buttons, 0 - disable 26 | * @param pixels 1 - enable pixels, 0 - disable 27 | * @param spi 1 - enable spi bridge, 0 - disable 28 | */ 29 | void begin(int touch=1, int pixels=1, int spi=1); 30 | 31 | /** 32 | * play music file on sd card, support wav & mp3 33 | * 34 | * @param name music file without path 35 | */ 36 | void play(const char *name); 37 | 38 | /** 39 | * execute a shell command 40 | * 41 | * @param cmd command to be executed 42 | */ 43 | void exec(const char *cmd); 44 | 45 | /** 46 | * adjust touch threshold 47 | * 48 | * @return threshold 49 | */ 50 | uint16_t calibrate_touch(); 51 | 52 | /** 53 | * charge a touch button's capacity, read the charging time 54 | * 55 | * @return measurement value 56 | */ 57 | uint16_t read_touch(uint8_t id); 58 | 59 | /** 60 | * detect all touch buttons 61 | * 62 | * return touch buttons' status 63 | */ 64 | uint16_t detect_touch(); 65 | 66 | /** 67 | * set touch threshold 68 | * 69 | * @param threshold 70 | */ 71 | void set_touch_threshold(uint16_t threshold) { 72 | touch_threshold = threshold; 73 | } 74 | 75 | /** 76 | * enable/disable usb to serial bridge 77 | * 78 | * @param enable 0 - disable console, otherwise enable console 79 | */ 80 | void set_console(uint8_t enable=1) { 81 | console = enable; 82 | } 83 | 84 | /** 85 | * attach an interrupt handler which will be called when a touch event happens 86 | * 87 | * @param handler touch interrupt handler 88 | */ 89 | void attach_touch_handler(void (*handler)(uint8_t id, uint8_t event)) { 90 | touch_handler = handler; 91 | } 92 | 93 | /** 94 | * attach an interrupt handler which will be called when a spi packet is received 95 | * 96 | * @param handler spi interrupt handler 97 | */ 98 | void attach_spi_handler(void (*handler)(uint8_t addr, uint8_t *data, uint8_t len)) { 99 | spi_handler = handler; 100 | } 101 | 102 | 103 | /** 104 | * receive spi raw data, convert raw data into a packet with address and lenght 105 | * 106 | * @param data spi received raw data 107 | */ 108 | void handle_spi_data(uint8_t data); 109 | 110 | /** 111 | * attach an interrupt handler which will be called when a single byte is received from spi 112 | * 113 | * @param handler raw spi interrupt handler 114 | */ 115 | void attach_spi_raw_handler(void (*handler)(uint8_t data)) { 116 | spi_raw_handler = handler; 117 | } 118 | 119 | /** 120 | * Get the Pixels reference of the 12 pixels on respeaker 121 | * 122 | * @return Pixels reference 123 | */ 124 | Pixels &pixels() { 125 | return *pixels_ptr; 126 | } 127 | 128 | /** 129 | * called by serialEventRun() repeatedly 130 | */ 131 | void _loop(); 132 | 133 | public: 134 | void (*spi_raw_handler)(uint8_t data); 135 | void (*spi_handler)(uint8_t addr, uint8_t *data, uint8_t len); 136 | 137 | private: 138 | Pixels *pixels_ptr; 139 | uint8_t *touch_data; 140 | 141 | static const uint8_t touch_pins[TOUCH_NUM]; 142 | static const uint8_t touch_pins_id[TOUCH_NUM]; 143 | uint16_t touch_threshold; 144 | void (*touch_handler)(uint8_t id, uint8_t event); 145 | uint32_t last_touch_detected; 146 | 147 | uint8_t spi_state; 148 | uint8_t spi_data_address; 149 | uint8_t spi_data_length; 150 | uint8_t spi_buf_index; 151 | uint8_t *spi_buf; 152 | 153 | uint8_t console; 154 | }; 155 | 156 | extern ReSpeaker respeaker; 157 | 158 | #endif // __RESPEAKER_H__ 159 | --------------------------------------------------------------------------------