mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-08 04:27:12 +03:00
Verify that SPI works with SH1106
This commit is contained in:
@@ -36,7 +36,7 @@ static const char *TAG = "display";
|
|||||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||||
|
|
||||||
#define DISPLAYER_STACK_SIZE 2048
|
#define DISPLAYER_STACK_SIZE (3*1024)
|
||||||
#define SCROLLABLE_SIZE 384
|
#define SCROLLABLE_SIZE 384
|
||||||
#define HEADER_SIZE 64
|
#define HEADER_SIZE 64
|
||||||
#define DEFAULT_SLEEP 3600
|
#define DEFAULT_SLEEP 3600
|
||||||
@@ -66,14 +66,14 @@ void display_init(char *welcome) {
|
|||||||
|
|
||||||
if (item && *item) {
|
if (item && *item) {
|
||||||
char * drivername=strstr(item,"driver");
|
char * drivername=strstr(item,"driver");
|
||||||
if (!drivername || (drivername && (strcasestr(drivername,"SSD1306") || strcasestr(drivername,"SSD1326")))) {
|
if (!drivername || (drivername && (strcasestr(drivername,"SSD1306") || strcasestr(drivername,"SSD1326") || strcasestr(drivername,"SH1106")))) {
|
||||||
display = &SSD13x6_display;
|
display = &SSD13x6_display;
|
||||||
if (display->init(item, welcome)) {
|
if (display->init(item, welcome)) {
|
||||||
init = true;
|
init = true;
|
||||||
ESP_LOGI(TAG, "Display initialization successful");
|
ESP_LOGI(TAG, "Display initialization successful");
|
||||||
} else {
|
} else {
|
||||||
display = NULL;
|
display = NULL;
|
||||||
ESP_LOGE(TAG, "Display initialization failed");
|
ESP_LOGW(TAG, "Display initialization failed");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(TAG,"Unknown display driver name in display config: %s",item);
|
ESP_LOGE(TAG,"Unknown display driver name in display config: %s",item);
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ static struct {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static bool init(char *config, char *welcome) {
|
static bool init(char *config, char *welcome) {
|
||||||
bool res = false;
|
bool res = true;
|
||||||
int width = -1, height = -1, model = SSD1306;
|
int width = -1, height = -1, model = SSD1306;
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
@@ -98,14 +98,16 @@ static bool init(char *config, char *welcome) {
|
|||||||
// no time for smart parsing - this is for tinkerers
|
// no time for smart parsing - this is for tinkerers
|
||||||
if ((p = strcasestr(config, "width")) != NULL) width = atoi(strchr(p, '=') + 1);
|
if ((p = strcasestr(config, "width")) != NULL) width = atoi(strchr(p, '=') + 1);
|
||||||
if ((p = strcasestr(config, "height")) != NULL) height = atoi(strchr(p, '=') + 1);
|
if ((p = strcasestr(config, "height")) != NULL) height = atoi(strchr(p, '=') + 1);
|
||||||
if ((p = strcasestr(config, "ssd1326")) != NULL) model = SSD1326;
|
|
||||||
|
if (strcasestr(config, "ssd1326")) model = SSD1326;
|
||||||
|
else if (strcasestr(config, "sh1106")) model = SH1106;
|
||||||
|
|
||||||
if (width == -1 || height == -1) {
|
if (width == -1 || height == -1) {
|
||||||
ESP_LOGW(TAG, "No display configured %s [%d x %d]", config, width, height);
|
ESP_LOGW(TAG, "No display configured %s [%d x %d]", config, width, height);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strstr(config, "I2C")) {
|
if (strstr(config, "I2C") && i2c_system_port != -1) {
|
||||||
int address = I2C_ADDRESS;
|
int address = I2C_ADDRESS;
|
||||||
|
|
||||||
if ((p = strcasestr(config, "address")) != NULL) address = atoi(strchr(p, '=') + 1);
|
if ((p = strcasestr(config, "address")) != NULL) address = atoi(strchr(p, '=') + 1);
|
||||||
@@ -117,10 +119,11 @@ static bool init(char *config, char *welcome) {
|
|||||||
SSD13x6_SetFont( &Display, &Font_droid_sans_fallback_15x17 );
|
SSD13x6_SetFont( &Display, &Font_droid_sans_fallback_15x17 );
|
||||||
SSD13x6_display.width = width;
|
SSD13x6_display.width = width;
|
||||||
SSD13x6_display.height = height;
|
SSD13x6_display.height = height;
|
||||||
|
|
||||||
text(DISPLAY_FONT_MEDIUM, DISPLAY_CENTERED, DISPLAY_CLEAR | DISPLAY_UPDATE, welcome);
|
text(DISPLAY_FONT_MEDIUM, DISPLAY_CENTERED, DISPLAY_CLEAR | DISPLAY_UPDATE, welcome);
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Display is I2C on port %u", address);
|
ESP_LOGI(TAG, "Display is I2C on port %u", address);
|
||||||
res = true;
|
} else if (strstr(config, "SPI") && spi_system_host != -1) {
|
||||||
} else if (strstr(config, "SPI")) {
|
|
||||||
int CS_pin = -1;
|
int CS_pin = -1;
|
||||||
|
|
||||||
if ((p = strcasestr(config, "CS")) != NULL) CS_pin = atoi(strchr(p, '=') + 1);
|
if ((p = strcasestr(config, "CS")) != NULL) CS_pin = atoi(strchr(p, '=') + 1);
|
||||||
@@ -130,11 +133,14 @@ static bool init(char *config, char *welcome) {
|
|||||||
SSD13x6_SetFont( &Display, &Font_droid_sans_fallback_15x17 );
|
SSD13x6_SetFont( &Display, &Font_droid_sans_fallback_15x17 );
|
||||||
SSD13x6_display.width = width;
|
SSD13x6_display.width = width;
|
||||||
SSD13x6_display.height = height;
|
SSD13x6_display.height = height;
|
||||||
|
|
||||||
text(DISPLAY_FONT_MEDIUM, DISPLAY_CENTERED, DISPLAY_CLEAR | DISPLAY_UPDATE, welcome);
|
text(DISPLAY_FONT_MEDIUM, DISPLAY_CENTERED, DISPLAY_CLEAR | DISPLAY_UPDATE, welcome);
|
||||||
ESP_LOGI(TAG, "Display is SPI host %u with CS:%d", spi_system_host, CS_pin);
|
|
||||||
|
ESP_LOGI(TAG, "Display is SPI host %u with cs:%d", spi_system_host, CS_pin);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(TAG, "Unknown display type");
|
res = false;
|
||||||
|
ESP_LOGW(TAG, "Unknown display type or no serial interface configured");
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -219,8 +225,9 @@ static bool line(int num, int x, int attribute, char *text) {
|
|||||||
|
|
||||||
// erase if requested
|
// erase if requested
|
||||||
if (attribute & DISPLAY_CLEAR) {
|
if (attribute & DISPLAY_CLEAR) {
|
||||||
|
int y_min = max(0, lines[num].y), y_max = max(0, lines[num].y + lines[num].font->Height);
|
||||||
for (int c = (attribute & DISPLAY_ONLY_EOL) ? x : 0; c < Display.Width; c++)
|
for (int c = (attribute & DISPLAY_ONLY_EOL) ? x : 0; c < Display.Width; c++)
|
||||||
for (int y = lines[num].y; y < lines[num].y + lines[num].font->Height; y++)
|
for (int y = y_min; y < y_max; y++)
|
||||||
SSD13x6_DrawPixelFast( &Display, c, y, SSD_COLOR_BLACK );
|
SSD13x6_DrawPixelFast( &Display, c, y, SSD_COLOR_BLACK );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,18 +375,31 @@ static void draw_cbr(u8_t *data, int height) {
|
|||||||
#else
|
#else
|
||||||
if (!height) height = Display->Height;
|
if (!height) height = Display->Height;
|
||||||
|
|
||||||
// copy data in frame buffer
|
SSD13x6_SetPageAddress( &Display, 0, height / 8 - 1);
|
||||||
|
|
||||||
|
// force addressing mode by columns (if we can)
|
||||||
|
if (SSD13x6_GetCaps( &Display ) & CAPS_ADDRESS_VERTICAL) {
|
||||||
|
// just copy data in frame buffer with bit-reverse
|
||||||
for (int c = 0; c < Display.Width; c++)
|
for (int c = 0; c < Display.Width; c++)
|
||||||
for (int r = 0; r < height / 8; r++)
|
for (int r = 0; r < height / 8; r++)
|
||||||
Display.Framebuffer[c*Display.Height/8 + r] = BitReverseTable256[data[c*height/8 +r]];
|
Display.Framebuffer[c*Display.Height/8 + r] = BitReverseTable256[data[c*height/8 +r]];
|
||||||
|
|
||||||
SSD13x6_SetPageAddress( &Display, 0, height / 8 - 1);
|
|
||||||
|
|
||||||
// force addressing mode by columns
|
|
||||||
if (AddressMode != AddressMode_Vertical) {
|
if (AddressMode != AddressMode_Vertical) {
|
||||||
AddressMode = AddressMode_Vertical;
|
AddressMode = AddressMode_Vertical;
|
||||||
SSD13x6_SetDisplayAddressMode( &Display, AddressMode );
|
SSD13x6_SetDisplayAddressMode( &Display, AddressMode );
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// need to do rwo/col swap and bit-reverse
|
||||||
|
int rows = (height ? height : Display.Height) / 8;
|
||||||
|
for (int r = 0; r < rows; r++) {
|
||||||
|
uint8_t *optr = Display.Framebuffer + r*Display.Width, *iptr = data + r;
|
||||||
|
for (int c = 0; c < Display.Width; c++) {
|
||||||
|
*optr++ = BitReverseTable256[*iptr];;
|
||||||
|
iptr += rows;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ESP_LOGW(TAG, "Can't set addressing mode to vertical, swapping");
|
||||||
|
}
|
||||||
|
|
||||||
SSD13x6_WriteRawData(&Display, Display.Framebuffer, Display.Width * Display.Height/8);
|
SSD13x6_WriteRawData(&Display, Display.Framebuffer, Display.Width * Display.Height/8);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ bool SSD13x6_I2CMasterAttachDisplayDefault( struct SSD13x6_Device* DeviceHandle,
|
|||||||
ESP_ERROR_CHECK_NONFATAL( gpio_set_level( RSTPin, 1 ), return false );
|
ESP_ERROR_CHECK_NONFATAL( gpio_set_level( RSTPin, 1 ), return false );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset( DeviceHandle, 0, sizeof( struct SSD13x6_Device ) );
|
||||||
DeviceHandle->Model = Model;
|
DeviceHandle->Model = Model;
|
||||||
|
|
||||||
return SSD13x6_Init_I2C( DeviceHandle,
|
return SSD13x6_Init_I2C( DeviceHandle,
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ bool SSD13x6_SPIMasterAttachDisplayDefault( struct SSD13x6_Device* DeviceHandle,
|
|||||||
|
|
||||||
ESP_ERROR_CHECK_NONFATAL( spi_bus_add_device( SPIHost, &SPIDeviceConfig, &SPIDeviceHandle ), return false );
|
ESP_ERROR_CHECK_NONFATAL( spi_bus_add_device( SPIHost, &SPIDeviceConfig, &SPIDeviceHandle ), return false );
|
||||||
|
|
||||||
|
memset( DeviceHandle, 0, sizeof( struct SSD13x6_Device ) );
|
||||||
DeviceHandle->Model = Model;
|
DeviceHandle->Model = Model;
|
||||||
|
|
||||||
return SSD13x6_Init_SPI( DeviceHandle,
|
return SSD13x6_Init_SPI( DeviceHandle,
|
||||||
@@ -72,19 +73,19 @@ bool SSD13x6_SPIMasterAttachDisplayDefault( struct SSD13x6_Device* DeviceHandle,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool SPIDefaultWriteBytes( spi_device_handle_t SPIHandle, int WriteMode, const uint8_t* Data, size_t DataLength ) {
|
static bool SPIDefaultWriteBytes( spi_device_handle_t SPIHandle, int WriteMode, const uint8_t* Data, size_t DataLength ) {
|
||||||
spi_transaction_t SPITransaction;
|
spi_transaction_t SPITransaction = { 0 };
|
||||||
|
|
||||||
NullCheck( SPIHandle, return false );
|
NullCheck( SPIHandle, return false );
|
||||||
NullCheck( Data, return false );
|
NullCheck( Data, return false );
|
||||||
|
|
||||||
if ( DataLength > 0 ) {
|
if ( DataLength > 0 ) {
|
||||||
memset( &SPITransaction, 0, sizeof( spi_transaction_t ) );
|
gpio_set_level( DCPin, WriteMode );
|
||||||
|
|
||||||
SPITransaction.length = DataLength * 8;
|
SPITransaction.length = DataLength * 8;
|
||||||
SPITransaction.tx_buffer = Data;
|
SPITransaction.tx_buffer = Data;
|
||||||
|
|
||||||
gpio_set_level( DCPin, WriteMode );
|
// only do polling as we don't have contention on SPI (otherwise DMA for transfers > 16 bytes)
|
||||||
ESP_ERROR_CHECK_NONFATAL( spi_device_transmit( SPIHandle, &SPITransaction ), return false );
|
ESP_ERROR_CHECK_NONFATAL( spi_device_polling_transmit(SPIHandle, &SPITransaction), return false );
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -15,15 +15,6 @@
|
|||||||
|
|
||||||
#include "ssd13x6.h"
|
#include "ssd13x6.h"
|
||||||
|
|
||||||
#define COM_Disable_LR_Remap 0
|
|
||||||
#define COM_Enable_LR_Remap BIT( 5 )
|
|
||||||
|
|
||||||
#define COM_Pins_Sequential 0
|
|
||||||
#define COM_Pins_Alternative BIT( 4 )
|
|
||||||
|
|
||||||
#define COM_ScanDir_LR 0
|
|
||||||
#define COM_ScanDir_RL 1
|
|
||||||
|
|
||||||
// used by both but different
|
// used by both but different
|
||||||
static uint8_t SSDCmd_Set_Display_Start_Line;
|
static uint8_t SSDCmd_Set_Display_Start_Line;
|
||||||
static uint8_t SSDCmd_Set_Display_Offset;
|
static uint8_t SSDCmd_Set_Display_Offset;
|
||||||
@@ -37,6 +28,11 @@ static const uint8_t SSD13x6_Max_Row = 7;
|
|||||||
|
|
||||||
static bool SSD13x6_Init( struct SSD13x6_Device* DeviceHandle, int Width, int Height );
|
static bool SSD13x6_Init( struct SSD13x6_Device* DeviceHandle, int Width, int Height );
|
||||||
|
|
||||||
|
int SSD13x6_GetCaps( struct SSD13x6_Device* DeviceHandle ) {
|
||||||
|
if (DeviceHandle->Model == SH1106) return 0;
|
||||||
|
else return CAPS_COLUMN_RANGE | CAPS_PAGE_RANGE | CAPS_ADDRESS_VERTICAL;
|
||||||
|
}
|
||||||
|
|
||||||
bool SSD13x6_WriteCommand( struct SSD13x6_Device* DeviceHandle, SSDCmd SSDCommand ) {
|
bool SSD13x6_WriteCommand( struct SSD13x6_Device* DeviceHandle, SSDCmd SSDCommand ) {
|
||||||
NullCheck( DeviceHandle->WriteCommand, return false );
|
NullCheck( DeviceHandle->WriteCommand, return false );
|
||||||
return ( DeviceHandle->WriteCommand ) ( DeviceHandle, SSDCommand );
|
return ( DeviceHandle->WriteCommand ) ( DeviceHandle, SSDCommand );
|
||||||
@@ -100,6 +96,9 @@ void SSD132x_ReMap( struct SSD13x6_Device* DeviceHandle ) {
|
|||||||
|
|
||||||
void SSD13x6_SetDisplayAddressMode( struct SSD13x6_Device* DeviceHandle, SSD13x6_AddressMode AddressMode ) {
|
void SSD13x6_SetDisplayAddressMode( struct SSD13x6_Device* DeviceHandle, SSD13x6_AddressMode AddressMode ) {
|
||||||
switch (DeviceHandle->Model) {
|
switch (DeviceHandle->Model) {
|
||||||
|
case SH1106:
|
||||||
|
// does not exist on SH1106
|
||||||
|
break;
|
||||||
case SSD1306:
|
case SSD1306:
|
||||||
SSD13x6_WriteCommand( DeviceHandle, 0x20 );
|
SSD13x6_WriteCommand( DeviceHandle, 0x20 );
|
||||||
SSD13x6_WriteCommand( DeviceHandle, AddressMode );
|
SSD13x6_WriteCommand( DeviceHandle, AddressMode );
|
||||||
@@ -112,10 +111,20 @@ void SSD13x6_SetDisplayAddressMode( struct SSD13x6_Device* DeviceHandle, SSD13x6
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SSD13x6_Update( struct SSD13x6_Device* DeviceHandle ) {
|
void SSD13x6_Update( struct SSD13x6_Device* DeviceHandle ) {
|
||||||
|
if (DeviceHandle->Model == SH1106) {
|
||||||
|
// SH1106 requires a page-by-page update and ahs no end Page/Column
|
||||||
|
for (int i = 0; i < DeviceHandle->Height / 8 ; i++) {
|
||||||
|
SSD13x6_SetPageAddress( DeviceHandle, i, 0);
|
||||||
|
SSD13x6_SetColumnAddress( DeviceHandle, 0, 0);
|
||||||
|
SSD13x6_WriteData( DeviceHandle, DeviceHandle->Framebuffer + i*DeviceHandle->Width, DeviceHandle->Width );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// others have an automatic counter and end Page/Column
|
||||||
SSD13x6_SetColumnAddress( DeviceHandle, 0, DeviceHandle->Width - 1);
|
SSD13x6_SetColumnAddress( DeviceHandle, 0, DeviceHandle->Width - 1);
|
||||||
SSD13x6_SetPageAddress( DeviceHandle, 0, DeviceHandle->Height / 8 - 1);
|
SSD13x6_SetPageAddress( DeviceHandle, 0, DeviceHandle->Height / 8 - 1);
|
||||||
SSD13x6_WriteData( DeviceHandle, DeviceHandle->Framebuffer, DeviceHandle->FramebufferSize );
|
SSD13x6_WriteData( DeviceHandle, DeviceHandle->Framebuffer, DeviceHandle->FramebufferSize );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SSD13x6_WriteRawData( struct SSD13x6_Device* DeviceHandle, uint8_t* Data, size_t DataLength ) {
|
void SSD13x6_WriteRawData( struct SSD13x6_Device* DeviceHandle, uint8_t* Data, size_t DataLength ) {
|
||||||
NullCheck( Data, return );
|
NullCheck( Data, return );
|
||||||
@@ -125,6 +134,7 @@ void SSD13x6_WriteRawData( struct SSD13x6_Device* DeviceHandle, uint8_t* Data, s
|
|||||||
|
|
||||||
void SSD13x6_SetHFlip( struct SSD13x6_Device* DeviceHandle, bool On ) {
|
void SSD13x6_SetHFlip( struct SSD13x6_Device* DeviceHandle, bool On ) {
|
||||||
switch (DeviceHandle->Model) {
|
switch (DeviceHandle->Model) {
|
||||||
|
case SH1106:
|
||||||
case SSD1306:
|
case SSD1306:
|
||||||
SSD13x6_WriteCommand( DeviceHandle, On ? 0xA1 : 0xA0 );
|
SSD13x6_WriteCommand( DeviceHandle, On ? 0xA1 : 0xA0 );
|
||||||
break;
|
break;
|
||||||
@@ -137,6 +147,7 @@ void SSD13x6_SetHFlip( struct SSD13x6_Device* DeviceHandle, bool On ) {
|
|||||||
|
|
||||||
void SSD13x6_SetVFlip( struct SSD13x6_Device* DeviceHandle, bool On ) {
|
void SSD13x6_SetVFlip( struct SSD13x6_Device* DeviceHandle, bool On ) {
|
||||||
switch (DeviceHandle->Model) {
|
switch (DeviceHandle->Model) {
|
||||||
|
case SH1106:
|
||||||
case SSD1306:
|
case SSD1306:
|
||||||
SSD13x6_WriteCommand( DeviceHandle, On ? 0xC8 : 0xC0 );
|
SSD13x6_WriteCommand( DeviceHandle, On ? 0xC8 : 0xC0 );
|
||||||
break;
|
break;
|
||||||
@@ -151,10 +162,18 @@ void SSD13x6_SetColumnAddress( struct SSD13x6_Device* DeviceHandle, uint8_t Star
|
|||||||
CheckBounds( Start > SSD13x6_Max_Col, return );
|
CheckBounds( Start > SSD13x6_Max_Col, return );
|
||||||
CheckBounds( End > SSD13x6_Max_Col, return );
|
CheckBounds( End > SSD13x6_Max_Col, return );
|
||||||
|
|
||||||
|
// on SH1106, there is no "end column"
|
||||||
|
if (DeviceHandle->Model == SH1106) {
|
||||||
|
// well, unfortunately this driver is 132 colums but most displays are 128...
|
||||||
|
if (DeviceHandle->Width != 132) Start += 2;
|
||||||
|
SSD13x6_WriteCommand( DeviceHandle, 0x10 | (Start >> 4) );
|
||||||
|
SSD13x6_WriteCommand( DeviceHandle, 0x00 | (Start & 0x0f) );
|
||||||
|
} else {
|
||||||
SSD13x6_WriteCommand( DeviceHandle, SSDCmd_Set_Column_Address );
|
SSD13x6_WriteCommand( DeviceHandle, SSDCmd_Set_Column_Address );
|
||||||
SSD13x6_WriteCommand( DeviceHandle, Start );
|
SSD13x6_WriteCommand( DeviceHandle, Start );
|
||||||
SSD13x6_WriteCommand( DeviceHandle, End );
|
SSD13x6_WriteCommand( DeviceHandle, End );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SSD13x6_SetPageAddress( struct SSD13x6_Device* DeviceHandle, uint8_t Start, uint8_t End ) {
|
void SSD13x6_SetPageAddress( struct SSD13x6_Device* DeviceHandle, uint8_t Start, uint8_t End ) {
|
||||||
NullCheck( DeviceHandle, return );
|
NullCheck( DeviceHandle, return );
|
||||||
@@ -162,6 +181,10 @@ void SSD13x6_SetPageAddress( struct SSD13x6_Device* DeviceHandle, uint8_t Start,
|
|||||||
CheckBounds( Start > SSD13x6_Max_Row, return );
|
CheckBounds( Start > SSD13x6_Max_Row, return );
|
||||||
CheckBounds( End > SSD13x6_Max_Row, return );
|
CheckBounds( End > SSD13x6_Max_Row, return );
|
||||||
|
|
||||||
|
// on SH1106, there is no "end page"
|
||||||
|
if (DeviceHandle->Model == SH1106) {
|
||||||
|
SSD13x6_WriteCommand( DeviceHandle, 0xB0 | Start );
|
||||||
|
} else {
|
||||||
// in case of SSD1326, this is sub-optimal as it can address by line, not by page
|
// in case of SSD1326, this is sub-optimal as it can address by line, not by page
|
||||||
if (DeviceHandle->Model != SSD1306) {
|
if (DeviceHandle->Model != SSD1306) {
|
||||||
Start *= 8;
|
Start *= 8;
|
||||||
@@ -172,6 +195,7 @@ void SSD13x6_SetPageAddress( struct SSD13x6_Device* DeviceHandle, uint8_t Start,
|
|||||||
SSD13x6_WriteCommand( DeviceHandle, Start );
|
SSD13x6_WriteCommand( DeviceHandle, Start );
|
||||||
SSD13x6_WriteCommand( DeviceHandle, End );
|
SSD13x6_WriteCommand( DeviceHandle, End );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool SSD13x6_HWReset( struct SSD13x6_Device* DeviceHandle ) {
|
bool SSD13x6_HWReset( struct SSD13x6_Device* DeviceHandle ) {
|
||||||
NullCheck( DeviceHandle, return 0 );
|
NullCheck( DeviceHandle, return 0 );
|
||||||
@@ -186,50 +210,40 @@ bool SSD13x6_HWReset( struct SSD13x6_Device* DeviceHandle ) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is all a big giant mystery that I have yet to figure out.
|
|
||||||
* Beware all ye who enter.
|
|
||||||
*/
|
|
||||||
static void SetCOMPinConfiguration( struct SSD13x6_Device* DeviceHandle, uint32_t RemapCFG, uint32_t PinCFG, int ScanDir ) {
|
|
||||||
SSD13x6_WriteCommand( DeviceHandle, 0xDA );
|
|
||||||
SSD13x6_WriteCommand( DeviceHandle, ( uint8_t ) ( RemapCFG | PinCFG | BIT( 1 ) ) );
|
|
||||||
|
|
||||||
SSD13x6_WriteCommand( DeviceHandle,
|
|
||||||
( ScanDir == COM_ScanDir_LR ) ? 0xC0 : 0xC8
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool SSD13x6_Init( struct SSD13x6_Device* DeviceHandle, int Width, int Height ) {
|
static bool SSD13x6_Init( struct SSD13x6_Device* DeviceHandle, int Width, int Height ) {
|
||||||
DeviceHandle->Width = Width;
|
DeviceHandle->Width = Width;
|
||||||
DeviceHandle->Height = Height;
|
DeviceHandle->Height = Height;
|
||||||
DeviceHandle->FramebufferSize = ( DeviceHandle->Width * Height ) / 8;
|
|
||||||
|
|
||||||
// DeviceHandle->Framebuffer = heap_caps_calloc( 1, DeviceHandle->FramebufferSize, MALLOC_CAP_INTERNAL );
|
|
||||||
DeviceHandle->Framebuffer = calloc( 1, DeviceHandle->FramebufferSize );
|
|
||||||
NullCheck( DeviceHandle->Framebuffer, return false );
|
|
||||||
|
|
||||||
SSD13x6_HWReset( DeviceHandle );
|
SSD13x6_HWReset( DeviceHandle );
|
||||||
|
SSD13x6_DisplayOff( DeviceHandle );
|
||||||
|
|
||||||
if (DeviceHandle->Model == SSD1306) {
|
if (DeviceHandle->Model == SSD1306 || DeviceHandle->Model == SH1106) {
|
||||||
SSDCmd_Set_Display_Start_Line = 0x40;
|
SSDCmd_Set_Display_Start_Line = 0x40;
|
||||||
SSDCmd_Set_Display_Offset = 0xD3;
|
SSDCmd_Set_Display_Offset = 0xD3;
|
||||||
SSDCmd_Set_Column_Address = 0x21,
|
SSDCmd_Set_Column_Address = 0x21,
|
||||||
SSDCmd_Set_Display_CLK = 0xD5;
|
SSDCmd_Set_Display_CLK = 0xD5;
|
||||||
SSDCmd_Set_Page_Address = 0x22;
|
SSDCmd_Set_Page_Address = 0x22;
|
||||||
|
|
||||||
SSD13x6_Max_Col = 127;
|
SSD13x6_Max_Col = 127;
|
||||||
|
|
||||||
|
if (DeviceHandle->Model == SSD1306) {
|
||||||
// charge pump regulator, do direct init
|
// charge pump regulator, do direct init
|
||||||
SSD13x6_WriteCommand( DeviceHandle, 0x8D );
|
SSD13x6_WriteCommand( DeviceHandle, 0x8D );
|
||||||
SSD13x6_WriteCommand( DeviceHandle, 0x14 ); /* MAGIC NUMBER */
|
SSD13x6_WriteCommand( DeviceHandle, 0x14 );
|
||||||
|
|
||||||
|
// COM pins HW config (alternative:EN, remap:DIS) - some display might need something difference
|
||||||
|
SSD13x6_WriteCommand( DeviceHandle, 0xDA );
|
||||||
|
SSD13x6_WriteCommand( DeviceHandle, (1 << 4) | (0 < 5) );
|
||||||
|
|
||||||
if ( Height == 64 ) {
|
|
||||||
SetCOMPinConfiguration( DeviceHandle, COM_Disable_LR_Remap, COM_Pins_Alternative, COM_ScanDir_LR );
|
|
||||||
} else {
|
} else {
|
||||||
SetCOMPinConfiguration( DeviceHandle, COM_Disable_LR_Remap, COM_Pins_Sequential, COM_ScanDir_LR );
|
// charge pump regulator, do direct init
|
||||||
|
SSD13x6_WriteCommand( DeviceHandle, 0xAD );
|
||||||
|
SSD13x6_WriteCommand( DeviceHandle, 0x8B );
|
||||||
|
|
||||||
|
// COM pins HW config (alternative:EN) - some display might need something difference
|
||||||
|
SSD13x6_WriteCommand( DeviceHandle, 0xDA );
|
||||||
|
SSD13x6_WriteCommand( DeviceHandle, 1 << 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (DeviceHandle->Model == SSD1326) {
|
} else if (DeviceHandle->Model == SSD1326) {
|
||||||
SSDCmd_Set_Display_Start_Line = 0xA1;
|
SSDCmd_Set_Display_Start_Line = 0xA1;
|
||||||
SSDCmd_Set_Display_Offset = 0xA2;
|
SSDCmd_Set_Display_Offset = 0xA2;
|
||||||
@@ -252,9 +266,11 @@ static bool SSD13x6_Init( struct SSD13x6_Device* DeviceHandle, int Width, int He
|
|||||||
SSD13x6_SetDisplayStartLine( DeviceHandle, 0 );
|
SSD13x6_SetDisplayStartLine( DeviceHandle, 0 );
|
||||||
SSD13x6_SetContrast( DeviceHandle, 0x7F );
|
SSD13x6_SetContrast( DeviceHandle, 0x7F );
|
||||||
SSD13x6_DisableDisplayRAM( DeviceHandle );
|
SSD13x6_DisableDisplayRAM( DeviceHandle );
|
||||||
|
SSD13x6_SetVFlip( DeviceHandle, false );
|
||||||
|
SSD13x6_SetHFlip( DeviceHandle, false );
|
||||||
SSD13x6_SetInverted( DeviceHandle, false );
|
SSD13x6_SetInverted( DeviceHandle, false );
|
||||||
SSD13x6_SetDisplayClocks( DeviceHandle, 0, 8 );
|
SSD13x6_SetDisplayClocks( DeviceHandle, 0, 8 );
|
||||||
SSD13x6_SetDisplayAddressMode( DeviceHandle, AddressMode_Vertical );
|
SSD13x6_SetDisplayAddressMode( DeviceHandle, AddressMode_Horizontal );
|
||||||
SSD13x6_SetColumnAddress( DeviceHandle, 0, DeviceHandle->Width - 1 );
|
SSD13x6_SetColumnAddress( DeviceHandle, 0, DeviceHandle->Width - 1 );
|
||||||
SSD13x6_SetPageAddress( DeviceHandle, 0, ( DeviceHandle->Height / 8 ) - 1 );
|
SSD13x6_SetPageAddress( DeviceHandle, 0, ( DeviceHandle->Height / 8 ) - 1 );
|
||||||
SSD13x6_EnableDisplayRAM( DeviceHandle );
|
SSD13x6_EnableDisplayRAM( DeviceHandle );
|
||||||
@@ -269,14 +285,16 @@ bool SSD13x6_Init_I2C( struct SSD13x6_Device* DeviceHandle, int Width, int Heigh
|
|||||||
NullCheck( WriteCommand, return false );
|
NullCheck( WriteCommand, return false );
|
||||||
NullCheck( WriteData, return false );
|
NullCheck( WriteData, return false );
|
||||||
|
|
||||||
memset( DeviceHandle, 0, sizeof( struct SSD13x6_Device ) );
|
|
||||||
|
|
||||||
DeviceHandle->WriteCommand = WriteCommand;
|
DeviceHandle->WriteCommand = WriteCommand;
|
||||||
DeviceHandle->WriteData = WriteData;
|
DeviceHandle->WriteData = WriteData;
|
||||||
DeviceHandle->Reset = Reset;
|
DeviceHandle->Reset = Reset;
|
||||||
DeviceHandle->Address = I2CAddress;
|
DeviceHandle->Address = I2CAddress;
|
||||||
DeviceHandle->RSTPin = ResetPin;
|
DeviceHandle->RSTPin = ResetPin;
|
||||||
|
|
||||||
|
DeviceHandle->FramebufferSize = ( Width * Height ) / 8;
|
||||||
|
DeviceHandle->Framebuffer = calloc( 1, DeviceHandle->FramebufferSize );
|
||||||
|
NullCheck( DeviceHandle->Framebuffer, return false );
|
||||||
|
|
||||||
return SSD13x6_Init( DeviceHandle, Width, Height );
|
return SSD13x6_Init( DeviceHandle, Width, Height );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,8 +303,6 @@ bool SSD13x6_Init_SPI( struct SSD13x6_Device* DeviceHandle, int Width, int Heigh
|
|||||||
NullCheck( WriteCommand, return false );
|
NullCheck( WriteCommand, return false );
|
||||||
NullCheck( WriteData, return false );
|
NullCheck( WriteData, return false );
|
||||||
|
|
||||||
memset( DeviceHandle, 0, sizeof( struct SSD13x6_Device ) );
|
|
||||||
|
|
||||||
DeviceHandle->WriteCommand = WriteCommand;
|
DeviceHandle->WriteCommand = WriteCommand;
|
||||||
DeviceHandle->WriteData = WriteData;
|
DeviceHandle->WriteData = WriteData;
|
||||||
DeviceHandle->Reset = Reset;
|
DeviceHandle->Reset = Reset;
|
||||||
@@ -294,5 +310,9 @@ bool SSD13x6_Init_SPI( struct SSD13x6_Device* DeviceHandle, int Width, int Heigh
|
|||||||
DeviceHandle->RSTPin = ResetPin;
|
DeviceHandle->RSTPin = ResetPin;
|
||||||
DeviceHandle->CSPin = CSPin;
|
DeviceHandle->CSPin = CSPin;
|
||||||
|
|
||||||
|
DeviceHandle->FramebufferSize = ( Width * Height ) / 8;
|
||||||
|
DeviceHandle->Framebuffer = heap_caps_calloc( 1, DeviceHandle->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
|
||||||
|
NullCheck( DeviceHandle->Framebuffer, return false );
|
||||||
|
|
||||||
return SSD13x6_Init( DeviceHandle, Width, Height );
|
return SSD13x6_Init( DeviceHandle, Width, Height );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,10 @@
|
|||||||
|
|
||||||
#define SSD_ALWAYS_INLINE __attribute__( ( always_inline ) )
|
#define SSD_ALWAYS_INLINE __attribute__( ( always_inline ) )
|
||||||
|
|
||||||
|
#define CAPS_COLUMN_RANGE 0x01
|
||||||
|
#define CAPS_PAGE_RANGE 0x02
|
||||||
|
#define CAPS_ADDRESS_VERTICAL 0x04
|
||||||
|
|
||||||
#if ! defined BIT
|
#if ! defined BIT
|
||||||
#define BIT( n ) ( 1 << n )
|
#define BIT( n ) ( 1 << n )
|
||||||
#endif
|
#endif
|
||||||
@@ -52,7 +56,7 @@ struct SSD13x6_Device {
|
|||||||
int Width;
|
int Width;
|
||||||
int Height;
|
int Height;
|
||||||
|
|
||||||
enum { SSD1306, SSD1326 } Model;
|
enum { SSD1306, SSD1326, SH1106 } Model;
|
||||||
uint8_t ReMap;
|
uint8_t ReMap;
|
||||||
uint8_t* Framebuffer;
|
uint8_t* Framebuffer;
|
||||||
int FramebufferSize;
|
int FramebufferSize;
|
||||||
@@ -88,6 +92,7 @@ void SSD13x6_SetPageAddress( struct SSD13x6_Device* DeviceHandle, uint8_t Start,
|
|||||||
bool SSD13x6_HWReset( struct SSD13x6_Device* DeviceHandle );
|
bool SSD13x6_HWReset( struct SSD13x6_Device* DeviceHandle );
|
||||||
bool SSD13x6_Init_I2C( struct SSD13x6_Device* DeviceHandle, int Width, int Height, int I2CAddress, int ResetPin, WriteCommandProc WriteCommand, WriteDataProc WriteData, ResetProc Reset );
|
bool SSD13x6_Init_I2C( struct SSD13x6_Device* DeviceHandle, int Width, int Height, int I2CAddress, int ResetPin, WriteCommandProc WriteCommand, WriteDataProc WriteData, ResetProc Reset );
|
||||||
bool SSD13x6_Init_SPI( struct SSD13x6_Device* DeviceHandle, int Width, int Height, int ResetPin, int CSPin, spi_device_handle_t SPIHandle, WriteCommandProc WriteCommand, WriteDataProc WriteData, ResetProc Reset );
|
bool SSD13x6_Init_SPI( struct SSD13x6_Device* DeviceHandle, int Width, int Height, int ResetPin, int CSPin, spi_device_handle_t SPIHandle, WriteCommandProc WriteCommand, WriteDataProc WriteData, ResetProc Reset );
|
||||||
|
int SSD13x6_GetCaps( struct SSD13x6_Device* DeviceHandle );
|
||||||
|
|
||||||
void SSD13x6_WriteRawData( struct SSD13x6_Device* DeviceHandle, uint8_t* Data, size_t DataLength );
|
void SSD13x6_WriteRawData( struct SSD13x6_Device* DeviceHandle, uint8_t* Data, size_t DataLength );
|
||||||
|
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ const spi_bus_config_t * config_spi_get(spi_host_device_t * spi_host) {
|
|||||||
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);
|
||||||
if ((p = strcasestr(nvs_item, "d/c")) != NULL) spi_system_dc_gpio = atoi(strchr(p, '=') + 1);
|
if ((p = strcasestr(nvs_item, "dc")) != NULL) spi_system_dc_gpio = atoi(strchr(p, '=') + 1);
|
||||||
if ((p = strcasestr(nvs_item, "host")) != NULL) spi_system_host = atoi(strchr(p, '=') + 1);
|
if ((p = strcasestr(nvs_item, "host")) != NULL) spi_system_host = atoi(strchr(p, '=') + 1);
|
||||||
free(nvs_item);
|
free(nvs_item);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,21 +71,23 @@ void services_init(void) {
|
|||||||
i2c_param_config(i2c_system_port, i2c_config);
|
i2c_param_config(i2c_system_port, i2c_config);
|
||||||
i2c_driver_install(i2c_system_port, i2c_config->mode, 0, 0, 0 );
|
i2c_driver_install(i2c_system_port, i2c_config->mode, 0, 0, 0 );
|
||||||
} else {
|
} else {
|
||||||
|
i2c_system_port = -1;
|
||||||
ESP_LOGW(TAG, "no I2C configured");
|
ESP_LOGW(TAG, "no I2C configured");
|
||||||
}
|
}
|
||||||
|
|
||||||
const spi_bus_config_t * spi_config = config_spi_get((spi_host_device_t*) &spi_system_host);
|
const spi_bus_config_t * spi_config = config_spi_get((spi_host_device_t*) &spi_system_host);
|
||||||
ESP_LOGI(TAG,"Configuring SPI data:%d clk:%d host:%u d/c:%d", spi_config->mosi_io_num, spi_config->sclk_io_num, spi_system_host, spi_system_dc_gpio);
|
ESP_LOGI(TAG,"Configuring SPI data:%d clk:%d host:%u dc:%d", spi_config->mosi_io_num, spi_config->sclk_io_num, spi_system_host, spi_system_dc_gpio);
|
||||||
|
|
||||||
if (spi_config->mosi_io_num != -1 && spi_config->sclk_io_num != -1) {
|
if (spi_config->mosi_io_num != -1 && spi_config->sclk_io_num != -1) {
|
||||||
spi_bus_initialize( spi_system_host, spi_config, 1 );
|
spi_bus_initialize( spi_system_host, spi_config, 1 );
|
||||||
if (spi_system_dc_gpio != 1) {
|
if (spi_system_dc_gpio != -1) {
|
||||||
gpio_set_direction( spi_system_dc_gpio, GPIO_MODE_OUTPUT );
|
gpio_set_direction( spi_system_dc_gpio, GPIO_MODE_OUTPUT );
|
||||||
gpio_set_level( spi_system_dc_gpio, 0 );
|
gpio_set_level( spi_system_dc_gpio, 0 );
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGW(TAG, "No D/C GPIO set, SPI display will not work");
|
ESP_LOGW(TAG, "No DC GPIO set, SPI display will not work");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
spi_system_host = -1;
|
||||||
ESP_LOGW(TAG, "no SPI configured");
|
ESP_LOGW(TAG, "no SPI configured");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ static struct scroller_s {
|
|||||||
|
|
||||||
static u8_t ANIC_resp = ANIM_NONE;
|
static u8_t ANIC_resp = ANIM_NONE;
|
||||||
|
|
||||||
#define SCROLL_STACK_SIZE 2048
|
#define SCROLL_STACK_SIZE (3*1024)
|
||||||
#define LINELEN 40
|
#define LINELEN 40
|
||||||
|
|
||||||
static log_level loglevel = lINFO;
|
static log_level loglevel = lINFO;
|
||||||
|
|||||||
Reference in New Issue
Block a user