-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathIoTuz.cpp
240 lines (202 loc) · 8.18 KB
/
IoTuz.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/***************************************************
IoTuz class to provide basic driver methods for the ESP32 based IoTuz board
from LCA 2017: https://github.com/CCHS-Melbourne/iotuz-esp32-hardware
By Marc MERLIN <marc_soft@merlins.org>
License: Apache 2.0.
Required libraries:
- Wire.h to support the pcf8574 port expander
****************************************************/
#include <Wire.h>
#include "IoTuz.h"
volatile int16_t encoder0Pos = 0;
// These need to be global because all sketches use them as a global
// tft adafruit library (games use tft2 a separate library, for which we skip the init
// since the adafruit init works fine for both)
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
// faster, better lib, that doesn't work yet.
//ILI9341_t3 tft = ILI9341_t3(TFT_CS, TFT_DC, TFT_RST);
// If you are lacking the ESP32 patch, you will get no error, but the LEDs will not work
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, RGB_LED_PIN, NEO_GRB + NEO_KHZ800);
// ADXL345
Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);
// Until further notice, there is a hack to get HW SPI be as fast as SW SPI:
// in espressif/esp32/cores/esp32/esp32-hal.h after the first define, add
// #define CONFIG_DISABLE_HAL_LOCKS 1
// Use with caution, this may cause unknown issues
void read_encoder_ISR()
{
static uint8_t old_AB = 0;
// grey code
// http://hades.mech.northwestern.edu/index.php/Rotary_Encoder
// also read up on 'Understanding Quadrature Encoded Signals'
// https://www.pjrc.com/teensy/td_libs_Encoder.html
// another interesting lib: https://github.com/0xPIT/encoder/blob/arduino/ClickEncoder.cpp
static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
old_AB <<= 2;
old_AB |= ((digitalRead(ENCODERB_PIN))?(1<<1):0) | ((digitalRead(ENCODERA_PIN))?(1<<0):0);
encoder0Pos += ( enc_states[( old_AB & 0x0f )]);
}
// Talking to the port expander:
// I2C/TWI success (transaction was successful).
#define ku8TWISuccess 0
// I2C/TWI device not present (address sent, NACK received).
#define ku8TWIDeviceNACK 2
// I2C/TWI data not received (data sent, NACK received).
#define ku8TWIDataNACK 3
// I2C/TWI other error.
#define ku8TWIError 4
void IoTuz::pcf8574_write_(uint8_t dt)
{
uint8_t error;
Wire.beginTransmission(I2C_EXPANDER);
// Serial.print("Writing to I2CEXP: ");
// Serial.println(dt);
Wire.write(dt);
error = Wire.endTransmission();
if (error != ku8TWISuccess) {
// FIXME: do something here if you like
}
}
// To clear bit #7, send 128
void IoTuz::i2cexp_clear_bits(uint8_t bitfield)
{
// set bits to clear to 0, all other to 1, binary and to clear the bits
_i2cexp &= (~bitfield);
pcf8574_write_(_i2cexp);
}
// To set bit #7, send 128
void IoTuz::i2cexp_set_bits(uint8_t bitfield)
{
_i2cexp |= bitfield;
pcf8574_write_(_i2cexp);
}
uint8_t IoTuz::i2cexp_read()
{
// For read to work, we must have sent 1 bits on the ports that get used as input
// This is done by i2cexp_clear_bits called in setup.
Wire.requestFrom(I2C_EXPANDER, 1); // FIXME: deal with returned error here?
while (Wire.available() < 1) ;
uint8_t read = ~Wire.read(); // Apparently one has to invert the bits read
// When no buttons are pushed, this returns 0x91, which includes some ports
// we use as output, so we do need to filter out the ports used as read.
// Serial.println(read, HEX);
return read;
}
int16_t IoTuz::read_encoder()
{
return encoder0Pos;
}
bool IoTuz::encoder_changed() {
static int16_t old_encoder0Pos = 0;
if (encoder0Pos != old_encoder0Pos)
{
old_encoder0Pos = encoder0Pos;
return true;
}
return false;
}
ButtState IoTuz::read_encoder_button()
{
static bool butEnc = false;
uint8_t butt_state = i2cexp_read() & I2CEXP_ENC_BUT;
if (butt_state && !butEnc)
{
butEnc = true;
//Serial.println("Encoder Button Pushed");
return ENC_PUSHED;
}
if (!butt_state && butEnc)
{
butEnc = false;
//Serial.println("Encoder Button Released");
return ENC_RELEASED;
}
return (butt_state?ENC_DOWN:ENC_UP);
}
// True turns the BL on
void IoTuz::screen_bl(bool state) {
state ? i2cexp_clear_bits(I2CEXP_LCD_BL_CTR) : i2cexp_set_bits(I2CEXP_LCD_BL_CTR);
}
IoTuz::IoTuz()
{
// Any write to I2CEXP should contain those mask bits so allow reads to work later
_i2cexp = I2CEXP_IMASK;
pinMode (ENCODERA_PIN, INPUT_PULLUP);
pinMode (ENCODERB_PIN, INPUT_PULLUP);
pinMode(SPI_MOSI, OUTPUT);
pinMode(SPI_MISO, INPUT);
pinMode(SPI_CLK, OUTPUT);
// Joystick Setup
pinMode(JOYSTICK_BUT_PIN, INPUT_PULLUP);
// TFT Setup
pinMode(TFT_CS, OUTPUT);
pinMode(TFT_DC, OUTPUT);
pinMode(TFT_RST, OUTPUT);
}
void IoTuz::begin()
{
Serial.begin(115200);
Serial.println("Serial Begin");
// required for i2exp to work
Wire.begin();
// Hardware SPI on ESP32 is actually slower than software SPI. Giving 80Mhz
// here does not make things any faster. There seems to be a fair amount of
// overhead in the fancier hw SPI on ESP32 which is designed to send more than
// one byte at the time, and only ends up sending one byte when called from an
// arduino library.
// Sadly, using software SPI in the adafruit library would prevent SPI from working
// in the touch screen code which only supports hardware SPI
// The TFT code runs at 24Mhz as per below, but testing shows that any speed over 2Mhz
// seems ignored and taken down to 2Mhz
//SPI.beginTransaction(SPISettings(24000000, MSBFIRST, SPI_MODE0));
// Talking to the touch screen can only work at 2Mhz, and both drivers change the SPI
// speed before sending data, so this works transparently.
// ESP32 requires an extended begin with pin mappings (which is not supported by the
// adafruit library), so we do an explicit begin here and then the other SPI libraries work
// with hardware SPI as setup here (they will do a second begin without pin mappings and
// that will be ignored).
SPI.begin(SPI_CLK, SPI_MISO, SPI_MOSI);
// Turn off TFT by default.
// Note this also initializes the read bits on PCF8574 by setting them to 1 as per I2CEXP_IMASK
i2cexp_set_bits(I2CEXP_LCD_BL_CTR);
Serial.println("ILI9341 Test!");
tft.begin();
// read diagnostics (optional but can help debug problems)
uint8_t x = tft.readcommand8(ILI9341_RDMODE);
Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDMADCTL);
Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDPIXFMT);
Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDIMGFMT);
Serial.print("Image Format: 0x"); Serial.println(x, HEX);
x = tft.readcommand8(ILI9341_RDSELFDIAG);
Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);
tft.setRotation(3);
tftw = tft.width(), tfth = tft.height();
Serial.print("Resolution: "); Serial.print(tftw);
Serial.print(" x "); Serial.println(tfth);
Serial.println(F("Done!"));
// Init Accel
if(!accel.begin()) {
/* There was a problem detecting the ADXL345 ... check your connections */
Serial.println("Ooops, no ADXL345 detected ... Check your wiring!");
while(1);
}
accel.setRange(ADXL345_RANGE_16_G);
sensor_t sensor;
accel.getSensor(&sensor);
Serial.println("------------------------------------");
Serial.print ("Sensor: "); Serial.println(sensor.name);
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" m/s^2");
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" m/s^2");
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" m/s^2");
Serial.println("------------------------------------");
Serial.println("");
// Initialize rotary encoder reading and decoding
attachInterrupt(ENCODERA_PIN, read_encoder_ISR, CHANGE);
attachInterrupt(ENCODERB_PIN, read_encoder_ISR, CHANGE);
}
// vim:sts=4:sw=4