Advertisement
honey_the_codewitch

st7789 update 1

Nov 27th, 2022 (edited)
826
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 31.67 KB | None | 0 0
  1. #include <Arduino.h>
  2.  
  3. #include <gfx_core.hpp>
  4. #include <gfx_draw_helpers.hpp>
  5. #include <gfx_palette.hpp>
  6. #include <gfx_pixel.hpp>
  7. #include <gfx_positioning.hpp>
  8. #include <tft_driver.hpp>
  9. namespace arduino {
  10. template <int16_t BaseWidth, int16_t BaseHeight, int8_t PinDC, int8_t PinRst,
  11.           int8_t PinBL, typename Bus, uint8_t Rotation = 0,
  12.           bool AltDisplayCode = false, unsigned int WriteSpeedPercent = 200,
  13.           unsigned int ReadSpeedPercent = WriteSpeedPercent>
  14. struct st7789 final {
  15.     constexpr static const int8_t pin_dc = PinDC;
  16.     constexpr static const int8_t pin_rst = PinRst;
  17.     constexpr static const int8_t pin_bl = PinBL;
  18.     constexpr static const uint8_t rotation = Rotation & 3;
  19.     constexpr static const bool alt_display_code = AltDisplayCode;
  20.     constexpr static const uint16_t base_width = BaseWidth;
  21.     constexpr static const uint16_t base_height = BaseHeight;
  22.     constexpr static const float write_speed_multiplier =
  23.         (WriteSpeedPercent / 100.0);
  24.     constexpr static const float read_speed_multiplier =
  25.         (ReadSpeedPercent / 100.0);
  26.  
  27.     constexpr static const size_t max_dma_size = base_width * base_height * 2;
  28.  
  29.    private:
  30.     constexpr static gfx::point16 compute_offset() {
  31.  
  32.         switch(rotation) {
  33.             case 0:
  34.                 if(base_width==135) {
  35.                     return {52,40};
  36.                 } else if(base_height==280) {
  37.                     return {0,20};
  38.                 } else if(base_width==172) {
  39.                     return {34,0};
  40.                 } else if(base_width==170) {
  41.                     return {35,0};
  42.                 } else if (base_width==128) {
  43.                     return {2,1};
  44.                 }
  45.                 return {0,0};
  46.             case 1:
  47.                 if(base_width==135) {
  48.                     return {40,53};
  49.                 } else if(base_height==280) {
  50.                     return {20,0};
  51.                 } else if(base_width==172) {
  52.                     return {0,34};
  53.                 } else if(base_width==170) {
  54.                     return {0,35};
  55.                 } else if (base_width==128) {
  56.                     return {1,2};
  57.                 }
  58.                 return {0,0};
  59.             case 2:
  60.                 if(base_width==135) {
  61.                     return {53,40};
  62.                 } else if(base_height==280) {
  63.                     return {0,20};
  64.                 } else if(base_width==172) {
  65.                     return {34,0};
  66.                 } else if(base_width==170) {
  67.                     return {35,0};
  68.                 } else if (base_width==128) {
  69.                     return {1,2};
  70.                 }
  71.                 return {0,80};
  72.             case 3:
  73.                 if(base_width==135) {
  74.                     return {40,52};
  75.                 } else if(base_height==280) {
  76.                     return {20,0};
  77.                 } else if(base_width==172) {
  78.                     return {0,34};
  79.                 } else if(base_width==170) {
  80.                     return {0,35};
  81.                 } else if (base_width==128) {
  82.                     return {2,1};
  83.                 }
  84.                 return {80,0};
  85.         }
  86.        
  87.    
  88.     }
  89.    
  90.     constexpr static const uint16_t column_start = compute_offset().x;
  91.     constexpr static const uint16_t row_start = compute_offset().y;
  92.  
  93.    public:
  94.     constexpr static const uint16_t width =
  95.         (rotation & 1) ? base_height : base_width;
  96.     constexpr static const uint16_t height =
  97.         (rotation & 1) ? base_width : base_height;
  98.     using type = st7789;
  99.     using driver = tft_driver<PinDC, PinRst, PinBL, Bus>;
  100.     using bus = Bus;
  101.     using pixel_type = gfx::rgb_pixel<16>;
  102.     using caps = gfx::gfx_caps<false, (bus::dma_size > 0), true, true, false,
  103.                                bus::readable, bus::readable>;
  104.     st7789()
  105.         : m_initialized(false), m_dma_initialized(false), m_in_batch(false) {}
  106.     ~st7789() {
  107.         if (m_dma_initialized) {
  108.             bus::deinitialize_dma();
  109.         }
  110.         if (m_initialized) {
  111.             driver::deinitialize();
  112.         }
  113.     }
  114.     bool initialize() {
  115.         if (!m_initialized) {
  116.             if (driver::initialize()) {
  117.                 bus::set_speed_multiplier(write_speed_multiplier);
  118.                 bus::begin_initialization();
  119.                 bus::begin_write();
  120.                 bus::begin_transaction();
  121.  
  122.                 driver::send_command(0x11);  // Sleep out
  123.                 delay(120);
  124.  
  125.                 driver::send_command(0x13);  // Normal display mode on
  126.  
  127.                 //------------------------------display and color format
  128.                 // setting--------------------------------//
  129.                 driver::send_command(0x36);
  130.                 driver::send_data8(0x08);
  131.  
  132.                 // JLX240 display datasheet
  133.                 driver::send_command(0xB6);
  134.                 driver::send_data8(0x0A);
  135.                 driver::send_data8(0x82);
  136.  
  137.                 driver::send_command(0xB0);
  138.                 driver::send_data8(0x00);
  139.                 driver::send_data8(
  140.                     0xE0);  // 5 to 6 bit conversion: r0 = r5, b0 = b5
  141.  
  142.                 driver::send_command(0x3A);
  143.                 driver::send_data8(0x55);
  144.                 delay(10);
  145.  
  146.                 //--------------------------------ST7789V Frame rate
  147.                 // setting----------------------------------//
  148.                 driver::send_command(0xB2);
  149.                 driver::send_data8(0x0c);
  150.                 driver::send_data8(0x0c);
  151.                 driver::send_data8(0x00);
  152.                 driver::send_data8(0x33);
  153.                 driver::send_data8(0x33);
  154.  
  155.                 driver::send_command(0xB7);  // Voltages: VGH / VGL
  156.                 driver::send_data8(0x35);
  157.  
  158.                 //---------------------------------ST7789V Power
  159.                 // setting--------------------------------------//
  160.                 driver::send_command(0xBB);
  161.                 driver::send_data8(0x28);  // JLX240 display datasheet
  162.  
  163.                 driver::send_command(0xC0);
  164.                 driver::send_data8(0x0C);
  165.  
  166.                 driver::send_command(0xC2);
  167.                 driver::send_data8(0x01);
  168.                 driver::send_data8(0xFF);
  169.  
  170.                 driver::send_command(0xC3);  // voltage VRHS
  171.                 driver::send_data8(0x10);
  172.  
  173.                 driver::send_command(0xC4);
  174.                 driver::send_data8(0x20);
  175.  
  176.                 driver::send_command(0xC6);
  177.                 driver::send_data8(0x0f);
  178.  
  179.                 driver::send_command(0xD0);
  180.                 driver::send_data8(0xa4);
  181.                 driver::send_data8(0xa1);
  182.  
  183.                 //--------------------------------ST7789V gamma
  184.                 // setting---------------------------------------//
  185.                 driver::send_command(0xE0);
  186.                 driver::send_data8(0xd0);
  187.                 driver::send_data8(0x00);
  188.                 driver::send_data8(0x02);
  189.                 driver::send_data8(0x07);
  190.                 driver::send_data8(0x0a);
  191.                 driver::send_data8(0x28);
  192.                 driver::send_data8(0x32);
  193.                 driver::send_data8(0x44);
  194.                 driver::send_data8(0x42);
  195.                 driver::send_data8(0x06);
  196.                 driver::send_data8(0x0e);
  197.                 driver::send_data8(0x12);
  198.                 driver::send_data8(0x14);
  199.                 driver::send_data8(0x17);
  200.  
  201.                 driver::send_command(0xE1);
  202.                 driver::send_data8(0xd0);
  203.                 driver::send_data8(0x00);
  204.                 driver::send_data8(0x02);
  205.                 driver::send_data8(0x07);
  206.                 driver::send_data8(0x0a);
  207.                 driver::send_data8(0x28);
  208.                 driver::send_data8(0x31);
  209.                 driver::send_data8(0x54);
  210.                 driver::send_data8(0x47);
  211.                 driver::send_data8(0x0e);
  212.                 driver::send_data8(0x1c);
  213.                 driver::send_data8(0x17);
  214.                 driver::send_data8(0x1b);
  215.                 driver::send_data8(0x1e);
  216.  
  217.                 driver::send_command(0x21);
  218.  
  219.                 driver::send_command(0x2A);  // Column address set
  220.                 driver::send_data8(0x00);
  221.                 driver::send_data8(0x00);
  222.                 driver::send_data8(
  223.                     uint8_t((column_start + base_width - 1) >> 8));
  224.                 driver::send_data8(uint8_t(column_start + base_width - 1));
  225.  
  226.                 driver::send_command(0x2B);  // Row address set
  227.                 driver::send_data8(0x00);
  228.                 driver::send_data8(0x00);
  229.                 driver::send_data8(uint8_t((row_start + base_height - 1) >> 8));
  230.                 driver::send_data8(uint8_t(row_start + base_height - 1));
  231.  
  232.                 bus::end_transaction();
  233.                 bus::end_write();
  234.                 delay(120);
  235.                 bus::begin_write();
  236.                 bus::begin_transaction();
  237.                 driver::send_command(0x29);  // Display on
  238.                 bus::end_transaction();
  239.                 bus::end_write();
  240.                 bus::end_initialization();
  241.                 bus::begin_write();
  242.                 bus::begin_transaction();
  243.                 apply_rotation();
  244.                 bus::end_transaction();
  245.                 bus::end_write();
  246.                 if (pin_bl > -1) {
  247.                     pinMode(pin_bl, OUTPUT);
  248.                     digitalWrite(pin_bl, HIGH);
  249.                 }
  250.  
  251.                 m_initialized = true;
  252.             }
  253.         }
  254.         return m_initialized;
  255.     }
  256.  
  257.     inline gfx::size16 dimensions() const { return gfx::size16(width, height); }
  258.     inline gfx::rect16 bounds() const { return dimensions().bounds(); }
  259.  
  260.     inline gfx::gfx_result point(gfx::point16 location, pixel_type color) {
  261.         return fill({location.x, location.y, location.x, location.y}, color);
  262.     }
  263.     inline gfx::gfx_result point_async(gfx::point16 location,
  264.                                        pixel_type color) {
  265.         return point(location, color);
  266.     }
  267.     gfx::gfx_result point(gfx::point16 location, pixel_type* out_color) const {
  268.         if (out_color == nullptr) return gfx::gfx_result::invalid_argument;
  269.         if (!m_initialized || m_in_batch) return gfx::gfx_result::invalid_state;
  270.         if (!bounds().intersects(location)) {
  271.             *out_color = pixel_type();
  272.             return gfx::gfx_result::success;
  273.         }
  274.         bus::dma_wait();
  275.         bus::set_speed_multiplier(read_speed_multiplier);
  276.         bus::begin_read();
  277.         bus::cs_low();
  278.         set_window({location.x, location.y, location.x, location.y}, true);
  279.         bus::direction(INPUT);
  280.         bus::read_raw8();  // throw away
  281.         out_color->native_value = ((bus::read_raw8() & 0xF8) << 8) |
  282.                                   ((bus::read_raw8() & 0xFC) << 3) |
  283.                                   (bus::read_raw8() >> 3);
  284.         bus::end_read();
  285.         bus::cs_high();
  286.         bus::set_speed_multiplier(write_speed_multiplier);
  287.         bus::direction(OUTPUT);
  288.         return gfx::gfx_result::success;
  289.     }
  290.     gfx::gfx_result fill(const gfx::rect16& bounds, pixel_type color) {
  291.         if (!initialize()) return gfx::gfx_result::device_error;
  292.         gfx::gfx_result rr = commit_batch();
  293.         if (rr != gfx::gfx_result::success) {
  294.             return rr;
  295.         }
  296.         if (!bounds.intersects(this->bounds())) return gfx::gfx_result::success;
  297.         const gfx::rect16 r = bounds.normalize().crop(this->bounds());
  298.         bus::begin_write();
  299.         bus::begin_transaction();
  300.         set_window(r);
  301.         bus::write_raw16_repeat(color.native_value,
  302.                                 (r.x2 - r.x1 + 1) * (r.y2 - r.y1 + 1));
  303.         bus::end_transaction();
  304.         bus::end_write();
  305.         return gfx::gfx_result::success;
  306.     }
  307.     inline gfx::gfx_result fill_async(const gfx::rect16& bounds,
  308.                                       pixel_type color) {
  309.         return fill(bounds, color);
  310.     }
  311.     inline gfx::gfx_result clear(const gfx::rect16& bounds) {
  312.         return fill(bounds, pixel_type());
  313.     }
  314.     inline gfx::gfx_result clear_async(const gfx::rect16& bounds) {
  315.         return clear(bounds);
  316.     }
  317.     template <typename Source>
  318.     inline gfx::gfx_result copy_from(const gfx::rect16& src_rect,
  319.                                      const Source& src, gfx::point16 location) {
  320.         if (!initialize()) return gfx::gfx_result::device_error;
  321.         gfx::gfx_result rr = commit_batch();
  322.         if (rr != gfx::gfx_result::success) {
  323.             return rr;
  324.         }
  325.         return copy_from_impl(src_rect, src, location, false);
  326.     }
  327.     template <typename Source>
  328.     inline gfx::gfx_result copy_from_async(const gfx::rect16& src_rect,
  329.                                            const Source& src,
  330.                                            gfx::point16 location) {
  331.         if (!initialize()) return gfx::gfx_result::device_error;
  332.         if (!m_dma_initialized) {
  333.             if (!bus::initialize_dma()) return gfx::gfx_result::device_error;
  334.             m_dma_initialized = true;
  335.         }
  336.         gfx::gfx_result rr = commit_batch();
  337.         if (rr != gfx::gfx_result::success) {
  338.             return rr;
  339.         }
  340.         return copy_from_impl(src_rect, src, location, true);
  341.     }
  342.     template <typename Destination>
  343.     inline gfx::gfx_result copy_to(const gfx::rect16& src_rect,
  344.                                    Destination& dst,
  345.                                    gfx::point16 location) const {
  346.         if (!src_rect.intersects(bounds())) return gfx::gfx_result::success;
  347.         gfx::rect16 srcr = src_rect.crop(bounds());
  348.         gfx::rect16 dstr =
  349.             gfx::rect16(location, srcr.dimensions()).crop(dst.bounds());
  350.         srcr = gfx::rect16(srcr.location(), dstr.dimensions());
  351.         return copy_to_helper<Destination,
  352.                               !(pixel_type::template has_channel_names<
  353.                                   gfx::channel_name::A>::value)>::copy_to(*this,
  354.                                                                           srcr,
  355.                                                                           dst,
  356.                                                                           dstr);
  357.     }
  358.     template <typename Destination>
  359.     inline gfx::gfx_result copy_to_async(const gfx::rect16& src_rect,
  360.                                          Destination& dst,
  361.                                          gfx::point16 location) const {
  362.         return copy_to(src_rect, dst, location);
  363.     }
  364.  
  365.     gfx::gfx_result commit_batch() {
  366.         if (m_in_batch) {
  367.             bus::end_transaction();
  368.             bus::end_write();
  369.             m_in_batch = false;
  370.         }
  371.         return gfx::gfx_result::success;
  372.     }
  373.     inline gfx::gfx_result commit_batch_async() { return commit_batch(); }
  374.     gfx::gfx_result begin_batch(const gfx::rect16& bounds) {
  375.         if (!initialize()) return gfx::gfx_result::device_error;
  376.         gfx::gfx_result rr = commit_batch();
  377.         if (rr != gfx::gfx_result::success) {
  378.             return rr;
  379.         }
  380.         const gfx::rect16 r = bounds.normalize();
  381.         bus::begin_write();
  382.         bus::begin_transaction();
  383.         set_window(r);
  384.         m_in_batch = true;
  385.         return gfx::gfx_result::success;
  386.     }
  387.     inline gfx::gfx_result begin_batch_async(const gfx::rect16& bounds) {
  388.         return begin_batch(bounds);
  389.     }
  390.     gfx::gfx_result write_batch(pixel_type color) {
  391.         bus::write_raw16(color.native_value);
  392.         return gfx::gfx_result::success;
  393.     }
  394.     inline gfx::gfx_result write_batch_async(pixel_type color) {
  395.         return write_batch(color);
  396.     }
  397.     inline gfx::gfx_result wait_all_async() {
  398.         bus::dma_wait();
  399.         return gfx::gfx_result::success;
  400.     }
  401.  
  402.    private:
  403.     bool m_initialized;
  404.     bool m_dma_initialized;
  405.     bool m_in_batch;
  406.     static void set_window(const gfx::rect16& bounds, bool read = false) {
  407.         driver::dc_command();
  408.         bus::write_raw8(0x2A);
  409.         driver::dc_data();
  410.         bus::write_raw16(column_start + bounds.x1);
  411.         bus::write_raw16(column_start + bounds.x2);
  412.         driver::dc_command();
  413.         bus::write_raw8(0x2B);
  414.         driver::dc_data();
  415.         bus::write_raw16(row_start + bounds.y1);
  416.         bus::write_raw16(row_start + bounds.y2);
  417.         driver::dc_command();
  418.         bus::write_raw8(read ? 0x2E : 0x2C);
  419.         driver::dc_data();
  420.     }
  421.     template <typename Destination, bool AllowBlt = true>
  422.     struct copy_to_helper {
  423.         inline static gfx::gfx_result copy_to(const type& src,
  424.                                               const gfx::rect16& srcr,
  425.                                               Destination& dst,
  426.                                               const gfx::rect16& dstr) {
  427.             if (gfx::helpers::template is_same<typename Destination::pixel_type,
  428.                                                pixel_type>::value &&
  429.                 dstr.top_left() == gfx::point16(0, 0)) {
  430.                 if (AllowBlt && dstr.width() == srcr.width() &&
  431.                     dstr.height() == srcr.height()) {
  432.                     if (dstr.top_left() == gfx::point16(0, 0)) {
  433.                         return copy_to_fast_helper<Destination>::do_copy(srcr,
  434.                                                                          dst);
  435.                     }
  436.                 }
  437.             }
  438.  
  439.             size_t dy = 0, dye = dstr.height();
  440.             size_t dx, dxe = dstr.width();
  441.             gfx::gfx_result r;
  442.             gfx::helpers::suspender<Destination, Destination::caps::suspend,
  443.                                     false>
  444.                 sustok(dst);
  445.             r = gfx::helpers::batcher<Destination, Destination::caps::batch,
  446.                                       false>::begin_batch(dst, dstr, false);
  447.             if (gfx::gfx_result::success != r) {
  448.                 return r;
  449.             }
  450.             int sox = srcr.left(), soy = srcr.top();
  451.             int dox = dstr.left(), doy = dstr.top();
  452.             while (dy < dye) {
  453.                 dx = 0;
  454.  
  455.                 while (dx < dxe) {
  456.                     pixel_type spx;
  457.                     r = src.point(gfx::point16(sox + dx, soy + dy), &spx);
  458.                     if (gfx::gfx_result::success != r) return r;
  459.                     typename Destination::pixel_type dpx;
  460.                     if (pixel_type::template has_channel_names<
  461.                             gfx::channel_name::A>::value) {
  462.                         r = gfx::helpers::blend_helper<
  463.                             type, Destination,
  464.                             Destination::caps::read>::do_blend(src, spx, dst,
  465.                                                                gfx::point16(
  466.                                                                    dox + dx,
  467.                                                                    doy + dy),
  468.                                                                &dpx);
  469.                         if (gfx::gfx_result::success != r) {
  470.                             return r;
  471.                         }
  472.                     } else {
  473.                         r = convert_palette(dst, src, spx, &dpx, nullptr);
  474.                         if (gfx::gfx_result::success != r) {
  475.                             return r;
  476.                         }
  477.                     }
  478.                     r = gfx::helpers::batcher<
  479.                         Destination, Destination::caps::batch,
  480.                         false>::write_batch(dst,
  481.                                             gfx::point16(dox + dx, doy + dy),
  482.                                             dpx, false);
  483.                     if (gfx::gfx_result::success != r) return r;
  484.                     ++dx;
  485.                 }
  486.                 ++dy;
  487.             }
  488.             return gfx::helpers::batcher<Destination, Destination::caps::batch,
  489.                                          false>::commit_batch(dst, false);
  490.         }
  491.     };
  492.     template <typename Destination>
  493.     struct copy_to_fast_helper {
  494.         static gfx::gfx_result do_copy(const gfx::rect16& src_rect,
  495.                                        Destination& dst) {
  496.             gfx::rect16 r = src_rect.normalize();
  497.             bool entire = false;
  498.             gfx::size16 bssz = r.dimensions();
  499.             size_t bsz = bssz.width * bssz.height * 3;
  500.             uint8_t* buf = (uint8_t*)malloc(bsz);
  501.             if (buf != nullptr) {
  502.                 entire = true;
  503.             } else {
  504.                 bsz = bssz.width * 3;
  505.                 buf = (uint8_t*)malloc(bsz);
  506.             }
  507.             if (buf != nullptr) {
  508.                 free(buf);
  509.                 buf = nullptr;
  510.             }
  511.             using batch =
  512.                 gfx::helpers::batcher<Destination, Destination::caps::batch,
  513.                                       Destination::caps::async>;
  514.             if (buf == nullptr) {
  515.                 gfx::helpers::suspender<Destination, Destination::caps::suspend,
  516.                                         Destination::caps::async>
  517.                     stok(dst, false);
  518.                 gfx::gfx_result rr = batch::begin_batch(
  519.                     dst,
  520.                     {0, 0, uint16_t(r.width() - 1), uint16_t(r.height() - 1)},
  521.                     false);
  522.                 if (rr != gfx::gfx_result::success) {
  523.                     return rr;
  524.                 }
  525.                 pixel_type px;
  526.                 for (int y = r.y1; y <= r.y2; ++y) {
  527.                     for (int x = r.x1; x <= r.x2; ++x) {
  528.                         uint8_t buf3[3];
  529.                         buf = buf3;
  530.                         fetch_buffer({uint16_t(x), uint16_t(y), uint16_t(x),
  531.                                       uint16_t(y)},
  532.                                      buf, 3);
  533.                         px.native_value = (((*buf) & 0xF8) << 8);
  534.                         ++buf;
  535.                         px.native_value |= (((*buf) & 0xFC) << 3);
  536.                         ++buf;
  537.                         px.native_value |= (*buf >> 3);
  538.                         batch::write_batch(
  539.                             dst, {uint16_t(x - r.x1), uint16_t(y - r.y1)}, px,
  540.                             false);
  541.                     }
  542.                 }
  543.                 rr = batch::commit_batch(dst, false);
  544.                 if (rr != gfx::gfx_result::success) {
  545.                     return rr;
  546.                 }
  547.                 buf = nullptr;
  548.             } else {
  549.                 if (entire) {
  550.                     fetch_buffer(r, buf, bsz);
  551.                     gfx::helpers::suspender<Destination,
  552.                                             Destination::caps::suspend,
  553.                                             Destination::caps::async>
  554.                         stok(dst, false);
  555.                     gfx::gfx_result rr =
  556.                         batch::begin_batch(dst,
  557.                                            {0, 0, uint16_t(r.width() - 1),
  558.                                             uint16_t(r.height() - 1)},
  559.                                            false);
  560.                     if (rr != gfx::gfx_result::success) {
  561.                         free(buf);
  562.                         return rr;
  563.                     }
  564.                     uint8_t* bbuf = buf;
  565.                     while (bsz) {
  566.                         pixel_type px;
  567.                         uint16_t x, y;
  568.                         x = 0;
  569.                         y = 0;
  570.                         px.native_value = (((*bbuf) & 0xF8) << 8);
  571.                         ++bbuf;
  572.                         px.native_value |= (((*bbuf) & 0xFC) << 3);
  573.                         ++bbuf;
  574.                         px.native_value |= (*bbuf >> 3);
  575.                         ++bbuf;
  576.                         ++x;
  577.                         if (x > r.x2 - r.x1) {
  578.                             x = 0;
  579.                             ++y;
  580.                         }
  581.                         batch::write_batch(dst, {x, y}, px, false);
  582.                         bsz -= 3;
  583.                     }
  584.                     rr = batch::commit_batch(dst, false);
  585.                     if (rr != gfx::gfx_result::success) {
  586.                         free(buf);
  587.                         return rr;
  588.                     }
  589.                 } else {
  590.                     gfx::helpers::suspender<Destination,
  591.                                             Destination::caps::suspend,
  592.                                             Destination::caps::async>
  593.                         stok(dst, false);
  594.                     for (int y = r.y1; y <= r.y2; ++y) {
  595.                         fetch_buffer(r, buf, bsz);
  596.                         gfx::gfx_result rr =
  597.                             batch::begin_batch(dst,
  598.                                                {0, 0, uint16_t(r.width() - 1),
  599.                                                 uint16_t(r.height() - 1)},
  600.                                                false);
  601.                         if (rr != gfx::gfx_result::success) {
  602.                             free(buf);
  603.                             return rr;
  604.                         }
  605.                         size_t bbsz = bsz;
  606.                         uint8_t* bbuf = buf;
  607.                         while (bbsz) {
  608.                             pixel_type px;
  609.                             uint16_t x = 0;
  610.                             px.native_value = (((*bbuf) & 0xF8) << 8);
  611.                             ++bbuf;
  612.                             px.native_value |= (((*bbuf) & 0xFC) << 3);
  613.                             ++bbuf;
  614.                             px.native_value |= (*bbuf >> 3);
  615.                             ++bbuf;
  616.                             ++x;
  617.                             batch::write_batch(dst, {x, uint16_t(y - r.y1)}, px,
  618.                                                false);
  619.                             bbsz -= 3;
  620.                         }
  621.                         rr = batch::commit_batch(dst, false);
  622.                         if (rr != gfx::gfx_result::success) {
  623.                             free(buf);
  624.                             return rr;
  625.                         }
  626.                     }
  627.                 }
  628.             }
  629.             if (buf != nullptr) {
  630.                 free(buf);
  631.             }
  632.             return gfx::gfx_result::success;
  633.         }
  634.  
  635.         static void fetch_buffer(const gfx::rect16& r, uint8_t* buf,
  636.                                  size_t len) {
  637.             bus::dma_wait();
  638.             bus::set_speed_multiplier(read_speed_multiplier);
  639.             bus::begin_read();
  640.             bus::cs_low();
  641.             set_window(r, true);
  642.             bus::direction(INPUT);
  643.             bus::read_raw8();  // throw away
  644.             bus::read_raw(buf, len);
  645.             bus::cs_high();
  646.             bus::end_read();
  647.             bus::set_speed_multiplier(write_speed_multiplier);
  648.             bus::direction(OUTPUT);
  649.         }
  650.     };
  651.     template <typename Source, bool Blt>
  652.     struct copy_from_helper {
  653.         static gfx::gfx_result do_draw(type* this_, const gfx::rect16& dstr,
  654.                                        const Source& src, gfx::rect16 srcr,
  655.                                        bool async) {
  656.             uint16_t w = dstr.dimensions().width;
  657.             uint16_t h = dstr.dimensions().height;
  658.             gfx::gfx_result rr;
  659.  
  660.             rr = this_->begin_batch(dstr);
  661.  
  662.             if (gfx::gfx_result::success != rr) {
  663.                 return rr;
  664.             }
  665.             for (uint16_t y = 0; y < h; ++y) {
  666.                 for (uint16_t x = 0; x < w; ++x) {
  667.                     typename Source::pixel_type pp;
  668.                     rr = src.point(gfx::point16(x + srcr.x1, y + srcr.y1), &pp);
  669.                     if (rr != gfx::gfx_result::success) return rr;
  670.                     pixel_type p;
  671.                     rr = gfx::convert_palette_from(src, pp, &p);
  672.                     if (gfx::gfx_result::success != rr) {
  673.                         return rr;
  674.                     }
  675.  
  676.                     rr = this_->write_batch(p);
  677.  
  678.                     if (gfx::gfx_result::success != rr) {
  679.                         return rr;
  680.                     }
  681.                 }
  682.             }
  683.  
  684.             rr = this_->commit_batch();
  685.  
  686.             return rr;
  687.         }
  688.     };
  689.  
  690.     template <typename Source>
  691.     struct copy_from_helper<Source, true> {
  692.         static gfx::gfx_result do_draw(type* this_, const gfx::rect16& dstr,
  693.                                        const Source& src, gfx::rect16 srcr,
  694.                                        bool async) {
  695.             if (async) {
  696.                 bus::dma_wait();
  697.             }
  698.             // direct blt
  699.             if (src.bounds().width() == srcr.width() && srcr.x1 == 0) {
  700.                 bus::begin_write();
  701.                 set_window(dstr);
  702.                 if (async) {
  703.                     bus::write_raw_dma(
  704.                         src.begin() + (srcr.y1 * src.dimensions().width * 2),
  705.                         (srcr.y2 - srcr.y1 + 1) * src.dimensions().width * 2);
  706.                 } else {
  707.                     bus::write_raw(
  708.                         src.begin() + (srcr.y1 * src.dimensions().width * 2),
  709.                         (srcr.y2 - srcr.y1 + 1) * src.dimensions().width * 2);
  710.                 }
  711.  
  712.                 bus::end_write();
  713.                 return gfx::gfx_result::success;
  714.             }
  715.             // line by line blt
  716.             uint16_t yy = 0;
  717.             uint16_t hh = srcr.height();
  718.             uint16_t ww = src.dimensions().width;
  719.             uint16_t pitch = (srcr.x2 - srcr.x1 + 1) * 2;
  720.             bus::begin_write();
  721.             bus::begin_transaction();
  722.             while (yy < hh - !!async) {
  723.                 gfx::rect16 dr = {dstr.x1, uint16_t(dstr.y1 + yy), dstr.x2,
  724.                                   uint16_t(dstr.y1 + yy)};
  725.                 set_window(dr);
  726.                 bus::write_raw(
  727.                     src.begin() + 2 * (ww * (srcr.y1 + yy) + srcr.x1), pitch);
  728.                 ++yy;
  729.             }
  730.             if (async) {
  731.                 gfx::rect16 dr = {dstr.x1, uint16_t(dstr.y1 + yy), dstr.x2,
  732.                                   uint16_t(dstr.y1 + yy)};
  733.                 set_window(dr);
  734.                 bus::write_raw_dma(
  735.                     src.begin() + 2 * (ww * (srcr.y1 + yy) + srcr.x1), pitch);
  736.             }
  737.             bus::end_transaction();
  738.             bus::end_write();
  739.             return gfx::gfx_result::success;
  740.         }
  741.     };
  742.     template <typename Source>
  743.     gfx::gfx_result copy_from_impl(const gfx::rect16& src_rect,
  744.                                    const Source& src, gfx::point16 location,
  745.                                    bool async) {
  746.         gfx::rect16 srcr = src_rect.normalize().crop(src.bounds());
  747.         gfx::rect16 dstr(location, src_rect.dimensions());
  748.         dstr = dstr.crop(bounds());
  749.         if (srcr.width() > dstr.width()) {
  750.             srcr.x2 = srcr.x1 + dstr.width() - 1;
  751.         }
  752.         if (srcr.height() > dstr.height()) {
  753.             srcr.y2 = srcr.y1 + dstr.height() - 1;
  754.         }
  755.         return copy_from_helper < Source,
  756.                gfx::helpers::is_same<pixel_type,
  757.                                      typename Source::pixel_type>::value &&
  758.                    Source::caps::blt > ::do_draw(this, dstr, src, srcr, async);
  759.     }
  760.     static void apply_rotation() {
  761.         bus::begin_write();
  762.         driver::send_command(0x36);
  763.         switch (rotation) {
  764.             case 0:
  765.                 // portrait
  766.                 driver::send_data8(0x8);
  767.                 break;
  768.             case 1:
  769.                 // landscape
  770.                 driver::send_data8(0x60 | 0x8);
  771.                 break;
  772.             case 2:
  773.                 // portrait
  774.                 driver::send_data8(0xC0 | 0x8);
  775.                 break;
  776.             case 3:
  777.                 // landscape
  778.                 driver::send_data8(0xA0 | 0x8);
  779.                 break;
  780.         }
  781.         delayMicroseconds(10);
  782.         bus::end_write();
  783.     }
  784. };
  785. }  // namespace arduino
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement