#pragma once #include #include #include "../clock.hpp" #include "../io/io.hpp" template class Epd { static constexpr auto width = uint16_t{200}; static constexpr auto height = uint16_t{200}; struct Cmd { static constexpr auto SW_RESET = uint8_t{0x12}; static constexpr auto DRIVER_OUTPUT_CONTROL = uint8_t{0x01}; static constexpr auto DATA_ENTRY_MODE = uint8_t{0x11}; static constexpr auto SET_RAM_X_ADDR_POSITIONS = uint8_t{0x44}; static constexpr auto SET_RAM_Y_ADDR_POSITIONS = uint8_t{0x45}; static constexpr auto BORDER_WAVEFORM_CONTROL = uint8_t{0x3C}; static constexpr auto READ_TEMPERATURE_SENSOR = uint8_t{0x18}; static constexpr auto SET_RAM_X_ADDR = uint8_t{0x4E}; static constexpr auto SET_RAM_Y_ADDR = uint8_t{0x4F}; static constexpr auto WRITE_RAM_BLACK = uint8_t{0x24}; static constexpr auto WRITE_RAM_RED = uint8_t{0x26}; static constexpr auto DISPLAY_UPDATE_CONTROL_2 = uint8_t{0x22}; static constexpr auto UPDATE_DISPLAY = uint8_t{0x20}; static constexpr auto DEEP_SLEEP_MODE = uint8_t{0x10}; }; io::Pin m_rst; io::Pin m_dc; io::Pin m_bsy; public: Epd() = default; ~Epd() = default; int Init() { m_rst.dir(io::Dir::OUT); m_dc.dir(io::Dir::OUT); m_bsy.dir(io::Dir::IN); Spi::init(); Reset(); WaitUntilIdle(); SendCommand(Cmd::SW_RESET); WaitUntilIdle(); SendCommand(Cmd::DRIVER_OUTPUT_CONTROL); SendData(0xC7); SendData(0x00); SendData(0x01); SendCommand(Cmd::DATA_ENTRY_MODE); SendData(0x01); SendCommand(Cmd::SET_RAM_X_ADDR_POSITIONS); SendData(0x00); SendData((width / 8) - 1); SendCommand(Cmd::SET_RAM_Y_ADDR_POSITIONS); SendData(height - 1); SendData(0x00); SendData(0x00); SendData(0x00); SendCommand(Cmd::BORDER_WAVEFORM_CONTROL); SendData(0x05); SendCommand(Cmd::READ_TEMPERATURE_SENSOR); SendData(0x80); SendCommand(Cmd::SET_RAM_X_ADDR); SendData(0x00); SendCommand(Cmd::SET_RAM_Y_ADDR); SendData(height - 1); SendData(0x00); WaitUntilIdle(); return 0; } void SendCommand(unsigned char command) { m_dc = false; SpiTransfer(command); } void SendData(unsigned char data) { m_dc = true; SpiTransfer(data); } void WaitUntilIdle() { while (m_bsy) { _delay_ms(100); } } void Reset() { m_rst = true; _delay_ms(200); m_rst = false; // module reset _delay_ms(10); m_rst = true; _delay_ms(200); } void DisplayFrame(const unsigned char *frame_buffer_black, const unsigned char *frame_buffer_red) { SendCommand(Cmd::WRITE_RAM_BLACK); for (auto i = uint16_t{0}; i < width * height / 8; i++) { SendData(pgm_read_byte(&frame_buffer_black[i])); } SendCommand(Cmd::WRITE_RAM_RED); for (auto i = uint16_t{0}; i < width * height / 8; i++) { SendData(~pgm_read_byte(&frame_buffer_red[i])); } SendCommand(Cmd::DISPLAY_UPDATE_CONTROL_2); SendData(0xF7); SendCommand(Cmd::UPDATE_DISPLAY); WaitUntilIdle(); } void DisplayClear() { SendCommand(Cmd::WRITE_RAM_BLACK); for (auto i = uint16_t{0}; i < width * height / 8; i++) { SendData(0xff); } SendCommand(Cmd::WRITE_RAM_RED); for (auto i = uint16_t{0}; i < width * height / 8; i++) { SendData(0x00); } SendCommand(Cmd::DISPLAY_UPDATE_CONTROL_2); SendData(0xF7); SendCommand(Cmd::UPDATE_DISPLAY); WaitUntilIdle(); } void Sleep() { SendCommand(Cmd::DEEP_SLEEP_MODE); SendData(0x01); _delay_ms(100); } void SpiTransfer(unsigned char data) { Spi::select(true); Spi::transfer(data); Spi::select(false); } };