diff --git a/Firmware/main/include/disp_tools.hpp b/Firmware/main/include/disp_tools.hpp index a8f67a5..be0e6c9 100644 --- a/Firmware/main/include/disp_tools.hpp +++ b/Firmware/main/include/disp_tools.hpp @@ -4,8 +4,8 @@ #ifndef CB_DISP_TOOLS_HPP #define CB_DISP_TOOLS_HPP -#include +#include class DispTools { public: @@ -14,34 +14,28 @@ public: void clear() { for (int y = 0; y < DISP_HEIGHT; y++) { for (int x = 0; x < DISP_WIDTH; x++) { - disp_frame[y][x] = 1; + SMD::get().set_pixel(x, y, true); } } } bool get_pixel(int x, int y) { // if (x < 0 || x >= DISP_WIDTH || y < 0 || y >= DISP_HEIGHT) // assert(false); - return disp_frame[y][x]; + return true; + // return disp_frame[y][x]; } void reset_pixel(int x, int y) { // if (x < 0 || x >= DISP_WIDTH || y < 0 || y >= DISP_HEIGHT) // assert(false); - - disp_frame[y][x] = true; + SMD::get().set_pixel(x, y, false); } void set_pixel(int x, int y) { // if (x < 0 || x >= DISP_WIDTH || y < 0 || y >= DISP_HEIGHT) // assert(false); // - disp_frame[y][x] = false; + SMD::get().set_pixel(x, y, true); } - void draw_rectangle(int x1, int y1, int x2, int y2); - void draw_line(int x1, int y1, int x2, int y2); - void draw_circle(int x, int y, int r); void draw_to_display(); - -private: - SMD::disp_frame_t disp_frame; }; diff --git a/Firmware/main/include/display.hpp b/Firmware/main/include/display.hpp index efed165..5151cc3 100644 --- a/Firmware/main/include/display.hpp +++ b/Firmware/main/include/display.hpp @@ -17,12 +17,28 @@ class SMD { public: - using disp_line_t = std::bitset<400>; - using disp_frame_t = std::array; + static constexpr size_t kLineBytes = DISP_WIDTH / 8; + static constexpr size_t kLineMultiSingle = (kLineBytes + 2); + static constexpr size_t kLineDataBytes = kLineMultiSingle * DISP_HEIGHT + 2; + + static DMA_ATTR uint8_t dma_buf[SMD::kLineDataBytes]; static SMD& get(); void clear(); - void draw(const disp_frame_t& frame); + void draw(); + + void set_pixel(int x, int y, bool value) { + assert(x >= 0 && x < DISP_WIDTH && y >= 0 && y < DISP_HEIGHT); + + unsigned lineIdx = 2 + kLineMultiSingle * y + (x / 8); + unsigned bitIdx = 1 << (7 - (x % 8)) % 8; + + if (value) { + dma_buf[lineIdx] &= ~bitIdx; + } else { + dma_buf[lineIdx] |= bitIdx; + } + } private: SMD(); @@ -34,14 +50,8 @@ private: .queue_size = 3, // .pre_cb = lcd_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line }; - static constexpr size_t kLineBytes = DISP_WIDTH / 8; - spi_device_handle_t _spi; - bool _vcom = false; - - static constexpr size_t kLineData = (kLineBytes + 4); - std::array buf{}; - - std::array prep_line(const SMD::disp_line_t& line); + spi_device_handle_t _spi; + bool _vcom = false; }; class SMDSurface : public Surface, public StandardEventQueue { diff --git a/Firmware/main/src/disp_tools.cpp b/Firmware/main/src/disp_tools.cpp index ddd6a19..cd24302 100644 --- a/Firmware/main/src/disp_tools.cpp +++ b/Firmware/main/src/disp_tools.cpp @@ -13,53 +13,4 @@ DispTools& DispTools::get() { return disp_tools; } -void DispTools::draw_rectangle(int x1, int y1, int x2, int y2) { - int dy = y2 - y1; - while (std::abs(dy) > 0) { - draw_line(x1, y1 + dy, x2, y1 + dy); - dy += (dy > 0) ? -1 : 1; - } -} -void DispTools::draw_line(int x1, int y1, int x2, int y2) { - int dx = x2 - x1; - int dy = y2 - y1; - int a = 0, b = 0, diff = 0; - - if (dx == 0) { - while (dy != 0) { - set_pixel(x1, y1 + dy); - dy += (dy > 0) ? -1 : 1; - } - return; - } - - if (dy == 0) { - while (dx != 0) { - set_pixel(x1 + dx, y1); - dx += (dx > 0) ? -1 : 1; - } - return; - } - - while (std::abs(a) <= std::abs(dx) && std::abs(b) <= std::abs(dy)) { - set_pixel(x1 + a, y1 + b); - if (diff < 0) { - a += (dx > 0) ? 1 : -1; - diff += std::abs(dy); - } else { - b += (dy > 0) ? 1 : -1; - diff -= std::abs(dx); - } - } -} -void DispTools::draw_circle(int x, int y, int r) { - if (r > 181) - return; - int dy = -r; - while (dy <= r) { - int dx = static_cast(std::sqrt(r * r - dy * dy)); - draw_line(x - dx, y + dy, x + dx, y + dy); - dy++; - } -} -void DispTools::draw_to_display() { SMD::get().draw(disp_frame); } +void DispTools::draw_to_display() { SMD::get().draw(); } diff --git a/Firmware/main/src/display.cpp b/Firmware/main/src/display.cpp index dda679e..9cd96e4 100644 --- a/Firmware/main/src/display.cpp +++ b/Firmware/main/src/display.cpp @@ -11,21 +11,12 @@ #include "disp_tools.hpp" +DMA_ATTR uint8_t SMD::dma_buf[SMD::kLineDataBytes]{}; + // This solution is attributed to Rich Schroeppel in the Programming Hacks section // TODO: Why does the device flag not work? unsigned char reverse_bits3(unsigned char b) { return (b * 0x0202020202ULL & 0x010884422010ULL) % 0x3ff; } -std::array SMD::prep_line(const SMD::disp_line_t& line) { - std::array data{}; - for (int i = 0; i < DISP_WIDTH; i++) { - data[i / 8] = data[i / 8] | (line[i] << (i % 8)); - } - for (int i = 0; i < kLineBytes; i++) { - data[i] = reverse_bits3(data[i]); - } - return data; -} - SMD& SMD::get() { static SMD smd; return smd; @@ -38,6 +29,12 @@ SMD::SMD() { ESP_ERROR_CHECK(gpio_set_direction(SPI_DISP_DISP, GPIO_MODE_OUTPUT)); ESP_ERROR_CHECK(gpio_set_level(SPI_DISP_DISP, 1)); ESP_ERROR_CHECK(gpio_hold_en(SPI_DISP_DISP)); + + for (uint8_t i = 0; i < DISP_HEIGHT; i++) { + dma_buf[kLineMultiSingle * i + 1] = reverse_bits3(i + 1); + dma_buf[2 + kLineMultiSingle * i + kLineBytes] = 0; + } + dma_buf[kLineDataBytes - 1] = 0; } void SMD::clear() { @@ -50,25 +47,15 @@ void SMD::clear() { ESP_ERROR_CHECK(spi_device_transmit(_spi, &t)); } -void SMD::draw(const disp_frame_t& frame) { +void SMD::draw() { _vcom = !_vcom; - for (uint8_t i = 0; i < DISP_HEIGHT; i++) { - spi_transaction_t t{}; + spi_transaction_t t{}; - t.tx_buffer = buf.data(); - t.length = buf.size() * 8; + t.tx_buffer = dma_buf; + t.length = SMD::kLineDataBytes * 8; + dma_buf[0] = 0b10000000 | (_vcom << 6); - buf[0] = 0b10000000 | (_vcom << 6); - buf[1] = reverse_bits3(i + 1); - - auto prepared = prep_line(frame.at(i)); - memcpy(buf.data() + 2, prepared.data(), kLineBytes); - - buf[2 + kLineBytes] = 0; - buf[2 + kLineBytes + 1] = 0; - - ESP_ERROR_CHECK(spi_device_transmit(_spi, &t)); - } + ESP_ERROR_CHECK(spi_device_transmit(_spi, &t)); } void SMDSurface::draw_pixel_impl(unsigned x, unsigned y, const BwPixel& pixel) { diff --git a/Firmware/main/src/hello_world_main.cpp b/Firmware/main/src/hello_world_main.cpp index fba85ea..b5c6f7a 100644 --- a/Firmware/main/src/hello_world_main.cpp +++ b/Firmware/main/src/hello_world_main.cpp @@ -45,7 +45,7 @@ FbTty tty; extern "C" void app_main() { esp_pm_config_t pm_config = { .max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ, .min_freq_mhz = 16, .light_sleep_enable = true}; - ESP_ERROR_CHECK(esp_pm_configure(&pm_config)); + // ESP_ERROR_CHECK(esp_pm_configure(&pm_config)); printf("Hello world!\n"); // TODO: Where to put that? ESP_ERROR_CHECK(esp_sleep_enable_gpio_wakeup()); @@ -64,8 +64,8 @@ extern "C" void app_main() { SMD::get(); SMD::get().clear(); DispTools::get().clear(); - DispTools::get().draw_line(0, 0, 399, 239); - DispTools::get().draw_circle(100, 100, 20); + // DispTools::get().draw_line(0, 0, 399, 239); + // DispTools::get().draw_circle(100, 100, 20); DispTools::get().draw_to_display(); tty.putstr("Hello\nworld!"); DispTools::get().draw_to_display();