mirror of
https://github.com/dwhinham/mt32-pi.git
synced 2026-10-27 06:21:59 +00:00
Add support for SH1106 OLED displays
This commit is contained in:
1 parent
126d04f2dc
commit
22dc67e540
8 files changed
+95
-9
No files matched your search
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- USB plug & play support for MIDI interfaces.
|
||||
* You can now connect/disconnect USB MIDI devices at runtime and they will be used instead of the GPIO MIDI interface when present.
|
||||
- Support for SH1106 OLED displays - many thanks to @arananet for donating a screen!
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ OBJS := src/config.o \
|
||||
src/lcd/hd44780.o \
|
||||
src/lcd/hd44780fourbit.o \
|
||||
src/lcd/hd44780i2c.o \
|
||||
src/lcd/sh1106.o \
|
||||
src/lcd/ssd1306.o \
|
||||
src/lcd/synthlcd.o \
|
||||
src/main.o \
|
||||
|
||||
@@ -61,6 +61,7 @@ public:
|
||||
ENUM(None, none) \
|
||||
ENUM(HD44780FourBit, hd44780_4bit) \
|
||||
ENUM(HD44780I2C, hd44780_i2c) \
|
||||
ENUM(SH1106I2C, sh1106_i2c) \
|
||||
ENUM(SSD1306I2C, ssd1306_i2c)
|
||||
|
||||
CONFIG_ENUM(TSystemDefaultSynth, ENUM_SYSTEMDEFAULTSYNTH);
|
||||
|
||||
+12
-2
@@ -51,7 +51,7 @@ public:
|
||||
virtual void Update(CMT32Synth& Synth) override;
|
||||
virtual void Update(CSoundFontSynth& Synth) override;
|
||||
|
||||
private:
|
||||
protected:
|
||||
struct TFrameBufferUpdatePacket
|
||||
{
|
||||
u8 DataControlByte;
|
||||
@@ -60,7 +60,7 @@ private:
|
||||
PACKED;
|
||||
|
||||
void WriteCommand(u8 nCommand) const;
|
||||
void WriteFrameBuffer() const;
|
||||
virtual void WriteFrameBuffer(bool bForceFullUpdate = false) const;
|
||||
void SwapFrameBuffers();
|
||||
void SetPixel(u8 nX, u8 nY);
|
||||
void ClearPixel(u8 nX, u8 nY);
|
||||
@@ -83,4 +83,14 @@ private:
|
||||
u8 m_nCurrentFrameBuffer;
|
||||
};
|
||||
|
||||
class CSH1106 : public CSSD1306
|
||||
{
|
||||
public:
|
||||
CSH1106(CI2CMaster* pI2CMaster, u8 nAddress = 0x3C, u8 nWidth = 128, u8 nHeight = 32, TLCDRotation Rotation = TLCDRotation::Normal);
|
||||
|
||||
private:
|
||||
void WriteData(const u8* pData, size_t nSize) const;
|
||||
virtual void WriteFrameBuffer(bool bForceFullUpdate = false) const override;
|
||||
};
|
||||
|
||||
#endif
|
||||
+3
-2
@@ -272,14 +272,15 @@ polyphony = 256
|
||||
# your device via the i2c_lcd_address option. Consult its datasheet, or see
|
||||
# our documentation for tested models and their configurations.
|
||||
#
|
||||
# Values: none*, hd44780_4bit, hd44780_i2c, ssd1306_i2c
|
||||
# Values: none*, hd44780_4bit, hd44780_i2c, sh1106_i2c, ssd1306_i2c
|
||||
#
|
||||
# none: No LCD
|
||||
# hd44780_4bit: Hitachi HD44780 or compatible (e.g. WS0010, RS0010) character
|
||||
# LCD connected to GPIO pins in 4-bit mode (see documentation for
|
||||
# pinout)
|
||||
# hd44780_i2c: As above, but using an I2C "backpack"
|
||||
# ssd1306_i2c: Small I2C-based OLED graphical display
|
||||
# sh1106_i2c: Small I2C-based OLED graphical display (usually 1.3")
|
||||
# ssd1306_i2c: Small I2C-based OLED graphical display (usually 0.96")
|
||||
type = none
|
||||
|
||||
# Set the width of the LCD.
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// sh1106.cpp
|
||||
//
|
||||
// mt32-pi - A baremetal MIDI synthesizer for Raspberry Pi
|
||||
// Copyright (C) 2020-2021 Dale Whinham <daleyo@gmail.com>
|
||||
//
|
||||
// This file is part of mt32-pi.
|
||||
//
|
||||
// mt32-pi is free software: you can redistribute it and/or modify it under the
|
||||
// terms of the GNU General Public License as published by the Free Software
|
||||
// Foundation, either version 3 of the License, or (at your option) any later
|
||||
// version.
|
||||
//
|
||||
// mt32-pi is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
// details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License along with
|
||||
// mt32-pi. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
#include "lcd/ssd1306.h"
|
||||
|
||||
enum TSH1106Command : u8
|
||||
{
|
||||
SetColumnAddressLow = 0x00,
|
||||
SetColumnAddressHigh = 0x10,
|
||||
SetStartLine = 0x40,
|
||||
SetPageAddress = 0xB0,
|
||||
};
|
||||
|
||||
CSH1106::CSH1106(CI2CMaster *pI2CMaster, u8 nAddress, u8 nWidth, u8 nHeight, TLCDRotation Rotation)
|
||||
: CSSD1306(pI2CMaster, nAddress, nWidth, nHeight, Rotation)
|
||||
{
|
||||
}
|
||||
|
||||
void CSH1106::WriteFrameBuffer(bool bForceFullUpdate) const
|
||||
{
|
||||
// Reset start line
|
||||
WriteCommand(SetStartLine | 0x00);
|
||||
|
||||
const size_t nPages = m_nHeight / 8;
|
||||
constexpr size_t nPageSize = 128;
|
||||
|
||||
// Copy framebuffer one page at a time
|
||||
for (u8 nPage = 0; nPage < nPages; ++nPage)
|
||||
{
|
||||
const size_t nOffset = nPage * nPageSize;
|
||||
const bool bNeedsUpdate = bForceFullUpdate || memcmp(&m_FrameBuffers[0].FrameBuffer[nOffset], &m_FrameBuffers[1].FrameBuffer[nOffset], nPageSize) != 0;
|
||||
|
||||
if (bNeedsUpdate)
|
||||
{
|
||||
WriteCommand(SetPageAddress | nPage);
|
||||
|
||||
// SH1106 displays have a 132x64 pixel memory, but most modules have a visible width of 128 centred on this buffer
|
||||
WriteCommand(SetColumnAddressLow | 0x02);
|
||||
WriteCommand(SetColumnAddressHigh | 0x00);
|
||||
|
||||
// Prefix this page's pixel data with a data control byte
|
||||
u8 Buffer[nPageSize + 1] = { 0x40 };
|
||||
memcpy(Buffer + 1, &m_FrameBuffers[m_nCurrentFrameBuffer].FrameBuffer[nOffset], nPageSize);
|
||||
|
||||
m_pI2CMaster->Write(m_nAddress, Buffer, sizeof(Buffer));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -210,14 +210,14 @@ void CSSD1306::WriteCommand(u8 nCommand) const
|
||||
m_pI2CMaster->Write(m_nAddress, Buffer, sizeof(Buffer));
|
||||
}
|
||||
|
||||
void CSSD1306::WriteFrameBuffer() const
|
||||
void CSSD1306::WriteFrameBuffer(bool bForceFullUpdate) const
|
||||
{
|
||||
// Reset start line
|
||||
WriteCommand(SetStartLine | 0x00);
|
||||
|
||||
// Compare two framebuffers
|
||||
const size_t nFrameBufferSize = m_nWidth * m_nHeight / 8;
|
||||
const bool bNeedsUpdate = memcmp(m_FrameBuffers[0].FrameBuffer, m_FrameBuffers[1].FrameBuffer, nFrameBufferSize) != 0;
|
||||
const bool bNeedsUpdate = bForceFullUpdate || memcmp(m_FrameBuffers[0].FrameBuffer, m_FrameBuffers[1].FrameBuffer, nFrameBufferSize) != 0;
|
||||
|
||||
// Copy entire framebuffer
|
||||
if (bNeedsUpdate)
|
||||
@@ -450,7 +450,7 @@ void CSSD1306::Print(const char* pText, u8 nCursorX, u8 nCursorY, bool bClearLin
|
||||
}
|
||||
|
||||
if (bImmediate)
|
||||
WriteFrameBuffer();
|
||||
WriteFrameBuffer(true);
|
||||
}
|
||||
|
||||
void CSSD1306::Clear(bool bImmediate)
|
||||
@@ -459,7 +459,7 @@ void CSSD1306::Clear(bool bImmediate)
|
||||
memset(pFrameBuffer, 0, m_nWidth * m_nHeight / 8);
|
||||
|
||||
if (bImmediate)
|
||||
WriteFrameBuffer();
|
||||
WriteFrameBuffer(true);
|
||||
}
|
||||
|
||||
void CSSD1306::SetBacklightEnabled(bool bEnabled)
|
||||
|
||||
+5
-1
@@ -116,6 +116,8 @@ bool CMT32Pi::Initialize(bool bSerialMIDIAvailable)
|
||||
m_pLCD = new CHD44780FourBit(pConfig->LCDWidth, pConfig->LCDHeight);
|
||||
else if (pConfig->LCDType == CConfig::TLCDType::HD44780I2C)
|
||||
m_pLCD = new CHD44780I2C(m_pI2CMaster, pConfig->LCDI2CLCDAddress, pConfig->LCDWidth, pConfig->LCDHeight);
|
||||
else if (pConfig->LCDType == CConfig::TLCDType::SH1106I2C)
|
||||
m_pLCD = new CSH1106(m_pI2CMaster, pConfig->LCDI2CLCDAddress, pConfig->LCDWidth, pConfig->LCDHeight, pConfig->LCDRotation);
|
||||
else if (pConfig->LCDType == CConfig::TLCDType::SSD1306I2C)
|
||||
m_pLCD = new CSSD1306(m_pI2CMaster, pConfig->LCDI2CLCDAddress, pConfig->LCDWidth, pConfig->LCDHeight, pConfig->LCDRotation);
|
||||
|
||||
@@ -244,13 +246,15 @@ bool CMT32Pi::Initialize(bool bSerialMIDIAvailable)
|
||||
CCPUThrottle::Get()->DumpStatus();
|
||||
SetPowerSaveTimeout(pConfig->SystemPowerSaveTimeout);
|
||||
|
||||
// Attach LCD to synths
|
||||
// Attach LCD to synths and clear
|
||||
if (m_pLCD)
|
||||
{
|
||||
if (m_pMT32Synth)
|
||||
m_pMT32Synth->SetLCD(m_pLCD);
|
||||
if (m_pSoundFontSynth)
|
||||
m_pSoundFontSynth->SetLCD(m_pLCD);
|
||||
|
||||
m_pLCD->Clear();
|
||||
}
|
||||
|
||||
// Start audio
|
||||
|
||||
Reference in new issue
Block a user