diff --git a/README.md b/README.md
index a2ad41c854..5051377c6a 100644
--- a/README.md
+++ b/README.md
@@ -729,7 +729,7 @@ your specific needs.
CAT24AA |
CYCLE-COUNTER |
-DRV832X |
+DRV832X-SPI |
DS1302 |
DS1631 |
DS18B20 |
@@ -792,27 +792,28 @@ your specific needs.
PCA9685 |
QMC5883L |
-SH1106 |
+SH1106-I2C |
SIEMENS-S65 |
SIEMENS-S75 |
SK6812 |
SK9822 |
-SSD1306 |
+SSD1306-I2C |
+SSD1306-SPI |
ST7586S |
ST7789 |
STTS22H |
STUSB4500 |
SX1276 |
-SX128X |
+SX128X |
TCS3414 |
TCS3472 |
TLC594x |
TMP102 |
TMP12x |
-TMP175 |
+TMP175 |
TOUCH2046 |
VL53L0 |
VL6180 |
diff --git a/examples/generic/ros/environment/project.xml b/examples/generic/ros/environment/project.xml
index 67bb72a1d0..3699e1a504 100644
--- a/examples/generic/ros/environment/project.xml
+++ b/examples/generic/ros/environment/project.xml
@@ -7,7 +7,7 @@
modm:driver:bme280
- modm:driver:ssd1306
+ modm:driver:ssd1306.i2c
modm:ros
modm:communication:ros
modm:processing:timer
diff --git a/examples/generic/ros/environment/thread_display.hpp b/examples/generic/ros/environment/thread_display.hpp
index 15440cfa12..f95b20be23 100644
--- a/examples/generic/ros/environment/thread_display.hpp
+++ b/examples/generic/ros/environment/thread_display.hpp
@@ -14,7 +14,7 @@
#include
#include
-#include
+#include
#include "hardware.hpp"
@@ -55,7 +55,7 @@ class DisplayThread: public modm::pt::Protothread
}
protected:
- modm::Ssd1306 display;
+ modm::Ssd1306I2c display;
modm::ShortTimeout boot_timeout;
bool _dirty;
int32_t _seq;
diff --git a/examples/nucleo_g474re/sh1106_i2c/main.cpp b/examples/nucleo_g474re/sh1106_i2c/main.cpp
new file mode 100644
index 0000000000..eb2eaa6c63
--- /dev/null
+++ b/examples/nucleo_g474re/sh1106_i2c/main.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2023, Raphael Lehmann
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include
+#include
+// #include
+
+/// SH1106 display in I2C mode
+using MyI2cMaster = modm::platform::I2cMaster1;
+using Scl = Board::D15;
+using Sda = Board::D14;
+
+using Display = modm::Sh1106I2c;
+// using Display = modm::Ssd1306;
+
+Display display;
+
+int
+main()
+{
+ Board::initialize();
+
+ modm::delay(100ms);
+
+ MyI2cMaster::connect();
+ // Use 20kHz I2C and internal pull-ups, works without external pull-ups
+ // if the jumper wires are short enought
+ MyI2cMaster::connect(MyI2cMaster::PullUps::Internal);
+
+ modm::delay(100ms);
+
+ RF_CALL_BLOCKING(display.initialize());
+ RF_CALL_BLOCKING(display.setOrientation(modm::glcd::Orientation::Landscape0));
+ RF_CALL_BLOCKING(display.setDisplayMode(Display::DisplayMode::Inverted));
+ RF_CALL_BLOCKING(display.setContrast(80));
+
+ display.setFont(modm::font::Assertion);
+
+ modm::ShortPeriodicTimer timer(333ms);
+ uint16_t counter(0);
+
+ while (true)
+ {
+ if (timer.execute())
+ {
+ display.clear();
+ display.setCursor(1, 1);
+ display << "Hello World!";
+ display.setCursor(1, 17);
+ display << counter++;
+ display.setCursor(1, 33);
+ display << "Line 3";
+ display.setCursor(1, 49);
+ display << "Line 4";
+
+ display.update();
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/nucleo_g474re/sh1106_i2c/project.xml b/examples/nucleo_g474re/sh1106_i2c/project.xml
new file mode 100644
index 0000000000..39d7ef1946
--- /dev/null
+++ b/examples/nucleo_g474re/sh1106_i2c/project.xml
@@ -0,0 +1,13 @@
+
+ modm:nucleo-g474re
+
+
+
+
+ modm:driver:sh1106.i2c
+ modm:driver:ssd1306.i2c
+ modm:platform:gpio
+ modm:platform:i2c:1
+ modm:build:scons
+
+
diff --git a/examples/nucleo_g474re/ssd1306_spi/main.cpp b/examples/nucleo_g474re/ssd1306_spi/main.cpp
new file mode 100644
index 0000000000..6e3673ba56
--- /dev/null
+++ b/examples/nucleo_g474re/ssd1306_spi/main.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2023, Raphael Lehmann
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include
+#include
+
+/**
+ * SSD1306 display in SPI 4-wire mode
+ *
+ * SCK <-> Arduino D3 / GpioB3
+ * MOSI <-> Arduino D4 / GpioB5
+ * CS <-> Arduino D5 / GpioB4
+ * D/C# <-> Arduino D2 / GpioA10
+ * RESET# <-> Arduino D7 / GpioA8
+ *
+ * En7V5 <-> Arduino D6 / GpioB10
+ *
+ * TODO: Describe charge pump setup for 7.5V
+ */
+
+using MySpiMaster = modm::platform::SpiMaster1;
+using Sck = Board::D3;
+using Mosi = Board::D4;
+using Cs = Board::D5;
+using Dc = Board::D2;
+using Reset = Board::D7;
+using En7V5 = Board::D6;
+using Display = modm::Ssd1306Spi;
+Display display;
+
+int
+main()
+{
+ Board::initialize();
+
+ En7V5::reset();
+ En7V5::setOutput();
+ Reset::reset();
+ Reset::setOutput();
+
+ Cs::setOutput();
+ Dc::setOutput();
+ MySpiMaster::connect();
+ MySpiMaster::initialize();
+
+ Cs::set();
+ En7V5::set();
+ modm::delay(500ms);
+
+ Reset::set();
+ modm::delay(1ms);
+
+ RF_CALL_BLOCKING(display.initialize());
+ RF_CALL_BLOCKING(display.setOrientation(modm::glcd::Orientation::Landscape0));
+ RF_CALL_BLOCKING(display.setDisplayMode(Display::DisplayMode::Inverted));
+ RF_CALL_BLOCKING(display.setContrast(80));
+
+ display.setFont(modm::font::Assertion);
+
+ modm::ShortPeriodicTimer timer(333ms);
+ uint16_t counter(0);
+
+ while (true)
+ {
+ if (timer.execute())
+ {
+ display.clear();
+ display.setCursor(1, 1);
+ display << "Hello World!";
+ display.setCursor(1,17);
+ display << counter++;
+
+ display.update();
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/nucleo_g474re/ssd1306_spi/project.xml b/examples/nucleo_g474re/ssd1306_spi/project.xml
new file mode 100644
index 0000000000..c1c6902d35
--- /dev/null
+++ b/examples/nucleo_g474re/ssd1306_spi/project.xml
@@ -0,0 +1,12 @@
+
+ modm:nucleo-g474re
+
+
+
+
+ modm:driver:ssd1306.spi
+ modm:platform:gpio
+ modm:platform:spi:1
+ modm:build:scons
+
+
diff --git a/examples/stm32f4_discovery/display/ssd1306/main.cpp b/examples/stm32f4_discovery/display/ssd1306_i2c/main.cpp
similarity index 92%
rename from examples/stm32f4_discovery/display/ssd1306/main.cpp
rename to examples/stm32f4_discovery/display/ssd1306_i2c/main.cpp
index aeea40c8a4..c18ccd4ffc 100644
--- a/examples/stm32f4_discovery/display/ssd1306/main.cpp
+++ b/examples/stm32f4_discovery/display/ssd1306_i2c/main.cpp
@@ -10,7 +10,7 @@
*/
#include
-#include
+#include
/**
* Example to demonstrate a MODM graphics display SSD1306.
@@ -24,7 +24,7 @@
typedef GpioB9 Sda;
typedef GpioB8 Scl;
typedef I2cMaster1 MyI2cMaster;
-modm::Ssd1306 display;
+modm::Ssd1306I2c display;
// ----------------------------------------------------------------------------
int
diff --git a/examples/stm32f4_discovery/display/ssd1306/project.xml b/examples/stm32f4_discovery/display/ssd1306_i2c/project.xml
similarity index 77%
rename from examples/stm32f4_discovery/display/ssd1306/project.xml
rename to examples/stm32f4_discovery/display/ssd1306_i2c/project.xml
index 02ecafaea8..901a274fab 100644
--- a/examples/stm32f4_discovery/display/ssd1306/project.xml
+++ b/examples/stm32f4_discovery/display/ssd1306_i2c/project.xml
@@ -1,10 +1,10 @@
modm:disco-f407vg
-
+
- modm:driver:ssd1306
+ modm:driver:ssd1306.i2c
modm:platform:gpio
modm:platform:i2c:1
modm:build:scons
diff --git a/src/modm/driver/display/sh1106.hpp b/src/modm/driver/display/sh1106_i2c.hpp
similarity index 76%
rename from src/modm/driver/display/sh1106.hpp
rename to src/modm/driver/display/sh1106_i2c.hpp
index 92120d7c80..3874fd6e8f 100644
--- a/src/modm/driver/display/sh1106.hpp
+++ b/src/modm/driver/display/sh1106_i2c.hpp
@@ -11,7 +11,7 @@
#pragma once
-#include "ssd1306.hpp"
+#include "ssd1306_i2c.hpp"
namespace modm
{
@@ -26,10 +26,10 @@ namespace modm
* @ingroup modm_driver_sh1106
*/
template
-class Sh1106 : public Ssd1306
+class Sh1106I2c : public Ssd1306I2c
{
public:
- Sh1106(uint8_t address = 0x3C) : Ssd1306(address) {}
+ Sh1106I2c(uint8_t address = 0x3C) : Ssd1306I2c(address) {}
protected:
modm::ResumableResult
@@ -39,13 +39,10 @@ class Sh1106 : public Ssd1306
this->transaction_success = true;
- this->commandBuffer[0] = ssd1306::AdressingCommands::HigherColumnStartAddress;
- this->commandBuffer[1] = 0x02;
-
for (page = 0; page < Height / 8; page++)
{
- this->commandBuffer[2] = 0xB0 | page;
- this->transaction_success &= RF_CALL(this->writeCommands(3));
+ this->commandBuffer[0] = std::to_underlying(ssd1306::AdressingCommands::PageStartAddress) | page;
+ this->transaction_success &= RF_CALL(this->writeCommands(1));
RF_WAIT_UNTIL(
this->transaction.configureDisplayWrite((uint8_t*)&this->buffer[page], 128));
@@ -62,14 +59,14 @@ class Sh1106 : public Ssd1306
{
RF_BEGIN();
// Default on Power-up - can be omitted
- this->commandBuffer[0] = ssd1306::AdressingCommands::MemoryMode;
- this->commandBuffer[1] = ssd1306::MemoryMode::PAGE;
+ this->commandBuffer[0] = std::to_underlying(ssd1306::AdressingCommands::MemoryMode);
+ this->commandBuffer[1] = std::to_underlying(ssd1306::MemoryMode::PAGE);
this->transaction_success &= RF_CALL(this->writeCommands(2));
RF_END();
}
private:
- size_t page;
+ uint8_t page;
};
} // namespace modm
diff --git a/src/modm/driver/display/sh1106.lb b/src/modm/driver/display/sh1106_i2c.lb
similarity index 76%
rename from src/modm/driver/display/sh1106.lb
rename to src/modm/driver/display/sh1106_i2c.lb
index 4222f45849..486524a2e9 100644
--- a/src/modm/driver/display/sh1106.lb
+++ b/src/modm/driver/display/sh1106_i2c.lb
@@ -12,13 +12,13 @@
def init(module):
- module.name = ":driver:sh1106"
- module.description = "SH1106 Display"
+ module.name = ":driver:sh1106.i2c"
+ module.description = "SH1106 Display in I2C mode"
def prepare(module, options):
- module.depends(":driver:ssd1306")
+ module.depends(":driver:ssd1306.i2c")
return True
def build(env):
env.outbasepath = "modm/src/modm/driver/display"
- env.copy("sh1106.hpp")
+ env.copy("sh1106_i2c.hpp")
diff --git a/src/modm/driver/display/ssd1306.hpp b/src/modm/driver/display/ssd1306.hpp
index e62881d154..ac9d958668 100644
--- a/src/modm/driver/display/ssd1306.hpp
+++ b/src/modm/driver/display/ssd1306.hpp
@@ -1,7 +1,5 @@
/*
- * Copyright (c) 2014, 2016-2017, Sascha Schade
- * Copyright (c) 2014-2016, 2018, Niklas Hauser
- * Copyright (c) 2021, Thomas Sommer
+ * Copyright (c) 2023, Raphael Lehmann
*
* This file is part of the modm project.
*
@@ -11,181 +9,6 @@
*/
// ----------------------------------------------------------------------------
-#ifndef MODM_SSD1306_HPP
-#define MODM_SSD1306_HPP
-
-#include
-#include
-#include
-#include
-
-#include "ssd1306_register.hpp"
-
-namespace modm
-{
-
-/// @ingroup modm_driver_ssd1306
-struct ssd1306 : public ssd1306_register
-{
-public:
- enum class
- ScrollStep : uint8_t
- {
- Frames2 = 0b111,
- Frames3 = 0b100,
- Frames4 = 0b101,
- Frames5 = 0b000,
- Frames25 = 0b110,
- Frames64 = 0b001,
- Frames128 = 0b010,
- Frames256 = 0b011
- };
-
- enum class
- ScrollDirection : uint8_t
- {
- Right = HorizontalScrollRight,
- Left = HorizontalScrollLeft,
- // RightBottom = VerticalAndHorizontalScrollRight,
- // LeftBottom = VerticalAndHorizontalScrollLeft,
- };
-
- enum class
- DisplayMode : uint8_t
- {
- Normal = NormalDisplay,
- Inverted = InvertedDisplay
- };
-
-public:
- /// @cond
- class Ssd1306_I2cWriteTransaction : public modm::I2cWriteTransaction
- {
- public:
- Ssd1306_I2cWriteTransaction(uint8_t address);
-
- bool
- configureDisplayWrite(const uint8_t *buffer, std::size_t size);
-
- protected:
- virtual Writing
- writing() override;
-
- virtual void
- detaching(modm::I2c::DetachCause cause) override;
-
- inline bool
- isWritable()
- { return !transfer_active; }
-
- private:
- uint8_t transfer_type;
- bool transfer_active;
- };
- /// @endcond
-}; // struct ssd1306
-
-/**
- * Driver for SSD1306 based OLED-displays using I2C.
- * This display is only rated to be driven with 400kHz, which limits
- * the frame rate to about 40Hz.
- *
- * @author Niklas Hauser
- * @author Thomas Sommer
- * @ingroup modm_driver_ssd1306
- */
-template
-class Ssd1306 : public ssd1306,
- public MonochromeGraphicDisplayVertical<128, Height>,
- public I2cDevice
-{
- static_assert((Height == 64) or (Height == 32), "Display height must be either 32 or 64 pixel!");
-
-public:
- Ssd1306(uint8_t address = 0x3C);
-
- /// Pings the display
- bool inline pingBlocking()
- { return RF_CALL_BLOCKING(this->ping()); }
-
- /// initializes for 3V3 with charge-pump
- bool inline initializeBlocking()
- { return RF_CALL_BLOCKING(initialize()); }
-
- /// Update the display with the content of the RAM buffer.
- void
- update() override
- { RF_CALL_BLOCKING(startWriteDisplay()); }
-
- /// Use this method to synchronize writing to the displays buffer
- /// to avoid tearing.
- /// @return `true` if the frame buffer is not being copied to the display
- bool isWritable()
- { return this->transaction.isWriteable(); }
-
- // MARK: - TASKS
- /// initializes for 3V3 with charge-pump asynchronously
- modm::ResumableResult
- initialize();
-
- // starts a frame transfer and waits for completion
- virtual modm::ResumableResult
- writeDisplay();
-
- modm::ResumableResult
- setDisplayMode(DisplayMode mode = DisplayMode::Normal)
- {
- commandBuffer[0] = mode;
- return writeCommands(1);
- }
-
- modm::ResumableResult
- setContrast(uint8_t contrast = 0xCE)
- {
- commandBuffer[0] = FundamentalCommands::ContrastControl;
- commandBuffer[1] = contrast;
- return writeCommands(2);
- }
-
- /**
- * \param orientation glcd::Orientation::Landscape0 or glcd::Orientation::Landscape180
- */
- modm::ResumableResult
- setOrientation(glcd::Orientation orientation);
-
- modm::ResumableResult
- configureScroll(uint8_t origin, uint8_t size, ScrollDirection direction, ScrollStep steps);
-
- modm::ResumableResult
- enableScroll()
- {
- commandBuffer[0] = ScrollingCommands::EnableScroll;
- return writeCommands(1);
- }
-
- modm::ResumableResult
- disableScroll()
- {
- commandBuffer[0] = ScrollingCommands::DisableScroll;
- return writeCommands(1);
- }
-
-protected:
- modm::ResumableResult
- writeCommands(std::size_t length);
-
- virtual modm::ResumableResult
- initializeMemoryMode();
-
- virtual modm::ResumableResult
- startWriteDisplay();
-
- uint8_t commandBuffer[7];
- bool transaction_success;
-};
-
-} // namespace modm
-
-#include "ssd1306_impl.hpp"
-
-#endif // MODM_SSD1306_HPP
+// DEPRECATE 2024q4
+#warning "Use 'ssd1306_i2c.hpp' instead!"
+#include "ssd1306_i2c.hpp"
diff --git a/src/modm/driver/display/ssd1306_common.hpp b/src/modm/driver/display/ssd1306_common.hpp
new file mode 100644
index 0000000000..4818234219
--- /dev/null
+++ b/src/modm/driver/display/ssd1306_common.hpp
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2021, Thomas Sommer
+ * Copyright (c) 2023, Raphael Lehmann
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+
+#ifndef MODM_SSD1306_COMMON_HPP
+#define MODM_SSD1306_COMMON_HPP
+
+#include
+#include
+#include
+
+namespace modm
+{
+
+/// @ingroup modm_driver_ssd1306
+struct ssd1306
+{
+protected:
+ enum class
+ FundamentalCommands : uint8_t
+ {
+ ContrastControl = 0x81, // Range 1-255
+ EntireDisplayResumeToRam = 0xA4,
+ EntireDisplayIgnoreRam = 0xA5,
+ NormalDisplay = 0xA6,
+ InvertedDisplay = 0xA7,
+ DisplayOff = 0xAE,
+ DisplayOn = 0xAF,
+ };
+
+ enum class
+ AdressingCommands : uint8_t
+ {
+ MemoryMode = 0x20, // enum MemoryMode
+ // HORIZONTAL and VERTICAL addressing only
+ ColumnAddress = 0x21, // Range 0-127
+ PageAddress = 0x22, // Range 0-7
+ // PAGE addressing only
+ PageStartAddress = 0xB0, // Range 0-7
+ LowerColumnStartAddress = 0x00,
+ HigherColumnStartAddress = 0x10,
+ };
+
+ enum class
+ HardwareConfigCommands : uint8_t
+ {
+ DisplayStartLine = 0x40,
+ SegmentRemap0 = 0xA0,
+ SegmentRemap127 = 0xA1,
+ MultiplexRatio = 0xA8, // Range 16-64
+ ComOutputScanDirectionIncrement = 0xC0,
+ ComOutputScanDirectionDecrement = 0xC8,
+ DisplayOffset = 0xD3, // Range 0-63
+ ComPinsOrder = 0xDA, // enum ComPinsOrder
+ };
+
+ enum class
+ ScrollingCommands : uint8_t
+ {
+ HorizontalScrollRight = 0x26,
+ HorizontalScrollLeft = 0x27,
+ VerticalAndHorizontalScrollRight = 0x29,
+ VerticalAndHorizontalScrollLeft = 0x2A,
+ VerticalScrollArea = 0xA3,
+ DisableScroll = 0x2E,
+ EnableScroll = 0x2F,
+ };
+
+ enum class
+ MemoryMode : uint8_t
+ {
+ HORIZONTAL = 0,
+ VERTICAL = 1,
+ PAGE = 2
+ };
+
+ enum class
+ TimingAndDrivingCommands : uint8_t
+ {
+ ChargePump = 0x8D, // enum ChargePump
+ DisplayClockDivideRatio = 0xD5, // [7:4] Frequency [3:0] Prescaler
+ PreChargePeriod = 0xD9,
+ V_DeselectLevel = 0xDB, // 0: ~0.65 x VCC, 1: 0.71 x VCC, 2: 0.77 x VCC, 3: 0.83 x VCC
+ Nop = 0xE3
+ };
+
+ enum class
+ ChargePump : uint8_t
+ {
+ DISABLE = 0x10,
+ V7_5 = 0x14,
+ V8_5 = 0x94,
+ V9 = 0x95,
+ };
+
+public:
+ enum class
+ ScrollStep : uint8_t
+ {
+ Frames2 = 0b111,
+ Frames3 = 0b100,
+ Frames4 = 0b101,
+ Frames5 = 0b000,
+ Frames25 = 0b110,
+ Frames64 = 0b001,
+ Frames128 = 0b010,
+ Frames256 = 0b011
+ };
+
+ enum class
+ ScrollDirection : uint8_t
+ {
+ Right = std::to_underlying(ScrollingCommands::HorizontalScrollRight),
+ Left = std::to_underlying(ScrollingCommands::HorizontalScrollLeft),
+ // RightBottom = ScrollingCommands::VerticalAndHorizontalScrollRight,
+ // LeftBottom = ScrollingCommands::VerticalAndHorizontalScrollLeft,
+ };
+
+ enum class
+ DisplayMode : uint8_t
+ {
+ Normal = std::to_underlying(FundamentalCommands::NormalDisplay),
+ Inverted = std::to_underlying(FundamentalCommands::InvertedDisplay),
+ };
+
+};
+
+/**
+ * Driver for SSD1306 based OLED-displays using SPI 4-wire mode.
+ *
+ * @author Raphael Lehmann
+ * @ingroup modm_driver_ssd1306
+ */
+template
+class Ssd1306Common : public ssd1306,
+ public MonochromeGraphicDisplayVertical<128, Height>
+{
+ static_assert((Height == 64) or (Height == 32), "Display height must be either 32 or 64 pixel!");
+
+public:
+ virtual modm::ResumableResult
+ setDisplayMode(DisplayMode mode = DisplayMode::Normal)
+ {
+ commandBuffer[0] = std::to_underlying(mode);
+ return writeCommands(1);
+ }
+
+ virtual modm::ResumableResult
+ setContrast(uint8_t contrast = 0xCE)
+ {
+ commandBuffer[0] = std::to_underlying(FundamentalCommands::ContrastControl);
+ commandBuffer[1] = contrast;
+ return writeCommands(2);
+ }
+
+ /**
+ * \param orientation glcd::Orientation::Landscape0 or glcd::Orientation::Landscape180
+ */
+ virtual modm::ResumableResult
+ setOrientation(glcd::Orientation orientation)
+ {
+ if (orientation == glcd::Orientation::Landscape0)
+ {
+ commandBuffer[0] = std::to_underlying(HardwareConfigCommands::SegmentRemap127);
+ commandBuffer[1] = std::to_underlying(HardwareConfigCommands::ComOutputScanDirectionDecrement);
+ }
+ else if (orientation == glcd::Orientation::Landscape180)
+ {
+ commandBuffer[0] = std::to_underlying(HardwareConfigCommands::SegmentRemap0);
+ commandBuffer[1] = std::to_underlying(HardwareConfigCommands::ComOutputScanDirectionIncrement);
+ }
+
+ return writeCommands(2);
+ }
+
+ virtual modm::ResumableResult
+ configureScroll(uint8_t origin, uint8_t size, ScrollDirection direction, ScrollStep steps)
+ {
+
+ commandBuffer[0] = std::to_underlying(ScrollingCommands::DisableScroll); // disableScroll()
+
+ uint8_t beginY = (origin > 7) ? 7 : origin;
+
+ uint8_t endY = ((origin + size) > 7) ? 7 : (origin + size);
+ if (endY < beginY) endY = beginY;
+
+ commandBuffer[1] = std::to_underlying(direction);
+ commandBuffer[2] = 0x00;
+ commandBuffer[3] = beginY;
+ commandBuffer[4] = std::to_underlying(steps);
+ commandBuffer[5] = endY;
+ commandBuffer[6] = 0x00;
+ commandBuffer[7] = 0xFF;
+
+ return writeCommands(8);
+ }
+
+ virtual modm::ResumableResult
+ enableScroll()
+ {
+ commandBuffer[0] = std::to_underlying(ScrollingCommands::EnableScroll);
+ return writeCommands(1);
+ }
+
+ virtual modm::ResumableResult
+ disableScroll()
+ {
+ commandBuffer[0] = std::to_underlying(ScrollingCommands::DisableScroll);
+ return writeCommands(1);
+ }
+
+protected:
+ virtual modm::ResumableResult
+ writeCommands(std::size_t length) = 0;
+
+ //uint8_t commandBuffer[31];
+ std::array commandBuffer;
+};
+
+} // namespace modm
+
+#endif // MODM_SSD1306_COMMON_HPP
diff --git a/src/modm/driver/display/ssd1306_common.lb b/src/modm/driver/display/ssd1306_common.lb
new file mode 100644
index 0000000000..10c5fa5b65
--- /dev/null
+++ b/src/modm/driver/display/ssd1306_common.lb
@@ -0,0 +1,23 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2023, Raphael Lehmann
+#
+# This file is part of the modm project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+# -----------------------------------------------------------------------------
+
+
+def init(module):
+ module.name = ":driver:ssd1306.common"
+ module.description = "Code shared by :ssd1306.i2c and :ssd1306.spi modules"
+
+def prepare(module, options):
+ return True
+
+def build(env):
+ env.outbasepath = "modm/src/modm/driver/display"
+ env.copy("ssd1306_common.hpp")
diff --git a/src/modm/driver/display/ssd1306_i2c.hpp b/src/modm/driver/display/ssd1306_i2c.hpp
new file mode 100644
index 0000000000..7665997a7c
--- /dev/null
+++ b/src/modm/driver/display/ssd1306_i2c.hpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2014, 2016-2017, Sascha Schade
+ * Copyright (c) 2014-2016, 2018, Niklas Hauser
+ * Copyright (c) 2021, Thomas Sommer
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+
+#ifndef MODM_SSD1306_I2C_HPP
+#define MODM_SSD1306_I2C_HPP
+
+#include
+#include
+#include
+#include
+#include "ssd1306_common.hpp"
+#include
+
+namespace modm
+{
+
+/// @ingroup modm_driver_ssd1306
+struct ssd1306_i2c
+{
+public:
+ enum class
+ Transfer : uint8_t
+ {
+ COMMAND_BURST = 0x00,
+ DATA_BURST = 0x40,
+ COMMAND = 0x80,
+ DATA = 0xC0
+ };
+
+ /// @cond
+ class Ssd1306_I2cWriteTransaction : public modm::I2cWriteTransaction
+ {
+ public:
+ Ssd1306_I2cWriteTransaction(uint8_t address);
+
+ bool
+ configureDisplayWrite(const uint8_t *buffer, std::size_t size);
+
+ protected:
+ Writing
+ writing() override;
+
+ void
+ detaching(modm::I2c::DetachCause cause) override;
+
+ inline bool
+ isWritable() const
+ { return !transfer_active; }
+
+ private:
+ uint8_t transfer_type;
+ bool transfer_active;
+ };
+ /// @endcond
+}; // struct ssd1306_i2c
+
+/**
+ * Driver for SSD1306 based OLED-displays using I2C.
+ * This display is only rated to be driven with 400kHz, which limits
+ * the frame rate to about 40Hz.
+ *
+ * @author Niklas Hauser
+ * @author Thomas Sommer
+ * @ingroup modm_driver_ssd1306
+ */
+template
+class Ssd1306I2c : public Ssd1306Common,
+ public I2cDevice
+{
+public:
+ Ssd1306I2c(uint8_t address = 0x3C);
+
+ /// Pings the display
+ bool inline
+ pingBlocking()
+ {
+ return RF_CALL_BLOCKING(this->ping());
+ }
+
+ /// initializes for 3V3 with charge-pump
+ bool inline
+ initializeBlocking()
+ {
+ return RF_CALL_BLOCKING(initialize());
+ }
+
+ /// Update the display with the content of the RAM buffer.
+ void
+ update()
+ {
+ RF_CALL_BLOCKING(startWriteDisplay());
+ }
+
+ /// Use this method to synchronize writing to the displays buffer
+ /// to avoid tearing.
+ /// @return `true` if the frame buffer is not being copied to the display
+ bool
+ isWritable() const
+ {
+ return this->transaction.isWriteable();
+ }
+
+ // MARK: - TASKS
+ /// initializes for 3V3 with charge-pump asynchronously
+ modm::ResumableResult
+ initialize();
+
+ // starts a frame transfer and waits for completion
+ virtual modm::ResumableResult
+ writeDisplay();
+
+protected:
+ modm::ResumableResult
+ writeCommands(std::size_t length) override;
+
+ virtual modm::ResumableResult
+ initializeMemoryMode();
+
+ virtual modm::ResumableResult
+ startWriteDisplay();
+
+ bool transaction_success;
+};
+
+// DEPRECATE 2024q4
+template
+using Ssd1306 [[deprecated("Use `modm::Ssd1306I2c` instead!")]] = Ssd1306I2c;
+
+} // namespace modm
+
+#include "ssd1306_i2c_impl.hpp"
+
+#endif // MODM_SSD1306_I2C_HPP
diff --git a/src/modm/driver/display/ssd1306.lb b/src/modm/driver/display/ssd1306_i2c.lb
similarity index 74%
rename from src/modm/driver/display/ssd1306.lb
rename to src/modm/driver/display/ssd1306_i2c.lb
index 0b138e8811..3c2526657b 100644
--- a/src/modm/driver/display/ssd1306.lb
+++ b/src/modm/driver/display/ssd1306_i2c.lb
@@ -12,19 +12,20 @@
def init(module):
- module.name = ":driver:ssd1306"
- module.description = "SSD1306 Display"
+ module.name = ":driver:ssd1306.i2c"
+ module.description = "SSD1306 Display in I2C mode"
def prepare(module, options):
module.depends(
":architecture:i2c.device",
+ ":driver:ssd1306.common",
":processing:timer",
":ui:display")
return True
def build(env):
env.outbasepath = "modm/src/modm/driver/display"
- env.copy("ssd1306.hpp")
- env.copy("ssd1306_impl.hpp")
- env.copy("ssd1306_register.hpp")
+ env.copy("ssd1306.hpp") # DEPRECATE 2024q4
+ env.copy("ssd1306_i2c.hpp")
+ env.copy("ssd1306_i2c_impl.hpp")
env.copy("ssd1306_i2c_transaction_impl.cpp")
diff --git a/src/modm/driver/display/ssd1306_i2c_impl.hpp b/src/modm/driver/display/ssd1306_i2c_impl.hpp
new file mode 100644
index 0000000000..b33dd25820
--- /dev/null
+++ b/src/modm/driver/display/ssd1306_i2c_impl.hpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2014-2015, Niklas Hauser
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+
+#ifndef MODM_SSD1306_I2C_HPP
+#error "Don't include this file directly, use 'ssd1306_i2c.hpp' instead!"
+#endif
+
+template
+modm::Ssd1306I2c::Ssd1306I2c(uint8_t address)
+ : I2cDevice(address)
+{}
+
+// ----------------------------------------------------------------------------
+// MARK: - Tasks
+template
+modm::ResumableResult
+modm::Ssd1306I2c::initialize()
+{
+ RF_BEGIN();
+ transaction_success = true;
+
+ this->commandBuffer[0] = std::to_underlying(ssd1306::FundamentalCommands::DisplayOff);
+ this->commandBuffer[1] = std::to_underlying(ssd1306::TimingAndDrivingCommands::DisplayClockDivideRatio);
+ this->commandBuffer[2] = 8 << 4; // Frequency (influences scrolling speed too)
+ this->commandBuffer[2] |= 0; // Prescaler
+ this->commandBuffer[3] = std::to_underlying(ssd1306::HardwareConfigCommands::MultiplexRatio);
+ this->commandBuffer[4] = 63; // Range 0-63
+ this->commandBuffer[5] = std::to_underlying(ssd1306::HardwareConfigCommands::DisplayOffset);
+ this->commandBuffer[6] = 0; // Range 0-63
+ transaction_success &= RF_CALL(writeCommands(7));
+
+ RF_CALL(initializeMemoryMode());
+
+ this->commandBuffer[0] = std::to_underlying(ssd1306::TimingAndDrivingCommands::ChargePump);
+ this->commandBuffer[1] = std::to_underlying(ssd1306::ChargePump::V7_5);
+ this->commandBuffer[2] = std::to_underlying(ssd1306::HardwareConfigCommands::SegmentRemap127);
+ this->commandBuffer[3] = std::to_underlying(ssd1306::HardwareConfigCommands::ComOutputScanDirectionDecrement);
+ this->commandBuffer[4] = std::to_underlying(ssd1306::HardwareConfigCommands::DisplayStartLine);
+ this->commandBuffer[4] |= 0; // Range 0-63
+ transaction_success &= RF_CALL(writeCommands(5));
+
+ this->commandBuffer[0] = std::to_underlying(ssd1306::HardwareConfigCommands::ComPinsOrder);
+ this->commandBuffer[1] = Height == 64 ? 0x12 : 0x02;
+ this->commandBuffer[2] = std::to_underlying(ssd1306::FundamentalCommands::ContrastControl);
+ this->commandBuffer[3] = 0xCF; // Strange non-linear beahaviour
+ this->commandBuffer[4] = std::to_underlying(ssd1306::TimingAndDrivingCommands::PreChargePeriod);
+ this->commandBuffer[5] = 1; // [3:0] Phase 1 period
+ this->commandBuffer[5] |= 15 << 4;// [7:4] Phase 2 period
+ transaction_success &= RF_CALL(writeCommands(6));
+
+ this->commandBuffer[0] = std::to_underlying(ssd1306::TimingAndDrivingCommands::V_DeselectLevel);
+ this->commandBuffer[1] = 4 << 4; // [7:4] See Datasheet
+ this->commandBuffer[2] = std::to_underlying(ssd1306::ScrollingCommands::DisableScroll);
+ this->commandBuffer[3] = std::to_underlying(ssd1306::FundamentalCommands::EntireDisplayResumeToRam);
+ this->commandBuffer[4] = std::to_underlying(ssd1306::FundamentalCommands::NormalDisplay);
+ transaction_success &= RF_CALL(writeCommands(5));
+
+ this->commandBuffer[0] = std::to_underlying(ssd1306::FundamentalCommands::DisplayOn);
+ transaction_success &= RF_CALL(writeCommands(1));
+
+ RF_END_RETURN(transaction_success);
+}
+
+/**
+ * @brief MemoryMode::HORIZONTAL and MemoryMode::VERTICAL
+ * have the best performance cause the whole buffer
+ * is send in one transaction.
+ */
+template
+modm::ResumableResult
+modm::Ssd1306I2c::initializeMemoryMode()
+{
+ RF_BEGIN();
+ this->commandBuffer[0] = std::to_underlying(ssd1306::AdressingCommands::MemoryMode);
+ this->commandBuffer[1] = std::to_underlying(ssd1306::MemoryMode::HORIZONTAL);
+ transaction_success &= RF_CALL(writeCommands(2));
+
+ // Default on Power-up - can be omitted
+ this->commandBuffer[0] = std::to_underlying(ssd1306::AdressingCommands::ColumnAddress);
+ this->commandBuffer[1] = 0;
+ this->commandBuffer[2] = 127;
+ this->commandBuffer[3] = std::to_underlying(ssd1306::AdressingCommands::PageAddress);
+ this->commandBuffer[4] = 0;
+ this->commandBuffer[5] = 7;
+ transaction_success &= RF_CALL(writeCommands(6));
+
+ RF_END();
+}
+
+// ----------------------------------------------------------------------------
+template
+modm::ResumableResult
+modm::Ssd1306I2c::startWriteDisplay()
+{
+ RF_BEGIN();
+
+ RF_WAIT_UNTIL(
+ this->transaction.configureDisplayWrite(&this->buffer[0][0], sizeof(this->buffer)) and
+ this->startTransaction());
+
+ RF_END();
+}
+
+template
+modm::ResumableResult
+modm::Ssd1306I2c::writeDisplay()
+{
+ RF_BEGIN();
+
+ RF_CALL(startWriteDisplay());
+
+ RF_WAIT_WHILE(this->isTransactionRunning());
+
+ RF_END_RETURN(this->wasTransactionSuccessful());
+}
+
+// ----------------------------------------------------------------------------
+// MARK: write command
+template
+modm::ResumableResult
+modm::Ssd1306I2c::writeCommands(std::size_t length)
+{
+ RF_BEGIN();
+
+ RF_WAIT_UNTIL(this->startWrite(this->commandBuffer.data(), length));
+
+ RF_WAIT_WHILE(this->isTransactionRunning());
+
+ RF_END_RETURN(this->wasTransactionSuccessful());
+}
diff --git a/src/modm/driver/display/ssd1306_i2c_transaction_impl.cpp b/src/modm/driver/display/ssd1306_i2c_transaction_impl.cpp
index 7ab1876784..02f0a73033 100644
--- a/src/modm/driver/display/ssd1306_i2c_transaction_impl.cpp
+++ b/src/modm/driver/display/ssd1306_i2c_transaction_impl.cpp
@@ -11,26 +11,27 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------
-#include "ssd1306.hpp"
+#include "ssd1306_i2c.hpp"
+#include
// ----------------------------------------------------------------------------
-modm::ssd1306::Ssd1306_I2cWriteTransaction::Ssd1306_I2cWriteTransaction(uint8_t address) :
- I2cWriteTransaction(address), transfer_type(ssd1306::Transfer::COMMAND_BURST), transfer_active(false)
+modm::ssd1306_i2c::Ssd1306_I2cWriteTransaction::Ssd1306_I2cWriteTransaction(uint8_t address) :
+ I2cWriteTransaction(address), transfer_type(std::to_underlying(Transfer::COMMAND_BURST)), transfer_active(false)
{}
bool
-modm::ssd1306::Ssd1306_I2cWriteTransaction::configureDisplayWrite(const uint8_t *buffer, std::size_t size)
+modm::ssd1306_i2c::Ssd1306_I2cWriteTransaction::configureDisplayWrite(const uint8_t *buffer, std::size_t size)
{
if (I2cWriteTransaction::configureWrite(buffer, size))
{
- transfer_type = Transfer::DATA_BURST;
+ transfer_type = std::to_underlying(Transfer::DATA_BURST);
return true;
}
return false;
}
modm::I2cTransaction::Writing
-modm::ssd1306::Ssd1306_I2cWriteTransaction::writing()
+modm::ssd1306_i2c::Ssd1306_I2cWriteTransaction::writing()
{
if (!transfer_active)
{
@@ -41,12 +42,12 @@ modm::ssd1306::Ssd1306_I2cWriteTransaction::writing()
}
void
-modm::ssd1306::Ssd1306_I2cWriteTransaction::detaching(modm::I2c::DetachCause cause)
+modm::ssd1306_i2c::Ssd1306_I2cWriteTransaction::detaching(modm::I2c::DetachCause cause)
{
I2cWriteTransaction::detaching(cause);
if (transfer_active or (cause != modm::I2c::DetachCause::NormalStop))
{
- transfer_type = Transfer::COMMAND_BURST;
+ transfer_type = std::to_underlying(Transfer::COMMAND_BURST);
transfer_active = false;
}
}
diff --git a/src/modm/driver/display/ssd1306_impl.hpp b/src/modm/driver/display/ssd1306_impl.hpp
deleted file mode 100644
index cde8634f40..0000000000
--- a/src/modm/driver/display/ssd1306_impl.hpp
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (c) 2014-2015, Niklas Hauser
- *
- * This file is part of the modm project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-// ----------------------------------------------------------------------------
-
-#ifndef MODM_SSD1306_HPP
-#error "Don't include this file directly, use 'ssd1306.hpp' instead!"
-#endif
-
-template
-modm::Ssd1306::Ssd1306(uint8_t address)
- : I2cDevice(address)
-{}
-
-// ----------------------------------------------------------------------------
-// MARK: - Tasks
-template
-modm::ResumableResult
-modm::Ssd1306::initialize()
-{
- RF_BEGIN();
- transaction_success = true;
-
- commandBuffer[0] = FundamentalCommands::DisplayOff;
- commandBuffer[1] = TimingAndDrivingCommands::DisplayClockDivideRatio;
- commandBuffer[2] = 8 << 4; // Frequency (influences scrolling speed too)
- commandBuffer[2] |= 0; // Prescaler
- commandBuffer[3] = HardwareConfigCommands::MultiplexRatio;
- commandBuffer[4] = 63; // Range 0-63
- commandBuffer[5] = HardwareConfigCommands::DisplayOffset;
- commandBuffer[6] = 0; // Range 0-63
- transaction_success &= RF_CALL(writeCommands(7));
-
- RF_CALL(initializeMemoryMode());
-
- commandBuffer[0] = TimingAndDrivingCommands::ChargePump;
- commandBuffer[1] = ChargePump::V7_5;
- commandBuffer[2] = HardwareConfigCommands::SegmentRemap127;
- commandBuffer[3] = HardwareConfigCommands::ComOutputScanDirectionDecrement;
- commandBuffer[4] = HardwareConfigCommands::DisplayStartLine;
- commandBuffer[4] |= 0; // Range 0-63
- transaction_success &= RF_CALL(writeCommands(5));
-
- commandBuffer[0] = HardwareConfigCommands::ComPinsOrder;
- commandBuffer[1] = Height == 64 ? 0x12 : 0x02;
- commandBuffer[2] = FundamentalCommands::ContrastControl;
- commandBuffer[3] = 0xCF; // Strange non-linear beahaviour
- commandBuffer[4] = TimingAndDrivingCommands::PreChargePeriod;
- commandBuffer[5] = 1; // [3:0] Phase 1 period
- commandBuffer[5] |= 15 << 4;// [7:4] Phase 2 period
- transaction_success &= RF_CALL(writeCommands(6));
-
- commandBuffer[0] = TimingAndDrivingCommands::V_DeselectLevel;
- commandBuffer[1] = 4 << 4; // [7:4] See Datasheet
- commandBuffer[2] = ScrollingCommands::DisableScroll;
- commandBuffer[3] = FundamentalCommands::EntireDisplayResumeToRam;
- commandBuffer[4] = FundamentalCommands::NormalDisplay;
- transaction_success &= RF_CALL(writeCommands(5));
-
- commandBuffer[0] = FundamentalCommands::DisplayOn;
- transaction_success &= RF_CALL(writeCommands(1));
-
- RF_END_RETURN(transaction_success);
-}
-
-/**
- * @brief MemoryMode::HORIZONTAL and MemoryMode::VERTICAL
- * have the best performance cause the whole buffer
- * is send in one transaction.
- */
-template
-modm::ResumableResult
-modm::Ssd1306::initializeMemoryMode()
-{
- RF_BEGIN();
- commandBuffer[0] = AdressingCommands::MemoryMode;
- commandBuffer[1] = MemoryMode::HORIZONTAL;
- transaction_success &= RF_CALL(writeCommands(2));
-
- // Default on Power-up - can be omitted
- commandBuffer[0] = AdressingCommands::ColumnAddress;
- commandBuffer[1] = 0;
- commandBuffer[2] = 127;
- commandBuffer[3] = AdressingCommands::PageAddress;
- commandBuffer[4] = 0;
- commandBuffer[5] = 7;
- transaction_success &= RF_CALL(writeCommands(6));
-
- RF_END();
-}
-
-// ----------------------------------------------------------------------------
-template
-modm::ResumableResult
-modm::Ssd1306::startWriteDisplay()
-{
- RF_BEGIN();
-
- RF_WAIT_UNTIL(
- this->transaction.configureDisplayWrite((uint8_t*)(&this->buffer), sizeof(this->buffer)) and
- this->startTransaction());
-
- RF_END();
-}
-
-template
-modm::ResumableResult
-modm::Ssd1306::writeDisplay()
-{
- RF_BEGIN();
-
- RF_CALL(startWriteDisplay());
-
- RF_WAIT_WHILE(this->isTransactionRunning());
-
- RF_END_RETURN(this->wasTransactionSuccessful());
-}
-
-template
-modm::ResumableResult
-modm::Ssd1306::setOrientation(glcd::Orientation orientation)
-{
- RF_BEGIN();
-
- if (orientation == glcd::Orientation::Landscape0)
- {
- commandBuffer[0] = HardwareConfigCommands::SegmentRemap127;
- commandBuffer[1] = HardwareConfigCommands::ComOutputScanDirectionDecrement;
- }
- else if (orientation == glcd::Orientation::Landscape180)
- {
- commandBuffer[0] = HardwareConfigCommands::SegmentRemap0;
- commandBuffer[1] = HardwareConfigCommands::ComOutputScanDirectionIncrement;
- }
-
- RF_END_RETURN_CALL(writeCommands(2));
-}
-
-template
-modm::ResumableResult
-modm::Ssd1306::configureScroll(uint8_t origin, uint8_t size,
- ScrollDirection direction, ScrollStep steps)
-{
- RF_BEGIN();
-
- if (!RF_CALL(disableScroll()))
- RF_RETURN(false);
-
- {
- uint8_t beginY = (origin > 7) ? 7 : origin;
-
- uint8_t endY = ((origin + size) > 7) ? 7 : (origin + size);
- if (endY < beginY) endY = beginY;
-
- commandBuffer[0] = uint8_t(direction);
- commandBuffer[1] = 0x00;
- commandBuffer[2] = beginY;
- commandBuffer[3] = uint8_t(steps);
- commandBuffer[4] = endY;
- commandBuffer[5] = 0x00;
- commandBuffer[6] = 0xFF;
- }
-
- RF_END_RETURN_CALL(writeCommands(7));
-}
-
-// ----------------------------------------------------------------------------
-// MARK: write command
-template
-modm::ResumableResult
-modm::Ssd1306::writeCommands(std::size_t length)
-{
- RF_BEGIN();
-
- RF_WAIT_UNTIL(this->startWrite(commandBuffer, length));
-
- RF_WAIT_WHILE(this->isTransactionRunning());
-
- RF_END_RETURN(this->wasTransactionSuccessful());
-}
diff --git a/src/modm/driver/display/ssd1306_register.hpp b/src/modm/driver/display/ssd1306_register.hpp
deleted file mode 100644
index ef6916f8a6..0000000000
--- a/src/modm/driver/display/ssd1306_register.hpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 2021, Thomas Sommer
- *
- * This file is part of the modm project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-// ----------------------------------------------------------------------------
-
-#pragma once
-
-namespace modm
-{
-
-/// @ingroup modm_driver_ssd1306
-struct ssd1306_register
-{
-protected:
- enum Transfer : uint8_t
- {
- COMMAND_BURST = 0x00,
- DATA_BURST = 0x40,
- COMMAND = 0x80,
- DATA = 0xC0
- };
-
- enum FundamentalCommands : uint8_t
- {
- ContrastControl = 0x81, // Range 1-255
- EntireDisplayResumeToRam = 0xA4,
- EntireDisplayIgnoreRam = 0xA5,
- NormalDisplay = 0xA6,
- InvertedDisplay = 0xA7,
- DisplayOff = 0xAE,
- DisplayOn = 0xAF,
- };
-
- enum AdressingCommands : uint8_t
- {
- MemoryMode = 0x20, // enum MemoryMode
- // HORIZONTAL and VERTICAL addressing only
- ColumnAddress = 0x21, // Range 0-127
- PageAddress = 0x22, // Range 0-7
- // PAGE addressing only
- PageStartAddress = 0xB0, // Range 0-7
- LowerColumnStartAddress = 0x00,
- HigherColumnStartAddress = 0x10,
- };
-
- enum HardwareConfigCommands : uint8_t
- {
- DisplayStartLine = 0x40,
- SegmentRemap0 = 0xA0,
- SegmentRemap127 = 0xA1,
- MultiplexRatio = 0xA8, // Range 16-64
- ComOutputScanDirectionIncrement = 0xC0,
- ComOutputScanDirectionDecrement = 0xC8,
- DisplayOffset = 0xD3, // Range 0-63
- ComPinsOrder = 0xDA, // enum ComPinsOrder
- };
-
- enum ScrollingCommands : uint8_t
- {
- HorizontalScrollRight = 0x26,
- HorizontalScrollLeft = 0x27,
- VerticalAndHorizontalScrollRight = 0x29,
- VerticalAndHorizontalScrollLeft = 0x2A,
- VerticalScrollArea = 0xA3,
- DisableScroll = 0x2E,
- EnableScroll = 0x2F,
- };
-
- enum MemoryMode : uint8_t
- {
- HORIZONTAL = 0,
- VERTICAL = 1,
- PAGE = 2
- };
-
- enum TimingAndDrivingCommands : uint8_t
- {
- ChargePump = 0x8D, // enum ChargePump
- DisplayClockDivideRatio = 0xD5, // [7:4] Frequency [3:0] Prescaler
- PreChargePeriod = 0xD9,
- V_DeselectLevel = 0xDB, // 0: ~0.65 x VCC, 1: 0.71 x VCC, 2: 0.77 x VCC, 3: 0.83 x VCC
- Nop = 0xE3
- };
-
- enum ChargePump : uint8_t
- {
- DISABLE = 0x00,
- V7_5 = 0x14,
- V8_5 = 0x94,
- V9 = 0x95,
- };
-};
-
-} // namespace modm
diff --git a/src/modm/driver/display/ssd1306_spi.hpp b/src/modm/driver/display/ssd1306_spi.hpp
new file mode 100644
index 0000000000..8411f907a9
--- /dev/null
+++ b/src/modm/driver/display/ssd1306_spi.hpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2014, 2016-2017, Sascha Schade
+ * Copyright (c) 2014-2016, 2018, Niklas Hauser
+ * Copyright (c) 2021, Thomas Sommer
+ * Copyright (c) 2023, Raphael Lehmann
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+
+#ifndef MODM_SSD1306_SPI_HPP
+#define MODM_SSD1306_SPI_HPP
+
+#include
+#include
+#include
+#include
+#include "ssd1306_common.hpp"
+#include
+
+namespace modm
+{
+
+/**
+ * Driver for SSD1306 based OLED-displays using SPI 4-wire mode.
+ *
+ * @author Raphael Lehmann
+ * @ingroup modm_driver_ssd1306
+ */
+template
+class Ssd1306Spi : public Ssd1306Common,
+ public SpiDevice,
+ protected modm::NestedResumable<2>
+{
+public:
+ enum class
+ InitSequences : uint8_t
+ {
+ Hp12832_02, /// HP12832-02 display module, 0.91inch, 128x32px, 4-wire
+ /// SPI, blue, external 7.5V supply
+ };
+
+ modm::ResumableResult
+ initialize(InitSequences initSeq = InitSequences::Hp12832_02);
+
+ /// Update the display with the content of the RAM buffer
+ modm::ResumableResult
+ writeDisplay();
+
+ /// Update the display with the content of the RAM buffer
+ /// @warning This function is blocking as long as the transfer of the
+ /// whole display buffer via SPI takes.
+ // Better use @see writeDisplay() instead.
+ void
+ update()
+ {
+ RF_CALL_BLOCKING(writeDisplay());
+ }
+
+protected:
+ modm::ResumableResult
+ writeCommands(std::size_t length) override;
+};
+
+} // namespace modm
+
+#include "ssd1306_spi_impl.hpp"
+
+#endif // MODM_SSD1306_SPI_HPP
diff --git a/src/modm/driver/display/ssd1306_spi.lb b/src/modm/driver/display/ssd1306_spi.lb
new file mode 100644
index 0000000000..a4aa60430e
--- /dev/null
+++ b/src/modm/driver/display/ssd1306_spi.lb
@@ -0,0 +1,29 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2023, Raphael Lehmann
+#
+# This file is part of the modm project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+# -----------------------------------------------------------------------------
+
+
+def init(module):
+ module.name = ":driver:ssd1306.spi"
+ module.description = "SSD1306 Display in SPI 4-wire mode"
+
+def prepare(module, options):
+ module.depends(
+ ":architecture:spi.device",
+ ":driver:ssd1306.common",
+ ":processing:timer",
+ ":ui:display")
+ return True
+
+def build(env):
+ env.outbasepath = "modm/src/modm/driver/display"
+ env.copy("ssd1306_spi.hpp")
+ env.copy("ssd1306_spi_impl.hpp")
diff --git a/src/modm/driver/display/ssd1306_spi_impl.hpp b/src/modm/driver/display/ssd1306_spi_impl.hpp
new file mode 100644
index 0000000000..07e2b4bd1a
--- /dev/null
+++ b/src/modm/driver/display/ssd1306_spi_impl.hpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2014-2015, Niklas Hauser
+ * Copyright (c) 2023, Raphael Lehmann
+ *
+ * This file is part of the modm project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+// ----------------------------------------------------------------------------
+
+#ifndef MODM_SSD1306_SPI_HPP
+#error "Don't include this file directly, use 'ssd1306_spi.hpp' instead!"
+#endif
+
+namespace modm
+{
+
+template
+ResumableResult
+Ssd1306Spi::initialize(InitSequences initSeq)
+{
+ RF_BEGIN();
+
+ this->attachConfigurationHandler([]() {
+ SpiMaster::setDataMode(SpiMaster::DataMode::Mode0);
+ SpiMaster::setDataOrder(SpiMaster::DataOrder::MsbFirst);
+ });
+ Cs::setOutput(modm::Gpio::High);
+ Dc::setOutput();
+
+ if (initSeq == InitSequences::Hp12832_02)
+ {
+ // Initialize sequence from HP12832-02-TSBG12P091-A-VER1.0.pdf page 14
+
+ this->commandBuffer[0] = std::to_underlying(ssd1306::FundamentalCommands::DisplayOff);
+ this->commandBuffer[1] = std::to_underlying(ssd1306::TimingAndDrivingCommands::DisplayClockDivideRatio);
+ this->commandBuffer[2] = 0x80; // 0x90 or 0x80 (page 14)?
+ this->commandBuffer[3] = std::to_underlying(ssd1306::HardwareConfigCommands::MultiplexRatio);
+ this->commandBuffer[4] = 0x1F; // 0x3F or 0x1F (page 14)?
+ this->commandBuffer[5] = std::to_underlying(ssd1306::HardwareConfigCommands::DisplayOffset);
+ this->commandBuffer[6] = 0;
+ this->commandBuffer[7] = std::to_underlying(ssd1306::AdressingCommands::MemoryMode);
+ this->commandBuffer[8] = std::to_underlying(ssd1306::MemoryMode::HORIZONTAL);
+ this->commandBuffer[9] = std::to_underlying(ssd1306::AdressingCommands::ColumnAddress);
+ this->commandBuffer[10] = 0;
+ this->commandBuffer[11] = 127;
+ this->commandBuffer[12] = std::to_underlying(ssd1306::AdressingCommands::PageAddress);
+ this->commandBuffer[13] = 0;
+ this->commandBuffer[14] = (Height == 64) ? 7 : 3;
+ this->commandBuffer[15] = std::to_underlying(ssd1306::HardwareConfigCommands::DisplayStartLine) | 0;
+ this->commandBuffer[16] = std::to_underlying(ssd1306::HardwareConfigCommands::SegmentRemap0);
+ this->commandBuffer[17] = std::to_underlying(ssd1306::HardwareConfigCommands::ComOutputScanDirectionIncrement);
+ this->commandBuffer[18] = std::to_underlying(ssd1306::HardwareConfigCommands::ComPinsOrder);
+ this->commandBuffer[19] = 0x02;
+ this->commandBuffer[20] = std::to_underlying(ssd1306::FundamentalCommands::ContrastControl);
+ this->commandBuffer[21] = 0x8F;
+ this->commandBuffer[22] = std::to_underlying(ssd1306::TimingAndDrivingCommands::PreChargePeriod);
+ this->commandBuffer[23] = 0x1F;
+ this->commandBuffer[24] = std::to_underlying(ssd1306::TimingAndDrivingCommands::V_DeselectLevel);
+ this->commandBuffer[25] = 0x30;
+ this->commandBuffer[26] = std::to_underlying(ssd1306::FundamentalCommands::EntireDisplayResumeToRam);
+ this->commandBuffer[27] = std::to_underlying(ssd1306::FundamentalCommands::NormalDisplay);
+ this->commandBuffer[28] = std::to_underlying(ssd1306::TimingAndDrivingCommands::ChargePump);
+ this->commandBuffer[29] = std::to_underlying(ssd1306::ChargePump::DISABLE);
+ this->commandBuffer[30] = std::to_underlying(ssd1306::FundamentalCommands::DisplayOn);
+
+ RF_RETURN_CALL(writeCommands(31));
+ }
+ else {
+ RF_RETURN(false);
+ }
+
+ RF_END();
+}
+
+template
+ResumableResult
+Ssd1306Spi::writeDisplay()
+{
+ RF_BEGIN();
+
+ RF_WAIT_UNTIL(this->acquireMaster());
+ Cs::reset();
+
+ Dc::set();
+
+ RF_CALL(SpiMaster::transfer((uint8_t*)(&this->buffer), nullptr, sizeof(this->buffer)));
+
+ if (this->releaseMaster()) {
+ Cs::set();
+ }
+
+ RF_END_RETURN(true);
+}
+
+template
+ResumableResult
+Ssd1306Spi::writeCommands(std::size_t length)
+{
+ RF_BEGIN();
+
+ RF_WAIT_UNTIL(this->acquireMaster());
+ Cs::reset();
+
+ Dc::reset();
+
+ RF_CALL(SpiMaster::transfer(this->commandBuffer.data(), nullptr, length));
+
+ if (this->releaseMaster()) {
+ Cs::set();
+ }
+
+ RF_END_RETURN(true);
+}
+
+} // namespace modm
diff --git a/src/modm/driver/module.lb b/src/modm/driver/module.lb
index ee5b6c7449..c6074c561a 100644
--- a/src/modm/driver/module.lb
+++ b/src/modm/driver/module.lb
@@ -16,6 +16,11 @@ def init(module):
module.description = "External Device Drivers"
def prepare(module, options):
+ # DEPRECATED: 2024q4
+ # module.add_alias(
+ # Alias(name="ssd1306",
+ # destination=":driver:ssd1306.i2c",
+ # description="DEPRECATED: Please use :driver:ssd1306.i2c instead."))
return True
def build(env):
diff --git a/tools/scripts/synchronize_docs.py b/tools/scripts/synchronize_docs.py
index 969051ecd1..363ec920e3 100755
--- a/tools/scripts/synchronize_docs.py
+++ b/tools/scripts/synchronize_docs.py
@@ -74,10 +74,9 @@ def name(raw_name):
.replace("-BITBANG", " BitBang")\
.replace("GPIO-SAMPLER", "Gpio Sampler")\
.replace("BLOCK-", "")\
- .replace("SPI-FLASH", "SPI Flash")\
- .replace("-SPI", "")
+ .replace("SPI-FLASH", "SPI Flash")
if result in ["DEVICE", "LIS3-TRANSPORT", "MEMORY-BUS", "TERMINAL", "ALLOCATOR",
- "MIRROR", "ADC-SAMPLER", "FAT", "HEAP", "--PYCACHE--", "FILE", "SPI-STACK-FLASH"]:
+ "MIRROR", "ADC-SAMPLER", "FAT", "HEAP", "--PYCACHE--", "FILE", "SPI-STACK-FLASH", "SSD1306-COMMON"]:
return None
return result