diff --git a/.cproject b/.cproject
index 6307a7df..f2ba4b3b 100644
--- a/.cproject
+++ b/.cproject
@@ -227,7 +227,7 @@
-
+
@@ -239,7 +239,7 @@
-
+
@@ -495,6 +495,12 @@
+
+
+
+
+
+
@@ -560,6 +566,12 @@
+
+
+
+
+
+
diff --git a/.project b/.project
index 8724a189..18d4dbf1 100644
--- a/.project
+++ b/.project
@@ -3,6 +3,7 @@
squeezelite-esp32
+ esp-idf
diff --git a/.settings/.gitignore b/.settings/.gitignore
new file mode 100644
index 00000000..aacc3e4e
--- /dev/null
+++ b/.settings/.gitignore
@@ -0,0 +1 @@
+/org.eclipse.ltk.core.refactoring.prefs
diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml
index 70f9cf9d..f2d1fea7 100644
--- a/.settings/language.settings.xml
+++ b/.settings/language.settings.xml
@@ -33,9 +33,9 @@
-
+
-
+
@@ -57,9 +57,9 @@
-
+
-
+
@@ -81,9 +81,9 @@
-
+
-
+
diff --git a/.settings/org.eclipse.cdt.core.prefs b/.settings/org.eclipse.cdt.core.prefs
index ccccf166..2dd6626d 100644
--- a/.settings/org.eclipse.cdt.core.prefs
+++ b/.settings/org.eclipse.cdt.core.prefs
@@ -49,10 +49,10 @@ environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.16039962
environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/IDF_PATH/value=C\:/msys32/opt/esp-idf
environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PATH/delimiter=\:
environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PATH/operation=replace
-environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PATH/value=C\:\\msys32\\usr\\bin;C\:\\msys32\\mingw32\\bin;C\:\\msys32\\opt\\xtensa-esp32-elf\\bin\\
+environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PATH/value=C\:\\msys32\\opt\\openocd-esp32\\bin;c\:\\msys32\\opt\\xtensa-esp32-elf\\bin\\;c\:\\msys32\\mingw32\\bin;C\:\\msys32\\usr\\bin;c\:\\Python27;C\:\\msys32\\usr\\bin\\vendor_perl;C\:\\msys32\\usr\\bin\\core_perl
environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PROJECT_NAME/delimiter=\:
environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PROJECT_NAME/operation=replace
-environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PROJECT_NAME/value=recovery.custom
+environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PROJECT_NAME/value=recovery
environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PROJECT_VER/delimiter=\:
environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PROJECT_VER/operation=append
environment/project/cdt.managedbuild.toolchain.gnu.cross.base.293933348.1603996291/PROJECT_VER/value=custom
diff --git a/Makefile b/Makefile
index 2c004921..e3948648 100644
--- a/Makefile
+++ b/Makefile
@@ -14,4 +14,6 @@
PROJECT_NAME?=squeezelite
include $(IDF_PATH)/make/project.mk
-CFLAGS += -Wno-error=format-overflow -Wno-error=stringop-truncation
\ No newline at end of file
+
+CFLAGS += -Wno-error=format-overflow -Wno-error=stringop-truncation
+CPPFLAGS+= -Wno-error=maybe-uninitialized
diff --git a/README.md b/README.md
index 1d8e3eaf..50e12390 100644
--- a/README.md
+++ b/README.md
@@ -81,18 +81,19 @@ Syntax is:
```
=Vcc|GND|amp|jack[,=Vcc|GND|amp|jack]
```
-
### Rotary Encoder
One rotary encoder is supported, quadrature shift with press. Such encoders usually have 2 pins for encoders (A and B), and common C that must be set to ground and an optional SW pin for press. A, B and SW must be pulled up, so automatic pull-up is provided by ESP32, but you can add your own resistors. A bit of filtering on A and B (~470nF) helps for debouncing which is not made by software.
-Encoder is hard-coded to respectively knob left, right and push on LMS and to volume down/up/play toggle on BT and AirPlay. There is no complex configuration like buttons (see below). Long press is not supported
+Encoder is normally hard-coded to respectively knob left, right and push on LMS and to volume down/up/play toggle on BT and AirPlay. Using the option 'volume' makes it hard-coded to volume down/up/play toggle all the time (even in LMS). The option 'longpress' allows an alternate mode when SW is long-pressed. In that mode, left is previous, right is next and press is toggle. Every long press on SW alternates between modes.
Use parameter rotary_config with the following syntax:
```
-A=,B=[,SW=gpio>]
+A=,B=[,SW=gpio>[,volume][,longpress]]
```
+HW note: all gpio used for rotary have internal pull-up so normally there is no need to provide Vcc to the encoder. Nevertheless if the encoder board you're using also has its own pull-up that are stronger than ESP32's ones (which is likely the case), then there will be crosstalk between gpio, so you must bring Vcc. Look at your board schematic and you'll understand that these board pull-up create a "winning" pull-down when any other pin is grounded.
+
### Buttons
Buttons are described using a JSON string with the following syntax
```
diff --git a/components/services/audio_controls.c b/components/services/audio_controls.c
index d950a1d3..8bcd9887 100644
--- a/components/services/audio_controls.c
+++ b/components/services/audio_controls.c
@@ -148,7 +148,7 @@ static void control_rotary_handler(void *client, rotary_event_e event, bool long
case ROTARY_PRESSED:
if (long_press) rotary.long_state = !rotary.long_state;
else if (rotary.volume_lock) action = ACTRLS_TOGGLE;
- else action = KNOB_RIGHT;
+ else action = KNOB_PUSH;
break;
default:
break;
diff --git a/components/services/buttons.c b/components/services/buttons.c
index 93e842fe..eed67640 100644
--- a/components/services/buttons.c
+++ b/components/services/buttons.c
@@ -81,7 +81,8 @@ static void IRAM_ATTR gpio_isr_handler(void* arg)
if (xTimerGetPeriod(button->timer) > button->debounce / portTICK_RATE_MS) xTimerChangePeriodFromISR(button->timer, button->debounce / portTICK_RATE_MS, &woken); // does that restart the timer?
else xTimerResetFromISR(button->timer, &woken);
- // ESP_EARLY_LOGI(TAG, "INT gpio %u level %u", button->gpio, button->level);
+ if (woken) portYIELD_FROM_ISR();
+ ESP_EARLY_LOGD(TAG, "INT gpio %u level %u", button->gpio, button->level);
}
/****************************************************************************************
diff --git a/components/services/services.c b/components/services/services.c
index f038b870..3f430e59 100644
--- a/components/services/services.c
+++ b/components/services/services.c
@@ -70,7 +70,7 @@ void services_init(void) {
i2c_param_config(i2c_system_port, i2c_config);
i2c_driver_install(i2c_system_port, i2c_config->mode, 0, 0, 0 );
} else {
- ESP_LOGE(TAG, "can't initialize I2C");
+ ESP_LOGW(TAG, "no I2C configured");
}
ESP_LOGD(TAG,"Configuring LEDs");
diff --git a/components/squeezelite/a1s/ac101.c b/components/squeezelite/a1s/ac101.c
index b46a816f..148e2397 100644
--- a/components/squeezelite/a1s/ac101.c
+++ b/components/squeezelite/a1s/ac101.c
@@ -37,6 +37,7 @@ const static char TAG[] = "AC101";
#define SPKOUT_EN ((1 << 11) | (1 << 7))
#define EAROUT_EN ((1 << 11) | (1 << 12) | (1 << 13))
+#define BIN(a,b,c,d) 0b##a##b##c##d
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
@@ -90,51 +91,52 @@ static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) {
ESP_LOGI(TAG, "DAC using I2C sda:%u, scl:%u", i2c_config.sda_io_num, i2c_config.scl_io_num);
res = i2c_write_reg(CHIP_AUDIO_RS, 0x123);
- //huh?
- //vTaskDelay(1000 / portTICK_PERIOD_MS);
+ // huh?
+ vTaskDelay(100 / portTICK_PERIOD_MS);
if (ESP_OK != res) {
ESP_LOGE(TAG, "AC101 reset failed! %d", res);
return false;
}
- // Enable the PLL from 256*44.1KHz MCLK source
- i2c_write_reg(PLL_CTRL1, 0x014f);
- //res |= i2c_write_reg(PLL_CTRL2, 0x83c0);
- i2c_write_reg(PLL_CTRL2, 0x8600);
+ // enable the PLL from BCLK source
+ i2c_write_reg(PLL_CTRL1, BIN(0000,0001,0100,1111)); // F=1,M=1,PLL,INT=31 (medium)
+ i2c_write_reg(PLL_CTRL2, BIN(1000,0110,0000,0000)); // PLL, F=96,N_i=1024-96,F=0,N_f=0*0.2;
+ // i2c_write_reg(PLL_CTRL2, BIN(1000,0011,1100,0000));
- //Clocking system
- i2c_write_reg(SYSCLK_CTRL, 0x8b08);
- i2c_write_reg(MOD_CLK_ENA, 0x800c);
- i2c_write_reg(MOD_RST_CTRL, 0x800c);
- i2c_write_reg(I2S_SR_CTRL, 0x7000); //sample rate
+ // clocking system
+ i2c_write_reg(SYSCLK_CTRL, BIN(1010,1010,0000,1000)); // PLLCLK, BCLK1, IS1CLK, PLL, SYSCLK
+ i2c_write_reg(MOD_CLK_ENA, BIN(1000,0000,0000,1100)); // IS21, ADC, DAC
+ i2c_write_reg(MOD_RST_CTRL, BIN(1000,0000,0000,1100)); // IS21, ADC, DAC
+ i2c_write_reg(I2S_SR_CTRL, BIN(0111,0000,0000,0000)); // 44.1kHz
- //AIF config
- i2c_write_reg(I2S1LCK_CTRL, 0x8850); //BCLK/LRCK
- i2c_write_reg(I2S1_SDOUT_CTRL, 0xc000);
- i2c_write_reg(I2S1_SDIN_CTRL, 0xc000);
- i2c_write_reg(I2S1_MXR_SRC, 0x2200);
-
- i2c_write_reg(ADC_SRCBST_CTRL, 0xccc4);
- i2c_write_reg(ADC_SRC, 0x2020);
- i2c_write_reg(ADC_DIG_CTRL, 0x8000);
- i2c_write_reg(ADC_APC_CTRL, 0xbbc3);
+ // analogue config
+ i2c_write_reg(I2S1LCK_CTRL, BIN(1000,1000,0101,0000)); // Slave, BCLK=I2S/8,LRCK=32,16bits,I2Smode, Stereo
+ i2c_write_reg(I2S1_SDOUT_CTRL, BIN(1100,0000,0000,0000)); // I2S1ADC (R&L)
+ i2c_write_reg(I2S1_SDIN_CTRL, BIN(1100,0000,0000,0000)); // IS21DAC (R&L)
+ i2c_write_reg(I2S1_MXR_SRC, BIN(0010,0010,0000,0000)); // ADCL, ADCR
+ i2c_write_reg(ADC_SRCBST_CTRL, BIN(0100,0100,0100,0000)); // disable all boost (default)
+#if ENABLE_ADC
+ i2c_write_reg(ADC_SRC, BIN(0000,0100,0000,1000)); // source=linein(R/L)
+ i2c_write_reg(ADC_DIG_CTRL, BIN(1000,0000,0000,0000)); // enable digital ADC
+ i2c_write_reg(ADC_ANA_CTRL, BIN(1011, 1011,0000,0000)); // enable analogue R/L, 0dB
+#else
+ i2c_write_reg(ADC_SRC, BIN(0000,0000,0000,0000)); // source=none
+ i2c_write_reg(ADC_DIG_CTRL, BIN(0000,0000,0000,0000)); // disable digital ADC
+ i2c_write_reg(ADC_ANA_CTRL, BIN(0011, 0011,0000,0000)); // disable analogue R/L, 0dB
+#endif
//Path Configuration
- i2c_write_reg(DAC_MXR_SRC, 0xcc00);
- i2c_write_reg(DAC_DIG_CTRL, 0x8000);
- i2c_write_reg(OMIXER_SR, 0x0081);
- i2c_write_reg(OMIXER_DACA_CTRL, 0xf080);
+ i2c_write_reg(DAC_MXR_SRC, BIN(1000,1000,0000,0000)); // DAC from I2S
+ i2c_write_reg(DAC_DIG_CTRL, BIN(1000,0000,0000,0000)); // enable DAC
+ i2c_write_reg(OMIXER_DACA_CTRL, BIN(1111,0000,0000,000)); // enable DAC/Analogue (see note on offset removal and PA)
+ i2c_write_reg(OMIXER_DACA_CTRL, BIN(1100,0000,0000,000)); // enable DAC/Analogue (see note on offset removal and PA)
+#if ENABLE_ADC
+ i2c_write_reg(OMIXER_SR, BIN(0000,0001,0000,0010)); // source=DAC(R/L) (are DACR and DACL really inverted in bitmap?)
+#else
+ i2c_write_reg(OMIXER_SR, BIN(0000,0101,0000,1010)); // source=DAC(R/L) and LINEIN(R/L)
+#endif
- // configure I2S
- uint16_t regval = i2c_read_reg(I2S1LCK_CTRL);
- regval &= 0xffc3;
- regval |= (AC_MODE_SLAVE << 15);
- regval |= (BIT_LENGTH_16_BITS << 4);
- regval |= (AC_MODE_SLAVE << 2);
- res |= i2c_write_reg(I2S1LCK_CTRL, regval);
- res |= i2c_write_reg(I2S_SR_CTRL, SAMPLE_RATE_44100);
-
// configure I2S pins & install driver
i2s_pin_config_t i2s_pin_config = (i2s_pin_config_t) { .bck_io_num = 27, .ws_io_num = 26,
.data_out_num = 25, .data_in_num = 35 //Not used
diff --git a/components/squeezelite/a1s/ac101.h b/components/squeezelite/a1s/ac101.h
index 00cddb7a..39c17379 100644
--- a/components/squeezelite/a1s/ac101.h
+++ b/components/squeezelite/a1s/ac101.h
@@ -61,7 +61,7 @@
#define DAC_VOL_CTRL 0x49
#define DAC_MXR_SRC 0x4c
#define DAC_MXR_GAIN 0x4d
-#define ADC_APC_CTRL 0x50
+#define ADC_ANA_CTRL 0x50
#define ADC_SRC 0x51
#define ADC_SRCBST_CTRL 0x52
#define OMIXER_DACA_CTRL 0x53