mirror of
https://github.com/dwhinham/mt32-pi.git
synced 2026-10-27 06:21:59 +00:00
Add ability to invert display on SSD1306
This commit is contained in:
1 parent
f5d31ff369
commit
e79897eb9a
8 files changed
+85
-53
No files matched your search
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Ability to invert the display orientation for SSD1306 (new configuration file option).
|
||||
|
||||
## [0.6.2] - 2020-10-18
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -38,6 +38,7 @@ CFG(type, TLCDType, m_LCDType, TLCDType::None )
|
||||
CFG(width, int, m_nLCDWidth, 20 )
|
||||
CFG(height, int, m_nLCDHeight, 2 )
|
||||
CFG(i2c_lcd_address, int, m_nLCDI2CLCDAddress, 0x3c, true )
|
||||
CFG(rotation, TLCDRotation, m_nLCDRotation, TLCDRotation::Normal )
|
||||
END_SECTION
|
||||
|
||||
#undef BEGIN_SECTION
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#ifndef _config_h
|
||||
#define _config_h
|
||||
|
||||
#include "lcd/ssd1306.h"
|
||||
#include "mt32synth.h"
|
||||
#include "rommanager.h"
|
||||
#include "utility.h"
|
||||
@@ -40,6 +41,8 @@ public:
|
||||
using TMT32EmuMIDIChannels = CMT32SynthBase::TMIDIChannels;
|
||||
using TMT32EmuROMSet = CROMManager::TROMSet;
|
||||
|
||||
using TLCDRotation = CSSD1306::TLCDRotation;
|
||||
|
||||
#define ENUM_LCDTYPE(ENUM) \
|
||||
ENUM(None, none) \
|
||||
ENUM(HD44780FourBit, hd44780_4bit) \
|
||||
@@ -71,6 +74,7 @@ private:
|
||||
static bool ParseOption(const char* pString, TMT32EmuMIDIChannels* pOut);
|
||||
static bool ParseOption(const char* pString, TMT32EmuROMSet* pOut);
|
||||
static bool ParseOption(const char* pString, TLCDType* pOut);
|
||||
static bool ParseOption(const char* pString, TLCDRotation* pOut);
|
||||
|
||||
static CConfig* s_pThis;
|
||||
};
|
||||
|
||||
@@ -26,11 +26,18 @@
|
||||
|
||||
#include "lcd/mt32lcd.h"
|
||||
#include "mt32synth.h"
|
||||
#include "utility.h"
|
||||
|
||||
class CSSD1306 : public CMT32LCD
|
||||
{
|
||||
public:
|
||||
CSSD1306(CI2CMaster* pI2CMaster, u8 nAddress = 0x3c, u8 nHeight = 32);
|
||||
#define ENUM_LCDROTATION(ENUM) \
|
||||
ENUM(Normal, normal) \
|
||||
ENUM(Inverted, inverted)
|
||||
|
||||
CONFIG_ENUM(TLCDRotation, ENUM_LCDROTATION);
|
||||
|
||||
CSSD1306(CI2CMaster* pI2CMaster, u8 nAddress = 0x3c, u8 nHeight = 32, TLCDRotation Rotation = TLCDRotation::Normal);
|
||||
|
||||
// CCharacterLCD
|
||||
virtual bool Initialize() override;
|
||||
@@ -51,11 +58,10 @@ private:
|
||||
CI2CMaster* m_pI2CMaster;
|
||||
u8 m_nAddress;
|
||||
u8 m_nHeight;
|
||||
TLCDRotation m_Rotation;
|
||||
|
||||
// +1 to store the 0x40 command at the beginning
|
||||
u8 m_Framebuffer[128 * 64 / 8 + 1];
|
||||
|
||||
static const u8 InitSequence[];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -177,3 +177,14 @@ height = 32
|
||||
#
|
||||
# Values: 00-80 (3c*)
|
||||
i2c_lcd_address = 3c
|
||||
|
||||
# Rotate the display output (graphical LCDs only).
|
||||
#
|
||||
# Some graphical displays support rotation. Use this option if you need to turn
|
||||
# the display around.
|
||||
#
|
||||
# Values: normal*, inverted
|
||||
#
|
||||
# normal: No rotation
|
||||
# inverted: The display output is upside down
|
||||
rotation = normal
|
||||
@@ -60,6 +60,7 @@ CONFIG_ENUM_STRINGS(TMT32EmuResamplerQuality, ENUM_RESAMPLERQUALITY);
|
||||
CONFIG_ENUM_STRINGS(TMT32EmuMIDIChannels, ENUM_MIDICHANNELS);
|
||||
CONFIG_ENUM_STRINGS(TMT32EmuROMSet, ENUM_ROMSET);
|
||||
CONFIG_ENUM_STRINGS(TLCDType, ENUM_LCDTYPE);
|
||||
CONFIG_ENUM_STRINGS(TLCDRotation, ENUM_LCDROTATION);
|
||||
|
||||
CConfig* CConfig::s_pThis = nullptr;
|
||||
|
||||
@@ -141,3 +142,4 @@ CONFIG_ENUM_PARSER(TMT32EmuResamplerQuality);
|
||||
CONFIG_ENUM_PARSER(TMT32EmuMIDIChannels);
|
||||
CONFIG_ENUM_PARSER(TMT32EmuROMSet);
|
||||
CONFIG_ENUM_PARSER(TLCDType);
|
||||
CONFIG_ENUM_PARSER(TLCDRotation);
|
||||
+1
-1
@@ -131,7 +131,7 @@ bool CKernel::Initialize(void)
|
||||
else if (m_Config.m_LCDType == CConfig::TLCDType::HD44780I2C)
|
||||
m_pLCD = new CHD44780I2C(&m_I2CMaster, m_Config.m_nLCDI2CLCDAddress, m_Config.m_nLCDWidth, m_Config.m_nLCDHeight);
|
||||
else if (m_Config.m_LCDType == CConfig::TLCDType::SSD1306I2C)
|
||||
m_pLCD = new CSSD1306(&m_I2CMaster, m_Config.m_nLCDI2CLCDAddress, m_Config.m_nLCDHeight);
|
||||
m_pLCD = new CSSD1306(&m_I2CMaster, m_Config.m_nLCDI2CLCDAddress, m_Config.m_nLCDHeight, m_Config.m_nLCDRotation);
|
||||
|
||||
if (m_pLCD)
|
||||
{
|
||||
|
||||
+53
-49
@@ -86,52 +86,12 @@ namespace
|
||||
constexpr auto FontSingle = Font<Utility::ArraySize(Font6x8), decltype(SingleColumn)>(Font6x8, SingleColumn);
|
||||
constexpr auto FontDouble = Font<Utility::ArraySize(Font6x8), decltype(DoubleColumn)>(Font6x8, DoubleColumn);
|
||||
|
||||
const u8 CSSD1306::InitSequence[] =
|
||||
{
|
||||
0xAE, // Screen off
|
||||
0x81, // Set contrast
|
||||
0x7F, // 00-FF, default to half
|
||||
|
||||
0xA6, // Normal display
|
||||
|
||||
0x20, // Set memory addressing mode
|
||||
0x0, // 00 = horizontal
|
||||
0x21, // Set column start and end address
|
||||
0x00,
|
||||
0x7F,
|
||||
0x22, // Set page address range
|
||||
0x00,
|
||||
0x03,
|
||||
|
||||
0xA1, // Set segment remap
|
||||
0xA8, // Set multiplex ratio
|
||||
0x1F, // Screen height - 1 (31)
|
||||
|
||||
0xC8, // Set COM output scan direction
|
||||
0xD3, // Set display offset
|
||||
0x00, // None
|
||||
0xDA, // Set com pins hardware configuration
|
||||
0x02, // Alternate COM config and disable COM left/right
|
||||
|
||||
0xD5, // Set display oscillator
|
||||
0x80, // Default value
|
||||
0xD9, // Set precharge period
|
||||
0x22, // Default value
|
||||
0xDB, // Set VCOMH deselected level
|
||||
0x20, // Default
|
||||
|
||||
0x8D, // Set charge pump
|
||||
0x14, // VCC generated by internal DC/DC circuit
|
||||
|
||||
0xA4, // Resume to RAM content display
|
||||
0xAF // Set display on
|
||||
};
|
||||
|
||||
CSSD1306::CSSD1306(CI2CMaster *pI2CMaster, u8 nAddress, u8 nHeight)
|
||||
CSSD1306::CSSD1306(CI2CMaster *pI2CMaster, u8 nAddress, u8 nHeight, TLCDRotation Rotation)
|
||||
: CMT32LCD(),
|
||||
m_pI2CMaster(pI2CMaster),
|
||||
m_nAddress(nAddress),
|
||||
m_nHeight(nHeight),
|
||||
m_Rotation(Rotation),
|
||||
|
||||
m_Framebuffer{0x40}
|
||||
{
|
||||
@@ -145,8 +105,52 @@ bool CSSD1306::Initialize()
|
||||
if (!(m_nHeight == 32 || m_nHeight == 64))
|
||||
return false;
|
||||
|
||||
const u8 segRemap = m_Rotation == TLCDRotation::Inverted ? 0xA0 : 0xA1;
|
||||
const u8 comScanDir = m_Rotation == TLCDRotation::Inverted ? 0xC0 : 0xC8;
|
||||
|
||||
const u8 initSequence[] =
|
||||
{
|
||||
0xAE, // Screen off
|
||||
0x81, // Set contrast
|
||||
0x7F, // 00-FF, default to half
|
||||
|
||||
0xA6, // Normal display
|
||||
|
||||
0x20, // Set memory addressing mode
|
||||
0x0, // 00 = horizontal
|
||||
0x21, // Set column start and end address
|
||||
0x00,
|
||||
0x7F,
|
||||
0x22, // Set page address range
|
||||
0x00,
|
||||
0x03,
|
||||
|
||||
segRemap, // Set segment remap
|
||||
0xA8, // Set multiplex ratio
|
||||
0x1F, // Screen height - 1 (31)
|
||||
|
||||
comScanDir, // Set COM output scan direction
|
||||
0xD3, // Set display offset
|
||||
0x00, // None
|
||||
0xDA, // Set com pins hardware configuration
|
||||
0x02, // Alternate COM config and disable COM left/right
|
||||
|
||||
0xD5, // Set display oscillator
|
||||
0x80, // Default value
|
||||
0xD9, // Set precharge period
|
||||
0x22, // Default value
|
||||
0xDB, // Set VCOMH deselected level
|
||||
0x20, // Default value
|
||||
|
||||
0x8D, // Set charge pump
|
||||
0x14, // VCC generated by internal DC/DC circuit
|
||||
|
||||
0xA4, // Resume to RAM content display
|
||||
0xAF // Set display on
|
||||
};
|
||||
|
||||
u8 buffer[] = {0x80, 0};
|
||||
for (auto byte : InitSequence)
|
||||
for (auto byte : initSequence)
|
||||
{
|
||||
buffer[1] = byte;
|
||||
m_pI2CMaster->Write(m_nAddress, buffer, 2);
|
||||
@@ -164,21 +168,21 @@ void CSSD1306::WriteFramebuffer() const
|
||||
void CSSD1306::SetPixel(u8 nX, u8 nY)
|
||||
{
|
||||
// Ensure range is within 0-127 for x, 0-63 for y
|
||||
nX &= 0x7f;
|
||||
nY &= 0x3f;
|
||||
nX &= 0x7F;
|
||||
nY &= 0x3F;
|
||||
|
||||
// The framebuffer starts with the 0x40 byte so that we can write out the entire
|
||||
// buffer to the I2C device in one shot, so offset by 1
|
||||
m_Framebuffer[((nY & 0xf8) << 4) + nX + 1] |= 1 << (nY & 7);
|
||||
m_Framebuffer[((nY & 0xF8) << 4) + nX + 1] |= 1 << (nY & 7);
|
||||
}
|
||||
|
||||
void CSSD1306::ClearPixel(u8 nX, u8 nY)
|
||||
{
|
||||
// Ensure range is within 0-127 for x, 0-63 for y
|
||||
nX &= 0x7f;
|
||||
nY &= 0x3f;
|
||||
nX &= 0x7F;
|
||||
nY &= 0x3F;
|
||||
|
||||
m_Framebuffer[((nY & 0xf8) << 4) + nX + 1] &= ~(1 << (nY & 7));
|
||||
m_Framebuffer[((nY & 0xF8) << 4) + nX + 1] &= ~(1 << (nY & 7));
|
||||
}
|
||||
|
||||
void CSSD1306::DrawChar(char chChar, u8 nCursorX, u8 nCursorY, bool bInverted, bool bDoubleWidth)
|
||||
|
||||
Reference in new issue
Block a user