diff --git a/src/config.cpp b/src/config.cpp index bb65840..d456c58 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -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; diff --git a/src/config.h b/src/config.h index 55c038e..71bb5ad 100644 --- a/src/config.h +++ b/src/config.h @@ -28,6 +28,10 @@ #include #include +#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; diff --git a/src/kernel.cpp b/src/kernel.cpp index 3ff835c..33bc5f8 100644 --- a/src/kernel.cpp +++ b/src/kernel.cpp @@ -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); diff --git a/src/kernel.h b/src/kernel.h index 7d2f346..efe5f4f 100644 --- a/src/kernel.h +++ b/src/kernel.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #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; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index e2576b5..9547baf 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -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), diff --git a/src/minidexed.h b/src/minidexed.h index 407d5db..8ca74c8 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/src/minidexed.ini b/src/minidexed.ini index 84d76ac..de9f150 100644 --- a/src/minidexed.ini +++ b/src/minidexed.ini @@ -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 diff --git a/src/userinterface.cpp b/src/userinterface.cpp index 241605e..9e7c112 100644 --- a/src/userinterface.cpp +++ b/src/userinterface.cpp @@ -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); diff --git a/src/userinterface.h b/src/userinterface.h index 5de2846..a8026db 100644 --- a/src/userinterface.h +++ b/src/userinterface.h @@ -26,16 +26,18 @@ #include #include #include +#include #include #include #include +#include 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; diff --git a/submod.sh b/submod.sh index d72d19c..c13dca3 100755 --- a/submod.sh +++ b/submod.sh @@ -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