Verify that SPI works with SH1106

This commit is contained in:
philippe44
2020-02-10 20:44:44 -08:00
parent 55e0efdb4a
commit 26c9a9e897
9 changed files with 151 additions and 102 deletions

View File

@@ -70,6 +70,7 @@ bool SSD13x6_I2CMasterAttachDisplayDefault( struct SSD13x6_Device* DeviceHandle,
ESP_ERROR_CHECK_NONFATAL( gpio_set_level( RSTPin, 1 ), return false );
}
memset( DeviceHandle, 0, sizeof( struct SSD13x6_Device ) );
DeviceHandle->Model = Model;
return SSD13x6_Init_I2C( DeviceHandle,

View File

@@ -56,9 +56,10 @@ bool SSD13x6_SPIMasterAttachDisplayDefault( struct SSD13x6_Device* DeviceHandle,
}
ESP_ERROR_CHECK_NONFATAL( spi_bus_add_device( SPIHost, &SPIDeviceConfig, &SPIDeviceHandle ), return false );
memset( DeviceHandle, 0, sizeof( struct SSD13x6_Device ) );
DeviceHandle->Model = Model;
return SSD13x6_Init_SPI( DeviceHandle,
Width,
Height,
@@ -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 ) {
spi_transaction_t SPITransaction;
spi_transaction_t SPITransaction = { 0 };
NullCheck( SPIHandle, return false );
NullCheck( Data, return false );
if ( DataLength > 0 ) {
memset( &SPITransaction, 0, sizeof( spi_transaction_t ) );
SPITransaction.length = DataLength * 8;
SPITransaction.tx_buffer = Data;
gpio_set_level( DCPin, WriteMode );
ESP_ERROR_CHECK_NONFATAL( spi_device_transmit( SPIHandle, &SPITransaction ), return false );
gpio_set_level( DCPin, WriteMode );
SPITransaction.length = DataLength * 8;
SPITransaction.tx_buffer = Data;
// only do polling as we don't have contention on SPI (otherwise DMA for transfers > 16 bytes)
ESP_ERROR_CHECK_NONFATAL( spi_device_polling_transmit(SPIHandle, &SPITransaction), return false );
}
return true;

View File

@@ -15,15 +15,6 @@
#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
static uint8_t SSDCmd_Set_Display_Start_Line;
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 );
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 ) {
NullCheck( DeviceHandle->WriteCommand, return false );
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 ) {
switch (DeviceHandle->Model) {
case SH1106:
// does not exist on SH1106
break;
case SSD1306:
SSD13x6_WriteCommand( DeviceHandle, 0x20 );
SSD13x6_WriteCommand( DeviceHandle, AddressMode );
@@ -112,9 +111,19 @@ void SSD13x6_SetDisplayAddressMode( struct SSD13x6_Device* DeviceHandle, SSD13x6
}
void SSD13x6_Update( struct SSD13x6_Device* DeviceHandle ) {
SSD13x6_SetColumnAddress( DeviceHandle, 0, DeviceHandle->Width - 1);
SSD13x6_SetPageAddress( DeviceHandle, 0, DeviceHandle->Height / 8 - 1);
SSD13x6_WriteData( DeviceHandle, DeviceHandle->Framebuffer, DeviceHandle->FramebufferSize );
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_SetPageAddress( DeviceHandle, 0, DeviceHandle->Height / 8 - 1);
SSD13x6_WriteData( DeviceHandle, DeviceHandle->Framebuffer, DeviceHandle->FramebufferSize );
}
}
void SSD13x6_WriteRawData( struct SSD13x6_Device* DeviceHandle, uint8_t* Data, size_t DataLength ) {
@@ -125,6 +134,7 @@ void SSD13x6_WriteRawData( struct SSD13x6_Device* DeviceHandle, uint8_t* Data, s
void SSD13x6_SetHFlip( struct SSD13x6_Device* DeviceHandle, bool On ) {
switch (DeviceHandle->Model) {
case SH1106:
case SSD1306:
SSD13x6_WriteCommand( DeviceHandle, On ? 0xA1 : 0xA0 );
break;
@@ -137,6 +147,7 @@ void SSD13x6_SetHFlip( struct SSD13x6_Device* DeviceHandle, bool On ) {
void SSD13x6_SetVFlip( struct SSD13x6_Device* DeviceHandle, bool On ) {
switch (DeviceHandle->Model) {
case SH1106:
case SSD1306:
SSD13x6_WriteCommand( DeviceHandle, On ? 0xC8 : 0xC0 );
break;
@@ -150,10 +161,18 @@ void SSD13x6_SetVFlip( struct SSD13x6_Device* DeviceHandle, bool On ) {
void SSD13x6_SetColumnAddress( struct SSD13x6_Device* DeviceHandle, uint8_t Start, uint8_t End ) {
CheckBounds( Start > SSD13x6_Max_Col, return );
CheckBounds( End > SSD13x6_Max_Col, return );
SSD13x6_WriteCommand( DeviceHandle, SSDCmd_Set_Column_Address );
SSD13x6_WriteCommand( DeviceHandle, Start );
SSD13x6_WriteCommand( DeviceHandle, End );
// 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, Start );
SSD13x6_WriteCommand( DeviceHandle, End );
}
}
void SSD13x6_SetPageAddress( struct SSD13x6_Device* DeviceHandle, uint8_t Start, uint8_t End ) {
@@ -162,15 +181,20 @@ void SSD13x6_SetPageAddress( struct SSD13x6_Device* DeviceHandle, uint8_t Start,
CheckBounds( Start > SSD13x6_Max_Row, return );
CheckBounds( End > SSD13x6_Max_Row, return );
// in case of SSD1326, this is sub-optimal as it can address by line, not by page
if (DeviceHandle->Model != SSD1306) {
Start *= 8;
End = (End + 1) * 8 - 1;
}
// 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
if (DeviceHandle->Model != SSD1306) {
Start *= 8;
End = (End + 1) * 8 - 1;
}
SSD13x6_WriteCommand( DeviceHandle, SSDCmd_Set_Page_Address );
SSD13x6_WriteCommand( DeviceHandle, Start );
SSD13x6_WriteCommand( DeviceHandle, End );
SSD13x6_WriteCommand( DeviceHandle, SSDCmd_Set_Page_Address );
SSD13x6_WriteCommand( DeviceHandle, Start );
SSD13x6_WriteCommand( DeviceHandle, End );
}
}
bool SSD13x6_HWReset( struct SSD13x6_Device* DeviceHandle ) {
@@ -186,50 +210,40 @@ bool SSD13x6_HWReset( struct SSD13x6_Device* DeviceHandle ) {
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 ) {
DeviceHandle->Width = Width;
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 );
if (DeviceHandle->Model == SSD1306) {
SSD13x6_DisplayOff( DeviceHandle );
if (DeviceHandle->Model == SSD1306 || DeviceHandle->Model == SH1106) {
SSDCmd_Set_Display_Start_Line = 0x40;
SSDCmd_Set_Display_Offset = 0xD3;
SSDCmd_Set_Column_Address = 0x21,
SSDCmd_Set_Display_CLK = 0xD5;
SSDCmd_Set_Page_Address = 0x22;
SSD13x6_Max_Col = 127;
// charge pump regulator, do direct init
SSD13x6_WriteCommand( DeviceHandle, 0x8D );
SSD13x6_WriteCommand( DeviceHandle, 0x14 ); /* MAGIC NUMBER */
if ( Height == 64 ) {
SetCOMPinConfiguration( DeviceHandle, COM_Disable_LR_Remap, COM_Pins_Alternative, COM_ScanDir_LR );
if (DeviceHandle->Model == SSD1306) {
// charge pump regulator, do direct init
SSD13x6_WriteCommand( DeviceHandle, 0x8D );
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) );
} 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) {
SSDCmd_Set_Display_Start_Line = 0xA1;
SSDCmd_Set_Display_Offset = 0xA2;
@@ -245,21 +259,23 @@ static bool SSD13x6_Init( struct SSD13x6_Device* DeviceHandle, int Width, int He
SSD13x6_SetHFlip( DeviceHandle, false );
SSD13x6_SetVFlip( DeviceHandle, false );
}
}
SSD13x6_SetMuxRatio( DeviceHandle, Height - 1 );
SSD13x6_SetDisplayOffset( DeviceHandle, 0x00 );
SSD13x6_SetDisplayStartLine( DeviceHandle, 0 );
SSD13x6_SetDisplayStartLine( DeviceHandle, 0 );
SSD13x6_SetContrast( DeviceHandle, 0x7F );
SSD13x6_DisableDisplayRAM( DeviceHandle );
SSD13x6_SetVFlip( DeviceHandle, false );
SSD13x6_SetHFlip( DeviceHandle, false );
SSD13x6_SetInverted( DeviceHandle, false );
SSD13x6_SetDisplayClocks( DeviceHandle, 0, 8 );
SSD13x6_SetDisplayAddressMode( DeviceHandle, AddressMode_Vertical );
SSD13x6_SetDisplayAddressMode( DeviceHandle, AddressMode_Horizontal );
SSD13x6_SetColumnAddress( DeviceHandle, 0, DeviceHandle->Width - 1 );
SSD13x6_SetPageAddress( DeviceHandle, 0, ( DeviceHandle->Height / 8 ) - 1 );
SSD13x6_EnableDisplayRAM( DeviceHandle );
SSD13x6_DisplayOn( DeviceHandle );
SSD13x6_Update( DeviceHandle );
SSD13x6_Update( DeviceHandle );
return true;
}
@@ -269,13 +285,15 @@ bool SSD13x6_Init_I2C( struct SSD13x6_Device* DeviceHandle, int Width, int Heigh
NullCheck( WriteCommand, return false );
NullCheck( WriteData, return false );
memset( DeviceHandle, 0, sizeof( struct SSD13x6_Device ) );
DeviceHandle->WriteCommand = WriteCommand;
DeviceHandle->WriteData = WriteData;
DeviceHandle->Reset = Reset;
DeviceHandle->Address = I2CAddress;
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 );
}
@@ -285,8 +303,6 @@ bool SSD13x6_Init_SPI( struct SSD13x6_Device* DeviceHandle, int Width, int Heigh
NullCheck( WriteCommand, return false );
NullCheck( WriteData, return false );
memset( DeviceHandle, 0, sizeof( struct SSD13x6_Device ) );
DeviceHandle->WriteCommand = WriteCommand;
DeviceHandle->WriteData = WriteData;
DeviceHandle->Reset = Reset;
@@ -294,5 +310,9 @@ bool SSD13x6_Init_SPI( struct SSD13x6_Device* DeviceHandle, int Width, int Heigh
DeviceHandle->RSTPin = ResetPin;
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 );
}

View File

@@ -12,6 +12,10 @@
#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
#define BIT( n ) ( 1 << n )
#endif
@@ -52,7 +56,7 @@ struct SSD13x6_Device {
int Width;
int Height;
enum { SSD1306, SSD1326 } Model;
enum { SSD1306, SSD1326, SH1106 } Model;
uint8_t ReMap;
uint8_t* Framebuffer;
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_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 );
int SSD13x6_GetCaps( struct SSD13x6_Device* DeviceHandle );
void SSD13x6_WriteRawData( struct SSD13x6_Device* DeviceHandle, uint8_t* Data, size_t DataLength );