Compare commits
9 Commits
master
...
gm1352_rea
Author | SHA1 | Date |
---|---|---|
King Kévin | 10bf54edb9 | |
King Kévin | d823f18526 | |
King Kévin | 7d8a98d0ea | |
King Kévin | 3a9cd32391 | |
King Kévin | dd8a3263c6 | |
King Kévin | 0756bb8fe5 | |
King Kévin | 66816abc9f | |
King Kévin | 66a6149fdf | |
King Kévin | 102bc6d038 |
43
README.md
43
README.md
|
@ -1,9 +1,48 @@
|
||||||
this is a template firmware for [ESP32-S2](https://www.espressif.com/en/products/socs/esp32-s2)-based micro-controller projects.
|
this project is about interfacing the GM-1352 sound level meter using an ESP32-S2-based board, so to read the sound level measurements digitally.
|
||||||
|
|
||||||
|
GM-1352
|
||||||
|
=======
|
||||||
|
|
||||||
|
the GM-1352 is the successor of the GM-1351, and very similar to it.
|
||||||
|
the main difference is that the power is not delivered by a 9V battery, but by 3x1.5V AA batteries.
|
||||||
|
|
||||||
|
[CuVoodoo #030](https://www.cuvoodoo.info/cuvoodoo-030-audio-is-killing-the-music/) already explained how to interface it.
|
||||||
|
basically just tap on the lines between the MCU (a EFM8BB10F8G-QFN20) and LCD controller (a Chip-on-Board under a blob of epoxy).
|
||||||
|
there are test points available for that:
|
||||||
|
|
||||||
|
- CS: chip select, to start data communication
|
||||||
|
- DATA: the actual data bits
|
||||||
|
- WR: the data clock (not periodic)
|
||||||
|
|
||||||
|
there are additional test points to read (or assert) button presses:
|
||||||
|
|
||||||
|
- 1: HOLD button (press low)
|
||||||
|
- 2: MIN/MAX button (press low)
|
||||||
|
- 3: POWER button (press low)
|
||||||
|
|
||||||
|
there is another test point marked S, but I don't know what this is for.
|
||||||
|
|
||||||
|
also note that the LCD has segments for Bluetooth and USB.
|
||||||
|
there might be variants of the GM-1352 with these options.
|
||||||
|
|
||||||
board
|
board
|
||||||
=====
|
=====
|
||||||
|
|
||||||
the board used is a [WEMOS](https://www.wemos.cc/en/latest/index.html) [S2 mini](https://www.wemos.cc/en/latest/s2/s2_mini.html).
|
this repository is the firmware for [ESP32-S2](https://www.espressif.com/en/products/socs/esp32-s2)-based [WEMOS](https://www.wemos.cc/en/latest/index.html) [S2 mini](https://www.wemos.cc/en/latest/s2/s2_mini.html) board.
|
||||||
|
|
||||||
|
connect the GM-1352 to the S2 mini as follows:
|
||||||
|
|
||||||
|
- B+ to 5V: to power or get power from the device
|
||||||
|
- B- to GND: ground reference
|
||||||
|
- POWER to 16: to wake up the S2 when the device is powered (the S2 will shut down shortly after the GM-1352)
|
||||||
|
- DATA to 18: this will be the SPI MOSI line to read the measurments
|
||||||
|
- CS to 33: this will be the SPI CS line to identify transactions
|
||||||
|
- WR to 35: this will be the SPI SCK line to clock the data bits (not periodic)
|
||||||
|
|
||||||
|
I soldered wires to the pads, and broke them out on a 8-pin female header, located above the battery compartment.
|
||||||
|
this also to easily connect on row of the S2 mini to it on the back of the GM-1352.
|
||||||
|
|
||||||
|
now you can power the sound level meter through the S2 mini USB port, and read the measurements over its serial CDC ACM interface.
|
||||||
|
|
||||||
compile and flash
|
compile and flash
|
||||||
=================
|
=================
|
||||||
|
|
261
main/main.c
261
main/main.c
|
@ -3,11 +3,16 @@
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include <sys/reent.h>
|
#include <sys/reent.h>
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_mac.h"
|
#include "esp_mac.h"
|
||||||
|
#include "esp_sleep.h"
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
|
#include "freertos/queue.h"
|
||||||
|
|
||||||
#include "tinyusb.h"
|
#include "tinyusb.h"
|
||||||
#include "tusb_cdc_acm.h"
|
#include "tusb_cdc_acm.h"
|
||||||
#include "tusb_dfu_rt.h"
|
#include "tusb_dfu_rt.h"
|
||||||
|
@ -15,14 +20,155 @@
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
|
#include "driver/spi_slave.h"
|
||||||
|
|
||||||
|
// get the length of an array
|
||||||
|
#define LENGTH(x) (sizeof(x) / sizeof((x)[0]))
|
||||||
|
|
||||||
// GPIO to force DFU mode (on high)
|
// GPIO to force DFU mode (on high)
|
||||||
#define DFU_PIN 14
|
#define DFU_PIN 14
|
||||||
// GPIO for on-board LED (WEMOS S2 mini, source on)
|
// GPIO for on-board LED (WEMOS S2 mini, source on)
|
||||||
#define LED_BOARD 15
|
#define LED_BOARD 15
|
||||||
|
|
||||||
|
// connect GPIO to test pad 3
|
||||||
|
#define GPIO_POWER (16U)
|
||||||
|
// connect GPIO to test pad DATA
|
||||||
|
#define GPIO_MOSI (18U)
|
||||||
|
// connect GPIO to test pad WR
|
||||||
|
#define GPIO_SCLK (35U)
|
||||||
|
// connect GPIO to test pad CS
|
||||||
|
#define GPIO_CS (33U)
|
||||||
|
|
||||||
static const char *TAG = "main";
|
static const char *TAG = "main";
|
||||||
|
|
||||||
|
/* the MCU sends 1 or 17 bytes frame the to LCD controller
|
||||||
|
* the below described which bit corresponds to which segment
|
||||||
|
* digit 1 is left most on the LCD, bit 7 is the most significant bit.
|
||||||
|
*
|
||||||
|
* byte 0:
|
||||||
|
* - 0x80: initialize LCD controller (1 byte frame)
|
||||||
|
* - 0xa0: set segments (17 bytes frame)
|
||||||
|
*
|
||||||
|
* byte 1:
|
||||||
|
* - bit 7: no segment
|
||||||
|
* - bit 6: no segment
|
||||||
|
* - bit 5: battery low level
|
||||||
|
* - bit 4: battery mid level
|
||||||
|
* - bit 3: battery high level
|
||||||
|
* - bit 2: OVER
|
||||||
|
* - bit 1: USB
|
||||||
|
* - bit 0: Bluetooth icon
|
||||||
|
*
|
||||||
|
* byte 2:
|
||||||
|
* - bit 7: battery case
|
||||||
|
* - bit 6: MAX
|
||||||
|
* - bit 5: MIN
|
||||||
|
* - bit 4: HOLD
|
||||||
|
* - bit 3: digit 1, segment b and segment c
|
||||||
|
* - bit 2: digit 2, segment f
|
||||||
|
* - bit 1: digit 2, segment g
|
||||||
|
* - bit 0: digit 2, segment e
|
||||||
|
*
|
||||||
|
* byte 3:
|
||||||
|
* - bit 7: FAST
|
||||||
|
* - bit 6: digit 2, segment a
|
||||||
|
* - bit 5: digit 2, segment b
|
||||||
|
* - bit 4: digit 2, segment c
|
||||||
|
* - bit 3: digit 2, segment d
|
||||||
|
* - bit 2: digit 3, segment f
|
||||||
|
* - bit 1: digit 3, segment g
|
||||||
|
* - bot 0: digit 3, segment e
|
||||||
|
*
|
||||||
|
* byte 4:
|
||||||
|
* - bit 7: SLOW
|
||||||
|
* - bit 6: digit 3, segment a
|
||||||
|
* - bit 5: digit 3, segment b
|
||||||
|
* - bit 4: digit 3, segment c
|
||||||
|
* - bit 3: digit 3, segment d
|
||||||
|
* - bit 2: no segment
|
||||||
|
* - bit 1: no segment
|
||||||
|
* - bit 0: digit 3, segment dp
|
||||||
|
*
|
||||||
|
* byte 5:
|
||||||
|
* - bit 7: dBC
|
||||||
|
* - bit 6: digit 4, segment f
|
||||||
|
* - bit 5: digit 4, segment g
|
||||||
|
* - bit 4: digit 4, segment e
|
||||||
|
* - bit 3: dBA
|
||||||
|
* - bit 2: digit 4, segment a
|
||||||
|
* - bit 1: digit 4, segment b
|
||||||
|
* - bit 0: digit 4, segment c
|
||||||
|
*
|
||||||
|
* byte 6:
|
||||||
|
* - bit 7: digit 4, segment d
|
||||||
|
*
|
||||||
|
* all other bits can be set to any value
|
||||||
|
*/
|
||||||
|
// number of bytes in an LCD frame
|
||||||
|
#define FRAME_SIZE (17U)
|
||||||
|
|
||||||
|
/** which bit should be set to enable which segment in specific digits
|
||||||
|
* @note 0 = byte 0 bit 0
|
||||||
|
*/
|
||||||
|
static const uint8_t digit_segments[4][8] = {
|
||||||
|
{ // digit 1
|
||||||
|
0, // a (segment does not exist)
|
||||||
|
16 + 3, // b
|
||||||
|
16 + 3, // c
|
||||||
|
0, // d (segment does not exist)
|
||||||
|
0, // e (segment does not exist)
|
||||||
|
0, // f (segment does not exist)
|
||||||
|
0, // g (segment does not exist)
|
||||||
|
0, // dp (segment does not exist)
|
||||||
|
},
|
||||||
|
{ // digit 2
|
||||||
|
24 + 6, // a
|
||||||
|
24 + 5, // b
|
||||||
|
24 + 4, // c
|
||||||
|
24 + 3, // d
|
||||||
|
16 + 0, // e
|
||||||
|
16 + 2, // f
|
||||||
|
16 + 1, // g
|
||||||
|
0, // dp (segment does not exist)
|
||||||
|
},
|
||||||
|
{ // digit 3
|
||||||
|
32 + 6, // a
|
||||||
|
32 + 5, // b
|
||||||
|
32 + 4, // c
|
||||||
|
32 + 3, // d
|
||||||
|
24 + 0, // e
|
||||||
|
24 + 2, // f
|
||||||
|
24 + 1, // g
|
||||||
|
0, // dp (actually 24 + 0 but we don't use it)
|
||||||
|
},
|
||||||
|
{ // digit 4
|
||||||
|
40 + 2, // a
|
||||||
|
40 + 1, // b
|
||||||
|
40 + 0, // c
|
||||||
|
48 + 7, // d
|
||||||
|
40 + 4, // e
|
||||||
|
40 + 6, // f
|
||||||
|
40 + 5, // g
|
||||||
|
0, // dp (segment does not exist)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/** the index corresponds to the digit to be displayed, the value represent the segments to be enabled
|
||||||
|
* @note LSb = a, MSb = dp
|
||||||
|
*/
|
||||||
|
static const uint8_t number_segments[10] = {
|
||||||
|
0x3f, // 0: a b c d e f
|
||||||
|
0x06, // 1: b c
|
||||||
|
0x5b, // 2: a b d e g
|
||||||
|
0x4f, // 3: a b c d g
|
||||||
|
0x66, // 4: b c f g
|
||||||
|
0x6d, // 5: a c d f g
|
||||||
|
0x7d, // 6: a c d e f g
|
||||||
|
0x07, // 7: a b c
|
||||||
|
0x7f, // 8: a b c d e f g
|
||||||
|
0x6f, // 9; a c b d f g
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief USB string descriptor
|
* @brief USB string descriptor
|
||||||
*/
|
*/
|
||||||
|
@ -31,26 +177,80 @@ static const char* usb_str_desc[USB_STRING_DESCRIPTOR_ARRAY_SIZE] = {
|
||||||
CONFIG_TINYUSB_DESC_MANUFACTURER_STRING, // 1: Manufacturer
|
CONFIG_TINYUSB_DESC_MANUFACTURER_STRING, // 1: Manufacturer
|
||||||
CONFIG_TINYUSB_DESC_PRODUCT_STRING, // 2: Product
|
CONFIG_TINYUSB_DESC_PRODUCT_STRING, // 2: Product
|
||||||
CONFIG_TINYUSB_DESC_SERIAL_STRING, // 3: Serials, should use chip ID
|
CONFIG_TINYUSB_DESC_SERIAL_STRING, // 3: Serials, should use chip ID
|
||||||
CONFIG_TINYUSB_DESC_CDC_STRING, // 4: CDC Interface
|
"GM1532 measurements", // 4: CDC Interface
|
||||||
"", // 5: MSC Interface
|
"", // 5: MSC Interface
|
||||||
"DFU (runtime mode)" // 6: DFU RT
|
"DFU (runtime mode)" // 6: DFU RT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static QueueHandle_t meas_queue; // queue for the measurement messages received
|
||||||
|
#define MEAS_QUEUE_SIZE 4 // max number of control message received
|
||||||
|
|
||||||
|
/* handle measurement received */
|
||||||
|
static void meas_task(void *pvParameter)
|
||||||
|
{
|
||||||
|
spi_slave_transaction_t t;
|
||||||
|
while (xQueueReceive(meas_queue, &t, portMAX_DELAY) == pdTRUE) {
|
||||||
|
const uint8_t* rx_buffer = t.rx_buffer; // t.rx_buffer is type-less
|
||||||
|
if (t.trans_len > 6 && 0xa0 == rx_buffer[0]) { // frame long enough for the LCD data
|
||||||
|
// extract digit segments
|
||||||
|
uint8_t segments[4] = {0}; // which digit segments are enabled
|
||||||
|
for (uint8_t digit = 0; digit < LENGTH(segments); digit++) {
|
||||||
|
segments[digit] = 0; // clear all segments
|
||||||
|
for (uint8_t seg = 0; seg < 8; seg++) {
|
||||||
|
if (rx_buffer[digit_segments[digit][seg] / 8] & (1 << (digit_segments[digit][seg] % 8))) {
|
||||||
|
segments[digit] |= (1 << seg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// figure out digit value
|
||||||
|
uint8_t digits[4] = {0};
|
||||||
|
for (uint8_t digit = 0; digit < LENGTH(digits); digit++) {
|
||||||
|
for (uint8_t i = 0; i < LENGTH(number_segments); i++) {
|
||||||
|
if (number_segments[i] == segments[digit]) {
|
||||||
|
digits[digit] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const uint16_t meas = digits[0] * 1000 + digits[1] * 100 + digits[2] * 10 + digits[3]; // in deci dBA
|
||||||
|
if (meas < 1400) { // ignore all segments on out of range values
|
||||||
|
printf("%u.%u dBA\n", meas / 10, meas % 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// called after LCD frame (e.g. SPI transaction) is received
|
||||||
|
static uint8_t timeout = 0;
|
||||||
|
void post_trans_cb(spi_slave_transaction_t *t) {
|
||||||
|
if (t) {
|
||||||
|
ESP_ERROR_CHECK( xQueueSend(meas_queue, t, 512) != pdTRUE ); // send measurement to be displayed
|
||||||
|
spi_slave_queue_trans(SPI2_HOST, t, portMAX_DELAY); // re-add transaction
|
||||||
|
}
|
||||||
|
timeout = 0; // reset timeout since we received data
|
||||||
|
}
|
||||||
|
|
||||||
void app_main(void)
|
void app_main(void)
|
||||||
{
|
{
|
||||||
// check DFU force
|
// check DFU force
|
||||||
gpio_config_t io_conf = {}; // to configure GPIO
|
gpio_config_t io_conf = {}; // to configure GPIO
|
||||||
|
// GPIO0 can also be pressed while soft reboot
|
||||||
|
io_conf.pin_bit_mask = (1ULL << 0); // GPIO to configure
|
||||||
|
io_conf.intr_type = GPIO_INTR_DISABLE; // disable interrupt
|
||||||
|
io_conf.mode = GPIO_MODE_INPUT; // set as input
|
||||||
|
io_conf.pull_down_en = false; // disable pull-down mode
|
||||||
|
io_conf.pull_up_en = true; // enable pull-up mode
|
||||||
|
ESP_ERROR_CHECK( gpio_config(&io_conf) ); // configure GPIO
|
||||||
|
// dedicated DFU button
|
||||||
io_conf.pin_bit_mask = (1ULL << DFU_PIN); // GPIO to configure
|
io_conf.pin_bit_mask = (1ULL << DFU_PIN); // GPIO to configure
|
||||||
io_conf.intr_type = GPIO_INTR_DISABLE; // disable interrupt
|
io_conf.intr_type = GPIO_INTR_DISABLE; // disable interrupt
|
||||||
io_conf.mode = GPIO_MODE_INPUT; // set as input
|
io_conf.mode = GPIO_MODE_INPUT; // set as input
|
||||||
io_conf.pull_down_en = 1; // enable pull-down mode
|
io_conf.pull_down_en = 1; // enable pull-down mode
|
||||||
io_conf.pull_up_en = 0; // disable pull-up mode
|
io_conf.pull_up_en = 0; // disable pull-up mode
|
||||||
ESP_ERROR_CHECK( gpio_config(&io_conf) ); // configure GPIO
|
ESP_ERROR_CHECK( gpio_config(&io_conf) ); // configure GPIO
|
||||||
if (gpio_get_level(DFU_PIN)) { // DFU mode asserted
|
if (!gpio_get_level(0) || gpio_get_level(DFU_PIN)) { // DFU mode asserted
|
||||||
tud_dfu_runtime_reboot_to_dfu_cb(); // reboot to DFU mode
|
tud_dfu_runtime_reboot_to_dfu_cb(); // reboot to DFU mode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// configure LEDs
|
// configure LEDs
|
||||||
io_conf.pin_bit_mask = (1ULL << LED_BOARD); // GPIO to configure
|
io_conf.pin_bit_mask = (1ULL << LED_BOARD); // GPIO to configure
|
||||||
io_conf.intr_type = GPIO_INTR_DISABLE; // disable interrupt
|
io_conf.intr_type = GPIO_INTR_DISABLE; // disable interrupt
|
||||||
|
@ -78,10 +278,49 @@ void app_main(void)
|
||||||
tinyusb_config_cdcacm_t amc_cfg = { 0 }; // the configuration uses default values
|
tinyusb_config_cdcacm_t amc_cfg = { 0 }; // the configuration uses default values
|
||||||
ESP_ERROR_CHECK( tusb_cdc_acm_init(&amc_cfg) ); // configure CDC ACM
|
ESP_ERROR_CHECK( tusb_cdc_acm_init(&amc_cfg) ); // configure CDC ACM
|
||||||
ESP_ERROR_CHECK( tusb_dfu_rf_init() ); // configure DFU runtime (ensures we can use it)
|
ESP_ERROR_CHECK( tusb_dfu_rf_init() ); // configure DFU runtime (ensures we can use it)
|
||||||
esp_tusb_init_console(TINYUSB_CDC_ACM_0); // log to USB
|
|
||||||
ESP_LOGI(TAG, "USB initialized");
|
ESP_LOGI(TAG, "USB initialized");
|
||||||
|
|
||||||
|
// configure shutdown
|
||||||
|
io_conf.pin_bit_mask = (1ULL << GPIO_POWER); // GPIO to configure
|
||||||
|
io_conf.intr_type = GPIO_INTR_DISABLE; // disable interrupt
|
||||||
|
io_conf.mode = GPIO_MODE_INPUT; // set as input
|
||||||
|
io_conf.pull_down_en = 0; // don't use pull-down
|
||||||
|
io_conf.pull_up_en = 0; // there is already an external pull-up
|
||||||
|
ESP_ERROR_CHECK( gpio_config(&io_conf) ); // configure GPIO
|
||||||
|
ESP_ERROR_CHECK( esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL) ); // make sure all sources are disabled
|
||||||
|
ESP_ERROR_CHECK( esp_sleep_enable_ext0_wakeup(GPIO_POWER, 0) ); // use power button to wake up (low when pressed)
|
||||||
|
|
||||||
|
// task to decode and show the measurements
|
||||||
|
meas_queue = xQueueCreate(MEAS_QUEUE_SIZE, sizeof(spi_slave_transaction_t));
|
||||||
|
ESP_ERROR_CHECK( NULL == meas_queue );
|
||||||
|
xTaskCreate(meas_task, "meas_task", 2048, NULL, 4, NULL);
|
||||||
|
|
||||||
|
// configure SPI for GM1352 LCD data frame reading
|
||||||
|
const spi_bus_config_t buscfg = { // SPI bus configuration
|
||||||
|
.mosi_io_num = GPIO_MOSI,
|
||||||
|
.miso_io_num = -1,
|
||||||
|
.sclk_io_num = GPIO_SCLK,
|
||||||
|
.quadwp_io_num = -1,
|
||||||
|
.quadhd_io_num = -1,
|
||||||
|
};
|
||||||
|
spi_slave_interface_config_t slvcfg={
|
||||||
|
.mode = 0,
|
||||||
|
.spics_io_num = GPIO_CS,
|
||||||
|
.queue_size = 3,
|
||||||
|
.flags = 0,
|
||||||
|
.post_setup_cb = NULL,
|
||||||
|
.post_trans_cb = post_trans_cb,
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK( spi_slave_initialize(SPI2_HOST, &buscfg, &slvcfg, SPI_DMA_CH_AUTO) );
|
||||||
|
spi_slave_transaction_t t; // for the SPI transaction
|
||||||
|
memset(&t, 0, sizeof(t)); // clear transaction
|
||||||
|
t.length = FRAME_SIZE * 8; // transaction size
|
||||||
|
WORD_ALIGNED_ATTR uint8_t recvbuf[FRAME_SIZE]; // SPI receive buffer must be word aligned for DMA
|
||||||
|
t.rx_buffer = recvbuf; // set buffer
|
||||||
|
spi_slave_queue_trans(SPI2_HOST, &t, portMAX_DELAY);
|
||||||
|
|
||||||
ESP_LOGI(TAG, "application ready");
|
ESP_LOGI(TAG, "application ready");
|
||||||
|
esp_tusb_init_console(TINYUSB_CDC_ACM_0); // log to USB
|
||||||
gpio_set_level(LED_BOARD, 0); // switch running LED on to indicate all is ready
|
gpio_set_level(LED_BOARD, 0); // switch running LED on to indicate all is ready
|
||||||
while (1) {
|
while (1) {
|
||||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||||
|
@ -91,5 +330,19 @@ void app_main(void)
|
||||||
} else {
|
} else {
|
||||||
gpio_set_level(LED_BOARD, 1);
|
gpio_set_level(LED_BOARD, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (timeout > 0) {
|
||||||
|
printf(".");
|
||||||
|
fflush(stdout);
|
||||||
|
fsync(fileno(stdout));
|
||||||
|
}
|
||||||
|
timeout++;
|
||||||
|
if (timeout > 10) {
|
||||||
|
printf("\nshutting down due to inactivity\n");
|
||||||
|
fflush(stdout);
|
||||||
|
fsync(fileno(stdout));
|
||||||
|
gpio_set_level(LED_BOARD, 1); // ensure run LED is off
|
||||||
|
esp_deep_sleep_start(); // go to deep sleep
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue