353 lines
16 KiB
C++
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;
|
|
}
|