Compare commits
3 Commits
91b49cd536
...
8d8369440c
| Author | SHA1 | Date | |
|---|---|---|---|
| 8d8369440c | |||
| 6218cdfc51 | |||
| 51e2f5097d |
28
eink.hpp
28
eink.hpp
@@ -21,6 +21,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 +40,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,
|
||||||
@@ -141,6 +145,17 @@ class Eink {
|
|||||||
template <typename RleImage>
|
template <typename RleImage>
|
||||||
static void draw(const RleImage &rleImage)
|
static void draw(const RleImage &rleImage)
|
||||||
{
|
{
|
||||||
|
draw(rleImage, original_lut_tag{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename RleImage, typename Lut = original_lut_tag>
|
||||||
|
static void draw(const RleImage &rleImage, const Lut &lut)
|
||||||
|
{
|
||||||
|
constexpr auto USE_ORIGINAL_LUT = std::is_same_v<Lut, original_lut_tag>;
|
||||||
|
if constexpr (!USE_ORIGINAL_LUT) {
|
||||||
|
writeLut(lut);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr auto sendImageChannel = [](const auto command, const auto &image) {
|
constexpr auto sendImageChannel = [](const auto command, const auto &image) {
|
||||||
sendCommand(command);
|
sendCommand(command);
|
||||||
for (auto j = std::size_t{0}; j < image.size(); ++j) {
|
for (auto j = std::size_t{0}; j < image.size(); ++j) {
|
||||||
@@ -159,7 +174,7 @@ class Eink {
|
|||||||
sendImageChannel(Cmd::WRITE_RAM_RED, std::get<1>(rleImage));
|
sendImageChannel(Cmd::WRITE_RAM_RED, std::get<1>(rleImage));
|
||||||
|
|
||||||
sendCommand(Cmd::DISPLAY_UPDATE_CONTROL_2);
|
sendCommand(Cmd::DISPLAY_UPDATE_CONTROL_2);
|
||||||
sendData(0xF7);
|
sendData(USE_ORIGINAL_LUT ? 0xF7 : 0xC7);
|
||||||
sendCommand(Cmd::UPDATE_DISPLAY);
|
sendCommand(Cmd::UPDATE_DISPLAY);
|
||||||
waitUntilIdle();
|
waitUntilIdle();
|
||||||
}
|
}
|
||||||
@@ -195,6 +210,17 @@ class Eink {
|
|||||||
waitUntilIdle();
|
waitUntilIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void writeLut(const Waveform &lut)
|
||||||
|
{
|
||||||
|
const auto flashLutPtr = reinterpret_cast<const std::byte *>(&lut);
|
||||||
|
|
||||||
|
sendCommand(Cmd::WRITE_LUT);
|
||||||
|
for (auto i = std::size_t{0}; i < sizeof(lut); ++i) {
|
||||||
|
const auto lutByte = flash::load(flashLutPtr[i]);
|
||||||
|
sendData(static_cast<word_t>(lutByte));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void autoPatternFill()
|
static void autoPatternFill()
|
||||||
{
|
{
|
||||||
constexpr auto RED_PATTERN_FILL_CMD = static_cast<Cmd>(0x46);
|
constexpr auto RED_PATTERN_FILL_CMD = static_cast<Cmd>(0x46);
|
||||||
|
|||||||
32
eink_spi.hpp
32
eink_spi.hpp
@@ -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()
|
||||||
{
|
{
|
||||||
|
|||||||
8
otp.hpp
8
otp.hpp
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user