porting master changes

There is a divergence in accessors.c that I've not resolved
This commit is contained in:
Philippe G
2020-08-02 23:13:46 -07:00
parent e6a4c85adc
commit 0865496d76
28 changed files with 544 additions and 337 deletions

View File

@@ -2,6 +2,9 @@
# Automatically generated file. DO NOT EDIT. # Automatically generated file. DO NOT EDIT.
# Espressif IoT Development Framework (ESP-IDF) Project Configuration # Espressif IoT Development Framework (ESP-IDF) Project Configuration
# #
CONFIG_DAC_CONFIG="model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32"
CONFIG_MUTE_GPIO=-1
CONFIG_MUTE_GPIO_LEVEL=-1
CONFIG_IDF_TARGET_ESP32=y CONFIG_IDF_TARGET_ESP32=y
CONFIG_IDF_TARGET="esp32" CONFIG_IDF_TARGET="esp32"
CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000

View File

@@ -2,6 +2,8 @@
# Automatically generated file. DO NOT EDIT. # Automatically generated file. DO NOT EDIT.
# Espressif IoT Development Framework (ESP-IDF) Project Configuration # Espressif IoT Development Framework (ESP-IDF) Project Configuration
# #
CONFIG_MUTE_GPIO=-1
CONFIG_MUTE_GPIO_LEVEL=-1
CONFIG_IDF_TARGET_ESP32=y CONFIG_IDF_TARGET_ESP32=y
CONFIG_IDF_TARGET="esp32" CONFIG_IDF_TARGET="esp32"
CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000

View File

@@ -118,6 +118,9 @@ CONFIG_SPKFAULT_GPIO=2
CONFIG_SPKFAULT_GPIO_LEVEL=0 CONFIG_SPKFAULT_GPIO_LEVEL=0
CONFIG_BAT_CHANNEL=7 CONFIG_BAT_CHANNEL=7
CONFIG_BAT_SCALE="20.24" CONFIG_BAT_SCALE="20.24"
CONFIG_SPDIF_CONFIG="bck=33,ws=25,do=15"
CONFIG_DAC_CONFIG="model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0"
CONFIG_MUTE_GPIO_LEVEL=-1
CONFIG_WIFI_MANAGER_TASK_PRIORITY=5 CONFIG_WIFI_MANAGER_TASK_PRIORITY=5
CONFIG_WIFI_MANAGER_MAX_RETRY=2 CONFIG_WIFI_MANAGER_MAX_RETRY=2
CONFIG_DEFAULT_AP_SSID="squeezelite" CONFIG_DEFAULT_AP_SSID="squeezelite"

View File

@@ -117,6 +117,9 @@ CONFIG_SPKFAULT_GPIO=2
CONFIG_SPKFAULT_GPIO_LEVEL=0 CONFIG_SPKFAULT_GPIO_LEVEL=0
CONFIG_BAT_CHANNEL=7 CONFIG_BAT_CHANNEL=7
CONFIG_BAT_SCALE="20.24" CONFIG_BAT_SCALE="20.24"
CONFIG_SPDIF_CONFIG="bck=33,ws=25,do=15"
CONFIG_DAC_CONFIG="model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14"
CONFIG_MUTE_GPIO_LEVEL=-1
CONFIG_WIFI_MANAGER_TASK_PRIORITY=5 CONFIG_WIFI_MANAGER_TASK_PRIORITY=5
CONFIG_WIFI_MANAGER_MAX_RETRY=2 CONFIG_WIFI_MANAGER_MAX_RETRY=2
CONFIG_DEFAULT_AP_SSID="squeezelite" CONFIG_DEFAULT_AP_SSID="squeezelite"

View File

@@ -611,9 +611,21 @@ void config_delete_key(const char *key){
} }
config_unlock(); config_unlock();
} }
void * config_alloc_get(nvs_type_t nvs_type, const char *key) { void * config_alloc_get(nvs_type_t nvs_type, const char *key) {
return config_alloc_get_default(nvs_type, key, NULL, 0); return config_alloc_get_default(nvs_type, key, NULL, 0);
} }
void * config_alloc_get_str(const char *key, char *lead, char *fallback) {
if (lead && *lead) return strdup(lead);
char *value = config_alloc_get_default(NVS_TYPE_STR, key, NULL, 0);
if ((!value || !*value) && fallback) {
if (value) free(value);
value = strdup(fallback);
}
return value;
}
void * config_alloc_get_default(nvs_type_t nvs_type, const char *key, void * default_value, size_t blob_size) { void * config_alloc_get_default(nvs_type_t nvs_type, const char *key, void * default_value, size_t blob_size) {
void * value = NULL; void * value = NULL;

View File

@@ -73,8 +73,11 @@ static void Update( struct GDS_Device* Device ) {
#endif #endif
} }
static void SetHFlip( struct GDS_Device* Device, bool On ) { Device->WriteCommand( Device, On ? 0xA1 : 0xA0 ); } static void SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) {
static void SetVFlip( struct GDS_Device *Device, bool On ) { Device->WriteCommand( Device, On ? 0xC8 : 0xC0 ); } Device->WriteCommand( Device, HFlip ? 0xA1 : 0xA0 );
Device->WriteCommand( Device, VFlip ? 0xC8 : 0xC0 );
}
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); } static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); }
static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); } static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); }
@@ -117,8 +120,7 @@ static bool Init( struct GDS_Device* Device ) {
Device->WriteCommand( Device, 0x40 + 0x00 ); Device->WriteCommand( Device, 0x40 + 0x00 );
Device->SetContrast( Device, 0x7F ); Device->SetContrast( Device, 0x7F );
// set flip modes // set flip modes
Device->SetVFlip( Device, false ); Device->SetLayout( Device, false, false, false );
Device->SetHFlip( Device, false );
// no Display Inversion // no Display Inversion
Device->WriteCommand( Device, 0xA6 ); Device->WriteCommand( Device, 0xA6 );
// set Clocks // set Clocks
@@ -135,7 +137,7 @@ static bool Init( struct GDS_Device* Device ) {
static const struct GDS_Device SH1106 = { static const struct GDS_Device SH1106 = {
.DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast, .DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast,
.SetVFlip = SetVFlip, .SetHFlip = SetHFlip, .SetLayout = SetLayout,
.Update = Update, .Init = Init, .Update = Update, .Init = Init,
.Depth = 1, .Depth = 1,
#if !defined SHADOW_BUFFER && defined USE_IRAM #if !defined SHADOW_BUFFER && defined USE_IRAM

View File

@@ -85,8 +85,11 @@ static void Update( struct GDS_Device* Device ) {
#endif #endif
} }
static void SetHFlip( struct GDS_Device* Device, bool On ) { Device->WriteCommand( Device, On ? 0xA1 : 0xA0 ); } static void SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) {
static void SetVFlip( struct GDS_Device *Device, bool On ) { Device->WriteCommand( Device, On ? 0xC8 : 0xC0 ); } Device->WriteCommand( Device, HFlip ? 0xA1 : 0xA0 );
Device->WriteCommand( Device, VFlip ? 0xC8 : 0xC0 );
}
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); } static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); }
static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); } static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); }
@@ -129,8 +132,7 @@ static bool Init( struct GDS_Device* Device ) {
Device->WriteCommand( Device, 0x40 + 0x00 ); Device->WriteCommand( Device, 0x40 + 0x00 );
Device->SetContrast( Device, 0x7F ); Device->SetContrast( Device, 0x7F );
// set flip modes // set flip modes
Device->SetVFlip( Device, false ); Device->SetLayout( Device, false, false, false);
Device->SetHFlip( Device, false );
// no Display Inversion // no Display Inversion
Device->WriteCommand( Device, 0xA6 ); Device->WriteCommand( Device, 0xA6 );
// set Clocks // set Clocks
@@ -150,7 +152,7 @@ static bool Init( struct GDS_Device* Device ) {
static const struct GDS_Device SSD1306 = { static const struct GDS_Device SSD1306 = {
.DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast, .DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast,
.SetVFlip = SetVFlip, .SetHFlip = SetHFlip, .SetLayout = SetLayout,
.Update = Update, .Init = Init, .Update = Update, .Init = Init,
.Mode = GDS_MONO, .Depth = 1, .Mode = GDS_MONO, .Depth = 1,
#if !defined SHADOW_BUFFER && defined USE_IRAM #if !defined SHADOW_BUFFER && defined USE_IRAM

View File

@@ -96,22 +96,15 @@ static void Update( struct GDS_Device* Device ) {
#endif #endif
} }
static void SetHFlip( struct GDS_Device* Device, bool On ) { static void SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private; struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
Private->ReMap = On ? (Private->ReMap & ~(1 << 1)) : (Private->ReMap | (1 << 1)); Private->ReMap = HFlip ? (Private->ReMap & ~(1 << 1)) : (Private->ReMap | (1 << 1));
Private->ReMap = VFlip ? (Private->ReMap | (1 << 4)) : (Private->ReMap & ~(1 << 4));
Device->WriteCommand( Device, 0xA0 ); Device->WriteCommand( Device, 0xA0 );
Device->WriteData( Device, &Private->ReMap, 1 ); Device->WriteData( Device, &Private->ReMap, 1 );
WriteDataByte( Device, 0x11 ); WriteDataByte( Device, 0x11 );
} }
static void SetVFlip( struct GDS_Device *Device, bool On ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
Private->ReMap = On ? (Private->ReMap | (1 << 4)) : (Private->ReMap & ~(1 << 4));
Device->WriteCommand( Device, 0xA0 );
Device->WriteData( Device, &Private->ReMap, 1 );
WriteDataByte( Device, 0x11 );
}
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); } static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); }
static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); } static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); }
@@ -152,8 +145,7 @@ static bool Init( struct GDS_Device* Device ) {
// set flip modes // set flip modes
Private->ReMap = 0; Private->ReMap = 0;
Device->SetVFlip( Device, false ); Device->SetLayout( Device, false, false, false);
Device->SetHFlip( Device, false );
// set Clocks // set Clocks
Device->WriteCommand( Device, 0xB3 ); Device->WriteCommand( Device, 0xB3 );
@@ -187,7 +179,7 @@ static bool Init( struct GDS_Device* Device ) {
static const struct GDS_Device SSD1322 = { static const struct GDS_Device SSD1322 = {
.DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast, .DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast,
.SetVFlip = SetVFlip, .SetHFlip = SetHFlip, .SetLayout = SetLayout,
.Update = Update, .Init = Init, .Update = Update, .Init = Init,
.Mode = GDS_GRAYSCALE, .Depth = 4, .Mode = GDS_GRAYSCALE, .Depth = 4,
}; };

View File

@@ -222,22 +222,19 @@ static void DrawBitmapCBR(struct GDS_Device* Device, uint8_t *Data, int Width, i
} }
} }
static void SetHFlip( struct GDS_Device* Device, bool On ) { static void SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private; struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
if (Private->Model == SSD1326) Private->ReMap = On ? (Private->ReMap | ((1 << 0) | (1 << 2))) : (Private->ReMap & ~((1 << 0) | (1 << 2))); if (Private->Model == SSD1326) {
else Private->ReMap = On ? (Private->ReMap | ((1 << 0) | (1 << 1))) : (Private->ReMap & ~((1 << 0) | (1 << 1))); Private->ReMap = HFlip ? (Private->ReMap | ((1 << 0) | (1 << 2))) : (Private->ReMap & ~((1 << 0) | (1 << 2)));
Private->ReMap = HFlip ? (Private->ReMap | (1 << 1)) : (Private->ReMap & ~(1 << 1));
} else {
Private->ReMap = VFlip ? (Private->ReMap | ((1 << 0) | (1 << 1))) : (Private->ReMap & ~((1 << 0) | (1 << 1)));
Private->ReMap = VFlip ? (Private->ReMap | (1 << 4)) : (Private->ReMap & ~(1 << 4));
}
Device->WriteCommand( Device, 0xA0 ); Device->WriteCommand( Device, 0xA0 );
Device->WriteCommand( Device, Private->ReMap ); Device->WriteCommand( Device, Private->ReMap );
} }
static void SetVFlip( struct GDS_Device *Device, bool On ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
if (Private->Model == SSD1326) Private->ReMap = On ? (Private->ReMap | (1 << 1)) : (Private->ReMap & ~(1 << 1));
else Private->ReMap = On ? (Private->ReMap | (1 << 4)) : (Private->ReMap & ~(1 << 4));
Device->WriteCommand( Device, 0xA0 );
Device->WriteCommand( Device, Private->ReMap );
}
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); } static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); }
static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); } static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); }
@@ -291,8 +288,7 @@ static bool Init( struct GDS_Device* Device ) {
Device->WriteCommand( Device, 0x00 ); Device->WriteCommand( Device, 0x00 );
Device->SetContrast( Device, 0x7F ); Device->SetContrast( Device, 0x7F );
// set flip modes // set flip modes
Device->SetVFlip( Device, false ); Device->SetLayout( Device, false, false, false );
Device->SetHFlip( Device, false );
// no Display Inversion // no Display Inversion
Device->WriteCommand( Device, 0xA6 ); Device->WriteCommand( Device, 0xA6 );
// set Clocks // set Clocks
@@ -316,7 +312,7 @@ static bool Init( struct GDS_Device* Device ) {
static const struct GDS_Device SSD132x = { static const struct GDS_Device SSD132x = {
.DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast, .DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast,
.SetVFlip = SetVFlip, .SetHFlip = SetHFlip, .SetLayout = SetLayout,
.Update = Update4, .Init = Init, .Update = Update4, .Init = Init,
.Mode = GDS_GRAYSCALE, .Depth = 4, .Mode = GDS_GRAYSCALE, .Depth = 4,
}; };

View File

@@ -164,34 +164,31 @@ static void Update24( struct GDS_Device* Device ) {
#else #else
// always update by full lines // always update by full lines
SetColumnAddress( Device, 0, Device->Width - 1); SetColumnAddress( Device, 0, Device->Width - 1);
Device->WriteCommand(Device, ENABLE_WRITE);
for (int r = 0; r < Device->Height; r += Private->PageSize) { for (int r = 0; r < Device->Height; r += min(Private->PageSize, Device->Height - r)) {
SetRowAddress( Device, r, r + Private->PageSize - 1 ); int Height = min(Private->PageSize, Device->Height - r);
SetRowAddress( Device, r, r + Height - 1 );
Device->WriteCommand(Device, ENABLE_WRITE);
if (Private->iRAM) { if (Private->iRAM) {
memcpy(Private->iRAM, Device->Framebuffer + r * Device->Width * 3, Private->PageSize * Device->Width * 3 ); memcpy(Private->iRAM, Device->Framebuffer + r * Device->Width * 3, Height * Device->Width * 3 );
Device->WriteData( Device, Private->iRAM, Private->PageSize * Device->Width * 3 ); Device->WriteData( Device, Private->iRAM, Height * Device->Width * 3 );
} else { } else {
Device->WriteData( Device, Device->Framebuffer + r * Device->Width * 3, Private->PageSize * Device->Width * 3 ); Device->WriteData( Device, Device->Framebuffer + r * Device->Width * 3, Height * Device->Width * 3 );
} }
} }
#endif #endif
} }
static void SetHFlip( struct GDS_Device* Device, bool On ) { static void SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private; struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
Private->ReMap = On ? (Private->ReMap & ~(1 << 1)) : (Private->ReMap | (1 << 1)); Private->ReMap = HFlip ? (Private->ReMap & ~(1 << 1)) : (Private->ReMap | (1 << 1));
Private->ReMap = VFlip ? (Private->ReMap | (1 << 4)) : (Private->ReMap & ~(1 << 4));
Device->WriteCommand( Device, 0xA0 ); Device->WriteCommand( Device, 0xA0 );
WriteByte( Device, Private->ReMap ); WriteByte( Device, Private->ReMap );
} }
static void SetVFlip( struct GDS_Device *Device, bool On ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
Private->ReMap = On ? (Private->ReMap | (1 << 4)) : (Private->ReMap & ~(1 << 4));
Device->WriteCommand( Device, 0xA0 );
WriteByte( Device, Private->ReMap );
}
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); } static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAF ); }
static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); } static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); }
@@ -242,8 +239,7 @@ static bool Init( struct GDS_Device* Device ) {
// set flip modes & contrast // set flip modes & contrast
Device->SetContrast( Device, 0x7F ); Device->SetContrast( Device, 0x7F );
Device->SetVFlip( Device, false ); Device->SetLayout( Device, false, false, false );
Device->SetHFlip( Device, false );
// set Adressing Mode Horizontal // set Adressing Mode Horizontal
Private->ReMap |= (0 << 2); Private->ReMap |= (0 << 2);
@@ -265,7 +261,7 @@ static bool Init( struct GDS_Device* Device ) {
static const struct GDS_Device SSD1351 = { static const struct GDS_Device SSD1351 = {
.DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast, .DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast,
.SetVFlip = SetVFlip, .SetHFlip = SetHFlip, .SetLayout = SetLayout,
.Update = Update16, .Init = Init, .Update = Update16, .Init = Init,
.Mode = GDS_RGB565, .Depth = 16, .Mode = GDS_RGB565, .Depth = 16,
}; };

View File

@@ -29,6 +29,9 @@ enum { ST7735, ST7789 };
struct PrivateSpace { struct PrivateSpace {
uint8_t *iRAM, *Shadowbuffer; uint8_t *iRAM, *Shadowbuffer;
struct {
uint16_t Height, Width;
} Offset;
uint8_t MADCtl, PageSize; uint8_t MADCtl, PageSize;
uint8_t Model; uint8_t Model;
}; };
@@ -75,8 +78,8 @@ static void Update16( struct GDS_Device* Device ) {
FirstCol *= 2; FirstCol *= 2;
LastCol = LastCol * 2 + 1; LastCol = LastCol * 2 + 1;
SetRowAddress( Device, FirstRow, LastRow ); SetRowAddress( Device, FirstRow + Private->Offset.Height, LastRow + Private->Offset.Height);
SetColumnAddress( Device, FirstCol, LastCol ); SetColumnAddress( Device, FirstCol + Private->Offset.Width, LastCol + Private->Offset.Width );
Device->WriteCommand( Device, ENABLE_WRITE ); Device->WriteCommand( Device, ENABLE_WRITE );
int ChunkSize = (LastCol - FirstCol + 1) * 2; int ChunkSize = (LastCol - FirstCol + 1) * 2;
@@ -100,12 +103,12 @@ static void Update16( struct GDS_Device* Device ) {
} }
#else #else
// always update by full lines // always update by full lines
SetColumnAddress( Device, 0, Device->Width - 1); SetColumnAddress( Device, Private->Offset.Width, Device->Width - 1);
for (int r = 0; r < Device->Height; r += min(Private->PageSize, Device->Height - r)) { for (int r = 0; r < Device->Height; r += min(Private->PageSize, Device->Height - r)) {
int Height = min(Private->PageSize, Device->Height - r); int Height = min(Private->PageSize, Device->Height - r);
SetRowAddress( Device, r, r + Height - 1 ); SetRowAddress( Device, Private->Offset.Height + r, Private->Offset.Height + r + Height - 1 );
Device->WriteCommand(Device, ENABLE_WRITE); Device->WriteCommand(Device, ENABLE_WRITE);
if (Private->iRAM) { if (Private->iRAM) {
@@ -142,8 +145,8 @@ static void Update24( struct GDS_Device* Device ) {
FirstCol = (FirstCol * 2) / 3; FirstCol = (FirstCol * 2) / 3;
LastCol = (LastCol * 2 + 1) / 3; LastCol = (LastCol * 2 + 1) / 3;
SetRowAddress( Device, FirstRow, LastRow ); SetRowAddress( Device, FirstRow + Private->Offset.Height, LastRow + Private->Offset.Height);
SetColumnAddress( Device, FirstCol, LastCol ); SetColumnAddress( Device, FirstCol + Private->Offset.Width, LastCol + Private->Offset.Width );
Device->WriteCommand( Device, ENABLE_WRITE ); Device->WriteCommand( Device, ENABLE_WRITE );
int ChunkSize = (LastCol - FirstCol + 1) * 3; int ChunkSize = (LastCol - FirstCol + 1) * 3;
@@ -167,41 +170,55 @@ static void Update24( struct GDS_Device* Device ) {
} }
#else #else
// always update by full lines // always update by full lines
SetColumnAddress( Device, 0, Device->Width - 1); SetColumnAddress( Device, Private->Offset.Width, Device->Width - 1);
Device->WriteCommand(Device, ENABLE_WRITE);
for (int r = 0; r < Device->Height; r += Private->PageSize) { for (int r = 0; r < Device->Height; r += min(Private->PageSize, Device->Height - r)) {
SetRowAddress( Device, r, r + Private->PageSize - 1 ); int Height = min(Private->PageSize, Device->Height - r);
SetRowAddress( Device, Private->Offset.Height + r, Private->Offset.Height + r + Height - 1 );
Device->WriteCommand(Device, ENABLE_WRITE);
if (Private->iRAM) { if (Private->iRAM) {
memcpy(Private->iRAM, Device->Framebuffer + r * Device->Width * 3, Private->PageSize * Device->Width * 3 ); memcpy(Private->iRAM, Device->Framebuffer + r * Device->Width * 3, Height * Device->Width * 3 );
Device->WriteData( Device, Private->iRAM, Private->PageSize * Device->Width * 3 ); Device->WriteData( Device, Private->iRAM, Height * Device->Width * 3 );
} else { } else {
Device->WriteData( Device, Device->Framebuffer + r * Device->Width * 3, Private->PageSize * Device->Width * 3 ); Device->WriteData( Device, Device->Framebuffer + r * Device->Width * 3, Height * Device->Width * 3 );
} }
} }
#endif #endif
} }
static void SetHFlip( struct GDS_Device* Device, bool On ) { static void SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private; struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
Private->MADCtl = On ? (Private->MADCtl & ~(1 << 7)) : (Private->MADCtl | (1 << 7));
Private->MADCtl = HFlip ? (Private->MADCtl | (1 << 7)) : (Private->MADCtl & ~(1 << 7));
Private->MADCtl = VFlip ? (Private->MADCtl | (1 << 6)) : (Private->MADCtl & ~(1 << 6));
Private->MADCtl = Rotate ? (Private->MADCtl | (1 << 5)) : (Private->MADCtl & ~(1 << 5));
Device->WriteCommand( Device, 0x36 ); Device->WriteCommand( Device, 0x36 );
WriteByte( Device, Private->MADCtl ); WriteByte( Device, Private->MADCtl );
if (Private->Model == ST7789) {
if (Rotate) Private->Offset.Width = HFlip ? 320 - Device->Width : 0;
else Private->Offset.Height = HFlip ? 320 - Device->Height : 0;
}
#ifdef SHADOW_BUFFER
// force a full refresh (almost ...)
memset(Private->Shadowbuffer, 0xAA, Device->FramebufferSize);
#endif
} }
static void SetVFlip( struct GDS_Device *Device, bool On ) {
struct PrivateSpace *Private = (struct PrivateSpace*) Device->Private;
Private->MADCtl = On ? (Private->MADCtl | (1 << 6)) : (Private->MADCtl & ~(1 << 6));
Device->WriteCommand( Device, 0x36 );
WriteByte( Device, Private->MADCtl );
}
static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0x29 ); } static void DisplayOn( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0x29 ); }
static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0x28 ); } static void DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0x28 ); }
static void SetContrast( struct GDS_Device* Device, uint8_t Contrast ) { static void SetContrast( struct GDS_Device* Device, uint8_t Contrast ) {
Device->WriteCommand( Device, 0x51 ); Device->WriteCommand( Device, 0x51 );
WriteByte( Device, Contrast ); WriteByte( Device, Contrast );
Device->SetContrast = NULL;
GDS_SetContrast( Device, Contrast );
Device->SetContrast = SetContrast;
} }
static bool Init( struct GDS_Device* Device ) { static bool Init( struct GDS_Device* Device ) {
@@ -209,7 +226,7 @@ static bool Init( struct GDS_Device* Device ) {
int Depth = (Device->Depth + 8 - 1) / 8; int Depth = (Device->Depth + 8 - 1) / 8;
Private->PageSize = min(8, PAGE_BLOCK / (Device->Width * Depth)); Private->PageSize = min(8, PAGE_BLOCK / (Device->Width * Depth));
#ifdef SHADOW_BUFFER #ifdef SHADOW_BUFFER
Private->Shadowbuffer = malloc( Device->FramebufferSize ); Private->Shadowbuffer = malloc( Device->FramebufferSize );
memset(Private->Shadowbuffer, 0xFF, Device->FramebufferSize); memset(Private->Shadowbuffer, 0xFF, Device->FramebufferSize);
@@ -224,21 +241,21 @@ static bool Init( struct GDS_Device* Device ) {
Device->WriteCommand( Device, 0x11 ); Device->WriteCommand( Device, 0x11 );
// need BGR & Address Mode // need BGR & Address Mode
Private->MADCtl = (1 << 3) | ((Device->Width > Device->Height ? 1 : 0) << 5); Private->MADCtl = 1 << 3;
Device->WriteCommand( Device, 0x36 ); Device->WriteCommand( Device, 0x36 );
WriteByte( Device, Private->MADCtl ); WriteByte( Device, Private->MADCtl );
// set flip modes & contrast // set flip modes & contrast
GDS_SetContrast( Device, 0x7F ); GDS_SetContrast( Device, 0x7f );
Device->SetVFlip( Device, false ); Device->SetLayout( Device, false, false, false );
Device->SetHFlip( Device, false );
// set screen depth (16/18) // set screen depth (16/18)
Device->WriteCommand( Device, 0x3A ); Device->WriteCommand( Device, 0x3A );
WriteByte( Device, Device->Depth == 24 ? 0x06 : 0x05 ); if (Private->Model == ST7789) WriteByte( Device, Device->Depth == 24 ? 0x066 : 0x55 );
else WriteByte( Device, Device->Depth == 24 ? 0x06 : 0x05 );
// no Display Inversion // no Display Inversion
Device->WriteCommand( Device, 0x20 ); Device->WriteCommand( Device, Private->Model == ST7735 ? 0x20 : 0x21 );
// gone with the wind // gone with the wind
Device->DisplayOn( Device ); Device->DisplayOn( Device );
@@ -249,15 +266,15 @@ static bool Init( struct GDS_Device* Device ) {
static const struct GDS_Device ST77xx = { static const struct GDS_Device ST77xx = {
.DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .DisplayOn = DisplayOn, .DisplayOff = DisplayOff,
.SetVFlip = SetVFlip, .SetHFlip = SetHFlip, .SetLayout = SetLayout,
.Update = Update16, .Init = Init, .Update = Update16, .Init = Init,
.Mode = GDS_RGB565, .Depth = 16, .Mode = GDS_RGB565, .Depth = 16,
}; };
struct GDS_Device* ST77xx_Detect(char *Driver, struct GDS_Device* Device) { struct GDS_Device* ST77xx_Detect(char *Driver, struct GDS_Device* Device) {
uint8_t Model; uint8_t Model;
int Depth; int Depth;
if (strcasestr(Driver, "ST7735")) Model = ST7735; if (strcasestr(Driver, "ST7735")) Model = ST7735;
else if (strcasestr(Driver, "ST7789")) Model = ST7789; else if (strcasestr(Driver, "ST7789")) Model = ST7789;
else return NULL; else return NULL;
@@ -275,6 +292,6 @@ struct GDS_Device* ST77xx_Detect(char *Driver, struct GDS_Device* Device) {
} }
if (Model == ST7789) Device->SetContrast = SetContrast; if (Model == ST7789) Device->SetContrast = SetContrast;
return Device; return Device;
} }

View File

@@ -236,8 +236,7 @@ void GDS_SetContrast( struct GDS_Device* Device, uint8_t Contrast ) {
} }
} }
void GDS_SetHFlip( struct GDS_Device* Device, bool On ) { if (Device->SetHFlip) Device->SetHFlip( Device, On ); } void GDS_SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate ) { if (Device->SetLayout) Device->SetLayout( Device, HFlip, VFlip, Rotate ); }
void GDS_SetVFlip( struct GDS_Device* Device, bool On ) { if (Device->SetVFlip) Device->SetVFlip( Device, On ); }
void GDS_SetDirty( struct GDS_Device* Device ) { Device->Dirty = true; } void GDS_SetDirty( struct GDS_Device* Device ) { Device->Dirty = true; }
int GDS_GetWidth( struct GDS_Device* Device ) { return Device->Width; } int GDS_GetWidth( struct GDS_Device* Device ) { return Device->Width; }
int GDS_GetHeight( struct GDS_Device* Device ) { return Device->Height; } int GDS_GetHeight( struct GDS_Device* Device ) { return Device->Height; }

View File

@@ -35,8 +35,7 @@ void GDS_SetContrast( struct GDS_Device* Device, uint8_t Contrast );
void GDS_DisplayOn( struct GDS_Device* Device ); void GDS_DisplayOn( struct GDS_Device* Device );
void GDS_DisplayOff( struct GDS_Device* Device ); void GDS_DisplayOff( struct GDS_Device* Device );
void GDS_Update( struct GDS_Device* Device ); void GDS_Update( struct GDS_Device* Device );
void GDS_SetHFlip( struct GDS_Device* Device, bool On ); void GDS_SetLayout( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate );
void GDS_SetVFlip( struct GDS_Device* Device, bool On );
void GDS_SetDirty( struct GDS_Device* Device ); void GDS_SetDirty( struct GDS_Device* Device );
int GDS_GetWidth( struct GDS_Device* Device ); int GDS_GetWidth( struct GDS_Device* Device );
int GDS_GetHeight( struct GDS_Device* Device ); int GDS_GetHeight( struct GDS_Device* Device );

View File

@@ -101,7 +101,7 @@ struct GDS_Device {
uint8_t Alloc; uint8_t Alloc;
uint8_t* Framebuffer; uint8_t* Framebuffer;
uint16_t FramebufferSize; uint32_t FramebufferSize;
bool Dirty; bool Dirty;
// default fonts when using direct draw // default fonts when using direct draw
@@ -117,8 +117,7 @@ struct GDS_Device {
void (*SetContrast)( struct GDS_Device* Device, uint8_t Contrast ); void (*SetContrast)( struct GDS_Device* Device, uint8_t Contrast );
void (*DisplayOn)( struct GDS_Device* Device ); void (*DisplayOn)( struct GDS_Device* Device );
void (*DisplayOff)( struct GDS_Device* Device ); void (*DisplayOff)( struct GDS_Device* Device );
void (*SetHFlip)( struct GDS_Device* Device, bool On ); void (*SetLayout)( struct GDS_Device* Device, bool HFlip, bool VFlip, bool Rotate );
void (*SetVFlip)( struct GDS_Device* Device, bool On );
// must provide for depth other than 1 (vertical) and 4 (may provide for optimization) // must provide for depth other than 1 (vertical) and 4 (may provide for optimization)
void (*DrawPixelFast)( struct GDS_Device* Device, int X, int Y, int Color ); void (*DrawPixelFast)( struct GDS_Device* Device, int X, int Y, int Color );
void (*DrawBitmapCBR)(struct GDS_Device* Device, uint8_t *Data, int Width, int Height, int Color ); void (*DrawBitmapCBR)(struct GDS_Device* Device, uint8_t *Data, int Width, int Height, int Color );
@@ -130,8 +129,8 @@ struct GDS_Device {
WriteCommandProc WriteCommand; WriteCommandProc WriteCommand;
WriteDataProc WriteData; WriteDataProc WriteData;
// 16 bytes for whatever the driver wants (should be aligned as it's 32 bits) // 32 bytes for whatever the driver wants (should be aligned as it's 32 bits)
uint32_t Private[4]; uint32_t Private[8];
}; };
bool GDS_Reset( struct GDS_Device* Device ); bool GDS_Reset( struct GDS_Device* Device );

View File

@@ -59,20 +59,15 @@ static const char *known_drivers[] = {"SH1106",
static void displayer_task(void *args); static void displayer_task(void *args);
struct GDS_Device *display; struct GDS_Device *display;
extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, ILI9341_Detect; extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect;
GDS_DetectFunc *drivers[] = { SH1106_Detect, SSD1306_Detect, SSD132x_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, ILI9341_Detect, NULL }; GDS_DetectFunc *drivers[] = { SH1106_Detect, SSD1306_Detect, SSD132x_Detect, SSD1675_Detect, SSD1322_Detect, SSD1351_Detect, ST77xx_Detect, NULL };
/**************************************************************************************** /****************************************************************************************
* *
*/ */
void display_init(char *welcome) { void display_init(char *welcome) {
bool init = false; bool init = false;
char *config = config_alloc_get(NVS_TYPE_STR, "display_config"); char *config = config_alloc_get_str("display_config", CONFIG_DISPLAY_CONFIG, "N/A");
if (!config) {
ESP_LOGI(TAG, "no display");
return;
}
int width = -1, height = -1, backlight_pin = -1; int width = -1, height = -1, backlight_pin = -1;
char *p, *drivername = strstr(config, "driver"); char *p, *drivername = strstr(config, "driver");
@@ -130,8 +125,7 @@ void display_init(char *welcome) {
static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4))); static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
static EXT_RAM_ATTR StackType_t xStack[DISPLAYER_STACK_SIZE] __attribute__ ((aligned (4))); static EXT_RAM_ATTR StackType_t xStack[DISPLAYER_STACK_SIZE] __attribute__ ((aligned (4)));
GDS_SetHFlip(display, strcasestr(config, "HFlip") ? true : false); GDS_SetLayout( display, strcasestr(config, "HFlip"), strcasestr(config, "VFlip"), strcasestr(config, "rotate"));
GDS_SetVFlip(display, strcasestr(config, "VFlip") ? true : false);
GDS_SetFont(display, &Font_droid_sans_fallback_15x17 ); GDS_SetFont(display, &Font_droid_sans_fallback_15x17 );
GDS_TextPos(display, GDS_FONT_MEDIUM, GDS_TEXT_CENTERED, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, welcome); GDS_TextPos(display, GDS_FONT_MEDIUM, GDS_TEXT_CENTERED, GDS_TEXT_CLEAR | GDS_TEXT_UPDATE, welcome);

View File

@@ -115,7 +115,7 @@ const spi_bus_config_t * config_spi_get(spi_host_device_t * spi_host) {
.quadhd_io_num = -1 .quadhd_io_num = -1
}; };
nvs_item = config_alloc_get(NVS_TYPE_STR, "spi_config"); nvs_item = config_alloc_get_str("spi_config", CONFIG_SPI_CONFIG, NULL);
if (nvs_item) { if (nvs_item) {
if ((p = strcasestr(nvs_item, "data")) != NULL) spi.mosi_io_num = atoi(strchr(p, '=') + 1); if ((p = strcasestr(nvs_item, "data")) != NULL) spi.mosi_io_num = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(nvs_item, "clk")) != NULL) spi.sclk_io_num = atoi(strchr(p, '=') + 1); if ((p = strcasestr(nvs_item, "clk")) != NULL) spi.sclk_io_num = atoi(strchr(p, '=') + 1);

View File

@@ -168,7 +168,7 @@ int led_allocate(void) {
*/ */
bool led_config(int idx, gpio_num_t gpio, int onstate, int pwm) { bool led_config(int idx, gpio_num_t gpio, int onstate, int pwm) {
if (gpio < 0) { if (gpio < 0) {
ESP_LOGW(TAG,"LED GPIO not configured"); ESP_LOGW(TAG,"LED GPIO -1 ignored");
return false; return false;
} }
@@ -231,7 +231,7 @@ void led_svc_init(void) {
#ifndef CONFIG_LED_LOCKED #ifndef CONFIG_LED_LOCKED
parse_set_GPIO(set_led_gpio); parse_set_GPIO(set_led_gpio);
#endif #endif
ESP_LOGI(TAG,"Configuring LEDs green:%d (active:%d %d%%), red:%d (active:%d %d%%)", green.gpio, green.active, green.pwm, red.gpio, red.active, red.pwm); ESP_LOGI(TAG,"Configuring LEDs green:%d (active:%d %d%%), red:%d (active:%d %d%%)", green.gpio, green.active, green.pwm, green.gpio, green.active, green.pwm );
char *nvs_item = config_alloc_get(NVS_TYPE_STR, "led_brightness"), *p; char *nvs_item = config_alloc_get(NVS_TYPE_STR, "led_brightness"), *p;
if (nvs_item) { if (nvs_item) {

View File

@@ -33,7 +33,7 @@
#include "adac.h" #include "adac.h"
#include "ac101.h" #include "ac101.h"
const static char TAG[] = "AC101"; static const char TAG[] = "AC101";
#define SPKOUT_EN ((1 << 9) | (1 << 11) | (1 << 7) | (1 << 5)) #define SPKOUT_EN ((1 << 9) | (1 << 11) | (1 << 7) | (1 << 5))
#define EAROUT_EN ((1 << 11) | (1 << 12) | (1 << 13)) #define EAROUT_EN ((1 << 11) | (1 << 12) | (1 << 13))
@@ -48,14 +48,14 @@ const static char TAG[] = "AC101";
return b;\ return b;\
} }
static bool init(int i2c_port_num, int i2s_num, i2s_config_t *config); static bool init(char *config, int i2c_port_num);
static void deinit(void); static void deinit(void);
static void speaker(bool active); static void speaker(bool active);
static void headset(bool active); static void headset(bool active);
static void volume(unsigned left, unsigned right); static bool volume(unsigned left, unsigned right);
static void power(adac_power_e mode); static void power(adac_power_e mode);
struct adac_s dac_a1s = { init, deinit, power, speaker, headset, volume }; const struct adac_s dac_ac101 = { "AC101", init, deinit, power, speaker, headset, volume };
static esp_err_t i2c_write_reg(uint8_t reg, uint16_t val); static esp_err_t i2c_write_reg(uint8_t reg, uint16_t val);
static uint16_t i2c_read_reg(uint8_t reg); static uint16_t i2c_read_reg(uint8_t reg);
@@ -70,21 +70,24 @@ static int i2c_port;
/**************************************************************************************** /****************************************************************************************
* init * init
*/ */
static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) { static bool init(char *config, int i2c_port_num) {
esp_err_t res = ESP_OK; esp_err_t res = ESP_OK;
char *p;
i2c_port = i2c_port_num;
// configure i2c // configure i2c
i2c_config_t i2c_config = { i2c_config_t i2c_config = {
.mode = I2C_MODE_MASTER, .mode = I2C_MODE_MASTER,
.sda_io_num = 33, .sda_io_num = -1,
.sda_pullup_en = GPIO_PULLUP_ENABLE, .sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = 32, .scl_io_num = -1,
.scl_pullup_en = GPIO_PULLUP_ENABLE, .scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 250000, .master.clk_speed = 250000,
}; };
if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1);
i2c_port = i2c_port_num;
i2c_param_config(i2c_port, &i2c_config); i2c_param_config(i2c_port, &i2c_config);
i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false); i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
@@ -96,8 +99,6 @@ static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) {
return 0; return 0;
} }
ESP_LOGI(TAG, "AC101 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); res = i2c_write_reg(CHIP_AUDIO_RS, 0x123);
// huh? // huh?
vTaskDelay(100 / portTICK_PERIOD_MS); vTaskDelay(100 / portTICK_PERIOD_MS);
@@ -140,13 +141,6 @@ static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) {
i2c_write_reg(OMIXER_SR, BIN(0000,0101,0000,1010)); // source=DAC(R/L) and LINEIN(R/L) i2c_write_reg(OMIXER_SR, BIN(0000,0101,0000,1010)); // source=DAC(R/L) and LINEIN(R/L)
#endif #endif
// configure I2S pins & install driver
i2s_pin_config_t i2s_pin_config = (i2s_pin_config_t) { .bck_io_num = CONFIG_I2S_BCK_IO, .ws_io_num = CONFIG_I2S_WS_IO,
.data_out_num = CONFIG_I2S_DO_IO, .data_in_num = CONFIG_I2S_DI_IO
};
res |= i2s_driver_install(i2s_num, i2s_config, 0, NULL);
res |= i2s_set_pin(i2s_num, &i2s_pin_config);
// enable earphone & speaker // enable earphone & speaker
i2c_write_reg(SPKOUT_CTRL, 0x0220); i2c_write_reg(SPKOUT_CTRL, 0x0220);
i2c_write_reg(HPOUT_CTRL, 0xf801); i2c_write_reg(HPOUT_CTRL, 0xf801);
@@ -155,7 +149,7 @@ static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) {
ac101_set_spk_volume(100); ac101_set_spk_volume(100);
ac101_set_earph_volume(100); ac101_set_earph_volume(100);
ESP_LOGI(TAG, "DAC using I2S bck:%d, ws:%d, do:%d", i2s_pin_config.bck_io_num, i2s_pin_config.ws_io_num, i2s_pin_config.data_out_num); ESP_LOGI(TAG, "AC101 uses I2C sda:%d, scl:%d", i2c_config.sda_io_num, i2c_config.scl_io_num);
return (res == ESP_OK); return (res == ESP_OK);
} }
@@ -170,8 +164,9 @@ static void deinit(void) {
/**************************************************************************************** /****************************************************************************************
* change volume * change volume
*/ */
static void volume(unsigned left, unsigned right) { static bool volume(unsigned left, unsigned right) {
// nothing at that point, volume is handled by backend // nothing at that point, volume is handled by backend
return false;
} }
/**************************************************************************************** /****************************************************************************************

View File

@@ -15,14 +15,15 @@
typedef enum { ADAC_ON = 0, ADAC_STANDBY, ADAC_OFF } adac_power_e; typedef enum { ADAC_ON = 0, ADAC_STANDBY, ADAC_OFF } adac_power_e;
struct adac_s { struct adac_s {
bool (*init)(int i2c_port_num, int i2s_num, i2s_config_t *config); char *model;
bool (*init)(char *config, int i2c_port_num);
void (*deinit)(void); void (*deinit)(void);
void (*power)(adac_power_e mode); void (*power)(adac_power_e mode);
void (*speaker)(bool active); void (*speaker)(bool active);
void (*headset)(bool active); void (*headset)(bool active);
void (*volume)(unsigned left, unsigned right); bool (*volume)(unsigned left, unsigned right);
}; };
extern struct adac_s dac_tas57xx; extern const struct adac_s dac_tas57xx;
extern struct adac_s dac_a1s; extern const struct adac_s dac_ac101;
extern struct adac_s dac_external; extern const struct adac_s dac_external;

View File

@@ -20,7 +20,7 @@ CFLAGS += -O3 -DLINKALL -DLOOPBACK -DNO_FAAD -DRESAMPLE16 -DEMBEDDED -DTREMOR_ON
# -I$(COMPONENT_PATH)/../codecs/inc/faad2 # -I$(COMPONENT_PATH)/../codecs/inc/faad2
COMPONENT_SRCDIRS := . tas57xx a1s external COMPONENT_SRCDIRS := . tas57xx ac101 external
COMPONENT_ADD_INCLUDEDIRS := . ./tas57xx ./a1s COMPONENT_ADD_INCLUDEDIRS := . ./tas57xx ./ac101
COMPONENT_EMBED_FILES := vu.data COMPONENT_EMBED_FILES := vu.data

View File

@@ -28,7 +28,6 @@ extern struct buffer *outputbuf;
// this is the only system-wide loglevel variable // this is the only system-wide loglevel variable
extern log_level loglevel; extern log_level loglevel;
static bool enable_bt_sink; static bool enable_bt_sink;
static bool enable_airplay; static bool enable_airplay;

View File

@@ -573,8 +573,9 @@ void draw_VU(struct GDS_Device * display, const uint8_t *data, int level, int x,
// adjust to current display window // adjust to current display window
if (width > VU_WIDTH) { if (width > VU_WIDTH) {
if (rotate) y += (width - VU_WIDTH) / 2;
else x += (width - VU_WIDTH) / 2;
width = VU_WIDTH; width = VU_WIDTH;
x += (width - VU_WIDTH) / 2;
} else { } else {
data += (VU_WIDTH - width) / 2 * VU_HEIGHT; data += (VU_WIDTH - width) / 2 * VU_HEIGHT;
} }

View File

@@ -12,46 +12,163 @@
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/task.h> #include <freertos/task.h>
#include <driver/i2s.h> #include <driver/i2s.h>
#include "driver/i2c.h"
#include "esp_log.h" #include "esp_log.h"
#include "cJSON.h"
#include "platform_config.h" #include "platform_config.h"
#include "adac.h" #include "adac.h"
static bool init(int i2c_port_num, int i2s_num, i2s_config_t *config); static const char TAG[] = "DAC external";
static void deinit(void) { };
static void speaker(bool active) { };
static void headset(bool active) { } ;
static void volume(unsigned left, unsigned right) { };
static void power(adac_power_e mode) { };
struct adac_s dac_external = { init, deinit, power, speaker, headset, volume }; static void deinit(void) { }
static void speaker(bool active) { }
static void headset(bool active) { }
static bool volume(unsigned left, unsigned right) { return false; }
static void power(adac_power_e mode);
static bool init(char *config, int i2c_port_num);
static char TAG[] = "DAC external"; static bool i2c_json_execute(char *set);
static esp_err_t i2c_write_reg(uint8_t reg, uint8_t val);
static uint8_t i2c_read_reg(uint8_t reg);
static bool init(int i2c_port_num, int i2s_num, i2s_config_t *config) { const struct adac_s dac_external = { "i2s", init, deinit, power, speaker, headset, volume };
i2s_pin_config_t i2s_pin_config = (i2s_pin_config_t) { .bck_io_num = CONFIG_I2S_BCK_IO, .ws_io_num = CONFIG_I2S_WS_IO, static int i2c_port, i2c_addr;
.data_out_num = CONFIG_I2S_DO_IO, .data_in_num = CONFIG_I2S_DI_IO }; static cJSON *i2c_json;
char *nvs_item = config_alloc_get(NVS_TYPE_STR, "dac_config");
/****************************************************************************************
* init
*/
static bool init(char *config, int i2c_port_num) {
char *p;
i2c_port = i2c_port_num;
if (nvs_item) { // configure i2c
char *p; i2c_config_t i2c_config = {
if ((p = strcasestr(nvs_item, "bck")) != NULL) i2s_pin_config.bck_io_num = atoi(strchr(p, '=') + 1); .mode = I2C_MODE_MASTER,
if ((p = strcasestr(nvs_item, "ws")) != NULL) i2s_pin_config.ws_io_num = atoi(strchr(p, '=') + 1); .sda_io_num = -1,
if ((p = strcasestr(nvs_item, "do")) != NULL) i2s_pin_config.data_out_num = atoi(strchr(p, '=') + 1); .sda_pullup_en = GPIO_PULLUP_ENABLE,
free(nvs_item); .scl_io_num = -1,
} .scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 250000,
};
if ((p = strcasestr(config, "i2c")) != NULL) i2c_addr = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1);
p = config_alloc_get_str("dac_controlset", CONFIG_DAC_CONTROLSET, NULL);
i2c_json = cJSON_Parse(p);
if (i2s_pin_config.bck_io_num != -1 && i2s_pin_config.ws_io_num != -1 && i2s_pin_config.data_out_num != -1) { if (!i2c_addr || !i2c_json || i2c_config.sda_io_num == -1 || i2c_config.scl_io_num == -1) {
i2s_driver_install(i2s_num, config, 0, NULL); if (p) free(p);
i2s_set_pin(i2s_num, &i2s_pin_config); ESP_LOGW(TAG, "No i2c controlset found");
ESP_LOGI(TAG, "External DAC using I2S bck:%u, ws:%u, do:%u", i2s_pin_config.bck_io_num, i2s_pin_config.ws_io_num, i2s_pin_config.data_out_num);
return true; return true;
} else { }
ESP_LOGI(TAG, "Cannot initialize I2S for DAC bck:%d ws:%d do:%d", i2s_pin_config.bck_io_num,
i2s_pin_config.ws_io_num, ESP_LOGI(TAG, "DAC uses I2C @%d with sda:%d, scl:%d", i2c_addr, i2c_config.sda_io_num, i2c_config.scl_io_num);
i2s_pin_config.data_out_num);
// we have an I2C configured
i2c_param_config(i2c_port, &i2c_config);
i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
if (!i2c_json_execute("init")) {
ESP_LOGE(TAG, "could not intialize DAC");
return false; return false;
} }
return true;
}
/****************************************************************************************
* power
*/
static void power(adac_power_e mode) {
if (mode == ADAC_STANDBY || mode == ADAC_OFF) i2c_json_execute("poweroff");
else i2c_json_execute("poweron");
} }
/****************************************************************************************
*
*/
bool i2c_json_execute(char *set) {
cJSON *json_set = cJSON_GetObjectItemCaseSensitive(i2c_json, set);
cJSON *item;
if (!json_set) return true;
cJSON_ArrayForEach(item, json_set)
{
cJSON *reg = cJSON_GetObjectItemCaseSensitive(item, "reg");
cJSON *val = cJSON_GetObjectItemCaseSensitive(item, "val");
cJSON *mode = cJSON_GetObjectItemCaseSensitive(item, "mode");
if (!reg || !val) continue;
if (!mode) {
i2c_write_reg(reg->valueint, val->valueint);
} else if (!strcasecmp(mode->valuestring, "or")) {
uint8_t data = i2c_read_reg(reg->valueint);
data |= (uint8_t) val->valueint;
i2c_write_reg(reg->valueint, data);
} else if (!strcasecmp(mode->valuestring, "and")) {
uint8_t data = i2c_read_reg(reg->valueint);
data &= (uint8_t) val->valueint;
i2c_write_reg(reg->valueint, data);
}
}
return true;
}
/****************************************************************************************
*
*/
static esp_err_t i2c_write_reg(uint8_t reg, uint8_t val) {
esp_err_t ret;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, i2c_addr | I2C_MASTER_WRITE, I2C_MASTER_NACK);
i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
i2c_master_write_byte(cmd, val, I2C_MASTER_NACK);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "I2C write failed");
}
return ret;
}
/****************************************************************************************
*
*/
static uint8_t i2c_read_reg(uint8_t reg) {
esp_err_t ret;
uint8_t data = 0;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, i2c_addr | I2C_MASTER_WRITE, I2C_MASTER_NACK);
i2c_master_write_byte(cmd, reg, I2C_MASTER_NACK);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, i2c_addr | I2C_MASTER_READ, I2C_MASTER_NACK);
i2c_master_read_byte(cmd, &data, I2C_MASTER_NACK);
i2c_master_stop(cmd);
ret = i2c_master_cmd_begin(i2c_port, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "I2C read failed");
}
return data;
}

View File

@@ -77,8 +77,8 @@ extern struct buffer *streambuf;
extern struct buffer *outputbuf; extern struct buffer *outputbuf;
extern u8_t *silencebuf; extern u8_t *silencebuf;
// by default no DAC selected const struct adac_s *dac_set[] = { &dac_tas57xx, &dac_ac101, NULL };
struct adac_s *adac = &dac_external; const struct adac_s *adac = &dac_external;
static log_level loglevel; static log_level loglevel;
@@ -93,7 +93,10 @@ static size_t dma_buf_frames;
static pthread_t thread; static pthread_t thread;
static TaskHandle_t stats_task; static TaskHandle_t stats_task;
static bool stats; static bool stats;
static int amp_gpio = -1; static struct {
int gpio, active;
} amp_control = { -1, 1 },
mute_control = { CONFIG_MUTE_GPIO, CONFIG_MUTE_GPIO_LEVEL };
DECLARE_ALL_MIN_MAX; DECLARE_ALL_MIN_MAX;
@@ -129,14 +132,17 @@ static void jack_handler(bool inserted) {
* amp GPIO * amp GPIO
*/ */
static void set_amp_gpio(int gpio, char *value) { static void set_amp_gpio(int gpio, char *value) {
char *p;
if (!strcasecmp(value, "amp")) { if (!strcasecmp(value, "amp")) {
amp_gpio = gpio; amp_control.gpio = gpio;
if ((p = strchr(value, ':')) != NULL) amp_control.active = atoi(p + 1);
gpio_pad_select_gpio(amp_gpio); gpio_pad_select_gpio(amp_control.gpio);
gpio_set_direction(amp_gpio, GPIO_MODE_OUTPUT); gpio_set_direction(amp_control.gpio, GPIO_MODE_OUTPUT);
gpio_set_level(amp_gpio, 0); gpio_set_level(amp_control.gpio, !amp_control.active);
LOG_INFO("setting amplifier GPIO %d", amp_gpio); LOG_INFO("setting amplifier GPIO %d (active:%d)", amp_control.gpio, amp_control.active);
} }
} }
@@ -146,7 +152,8 @@ static void set_amp_gpio(int gpio, char *value) {
void output_init_i2s(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle) { void output_init_i2s(log_level level, char *device, unsigned output_buf_size, char *params, unsigned rates[], unsigned rate_delay, unsigned idle) {
loglevel = level; loglevel = level;
char *p; char *p;
esp_err_t res;
p = config_alloc_get_default(NVS_TYPE_STR, "jack_mutes_amp", "n", 0); p = config_alloc_get_default(NVS_TYPE_STR, "jack_mutes_amp", "n", 0);
jack_mutes_amp = (strcmp(p,"1") == 0 ||strcasecmp(p,"y") == 0); jack_mutes_amp = (strcmp(p,"1") == 0 ||strcasecmp(p,"y") == 0);
free(p); free(p);
@@ -182,7 +189,14 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
} }
running = true; running = true;
i2s_pin_config_t i2s_pin_config = { .bck_io_num = -1, .ws_io_num = -1, .data_out_num = -1, .data_in_num = -1 };
// get SPDIF configuration from NVS or compile
char *spdif_config = config_alloc_get_str("spdif_config", CONFIG_SPDIF_CONFIG, "bck=" STR(CONFIG_SPDIF_BCK_IO)
",ws=" STR(CONFIG_SPDIF_WS_IO) ",do=" STR(CONFIG_SPDIF_DO_IO));
if ((p = strcasestr(spdif_config, "do")) != NULL) i2s_pin_config.data_out_num = atoi(strchr(p, '=') + 1);
// common I2S initialization // common I2S initialization
i2s_config.mode = I2S_MODE_MASTER | I2S_MODE_TX; i2s_config.mode = I2S_MODE_MASTER | I2S_MODE_TX;
i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT; i2s_config.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT;
@@ -191,21 +205,13 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
i2s_config.tx_desc_auto_clear = true; i2s_config.tx_desc_auto_clear = true;
i2s_config.use_apll = true; i2s_config.use_apll = true;
i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1; //Interrupt level 1 i2s_config.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1; //Interrupt level 1
if (strcasestr(device, "spdif")) { if (strcasestr(device, "spdif")) {
spdif = true; spdif = true;
i2s_pin_config_t i2s_pin_config = (i2s_pin_config_t) { .bck_io_num = CONFIG_SPDIF_BCK_IO, .ws_io_num = CONFIG_SPDIF_WS_IO,
.data_out_num = CONFIG_SPDIF_DO_IO, .data_in_num = -1 }; if ((p = strcasestr(spdif_config, "bck")) != NULL) i2s_pin_config.bck_io_num = atoi(strchr(p, '=') + 1);
#ifndef CONFIG_SPDIF_LOCKED if ((p = strcasestr(spdif_config, "ws")) != NULL) i2s_pin_config.ws_io_num = atoi(strchr(p, '=') + 1);
char *nvs_item = config_alloc_get(NVS_TYPE_STR, "spdif_config");
if (nvs_item) {
if ((p = strcasestr(nvs_item, "bck")) != NULL) i2s_pin_config.bck_io_num = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(nvs_item, "ws")) != NULL) i2s_pin_config.ws_io_num = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(nvs_item, "do")) != NULL) i2s_pin_config.data_out_num = atoi(strchr(p, '=') + 1);
free(nvs_item);
}
#endif
if (i2s_pin_config.bck_io_num == -1 || i2s_pin_config.ws_io_num == -1 || i2s_pin_config.data_out_num == -1) { if (i2s_pin_config.bck_io_num == -1 || i2s_pin_config.ws_io_num == -1 || i2s_pin_config.data_out_num == -1) {
LOG_WARN("Cannot initialize I2S for SPDIF bck:%d ws:%d do:%d", i2s_pin_config.bck_io_num, LOG_WARN("Cannot initialize I2S for SPDIF bck:%d ws:%d do:%d", i2s_pin_config.bck_io_num,
i2s_pin_config.ws_io_num, i2s_pin_config.ws_io_num,
@@ -223,30 +229,64 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
audio frame. So the real depth is true frames is (LEN * COUNT / 2) audio frame. So the real depth is true frames is (LEN * COUNT / 2)
*/ */
dma_buf_frames = DMA_BUF_COUNT * DMA_BUF_LEN / 2; dma_buf_frames = DMA_BUF_COUNT * DMA_BUF_LEN / 2;
i2s_driver_install(CONFIG_I2S_NUM, &i2s_config, 0, NULL); res = i2s_driver_install(CONFIG_I2S_NUM, &i2s_config, 0, NULL);
i2s_set_pin(CONFIG_I2S_NUM, &i2s_pin_config); res |= i2s_set_pin(CONFIG_I2S_NUM, &i2s_pin_config);
LOG_INFO("SPDIF using I2S bck:%u, ws:%u, do:%u", i2s_pin_config.bck_io_num, i2s_pin_config.ws_io_num, i2s_pin_config.data_out_num); LOG_INFO("SPDIF using I2S bck:%u, ws:%u, do:%u", i2s_pin_config.bck_io_num, i2s_pin_config.ws_io_num, i2s_pin_config.data_out_num);
} else { } else {
#if CONFIG_SPDIF_DO_IO != -1 // turn off SPDIF if configured
gpio_pad_select_gpio(CONFIG_SPDIF_DO_IO); if (i2s_pin_config.data_out_num >= 0) {
gpio_set_direction(CONFIG_SPDIF_DO_IO, GPIO_MODE_OUTPUT); gpio_pad_select_gpio(i2s_pin_config.data_out_num);
gpio_set_level(CONFIG_SPDIF_DO_IO, 0); gpio_set_direction(i2s_pin_config.data_out_num, GPIO_MODE_OUTPUT);
#endif gpio_set_level(i2s_pin_config.data_out_num, 0);
}
char *dac_config = config_alloc_get_str("dac_config", CONFIG_DAC_CONFIG, "model=i2s,bck=" STR(CONFIG_I2S_BCK_IO)
",ws=" STR(CONFIG_I2S_WS_IO) ",do=" STR(CONFIG_I2S_DO_IO)
",sda=" STR(CONFIG_I2C_SDA) ",scl=" STR(CONFIG_I2C_SCL)
",mute" STR(CONFIG_MUTE_GPIO));
char model[32] = "i2s";
if ((p = strcasestr(dac_config, "model")) != NULL) sscanf(p, "%*[^=]=%31[^,]", model);
for (int i = 0; adac == &dac_external && dac_set[i]; i++) if (strcasestr(dac_set[i]->model, model)) adac = dac_set[i];
res = adac->init(dac_config, I2C_PORT) ? ESP_OK : ESP_FAIL;
if ((p = strcasestr(dac_config, "bck")) != NULL) i2s_pin_config.bck_io_num = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(dac_config, "ws")) != NULL) i2s_pin_config.ws_io_num = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(dac_config, "do")) != NULL) i2s_pin_config.data_out_num = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(dac_config, "mute")) != NULL) {
char mute[8];
sscanf(p, "%*[^=]=%7[^,]", mute);
mute_control.gpio = atoi(mute);
if ((p = strchr(mute, ':')) != NULL) mute_control.active = atoi(p + 1);
}
free(dac_config);
i2s_config.sample_rate = output.current_sample_rate; i2s_config.sample_rate = output.current_sample_rate;
i2s_config.bits_per_sample = bytes_per_frame * 8 / 2; i2s_config.bits_per_sample = bytes_per_frame * 8 / 2;
// Counted in frames (but i2s allocates a buffer <= 4092 bytes) // Counted in frames (but i2s allocates a buffer <= 4092 bytes)
i2s_config.dma_buf_len = DMA_BUF_LEN; i2s_config.dma_buf_len = DMA_BUF_LEN;
i2s_config.dma_buf_count = DMA_BUF_COUNT; i2s_config.dma_buf_count = DMA_BUF_COUNT;
dma_buf_frames = DMA_BUF_COUNT * DMA_BUF_LEN; dma_buf_frames = DMA_BUF_COUNT * DMA_BUF_LEN;
// finally let DAC driver initialize I2C and I2S res |= i2s_driver_install(CONFIG_I2S_NUM, &i2s_config, 0, NULL);
if (dac_tas57xx.init(I2C_PORT, CONFIG_I2S_NUM, &i2s_config)) adac = &dac_tas57xx; res |= i2s_set_pin(CONFIG_I2S_NUM, &i2s_pin_config);
else if (dac_a1s.init(I2C_PORT, CONFIG_I2S_NUM, &i2s_config)) adac = &dac_a1s;
else if (!dac_external.init(I2C_PORT, CONFIG_I2S_NUM, &i2s_config)) { if (res == ESP_OK && mute_control.gpio >= 0) {
LOG_WARN("DAC not configured and SPDIF not enabled, I2S will not continue"); gpio_pad_select_gpio(mute_control.gpio);
return; gpio_set_direction(mute_control.gpio, GPIO_MODE_OUTPUT);
} gpio_set_level(mute_control.gpio, mute_control.active);
}
LOG_INFO("%s DAC using I2S bck:%d, ws:%d, do:%d, mute:%d:%d (res:%d)", model, i2s_pin_config.bck_io_num, i2s_pin_config.ws_io_num,
i2s_pin_config.data_out_num, mute_control.gpio, mute_control.active, res);
}
free(spdif_config);
if (res != ESP_OK) {
LOG_WARN("no DAC configured");
return;
} }
LOG_INFO("Initializing I2S mode %s with rate: %d, bits per sample: %d, buffer frames: %d, number of buffers: %d ", LOG_INFO("Initializing I2S mode %s with rate: %d, bits per sample: %d, buffer frames: %d, number of buffers: %d ",
@@ -314,8 +354,8 @@ void output_close_i2s(void) {
* change volume * change volume
*/ */
bool output_volume_i2s(unsigned left, unsigned right) { bool output_volume_i2s(unsigned left, unsigned right) {
adac->volume(left, right); if (mute_control.gpio >= 0) gpio_set_level(mute_control.gpio, (left | right) ? !mute_control.active : mute_control.active);
return false; return adac->volume(left, right);
} }
/**************************************************************************************** /****************************************************************************************
@@ -396,8 +436,8 @@ static void *output_thread_i2s(void *arg) {
LOG_INFO("Output state is %d", output.state); LOG_INFO("Output state is %d", output.state);
if (output.state == OUTPUT_OFF) { if (output.state == OUTPUT_OFF) {
led_blink(LED_GREEN, 100, 2500); led_blink(LED_GREEN, 100, 2500);
if (amp_gpio != -1) gpio_set_level(amp_gpio, 0); if (amp_control.gpio != -1) gpio_set_level(amp_control.gpio, !amp_control.active);
LOG_INFO("switching off amp GPIO %d", amp_gpio); LOG_INFO("switching off amp GPIO %d", amp_control.gpio);
} else if (output.state == OUTPUT_STOPPED) { } else if (output.state == OUTPUT_STOPPED) {
adac->speaker(false); adac->speaker(false);
led_blink(LED_GREEN, 200, 1000); led_blink(LED_GREEN, 200, 1000);
@@ -460,7 +500,7 @@ static void *output_thread_i2s(void *arg) {
i2s_zero_dma_buffer(CONFIG_I2S_NUM); i2s_zero_dma_buffer(CONFIG_I2S_NUM);
i2s_start(CONFIG_I2S_NUM); i2s_start(CONFIG_I2S_NUM);
adac->power(ADAC_ON); adac->power(ADAC_ON);
if (amp_gpio != -1) gpio_set_level(amp_gpio, 1); if (amp_control.gpio != -1) gpio_set_level(amp_control.gpio, amp_control.active);
} }
// this does not work well as set_sample_rates resets the fifos (and it's too early) // this does not work well as set_sample_rates resets the fifos (and it's too early)

View File

@@ -9,28 +9,28 @@
* *
*/ */
#include "squeezelite.h" #include <string.h>
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "driver/i2s.h" #include "driver/i2s.h"
#include "driver/i2c.h" #include "driver/i2c.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "esp_log.h"
#include "adac.h" #include "adac.h"
// this is the only hard-wired thing
#define VOLUME_GPIO 14
#define TAS575x 0x98 #define TAS575x 0x98
#define TAS578x 0x90 #define TAS578x 0x90
static bool init(int i2c_port_num, int i2s_num, i2s_config_t *config); static const char TAG[] = "TAS575x/8x";
static bool init(char *config, int i2c_port_num);
static void deinit(void); static void deinit(void);
static void speaker(bool active); static void speaker(bool active);
static void headset(bool active); static void headset(bool active);
static void volume(unsigned left, unsigned right); static bool volume(unsigned left, unsigned right);
static void power(adac_power_e mode); static void power(adac_power_e mode);
struct adac_s dac_tas57xx = { init, deinit, power, speaker, headset, volume }; const struct adac_s dac_tas57xx = { "TAS57xx", init, deinit, power, speaker, headset, volume };
struct tas57xx_cmd_s { struct tas57xx_cmd_s {
uint8_t reg; uint8_t reg;
@@ -59,8 +59,7 @@ static const struct tas57xx_cmd_s tas57xx_cmd[] = {
{ 0x56, 0x00 }, // TAS57_ANALOGUE_ON { 0x56, 0x00 }, // TAS57_ANALOGUE_ON
}; };
static log_level loglevel = lINFO; static uint8_t tas57_addr;
static u8_t tas57_addr;
static int i2c_port; static int i2c_port;
static void dac_cmd(dac_cmd_e cmd, ...); static void dac_cmd(dac_cmd_e cmd, ...);
@@ -69,19 +68,23 @@ static int tas57_detect(void);
/**************************************************************************************** /****************************************************************************************
* init * init
*/ */
static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) { static bool init(char *config, int i2c_port_num) {
i2c_port = i2c_port_num; i2c_port = i2c_port_num;
char *p;
// configure i2c // configure i2c
i2c_config_t i2c_config = { i2c_config_t i2c_config = {
.mode = I2C_MODE_MASTER, .mode = I2C_MODE_MASTER,
.sda_io_num = 27, .sda_io_num = -1,
.sda_pullup_en = GPIO_PULLUP_ENABLE, .sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = 26, .scl_io_num = -1,
.scl_pullup_en = GPIO_PULLUP_ENABLE, .scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000, .master.clk_speed = 250000,
}; };
if ((p = strcasestr(config, "sda")) != NULL) i2c_config.sda_io_num = atoi(strchr(p, '=') + 1);
if ((p = strcasestr(config, "scl")) != NULL) i2c_config.scl_io_num = atoi(strchr(p, '=') + 1);
i2c_param_config(i2c_port, &i2c_config); i2c_param_config(i2c_port, &i2c_config);
i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false); i2c_driver_install(i2c_port, I2C_MODE_MASTER, false, false, false);
@@ -89,13 +92,11 @@ static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) {
tas57_addr = tas57_detect(); tas57_addr = tas57_detect();
if (!tas57_addr) { if (!tas57_addr) {
LOG_WARN("No TAS57xx detected"); ESP_LOGW(TAG, "No TAS57xx detected");
i2c_driver_delete(i2c_port); i2c_driver_delete(i2c_port);
return 0; return false;
} }
LOG_INFO("TAS57xx DAC using I2C sda:%u, scl:%u", i2c_config.sda_io_num, i2c_config.scl_io_num);
i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create(); i2c_cmd_handle_t i2c_cmd = i2c_cmd_link_create();
for (int i = 0; tas57xx_init_sequence[i].reg != 0xff; i++) { for (int i = 0; tas57xx_init_sequence[i].reg != 0xff; i++) {
@@ -103,32 +104,21 @@ static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) {
i2c_master_write_byte(i2c_cmd, tas57_addr | I2C_MASTER_WRITE, I2C_MASTER_NACK); i2c_master_write_byte(i2c_cmd, tas57_addr | I2C_MASTER_WRITE, I2C_MASTER_NACK);
i2c_master_write_byte(i2c_cmd, tas57xx_init_sequence[i].reg, I2C_MASTER_NACK); i2c_master_write_byte(i2c_cmd, tas57xx_init_sequence[i].reg, I2C_MASTER_NACK);
i2c_master_write_byte(i2c_cmd, tas57xx_init_sequence[i].value, I2C_MASTER_NACK); i2c_master_write_byte(i2c_cmd, tas57xx_init_sequence[i].value, I2C_MASTER_NACK);
ESP_LOGD(TAG, "i2c write %x at %u", tas57xx_init_sequence[i].reg, tas57xx_init_sequence[i].value);
LOG_DEBUG("i2c write %x at %u", tas57xx_init_sequence[i].reg, tas57xx_init_sequence[i].value);
} }
i2c_master_stop(i2c_cmd); i2c_master_stop(i2c_cmd);
esp_err_t res = i2c_master_cmd_begin(i2c_port, i2c_cmd, 500 / portTICK_RATE_MS); esp_err_t res = i2c_master_cmd_begin(i2c_port, i2c_cmd, 500 / portTICK_RATE_MS);
i2c_cmd_link_delete(i2c_cmd); i2c_cmd_link_delete(i2c_cmd);
// configure I2S pins & install driver ESP_LOGI(TAG, "TAS57xx uses I2C sda:%d, scl:%d", i2c_config.sda_io_num, i2c_config.scl_io_num);
i2s_pin_config_t i2s_pin_config = (i2s_pin_config_t) { .bck_io_num = CONFIG_I2S_BCK_IO, .ws_io_num = CONFIG_I2S_WS_IO,
.data_out_num = CONFIG_I2S_DO_IO, .data_in_num = CONFIG_I2S_DI_IO,
};
res |= i2s_driver_install(i2s_num, i2s_config, 0, NULL);
res |= i2s_set_pin(i2s_num, &i2s_pin_config);
LOG_INFO("DAC using I2S bck:%d, ws:%d, do:%d", i2s_pin_config.bck_io_num, i2s_pin_config.ws_io_num, i2s_pin_config.data_out_num);
if (res == ESP_OK) { if (res != ESP_OK) {
// init volume & mute ESP_LOGE(TAG, "could not intialize TAS57xx %d", res);
gpio_pad_select_gpio(VOLUME_GPIO);
gpio_set_direction(VOLUME_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(VOLUME_GPIO, 0);
return true;
} else {
LOG_ERROR("could not intialize TAS57xx %d", res);
return false; return false;
} }
return true;
} }
/**************************************************************************************** /****************************************************************************************
@@ -141,10 +131,7 @@ static void deinit(void) {
/**************************************************************************************** /****************************************************************************************
* change volume * change volume
*/ */
static void volume(unsigned left, unsigned right) { static bool volume(unsigned left, unsigned right) { return false; }
LOG_INFO("TAS57xx volume (L:%u R:%u)", left, right);
gpio_set_level(VOLUME_GPIO, left || right);
}
/**************************************************************************************** /****************************************************************************************
* power * power
@@ -161,7 +148,7 @@ static void power(adac_power_e mode) {
dac_cmd(TAS57_DOWN); dac_cmd(TAS57_DOWN);
break; break;
default: default:
LOG_WARN("unknown DAC command"); ESP_LOGW(TAG, "unknown DAC command");
break; break;
} }
} }
@@ -177,8 +164,7 @@ static void speaker(bool active) {
/**************************************************************************************** /****************************************************************************************
* headset * headset
*/ */
static void headset(bool active) { static void headset(bool active) { }
}
/**************************************************************************************** /****************************************************************************************
* DAC specific commands * DAC specific commands
@@ -192,7 +178,7 @@ void dac_cmd(dac_cmd_e cmd, ...) {
switch(cmd) { switch(cmd) {
case TAS57_VOLUME: case TAS57_VOLUME:
LOG_ERROR("DAC volume not handled yet"); ESP_LOGE(TAG, "DAC volume not handled yet");
break; break;
default: default:
i2c_master_start(i2c_cmd); i2c_master_start(i2c_cmd);
@@ -206,7 +192,7 @@ void dac_cmd(dac_cmd_e cmd, ...) {
i2c_cmd_link_delete(i2c_cmd); i2c_cmd_link_delete(i2c_cmd);
if (ret != ESP_OK) { if (ret != ESP_OK) {
LOG_ERROR("could not intialize TAS57xx %d", ret); ESP_LOGE(TAG, "could not intialize TAS57xx %d", ret);
} }
va_end(args); va_end(args);
@@ -216,7 +202,7 @@ void dac_cmd(dac_cmd_e cmd, ...) {
* TAS57 detection * TAS57 detection
*/ */
static int tas57_detect(void) { static int tas57_detect(void) {
u8_t data, addr[] = {TAS578x, TAS575x}; uint8_t data, addr[] = {TAS578x, TAS575x};
int ret; int ret;
for (int i = 0; i < sizeof(addr); i++) { for (int i = 0; i < sizeof(addr); i++) {
@@ -235,7 +221,7 @@ static int tas57_detect(void) {
i2c_cmd_link_delete(i2c_cmd); i2c_cmd_link_delete(i2c_cmd);
if (ret == ESP_OK) { if (ret == ESP_OK) {
LOG_INFO("Detected TAS @0x%x", addr[i]); ESP_LOGI(TAG, "Detected TAS @0x%x", addr[i]);
return addr[i]; return addr[i];
} }
} }

View File

@@ -21,6 +21,7 @@ menu "Squeezelite-ESP32"
help help
Set logging level info|debug|sdebug Set logging level info|debug|sdebug
endmenu endmenu
config JACK_LOCKED config JACK_LOCKED
bool bool
config BAT_LOCKED config BAT_LOCKED
@@ -33,59 +34,109 @@ menu "Squeezelite-ESP32"
bool bool
config SPKFAULT_LOCKED config SPKFAULT_LOCKED
bool bool
menu "Audio Output" config MUTE_GPIO_LEVEL
choice OUTPUT_TYPE int
prompt "Output Type" default 0
default BASIC_I2C_BT
help # AGGREGATES - begin
Type of hardware platform # these parameters are "aggregates" that take precedence. The must have a default value
config SQUEEZEAMP config DAC_CONFIG
bool "SqueezeAMP" string
select JACK_LOCKED default "model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0" if SQUEEZEAMP
select BAT_LOCKED default "model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32" if A1S
select I2C_LOCKED default "model=I2S,bck=26,ws=25,do=33,i2c=106,sda=21,scl=22" if TWATCH2020
select SPDIF_LOCKED default ""
select LED_LOCKED config SPDIF_CONFIG
select SPKFAULT_LOCKED string
config A1S default "bck=33,ws=25,do=15" if SQUEEZEAMP
bool "ESP32-A1S module" default ""
select I2C_LOCKED config SPI_CONFIG
config BASIC_I2C_BT string
bool "Generic I2S & Bluetooth" default "dc=27,data=19,clk=18" if TWATCH2020
endchoice default ""
config DISPLAY_CONFIG
menu "DAC I2S settings" string
default "SPI,driver=ST7789,width=240,height=240,cs=5,back=12,speed=16000000,HFlip,VFlip" if TWATCH2020
default ""
config DAC_CONTROLSET
string
default "{ \"init\": [ {\"reg\":41, \"val\":128}, {\"reg\":18, \"val\":255} ], \"poweron\": [ {\"reg\":18, \"val\":64, \"mode\":\"or\"} ], \"poweroff\": [ {\"reg\":18, \"val\":191, \"mode\":\"and\"} ] }" if TWATCH2020
default ""
# AGGREGATES - end
choice OUTPUT_TYPE
prompt "Main system"
default BASIC_I2C_BT
help
Type of hardware platform
config SQUEEZEAMP
bool "SqueezeAMP"
select JACK_LOCKED
select BAT_LOCKED
select I2C_LOCKED
select LED_LOCKED
select SPKFAULT_LOCKED
config A1S
bool "ESP32-A1S module"
select I2C_LOCKED
config TWATCH2020
bool "T-WATCH2020 by LilyGo"
select I2C_LOCKED
config BASIC_I2C_BT
bool "Generic I2S & Bluetooth"
endchoice
menu "Audio settings"
menu "DAC settings"
visible if BASIC_I2C_BT visible if BASIC_I2C_BT
config I2S_NUM menu "I2S settings"
int "I2S channel (0 or 1). " config I2S_NUM
default 0 int "I2S channel (0 or 1). "
help default 0
I2S dma channel to use. help
config I2S_BCK_IO I2S dma channel to use.
int "I2S Bit clock GPIO number. " config I2S_BCK_IO
default 33 if !A1S int "I2S Bit clock GPIO number. "
default 27 if A1S default 33
help help
I2S Bit Clock gpio pin to use. I2S Bit Clock gpio pin to use.
config I2S_WS_IO config I2S_WS_IO
int "I2S Word Select GPIO number. " int "I2S Word Select GPIO number. "
default 25 if !A1S default 25
default 26 if A1S help
help I2S Word Select gpio pin to use.
I2S Word Select gpio pin to use. config I2S_DO_IO
config I2S_DO_IO int "I2S Data Output GPIO number. "
int "I2S Data Output GPIO number. " default 32
default 32 if !A1S help
default 25 if A1S I2S data output gpio pin to use.
help config I2S_DI_IO
I2S data output gpio pin to use. int "I2S Data Input GPIO number. "
config I2S_DI_IO default -1 if !A1S
int "I2S Data Input GPIO number. " help
default -1 if !A1S I2S data input gpio pin to use (not used mostly, leave it to -1).
default 35 if A1S endmenu
help menu "I2C settings"
I2S data input gpio pin to use (not used mostly, leave it to -1). config I2C_SDA
int "I2C SDA GPIO number for DAC control. "
default -1
help
I2C data gpio pin to use with DAC (not used mostly, leave it to -1).
config I2C_SCL
int "I2C SCL GPIO number for DAC control. "
default -1
help
I2C clock gpio pin to use with DAC (not used mostly, leave it to -1).
endmenu
config MUTE_GPIO
int "GPIO for muting DAC"
default -1
help
GPIO used to mute DAC (not used mostly, leave it to -1).
config MUTE_GPIO_LEVEL
int "Mute GPIO active level"
depends on MUTE_GPIO != -1
default 1
endmenu endmenu
menu "SPDIF settings" menu "SPDIF settings"
@@ -107,9 +158,7 @@ menu "Squeezelite-ESP32"
Must be set as SPDIF re-uses I2S but only needs DO (recommendation: set it to I2S Word select value) Must be set as SPDIF re-uses I2S but only needs DO (recommendation: set it to I2S Word select value)
config SPDIF_DO_IO config SPDIF_DO_IO
int "SPDIF Data I/O GPIO number" int "SPDIF Data I/O GPIO number"
default 15 if SQUEEZEAMP default -1
default I2S_DO_IO if !A1S
default -1 if A1S
help help
I2S data output IO use to simulate SPDIF I2S data output IO use to simulate SPDIF
endmenu endmenu
@@ -181,16 +230,17 @@ menu "Squeezelite-ESP32"
endmenu endmenu
menu "Display Screen" menu "Display Screen"
depends on !TWATCH2020
config DISPLAY_CONFIG config DISPLAY_CONFIG
string "Screen configuraton" string "Screen configuraton"
default ""
help help
Set parameters for display screen, leave empty for no screen Set parameters for display screen, leave empty for no screen
I2C,width=<pixels>,height=<pixels>[address=<i2c_address>][,HFlip][,VFlip] I2C,driver=<model>,width=<pixels>,height=<pixels>[address=<i2c_address>][,HFlip][,VFlip][,rotate]
SPI,width=<pixels>,height=<pixels>,cs=<gpio>[,HFlip][,VFlip] SPI,driver=<model>,width=<pixels>,height=<pixels>,cs=<gpio>[,HFlip][,VFlip][,rotate]
endmenu endmenu
menu "Various I/O" menu "Various I/O"
visible if !TWATCH2020
config I2C_CONFIG config I2C_CONFIG
string "I2C system configuration" string "I2C system configuration"
default "" default ""
@@ -199,7 +249,6 @@ menu "Squeezelite-ESP32"
sda=<gpio>,scl=<gpio>[,speed=<num>][,port=<0|1>] sda=<gpio>,scl=<gpio>[,speed=<num>][,port=<0|1>]
config SPI_CONFIG config SPI_CONFIG
string "SPI system configuration" string "SPI system configuration"
default ""
help help
Set parameters of shared SPI interface Set parameters of shared SPI interface
data=<gpio>,clk=<gpio>[,d/c=<num>][,host=<0|1|2>] data=<gpio>,clk=<gpio>[,d/c=<num>][,host=<0|1|2>]
@@ -208,7 +257,7 @@ menu "Squeezelite-ESP32"
default "" default ""
help help
Set parameters of shared GPIO with special values. Set parameters of shared GPIO with special values.
<gpio_1>=Vcc|GND|amp|jack[:0|1][,<gpio_n>=Vcc|GND|amp|jack[:0|1]] <gpio_1>=Vcc|GND|amp[:0|1]|jack[:0|1][,<gpio_n>=Vcc|GND|amp[:0|1]|jack[:0|1]]
'amp' => GPIO that is set when playback starts 'amp' => GPIO that is set when playback starts
'jack' => GPIO used for audio jack detection 'jack' => GPIO used for audio jack detection
'green', 'red' => GPIO for status LED 'green', 'red' => GPIO for status LED
@@ -218,40 +267,39 @@ menu "Squeezelite-ESP32"
default "" default ""
help help
Set GPIO for rotary encoder (quadrature phase). See README on SqueezeESP32 project's GitHub for more details Set GPIO for rotary encoder (quadrature phase). See README on SqueezeESP32 project's GitHub for more details
A=<gpio>,B=<gpio>[,SW=gpio>[,volume][,longpress]] A=<gpio>,B=<gpio>[,SW=gpio>[[,knobonly[=<ms>]|[,volume][,longpress]]
endmenu endmenu
menu "LED configuration" menu "LED configuration"
visible if !SQUEEZEAMP visible if !SQUEEZEAMP && !TWATCH2020
config LED_GREEN_GPIO config LED_GREEN_GPIO
int "Green led GPIO" int "Green led GPIO"
default -1 if !SQUEEZEAMP default 12 if SQUEEZEAMP
default 12 if SQUEEZEAMP default -1
help help
Set to -1 for no LED Set to -1 for no LED
config LED_GREEN_GPIO_LEVEL config LED_GREEN_GPIO_LEVEL
int "Green led ON level" int "Green led ON level"
depends on LED_GREEN_GPIO != -1 depends on LED_GREEN_GPIO != -1
default 0 if SQUEEZEAMP default 0 if SQUEEZEAMP
default 1 if !SQUEEZEAMP default 1
config LED_RED_GPIO config LED_RED_GPIO
int "Red led GPIO" int "Red led GPIO"
default -1 if !SQUEEZEAMP
default 13 if SQUEEZEAMP default 13 if SQUEEZEAMP
default -1
help help
Set to -1 for no LED Set to -1 for no LED
config LED_RED_GPIO_LEVEL config LED_RED_GPIO_LEVEL
int "Red led ON level" int "Red led ON level"
depends on LED_RED_GPIO != -1 depends on LED_RED_GPIO != -1
default 0 if SQUEEZEAMP default 0 if SQUEEZEAMP
default 1 if !SQUEEZEAMP default 1
endmenu endmenu
menu "Audio JACK" menu "Audio JACK"
visible if !SQUEEZEAMP visible if !SQUEEZEAMP && !TWATCH2020
config JACK_GPIO config JACK_GPIO
int "Jack insertion GPIO" int "Jack insertion GPIO"
default -1 if !SQUEEZEAMP
default 34 if SQUEEZEAMP default 34 if SQUEEZEAMP
default -1
help help
GPIO to detect speaker jack insertion. Set to -1 for no detection. GPIO to detect speaker jack insertion. Set to -1 for no detection.
config JACK_GPIO_LEVEL config JACK_GPIO_LEVEL
@@ -260,11 +308,11 @@ menu "Squeezelite-ESP32"
default 0 default 0
endmenu endmenu
menu "Speaker Fault" menu "Speaker Fault"
visible if !SQUEEZEAMP visible if !SQUEEZEAMP && !TWATCH2020
config SPKFAULT_GPIO config SPKFAULT_GPIO
int "Speaker fault GPIO" int "Speaker fault GPIO"
default -1 if !SQUEEZEAMP
default 2 if SQUEEZEAMP default 2 if SQUEEZEAMP
default -1
help help
GPIO to detect speaker fault condition. Set to -1 for no detection. GPIO to detect speaker fault condition. Set to -1 for no detection.
config SPKFAULT_GPIO_LEVEL config SPKFAULT_GPIO_LEVEL
@@ -273,18 +321,18 @@ menu "Squeezelite-ESP32"
default 0 default 0
endmenu endmenu
menu "Battery measure" menu "Battery measure"
visible if !SQUEEZEAMP visible if !SQUEEZEAMP && !TWATCH2020
config BAT_CHANNEL config BAT_CHANNEL
int "Set channel (0..7)" int "Set channel (0..7)"
default -1 if !SQUEEZEAMP
default 7 if SQUEEZEAMP default 7 if SQUEEZEAMP
default -1
help help
Read a value every 10s on ADC1 on set Channel Read a value every 10s on ADC1 on set Channel
config BAT_SCALE config BAT_SCALE
string "Set scaling factor" string "Set scaling factor"
depends on BAT_CHANNEL != -1 depends on BAT_CHANNEL != -1
default "" if !SQUEEZEAMP
default "20.24" if SQUEEZEAMP default "20.24" if SQUEEZEAMP
default ""
help help
Set the scaling factor for this 12 bits ADC Set the scaling factor for this 12 bits ADC
endmenu endmenu

View File

@@ -359,7 +359,8 @@ void register_default_nvs(){
ESP_LOGD(TAG,"Registering default value for key %s", "dac_config"); ESP_LOGD(TAG,"Registering default value for key %s", "dac_config");
config_set_default(NVS_TYPE_STR, "dac_config", "", 0); config_set_default(NVS_TYPE_STR, "dac_config", "", 0);
//todo: add dac_config for known targets //todo: add dac_config for known targets
ESP_LOGD(TAG,"Registering default value for key %s", "dac_controlset");
config_set_default(NVS_TYPE_STR, "dac_controlset", "", 0);
ESP_LOGD(TAG,"Registering default value for key %s", "bat_config"); ESP_LOGD(TAG,"Registering default value for key %s", "bat_config");
config_set_default(NVS_TYPE_STR, "bat_config", "", 0); config_set_default(NVS_TYPE_STR, "bat_config", "", 0);