???
This commit is contained in:
12
Platforms.h
12
Platforms.h
@@ -23,8 +23,8 @@
|
||||
#define IN_FLASH ICACHE_FLASH_ATTR
|
||||
#endif
|
||||
|
||||
#define min(a,b) (a<b) ? (a) : (b)
|
||||
#define max(a,b) (a>b) ? (a) : (b)
|
||||
//#define min(a,b) (a<b) ? (a) : (b)
|
||||
//#define max(a,b) (a>b) ? (a) : (b)
|
||||
|
||||
//template <typename T> inline T min(const T a, const T b) {
|
||||
// return (a<b) ? (a) : (b);
|
||||
@@ -36,6 +36,14 @@
|
||||
|
||||
#if ESP8266
|
||||
#define sprintf os_sprintf
|
||||
extern "C" {
|
||||
#include "ets_sys.h"
|
||||
#include "c_types.h"
|
||||
#include "osapi.h"
|
||||
#include "user_interface.h"
|
||||
#include "mem.h"
|
||||
#include "espconn.h"
|
||||
}
|
||||
#elif ESP32
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -108,7 +108,7 @@ public:
|
||||
Scalar get() {
|
||||
const Scalar res = data[tail];
|
||||
tail = (tail + 1) % size;
|
||||
--used;
|
||||
if (used>0) {--used;}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,8 @@ public:
|
||||
/** get the pixel-width of the given char */
|
||||
uint8_t getCharWidht(char c) const {
|
||||
if (c == 32) {return 3;} // whitespace
|
||||
return offsets[c-off+1] - offsets[c-off];
|
||||
const int i = c-off;
|
||||
return offsets[i+1] - offsets[i];
|
||||
}
|
||||
|
||||
uint8_t getHeight() const {
|
||||
@@ -57,8 +58,8 @@ public:
|
||||
return sum;
|
||||
}
|
||||
|
||||
/** draw the given char at the given position */
|
||||
template <typename Scalar, typename Destination> void draw(const char* c, Scalar dx, Scalar dy, Destination& dst) {
|
||||
/** draw the given string at the given position */
|
||||
template <typename Scalar, typename Destination> void draw(const char* c, Scalar dx, Scalar dy, Destination& dst) const {
|
||||
while(*c) {
|
||||
draw(*c, dx, dy, dst);
|
||||
dx += getCharWidht(*c);// + 1;
|
||||
@@ -67,11 +68,10 @@ public:
|
||||
}
|
||||
|
||||
/** draw the given char at the given position */
|
||||
template <typename Scalar, typename Destination> void draw(unsigned char c, Scalar dx, Scalar dy, Destination& dst) {
|
||||
template <typename Scalar, typename Destination> void draw(unsigned char c, Scalar dx, Scalar dy, Destination& dst) const {
|
||||
|
||||
if (c == 32) {return;} // skip whitespace
|
||||
|
||||
|
||||
const uint16_t x1 = offsets[c-off];
|
||||
const uint16_t x2 = offsets[c-off+1];
|
||||
const uint16_t y1 = 0;
|
||||
@@ -80,8 +80,8 @@ public:
|
||||
for (uint16_t y = y1; y < y2; ++y) {
|
||||
for (uint16_t x = x1; x < x2; ++x) {
|
||||
const uint16_t idx = (x/8) + (y*this->w/8);
|
||||
const uint8_t pixel = data[idx] & (1<<(x&7));
|
||||
if (pixel) {
|
||||
const uint8_t pxInFont = data[idx] & (1<<(x&7)); // pixel from font glyph
|
||||
if (pxInFont) {
|
||||
dst.setPixel(dx+x-x1, dy+y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,17 +70,23 @@
|
||||
|
||||
|
||||
|
||||
class SSD1306 {
|
||||
template <typename I2C> class SSD1306 {
|
||||
|
||||
private:
|
||||
|
||||
static constexpr uint8_t ADDR7 = 0b0111100;
|
||||
bool inited = false;
|
||||
|
||||
I2C& i2c;
|
||||
|
||||
public:
|
||||
|
||||
SSD1306(I2C& i2c) : i2c(i2c) {
|
||||
|
||||
}
|
||||
|
||||
bool isPresent() {
|
||||
return i2c::query(ADDR7);
|
||||
return i2c.query(ADDR7);
|
||||
}
|
||||
|
||||
void initOnce() {
|
||||
@@ -137,15 +143,15 @@ public:
|
||||
// i2c::stop();
|
||||
// }
|
||||
|
||||
i2c::startWrite(ADDR7);
|
||||
bool ok = i2c::writeByteAndCheck(0x40);
|
||||
i2c.startWrite(ADDR7);
|
||||
bool ok = i2c.writeByteAndCheck(0x40);
|
||||
if (!ok) {os_printf("failed write data\n");}
|
||||
|
||||
for (uint16_t i=0; i < (SSD1306_LCDWIDTH*SSD1306_LCDHEIGHT/8); i++) {
|
||||
i2c::writeByteAndCheck(data[i]);
|
||||
i2c.writeByteAndCheck(data[i]);
|
||||
}
|
||||
|
||||
i2c::stop();
|
||||
i2c.stop();
|
||||
|
||||
}
|
||||
|
||||
@@ -240,13 +246,13 @@ private:
|
||||
|
||||
void sendCommand(uint8_t cmd) {
|
||||
bool ok;
|
||||
ok = i2c::startWrite(ADDR7);
|
||||
ok = i2c.startWrite(ADDR7);
|
||||
if (!ok) {os_printf("failed start write\n");}
|
||||
ok = i2c::writeByteAndCheck(0x00); // command
|
||||
ok = i2c.writeByteAndCheck(0x00); // command
|
||||
if (!ok) {os_printf("failed command mode\n");}
|
||||
ok = i2c::writeByteAndCheck(cmd);
|
||||
ok = i2c.writeByteAndCheck(cmd);
|
||||
if (!ok) {os_printf("failed command\n");}
|
||||
i2c::stop();
|
||||
i2c.stop();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
#ifndef WS2812B_H
|
||||
#define WS2812B_H
|
||||
|
||||
|
||||
#include "../../data/Color.h"
|
||||
#include "../../Platforms.h"
|
||||
#include "../../Debug.h"
|
||||
|
||||
#include "../../io/GPIO.h"
|
||||
|
||||
|
||||
|
||||
@@ -17,9 +16,9 @@
|
||||
|
||||
static constexpr const char* NAME = "WS2812B";
|
||||
|
||||
// #define LED_SET_PIN_TO_OUTPUT GPIO5_OUTPUT_SET
|
||||
// #define LED_SET_PIN_H GPIO5_H
|
||||
// #define LED_SET_PIN_L GPIO5_L
|
||||
#define LED_SET_PIN_TO_OUTPUT GPIO5_OUTPUT_SET
|
||||
#define LED_SET_PIN_H GPIO5_H
|
||||
#define LED_SET_PIN_L GPIO5_L
|
||||
|
||||
//#define NS_PER_TICK ( (1000ul*1000ul*1000ul) / (80ul*1000ul*1000ul) )
|
||||
|
||||
@@ -453,34 +452,19 @@
|
||||
|
||||
};
|
||||
|
||||
#elif false //ESP32
|
||||
#elif ESP32
|
||||
|
||||
#include <driver/gpio.h>
|
||||
#include <rom/ets_sys.h>
|
||||
#include <xtensa/core-macros.h>
|
||||
#include "driver/timer.h"
|
||||
#include "../../io/I2S.h"
|
||||
|
||||
static constexpr timer_group_t grp = TIMER_GROUP_0;
|
||||
static constexpr timer_idx_t idx = TIMER_0;
|
||||
template <int PIN_DATA, int NUM_LEDS> class WS2812B {
|
||||
|
||||
template <int numLEDs, gpio_num_t outPin> class WS2812B;
|
||||
|
||||
static IRAM_ATTR void myISR(void* arg) {
|
||||
printf("interrupt\n");
|
||||
//WS2812B* leds = (WS2812B*) arg;
|
||||
//timer_pause(grp, idx);
|
||||
//leds->flushOLD();
|
||||
}
|
||||
|
||||
template <int numLEDs, gpio_num_t outPin> class WS2812B {
|
||||
|
||||
static constexpr const char* TAG = "WS2812";
|
||||
|
||||
/** enable/disable each led */
|
||||
bool enabled[numLEDs] = {true};
|
||||
static constexpr const char* TAG = "WS2818B";
|
||||
|
||||
/** color-value for each attached LED */
|
||||
Color colors[numLEDs];
|
||||
Color colors[NUM_LEDS];
|
||||
|
||||
/** enable/disable each led */
|
||||
bool enabled[NUM_LEDS] = {true};
|
||||
|
||||
public:
|
||||
|
||||
@@ -490,13 +474,11 @@
|
||||
}
|
||||
|
||||
void init() {
|
||||
|
||||
ESP_LOGI(TAG, "init()");
|
||||
|
||||
gpio_set_direction(outPin, GPIO_MODE_OUTPUT);
|
||||
|
||||
debugMod1(TAG, "init with %d leds", NUM_LEDS);
|
||||
cfg();
|
||||
}
|
||||
|
||||
|
||||
/** set the color for the given LED */
|
||||
void setColor(const uint8_t idx, const Color rgb) {
|
||||
colors[idx] = rgb;
|
||||
@@ -504,7 +486,7 @@
|
||||
|
||||
/** set the color for all LEDs */
|
||||
void setColor(const Color rgb) {
|
||||
for (int idx = 0; idx < numLEDs; ++idx) {
|
||||
for (int idx = 0; idx < NUM_LEDS; ++idx) {
|
||||
colors[idx] = rgb;
|
||||
}
|
||||
}
|
||||
@@ -516,7 +498,7 @@
|
||||
|
||||
/** enable/disable all LEDs */
|
||||
void setEnabled(const bool en) {
|
||||
for (int idx = 0; idx < numLEDs; ++idx) {
|
||||
for (int idx = 0; idx < NUM_LEDS; ++idx) {
|
||||
enabled[idx] = en;
|
||||
}
|
||||
}
|
||||
@@ -530,75 +512,46 @@
|
||||
return colors[idx];
|
||||
}
|
||||
|
||||
|
||||
timer_config_t config;
|
||||
|
||||
/** flush configured changes */
|
||||
IRAM_ATTR void flush() {
|
||||
|
||||
printf("flush()\n");
|
||||
|
||||
config.alarm_en = 1;
|
||||
config.auto_reload = 1;
|
||||
config.counter_dir = TIMER_COUNT_UP;
|
||||
config.divider = 2;
|
||||
config.intr_type = TIMER_INTR_LEVEL;
|
||||
config.counter_en = TIMER_PAUSE;
|
||||
|
||||
|
||||
|
||||
ESP_ERROR_CHECK(timer_init(grp, idx, &config));
|
||||
|
||||
ESP_ERROR_CHECK(timer_set_counter_value(grp, idx, 0));
|
||||
ESP_ERROR_CHECK(timer_set_alarm_value(grp, idx, 2));
|
||||
ESP_ERROR_CHECK(timer_enable_intr(grp, idx));
|
||||
ESP_ERROR_CHECK(timer_isr_register(grp, idx, myISR, (void*)this, ESP_INTR_FLAG_IRAM, NULL));
|
||||
|
||||
printf("start()\n");
|
||||
ESP_ERROR_CHECK(timer_start(grp, idx));
|
||||
|
||||
void flush() {
|
||||
flushBrightness(255);
|
||||
}
|
||||
|
||||
void flushBrightness(const uint8_t brightness) {
|
||||
|
||||
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
|
||||
portENTER_CRITICAL(&mux);
|
||||
|
||||
IRAM_ATTR void flushOLD() {
|
||||
|
||||
ESP_LOGI(TAG, "sending %d LEDs", numLEDs);
|
||||
|
||||
// important! otherwise often interrupted within
|
||||
portDISABLE_INTERRUPTS();
|
||||
|
||||
//portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
|
||||
//portENTER_CRITICAL(&myMutex);
|
||||
//for (volatile int i = 0; i < 256; ++i) {;}
|
||||
//while (_getCycleCount() > 10000000) {;}
|
||||
|
||||
volatile uint8_t _x;
|
||||
for (int i = 4; i >= 0; --i) {_x = colors[i].r;}
|
||||
|
||||
// process each LED
|
||||
for (int i = 0; i < numLEDs; ++i) {
|
||||
for (int i = 0; i < NUM_LEDS; ++i) {
|
||||
|
||||
portDISABLE_INTERRUPTS();
|
||||
const volatile Color c = colors[i];
|
||||
_x = colors[i+1].r;
|
||||
|
||||
if (enabled[i]) {
|
||||
sendByte(c.g);
|
||||
sendByte(c.r);
|
||||
sendByte(c.b);
|
||||
} else {
|
||||
sendByte(0);
|
||||
sendByte(0);
|
||||
sendByte(0);
|
||||
}
|
||||
// send each LEDs 24-bit GRB data
|
||||
const Color rgb = colors[i].brightness(brightness);
|
||||
sendByte(rgb.g);
|
||||
sendByte(rgb.r);
|
||||
sendByte(rgb.b);
|
||||
|
||||
}
|
||||
|
||||
//portEXIT_CRITICAL(&myMutex);
|
||||
|
||||
portENABLE_INTERRUPTS();
|
||||
portEXIT_CRITICAL(&mux);
|
||||
delay5000();
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
static inline uint32_t _getCycleCount(void) {
|
||||
uint32_t ccount;
|
||||
__asm__ __volatile__("rsr %0,ccount":"=a" (ccount));
|
||||
return ccount;
|
||||
}
|
||||
|
||||
/** send one whole byte */
|
||||
inline void sendByte(const uint8_t b) {
|
||||
if (b & 0b10000000) {send1();} else {send0();}
|
||||
if (b & 0b01000000) {send1();} else {send0();}
|
||||
@@ -610,300 +563,111 @@
|
||||
if (b & 0b00000001) {send1();} else {send0();}
|
||||
}
|
||||
|
||||
/** send a 0 (short 1 pulse, long 0 pulse) */
|
||||
inline void send0() {
|
||||
gpio_set_level(outPin, 1);
|
||||
delayShort();
|
||||
gpio_set_level(outPin, 0);
|
||||
delayLong();
|
||||
}
|
||||
|
||||
/** send a 1 (long 1 pulse, short 0 pulse) */
|
||||
inline void send1() {
|
||||
gpio_set_level(outPin, 1);
|
||||
delayLong();
|
||||
gpio_set_level(outPin, 0);
|
||||
delayShort();
|
||||
MyGPIO::set(PIN_DATA);
|
||||
delay800();
|
||||
MyGPIO::clear(PIN_DATA);
|
||||
delay100();
|
||||
}
|
||||
|
||||
inline void delayShort() {
|
||||
volatile int i;
|
||||
i = 0; i = 1; i = 2; i = 3;
|
||||
(void) i;
|
||||
inline void send0() {
|
||||
MyGPIO::set(PIN_DATA);
|
||||
delay100();
|
||||
MyGPIO::clear(PIN_DATA);
|
||||
delay800();
|
||||
}
|
||||
|
||||
inline void delayLong() {
|
||||
volatile int j;
|
||||
j = 0; j = 1; j = 2; j = 3;
|
||||
j = 4; j = 5; j = 6; j = 7;
|
||||
j = 8; j = 9; j = 1; j = 2;
|
||||
(void) j;
|
||||
// for (size_t i = 0; i < 16; ++i) {
|
||||
// asm volatile("nop");
|
||||
// }
|
||||
void delay100() {
|
||||
//for (volatile uint8_t i = 0; i < 1; ++i) {;}
|
||||
const uint32_t start = _getCycleCount();
|
||||
while (_getCycleCount() < start + 10) {;}
|
||||
}
|
||||
|
||||
void delay800() {
|
||||
//for (volatile uint8_t i = 0; i < 10; ++i) {;}
|
||||
const uint32_t start = _getCycleCount();
|
||||
while (_getCycleCount() < start + 100) {;}
|
||||
}
|
||||
|
||||
void delay5000() {
|
||||
//for (volatile uint8_t i = 0; i < 10; ++i) {;}
|
||||
const uint32_t start = _getCycleCount();
|
||||
while (_getCycleCount() < start + 1000) {;}
|
||||
}
|
||||
|
||||
void cfg() {
|
||||
MyGPIO::setOutput(PIN_DATA);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
#ifdef xxx
|
||||
|
||||
#elif false //othertest
|
||||
/** comm via I2S */
|
||||
using MyI2S = I2S<PIN_DATA,0,0>;
|
||||
MyI2S i2s;
|
||||
|
||||
//#include <driver/gpio.h>
|
||||
#include <rom/ets_sys.h>
|
||||
#include <xtensa/core-macros.h>
|
||||
#include <driver/rmt.h>
|
||||
#include <soc/rmt_struct.h>
|
||||
|
||||
template <int numLEDs, gpio_num_t outPin> class WS2812B {
|
||||
|
||||
static constexpr const char* TAG = "WS2812";
|
||||
static constexpr rmt_channel_t chan = RMT_CHANNEL_0;
|
||||
|
||||
//#define portDISABLE_INTERRUPTS() do { XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL); portbenchmarkINTERRUPT_DISABLE(); } while (0)
|
||||
//#define portENABLE_INTERRUPTS() do { portbenchmarkINTERRUPT_RESTORE(0); XTOS_SET_INTLEVEL(0); } while (0)
|
||||
//#define ENABLE_INTERRUPTS() portENABLE_INTERRUPTS()
|
||||
//#define DISABLE_INTERRUPTS() portDISABLE_INTERRUPTS()
|
||||
|
||||
static constexpr int numBits = (3*8) * 2; // (r,g,b) each 8 bit NOTE! must be < 64 to fit into the buffer!
|
||||
//static constexpr int numItems = 256;//(numLEDs*3)*8;
|
||||
//static constexpr int numItems = (numLEDs*3)*8;
|
||||
rmt_item32_t items[numBits+1]; // + one entry has two bits + 0-terminator (just like within strings)
|
||||
|
||||
/** enable/disable each led */
|
||||
bool enabled[numLEDs] = {true};
|
||||
|
||||
/** color-value for each attached LED */
|
||||
Color colors[numLEDs];
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
WS2812B() {
|
||||
init();
|
||||
void cfg() {
|
||||
const uint32_t sRate = 1000*1000 / (1.0) / 2 / 2;
|
||||
i2s.configure(sRate, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_STEREO);
|
||||
}
|
||||
|
||||
void init() {
|
||||
/** flush configured changes, including global brightness */
|
||||
void flushBrightness(const uint8_t brightness) {
|
||||
|
||||
ESP_LOGI(TAG, "init()");
|
||||
|
||||
rmt_config_t cfg;
|
||||
cfg.rmt_mode = RMT_MODE_TX;
|
||||
cfg.channel = chan;
|
||||
cfg.gpio_num = outPin;
|
||||
cfg.mem_block_num = 1;//chan+1;//8-chan;//chan+1;//8 - chan; //chan+1;//
|
||||
cfg.clk_div = 8;
|
||||
cfg.tx_config.loop_en = false;
|
||||
cfg.tx_config.carrier_en = false;
|
||||
cfg.tx_config.idle_output_en = true;
|
||||
cfg.tx_config.idle_level = (rmt_idle_level_t)0;
|
||||
cfg.tx_config.carrier_freq_hz = 10000;
|
||||
cfg.tx_config.carrier_level = (rmt_carrier_level_t)1;
|
||||
cfg.tx_config.carrier_duty_percent = 50;
|
||||
|
||||
ESP_ERROR_CHECK(rmt_config(&cfg));
|
||||
|
||||
// disable when using custom ISR
|
||||
//ESP_ERROR_CHECK(rmt_driver_install(chan, 0, 0));
|
||||
|
||||
// setup constant values once
|
||||
for (int idx = 0; idx < numBits; ++idx) {
|
||||
items[idx].duration0 = 0;
|
||||
items[idx].level0 = 1;
|
||||
items[idx].duration1 = 0;
|
||||
items[idx].level1 = 0;
|
||||
}
|
||||
items[numBits].val = 0; // 0 terminator
|
||||
|
||||
ESP_LOGI(TAG, "init OK!");
|
||||
|
||||
}
|
||||
|
||||
/** set the color for the given LED */
|
||||
void setColor(const uint8_t idx, const Color rgb) {
|
||||
colors[idx] = rgb;
|
||||
}
|
||||
|
||||
/** set the color for all LEDs */
|
||||
void setColor(const Color rgb) {
|
||||
for (int idx = 0; idx < numLEDs; ++idx) {
|
||||
colors[idx] = rgb;
|
||||
}
|
||||
}
|
||||
|
||||
/** enable/disable the given LED */
|
||||
void setEnabled(const uint8_t idx, const bool en) {
|
||||
enabled[idx] = en;
|
||||
}
|
||||
|
||||
/** enable/disable all LEDs */
|
||||
void setEnabled(const bool en) {
|
||||
for (int idx = 0; idx < numLEDs; ++idx) {
|
||||
enabled[idx] = en;
|
||||
}
|
||||
}
|
||||
|
||||
/** is the given LED enabled? */
|
||||
bool isEnabled(const uint8_t idx) const {
|
||||
return enabled[idx];
|
||||
}
|
||||
|
||||
Color& getColor(const uint8_t idx) {
|
||||
return colors[idx];
|
||||
}
|
||||
|
||||
int nextLED;
|
||||
|
||||
/** flush configured changes */
|
||||
/*
|
||||
void flush() {
|
||||
|
||||
nextLED = 0;
|
||||
ESP_LOGI(TAG, "sending %d LEDs", numLEDs);
|
||||
|
||||
// important! otherwise often interrupted within
|
||||
portDISABLE_INTERRUPTS();
|
||||
|
||||
for (int i = 0; i < 1024; ++i) {
|
||||
asm volatile("nop");
|
||||
}
|
||||
|
||||
//waitForTX();
|
||||
|
||||
const size_t toWrite = 8+8+8+1;// 8-bit R, 8-bit G, 8-bit B, null-terminator
|
||||
|
||||
// add null terminator
|
||||
items[toWrite-1].val = 0;
|
||||
// seems important for i2s ?
|
||||
reset();
|
||||
uint8_t tmp[8*3];
|
||||
|
||||
// process each LED
|
||||
for (int i = 0; i < numLEDs; i+=2) {
|
||||
for (int i = 0; i < NUM_LEDS; ++i) {
|
||||
|
||||
enqueueNext();
|
||||
|
||||
// add null terminator
|
||||
//items[idx].val = 0;
|
||||
|
||||
// wait for sending to complete using the RMT Unit's status
|
||||
waitForTX();
|
||||
|
||||
ESP_ERROR_CHECK(rmt_fill_tx_items(this->chan, items, toWrite, 0));
|
||||
ESP_ERROR_CHECK(rmt_tx_start(this->chan, true));
|
||||
|
||||
// reset for next round
|
||||
//idx = 0;
|
||||
|
||||
}
|
||||
|
||||
//waitForTX();
|
||||
|
||||
portENABLE_INTERRUPTS();
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
static constexpr int toWrite = 8+8+8+1;
|
||||
rmt_isr_handle_t isrHandle;
|
||||
|
||||
void flush() {
|
||||
|
||||
nextLED = 0;
|
||||
ESP_LOGI(TAG, "sending %d LEDs", numLEDs);
|
||||
|
||||
enqueueNext();
|
||||
|
||||
ESP_ERROR_CHECK(rmt_isr_register(onISR, this, ESP_INTR_FLAG_LEVEL1, &isrHandle));
|
||||
ESP_ERROR_CHECK(rmt_set_tx_thr_intr_en(this->chan, true, toWrite/2));
|
||||
//ESP_ERROR_CHECK(rmt_set_tx_intr_en(this->chan, true));
|
||||
|
||||
printf("_start\n");
|
||||
ESP_ERROR_CHECK(rmt_tx_start(this->chan, true));
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static IRAM_ATTR void onISR(void* arg) {
|
||||
printf(".\n");
|
||||
WS2812B* led = (WS2812B*) arg;
|
||||
if (led->nextLED < numLEDs) {
|
||||
led->enqueueNext();
|
||||
// send each LEDs 24-bit GRB data
|
||||
if (enabled[i]) {
|
||||
const Color rgb = colors[i].brightness(brightness);
|
||||
sendByte(rgb.g, &tmp[0]);
|
||||
sendByte(rgb.r, &tmp[8]);
|
||||
sendByte(rgb.b, &tmp[16]);
|
||||
} else {
|
||||
rmt_tx_stop(led->chan);
|
||||
}
|
||||
sendByte(0, &tmp[0]);
|
||||
sendByte(0, &tmp[8]);
|
||||
sendByte(0, &tmp[16]);
|
||||
}
|
||||
|
||||
void IRAM_ATTR enqueueNext() {
|
||||
|
||||
printf("e\n");
|
||||
int idx = 0;
|
||||
|
||||
if (enabled[nextLED]) {
|
||||
emplaceByte(colors[nextLED].g, idx);
|
||||
emplaceByte(colors[nextLED].r, idx);
|
||||
emplaceByte(colors[nextLED].b, idx);
|
||||
} else {
|
||||
emplaceByte(0, idx);
|
||||
emplaceByte(0, idx);
|
||||
emplaceByte(0, idx);
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(rmt_fill_tx_items(this->chan, items, toWrite, 0));
|
||||
|
||||
++nextLED;
|
||||
i2s.add(tmp, sizeof(tmp));
|
||||
|
||||
}
|
||||
|
||||
void waitForTX() {
|
||||
|
||||
uint32_t status; // status while sending: 16797696 ??
|
||||
for (int i = 0; i < 2000; ++i) {
|
||||
rmt_get_status(this->chan, &status);
|
||||
if (status == 0) {break;}
|
||||
//if (status != 16797696) {break;}
|
||||
//if ( (status & (1<<24)) == 0 ) {break;} // somewhat OK
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// for (int i = 0; i < 1000; ++i) {
|
||||
// asm volatile("nop");
|
||||
// }
|
||||
|
||||
void reset() {
|
||||
const uint8_t lo[64] = {
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
|
||||
};
|
||||
for (int i = 0; i < 8 ; ++i) {
|
||||
i2s.add(lo, sizeof(lo));
|
||||
}
|
||||
}
|
||||
|
||||
/** send one whole byte */
|
||||
inline void emplaceByte(const uint8_t b, int& idx) {
|
||||
if (b & 0b10000000) {emplace1(idx);} else {emplace0(idx);}
|
||||
if (b & 0b01000000) {emplace1(idx);} else {emplace0(idx);}
|
||||
if (b & 0b00100000) {emplace1(idx);} else {emplace0(idx);}
|
||||
if (b & 0b00010000) {emplace1(idx);} else {emplace0(idx);}
|
||||
if (b & 0b00001000) {emplace1(idx);} else {emplace0(idx);}
|
||||
if (b & 0b00000100) {emplace1(idx);} else {emplace0(idx);}
|
||||
if (b & 0b00000010) {emplace1(idx);} else {emplace0(idx);}
|
||||
if (b & 0b00000001) {emplace1(idx);} else {emplace0(idx);}
|
||||
static constexpr const uint8_t DATA0 = 0b11100000;
|
||||
static constexpr const uint8_t DATA1 = 0b11111000;
|
||||
|
||||
// send 1 LED byte. 1 bit to send = 8 byte i2s. also converts to little endian
|
||||
inline void sendByte(const uint8_t b, uint8_t* dst) {
|
||||
if (b & 0b10000000) {dst[1] = DATA1;} else {dst[1] = DATA0;}
|
||||
if (b & 0b01000000) {dst[0] = DATA1;} else {dst[0] = DATA0;}
|
||||
if (b & 0b00100000) {dst[3] = DATA1;} else {dst[3] = DATA0;}
|
||||
if (b & 0b00010000) {dst[2] = DATA1;} else {dst[2] = DATA0;}
|
||||
if (b & 0b00001000) {dst[5] = DATA1;} else {dst[5] = DATA0;}
|
||||
if (b & 0b00000100) {dst[4] = DATA1;} else {dst[4] = DATA0;}
|
||||
if (b & 0b00000010) {dst[7] = DATA1;} else {dst[7] = DATA0;}
|
||||
if (b & 0b00000001) {dst[6] = DATA1;} else {dst[6] = DATA0;}
|
||||
}
|
||||
|
||||
/** emplace a 0 (short 1 pulse, long 0 pulse) */
|
||||
inline void emplace0(int& idx) {
|
||||
items[idx].duration0 = 2;//1;
|
||||
//items[idx].level0 = 1;
|
||||
items[idx].duration1 = 8;//7;
|
||||
//items[idx].level1 = 0;
|
||||
++idx;
|
||||
}
|
||||
|
||||
/** emplace a 1 (long 1 pulse, short 0 pulse) */
|
||||
inline void emplace1(int& idx) {
|
||||
items[idx].duration0 = 7;//6;
|
||||
//items[idx].level0 = 1;
|
||||
items[idx].duration1 = 3;//2;
|
||||
//items[idx].level1 = 0;
|
||||
++idx;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
33
ext/poti/MCP42xxx.h
Normal file
33
ext/poti/MCP42xxx.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "../../io/GPIO.h"
|
||||
#include "../../Debug.h"
|
||||
|
||||
|
||||
template <typename SPI, int PIN_CS> class MCP42xxx {
|
||||
|
||||
private:
|
||||
|
||||
SPI& spi;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
MCP42xxx(SPI& spi) : spi(spi) {
|
||||
;
|
||||
}
|
||||
|
||||
void setVolume(const uint8_t vol) {
|
||||
|
||||
debugMod1(TAG, "setVolume(%d)", vol);
|
||||
|
||||
MyGPIO::setOutput(PIN_CS);
|
||||
MyGPIO::clear(PIN_CS);
|
||||
|
||||
const uint8_t cmd = 0b00010011; // xx 01=write xx 11=both
|
||||
spi.writeByte(cmd);
|
||||
spi.writeByte(vol);
|
||||
|
||||
MyGPIO::set(PIN_CS);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
9
ext/rf/SX1276.h
Normal file
9
ext/rf/SX1276.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef RF_SX1276
|
||||
#define RF_SX1276
|
||||
|
||||
class SX1276 {
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,9 +1,10 @@
|
||||
#ifndef SENS_BME280
|
||||
#define SENS_BME280
|
||||
|
||||
#include "../../io/SoftI2C.h"
|
||||
#include "../../Platforms.h"
|
||||
#include "../../Debug.h"
|
||||
|
||||
class BME280 {
|
||||
template <typename I2C> class BME280 {
|
||||
|
||||
static constexpr const char* NAME = "BME280";
|
||||
|
||||
@@ -53,11 +54,15 @@ public:
|
||||
} cal;
|
||||
|
||||
|
||||
I2C& i2c;
|
||||
|
||||
BME280(I2C& i2c) : i2c(i2c) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool isPresent() {
|
||||
return i2c::query(ADDR7);
|
||||
return i2c.query(ADDR7);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -178,20 +183,20 @@ public:
|
||||
bool ok;
|
||||
|
||||
// address the slave in write mode and select the first register to read
|
||||
ok = i2c::startWrite(ADDR7);
|
||||
ok = i2c.startWrite(ADDR7);
|
||||
if (!ok) {os_printf("failed start write\n"); return false;}
|
||||
ok = i2c::writeByteAndCheck(addr);
|
||||
ok = i2c.writeByteAndCheck(addr);
|
||||
if (!ok) {os_printf("failed to select register %d\n", addr); return false;}
|
||||
|
||||
//i2c::stop();
|
||||
|
||||
// address the slave in read mode and read [len] registers
|
||||
ok = i2c::startRead(ADDR7);
|
||||
ok = i2c.startRead(ADDR7);
|
||||
if (!ok) {os_printf("failed start read\n"); return 0;}
|
||||
i2c::readBytes(dst, len);
|
||||
i2c.readBytes(dst, len);
|
||||
|
||||
// done
|
||||
i2c::stop();
|
||||
i2c.stop();
|
||||
return true;
|
||||
|
||||
}
|
||||
@@ -201,15 +206,15 @@ public:
|
||||
bool ok;
|
||||
|
||||
// address the slave in write mode and select the first register to read
|
||||
ok = i2c::startWrite(ADDR7);
|
||||
ok = i2c.startWrite(ADDR7);
|
||||
if (!ok) {os_printf("failed start write\n"); return false;}
|
||||
ok = i2c::writeByteAndCheck(addr);
|
||||
ok = i2c.writeByteAndCheck(addr);
|
||||
if (!ok) {os_printf("failed to select register %d\n", addr); return false;}
|
||||
ok = i2c::writeBytesAndCheck(src, len);
|
||||
ok = i2c.writeBytesAndCheck(src, len);
|
||||
if (!ok) {os_printf("failed to write register contents \n"); return false;}
|
||||
|
||||
// done
|
||||
i2c::stop();
|
||||
i2c.stop();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
415
ext/sens/MAX30102.h
Normal file
415
ext/sens/MAX30102.h
Normal file
@@ -0,0 +1,415 @@
|
||||
#ifndef MAX30102_H
|
||||
#define MAX30102_H
|
||||
|
||||
#include "../../Platforms.h"
|
||||
//#include "../../io/HardI2C.h"
|
||||
#include "../../io/SoftI2C.h"
|
||||
|
||||
// https://www.roboter-bausatz.de/media/pdf/bf/52/37/RBS12853_MAX30102-DS-917698.pdf
|
||||
// https://github.com/sparkfun/SparkFun_MAX3010x_Sensor_Library/blob/master/src/MAX30105.cpp
|
||||
// https://github.com/vrano714/max30102-tutorial-raspberrypi/blob/master/max30102.py
|
||||
|
||||
/** SPI-like touch controller */
|
||||
template <typename I2C> class Max30102 {
|
||||
|
||||
public:
|
||||
|
||||
class Listener {
|
||||
public:
|
||||
virtual void onIR(const uint32_t ir) = 0;
|
||||
virtual void onRed(const uint32_t red) = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
I2C& i2c;
|
||||
|
||||
static constexpr const char* NAME = "Max30102";
|
||||
static constexpr uint8_t ADDR = 0b1010111;
|
||||
|
||||
// Status Registers
|
||||
static const uint8_t MAX30105_INTSTAT1 = 0x00;
|
||||
static const uint8_t MAX30105_INTSTAT2 = 0x01;
|
||||
static const uint8_t MAX30105_INTENABLE1 = 0x02;
|
||||
static const uint8_t MAX30105_INTENABLE2 = 0x03;
|
||||
|
||||
// FIFO Registers
|
||||
static const uint8_t MAX30105_FIFOWRITEPTR = 0x04;
|
||||
static const uint8_t MAX30105_FIFOOVERFLOW = 0x05;
|
||||
static const uint8_t MAX30105_FIFOREADPTR = 0x06;
|
||||
static const uint8_t MAX30105_FIFODATA = 0x07;
|
||||
|
||||
// Configuration Registers
|
||||
static const uint8_t MAX30105_FIFOCONFIG = 0x08;
|
||||
static const uint8_t MAX30105_MODECONFIG = 0x09;
|
||||
static const uint8_t MAX30105_PARTICLECONFIG = 0x0A; // Note, sometimes listed as "SPO2" config in datasheet (pg. 11)
|
||||
static const uint8_t MAX30105_LED1_PULSEAMP = 0x0C;
|
||||
static const uint8_t MAX30105_LED2_PULSEAMP = 0x0D;
|
||||
//static const uint8_t MAX30105_LED3_PULSEAMP = 0x0E; // not available for MAX30102
|
||||
static const uint8_t MAX30105_LED_PROX_AMP = 0x10;
|
||||
static const uint8_t MAX30105_MULTILEDCONFIG1 = 0x11;
|
||||
static const uint8_t MAX30105_MULTILEDCONFIG2 = 0x12;
|
||||
|
||||
// Die Temperature Registers
|
||||
static const uint8_t MAX30105_DIETEMPINT = 0x1F;
|
||||
static const uint8_t MAX30105_DIETEMPFRAC = 0x20;
|
||||
static const uint8_t MAX30105_DIETEMPCONFIG = 0x21;
|
||||
|
||||
// Proximity Function Registers
|
||||
static const uint8_t MAX30105_PROXINTTHRESH = 0x30;
|
||||
|
||||
// Part ID Registers
|
||||
static const uint8_t MAX30105_REVISIONID = 0xFE;
|
||||
static const uint8_t MAX30105_PARTID = 0xFF; // Should always be 0x15. Identical to MAX30102.
|
||||
|
||||
// MAX30105 Commands
|
||||
// Interrupt configuration (pg 13, 14)
|
||||
static const uint8_t MAX30105_INT_A_FULL_MASK = (uint8_t)~0b10000000;
|
||||
static const uint8_t MAX30105_INT_A_FULL_ENABLE = 0x80;
|
||||
static const uint8_t MAX30105_INT_A_FULL_DISABLE = 0x00;
|
||||
|
||||
static const uint8_t MAX30105_INT_DATA_RDY_MASK = (uint8_t)~0b01000000;
|
||||
static const uint8_t MAX30105_INT_DATA_RDY_ENABLE = 0x40;
|
||||
static const uint8_t MAX30105_INT_DATA_RDY_DISABLE = 0x00;
|
||||
|
||||
static const uint8_t MAX30105_INT_ALC_OVF_MASK = (uint8_t)~0b00100000;
|
||||
static const uint8_t MAX30105_INT_ALC_OVF_ENABLE = 0x20;
|
||||
static const uint8_t MAX30105_INT_ALC_OVF_DISABLE = 0x00;
|
||||
|
||||
static const uint8_t MAX30105_INT_PROX_INT_MASK = (uint8_t)~0b00010000;
|
||||
static const uint8_t MAX30105_INT_PROX_INT_ENABLE = 0x10;
|
||||
static const uint8_t MAX30105_INT_PROX_INT_DISABLE = 0x00;
|
||||
|
||||
static const uint8_t MAX30105_INT_DIE_TEMP_RDY_MASK = (uint8_t)~0b00000010;
|
||||
static const uint8_t MAX30105_INT_DIE_TEMP_RDY_ENABLE = 0x02;
|
||||
static const uint8_t MAX30105_INT_DIE_TEMP_RDY_DISABLE = 0x00;
|
||||
|
||||
static const uint8_t MAX30105_SAMPLEAVG_MASK = (uint8_t)~0b11100000;
|
||||
static const uint8_t MAX30105_SAMPLEAVG_1 = 0x00;
|
||||
static const uint8_t MAX30105_SAMPLEAVG_2 = 0x20;
|
||||
static const uint8_t MAX30105_SAMPLEAVG_4 = 0x40;
|
||||
static const uint8_t MAX30105_SAMPLEAVG_8 = 0x60;
|
||||
static const uint8_t MAX30105_SAMPLEAVG_16 = 0x80;
|
||||
static const uint8_t MAX30105_SAMPLEAVG_32 = 0xA0;
|
||||
|
||||
static const uint8_t MAX30105_ROLLOVER_MASK = 0xEF;
|
||||
static const uint8_t MAX30105_ROLLOVER_ENABLE = 0x10;
|
||||
static const uint8_t MAX30105_ROLLOVER_DISABLE = 0x00;
|
||||
|
||||
static const uint8_t MAX30105_A_FULL_MASK = 0xF0;
|
||||
|
||||
// Mode configuration commands (page 19)
|
||||
static const uint8_t MAX30105_SHUTDOWN_MASK = 0x7F;
|
||||
static const uint8_t MAX30105_SHUTDOWN = 0x80;
|
||||
static const uint8_t MAX30105_WAKEUP = 0x00;
|
||||
|
||||
static const uint8_t MAX30105_RESET_MASK = 0xBF;
|
||||
static const uint8_t MAX30105_RESET = 0x40;
|
||||
|
||||
static const uint8_t MAX30105_MODE_MASK = 0xF8;
|
||||
static const uint8_t MAX30105_MODE_REDONLY = 0x02;
|
||||
static const uint8_t MAX30105_MODE_REDIRONLY = 0x03;
|
||||
static const uint8_t MAX30105_MODE_MULTILED = 0x07;
|
||||
|
||||
// Particle sensing configuration commands (pgs 19-20)
|
||||
static const uint8_t MAX30105_ADCRANGE_MASK = 0x9F;
|
||||
static const uint8_t MAX30105_ADCRANGE_2048 = 0x00;
|
||||
static const uint8_t MAX30105_ADCRANGE_4096 = 0x20;
|
||||
static const uint8_t MAX30105_ADCRANGE_8192 = 0x40;
|
||||
static const uint8_t MAX30105_ADCRANGE_16384 = 0x60;
|
||||
|
||||
static const uint8_t MAX30105_SAMPLERATE_MASK = 0xE3;
|
||||
static const uint8_t MAX30105_SAMPLERATE_50 = 0x00;
|
||||
static const uint8_t MAX30105_SAMPLERATE_100 = 0x04;
|
||||
static const uint8_t MAX30105_SAMPLERATE_200 = 0x08;
|
||||
static const uint8_t MAX30105_SAMPLERATE_400 = 0x0C;
|
||||
static const uint8_t MAX30105_SAMPLERATE_800 = 0x10;
|
||||
static const uint8_t MAX30105_SAMPLERATE_1000 = 0x14;
|
||||
static const uint8_t MAX30105_SAMPLERATE_1600 = 0x18;
|
||||
static const uint8_t MAX30105_SAMPLERATE_3200 = 0x1C;
|
||||
|
||||
static const uint8_t MAX30105_PULSEWIDTH_MASK = 0xFC;
|
||||
static const uint8_t MAX30105_PULSEWIDTH_69 = 0x00;
|
||||
static const uint8_t MAX30105_PULSEWIDTH_118 = 0x01;
|
||||
static const uint8_t MAX30105_PULSEWIDTH_215 = 0x02;
|
||||
static const uint8_t MAX30105_PULSEWIDTH_411 = 0x03;
|
||||
|
||||
//Multi-LED Mode configuration (pg 22)
|
||||
static const uint8_t MAX30105_SLOT1_MASK = 0xF8;
|
||||
static const uint8_t MAX30105_SLOT2_MASK = 0x8F;
|
||||
static const uint8_t MAX30105_SLOT3_MASK = 0xF8;
|
||||
static const uint8_t MAX30105_SLOT4_MASK = 0x8F;
|
||||
|
||||
static const uint8_t SLOT_NONE = 0x00;
|
||||
static const uint8_t SLOT_RED_LED = 0x01;
|
||||
static const uint8_t SLOT_IR_LED = 0x02;
|
||||
static const uint8_t SLOT_GREEN_LED = 0x03;
|
||||
static const uint8_t SLOT_NONE_PILOT = 0x04;
|
||||
static const uint8_t SLOT_RED_PILOT = 0x05;
|
||||
static const uint8_t SLOT_IR_PILOT = 0x06;
|
||||
static const uint8_t SLOT_GREEN_PILOT = 0x07;
|
||||
|
||||
static const uint8_t MAX_30105_EXPECTEDPARTID = 0x15;
|
||||
|
||||
Listener* listener = nullptr;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
Max30102(I2C& i2c) : i2c(i2c) {
|
||||
;
|
||||
}
|
||||
|
||||
void setListener(Listener* l) {
|
||||
this->listener = l;
|
||||
}
|
||||
|
||||
bool isPresent() {
|
||||
return i2c.query(ADDR);
|
||||
}
|
||||
|
||||
uint8_t getRevisionID() {
|
||||
return i2c.readReg8(ADDR, MAX30105_REVISIONID);
|
||||
}
|
||||
|
||||
uint8_t getPartID() {
|
||||
return i2c.readReg8(ADDR, MAX30105_PARTID);
|
||||
}
|
||||
|
||||
|
||||
void softReset(void) {
|
||||
|
||||
bitMask(MAX30105_MODECONFIG, MAX30105_RESET_MASK, MAX30105_RESET);
|
||||
|
||||
// Poll for bit to clear, reset is then complete
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
const uint8_t response = i2c.readReg8(ADDR, MAX30105_MODECONFIG);
|
||||
if ((response & MAX30105_RESET) == 0) break; //We're done!
|
||||
vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
ESP_LOGI(NAME, "softReset done");
|
||||
|
||||
}
|
||||
|
||||
// void MAX30105::shutDown(void) {
|
||||
// // Put IC into low power mode (datasheet pg. 19)
|
||||
// // During shutdown the IC will continue to respond to I2C commands but will
|
||||
// // not update with or take new readings (such as temperature)
|
||||
// bitMask(MAX30105_MODECONFIG, MAX30105_SHUTDOWN_MASK, MAX30105_SHUTDOWN);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
void setModePulse() {
|
||||
|
||||
//wakeUp();
|
||||
softReset();
|
||||
//wakeUp();
|
||||
|
||||
writeReg8(MAX30105_INTENABLE1, 0x00);// | MAX30105_INT_DATA_RDY_ENABLE);//64);//16|64);//0xC0);
|
||||
writeReg8(MAX30105_INTENABLE2, 0x00);
|
||||
|
||||
//writeReg8(MAX30105_PROXINTTHRESH, 0);
|
||||
//writeReg8(MAX30105_PifROXINTTHRESH, 64);
|
||||
|
||||
|
||||
//setLEDMode(MAX30105_MODE_REDONLY);
|
||||
setLEDMode(MAX30105_MODE_REDIRONLY);
|
||||
//setLEDMode(MAX30105_MODE_MULTILED);
|
||||
|
||||
writeReg8(MAX30105_FIFOCONFIG, MAX30105_SAMPLEAVG_8 | MAX30105_ROLLOVER_ENABLE);
|
||||
|
||||
//setFIFOAverage(MAX30105_SAMPLEAVG_8);
|
||||
setADCRange(MAX30105_ADCRANGE_16384);
|
||||
setSampleRate(MAX30105_SAMPLERATE_200);
|
||||
setPulseWidth(MAX30105_PULSEWIDTH_215);
|
||||
|
||||
//Default is 0x1F which gets us 6.4mA
|
||||
//powerLevel = 0x02, 0.4mA - Presence detection of ~4 inch
|
||||
//powerLevel = 0x1F, 6.4mA - Presence detection of ~8 inch
|
||||
//powerLevel = 0x7F, 25.4mA - Presence detection of ~8 inch
|
||||
//powerLevel = 0xFF, 50.0mA - Presence detection of ~12 inch
|
||||
|
||||
const int powerLevel = 0x30;
|
||||
setPulseAmplitudeRed(powerLevel);
|
||||
setPulseAmplitudeIR(powerLevel);
|
||||
setPulseAmplitudeProximity(powerLevel);
|
||||
|
||||
// THIS ONE ONLY WORKS FOR "MAX30105_MODE_MULTILED" ?!
|
||||
// writeReg8(MAX30105_MULTILEDCONFIG1, (SLOT_RED_PILOT<<4) | (SLOT_RED_LED<<0) );
|
||||
// writeReg8(MAX30105_MULTILEDCONFIG2, (SLOT_IR_PILOT<<4) | (SLOT_IR_LED<<0) );
|
||||
// ------
|
||||
// writeReg8(MAX30105_MULTILEDCONFIG1, (SLOT_IR_LED<<4) | (SLOT_RED_LED<<0) );
|
||||
// writeReg8(MAX30105_MULTILEDCONFIG2, 0 );
|
||||
|
||||
clearFIFO();
|
||||
}
|
||||
|
||||
void writeReg8(const uint8_t reg, const uint8_t val) {
|
||||
ESP_LOGI(NAME, "write reg: 0x%02x <- val: %d", reg, val);
|
||||
i2c.writeReg8(ADDR, reg, val);
|
||||
}
|
||||
|
||||
uint8_t readReg8(const uint8_t reg) {
|
||||
return i2c.readReg8(ADDR, reg);
|
||||
}
|
||||
|
||||
// //Check for new data but give up after a certain amount of time
|
||||
// //Returns true if new data was found
|
||||
// //Returns false if new data was not found
|
||||
// bool safeCheck(uint8_t maxTimeToCheck) {
|
||||
|
||||
// for (int i = 0; i < maxTimeToCheck; ++i) {
|
||||
// if(check() == true) {
|
||||
// return(true);
|
||||
// }
|
||||
// vTaskDelay(1 / portTICK_PERIOD_MS);
|
||||
// }
|
||||
// return false;
|
||||
|
||||
// }
|
||||
|
||||
|
||||
void check(void) {
|
||||
|
||||
// const uint8_t intr1 = readReg8(MAX30105_INTSTAT1);
|
||||
// const uint8_t intr2 = readReg8(MAX30105_INTSTAT2);
|
||||
// // new data available?
|
||||
// //if (intr1 & 64) { .. }
|
||||
|
||||
|
||||
uint8_t readPointer = getReadPointer();
|
||||
const uint8_t writePointer = getWritePointer();
|
||||
|
||||
//uint8_t readPointer = getReadPointer();
|
||||
//const uint8_t writePointer = getWritePointer();
|
||||
//ESP_LOGI(NAME, "intr. %d %d", readPointer, writePointer);
|
||||
|
||||
while (readPointer != writePointer) {
|
||||
|
||||
//printf(";%d;%d\n", readPointer, writePointer);
|
||||
|
||||
uint8_t tmp[6];
|
||||
i2c.readReg(ADDR, MAX30105_FIFODATA, 6, tmp);
|
||||
|
||||
const uint32_t val1 = ((tmp[0] << 16) | (tmp[1] << 8) | (tmp[2] << 0)) & 0x3FFFF; //Zero out all but 18 bits
|
||||
const uint32_t val2 = ((tmp[3] << 16) | (tmp[4] << 8) | (tmp[5] << 0)) & 0x3FFFF; //Zero out all but 18 bits
|
||||
|
||||
//printf(";%d;%d;%d;%d\n", readPointer, writePointer, val1, val2);//, val3, val4);
|
||||
|
||||
// inc
|
||||
readPointer = (readPointer + 1) % 32;
|
||||
|
||||
// callback
|
||||
if (listener) {
|
||||
listener->onRed(val1);
|
||||
listener->onIR(val2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int8_t getTemp() {
|
||||
|
||||
// trigger temp acquire
|
||||
writeReg8(MAX30105_DIETEMPCONFIG, 1);
|
||||
|
||||
int8_t full = readReg8(MAX30105_DIETEMPINT);
|
||||
//uint8_f frac = i2c.readReg8(MAX30105_DIETEMPFRAC);
|
||||
return full;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void wakeUp(void) {
|
||||
// Pull IC out of low power mode (datasheet pg. 19)
|
||||
bitMask(MAX30105_MODECONFIG, MAX30105_SHUTDOWN_MASK, MAX30105_WAKEUP);
|
||||
}
|
||||
|
||||
void setLEDMode(uint8_t mode) {
|
||||
// Set which LEDs are used for sampling -- Red only, RED+IR only, or custom.
|
||||
// See datasheet, page 18
|
||||
bitMask(MAX30105_MODECONFIG, MAX30105_MODE_MASK, mode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void setPulseAmplitudeRed(uint8_t amplitude) {
|
||||
writeReg8( MAX30105_LED1_PULSEAMP, amplitude);
|
||||
}
|
||||
|
||||
void setPulseAmplitudeIR(uint8_t amplitude) {
|
||||
writeReg8(MAX30105_LED2_PULSEAMP, amplitude);
|
||||
}
|
||||
|
||||
// void setPulseAmplitudeGreen(uint8_t amplitude) {
|
||||
// writeReg8(MAX30105_LED3_PULSEAMP, amplitude);
|
||||
// }
|
||||
|
||||
void setPulseAmplitudeProximity(uint8_t amplitude) {
|
||||
writeReg8(MAX30105_LED_PROX_AMP, amplitude);
|
||||
}
|
||||
|
||||
void setFIFOAverage(uint8_t numberOfSamples) {
|
||||
bitMask(MAX30105_FIFOCONFIG, MAX30105_SAMPLEAVG_MASK, numberOfSamples);
|
||||
}
|
||||
|
||||
void enableFIFORollover(void) {
|
||||
bitMask(MAX30105_FIFOCONFIG, MAX30105_ROLLOVER_MASK, MAX30105_ROLLOVER_ENABLE);
|
||||
}
|
||||
|
||||
void setADCRange(uint8_t adcRange) {
|
||||
// adcRange: one of MAX30105_ADCRANGE_2048, _4096, _8192, _16384
|
||||
bitMask(MAX30105_PARTICLECONFIG, MAX30105_ADCRANGE_MASK, adcRange);
|
||||
}
|
||||
|
||||
void setSampleRate(uint8_t sampleRate) {
|
||||
// sampleRate: one of MAX30105_SAMPLERATE_50, _100, _200, _400, _800, _1000, _1600, _3200
|
||||
bitMask(MAX30105_PARTICLECONFIG, MAX30105_SAMPLERATE_MASK, sampleRate);
|
||||
}
|
||||
|
||||
void setPulseWidth(uint8_t pulseWidth) {
|
||||
// pulseWidth: one of MAX30105_PULSEWIDTH_69, _188, _215, _411
|
||||
bitMask(MAX30105_PARTICLECONFIG, MAX30105_PULSEWIDTH_MASK, pulseWidth);
|
||||
}
|
||||
|
||||
|
||||
void clearFIFO(void) {
|
||||
writeReg8(MAX30105_FIFOWRITEPTR, 0);
|
||||
writeReg8(MAX30105_FIFOOVERFLOW, 0);
|
||||
writeReg8(MAX30105_FIFOREADPTR, 0);
|
||||
}
|
||||
|
||||
//Read the FIFO Write Pointer
|
||||
uint8_t getWritePointer(void) {
|
||||
return readReg8(MAX30105_FIFOWRITEPTR);
|
||||
}
|
||||
|
||||
//Read the FIFO Read Pointer
|
||||
uint8_t getReadPointer(void) {
|
||||
return readReg8(MAX30105_FIFOREADPTR);
|
||||
}
|
||||
|
||||
//Given a register, read it, mask it, and then set the thing
|
||||
void bitMask(const uint8_t reg, const uint8_t mask, const uint8_t thing) {
|
||||
|
||||
const uint8_t orig = i2c.readReg8(ADDR, reg);
|
||||
const uint8_t masked = orig & mask;
|
||||
const uint8_t out = masked | thing;
|
||||
|
||||
ESP_LOGI(NAME, "reg: %d - orig: %d new: %d", reg, orig, out);
|
||||
|
||||
writeReg8(reg, out);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // MAX30102_H
|
||||
50
io/GPIO.h
50
io/GPIO.h
@@ -8,7 +8,7 @@
|
||||
|
||||
#include "fastGPIO.h"
|
||||
|
||||
struct GPIO {
|
||||
struct MyGPIO {
|
||||
|
||||
static inline bool get(const uint8_t num) {
|
||||
return GPIO_INPUT_GET(num);
|
||||
@@ -64,6 +64,34 @@
|
||||
}
|
||||
}
|
||||
|
||||
static inline void setPullUp(const uint8_t num) {
|
||||
switch(num) {
|
||||
case 0: GPIO0_INPUT_PULLUP_SET; break;
|
||||
case 1: GPIO1_INPUT_PULLUP_SET; break;
|
||||
case 2: GPIO2_INPUT_PULLUP_SET; break;
|
||||
case 3: GPIO3_INPUT_PULLUP_SET; break;
|
||||
case 4: GPIO4_INPUT_PULLUP_SET; break;
|
||||
case 5: GPIO5_INPUT_PULLUP_SET; break;
|
||||
//case 6: GPIO6_INPUT_PULLUP_SET; break;
|
||||
//case 7: GPIO7_INPUT_PULLUP_SET; break;
|
||||
//case 8: GPIO8_INPUT_PULLUP_SET; break;
|
||||
case 9: GPIO9_INPUT_PULLUP_SET; break;
|
||||
case 10: GPIO10_INPUT_PULLUP_SET; break;
|
||||
//case 11: GPIO11_INPUT_PULLUP_SET; break;
|
||||
case 12: GPIO12_INPUT_PULLUP_SET; break;
|
||||
case 13: GPIO13_INPUT_PULLUP_SET; break;
|
||||
case 14: GPIO14_INPUT_PULLUP_SET; break;
|
||||
case 15: GPIO15_INPUT_PULLUP_SET; break;
|
||||
}
|
||||
}
|
||||
|
||||
static void toggleBuiltInLED() {
|
||||
static bool level = false;
|
||||
setOutput(2);
|
||||
level = !level;
|
||||
if (level) {set(2);} else {clear(2);}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#elif ESP32
|
||||
@@ -87,24 +115,40 @@
|
||||
|
||||
static inline void set(const uint8_t num) {
|
||||
WRITE_PERI_REG(GPIO_OUT_W1TS_REG, 1 << num);
|
||||
//gpio_set_level((gpio_num_t)num, 1);
|
||||
}
|
||||
|
||||
static inline void clear(const uint8_t num) {
|
||||
WRITE_PERI_REG(GPIO_OUT_W1TC_REG, 1 << num);
|
||||
//gpio_set_level((gpio_num_t)num, 0);
|
||||
}
|
||||
|
||||
static inline void setOutput(const uint8_t num) {
|
||||
setOutput((gpio_num_t)num);
|
||||
}
|
||||
static inline void setOutput(const gpio_num_t num) {
|
||||
gpio_set_direction(num, GPIO_MODE_OUTPUT);
|
||||
//gpio_set_direction(num, GPIO_MODE_OUTPUT); // does not always suffice?!
|
||||
gpio_config_t io_conf;
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1<<num);
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
static inline void setInput(const uint8_t num) {
|
||||
setInput((gpio_num_t)num);
|
||||
}
|
||||
static inline void setInput(const gpio_num_t num) {
|
||||
gpio_set_direction(num, GPIO_MODE_INPUT);
|
||||
//gpio_set_direction(num, GPIO_MODE_INPUT); // does not always suffice?!
|
||||
gpio_config_t io_conf;
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pin_bit_mask = (1<<num);
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
gpio_config(&io_conf);
|
||||
}
|
||||
|
||||
static void toggleBuiltInLED() {
|
||||
|
||||
109
io/I2S.h
Normal file
109
io/I2S.h
Normal file
@@ -0,0 +1,109 @@
|
||||
#ifndef I2S_H
|
||||
#define I2S_H
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "driver/i2s.h"
|
||||
|
||||
template <int PIN_DATA, int PIN_CLK, int PIN_LR> class I2S {
|
||||
|
||||
static constexpr i2s_port_t port = I2S_NUM_0;
|
||||
i2s_config_t cfg;
|
||||
|
||||
struct Setup {
|
||||
uint32_t sampleRate = 0;
|
||||
i2s_bits_per_sample_t bitsPerSample = I2S_BITS_PER_SAMPLE_8BIT;
|
||||
i2s_channel_t channels = I2S_CHANNEL_MONO;
|
||||
} cur;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
I2S() {
|
||||
|
||||
#ifdef CONFIG_A2DP_SINK_OUTPUT_INTERNAL_DAC
|
||||
cfg.mode = static_cast<i2s_mode_t>(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN);
|
||||
#else
|
||||
cfg.mode = static_cast<i2s_mode_t>(I2S_MODE_MASTER | I2S_MODE_TX);
|
||||
#endif
|
||||
|
||||
cfg.dma_buf_count = 6;
|
||||
cfg.dma_buf_len = 128;
|
||||
|
||||
cfg.sample_rate = 44100;
|
||||
cfg.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT;
|
||||
cfg.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT; //2-channels
|
||||
cfg.communication_format = I2S_COMM_FORMAT_I2S_MSB;
|
||||
|
||||
|
||||
cfg.intr_alloc_flags = 0; //Default interrupt priority
|
||||
cfg.tx_desc_auto_clear = true; //Auto clear tx descriptor on underflow
|
||||
|
||||
i2s_driver_install(port, &cfg, 0, nullptr);
|
||||
|
||||
#ifdef CONFIG_A2DP_SINK_OUTPUT_INTERNAL_DAC
|
||||
i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
|
||||
i2s_set_pin(0, NULL);
|
||||
#else
|
||||
i2s_pin_config_t pins;
|
||||
pins.bck_io_num = PIN_CLK;//CONFIG_I2S_BCK_PIN;
|
||||
pins.ws_io_num = PIN_LR;//CONFIG_I2S_LRCK_PIN;
|
||||
pins.data_out_num = PIN_DATA;//CONFIG_I2S_DATA_PIN;
|
||||
pins.data_in_num = -1; //Not used
|
||||
i2s_set_pin(port, &pins);
|
||||
#endif
|
||||
|
||||
configure(44100, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_STEREO);
|
||||
|
||||
}
|
||||
|
||||
/** change the i2s configuration */
|
||||
void configure(const uint32_t sampleRate, const i2s_bits_per_sample_t bitsPerSample, const i2s_channel_t channels) {
|
||||
|
||||
// only update when changed!
|
||||
if (cur.sampleRate != sampleRate || cur.bitsPerSample != bitsPerSample || cur.channels != channels) {
|
||||
i2s_set_clk(port, sampleRate, bitsPerSample, channels); // update
|
||||
cur.sampleRate = sampleRate;
|
||||
cur.bitsPerSample = bitsPerSample;
|
||||
cur.channels = channels;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** add the given samples for playback. returns the number of added samples, which might be less in case of timeouts */
|
||||
size_t add(const uint8_t* data, const size_t len) {
|
||||
size_t written;
|
||||
i2s_write(port, data, len, &written, portMAX_DELAY);
|
||||
return written;
|
||||
}
|
||||
|
||||
uint16_t tmp[2048];
|
||||
|
||||
size_t addSignedToUnsigned(const uint8_t* data, const size_t len) {
|
||||
const int16_t* src = (const int16_t*) data;
|
||||
uint16_t* dst = (uint16_t*) data;
|
||||
for (int i = 0; i < len/2; ++i) {
|
||||
//dst[i] = (int)src[i] + (int)32768;
|
||||
//dst[i] = (int)src[i] / 270 + 128;
|
||||
tmp[i] = (int)src[i] + 32768;
|
||||
}
|
||||
//return add(data, len);
|
||||
return add((const uint8_t*)tmp, len);
|
||||
}
|
||||
|
||||
// /** add the given samples for playback. blocks until all have been added */
|
||||
// void addAll(const uint8_t* data, const size_t len) {
|
||||
// size_t added = add(data, len);
|
||||
// len -= added;
|
||||
// data +=
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // I2S_H
|
||||
293
io/SoftI2C.h
293
io/SoftI2C.h
@@ -6,10 +6,284 @@
|
||||
#include "GPIO.h"
|
||||
|
||||
|
||||
/** new implementation */
|
||||
template <int PIN_SDA, int PIN_SCL, bool fast> class SoftI2C {
|
||||
|
||||
static constexpr const char* NAME = "softI2C";
|
||||
|
||||
inline void sdaDirOut() {MyGPIO::setOutput(PIN_SDA);}
|
||||
inline void sdaDirIn() {MyGPIO::setInput(PIN_SDA);}
|
||||
|
||||
inline void sclDirOut() {MyGPIO::setOutput(PIN_SCL);}
|
||||
|
||||
inline void sdaHi() {MyGPIO::set(PIN_SDA);}
|
||||
inline void sdaLo() {MyGPIO::clear(PIN_SDA);}
|
||||
inline bool sdaRead() {return MyGPIO::get(PIN_SDA);}
|
||||
|
||||
inline void sclHi() {MyGPIO::set(PIN_SCL);}
|
||||
inline void sclLo() {MyGPIO::clear(PIN_SCL);}
|
||||
|
||||
inline void waitLong() {
|
||||
for (uint8_t i = 0; i < 240; ++i) {
|
||||
__asm__ __volatile__("nop");
|
||||
__asm__ __volatile__("nop");
|
||||
}
|
||||
}
|
||||
|
||||
inline void waitShort() {
|
||||
for (uint8_t i = 0; i < 240; ++i) {
|
||||
__asm__ __volatile__("nop");
|
||||
__asm__ __volatile__("nop");
|
||||
}
|
||||
}
|
||||
|
||||
void init() {
|
||||
debugMod2(NAME, "init. SDA: %d, SCL: %d", PIN_SDA, PIN_SCL);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
SoftI2C() {
|
||||
init();
|
||||
}
|
||||
|
||||
/** start communication */
|
||||
inline void start() {
|
||||
|
||||
sdaDirOut();
|
||||
sclDirOut();
|
||||
|
||||
sdaHi();
|
||||
sclHi();
|
||||
|
||||
waitLong();
|
||||
sdaLo();
|
||||
|
||||
waitLong();
|
||||
sclLo();
|
||||
|
||||
waitLong();
|
||||
|
||||
}
|
||||
|
||||
/** stop communication */
|
||||
inline void stop() {
|
||||
|
||||
sdaDirOut();
|
||||
sclDirOut();
|
||||
|
||||
sdaLo();
|
||||
sclLo();
|
||||
|
||||
waitLong();
|
||||
sclHi();
|
||||
|
||||
waitLong();
|
||||
sdaHi();
|
||||
|
||||
sdaDirIn(); // free the bus
|
||||
|
||||
waitLong();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** read the given number of bytes from the slave and generate ACK/NACK as needed */
|
||||
void readBytes(uint8_t* dst, uint8_t len) {
|
||||
while(len) {
|
||||
*dst = _readByte();
|
||||
--len;
|
||||
++dst;
|
||||
if (len) {_writeAck();} else {_writeNAck();} // done? or want more?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// write one byte to the bus and check slave's ACK/NACK
|
||||
bool IN_FLASH writeByteAndCheck(const uint8_t byte) {
|
||||
_writeByte(byte);
|
||||
return _readAck();
|
||||
}
|
||||
|
||||
// write several bytes to the bus and check slave's ACK/NACK
|
||||
bool IN_FLASH writeBytesAndCheck(const uint8_t* src, uint8_t len) {
|
||||
while(len) {
|
||||
const bool ok = writeByteAndCheck(*src);
|
||||
if (!ok) {return false;}
|
||||
--len; ++src;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
inline bool startWrite(const uint8_t addr7) {
|
||||
start();
|
||||
_writeByte( (addr7<<1) | 0 );
|
||||
const bool ok = _readAck();
|
||||
return ok;
|
||||
}
|
||||
|
||||
inline bool startRead(const uint8_t addr7) {
|
||||
start();
|
||||
_writeByte( (addr7<<1) | 1 );
|
||||
const bool ok = _readAck();
|
||||
return ok;
|
||||
}
|
||||
|
||||
inline bool query(const uint8_t addr7) {
|
||||
const bool ok = startWrite(addr7);
|
||||
stop();
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
uint8_t readReg8(const uint8_t addr, const uint8_t reg) {
|
||||
uint8_t dst = 0xFF;
|
||||
readReg(addr, reg, 1, &dst);
|
||||
return dst;
|
||||
}
|
||||
|
||||
bool readReg(const uint8_t addr, const uint8_t reg, const uint8_t len, uint8_t* dst) {
|
||||
|
||||
bool ok;
|
||||
|
||||
// select register(s) to read
|
||||
ok = startWrite(addr);
|
||||
if (!ok) {debugMod(NAME, "failed start write1\n"); return false;}
|
||||
ok = writeByteAndCheck(reg);
|
||||
if (!ok) {debugMod(NAME, "failed select register\n"); return false;}
|
||||
stop();
|
||||
|
||||
// read register(s)
|
||||
ok = startRead(addr);
|
||||
if (!ok) {debugMod(NAME, "failed start write2\n"); return false;}
|
||||
readBytes(dst, len);
|
||||
stop();
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool writeReg(const uint8_t addr, const uint8_t reg, const uint8_t len, const uint8_t* src) {
|
||||
|
||||
bool ok;
|
||||
|
||||
// address the slave in write mode and select the first register to read
|
||||
ok = startWrite(addr);
|
||||
if (!ok) {debugMod(NAME, "failed start write\n"); return false;}
|
||||
ok = writeByteAndCheck(reg);
|
||||
if (!ok) {debugMod1(NAME, "failed to select register %d\n", addr); return false;}
|
||||
ok = writeBytesAndCheck(src, len);
|
||||
if (!ok) {debugMod(NAME, "failed to write register contents \n"); return false;}
|
||||
|
||||
// done
|
||||
stop();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool writeReg8(const uint8_t addr, const uint8_t reg, const uint8_t val) {
|
||||
return writeReg(addr, reg, 1, &val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/** write one bit to the bus */
|
||||
inline void _writeBit(const bool out) {
|
||||
//sdaDirOut(); // switch to output mode
|
||||
if(out) {sdaHi();} else {sdaLo();} // apply data
|
||||
sclHi(); // clock pulse
|
||||
waitShort();
|
||||
sclLo();
|
||||
waitShort();
|
||||
//sdaDirIn(); // free the bus
|
||||
}
|
||||
|
||||
/** read one bit from the bus */
|
||||
inline uint8_t _readBit() {
|
||||
//sdaDirIn(); // switch to input mode
|
||||
sclHi(); // clock pulse and read
|
||||
waitShort();
|
||||
const uint8_t val = sdaRead();
|
||||
sclLo();
|
||||
waitShort();
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// read 8 bits from the bus, WITHOUT sending ACK/NACK
|
||||
uint8_t _readByte() {
|
||||
sdaDirIn(); // switch SDA to input mode
|
||||
return
|
||||
(_readBit() << 7) |
|
||||
(_readBit() << 6) |
|
||||
(_readBit() << 5) |
|
||||
(_readBit() << 4) |
|
||||
(_readBit() << 3) |
|
||||
(_readBit() << 2) |
|
||||
(_readBit() << 1) |
|
||||
(_readBit() << 0);
|
||||
}
|
||||
|
||||
inline bool _readAck() {
|
||||
sdaDirIn(); // switch to input mode
|
||||
const uint8_t res = _readBit();
|
||||
return res == 0; // ACK when input pulled low
|
||||
}
|
||||
|
||||
|
||||
// write one byte to the bus
|
||||
void _writeByte(const uint8_t byte) {
|
||||
sdaDirOut(); // switch SDA to output mode
|
||||
_writeBit(byte & (1<<7));
|
||||
_writeBit(byte & (1<<6));
|
||||
_writeBit(byte & (1<<5));
|
||||
_writeBit(byte & (1<<4));
|
||||
_writeBit(byte & (1<<3));
|
||||
_writeBit(byte & (1<<2));
|
||||
_writeBit(byte & (1<<1));
|
||||
_writeBit(byte & (1<<0));
|
||||
}
|
||||
|
||||
inline void _writeAck() {
|
||||
sdaDirOut(); // switch SDA to output mode
|
||||
_writeBit(0);
|
||||
}
|
||||
|
||||
inline void _writeNAck() {
|
||||
sdaDirOut(); // switch SDA to output mode
|
||||
_writeBit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
#if ESP8266
|
||||
#include "fastGPIO.h"
|
||||
#elif ESP32
|
||||
# error "Not yet supported"
|
||||
#include "GPIO.h"
|
||||
#endif
|
||||
|
||||
// https://www.best-microcontroller-projects.com/i2c-tutorial.html
|
||||
@@ -42,6 +316,8 @@ namespace i2c {
|
||||
|
||||
#elif ESP32
|
||||
//# error "Not yet supported"
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -127,7 +403,7 @@ namespace i2c {
|
||||
}
|
||||
|
||||
|
||||
/** write one bit to the bus */
|
||||
// write one bit to the bus
|
||||
static inline void writeBit(const bool out) {
|
||||
sdaDirOut(); // switch to output mode
|
||||
if(out) {sdaHi();} else {sdaLo();} // apply data
|
||||
@@ -138,7 +414,7 @@ namespace i2c {
|
||||
sdaDirIn(); // free the bus
|
||||
}
|
||||
|
||||
/** read one bit from the bus */
|
||||
// read one bit from the bus
|
||||
static inline uint8_t readBit() {
|
||||
sdaDirIn(); // switch to input mode
|
||||
sclHi(); // clock pulse and read
|
||||
@@ -163,7 +439,7 @@ namespace i2c {
|
||||
writeBit(1);
|
||||
}
|
||||
|
||||
/** read 8 bits from the bus, WITHOUT sending ACK/NACK */
|
||||
// read 8 bits from the bus, WITHOUT sending ACK/NACK
|
||||
static uint8_t IN_FLASH readByte() {
|
||||
return
|
||||
(readBit() << 7) |
|
||||
@@ -176,7 +452,7 @@ namespace i2c {
|
||||
(readBit() << 0);
|
||||
}
|
||||
|
||||
/** read the given number of bytes from the slave and generate ACK/NACK as needed */
|
||||
// read the given number of bytes from the slave and generate ACK/NACK as needed
|
||||
static void readBytes(uint8_t* dst, uint8_t len) {
|
||||
while(len) {
|
||||
*dst = readByte();
|
||||
@@ -186,7 +462,7 @@ namespace i2c {
|
||||
}
|
||||
}
|
||||
|
||||
/** write one byte to the bus */
|
||||
// write one byte to the bus
|
||||
static void IN_FLASH writeByte(const uint8_t byte) {
|
||||
writeBit(byte & BIT( 7));
|
||||
writeBit(byte & BIT( 6));
|
||||
@@ -198,13 +474,13 @@ namespace i2c {
|
||||
writeBit(byte & BIT( 0));
|
||||
}
|
||||
|
||||
/** write one byte to the bus and check slave's ACK/NACK */
|
||||
// write one byte to the bus and check slave's ACK/NACK
|
||||
static bool IN_FLASH writeByteAndCheck(const uint8_t byte) {
|
||||
writeByte(byte);
|
||||
return readAck();
|
||||
}
|
||||
|
||||
/** write several bytes to the bus and check slave's ACK/NACK */
|
||||
// write several bytes to the bus and check slave's ACK/NACK
|
||||
static bool IN_FLASH writeBytesAndCheck(const uint8_t* src, uint8_t len) {
|
||||
while(len) {
|
||||
const bool ok = writeByteAndCheck(*src);
|
||||
@@ -236,5 +512,6 @@ namespace i2c {
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
#endif // SOFTSPI_H
|
||||
|
||||
22
io/SoftSPI.h
22
io/SoftSPI.h
@@ -347,10 +347,10 @@ public:
|
||||
|
||||
private:
|
||||
void init() {
|
||||
debugMod(NAME, "init()");
|
||||
GPIO::setInput(PIN_MISO);
|
||||
GPIO::setOutput(PIN_MOSI);
|
||||
GPIO::setOutput(PIN_CLK);
|
||||
debugMod3(NAME, "init() MISO:%d MOSI:%d CLK:%d", PIN_MISO, PIN_MOSI, PIN_CLK);
|
||||
if (PIN_MISO) {MyGPIO::setInput(PIN_MISO);}
|
||||
if (PIN_MOSI) {MyGPIO::setOutput(PIN_MOSI);}
|
||||
MyGPIO::setOutput(PIN_CLK);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -363,12 +363,12 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
inline void clkLo() { GPIO::clear(PIN_CLK); }
|
||||
inline void clkHi() { GPIO::set(PIN_CLK); }
|
||||
inline void clkLo() { MyGPIO::clear(PIN_CLK); }
|
||||
inline void clkHi() { MyGPIO::set(PIN_CLK); }
|
||||
|
||||
/** write one bit to the bus */
|
||||
inline void writeBit(const bool out) {
|
||||
if(out) {GPIO::set(PIN_MOSI);} else {GPIO::clear(PIN_MOSI);}
|
||||
if(out) {MyGPIO::set(PIN_MOSI);} else {MyGPIO::clear(PIN_MOSI);}
|
||||
wait();
|
||||
clkHi();
|
||||
wait();
|
||||
@@ -380,7 +380,7 @@ private:
|
||||
inline uint8_t readBit() {
|
||||
clkHi();
|
||||
wait();
|
||||
const bool val = GPIO::get(PIN_MISO);
|
||||
const bool val = MyGPIO::get(PIN_MISO);
|
||||
wait();
|
||||
clkLo();
|
||||
wait();
|
||||
@@ -388,11 +388,11 @@ private:
|
||||
}
|
||||
|
||||
inline uint8_t readWriteBit(const bool out) {
|
||||
if(out) {GPIO::set(PIN_MOSI);} else {GPIO::clear(PIN_MOSI);}
|
||||
if(out) {MyGPIO::set(PIN_MOSI);} else {MyGPIO::clear(PIN_MOSI);}
|
||||
wait();
|
||||
clkHi();
|
||||
wait();
|
||||
const bool inp = GPIO::get(PIN_MISO);
|
||||
const bool inp = MyGPIO::get(PIN_MISO);
|
||||
wait();
|
||||
clkLo();
|
||||
wait();
|
||||
@@ -474,7 +474,7 @@ public:
|
||||
|
||||
/** read 8 bits */
|
||||
uint8_t readByte() {
|
||||
GPIO::clear(PIN_MOSI);
|
||||
MyGPIO::clear(PIN_MOSI);
|
||||
return
|
||||
(readBit() << 7) |
|
||||
(readBit() << 6) |
|
||||
|
||||
@@ -183,12 +183,21 @@ namespace WiFiRaw {
|
||||
};
|
||||
|
||||
|
||||
#ifdef ESP8266
|
||||
WiFiRaw::MACAddress getMyMAC() {
|
||||
WiFiRaw::MACAddress mine;
|
||||
wifi_get_macaddr(0x00, (uint8_t*)&mine);
|
||||
return mine;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ESP32
|
||||
WiFiRaw::MACAddress getMyMAC() {
|
||||
WiFiRaw::MACAddress mine;
|
||||
esp_wifi_get_mac(ESP_IF_WIFI_STA, (uint8_t*)&mine);
|
||||
return mine;
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user