mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-09 13:07:03 +03:00
more display refactoring, led bug correction
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
#include "gds_private.h"
|
#include "gds_private.h"
|
||||||
|
|
||||||
#define SHADOW_BUFFER
|
#define SHADOW_BUFFER
|
||||||
|
#define USE_IRAM
|
||||||
|
|
||||||
static char TAG[] = "SH1106";
|
static char TAG[] = "SH1106";
|
||||||
|
|
||||||
@@ -83,8 +84,13 @@ static bool Init( struct GDS_Device* Device ) {
|
|||||||
NullCheck( Device->Framebuffer, return false );
|
NullCheck( Device->Framebuffer, return false );
|
||||||
|
|
||||||
#ifdef SHADOW_BUFFER
|
#ifdef SHADOW_BUFFER
|
||||||
if (Device->IF == IF_I2C) Device->Shadowbuffer = malloc( Device->FramebufferSize );
|
#ifdef USE_IRAM
|
||||||
else Device->Shadowbuffer = heap_caps_malloc( Device->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
|
// benchmarks showed little gain to have SPI memory already in IRAL vs letting driver copy
|
||||||
|
if (Device->IF == IF_SPI) Device->Shadowbuffer = heap_caps_malloc( Device->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
|
||||||
|
else
|
||||||
|
#else
|
||||||
|
Device->Shadowbuffer = malloc( Device->FramebufferSize );
|
||||||
|
#endif
|
||||||
NullCheck( Device->Shadowbuffer, return false );
|
NullCheck( Device->Shadowbuffer, return false );
|
||||||
memset(Device->Shadowbuffer, 0xFF, Device->FramebufferSize);
|
memset(Device->Shadowbuffer, 0xFF, Device->FramebufferSize);
|
||||||
#endif
|
#endif
|
||||||
@@ -130,8 +136,9 @@ 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,
|
.SetVFlip = SetVFlip, .SetHFlip = SetHFlip,
|
||||||
.DrawPixelFast = GDS_DrawPixelFast,
|
|
||||||
.Update = Update, .Init = Init,
|
.Update = Update, .Init = Init,
|
||||||
|
//.DrawPixelFast = GDS_DrawPixelFast,
|
||||||
|
//.ClearWindow = ClearWindow,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GDS_Device* SH1106_Detect(char *Driver, struct GDS_Device* Device) {
|
struct GDS_Device* SH1106_Detect(char *Driver, struct GDS_Device* Device) {
|
||||||
@@ -139,6 +146,7 @@ struct GDS_Device* SH1106_Detect(char *Driver, struct GDS_Device* Device) {
|
|||||||
|
|
||||||
if (!Device) Device = calloc(1, sizeof(struct GDS_Device));
|
if (!Device) Device = calloc(1, sizeof(struct GDS_Device));
|
||||||
*Device = SH1106;
|
*Device = SH1106;
|
||||||
|
Device->Depth = 1;
|
||||||
ESP_LOGI(TAG, "SH1106 driver");
|
ESP_LOGI(TAG, "SH1106 driver");
|
||||||
|
|
||||||
return Device;
|
return Device;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "gds_private.h"
|
#include "gds_private.h"
|
||||||
|
|
||||||
#define SHADOW_BUFFER
|
#define SHADOW_BUFFER
|
||||||
|
#define USE_IRAM
|
||||||
|
|
||||||
static char TAG[] = "SSD1306";
|
static char TAG[] = "SSD1306";
|
||||||
|
|
||||||
@@ -81,8 +82,13 @@ static bool Init( struct GDS_Device* Device ) {
|
|||||||
NullCheck( Device->Framebuffer, return false );
|
NullCheck( Device->Framebuffer, return false );
|
||||||
|
|
||||||
#ifdef SHADOW_BUFFER
|
#ifdef SHADOW_BUFFER
|
||||||
if (Device->IF == IF_I2C) Device->Shadowbuffer = malloc( Device->FramebufferSize );
|
#ifdef USE_IRAM
|
||||||
else Device->Shadowbuffer = heap_caps_malloc( Device->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
|
// benchmarks showed little gain to have SPI memory already in IRAL vs letting driver copy
|
||||||
|
if (Device->IF == IF_SPI) Device->Shadowbuffer = heap_caps_malloc( Device->FramebufferSize, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
|
||||||
|
else
|
||||||
|
#else
|
||||||
|
Device->Shadowbuffer = malloc( Device->FramebufferSize );
|
||||||
|
#endif
|
||||||
NullCheck( Device->Shadowbuffer, return false );
|
NullCheck( Device->Shadowbuffer, return false );
|
||||||
memset(Device->Shadowbuffer, 0xFF, Device->FramebufferSize);
|
memset(Device->Shadowbuffer, 0xFF, Device->FramebufferSize);
|
||||||
#endif
|
#endif
|
||||||
@@ -95,7 +101,7 @@ static bool Init( struct GDS_Device* Device ) {
|
|||||||
Device->WriteCommand( Device, 0x8D );
|
Device->WriteCommand( Device, 0x8D );
|
||||||
Device->WriteCommand( Device, 0x14 );
|
Device->WriteCommand( Device, 0x14 );
|
||||||
|
|
||||||
// COM pins HW config (alternative:EN if 64, DIS if 32, remap:DIS) - some display might need something difference
|
// COM pins HW config (alternative:EN if 64, DIS if 32, remap:DIS) - some display might need something different
|
||||||
Device->WriteCommand( Device, 0xDA );
|
Device->WriteCommand( Device, 0xDA );
|
||||||
Device->WriteCommand( Device, ((Device->Height == 64 ? 1 : 0) << 4) | (0 < 5) );
|
Device->WriteCommand( Device, ((Device->Height == 64 ? 1 : 0) << 4) | (0 < 5) );
|
||||||
|
|
||||||
@@ -131,8 +137,9 @@ 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,
|
.SetVFlip = SetVFlip, .SetHFlip = SetHFlip,
|
||||||
.DrawPixelFast = GDS_DrawPixelFast,
|
|
||||||
.Update = Update, .Init = Init,
|
.Update = Update, .Init = Init,
|
||||||
|
//.DrawPixelFast = GDS_DrawPixelFast,
|
||||||
|
//.ClearWindow = ClearWindow,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GDS_Device* SSD1306_Detect(char *Driver, struct GDS_Device* Device) {
|
struct GDS_Device* SSD1306_Detect(char *Driver, struct GDS_Device* Device) {
|
||||||
@@ -140,6 +147,7 @@ struct GDS_Device* SSD1306_Detect(char *Driver, struct GDS_Device* Device) {
|
|||||||
|
|
||||||
if (!Device) Device = calloc(1, sizeof(struct GDS_Device));
|
if (!Device) Device = calloc(1, sizeof(struct GDS_Device));
|
||||||
*Device = SSD1306;
|
*Device = SSD1306;
|
||||||
|
Device->Depth = 1;
|
||||||
ESP_LOGI(TAG, "SSD1306 driver");
|
ESP_LOGI(TAG, "SSD1306 driver");
|
||||||
|
|
||||||
return Device;
|
return Device;
|
||||||
|
|||||||
235
components/display/SSD132x.c
Normal file
235
components/display/SSD132x.c
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2017-2018 Tara Keeling
|
||||||
|
* 2020 Philippe G.
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <esp_heap_caps.h>
|
||||||
|
#include <esp_log.h>
|
||||||
|
|
||||||
|
#include "gds.h"
|
||||||
|
#include "gds_private.h"
|
||||||
|
|
||||||
|
#define SHADOW_BUFFER
|
||||||
|
#define USE_IRAM
|
||||||
|
#define PAGE_BLOCK 1024
|
||||||
|
|
||||||
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||||
|
|
||||||
|
static char TAG[] = "SSD132x";
|
||||||
|
|
||||||
|
enum { SSD1326, SSD1327 };
|
||||||
|
|
||||||
|
struct SSD132x_Private {
|
||||||
|
uint8_t *iRAM;
|
||||||
|
uint8_t ReMap, PageSize;
|
||||||
|
uint8_t Model;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Functions are not deckared to minimize # of lines
|
||||||
|
|
||||||
|
static void SetColumnAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) {
|
||||||
|
Device->WriteCommand( Device, 0x15 );
|
||||||
|
Device->WriteCommand( Device, Start );
|
||||||
|
Device->WriteCommand( Device, End );
|
||||||
|
}
|
||||||
|
static void SetRowAddress( struct GDS_Device* Device, uint8_t Start, uint8_t End ) {
|
||||||
|
// can be by row, not by page (see Update Optimization)
|
||||||
|
Device->WriteCommand( Device, 0x75 );
|
||||||
|
Device->WriteCommand( Device, Start );
|
||||||
|
Device->WriteCommand( Device, End );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Update4( struct GDS_Device* Device ) {
|
||||||
|
struct SSD132x_Private *Private = (struct SSD132x_Private*) Device->Private;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
// always update by full lines
|
||||||
|
SetColumnAddress( Device, 0, Device->Width / 2 - 1);
|
||||||
|
|
||||||
|
#ifdef SHADOW_BUFFER
|
||||||
|
uint16_t *optr = (uint16_t*) Device->Shadowbuffer, *iptr = (uint16_t*) Device->Framebuffer;
|
||||||
|
bool dirty = false;
|
||||||
|
int page;
|
||||||
|
|
||||||
|
for (r = 0, page = 0; r < Device->Height; r++) {
|
||||||
|
// look for change and update shadow (cheap optimization = width always / by 2)
|
||||||
|
for (int c = Device->Width / 2 / 2; --c >= 0;) {
|
||||||
|
if (*optr != *iptr) {
|
||||||
|
dirty = true;
|
||||||
|
*optr = *iptr;
|
||||||
|
}
|
||||||
|
iptr++; optr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// one line done, check for page boundary
|
||||||
|
if (++page == Private->PageSize) {
|
||||||
|
if (dirty) {
|
||||||
|
SetRowAddress( Device, r - page + 1, r );
|
||||||
|
// own use of IRAM has not proven to be much better than letting SPI do its copy
|
||||||
|
if (Private->iRAM) {
|
||||||
|
memcpy(Private->iRAM, Device->Shadowbuffer + (r - page + 1) * Device->Width / 2, Device->Width * page / 2 );
|
||||||
|
Device->WriteData( Device, Private->iRAM, Device->Width * page / 2 );
|
||||||
|
} else {
|
||||||
|
Device->WriteData( Device, Device->Shadowbuffer + (r - page + 1) * Device->Width / 2, Device->Width * page / 2 );
|
||||||
|
}
|
||||||
|
dirty = false;
|
||||||
|
}
|
||||||
|
page = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
for (r = 0; r < Device->Height; r += Private->PageSize) {
|
||||||
|
SetRowAddress( Device, r, r + Private->PageSize - 1 );
|
||||||
|
Device->WriteData( Device, Device->Framebuffer + r * Device->Width / 2, Device->Width * Private->PageSize / 2 );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Update1( struct GDS_Device* Device ) {
|
||||||
|
#ifdef SHADOW_BUFFER
|
||||||
|
// not sure the compiler does not have to redo all calculation in for loops, so local it is
|
||||||
|
int width = Device->Width, rows = Device->Height / 8;
|
||||||
|
uint8_t *optr = Device->Shadowbuffer, *iptr = Device->Framebuffer;
|
||||||
|
|
||||||
|
// by row, find first and last columns that have been updated
|
||||||
|
for (int r = 0; r < rows; r++) {
|
||||||
|
uint8_t first = 0, last;
|
||||||
|
for (int c = 0; c < width; c++) {
|
||||||
|
if (*iptr != *optr) {
|
||||||
|
if (!first) first = c + 1;
|
||||||
|
last = c ;
|
||||||
|
}
|
||||||
|
*optr++ = *iptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now update the display by "byte rows"
|
||||||
|
if (first--) {
|
||||||
|
SetColumnAddress( Device, first, last );
|
||||||
|
SetRowAddress( Device, r, r);
|
||||||
|
Device->WriteData( Device, Device->Shadowbuffer + r*width + first, last - first + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// automatic counter and end Page/Column
|
||||||
|
SetColumnAddress( Device, 0, Device->Width - 1);
|
||||||
|
SetPageAddress( Device, 0, Device->Height / 8 - 1);
|
||||||
|
Device->WriteData( Device, Device->Framebuffer, Device->FramebufferSize );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetHFlip( struct GDS_Device* Device, bool On ) {
|
||||||
|
struct SSD132x_Private *Private = (struct SSD132x_Private*) Device->Private;
|
||||||
|
if (Private->Model == SSD1326) Private->ReMap = On ? (Private->ReMap | ((1 << 0) | (1 << 2))) : (Private->ReMap & ~((1 << 0) | (1 << 2)));
|
||||||
|
else Private->ReMap = On ? (Private->ReMap | ((1 << 0) | (1 << 1))) : (Private->ReMap & ~((1 << 0) | (1 << 1)));
|
||||||
|
Device->WriteCommand( Device, 0xA0 );
|
||||||
|
Device->WriteCommand( Device, Private->ReMap );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetVFlip( struct GDS_Device *Device, bool On ) {
|
||||||
|
struct SSD132x_Private *Private = (struct SSD132x_Private*) 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 DisplayOff( struct GDS_Device* Device ) { Device->WriteCommand( Device, 0xAE ); }
|
||||||
|
|
||||||
|
static void SetContrast( struct GDS_Device* Device, uint8_t Contrast ) {
|
||||||
|
Device->WriteCommand( Device, 0x81 );
|
||||||
|
Device->WriteCommand( Device, Contrast );
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Init( struct GDS_Device* Device ) {
|
||||||
|
struct SSD132x_Private *Private = (struct SSD132x_Private*) Device->Private;
|
||||||
|
|
||||||
|
// find a page size that is not too small is an integer of height
|
||||||
|
Private->PageSize = min(8, PAGE_BLOCK / (Device->Width / 2));
|
||||||
|
Private->PageSize = Device->Height / (Device->Height / Private->PageSize) ;
|
||||||
|
|
||||||
|
#ifdef USE_IRAM
|
||||||
|
// let SPI driver allocate memory, it has not proven to be more efficient
|
||||||
|
if (Device->IF == IF_SPI) Private->iRAM = heap_caps_malloc( Private->PageSize * Device->Width / 2, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA );
|
||||||
|
#endif
|
||||||
|
Device->FramebufferSize = ( Device->Width * Device->Height ) / 2;
|
||||||
|
Device->Framebuffer = calloc( 1, Device->FramebufferSize );
|
||||||
|
NullCheck( Device->Framebuffer, return false );
|
||||||
|
|
||||||
|
#ifdef SHADOW_BUFFER
|
||||||
|
Device->Shadowbuffer = malloc( Device->FramebufferSize );
|
||||||
|
NullCheck( Device->Shadowbuffer, return false );
|
||||||
|
memset(Device->Shadowbuffer, 0xFF, Device->FramebufferSize);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "SSD1326/7 with bit depth %u, page %u, iRAM %p", Device->Depth, Private->PageSize, Private->iRAM);
|
||||||
|
|
||||||
|
// need to be off and disable display RAM
|
||||||
|
Device->DisplayOff( Device );
|
||||||
|
Device->WriteCommand( Device, 0xA5 );
|
||||||
|
|
||||||
|
// need COM split (6)
|
||||||
|
Private->ReMap = 1 << 6;
|
||||||
|
// MUX Ratio
|
||||||
|
Device->WriteCommand( Device, 0xA8 );
|
||||||
|
Device->WriteCommand( Device, Device->Height - 1);
|
||||||
|
// Display Offset
|
||||||
|
Device->WriteCommand( Device, 0xA2 );
|
||||||
|
Device->WriteCommand( Device, 0 );
|
||||||
|
// Display Start Line
|
||||||
|
Device->WriteCommand( Device, 0xA1 );
|
||||||
|
Device->WriteCommand( Device, 0x00 );
|
||||||
|
Device->SetContrast( Device, 0x7F );
|
||||||
|
// set flip modes
|
||||||
|
Device->SetVFlip( Device, false );
|
||||||
|
Device->SetHFlip( Device, false );
|
||||||
|
// no Display Inversion
|
||||||
|
Device->WriteCommand( Device, 0xA6 );
|
||||||
|
// set Clocks
|
||||||
|
Device->WriteCommand( Device, 0xB3 );
|
||||||
|
Device->WriteCommand( Device, ( 0x08 << 4 ) | 0x00 );
|
||||||
|
// set Adressing Mode Horizontal
|
||||||
|
Private->ReMap |= (0 << 2);
|
||||||
|
// set monotchrome mode if required
|
||||||
|
if (Device->Depth == 1) Private->ReMap |= (1 << 4);
|
||||||
|
// write ReMap byte
|
||||||
|
Device->WriteCommand( Device, 0xA0 );
|
||||||
|
Device->WriteCommand( Device, Private->ReMap );
|
||||||
|
|
||||||
|
// gone with the wind
|
||||||
|
Device->WriteCommand( Device, 0xA4 );
|
||||||
|
Device->DisplayOn( Device );
|
||||||
|
Device->Update( Device );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct GDS_Device SSD132x = {
|
||||||
|
.DisplayOn = DisplayOn, .DisplayOff = DisplayOff, .SetContrast = SetContrast,
|
||||||
|
.SetVFlip = SetVFlip, .SetHFlip = SetHFlip,
|
||||||
|
.Update = Update4, .Init = Init,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GDS_Device* SSD132x_Detect(char *Driver, struct GDS_Device* Device) {
|
||||||
|
uint8_t Model;
|
||||||
|
|
||||||
|
if (!strcasestr(Driver, "SSD1326")) Model = SSD1326;
|
||||||
|
else if (!strcasestr(Driver, "SSD1327")) Model = SSD1327;
|
||||||
|
else return NULL;
|
||||||
|
|
||||||
|
if (!Device) Device = calloc(1, sizeof(struct GDS_Device));
|
||||||
|
*Device = SSD132x;
|
||||||
|
((struct SSD132x_Private*) Device->Private)->Model = Model;
|
||||||
|
sscanf(Driver, "%*[^:]:%c", &Device->Depth);
|
||||||
|
if (Model == SSD1326 && Device->Depth == 1) Device->Update = Update1;
|
||||||
|
else Device->Depth = 4;
|
||||||
|
|
||||||
|
return Device;
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ static struct GDS_Device Display;
|
|||||||
|
|
||||||
static char TAG[] = "gds";
|
static char TAG[] = "gds";
|
||||||
|
|
||||||
struct GDS_Device* GDS_AutoDetect( char *Driver, GDS_DetectFunc DetectFunc[] ) {
|
struct GDS_Device* GDS_AutoDetect( char *Driver, GDS_DetectFunc* DetectFunc[] ) {
|
||||||
for (int i = 0; DetectFunc[i]; i++) {
|
for (int i = 0; DetectFunc[i]; i++) {
|
||||||
if (DetectFunc[i](Driver, &Display)) {
|
if (DetectFunc[i](Driver, &Display)) {
|
||||||
ESP_LOGD(TAG, "Detected driver %p", &Display);
|
ESP_LOGD(TAG, "Detected driver %p", &Display);
|
||||||
@@ -54,19 +54,25 @@ void GDS_ClearExt(struct GDS_Device* Device, bool full, ...) {
|
|||||||
|
|
||||||
void GDS_Clear( struct GDS_Device* Device, int Color ) {
|
void GDS_Clear( struct GDS_Device* Device, int Color ) {
|
||||||
memset( Device->Framebuffer, Color, Device->FramebufferSize );
|
memset( Device->Framebuffer, Color, Device->FramebufferSize );
|
||||||
|
Device->Dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GDS_ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color ) {
|
void GDS_ClearWindow( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color ) {
|
||||||
|
// driver can provide onw optimized clear window
|
||||||
|
if (Device->ClearWindow) {
|
||||||
|
Device->ClearWindow( Device, x1, y1, x2, y2, Color );
|
||||||
// cheap optimization on boundaries
|
// cheap optimization on boundaries
|
||||||
if (x1 == 0 && x2 == Device->Width - 1 && y1 % 8 == 0 && (y2 + 1) % 8 == 0) {
|
if (x1 == 0 && x2 == Device->Width - 1 && y1 % 8 == 0 && (y2 + 1) % 8 == 0) {
|
||||||
memset( Device->Framebuffer + (y1 / 8) * Device->Width, 0, (y2 - y1 + 1) / 8 * Device->Width );
|
memset( Device->Framebuffer + (y1 / 8) * Device->Width, 0, (y2 - y1 + 1) / 8 * Device->Width );
|
||||||
} else {
|
} else {
|
||||||
for (int y = y1; y <= y2; y++) {
|
for (int y = y1; y <= y2; y++) {
|
||||||
for (int x = x1; x <= x2; x++) {
|
for (int x = x1; x <= x2; x++) {
|
||||||
Device->DrawPixelFast( Device, x, y, Color);
|
GDS_DrawPixelFast( Device, x, y, Color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Device->Dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GDS_Update( struct GDS_Device* Device ) {
|
void GDS_Update( struct GDS_Device* Device ) {
|
||||||
|
|||||||
@@ -4,16 +4,20 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#define GDS_COLOR_BLACK 0
|
enum { GDS_COLOR_L0 = 0, GDS_COLOR_L1, GDS_COLOR_L2, GDS_COLOR_L3, GDS_COLOR_L4, GDS_COLOR_L5, GDS_COLOR_L6, GDS_COLOR_L7,
|
||||||
#define GDS_COLOR_WHITE 1
|
GDS_COLOR_L8, GDS_COLOR_L9, GDS_COLOR_L10, GDS_COLOR_L11, GDS_COLOR_L12, GDS_COLOR_L13, GDS_COLOR_L14, GDS_COLOR_L15,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GDS_COLOR_BLACK GDS_COLOR_L0
|
||||||
|
#define GDS_COLOR_WHITE GDS_COLOR_L15
|
||||||
#define GDS_COLOR_XOR 2
|
#define GDS_COLOR_XOR 2
|
||||||
|
|
||||||
struct GDS_Device;
|
struct GDS_Device;
|
||||||
struct GDS_FontDef;
|
struct GDS_FontDef;
|
||||||
|
|
||||||
typedef struct GDS_Device* (*GDS_DetectFunc)(char *Driver, struct GDS_Device *Device);
|
typedef struct GDS_Device* GDS_DetectFunc(char *Driver, struct GDS_Device *Device);
|
||||||
|
|
||||||
struct GDS_Device* GDS_AutoDetect( char *Driver, GDS_DetectFunc[] );
|
struct GDS_Device* GDS_AutoDetect( char *Driver, GDS_DetectFunc* DetectFunc[] );
|
||||||
|
|
||||||
void GDS_SetContrast( struct GDS_Device* Device, uint8_t Contrast );
|
void GDS_SetContrast( struct GDS_Device* Device, uint8_t Contrast );
|
||||||
void GDS_DisplayOn( struct GDS_Device* Device );
|
void GDS_DisplayOn( struct GDS_Device* Device );
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <esp_attr.h>
|
#include <esp_attr.h>
|
||||||
|
|
||||||
#include "gds.h"
|
|
||||||
#include "gds_private.h"
|
#include "gds_private.h"
|
||||||
|
#include "gds.h"
|
||||||
#include "gds_draw.h"
|
#include "gds_draw.h"
|
||||||
|
|
||||||
static const unsigned char BitReverseTable256[] =
|
static const unsigned char BitReverseTable256[] =
|
||||||
@@ -45,49 +45,11 @@ __attribute__( ( always_inline ) ) static inline void SwapInt( int* a, int* b )
|
|||||||
*a = Temp;
|
*a = Temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void IRAM_ATTR GDS_DrawPixelFast( struct GDS_Device* Device, int X, int Y, int Color ) {
|
// un-comment if need to be instanciated for external callers
|
||||||
uint32_t YBit = ( Y & 0x07 );
|
extern inline void IRAM_ATTR GDS_DrawPixelFast( struct GDS_Device* Device, int X, int Y, int Color );
|
||||||
uint8_t* FBOffset = NULL;
|
extern inline void IRAM_ATTR GDS_DrawPixel( struct GDS_Device* Device, int X, int Y, int Color );
|
||||||
|
|
||||||
/*
|
void GDS_DrawHLine( struct GDS_Device* Device, int x, int y, int Width, int Color ) {
|
||||||
* We only need to modify the Y coordinate since the pitch
|
|
||||||
* of the screen is the same as the width.
|
|
||||||
* Dividing Y by 8 gives us which row the pixel is in but not
|
|
||||||
* the bit position.
|
|
||||||
*/
|
|
||||||
Y>>= 3;
|
|
||||||
|
|
||||||
FBOffset = Device->Framebuffer + ( ( Y * Device->Width ) + X );
|
|
||||||
|
|
||||||
if ( Color == GDS_COLOR_XOR ) {
|
|
||||||
*FBOffset ^= BIT( YBit );
|
|
||||||
} else {
|
|
||||||
*FBOffset = ( Color == GDS_COLOR_WHITE ) ? *FBOffset | BIT( YBit ) : *FBOffset & ~BIT( YBit );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void IRAM_ATTR GDS_DrawPixel4Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
|
|
||||||
uint32_t YBit = ( Y & 0x07 );
|
|
||||||
uint8_t* FBOffset = NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We only need to modify the Y coordinate since the pitch
|
|
||||||
* of the screen is the same as the width.
|
|
||||||
* Dividing Y by 8 gives us which row the pixel is in but not
|
|
||||||
* the bit position.
|
|
||||||
*/
|
|
||||||
Y>>= 3;
|
|
||||||
|
|
||||||
FBOffset = Device->Framebuffer + ( ( Y * Device->Width ) + X );
|
|
||||||
|
|
||||||
if ( Color == GDS_COLOR_XOR ) {
|
|
||||||
*FBOffset ^= BIT( YBit );
|
|
||||||
} else {
|
|
||||||
*FBOffset = ( Color == GDS_COLOR_WHITE ) ? *FBOffset | BIT( YBit ) : *FBOffset & ~BIT( YBit );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void IRAM_ATTR GDS_DrawHLine( struct GDS_Device* Device, int x, int y, int Width, int Color ) {
|
|
||||||
int XEnd = x + Width;
|
int XEnd = x + Width;
|
||||||
|
|
||||||
Device->Dirty = true;
|
Device->Dirty = true;
|
||||||
@@ -98,30 +60,24 @@ void IRAM_ATTR GDS_DrawHLine( struct GDS_Device* Device, int x, int y, int Width
|
|||||||
if (y < 0) y = 0;
|
if (y < 0) y = 0;
|
||||||
else if (y >= Device->Height) x = Device->Height - 1;
|
else if (y >= Device->Height) x = Device->Height - 1;
|
||||||
|
|
||||||
for ( ; x < XEnd; x++ ) {
|
for ( ; x < XEnd; x++ ) GDS_DrawPixelFast( Device, x, y, Color );
|
||||||
if ( IsPixelVisible( Device, x, y ) == true ) {
|
|
||||||
Device->DrawPixelFast( Device, x, y, Color );
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR GDS_DrawVLine( struct GDS_Device* Device, int x, int y, int Height, int Color ) {
|
void GDS_DrawVLine( struct GDS_Device* Device, int x, int y, int Height, int Color ) {
|
||||||
int YEnd = y + Height;
|
int YEnd = y + Height;
|
||||||
|
|
||||||
Device->Dirty = true;
|
Device->Dirty = true;
|
||||||
|
|
||||||
for ( ; y < YEnd; y++ ) {
|
if (x < 0) x = 0;
|
||||||
if ( IsPixelVisible( Device, x, y ) == true ) {
|
if (x >= Device->Width) x = Device->Width - 1;
|
||||||
GDS_DrawPixel( Device, x, y, Color );
|
|
||||||
} else {
|
if (y < 0) y = 0;
|
||||||
break;
|
else if (YEnd >= Device->Height) YEnd = Device->Height - 1;
|
||||||
}
|
|
||||||
}
|
for ( ; y < YEnd; y++ ) GDS_DrawPixel( Device, x, y, Color );
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void IRAM_ATTR DrawWideLine( struct GDS_Device* Device, int x0, int y0, int x1, int y1, int Color ) {
|
static inline void DrawWideLine( struct GDS_Device* Device, int x0, int y0, int x1, int y1, int Color ) {
|
||||||
int dx = ( x1 - x0 );
|
int dx = ( x1 - x0 );
|
||||||
int dy = ( y1 - y0 );
|
int dy = ( y1 - y0 );
|
||||||
int Error = 0;
|
int Error = 0;
|
||||||
@@ -138,7 +94,7 @@ static inline void IRAM_ATTR DrawWideLine( struct GDS_Device* Device, int x0, in
|
|||||||
|
|
||||||
for ( ; x < x1; x++ ) {
|
for ( ; x < x1; x++ ) {
|
||||||
if ( IsPixelVisible( Device, x, y ) == true ) {
|
if ( IsPixelVisible( Device, x, y ) == true ) {
|
||||||
Device->DrawPixelFast( Device, x, y, Color );
|
GDS_DrawPixelFast( Device, x, y, Color );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( Error > 0 ) {
|
if ( Error > 0 ) {
|
||||||
@@ -150,7 +106,7 @@ static inline void IRAM_ATTR DrawWideLine( struct GDS_Device* Device, int x0, in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void IRAM_ATTR DrawTallLine( struct GDS_Device* Device, int x0, int y0, int x1, int y1, int Color ) {
|
static inline void DrawTallLine( struct GDS_Device* Device, int x0, int y0, int x1, int y1, int Color ) {
|
||||||
int dx = ( x1 - x0 );
|
int dx = ( x1 - x0 );
|
||||||
int dy = ( y1 - y0 );
|
int dy = ( y1 - y0 );
|
||||||
int Error = 0;
|
int Error = 0;
|
||||||
@@ -167,7 +123,7 @@ static inline void IRAM_ATTR DrawTallLine( struct GDS_Device* Device, int x0, in
|
|||||||
|
|
||||||
for ( ; y < y1; y++ ) {
|
for ( ; y < y1; y++ ) {
|
||||||
if ( IsPixelVisible( Device, x, y ) == true ) {
|
if ( IsPixelVisible( Device, x, y ) == true ) {
|
||||||
Device->DrawPixelFast( Device, x, y, Color );
|
GDS_DrawPixelFast( Device, x, y, Color );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( Error > 0 ) {
|
if ( Error > 0 ) {
|
||||||
@@ -179,7 +135,7 @@ static inline void IRAM_ATTR DrawTallLine( struct GDS_Device* Device, int x0, in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR GDS_DrawLine( struct GDS_Device* Device, int x0, int y0, int x1, int y1, int Color ) {
|
void GDS_DrawLine( struct GDS_Device* Device, int x0, int y0, int x1, int y1, int Color ) {
|
||||||
if ( x0 == x1 ) {
|
if ( x0 == x1 ) {
|
||||||
GDS_DrawVLine( Device, x0, y0, ( y1 - y0 ), Color );
|
GDS_DrawVLine( Device, x0, y0, ( y1 - y0 ), Color );
|
||||||
} else if ( y0 == y1 ) {
|
} else if ( y0 == y1 ) {
|
||||||
@@ -206,7 +162,7 @@ void IRAM_ATTR GDS_DrawLine( struct GDS_Device* Device, int x0, int y0, int x1,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR GDS_DrawBox( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color, bool Fill ) {
|
void GDS_DrawBox( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color, bool Fill ) {
|
||||||
int Width = ( x2 - x1 );
|
int Width = ( x2 - x1 );
|
||||||
int Height = ( y2 - y1 );
|
int Height = ( y2 - y1 );
|
||||||
|
|
||||||
@@ -236,29 +192,140 @@ void IRAM_ATTR GDS_DrawBox( struct GDS_Device* Device, int x1, int y1, int x2, i
|
|||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
* Process graphic display data from column-oriented data (MSbit first)
|
* Process graphic display data from column-oriented data (MSbit first)
|
||||||
*/
|
*/
|
||||||
void GDS_DrawBitmapCBR(struct GDS_Device* Device, uint8_t *Data, int Width, int Height) {
|
void GDS_DrawBitmapCBR(struct GDS_Device* Device, uint8_t *Data, int Width, int Height, int Color ) {
|
||||||
if (!Height) Height = Device->Height;
|
if (!Height) Height = Device->Height;
|
||||||
if (!Width) Width = Device->Width;
|
if (!Width) Width = Device->Width;
|
||||||
|
Height >>= 3;
|
||||||
|
|
||||||
// need to do row/col swap and bit-reverse
|
if (Device->Depth == 1) {
|
||||||
int Rows = Height / 8;
|
// need to do row/col swap and bit-reverse
|
||||||
for (int r = 0; r < Rows; r++) {
|
for (int r = 0; r < Height; r++) {
|
||||||
uint8_t *optr = Device->Framebuffer + r*Device->Width, *iptr = Data + r;
|
uint8_t *optr = Device->Framebuffer + r*Device->Width, *iptr = Data + r;
|
||||||
for (int c = Width; --c >= 0;) {
|
for (int c = Width; --c >= 0;) {
|
||||||
*optr++ = BitReverseTable256[*iptr];;
|
*optr++ = BitReverseTable256[*iptr];
|
||||||
iptr += Rows;
|
iptr += Height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else if (Device->Depth == 4) {
|
||||||
|
uint8_t *optr = Device->Framebuffer;
|
||||||
|
int LineLen = Device->Width >> 1;
|
||||||
|
for (int i = Width * Height, r = 0, c = 0; --i >= 0;) {
|
||||||
|
uint8_t Byte = BitReverseTable256[*Data++];
|
||||||
|
// we need to linearize code to let compiler better optimize
|
||||||
|
if (c & 0x01) {
|
||||||
|
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
|
||||||
|
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
|
||||||
|
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
|
||||||
|
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
|
||||||
|
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
|
||||||
|
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
|
||||||
|
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
|
||||||
|
*optr = (*optr & 0x0f) | (((Byte & 0x01)*Color)<<4); optr += LineLen; Byte >>= 1;
|
||||||
|
} else {
|
||||||
|
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
|
||||||
|
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
|
||||||
|
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
|
||||||
|
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
|
||||||
|
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
|
||||||
|
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
|
||||||
|
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
|
||||||
|
*optr = (*optr & 0xf0) | (((Byte & 0x01)*Color)); optr += LineLen; Byte >>= 1;
|
||||||
|
}
|
||||||
|
// end of a column, move to next one
|
||||||
|
if (++r == Height) { c++; r = 0; optr = Device->Framebuffer + (c >> 1); }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// don't know bitdepth, use brute-force solution
|
||||||
|
for (int i = Width * Height, r = 0, c = 0; --i >= 0;) {
|
||||||
|
uint8_t Byte = *Data++;
|
||||||
|
GDS_DrawPixelFast( Device, c, (r << 3) + 7, (Byte & 0x01) * Color ); Byte >>= 1;
|
||||||
|
GDS_DrawPixelFast( Device, c, (r << 3) + 6, (Byte & 0x01) * Color ); Byte >>= 1;
|
||||||
|
GDS_DrawPixelFast( Device, c, (r << 3) + 5, (Byte & 0x01) * Color ); Byte >>= 1;
|
||||||
|
GDS_DrawPixelFast( Device, c, (r << 3) + 4, (Byte & 0x01) * Color ); Byte >>= 1;
|
||||||
|
GDS_DrawPixelFast( Device, c, (r << 3) + 3, (Byte & 0x01) * Color ); Byte >>= 1;
|
||||||
|
GDS_DrawPixelFast( Device, c, (r << 3) + 2, (Byte & 0x01) * Color ); Byte >>= 1;
|
||||||
|
GDS_DrawPixelFast( Device, c, (r << 3) + 1, (Byte & 0x01) * Color ); Byte >>= 1;
|
||||||
|
GDS_DrawPixelFast( Device, c, (r << 3) + 0, (Byte & 0x01) * Color );
|
||||||
|
if (++r == Height) { c++; r = 0; }
|
||||||
|
}
|
||||||
|
/* for better understanding, here is the mundane version
|
||||||
|
for (int x = 0; x < Width; x++) {
|
||||||
|
for (int y = 0; y < Height; y++) {
|
||||||
|
uint8_t Byte = *Data++;
|
||||||
|
GDS_DrawPixel4Fast( Device, x, y * 8 + 0, ((Byte >> 7) & 0x01) * Color );
|
||||||
|
GDS_DrawPixel4Fast( Device, x, y * 8 + 1, ((Byte >> 6) & 0x01) * Color );
|
||||||
|
GDS_DrawPixel4Fast( Device, x, y * 8 + 2, ((Byte >> 5) & 0x01) * Color );
|
||||||
|
GDS_DrawPixel4Fast( Device, x, y * 8 + 3, ((Byte >> 4) & 0x01) * Color );
|
||||||
|
GDS_DrawPixel4Fast( Device, x, y * 8 + 4, ((Byte >> 3) & 0x01) * Color );
|
||||||
|
GDS_DrawPixel4Fast( Device, x, y * 8 + 5, ((Byte >> 2) & 0x01) * Color );
|
||||||
|
GDS_DrawPixel4Fast( Device, x, y * 8 + 6, ((Byte >> 1) & 0x01) * Color );
|
||||||
|
GDS_DrawPixel4Fast( Device, x, y * 8 + 7, ((Byte >> 0) & 0x01) * Color );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
Device->Dirty = true;
|
Device->Dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* Simply draw a RGB565 image
|
||||||
|
* monoschrome (0.2125 * color.r) + (0.7154 * color.g) + (0.0721 * color.b)
|
||||||
|
* grayscale (0.3 * R) + (0.59 * G) + (0.11 * B) )
|
||||||
|
*/
|
||||||
|
void GDS_DrawRGB16( struct GDS_Device* Device, int x, int y, int Width, int Height, int RGB_Mode, uint16_t **Image ) {
|
||||||
|
if (Device->DrawRGB16) {
|
||||||
|
Device->DrawRGB16( Device, x, y, Width, Height, RGB_Mode, Image );
|
||||||
|
} else if (Device->Depth == 4) {
|
||||||
|
for (int c = 0; c < Width; c++) {
|
||||||
|
for (int r = 0; r < Height; r++) {
|
||||||
|
int pixel = Image[r][c];
|
||||||
|
switch(RGB_Mode) {
|
||||||
|
case GDS_RGB565:
|
||||||
|
pixel = (((pixel & 0x1f) * 11 + (((pixel >> 5) & 0x3f) * 59) / 2 + (pixel >> 11) * 30) / 100) >> 1;
|
||||||
|
break;
|
||||||
|
case GDS_RGB555:
|
||||||
|
pixel = (((pixel & 0x1f) * 11 + ((pixel >> 5) & 0x1f) * 59 + (pixel >> 10) * 30) / 100) >> 1;
|
||||||
|
break;
|
||||||
|
case GDS_RGB444:
|
||||||
|
pixel = ((pixel & 0x0f) * 11 + ((pixel >> 4) & 0x0f) * 59 + (pixel >> 8) * 30) / 100;
|
||||||
|
break;
|
||||||
|
case GDS_RGB8_GRAY:
|
||||||
|
pixel = Image[r][c] >> 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
GDS_DrawPixel( Device, c + x, r + y, pixel );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (Device->Depth == 1) {
|
||||||
|
for (int c = 0; c < Width; c++) {
|
||||||
|
for (int r = 0; r < Height; r++) {
|
||||||
|
int pixel = Image[r][c];
|
||||||
|
switch(RGB_Mode) {
|
||||||
|
case GDS_RGB565:
|
||||||
|
pixel = (((pixel & 0x1f) * 21 + (((pixel >> 5) & 0x3f) * 71) / 2+ (pixel >> 11) * 7) / 100) >> 4;
|
||||||
|
break;
|
||||||
|
case GDS_RGB555:
|
||||||
|
pixel = (((pixel & 0x1f) * 21 + ((pixel >> 5) & 0x1f) * 71 + (pixel >> 10) * 7) / 100) >> 4;
|
||||||
|
break;
|
||||||
|
case GDS_RGB444:
|
||||||
|
pixel = (((pixel & 0x0f) * 21 + ((pixel >> 4) & 0x0f) * 71 + (pixel >> 8) * 7) / 100) >> 3;
|
||||||
|
break;
|
||||||
|
case GDS_RGB8_GRAY:
|
||||||
|
pixel = Image[r][c] >> 7;
|
||||||
|
}
|
||||||
|
GDS_DrawPixel( Device, c + x, r + y, pixel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
* Process graphic display data MSBit first
|
* Process graphic display data MSBit first
|
||||||
* WARNING: this has not been tested yet
|
* WARNING: this has not been tested yet
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
static void draw_raw(int x1, int y1, int x2, int y2, bool by_column, bool MSb, u8_t *data) {
|
static void DrawBitmap(int x1, int y1, int x2, int y2, bool by_column, bool MSb, u8_t *data) {
|
||||||
// default end point to display size
|
// default end point to display size
|
||||||
if (x2 == -1) x2 = Display.Width - 1;
|
if (x2 == -1) x2 = Display.Width - 1;
|
||||||
if (y2 == -1) y2 = Display.Height - 1;
|
if (y2 == -1) y2 = Display.Height - 1;
|
||||||
|
|||||||
@@ -11,13 +11,20 @@ extern "C" {
|
|||||||
|
|
||||||
struct GDS_Device;
|
struct GDS_Device;
|
||||||
|
|
||||||
void IRAM_ATTR GDS_DrawHLine( struct GDS_Device* Device, int x, int y, int Width, int Color );
|
enum { GDS_RGB565, GDS_RGB555, GDS_RGB444, GDS_RGB8_GRAY };
|
||||||
void IRAM_ATTR GDS_DrawVLine( struct GDS_Device* Device, int x, int y, int Height, int Color );
|
|
||||||
void IRAM_ATTR GDS_DrawLine( struct GDS_Device* Device, int x0, int y0, int x1, int y1, int Color );
|
#ifndef _GDS_PRIVATE_H_
|
||||||
void IRAM_ATTR GDS_DrawBox( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color, bool Fill );
|
void IRAM_ATTR GDS_DrawPixelFast( struct GDS_Device* Device, int X, int Y, int Color );
|
||||||
|
void IRAM_ATTR GDS_DrawPixel( struct GDS_Device* Device, int X, int Y, int Color );
|
||||||
|
#endif
|
||||||
|
void GDS_DrawHLine( struct GDS_Device* Device, int x, int y, int Width, int Color );
|
||||||
|
void GDS_DrawVLine( struct GDS_Device* Device, int x, int y, int Height, int Color );
|
||||||
|
void GDS_DrawLine( struct GDS_Device* Device, int x0, int y0, int x1, int y1, int Color );
|
||||||
|
void GDS_DrawBox( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color, bool Fill );
|
||||||
|
void GDS_DrawRGB16( struct GDS_Device* Device, int x, int y, int Width, int Height, int RGB_Mode, uint16_t **Image );
|
||||||
|
|
||||||
// draw a bitmap with source 1-bit depth organized in column and col0 = bit7 of byte 0
|
// draw a bitmap with source 1-bit depth organized in column and col0 = bit7 of byte 0
|
||||||
void IRAM_ATTR GDS_DrawBitmapCBR( struct GDS_Device* Device, uint8_t *Data, int Width, int Height);
|
void GDS_DrawBitmapCBR( struct GDS_Device* Device, uint8_t *Data, int Width, int Height, int Color);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "gds.h"
|
|
||||||
#include "gds_draw.h"
|
|
||||||
#include "gds_font.h"
|
|
||||||
#include "gds_private.h"
|
#include "gds_private.h"
|
||||||
|
#include "gds.h"
|
||||||
|
#include "gds_font.h"
|
||||||
|
#include "gds_draw.h"
|
||||||
#include "gds_err.h"
|
#include "gds_err.h"
|
||||||
|
|
||||||
static int RoundUpFontHeight( const struct GDS_FontDef* Font ) {
|
static int RoundUpFontHeight( const struct GDS_FontDef* Font ) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#ifndef _GDS_PRIVATE_H_
|
||||||
|
#define _GDS_PRIVATE_H_
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
@@ -10,8 +11,6 @@
|
|||||||
#define GDS_CLIPDEBUG_WARNING 1
|
#define GDS_CLIPDEBUG_WARNING 1
|
||||||
#define GDS_CLIPDEBUG_ERROR 2
|
#define GDS_CLIPDEBUG_ERROR 2
|
||||||
|
|
||||||
#define SHADOW_BUFFER
|
|
||||||
|
|
||||||
#if CONFIG_GDS_CLIPDEBUG == GDS_CLIPDEBUG_NONE
|
#if CONFIG_GDS_CLIPDEBUG == GDS_CLIPDEBUG_NONE
|
||||||
/*
|
/*
|
||||||
* Clip silently with no console output.
|
* Clip silently with no console output.
|
||||||
@@ -94,25 +93,29 @@ struct GDS_Device {
|
|||||||
bool FontForceMonospace;
|
bool FontForceMonospace;
|
||||||
|
|
||||||
// various driver-specific method
|
// various driver-specific method
|
||||||
|
// must provide
|
||||||
bool (*Init)( struct GDS_Device* Device);
|
bool (*Init)( struct GDS_Device* 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 (*Update)( struct GDS_Device* Device );
|
|
||||||
void (*DrawPixelFast)( struct GDS_Device* Device, int X, int Y, int Color );
|
|
||||||
void (*SetHFlip)( struct GDS_Device* Device, bool On );
|
void (*SetHFlip)( struct GDS_Device* Device, bool On );
|
||||||
void (*SetVFlip)( struct GDS_Device* Device, bool On );
|
void (*SetVFlip)( struct GDS_Device* Device, bool On );
|
||||||
|
void (*Update)( struct GDS_Device* Device );
|
||||||
|
// may provide for optimization
|
||||||
|
void (*DrawPixelFast)( struct GDS_Device* Device, int X, int Y, int Color );
|
||||||
|
void (*DrawRGB16)( struct GDS_Device* Device, int x, int y, int Width, int Height, int RGB_Mode, uint16_t **Image );
|
||||||
|
void (*ClearWindow)( struct GDS_Device* Device, int x1, int y1, int x2, int y2, int Color );
|
||||||
|
|
||||||
// interface-specific methods
|
// interface-specific methods
|
||||||
WriteCommandProc WriteCommand;
|
WriteCommandProc WriteCommand;
|
||||||
WriteDataProc WriteData;
|
WriteDataProc WriteData;
|
||||||
|
|
||||||
|
// 16 bytes for whatever the driver wants (should be aligned as it's 32 bits)
|
||||||
|
uint32_t Private[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
bool GDS_Reset( struct GDS_Device* Device );
|
bool GDS_Reset( struct GDS_Device* Device );
|
||||||
|
|
||||||
void IRAM_ATTR GDS_DrawPixelFast( struct GDS_Device* Device, int X, int Y, int Color );
|
|
||||||
void IRAM_ATTR GDS_DrawPixel4Fast( struct GDS_Device* Device, int X, int Y, int Color );
|
|
||||||
|
|
||||||
inline bool IsPixelVisible( struct GDS_Device* Device, int x, int y ) {
|
inline bool IsPixelVisible( struct GDS_Device* Device, int x, int y ) {
|
||||||
bool Result = (
|
bool Result = (
|
||||||
( x >= 0 ) &&
|
( x >= 0 ) &&
|
||||||
@@ -130,17 +133,44 @@ inline bool IsPixelVisible( struct GDS_Device* Device, int x, int y ) {
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void IRAM_ATTR GDS_DrawPixel1Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
|
||||||
|
uint32_t YBit = ( Y & 0x07 );
|
||||||
|
uint8_t* FBOffset = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We only need to modify the Y coordinate since the pitch
|
||||||
|
* of the screen is the same as the width.
|
||||||
|
* Dividing Y by 8 gives us which row the pixel is in but not
|
||||||
|
* the bit position.
|
||||||
|
*/
|
||||||
|
Y>>= 3;
|
||||||
|
|
||||||
|
FBOffset = Device->Framebuffer + ( ( Y * Device->Width ) + X );
|
||||||
|
|
||||||
|
if ( Color == GDS_COLOR_XOR ) {
|
||||||
|
*FBOffset ^= BIT( YBit );
|
||||||
|
} else {
|
||||||
|
*FBOffset = ( Color == GDS_COLOR_WHITE ) ? *FBOffset | BIT( YBit ) : *FBOffset & ~BIT( YBit );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void IRAM_ATTR GDS_DrawPixel4Fast( struct GDS_Device* Device, int X, int Y, int Color ) {
|
||||||
|
uint8_t* FBOffset;
|
||||||
|
|
||||||
|
FBOffset = Device->Framebuffer + ( (Y * Device->Width >> 1) + (X >> 1));
|
||||||
|
*FBOffset = X & 0x01 ? (*FBOffset & 0x0f) | (Color << 4) : ((*FBOffset & 0xf0) | Color);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void IRAM_ATTR GDS_DrawPixelFast( struct GDS_Device* Device, int X, int Y, int Color ) {
|
||||||
|
if (Device->DrawPixelFast) Device->DrawPixelFast( Device, X, Y, Color );
|
||||||
|
else if (Device->Depth == 4) GDS_DrawPixel4Fast( Device, X, Y, Color);
|
||||||
|
else if (Device->Depth == 1) GDS_DrawPixel1Fast( Device, X, Y, Color);
|
||||||
|
}
|
||||||
|
|
||||||
inline void IRAM_ATTR GDS_DrawPixel( struct GDS_Device* Device, int x, int y, int Color ) {
|
inline void IRAM_ATTR GDS_DrawPixel( struct GDS_Device* Device, int x, int y, int Color ) {
|
||||||
if ( IsPixelVisible( Device, x, y ) == true ) {
|
if ( IsPixelVisible( Device, x, y ) == true ) {
|
||||||
Device->DrawPixelFast( Device, x, y, Color );
|
GDS_DrawPixelFast( Device, x, y, Color );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void IRAM_ATTR GDS_DrawPixel4( struct GDS_Device* Device, int x, int y, int Color ) {
|
#endif
|
||||||
if ( IsPixelVisible( Device, x, y ) == true ) {
|
|
||||||
Device->DrawPixelFast( Device, x, y, Color );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -22,10 +22,11 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
#include "gds_private.h"
|
||||||
#include "gds.h"
|
#include "gds.h"
|
||||||
#include "gds_draw.h"
|
#include "gds_draw.h"
|
||||||
#include "gds_text.h"
|
#include "gds_text.h"
|
||||||
#include "gds_private.h"
|
|
||||||
|
|
||||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||||
|
|
||||||
@@ -109,7 +110,7 @@ bool GDS_TextLine(struct GDS_Device* Device, int N, int Pos, int Attr, char *Tex
|
|||||||
int Y_min = max(0, Device->Lines[N].Y), Y_max = max(0, Device->Lines[N].Y + Device->Lines[N].Font->Height);
|
int Y_min = max(0, Device->Lines[N].Y), Y_max = max(0, Device->Lines[N].Y + Device->Lines[N].Font->Height);
|
||||||
for (int c = (Attr & GDS_TEXT_CLEAR_EOL) ? X : 0; c < Device->Width; c++)
|
for (int c = (Attr & GDS_TEXT_CLEAR_EOL) ? X : 0; c < Device->Width; c++)
|
||||||
for (int y = Y_min; y < Y_max; y++)
|
for (int y = Y_min; y < Y_max; y++)
|
||||||
Device->DrawPixelFast( Device, c, y, GDS_COLOR_BLACK );
|
GDS_DrawPixelFast( Device, c, y, GDS_COLOR_BLACK );
|
||||||
}
|
}
|
||||||
|
|
||||||
GDS_FontDrawString( Device, X, Device->Lines[N].Y, Text, GDS_COLOR_WHITE );
|
GDS_FontDrawString( Device, X, Device->Lines[N].Y, Text, GDS_COLOR_WHITE );
|
||||||
|
|||||||
@@ -59,9 +59,8 @@ static EXT_RAM_ATTR struct {
|
|||||||
static void displayer_task(void *args);
|
static void displayer_task(void *args);
|
||||||
|
|
||||||
struct GDS_Device *display;
|
struct GDS_Device *display;
|
||||||
struct GDS_Device* SSD1306_Detect(char *Driver, struct GDS_Device* Device);
|
extern GDS_DetectFunc SSD1306_Detect, SSD132x_Detect, SH1106_Detect;
|
||||||
struct GDS_Device* SH1106_Detect(char *Driver, struct GDS_Device* Device);
|
GDS_DetectFunc *drivers[] = { SH1106_Detect, SSD1306_Detect, SSD132x_Detect, NULL };
|
||||||
GDS_DetectFunc drivers[] = { SH1106_Detect, SSD1306_Detect, NULL };
|
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ const spi_bus_config_t * config_spi_get(spi_host_device_t * spi_host) {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void parse_set_GPIO(void (*cb)(int gpio, char *value)) {
|
void parse_set_GPIO(void (*cb)(int gpio, char *value)) {
|
||||||
char *nvs_item, *p, type[4];
|
char *nvs_item, *p, type[16];
|
||||||
int gpio;
|
int gpio;
|
||||||
|
|
||||||
if ((nvs_item = config_alloc_get(NVS_TYPE_STR, "set_GPIO")) == NULL) return;
|
if ((nvs_item = config_alloc_get(NVS_TYPE_STR, "set_GPIO")) == NULL) return;
|
||||||
@@ -97,7 +97,7 @@ void parse_set_GPIO(void (*cb)(int gpio, char *value)) {
|
|||||||
p = nvs_item;
|
p = nvs_item;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (sscanf(p, "%d=%3[^,]", &gpio, type) > 0) cb(gpio, type);
|
if (sscanf(p, "%d=%15[^,]", &gpio, type) > 0) cb(gpio, type);
|
||||||
p = strchr(p, ',');
|
p = strchr(p, ',');
|
||||||
} while (p++);
|
} while (p++);
|
||||||
|
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ void set_led_gpio(int gpio, char *value) {
|
|||||||
green.gpio = gpio;
|
green.gpio = gpio;
|
||||||
if ((p = strchr(value, ':')) != NULL) green.active = atoi(p + 1);
|
if ((p = strchr(value, ':')) != NULL) green.active = atoi(p + 1);
|
||||||
} else if (strcasestr(value, "red")) {
|
} else if (strcasestr(value, "red")) {
|
||||||
red.active = gpio;
|
red.gpio = gpio;
|
||||||
if ((p = strchr(value, ':')) != NULL) red.active = atoi(p + 1);
|
if ((p = strchr(value, ':')) != NULL) red.active = atoi(p + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ static int i2c_port;
|
|||||||
* init
|
* init
|
||||||
*/
|
*/
|
||||||
static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) {
|
static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) {
|
||||||
esp_err_t res;
|
esp_err_t res = ESP_OK;
|
||||||
|
|
||||||
i2c_port = i2c_port_num;
|
i2c_port = i2c_port_num;
|
||||||
|
|
||||||
@@ -144,8 +144,8 @@ static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) {
|
|||||||
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,
|
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
|
.data_out_num = CONFIG_I2S_DO_IO, .data_in_num = CONFIG_I2S_DI_IO
|
||||||
};
|
};
|
||||||
i2s_driver_install(i2s_num, i2s_config, 0, NULL);
|
res |= i2s_driver_install(i2s_num, i2s_config, 0, NULL);
|
||||||
i2s_set_pin(i2s_num, &i2s_pin_config);
|
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);
|
||||||
@@ -156,9 +156,9 @@ 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:%u, ws:%u, do:%u", i2s_pin_config.bck_io_num, i2s_pin_config.ws_io_num, i2s_pin_config.data_out_num);
|
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);
|
||||||
|
|
||||||
return true;
|
return (res == ESP_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************************
|
/****************************************************************************************
|
||||||
|
|||||||
@@ -233,8 +233,8 @@ bool sb_display_init(void) {
|
|||||||
displayer.mutex = xSemaphoreCreateMutex();
|
displayer.mutex = xSemaphoreCreateMutex();
|
||||||
displayer.task = xTaskCreateStatic( (TaskFunction_t) displayer_task, "displayer_thread", SCROLL_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, &xTaskBuffer);
|
displayer.task = xTaskCreateStatic( (TaskFunction_t) displayer_task, "displayer_thread", SCROLL_STACK_SIZE, NULL, ESP_TASK_PRIO_MIN + 1, xStack, &xTaskBuffer);
|
||||||
|
|
||||||
// size scroller
|
// size scroller (width + current screen)
|
||||||
scroller.scroll.max = (displayer.width * displayer.height / 8) * 10;
|
scroller.scroll.max = (displayer.width * displayer.height / 8) * (10 + 1);
|
||||||
scroller.scroll.frame = malloc(scroller.scroll.max);
|
scroller.scroll.frame = malloc(scroller.scroll.max);
|
||||||
scroller.back.frame = malloc(displayer.width * displayer.height / 8);
|
scroller.back.frame = malloc(displayer.width * displayer.height / 8);
|
||||||
scroller.frame = malloc(displayer.width * displayer.height / 8);
|
scroller.frame = malloc(displayer.width * displayer.height / 8);
|
||||||
@@ -501,7 +501,7 @@ static void grfe_handler( u8_t *data, int len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// draw new frame
|
// draw new frame
|
||||||
GDS_DrawBitmapCBR(display, data + sizeof(struct grfe_packet), displayer.width, displayer.height);
|
GDS_DrawBitmapCBR(display, data + sizeof(struct grfe_packet), displayer.width, displayer.height, GDS_COLOR_WHITE);
|
||||||
GDS_Update(display);
|
GDS_Update(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -580,7 +580,8 @@ static void grfs_handler(u8_t *data, int len) {
|
|||||||
scroller.scroll.size = offset + size;
|
scroller.scroll.size = offset + size;
|
||||||
LOG_INFO("scroller current size %u", scroller.scroll.size);
|
LOG_INFO("scroller current size %u", scroller.scroll.size);
|
||||||
} else {
|
} else {
|
||||||
LOG_INFO("scroller too larger %u/%u", scroller.scroll.size + size, scroller.scroll.max);
|
LOG_INFO("scroller too larger %u/%u/%u", scroller.scroll.size + size, scroller.scroll.max, scroller.scroll.width);
|
||||||
|
scroller.scroll.width = scroller.scroll.size / (displayer.height / 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -598,13 +599,13 @@ static void grfg_handler(u8_t *data, int len) {
|
|||||||
scroller.width = htons(pkt->width);
|
scroller.width = htons(pkt->width);
|
||||||
memcpy(scroller.back.frame, data + sizeof(struct grfg_packet), len - sizeof(struct grfg_packet));
|
memcpy(scroller.back.frame, data + sizeof(struct grfg_packet), len - sizeof(struct grfg_packet));
|
||||||
|
|
||||||
// update display asynchronously (frames are oganized by columns)
|
// update display asynchronously (frames are organized by columns)
|
||||||
memcpy(scroller.frame, scroller.back.frame, scroller.back.width * displayer.height / 8);
|
memcpy(scroller.frame, scroller.back.frame, scroller.back.width * displayer.height / 8);
|
||||||
for (int i = 0; i < scroller.width * displayer.height / 8; i++) scroller.frame[i] |= scroller.scroll.frame[scroller.scrolled * displayer.height / 8 + i];
|
for (int i = 0; i < scroller.width * displayer.height / 8; i++) scroller.frame[i] |= scroller.scroll.frame[scroller.scrolled * displayer.height / 8 + i];
|
||||||
|
|
||||||
// can only write if we really own display
|
// can only write if we really own display
|
||||||
if (displayer.owned) {
|
if (displayer.owned) {
|
||||||
GDS_DrawBitmapCBR(display, scroller.frame, scroller.back.width, displayer.height);
|
GDS_DrawBitmapCBR(display, scroller.frame, scroller.back.width, displayer.height, GDS_COLOR_WHITE);
|
||||||
GDS_Update(display);
|
GDS_Update(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -855,7 +856,7 @@ static void displayer_task(void *args) {
|
|||||||
memcpy(scroller.frame, scroller.back.frame, scroller.back.width * displayer.height / 8);
|
memcpy(scroller.frame, scroller.back.frame, scroller.back.width * displayer.height / 8);
|
||||||
for (int i = 0; i < scroller.width * displayer.height / 8; i++) scroller.frame[i] |= scroller.scroll.frame[scroller.scrolled * displayer.height / 8 + i];
|
for (int i = 0; i < scroller.width * displayer.height / 8; i++) scroller.frame[i] |= scroller.scroll.frame[scroller.scrolled * displayer.height / 8 + i];
|
||||||
scroller.scrolled += scroller.by;
|
scroller.scrolled += scroller.by;
|
||||||
if (displayer.owned) GDS_DrawBitmapCBR(display, scroller.frame, scroller.width, displayer.height);
|
if (displayer.owned) GDS_DrawBitmapCBR(display, scroller.frame, scroller.width, displayer.height, GDS_COLOR_WHITE);
|
||||||
|
|
||||||
// short sleep & don't need background update
|
// short sleep & don't need background update
|
||||||
scroller.wake = scroller.speed;
|
scroller.wake = scroller.speed;
|
||||||
|
|||||||
@@ -252,9 +252,9 @@ void output_init_i2s(log_level level, char *device, unsigned output_buf_size, ch
|
|||||||
// finally let DAC driver initialize I2C and I2S
|
// finally let DAC driver initialize I2C and I2S
|
||||||
if (dac_tas57xx.init(I2C_PORT, CONFIG_I2S_NUM, &i2s_config)) adac = &dac_tas57xx;
|
if (dac_tas57xx.init(I2C_PORT, CONFIG_I2S_NUM, &i2s_config)) adac = &dac_tas57xx;
|
||||||
else if (dac_a1s.init(I2C_PORT, CONFIG_I2S_NUM, &i2s_config)) adac = &dac_a1s;
|
else if (dac_a1s.init(I2C_PORT, CONFIG_I2S_NUM, &i2s_config)) adac = &dac_a1s;
|
||||||
else {
|
else if (!dac_external.init(I2C_PORT, CONFIG_I2S_NUM, &i2s_config)) {
|
||||||
dac_external.init(I2C_PORT, CONFIG_I2S_NUM, &i2s_config);
|
LOG_WARN("DAC not configured and SPDIF not enabled, I2S will not continue");
|
||||||
adac = &dac_external;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,9 @@
|
|||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "adac.h"
|
#include "adac.h"
|
||||||
|
|
||||||
|
// this is the only hard-wired thing
|
||||||
#define VOLUME_GPIO 14
|
#define VOLUME_GPIO 14
|
||||||
|
|
||||||
#define TAS575x 0x98
|
#define TAS575x 0x98
|
||||||
#define TAS578x 0x90
|
#define TAS578x 0x90
|
||||||
|
|
||||||
@@ -104,11 +106,6 @@ static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) {
|
|||||||
|
|
||||||
LOG_INFO("TAS57xx DAC using I2C sda:%u, scl:%u", i2c_config.sda_io_num, i2c_config.scl_io_num);
|
LOG_INFO("TAS57xx DAC using I2C sda:%u, scl:%u", i2c_config.sda_io_num, i2c_config.scl_io_num);
|
||||||
|
|
||||||
// init volume & mute
|
|
||||||
gpio_pad_select_gpio(VOLUME_GPIO);
|
|
||||||
gpio_set_direction(VOLUME_GPIO, GPIO_MODE_OUTPUT);
|
|
||||||
gpio_set_level(VOLUME_GPIO, 0);
|
|
||||||
|
|
||||||
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++) {
|
||||||
@@ -121,22 +118,26 @@ static bool init(int i2c_port_num, int i2s_num, i2s_config_t *i2s_config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
i2c_master_stop(i2c_cmd);
|
i2c_master_stop(i2c_cmd);
|
||||||
esp_err_t ret = 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
|
// 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,
|
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,
|
.data_out_num = CONFIG_I2S_DO_IO, .data_in_num = CONFIG_I2S_DI_IO,
|
||||||
};
|
};
|
||||||
i2s_driver_install(i2s_num, i2s_config, 0, NULL);
|
res |= i2s_driver_install(i2s_num, i2s_config, 0, NULL);
|
||||||
i2s_set_pin(i2s_num, &i2s_pin_config);
|
res |= i2s_set_pin(i2s_num, &i2s_pin_config);
|
||||||
LOG_INFO("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);
|
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 (ret != ESP_OK) {
|
if (res == ESP_OK) {
|
||||||
LOG_ERROR("could not intialize TAS57xx %d", ret);
|
// init volume & mute
|
||||||
return false;
|
gpio_pad_select_gpio(VOLUME_GPIO);
|
||||||
} else {
|
gpio_set_direction(VOLUME_GPIO, GPIO_MODE_OUTPUT);
|
||||||
|
gpio_set_level(VOLUME_GPIO, 0);
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
LOG_ERROR("could not intialize TAS57xx %d", res);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user