eink/eink/main.cpp

353 lines
16 KiB
C++

#include "clock.hpp"
#include <array>
#include <type_traits>
#include <cstdint>
#include <cstring>
#include "eink/eink.hpp"
#include "flash/flash.hpp"
#include "io/io.hpp"
#include "uart/uart.hpp"
#include "image.hpp"
using uart_t = uart::Uart0<uart::Config<115200>>;
REGISTER_UART0_INT_VECTORS(uart_t);
using spi_t = eink::Spi<io::P::C4, io::P::C5, io::P::C3, io::P::C2>;
using eink_t = eink::Eink<200, 200, spi_t, io::P::C1, io::P::C0>;
using eink::Voltage::VSH1;
using eink::Voltage::VSH2;
using eink::Voltage::VSL1;
using eink::Voltage::VSS1;
constexpr auto
ORIGINAL_WAVEFORM_LUT =
flash::Wrapper<eink::Waveform>{
eink::Waveform{
.lut = {{{
{.phaseD = VSH1, .phaseC = VSH1, .phaseB = VSS1, .phaseA = VSH1},
{.phaseD = VSL1, .phaseC = VSL1, .phaseB = VSH1, .phaseA = VSL1},
{.phaseD = VSL1, .phaseC = VSH1, .phaseB = VSL1, .phaseA = VSH1},
{.phaseD = VSL1, .phaseC = VSL1, .phaseB = VSL1, .phaseA = VSH1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSL1, .phaseA = VSH1},
{.phaseD = VSL1, .phaseC = VSL1, .phaseB = VSH1, .phaseA = VSL1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSH1, .phaseA = VSL1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSH1, .phaseA = VSL1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSH1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSH1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSH1},
}},
{{
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSH1, .phaseA = VSH1},
{.phaseD = VSS1, .phaseC = VSL1, .phaseB = VSH1, .phaseA = VSL1},
{.phaseD = VSL1, .phaseC = VSH1, .phaseB = VSL1, .phaseA = VSH1},
{.phaseD = VSS1, .phaseC = VSH1, .phaseB = VSL1, .phaseA = VSH1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSL1, .phaseA = VSH1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSH1, .phaseA = VSL1},
{.phaseD = VSS1, .phaseC = VSL1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSL1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSL1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
}},
{{
{.phaseD = VSL1, .phaseC = VSL1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSL1, .phaseC = VSL1, .phaseB = VSH1, .phaseA = VSL1},
{.phaseD = VSL1, .phaseC = VSH1, .phaseB = VSL1, .phaseA = VSH1},
{.phaseD = VSH1, .phaseC = VSH1, .phaseB = VSL1, .phaseA = VSH1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSL1, .phaseA = VSH1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSH1, .phaseA = VSL1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSH2, .phaseC = VSL1, .phaseB = VSL1, .phaseA = VSS1},
{.phaseD = VSH2, .phaseC = VSS1, .phaseB = VSL1, .phaseA = VSL1},
{.phaseD = VSH2, .phaseC = VSH2, .phaseB = VSH2, .phaseA = VSL1},
{.phaseD = VSS1, .phaseC = VSH2, .phaseB = VSH2, .phaseA = VSH2},
}},
{{
{.phaseD = VSL1, .phaseC = VSL1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSL1, .phaseC = VSL1, .phaseB = VSH1, .phaseA = VSL1},
{.phaseD = VSL1, .phaseC = VSH1, .phaseB = VSL1, .phaseA = VSH1},
{.phaseD = VSH1, .phaseC = VSH1, .phaseB = VSL1, .phaseA = VSH1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSL1, .phaseA = VSH1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSH1, .phaseA = VSL1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSH2, .phaseC = VSL1, .phaseB = VSL1, .phaseA = VSS1},
{.phaseD = VSH2, .phaseC = VSS1, .phaseB = VSL1, .phaseA = VSL1},
{.phaseD = VSH2, .phaseC = VSH2, .phaseB = VSH2, .phaseA = VSL1},
{.phaseD = VSS1, .phaseC = VSH2, .phaseB = VSH2, .phaseA = VSH2},
}},
{{
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSL1, .phaseA = VSH1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
{.phaseD = VSS1, .phaseC = VSS1, .phaseB = VSS1, .phaseA = VSS1},
}}},
.timings =
{
{
.frameCountPhaseA = 32,
.frameCountPhaseB = 16,
.repeatSubPhaseAB = 0,
.frameCountPhaseC = 19,
.frameCountPhaseD = 20,
.repeatSubPhaseCD = 0,
.repeat = 0,
},
{
.frameCountPhaseA = 3,
.frameCountPhaseB = 3,
.repeatSubPhaseAB = 6,
.frameCountPhaseC = 12,
.frameCountPhaseD = 10,
.repeatSubPhaseCD = 0,
.repeat = 0,
},
{
.frameCountPhaseA = 3,
.frameCountPhaseB = 4,
.repeatSubPhaseAB = 0,
.frameCountPhaseC = 3,
.frameCountPhaseD = 4,
.repeatSubPhaseCD = 0,
.repeat = 10,
},
{
.frameCountPhaseA = 3,
.frameCountPhaseB = 3,
.repeatSubPhaseAB = 10,
.frameCountPhaseC = 22,
.frameCountPhaseD = 2,
.repeatSubPhaseCD = 0,
.repeat = 0,
},
{
.frameCountPhaseA = 3,
.frameCountPhaseB = 3,
.repeatSubPhaseAB = 3,
.frameCountPhaseC = 0,
.frameCountPhaseD = 0,
.repeatSubPhaseCD = 0,
.repeat = 0,
},
{
.frameCountPhaseA = 2,
.frameCountPhaseB = 2,
.repeatSubPhaseAB = 3,
.frameCountPhaseC = 5,
.frameCountPhaseD = 5,
.repeatSubPhaseCD = 1,
.repeat = 0,
},
{
.frameCountPhaseA = 22,
.frameCountPhaseB = 20,
.repeatSubPhaseAB = 0,
.frameCountPhaseC = 20,
.frameCountPhaseD = 0,
.repeatSubPhaseCD = 0,
.repeat = 0,
},
{
.frameCountPhaseA = 0,
.frameCountPhaseB = 0,
.repeatSubPhaseAB = 0,
.frameCountPhaseC = 0,
.frameCountPhaseD = 0,
.repeatSubPhaseCD = 0,
.repeat = 0,
},
{
.frameCountPhaseA = 4,
.frameCountPhaseB = 5,
.repeatSubPhaseAB = 0,
.frameCountPhaseC = 3,
.frameCountPhaseD = 40,
.repeatSubPhaseCD = 0,
.repeat = 2,
},
{
.frameCountPhaseA = 2,
.frameCountPhaseB = 3,
.repeatSubPhaseAB = 0,
.frameCountPhaseC = 3,
.frameCountPhaseD = 50,
.repeatSubPhaseCD = 0,
.repeat = 1,
},
{
.frameCountPhaseA = 6,
.frameCountPhaseB = 3,
.repeatSubPhaseAB = 0,
.frameCountPhaseC = 34,
.frameCountPhaseD = 5,
.repeatSubPhaseCD = 0,
.repeat = 0,
},
{
.frameCountPhaseA = 4,
.frameCountPhaseB = 5,
.repeatSubPhaseAB = 0,
.frameCountPhaseC = 5,
.frameCountPhaseD = 1,
.repeatSubPhaseCD = 0,
.repeat = 0,
},
},
.frameRates = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
.subPhaseGateStates = {},
}};
static inline consteval auto createFastWaveformLut(const flash::Wrapper<eink::Waveform> &original)
{
auto fastWaveformLut = original.value;
for (auto i = std::size_t{0}; i < std::size(fastWaveformLut.timings) - 1; ++i) {
fastWaveformLut.timings[i].frameCountPhaseA = 0;
fastWaveformLut.timings[i].frameCountPhaseB = 0;
fastWaveformLut.timings[i].repeatSubPhaseAB = 0;
fastWaveformLut.timings[i].frameCountPhaseC = 0;
fastWaveformLut.timings[i].frameCountPhaseD = 0;
fastWaveformLut.timings[i].repeatSubPhaseCD = 0;
fastWaveformLut.timings[i].repeat = 0;
}
fastWaveformLut.timings[11].frameCountPhaseA = 4;
fastWaveformLut.timings[11].frameCountPhaseB = 5;
fastWaveformLut.timings[11].repeatSubPhaseAB = 2;
fastWaveformLut.timings[11].frameCountPhaseC = 5;
fastWaveformLut.timings[11].frameCountPhaseD = 1;
fastWaveformLut.timings[11].repeatSubPhaseCD = 2;
fastWaveformLut.timings[11].repeat = 4;
return flash::Wrapper{fastWaveformLut};
}
constexpr auto FAST_WAVEFORM_LUT = createFastWaveformLut(ORIGINAL_WAVEFORM_LUT);
void dumpOTP(eink_t &einkDisplay, uart_t &serial)
{
constexpr auto printWidth = 16;
auto printedCnt = std::size_t{0};
einkDisplay.dumpOTP([&serial, &printedCnt](const auto &data) {
constexpr auto printAddress = true;
if (printedCnt > 0 && printedCnt % printWidth == 0) {
serial << F("\r\n");
}
if (printAddress && printedCnt % printWidth == 0) {
serial << F("0x");
serial.txNumber<std::size_t, 16, 4>(printedCnt);
serial << F(": ");
}
serial << F("0x");
serial.txNumber<std::remove_cvref_t<decltype(data)>, 16, 2>(data);
serial << F(", ");
++printedCnt;
});
serial << F("\r\n");
}
int main()
{
uart_t serial;
serial.init();
sei();
serial << F("e-Paper demo") << F("\r\n");
auto einkDisplay = eink_t{};
serial << F("e-Paper init") << F("\r\n");
einkDisplay.init();
serial << F("e-Paper dump OTP") << F("\r\n");
dumpOTP(einkDisplay, serial);
serial << F("e-Paper clear") << F("\r\n");
einkDisplay.clear();
serial << F("e-Paper update") << F("\r\n");
einkDisplay.update();
serial << F("e-Paper draw fast") << F("\r\n");
einkDisplay.draw(RLE_IMAGE);
serial << F("e-Paper update") << F("\r\n");
einkDisplay.update(FAST_WAVEFORM_LUT);
serial << F("e-Paper clear") << F("\r\n");
einkDisplay.clear();
serial << F("e-Paper update") << F("\r\n");
einkDisplay.update();
serial << F("e-Paper draw") << F("\r\n");
einkDisplay.draw(RLE_IMAGE);
serial << F("e-Paper update") << F("\r\n");
einkDisplay.update();
serial << F("e-Paper clear") << F("\r\n");
einkDisplay.clear();
serial << F("e-Paper update") << F("\r\n");
einkDisplay.update();
serial << F("e-Paper draw text") << F("\r\n");
const auto startX = 16;
const auto startY = 58;
einkDisplay.drawText({startX, startY}, "B->B: ", eink_t::Color::BLACK, eink_t::Color::WHITE);
einkDisplay.drawText({startX + 6 * 8, startY}, "Black on black", eink_t::Color::BLACK, eink_t::Color::BLACK);
einkDisplay.drawText({startX, startY + 10}, "B->R: ", eink_t::Color::BLACK, eink_t::Color::WHITE);
einkDisplay.drawText({startX + 6 * 8, startY + 10}, "Black on red", eink_t::Color::BLACK, eink_t::Color::RED);
einkDisplay.drawText({startX, startY + 20}, "B->W: ", eink_t::Color::BLACK, eink_t::Color::WHITE);
einkDisplay.drawText({startX + 6 * 8, startY + 20}, "Black on white", eink_t::Color::BLACK, eink_t::Color::WHITE);
einkDisplay.drawText({startX, startY + 30}, "R->B: ", eink_t::Color::BLACK, eink_t::Color::WHITE);
einkDisplay.drawText({startX + 6 * 8, startY + 30}, "Red on black", eink_t::Color::RED, eink_t::Color::BLACK);
einkDisplay.drawText({startX, startY + 40}, "R->R: ", eink_t::Color::BLACK, eink_t::Color::WHITE);
einkDisplay.drawText({startX + 6 * 8, startY + 40}, "Red on red", eink_t::Color::RED, eink_t::Color::RED);
einkDisplay.drawText({startX, startY + 50}, "R->W: ", eink_t::Color::BLACK, eink_t::Color::WHITE);
einkDisplay.drawText({startX + 6 * 8, startY + 50}, "Red on white", eink_t::Color::RED, eink_t::Color::WHITE);
einkDisplay.drawText({startX, startY + 60}, "W->B: ", eink_t::Color::BLACK, eink_t::Color::WHITE);
einkDisplay.drawText({startX + 6 * 8, startY + 60}, "White on black", eink_t::Color::WHITE, eink_t::Color::BLACK);
einkDisplay.drawText({startX, startY + 70}, "W->R: ", eink_t::Color::BLACK, eink_t::Color::WHITE);
einkDisplay.drawText({startX + 6 * 8, startY + 70}, "White on red", eink_t::Color::WHITE, eink_t::Color::RED);
einkDisplay.drawText({startX, startY + 80}, "W->W: ", eink_t::Color::BLACK, eink_t::Color::WHITE);
einkDisplay.drawText({startX + 6 * 8, startY + 80}, "White on white", eink_t::Color::WHITE, eink_t::Color::WHITE);
serial << F("e-Paper update") << F("\r\n");
einkDisplay.update();
einkDisplay.clear();
einkDisplay.drawText({0, 0 * 5 * 8}, "Big", eink_t::Color::BLACK, eink_t::Color::WHITE, 5);
einkDisplay.drawText({0, 1 * 5 * 8}, "scale", eink_t::Color::BLACK, eink_t::Color::WHITE, 5);
einkDisplay.drawText({0, 2 * 5 * 8}, "O.o", eink_t::Color::RED, eink_t::Color::WHITE, 5);
einkDisplay.update();
serial << F("e-Paper sleep") << F("\r\n");
einkDisplay.sleep();
while (true) {
serial << F("e-Paper running") << F("\r\n");
_delay_ms(1000);
}
return 0;
}