Support for ST7789 based (SPI) displays (#652)

* Initial build with basic structure to support st7789device once added to circle.

* Implementation of ST7789 display - requires updated circle with new ST7789 character driver.

* Added more details to minidexed.ini about ST7789 and SPI options.

* Update to develop branch of circle that now supports st7789 character mode display.

* Minor formatting fixes to tidy up.

* Allow setting of more advanced SPI parameters: mode and clock.

* Update to allow for font size as an option.
main continuous
Kevin 2 weeks ago committed by GitHub
parent 4fa9e167b2
commit d08280bc70
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 73
      src/config.cpp
  2. 36
      src/config.h
  3. 29
      src/kernel.cpp
  4. 2
      src/kernel.h
  5. 4
      src/minidexed.cpp
  6. 3
      src/minidexed.h
  7. 21
      src/minidexed.ini
  8. 69
      src/userinterface.cpp
  9. 7
      src/userinterface.h
  10. 2
      submod.sh

@ -102,6 +102,20 @@ void CConfig::Load (void)
m_bSSD1306LCDRotate = m_Properties.GetNumber ("SSD1306LCDRotate", 0) != 0;
m_bSSD1306LCDMirror = m_Properties.GetNumber ("SSD1306LCDMirror", 0) != 0;
m_nSPIBus = m_Properties.GetNumber ("SPIBus", SPI_INACTIVE); // Disabled by default
m_nSPIMode = m_Properties.GetNumber ("SPIMode", SPI_DEF_MODE);
m_nSPIClockKHz = m_Properties.GetNumber ("SPIClockKHz", SPI_DEF_CLOCK);
m_bST7789Enabled = m_Properties.GetNumber ("ST7789Enabled", 0) != 0;
m_nST7789Data = m_Properties.GetNumber ("ST7789Data", 0);
m_nST7789Select = m_Properties.GetNumber ("ST7789Select", 0);
m_nST7789Reset = m_Properties.GetNumber ("ST7789Reset", 0); // optional
m_nST7789Backlight = m_Properties.GetNumber ("ST7789Backlight", 0); // optional
m_nST7789Width = m_Properties.GetNumber ("ST7789Width", 240);
m_nST7789Height = m_Properties.GetNumber ("ST7789Height", 240);
m_nST7789Rotation = m_Properties.GetNumber ("ST7789Rotation", 0);
m_bST7789SmallFont = m_Properties.GetNumber ("ST7789SmallFont", 0) != 0;
m_nLCDColumns = m_Properties.GetNumber ("LCDColumns", 16);
m_nLCDRows = m_Properties.GetNumber ("LCDRows", 2);
@ -299,6 +313,65 @@ bool CConfig::GetSSD1306LCDMirror (void) const
return m_bSSD1306LCDMirror;
}
unsigned CConfig::GetSPIBus (void) const
{
return m_nSPIBus;
}
unsigned CConfig::GetSPIMode (void) const
{
return m_nSPIMode;
}
unsigned CConfig::GetSPIClockKHz (void) const
{
return m_nSPIClockKHz;
}
bool CConfig::GetST7789Enabled (void) const
{
return m_bST7789Enabled;
}
unsigned CConfig::GetST7789Data (void) const
{
return m_nST7789Data;
}
unsigned CConfig::GetST7789Select (void) const
{
return m_nST7789Select;
}
unsigned CConfig::GetST7789Reset (void) const
{
return m_nST7789Reset;
}
unsigned CConfig::GetST7789Backlight (void) const
{
return m_nST7789Backlight;
}
unsigned CConfig::GetST7789Width (void) const
{
return m_nST7789Width;
}
unsigned CConfig::GetST7789Height (void) const
{
return m_nST7789Height;
}
unsigned CConfig::GetST7789Rotation (void) const
{
return m_nST7789Rotation;
}
bool CConfig::GetST7789SmallFont (void) const
{
return m_bST7789SmallFont;
}
unsigned CConfig::GetLCDColumns (void) const
{
return m_nLCDColumns;

@ -28,6 +28,10 @@
#include <circle/sysconfig.h>
#include <string>
#define SPI_INACTIVE 255
#define SPI_DEF_CLOCK 15000 // kHz
#define SPI_DEF_MODE 0 // Default mode (0,1,2,3)
class CConfig // Configuration for MiniDexed
{
public:
@ -103,6 +107,22 @@ public:
bool GetSSD1306LCDRotate (void) const;
bool GetSSD1306LCDMirror (void) const;
// SPI support
unsigned GetSPIBus (void) const;
unsigned GetSPIMode (void) const;
unsigned GetSPIClockKHz (void) const;
// ST7789 LCD
bool GetST7789Enabled (void) const;
unsigned GetST7789Data (void) const;
unsigned GetST7789Select (void) const;
unsigned GetST7789Reset (void) const;
unsigned GetST7789Backlight (void) const;
unsigned GetST7789Width (void) const;
unsigned GetST7789Height (void) const;
unsigned GetST7789Rotation (void) const;
bool GetST7789SmallFont (void) const;
unsigned GetLCDColumns (void) const;
unsigned GetLCDRows (void) const;
@ -204,7 +224,21 @@ private:
unsigned m_nSSD1306LCDHeight;
bool m_bSSD1306LCDRotate;
bool m_bSSD1306LCDMirror;
unsigned m_nSPIBus;
unsigned m_nSPIMode;
unsigned m_nSPIClockKHz;
bool m_bST7789Enabled;
unsigned m_nST7789Data;
unsigned m_nST7789Select;
unsigned m_nST7789Reset;
unsigned m_nST7789Backlight;
unsigned m_nST7789Width;
unsigned m_nST7789Height;
unsigned m_nST7789Rotation;
unsigned m_bST7789SmallFont;
unsigned m_nLCDColumns;
unsigned m_nLCDRows;

@ -33,6 +33,7 @@ CKernel::CKernel (void)
m_Config (&mFileSystem),
m_GPIOManager (&mInterrupt),
m_I2CMaster (CMachineInfo::Get ()->GetDevice (DeviceI2CMaster), TRUE),
m_pSPIMaster (nullptr),
m_pDexed (0)
{
s_pThis = this;
@ -66,6 +67,32 @@ bool CKernel::Initialize (void)
m_Config.Load ();
unsigned nSPIMaster = m_Config.GetSPIBus();
unsigned nSPIMode = m_Config.GetSPIMode();
unsigned long nSPIClock = 1000 * m_Config.GetSPIClockKHz();
#if RASPPI<4
// By default older RPI versions use SPI 0.
// It is possible to build circle to support SPI 1 for
// devices that use the 40-pin header, but that isn't
// enabled at present...
if (nSPIMaster == 0)
#else
// RPI 4+ has several possible SPI Bus Configurations.
// As mentioned above, SPI 1 is not built by default.
// See circle/include/circle/spimaster.h
if (nSPIMaster == 0 || nSPIMaster == 3 || nSPIMaster == 4 || nSPIMaster == 5 || nSPIMaster == 6)
#endif
{
unsigned nCPHA = (nSPIMode & 1) ? 1 : 0;
unsigned nCPOL = (nSPIMode & 2) ? 1 : 0;
m_pSPIMaster = new CSPIMaster (nSPIClock, nCPOL, nCPHA, nSPIMaster);
if (!m_pSPIMaster->Initialize())
{
delete (m_pSPIMaster);
m_pSPIMaster = nullptr;
}
}
if (m_Config.GetUSBGadgetMode())
{
#if RASPPI==5
@ -86,7 +113,7 @@ bool CKernel::Initialize (void)
return FALSE;
}
m_pDexed = new CMiniDexed (&m_Config, &mInterrupt, &m_GPIOManager, &m_I2CMaster,
m_pDexed = new CMiniDexed (&m_Config, &mInterrupt, &m_GPIOManager, &m_I2CMaster, m_pSPIMaster,
&mFileSystem);
assert (m_pDexed);

@ -24,6 +24,7 @@
#include <circle/cputhrottle.h>
#include <circle/gpiomanager.h>
#include <circle/i2cmaster.h>
#include <circle/spimaster.h>
#include <circle/usb/usbcontroller.h>
#include "config.h"
#include "minidexed.h"
@ -54,6 +55,7 @@ private:
CCPUThrottle m_CPUThrottle;
CGPIOManager m_GPIOManager;
CI2CMaster m_I2CMaster;
CSPIMaster *m_pSPIMaster;
CMiniDexed *m_pDexed;
CUSBController *m_pUSB;

@ -31,13 +31,13 @@
LOGMODULE ("minidexed");
CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster, FATFS *pFileSystem)
CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster, CSPIMaster *pSPIMaster, FATFS *pFileSystem)
:
#ifdef ARM_ALLOW_MULTI_CORE
CMultiCoreSupport (CMemorySystem::Get ()),
#endif
m_pConfig (pConfig),
m_UI (this, pGPIOManager, pI2CMaster, pConfig),
m_UI (this, pGPIOManager, pI2CMaster, pSPIMaster, pConfig),
m_PerformanceConfig (pFileSystem),
m_PCKeyboard (this, pConfig, &m_UI),
m_SerialMIDI (this, pInterrupt, pConfig, &m_UI),

@ -36,6 +36,7 @@
#include <circle/interrupt.h>
#include <circle/gpiomanager.h>
#include <circle/i2cmaster.h>
#include <circle/spimaster.h>
#include <circle/multicore.h>
#include <circle/sound/soundbasedevice.h>
#include <circle/spinlock.h>
@ -51,7 +52,7 @@ class CMiniDexed
{
public:
CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster, FATFS *pFileSystem);
CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster, CSPIMaster *pSPIMaster, FATFS *pFileSystem);
bool Initialize (void);

@ -55,6 +55,27 @@ SSD1306LCDHeight=32
SSD1306LCDRotate=0
SSD1306LCDMirror=0
# ST7789 LCD
# SPIBus=0 for any RPi (GPIO 10,11,8,7).
# Note: Leave blank (default) if no SPI device required.
# Select=0|1 for CE0 or CE1
# Data = GPIO pin number
# Optional: Reset, Backlight = GPIO pin numbers
# Rotation=0,90,180,270
# SmallFont=0 (default), 1
#
# For a 240 wide display set LCDColumns=15 with LCDRows=2
SPIBus=
ST7789Enabled=0
ST7789Data=
ST7789Select=
ST7789Reset=
ST7789Backlight=
ST7789Width=240
ST7789Height=240
ST7789Rotation=0
ST7789SmallFont=0
# Default is 16x2 display (e.g. HD44780)
LCDColumns=16
LCDRows=2

@ -27,10 +27,11 @@
LOGMODULE ("ui");
CUserInterface::CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster, CConfig *pConfig)
CUserInterface::CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster, CSPIMaster *pSPIMaster, CConfig *pConfig)
: m_pMiniDexed (pMiniDexed),
m_pGPIOManager (pGPIOManager),
m_pI2CMaster (pI2CMaster),
m_pSPIMaster (pSPIMaster),
m_pConfig (pConfig),
m_pLCD (0),
m_pLCDBuffered (0),
@ -57,17 +58,69 @@ bool CUserInterface::Initialize (void)
{
unsigned i2caddr = m_pConfig->GetLCDI2CAddress ();
unsigned ssd1306addr = m_pConfig->GetSSD1306LCDI2CAddress ();
bool st7789 = m_pConfig->GetST7789Enabled ();
if (ssd1306addr != 0) {
m_pSSD1306 = new CSSD1306Device (m_pConfig->GetSSD1306LCDWidth (), m_pConfig->GetSSD1306LCDHeight (),
m_pI2CMaster, ssd1306addr,
m_pConfig->GetSSD1306LCDRotate (), m_pConfig->GetSSD1306LCDMirror ());
LOGDBG ("LCD: SSD1306");
if (!m_pSSD1306->Initialize ())
{
LOGDBG("LCD: SSD1306 initialization failed");
return false;
}
LOGDBG ("LCD: SSD1306");
m_pLCD = m_pSSD1306;
} else if (i2caddr == 0)
}
else if (st7789)
{
if (m_pSPIMaster == nullptr)
{
LOGDBG("LCD: ST7789 Enabled but SPI Initialisation Failed");
return false;
}
unsigned long nSPIClock = 1000 * m_pConfig->GetSPIClockKHz();
unsigned nSPIMode = m_pConfig->GetSPIMode();
unsigned nCPHA = (nSPIMode & 1) ? 1 : 0;
unsigned nCPOL = (nSPIMode & 2) ? 1 : 0;
LOGDBG("SPI: CPOL=%u; CPHA=%u; CLK=%u",nCPOL,nCPHA,nSPIClock);
m_pST7789Display = new CST7789Display (m_pSPIMaster,
m_pConfig->GetST7789Data(),
m_pConfig->GetST7789Reset(),
m_pConfig->GetST7789Backlight(),
m_pConfig->GetST7789Width(),
m_pConfig->GetST7789Height(),
nCPOL, nCPHA, nSPIClock,
m_pConfig->GetST7789Select());
if (m_pST7789Display->Initialize())
{
m_pST7789Display->SetRotation (m_pConfig->GetST7789Rotation());
bool bLargeFont = !(m_pConfig->GetST7789SmallFont());
m_pST7789 = new CST7789Device (m_pSPIMaster, m_pST7789Display, m_pConfig->GetLCDColumns (), m_pConfig->GetLCDRows (), bLargeFont, bLargeFont);
if (m_pST7789->Initialize())
{
LOGDBG ("LCD: ST7789");
m_pLCD = m_pST7789;
}
else
{
LOGDBG ("LCD: Failed to initalize ST7789 character device");
delete (m_pST7789);
delete (m_pST7789Display);
m_pST7789 = nullptr;
m_pST7789Display = nullptr;
return false;
}
}
else
{
LOGDBG ("LCD: Failed to initialize ST7789 display");
delete (m_pST7789Display);
m_pST7789Display = nullptr;
return false;
}
}
else if (i2caddr == 0)
{
m_pHD44780 = new CHD44780Device (m_pConfig->GetLCDColumns (), m_pConfig->GetLCDRows (),
m_pConfig->GetLCDPinData4 (),
@ -77,22 +130,24 @@ bool CUserInterface::Initialize (void)
m_pConfig->GetLCDPinEnable (),
m_pConfig->GetLCDPinRegisterSelect (),
m_pConfig->GetLCDPinReadWrite ());
LOGDBG ("LCD: HD44780");
if (!m_pHD44780->Initialize ())
{
LOGDBG("LCD: HD44780 initialization failed");
return false;
}
LOGDBG ("LCD: HD44780");
m_pLCD = m_pHD44780;
}
else
{
m_pHD44780 = new CHD44780Device (m_pI2CMaster, i2caddr,
m_pConfig->GetLCDColumns (), m_pConfig->GetLCDRows ());
LOGDBG ("LCD: HD44780 I2C");
if (!m_pHD44780->Initialize ())
{
LOGDBG("LCD: HD44780 (I2C) initialization failed");
return false;
}
LOGDBG ("LCD: HD44780 I2C");
m_pLCD = m_pHD44780;
}
assert (m_pLCD);
@ -217,7 +272,7 @@ void CUserInterface::DisplayWrite (const char *pMenu, const char *pParam, const
CString Value (" ");
if (bArrowDown)
{
Value = "\x7F"; // arrow left character
Value = "<"; // arrow left character
}
Value.Append (pValue);
@ -232,7 +287,7 @@ void CUserInterface::DisplayWrite (const char *pMenu, const char *pParam, const
}
}
Value.Append ("\x7E"); // arrow right character
Value.Append (">"); // arrow right character
}
Msg.Append (Value);

@ -26,16 +26,18 @@
#include <sensor/ky040.h>
#include <display/hd44780device.h>
#include <display/ssd1306device.h>
#include <display/st7789device.h>
#include <circle/gpiomanager.h>
#include <circle/writebuffer.h>
#include <circle/i2cmaster.h>
#include <circle/spimaster.h>
class CMiniDexed;
class CUserInterface
{
public:
CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster, CConfig *pConfig);
CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster, CSPIMaster *pSPIMaster, CConfig *pConfig);
~CUserInterface (void);
bool Initialize (void);
@ -68,11 +70,14 @@ private:
CMiniDexed *m_pMiniDexed;
CGPIOManager *m_pGPIOManager;
CI2CMaster *m_pI2CMaster;
CSPIMaster *m_pSPIMaster;
CConfig *m_pConfig;
CCharDevice *m_pLCD;
CHD44780Device *m_pHD44780;
CSSD1306Device *m_pSSD1306;
CST7789Display *m_pST7789Display;
CST7789Device *m_pST7789;
CWriteBufferDevice *m_pLCDBuffered;
CUIButtons *m_pUIButtons;

@ -12,7 +12,7 @@ cd -
#
# Optional update submodules explicitly
cd circle-stdlib/libs/circle
git checkout 4b3e06f
git checkout 4155f43
cd -
cd circle-stdlib/libs/circle-newlib
#git checkout develop

Loading…
Cancel
Save