Skip to content

Commit

Permalink
Merge branch 'master-v4.3' of https://github.com/sle118/squeezelite-e…
Browse files Browse the repository at this point in the history
…sp32 into fix_led_vu
  • Loading branch information
wizmo2 committed Sep 16, 2023
2 parents fd0c38c + effc574 commit 55303ec
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 15 deletions.
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Please note that when sending to a Bluetooth speaker (source), only 44.1 kHz can
Most DAC will work out-of-the-box with simply an I2S connection, but some require specific commands to be sent using I2C. See DAC option below to understand how to send these dedicated commands. There is build-in support for TAS575x, TAS5780, TAS5713 and AC101 DAC.

### Raw WROOM esp32-s3 module
The esp32-s3 based modules like [this]@(https://www.espressif.com/sites/default/files/documentation/esp32-s3-wroom-1_wroom-1u_datasheet_en.pdf) are also supported but requires esp-idf 4.4. It is not yet part of official releases, but it compiles & runs. The s3 does not have bluetooth audio. Note that CPU performances are greatly enhanced.
The esp32-s3 based modules like [this](https://www.espressif.com/sites/default/files/documentation/esp32-s3-wroom-1_wroom-1u_datasheet_en.pdf) are also supported but requires esp-idf 4.4. It is not yet part of official releases, but it compiles & runs. The s3 does not have bluetooth audio. Note that CPU performances are greatly enhanced.

### SqueezeAMP
This is the main hardware companion of Squeezelite-esp32 and has been developped together. Details on capabilities can be found [here](https://forums.slimdevices.com/showthread.php?110926-pre-ANNOUNCE-SqueezeAMP-and-SqueezeliteESP32) and [here](https://github.com/philippe44/SqueezeAMP).
Expand Down Expand Up @@ -389,11 +389,12 @@ Where (all parameters are optionals except gpio)
Where `<action>` is either the name of another configuration to load (remap) or one amongst

```
ACTRLS_NONE, ACTRLS_SLEEP, ACTRLS_POWER, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY,
ACTRLS_NONE, ACTRLS_POWER, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY,
ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT,
BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT,
BCTRLS_PS1, BCTRLS_PS2, BCTRLS_PS3, BCTRLS_PS4, BCTRLS_PS5, BCTRLS_PS6, BCTRLS_PS7, BCTRLS_PS8, BCTRLS_PS9, BCTRLS_PS10,
KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH,
KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH,
ACTRLS_SLEEP,
```
Note that ACTRLS_SLEEP is not an actual button that can be sent to LMS, but it's a hook to activate deep sleep mode (see [Sleeping](#sleeping)).

Expand Down Expand Up @@ -508,11 +509,11 @@ NB: Set parameter to empty to disable battery reading. For named configurations
### Sleeping
The esp32 can be put in deep sleep mode to save some power. How much really depends on the connected periperals, so best is to do your own measures. Waking-up from deep sleep is the equivalent of a reboot, but as the chip takes a few seconds to connect, it's still an efficient process.

The esp32 can enter deep sleep after an audio inactivity timeout, after a button has been pressed or after a GPIO is set to a given level. It wakes up only on GPIO events
The esp32 can enter deep sleep after an audio inactivity timeout, after a button has been pressed or after a GPIO is set to a given level. It wakes up only on some GPIO events. Note that *all* GPIO are isolated when sleeping (unless they are set with the `rtc`option) so you can not assume anything about their value, except that they will not drain current. The `rtc` option allows to keep some GPIO (from the RTC domain only) either pulled up or down. This can be useful if you want to keep some periperal active, for example a GPIO expander whose interrupt will be used to wake-up the system.

The NVS parameter `sleep_config` is mostly used for setting sleep conditions
```
[delay=<mins>][,sleep=<gpio>[:0|1]][,wake=<gpio>[:0|1][|<gpio>[:0|1]...]
[delay=<mins>][,sleep=<gpio>[:0|1]][,wake=<gpio>[:0|1][|<gpio>[:0|1]...][,rtc=<gpio>[:0|1][|<gpio>[:0|1]...]
```
- delay is in **minutes**
- sleep is the GPIO that will put the system into sleep and it can be a level 0 or 1
Expand All @@ -524,10 +525,12 @@ Please see [buttons](#buttons) for detailed syntax.

The option to use multiple GPIOs is very limited on esp32 and the esp-idf 4.3.x we are using: it is only possible to wake-up when **any** of the defined GPIO is set to 1. The fact that you can specify different levels in the wake list is irrelevant for now, it's just a provision for future upgrades to more recent versions of esp-idf.

**Note that not all GPIOs can be used to wake-up the esp32**
**Only the following GPIOs can be used to wake-up the esp32**
- ESP32: 0, 2, 4, 12-15, 25-27, 32-39;
- ESP32-S3: 0-21.

Some have asked for a soft power on/off option. Although this is not built-in, it's easy to create yours as long as the regulator/power supply of the board can be controlled by Vcc or GND. Depending on how it is active, add a pull-up/down resistor to the regulator's control and connect it also to one GPIO of the esp32. Then using set_GPIO, set that GPIO to Vcc or GND. Use a hardware button that forces the regulator on with a pull- up/down and once the esp32 has booted, it will force the GPIO to the desired value maintaining the board on by software. To power it off by software, just use the deep sleep option which will suspend all GPIO hence switching off the regulator.

# Configuration

## Setup WiFi
Expand Down
4 changes: 2 additions & 2 deletions components/services/audio_controls.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ static const actrls_config_map_t actrls_config_map[] =
// BEWARE: the actions below need to stay aligned with the corresponding enum to properly support json parsing
// along with the actrls_t controls in LMS_controls, bt_sink and raop_sink
#define EP(x) [x] = #x /* ENUM PRINT */
static const char * actrls_action_s[ ] = { EP(ACTRLS_SLEEP),EP(ACTRLS_POWER),EP(ACTRLS_VOLUP),EP(ACTRLS_VOLDOWN),EP(ACTRLS_TOGGLE),EP(ACTRLS_PLAY),
static const char * actrls_action_s[ ] = { EP(ACTRLS_POWER),EP(ACTRLS_VOLUP),EP(ACTRLS_VOLDOWN),EP(ACTRLS_TOGGLE),EP(ACTRLS_PLAY),
EP(ACTRLS_PAUSE),EP(ACTRLS_STOP),EP(ACTRLS_REW),EP(ACTRLS_FWD),EP(ACTRLS_PREV),EP(ACTRLS_NEXT),
EP(BCTRLS_UP),EP(BCTRLS_DOWN),EP(BCTRLS_LEFT),EP(BCTRLS_RIGHT),
EP(BCTRLS_PS0),EP(BCTRLS_PS1),EP(BCTRLS_PS2),EP(BCTRLS_PS3),EP(BCTRLS_PS4),EP(BCTRLS_PS5),EP(BCTRLS_PS6),EP(BCTRLS_PS7),EP(BCTRLS_PS8),EP(BCTRLS_PS9),
EP(KNOB_LEFT),EP(KNOB_RIGHT),EP(KNOB_PUSH),
EP(KNOB_LEFT),EP(KNOB_RIGHT),EP(KNOB_PUSH), EP(ACTRLS_SLEEP),
""} ;

static const char * TAG = "audio controls";
Expand Down
4 changes: 2 additions & 2 deletions components/services/audio_controls.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
#include "buttons.h"

// BEWARE: this is the index of the array of action below (change actrls_action_s as well!)
typedef enum { ACTRLS_NONE = -1, ACTRLS_SLEEP, ACTRLS_POWER, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY,
typedef enum { ACTRLS_NONE = -1, ACTRLS_POWER, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY,
ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT,
BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT,
BCTRLS_PS0,BCTRLS_PS1,BCTRLS_PS2,BCTRLS_PS3,BCTRLS_PS4,BCTRLS_PS5,BCTRLS_PS6,BCTRLS_PS7,BCTRLS_PS8,BCTRLS_PS9,
KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH,
ACTRLS_REMAP, ACTRLS_MAX
ACTRLS_REMAP, ACTRLS_SLEEP, ACTRLS_MAX
} actrls_action_e;

typedef void (*actrls_handler)(bool pressed);
Expand Down
3 changes: 2 additions & 1 deletion components/services/led.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,8 @@ void set_led_gpio(int gpio, char *value) {
struct led_config_s *config;

if (strcasestr(value, "green")) config = &green;
else config = &red;
else if (strcasestr(value, "red"))config = &red;
else return;

config->gpio = gpio;
char *p = value;
Expand Down
46 changes: 42 additions & 4 deletions components/services/services.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pwm_system_t pwm_system = {

static EXT_RAM_ATTR struct {
uint64_t wake_gpio, wake_level;
uint64_t rtc_gpio, rtc_level;
uint32_t delay;
} sleep_config;

Expand Down Expand Up @@ -136,6 +137,28 @@ static void sleep_init(void) {
ESP_LOGI(TAG, "Sleep wake-up gpio bitmap 0x%llx (active 0x%llx)", sleep_config.wake_gpio, sleep_config.wake_level);
}
}

// get the rtc-pull criteria
if ((p = strcasestr(config, "rtc"))) {
char list[32] = "", item[8];
sscanf(p, "%*[^=]=%31[^,]", list);
p = list - 1;
while (p++ && sscanf(p, "%7[^|]", item)) {
int level = 0, gpio = atoi(item);
if (!rtc_gpio_is_valid_gpio(gpio)) {
ESP_LOGE(TAG, "invalid rtc GPIO %d", gpio);
} else {
sleep_config.rtc_gpio |= 1LL << gpio;
}
if (sscanf(item, "%*[^:]:%d", &level)) sleep_config.rtc_level |= level << gpio;
p = strchr(p, '|');
}

// when moving to esp-idf more recent than 4.4.x, multiple gpio wake-up with level specific can be done
if (sleep_config.rtc_gpio) {
ESP_LOGI(TAG, "RTC forced gpio bitmap 0x%llx (active 0x%llx)", sleep_config.rtc_gpio, sleep_config.rtc_level);
}
}

// then get the gpio that activate sleep (we could check that we have a valid wake)
if ((p = strcasestr(config, "sleep"))) {
Expand Down Expand Up @@ -165,22 +188,37 @@ void services_sleep_activate(sleep_cause_e cause) {
// call all sleep hooks that might want to do something
for (void (**hook)(void) = sleep_hooks; *hook; hook++) (*hook)();

// isolate all possible GPIOs, except the wake-up ones
// isolate all possible GPIOs, except the wake-up and RTC-maintaines ones
esp_sleep_config_gpio_isolate();

// keep RTC domain up if we need to maintain pull-up/down of some GPIO from RTC
if (sleep_config.rtc_gpio) esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);

for (int i = 0; i < GPIO_NUM_MAX; i++) {
if (!rtc_gpio_is_valid_gpio(i) || ((1LL << i) & sleep_config.wake_gpio)) continue;
rtc_gpio_isolate(i);
// must be a RTC GPIO
if (!rtc_gpio_is_valid_gpio(i)) continue;

// do we need to maintain a pull-up or down of that GPIO
if ((1LL << i) & sleep_config.rtc_gpio) {
if ((sleep_config.rtc_level >> i) & 0x01) rtc_gpio_pullup_en(i);
else rtc_gpio_pulldown_en(i);
// or is this not wake-up GPIO, just isolate it
} else if (!((1LL << i) & sleep_config.wake_gpio)) {
rtc_gpio_isolate(i);
}
}

// is there just one GPIO
if (sleep_config.wake_gpio & (sleep_config.wake_gpio - 1)) {
ESP_LOGI(TAG, "going to sleep cause %d, wake-up on multiple GPIO, any '1' wakes up 0x%llx", cause, sleep_config.wake_gpio);
esp_sleep_enable_ext1_wakeup(sleep_config.wake_gpio, ESP_EXT1_WAKEUP_ANY_HIGH);
} else {
} else if (sleep_config.wake_gpio) {
int gpio = __builtin_ctz(sleep_config.wake_gpio);
int level = (sleep_config.wake_level >> gpio) & 0x01;
ESP_LOGI(TAG, "going to sleep cause %d, wake-up on GPIO %d level %d", cause, gpio, level);
esp_sleep_enable_ext0_wakeup(gpio, level);
} else {
ESP_LOGW(TAG, "going to sleep cause %d, no wake-up option", cause);
}

// we need to use a timer in case the same button is used for sleep and wake-up and it's "pressed" vs "released" selected
Expand Down

0 comments on commit 55303ec

Please sign in to comment.