Compare commits

...

7 Commits

4 changed files with 307 additions and 47 deletions

172
eink.hpp
View File

@@ -6,8 +6,10 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <cstring>
#include "eink_spi.hpp" #include "eink_spi.hpp"
#include "font.hpp"
#include "otp.hpp" #include "otp.hpp"
#include "../clock.hpp" #include "../clock.hpp"
@@ -21,6 +23,9 @@ template <std::uint16_t Width, std::uint16_t Height, typename Spi, io::P RstPin,
class Eink { class Eink {
using word_t = typename Spi::word_t; using word_t = typename Spi::word_t;
struct original_lut_tag {
};
static io::Pin<RstPin> m_rst; static io::Pin<RstPin> m_rst;
static io::Pin<BusyPin> m_busy; static io::Pin<BusyPin> m_busy;
@@ -37,6 +42,7 @@ class Eink {
WRITE_RAM_RED = 0x26, WRITE_RAM_RED = 0x26,
READ_RAM = 0x27, READ_RAM = 0x27,
LOAD_OTP_TO_RAM = 0x31, LOAD_OTP_TO_RAM = 0x31,
WRITE_LUT = 0x32,
BORDER_WAVEFORM_CONTROL = 0x3C, BORDER_WAVEFORM_CONTROL = 0x3C,
READ_RAM_CHANNEL = 0x41, READ_RAM_CHANNEL = 0x41,
SET_RAM_X_ADDR_POSITIONS = 0x44, SET_RAM_X_ADDR_POSITIONS = 0x44,
@@ -77,8 +83,9 @@ class Eink {
sendData(0x01); sendData(0x01);
setDataEntryMode(RamDirection::DECREMENT, RamDirection::INCREMENT, FastestMovingIndex::X); setDataEntryMode(RamDirection::DECREMENT, RamDirection::INCREMENT, FastestMovingIndex::X);
setRamRange();
setRamRange({Width / 8 - 1, 0}, {0, Height - 1}); setRamXPos();
setRamYPos();
sendCommand(Cmd::BORDER_WAVEFORM_CONTROL); sendCommand(Cmd::BORDER_WAVEFORM_CONTROL);
sendData(0x05); sendData(0x05);
@@ -86,9 +93,6 @@ class Eink {
sendCommand(Cmd::READ_TEMPERATURE_SENSOR); sendCommand(Cmd::READ_TEMPERATURE_SENSOR);
sendData(0x80); sendData(0x80);
setRamXPos(Width / 8 - 1);
setRamYPos(0);
waitUntilIdle(); waitUntilIdle();
} }
@@ -138,13 +142,34 @@ class Eink {
waitUntilIdle(); waitUntilIdle();
} }
static void update()
{
update(original_lut_tag{});
}
template <typename Lut = original_lut_tag>
static void update(const Lut &lut)
{
constexpr auto USE_ORIGINAL_LUT = std::is_same_v<Lut, original_lut_tag>;
if constexpr (!USE_ORIGINAL_LUT) {
writeLut(lut);
}
sendCommand(Cmd::DISPLAY_UPDATE_CONTROL_2);
sendData(USE_ORIGINAL_LUT ? 0xF7 : 0xC7);
sendCommand(Cmd::UPDATE_DISPLAY);
waitUntilIdle();
}
template <typename RleImage> template <typename RleImage>
static void draw(const RleImage &rleImage) static void draw(const RleImage &rleImage)
{ {
constexpr auto sendImageChannel = [](const auto command, const auto &image) { constexpr auto sendImageChannel = [](const auto command, const auto &image) {
using image_t = std::remove_cvref_t<decltype(image)>;
sendCommand(command); sendCommand(command);
for (auto j = std::size_t{0}; j < image.size(); ++j) { for (auto j = std::size_t{0}; j < std::tuple_size_v<image_t>; ++j) {
const auto [count, data] = flash::load(image[j]); const auto [count, data] = flash::loadLike<RleImage>(image[j]);
for (auto i = std::uint16_t{0}; i < count; ++i) { for (auto i = std::uint16_t{0}; i < count; ++i) {
if (command == Cmd::WRITE_RAM_BLACK) { if (command == Cmd::WRITE_RAM_BLACK) {
sendData(data); sendData(data);
@@ -155,13 +180,8 @@ class Eink {
} }
}; };
sendImageChannel(Cmd::WRITE_RAM_BLACK, std::get<0>(rleImage)); sendImageChannel(Cmd::WRITE_RAM_BLACK, std::get<0>(rleImage.value));
sendImageChannel(Cmd::WRITE_RAM_RED, std::get<1>(rleImage)); sendImageChannel(Cmd::WRITE_RAM_RED, std::get<1>(rleImage.value));
sendCommand(Cmd::DISPLAY_UPDATE_CONTROL_2);
sendData(0xF7);
sendCommand(Cmd::UPDATE_DISPLAY);
waitUntilIdle();
} }
static void clear(const Color color = Color::WHITE) static void clear(const Color color = Color::WHITE)
@@ -188,11 +208,109 @@ class Eink {
for (auto i = std::uint16_t{0}; i < Width * Height / 8; i++) { for (auto i = std::uint16_t{0}; i < Width * Height / 8; i++) {
sendData(fillData.second); sendData(fillData.second);
} }
}
sendCommand(Cmd::DISPLAY_UPDATE_CONTROL_2); static void drawText(const std::pair<std::uint8_t, std::uint8_t> &pos, const char *text,
sendData(0xF7); const Color textColor = Color::BLACK, const Color backgroundColor = Color::WHITE,
sendCommand(Cmd::UPDATE_DISPLAY); const std::uint8_t scaling = 1)
waitUntilIdle(); {
const auto textLength = std::strlen(text);
constexpr auto getXScreenCoordinates = [](const std::uint8_t pos) { return (Width - pos - 1) / 8; };
constexpr auto flipEndianness = [](const std::uint8_t value) {
auto flippedVal = std::uint8_t{0};
for (auto i = 0; i < 8; ++i) {
const auto oldBit = (value >> i) & 1;
flippedVal |= oldBit << (8 - i - 1);
}
return flippedVal;
};
const auto adjustColor = [&](const auto &data, const auto command) {
auto backgroundData = data;
auto outData = data & 0x00;
if (command == Cmd::WRITE_RAM_BLACK) {
if (backgroundColor == Color::BLACK) {
backgroundData = 0x00;
} else if (backgroundColor == Color::RED || backgroundColor == Color::WHITE) {
backgroundData = 0xFF;
}
if (textColor == Color::BLACK) {
outData = backgroundData & ~data;
} else if (textColor == Color::RED || textColor == Color::WHITE) {
outData = backgroundData | data;
}
} else {
if (backgroundColor == Color::BLACK || backgroundColor == Color::WHITE) {
backgroundData = 0x00;
} else if (backgroundColor == Color::RED) {
backgroundData = 0xFF;
}
if (textColor == Color::BLACK || textColor == Color::WHITE) {
outData = backgroundData & ~data;
} else if (textColor == Color::RED) {
outData = backgroundData | data;
}
}
return outData;
};
const auto sendChannel = [&](const auto command) {
for (auto i = std::size_t{0}; i < textLength; ++i) {
const auto posX = pos.first + i * 8 * scaling;
const auto screenPosX = getXScreenCoordinates(posX);
setRamRange({screenPosX, screenPosX - (scaling - 1)}, {pos.second, pos.second + 8 * scaling - 1});
setRamXPos(screenPosX);
setRamYPos(pos.second);
sendCommand(command);
for (auto j = std::uint8_t{0}; j < 8; ++j) {
const auto fontByte = flash::loadLike<decltype(FONT_8X8)>(FONT_8X8.value[text[i]][j]);
static_assert(std::is_same_v<std::remove_cvref_t<decltype(fontByte)>, std::uint8_t>);
const auto dataByte = adjustColor(flipEndianness(fontByte), command);
auto scaledByte = std::uint8_t{0};
auto bitCounter = 0;
for (auto sy = std::uint8_t{0}; sy < scaling; ++sy) {
for (auto b = std::uint8_t{0}; b < 8; ++b) {
const auto currentBit = dataByte >> (8 - b - 1) & 1;
for (auto sx = std::uint8_t{0}; sx < scaling; ++sx) {
scaledByte |= currentBit << (8 - bitCounter - 1);
if (++bitCounter == 8) {
sendData(scaledByte);
scaledByte = 0;
bitCounter = 0;
}
}
}
}
}
}
};
sendChannel(Cmd::WRITE_RAM_BLACK);
sendChannel(Cmd::WRITE_RAM_RED);
setRamRange();
setRamXPos();
setRamYPos();
}
template <typename Lut>
static void writeLut(const Lut &lut)
{
static_assert(sizeof(lut) == sizeof(Waveform), "Invalid LUT size");
sendCommand(Cmd::WRITE_LUT);
for (auto i = std::size_t{0}; i < sizeof(lut); ++i) {
const auto lutByte = lut[i];
static_assert(std::is_same_v<std::byte, std::remove_cvref_t<decltype(lutByte)>>, "Invalid LUT value type");
sendData(static_cast<word_t>(lutByte));
}
} }
static void autoPatternFill() static void autoPatternFill()
@@ -210,11 +328,6 @@ class Eink {
sendCommand(BLACK_PATTERN_FILL_CMD); sendCommand(BLACK_PATTERN_FILL_CMD);
sendData(BLACK_PATTERN); sendData(BLACK_PATTERN);
waitUntilIdle(); waitUntilIdle();
sendCommand(Cmd::DISPLAY_UPDATE_CONTROL_2);
sendData(0xF7);
sendCommand(Cmd::UPDATE_DISPLAY);
waitUntilIdle();
} }
static void setDataEntryMode(const RamDirection &xDir = RamDirection::INCREMENT, static void setDataEntryMode(const RamDirection &xDir = RamDirection::INCREMENT,
@@ -229,8 +342,8 @@ class Eink {
sendData(setting); sendData(setting);
} }
static void setRamRange(const std::pair<std::uint8_t, std::uint8_t> &xrange, static void setRamRange(const std::pair<std::uint8_t, std::uint8_t> &xrange = {Width / 8 - 1, 0},
const std::pair<std::uint16_t, std::uint16_t> &yrange) const std::pair<std::uint16_t, std::uint16_t> &yrange = {0, Height - 1})
{ {
sendCommand(Cmd::SET_RAM_X_ADDR_POSITIONS); sendCommand(Cmd::SET_RAM_X_ADDR_POSITIONS);
sendData(xrange.first & 0b00111111); sendData(xrange.first & 0b00111111);
@@ -243,13 +356,13 @@ class Eink {
sendData((yrange.second >> 8) & 0b1); sendData((yrange.second >> 8) & 0b1);
} }
static void setRamXPos(const std::uint8_t pos) static void setRamXPos(const std::uint8_t pos = Width / 8 - 1)
{ {
sendCommand(Cmd::SET_RAM_X_ADDR); sendCommand(Cmd::SET_RAM_X_ADDR);
sendData(pos & 0b00111111); sendData(pos & 0b00111111);
} }
static void setRamYPos(const std::uint16_t pos) static void setRamYPos(const std::uint16_t pos = 0)
{ {
sendCommand(Cmd::SET_RAM_Y_ADDR); sendCommand(Cmd::SET_RAM_Y_ADDR);
sendData(pos & 0xFF); sendData(pos & 0xFF);
@@ -279,11 +392,6 @@ class Eink {
sendData(0x00); sendData(0x00);
} }
sendCommand(Cmd::DISPLAY_UPDATE_CONTROL_2);
sendData(0xF7);
sendCommand(Cmd::UPDATE_DISPLAY);
waitUntilIdle();
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
sendCommand(Cmd::DISPLAY_UPDATE_CONTROL_2); sendCommand(Cmd::DISPLAY_UPDATE_CONTROL_2);

View File

@@ -15,17 +15,26 @@ namespace eink {
template <io::P SclPin, io::P SdaPin, io::P CsPin, io::P DcPin, std::uint32_t Freq = 100'000> template <io::P SclPin, io::P SdaPin, io::P CsPin, io::P DcPin, std::uint32_t Freq = 100'000>
class Spi { class Spi {
template <std::uint32_t StaticClockCycles>
static constexpr double calcClockDelay() static constexpr double calcClockDelay()
{ {
// TODO: Verify static clock cycles constexpr auto maxFrequency = F_CPU / StaticClockCycles;
constexpr auto staticClockCycles = 10;
constexpr auto maxFrequency = F_CPU / staticClockCycles;
static_assert(Freq <= maxFrequency, "SPI frequency not achievable using selected clock speed"); static_assert(Freq <= maxFrequency, "SPI frequency not achievable using selected clock speed");
constexpr auto staticDelay = (1.0 * 1000 * 1000 / maxFrequency); constexpr auto staticDelay = (1.0 * 1000 * 1000 / maxFrequency);
const auto delayUs = ((1.0 * 1000 * 1000 / Freq) - staticDelay) / 2; const auto delayUs = ((1.0 * 1000 * 1000 / Freq) - staticDelay) / 2;
return (delayUs > 0 ? delayUs : 0); return (delayUs > 0 ? delayUs : 0);
} }
static constexpr double calcWriteClockDelay()
{
return calcClockDelay<8>();
}
static constexpr double calcReadClockDelay()
{
return calcClockDelay<5>();
}
static constexpr auto THREE_WIRE_SPI = (DcPin == io::P::NONE); static constexpr auto THREE_WIRE_SPI = (DcPin == io::P::NONE);
public: public:
@@ -42,7 +51,7 @@ class Spi {
sm_dc.dir(io::Dir::OUT); sm_dc.dir(io::Dir::OUT);
} }
static void write(const word_t data, const bool command = true) static void write(word_t data, const bool command = true)
{ {
constexpr auto numBits = THREE_WIRE_SPI ? 9 : 8; constexpr auto numBits = THREE_WIRE_SPI ? 9 : 8;
@@ -66,10 +75,10 @@ class Spi {
sm_sda = data >> bitPos & 1; sm_sda = data >> bitPos & 1;
_delay_us(DELAY_US); _delay_us(WRITE_DELAY_US);
sm_scl.toggle(); sm_scl.toggle();
_delay_us(DELAY_US); _delay_us(WRITE_DELAY_US);
sm_scl.toggle(); sm_scl.toggle();
}, },
std::make_index_sequence<numBits>{}); std::make_index_sequence<numBits>{});
@@ -85,9 +94,9 @@ class Spi {
if constexpr (THREE_WIRE_SPI) { if constexpr (THREE_WIRE_SPI) {
sm_sda = true; sm_sda = true;
_delay_us(DELAY_US); _delay_us(READ_DELAY_US);
sm_scl.toggle(); sm_scl.toggle();
_delay_us(DELAY_US); _delay_us(READ_DELAY_US);
sm_scl.toggle(); sm_scl.toggle();
} }
@@ -102,13 +111,13 @@ class Spi {
[&](const auto idx) { [&](const auto idx) {
constexpr auto bitPos = numBits - idx.value - 1; constexpr auto bitPos = numBits - idx.value - 1;
_delay_us(DELAY_US); _delay_us(READ_DELAY_US);
sm_scl.toggle(); sm_scl.toggle();
const auto receivedBit = sm_sda.read(); const auto receivedBit = sm_sda.read();
res |= word_t{receivedBit} << bitPos; res |= word_t{receivedBit} << bitPos;
_delay_us(DELAY_US); _delay_us(READ_DELAY_US);
sm_scl.toggle(); sm_scl.toggle();
}, },
std::make_index_sequence<numBits>{}); std::make_index_sequence<numBits>{});
@@ -129,7 +138,8 @@ class Spi {
static io::Pin<CsPin> sm_cs; static io::Pin<CsPin> sm_cs;
static io::Pin<DcPin> sm_dc; static io::Pin<DcPin> sm_dc;
static constexpr auto DELAY_US = calcClockDelay(); static constexpr auto WRITE_DELAY_US = calcWriteClockDelay();
static constexpr auto READ_DELAY_US = calcReadClockDelay();
static inline std::uint8_t disableInterrupts() static inline std::uint8_t disableInterrupts()
{ {

142
font.hpp Normal file
View File

@@ -0,0 +1,142 @@
#pragma once
#include <array>
#include <cstdint>
#include "../flash/flash.hpp"
namespace eink {
constexpr auto FONT_8X8 = flash::Wrapper{std::to_array<std::array<std::uint8_t, 8>>({
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul)
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space)
{0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!)
{0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (")
{0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#)
{0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($)
{0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%)
{0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&)
{0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (')
{0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (()
{0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ())
{0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*)
{0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+)
{0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,)
{0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-)
{0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.)
{0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/)
{0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0)
{0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1)
{0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2)
{0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3)
{0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4)
{0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5)
{0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6)
{0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7)
{0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8)
{0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9)
{0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:)
{0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (;)
{0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<)
{0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=)
{0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>)
{0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?)
{0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@)
{0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A)
{0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B)
{0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C)
{0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D)
{0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E)
{0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F)
{0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G)
{0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H)
{0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I)
{0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J)
{0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K)
{0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L)
{0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M)
{0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N)
{0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O)
{0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P)
{0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q)
{0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R)
{0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S)
{0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T)
{0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U)
{0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V)
{0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W)
{0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X)
{0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y)
{0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z)
{0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([)
{0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\)
{0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (])
{0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^)
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_)
{0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`)
{0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a)
{0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b)
{0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c)
{0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d)
{0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e)
{0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f)
{0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g)
{0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h)
{0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i)
{0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j)
{0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k)
{0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l)
{0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m)
{0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n)
{0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o)
{0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p)
{0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q)
{0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r)
{0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s)
{0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t)
{0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u)
{0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v)
{0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w)
{0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x)
{0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y)
{0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z)
{0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({)
{0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|)
{0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (})
{0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~)
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F
})};
} // namespace eink

View File

@@ -7,10 +7,10 @@ namespace eink {
// [SOURCE]_[VCOM] // [SOURCE]_[VCOM]
enum class Voltage : std::uint8_t { enum class Voltage : std::uint8_t {
VSS_DCVCOM = 0b00, VSS1 = 0b00,
VSH1_VSH1DCVCOM = 0b01, VSH1 = 0b01,
VSL_VSLDCVCOM = 0b10, VSL1 = 0b10,
VSH2_NA = 0b11, VSH2 = 0b11,
}; };
struct [[gnu::packed]] Phases struct [[gnu::packed]] Phases