1*61c4878aSAndroid Build Coastguard Worker.. _seed-0104: 2*61c4878aSAndroid Build Coastguard Worker 3*61c4878aSAndroid Build Coastguard Worker===================== 4*61c4878aSAndroid Build Coastguard Worker0104: Display Support 5*61c4878aSAndroid Build Coastguard Worker===================== 6*61c4878aSAndroid Build Coastguard Worker.. seed:: 7*61c4878aSAndroid Build Coastguard Worker :number: 104 8*61c4878aSAndroid Build Coastguard Worker :name: Display Support 9*61c4878aSAndroid Build Coastguard Worker :status: Accepted 10*61c4878aSAndroid Build Coastguard Worker :proposal_date: 2023-06-12 11*61c4878aSAndroid Build Coastguard Worker :cl: 150793 12*61c4878aSAndroid Build Coastguard Worker :authors: Chris Mumford 13*61c4878aSAndroid Build Coastguard Worker :facilitator: Anthony DiGirolamo 14*61c4878aSAndroid Build Coastguard Worker 15*61c4878aSAndroid Build Coastguard Worker------- 16*61c4878aSAndroid Build Coastguard WorkerSummary 17*61c4878aSAndroid Build Coastguard Worker------- 18*61c4878aSAndroid Build Coastguard WorkerAdd support for graphics displays. This includes display drivers for a few 19*61c4878aSAndroid Build Coastguard Workerpopular display controllers, framebuffer management, and a framework to simplify 20*61c4878aSAndroid Build Coastguard Workeradding a graphics display to a Pigweed application. 21*61c4878aSAndroid Build Coastguard Worker 22*61c4878aSAndroid Build Coastguard Worker---------- 23*61c4878aSAndroid Build Coastguard WorkerMotivation 24*61c4878aSAndroid Build Coastguard Worker---------- 25*61c4878aSAndroid Build Coastguard WorkerPigweed currently has no specific support for a display device. Projects that 26*61c4878aSAndroid Build Coastguard Workerrequire a display currently must do the full implementation, including the 27*61c4878aSAndroid Build Coastguard Workerdisplay driver in most instances, to add display support. 28*61c4878aSAndroid Build Coastguard Worker 29*61c4878aSAndroid Build Coastguard WorkerThis proposes the addition of a basic framework for display devices, as well 30*61c4878aSAndroid Build Coastguard Workeras implementations for a few common Pigweed test devices - specifically the 31*61c4878aSAndroid Build Coastguard WorkerSTM32F429I. This enables developers to quickly and easily add display support 32*61c4878aSAndroid Build Coastguard Workerfor supported devices and an implementation to model when adding new device 33*61c4878aSAndroid Build Coastguard Workersupport. 34*61c4878aSAndroid Build Coastguard Worker 35*61c4878aSAndroid Build Coastguard Worker-------- 36*61c4878aSAndroid Build Coastguard WorkerProposal 37*61c4878aSAndroid Build Coastguard Worker-------- 38*61c4878aSAndroid Build Coastguard WorkerThis proposes no changes to existing modules, but suggests several new libraries 39*61c4878aSAndroid Build Coastguard Workerall within a single new module titled ``pw_display`` that together define a 40*61c4878aSAndroid Build Coastguard Workerframework for rendering to displays. 41*61c4878aSAndroid Build Coastguard Worker 42*61c4878aSAndroid Build Coastguard Worker 43*61c4878aSAndroid Build Coastguard WorkerNew Libraries 44*61c4878aSAndroid Build Coastguard Worker============= 45*61c4878aSAndroid Build Coastguard Worker.. list-table:: 46*61c4878aSAndroid Build Coastguard Worker :widths: 5 45 47*61c4878aSAndroid Build Coastguard Worker :header-rows: 1 48*61c4878aSAndroid Build Coastguard Worker 49*61c4878aSAndroid Build Coastguard Worker * - Library 50*61c4878aSAndroid Build Coastguard Worker - Function 51*61c4878aSAndroid Build Coastguard Worker 52*61c4878aSAndroid Build Coastguard Worker * - pw_display/display 53*61c4878aSAndroid Build Coastguard Worker - Manage draw thread, framebuffers, and driver 54*61c4878aSAndroid Build Coastguard Worker 55*61c4878aSAndroid Build Coastguard Worker * - pw_display/driver 56*61c4878aSAndroid Build Coastguard Worker - Display driver interface definition 57*61c4878aSAndroid Build Coastguard Worker 58*61c4878aSAndroid Build Coastguard Worker * - pw_display/pixel_pusher 59*61c4878aSAndroid Build Coastguard Worker - Transport of pixel data to display controller 60*61c4878aSAndroid Build Coastguard Worker 61*61c4878aSAndroid Build Coastguard Worker * - pw_display/drivers/ili9341 62*61c4878aSAndroid Build Coastguard Worker - Display driver for the ILI9341 display controller 63*61c4878aSAndroid Build Coastguard Worker 64*61c4878aSAndroid Build Coastguard Worker * - pw_display/drivers/imgui 65*61c4878aSAndroid Build Coastguard Worker - Host display driver using `Dear ImGui <https://www.dearimgui.com/>`_ 66*61c4878aSAndroid Build Coastguard Worker 67*61c4878aSAndroid Build Coastguard Worker * - pw_display/drivers/mipi 68*61c4878aSAndroid Build Coastguard Worker - Display driver for `MIPI DSI <https://www.mipi.org/specifications/dsi>`_ controllers 69*61c4878aSAndroid Build Coastguard Worker 70*61c4878aSAndroid Build Coastguard Worker * - pw_display/drivers/null 71*61c4878aSAndroid Build Coastguard Worker - Null display driver for headless devices 72*61c4878aSAndroid Build Coastguard Worker 73*61c4878aSAndroid Build Coastguard Worker * - pw_display/drivers/st7735 74*61c4878aSAndroid Build Coastguard Worker - Display driver for the `ST7735 <https://www.displayfuture.com/Display/datasheet/controller/ST7735.pdf>`_ display controller 75*61c4878aSAndroid Build Coastguard Worker 76*61c4878aSAndroid Build Coastguard Worker * - pw_display/drivers/st7789 77*61c4878aSAndroid Build Coastguard Worker - Display driver for the ST7789 display controller 78*61c4878aSAndroid Build Coastguard Worker 79*61c4878aSAndroid Build Coastguard Worker * - pw_display/draw 80*61c4878aSAndroid Build Coastguard Worker - Very basic drawing library for test and bring-up purposes 81*61c4878aSAndroid Build Coastguard Worker 82*61c4878aSAndroid Build Coastguard Worker * - pw_display/framebuffer 83*61c4878aSAndroid Build Coastguard Worker - Manage access to pixel buffer. 84*61c4878aSAndroid Build Coastguard Worker 85*61c4878aSAndroid Build Coastguard Worker * - pw_display/framebuffer_mcuxpresso 86*61c4878aSAndroid Build Coastguard Worker - Specialization of the framebuffer for the MCUxpresso devices 87*61c4878aSAndroid Build Coastguard Worker 88*61c4878aSAndroid Build Coastguard Worker * - pw_display/geometry 89*61c4878aSAndroid Build Coastguard Worker - Basic shared math types such as 2D vectors, etc. 90*61c4878aSAndroid Build Coastguard Worker 91*61c4878aSAndroid Build Coastguard Worker 92*61c4878aSAndroid Build Coastguard WorkerGeometry 93*61c4878aSAndroid Build Coastguard Worker======== 94*61c4878aSAndroid Build Coastguard Worker``pw_display/geometry`` contains two helper structures for common values usually 95*61c4878aSAndroid Build Coastguard Workerused as a pair. 96*61c4878aSAndroid Build Coastguard Worker 97*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 98*61c4878aSAndroid Build Coastguard Worker 99*61c4878aSAndroid Build Coastguard Worker namespace pw::display { 100*61c4878aSAndroid Build Coastguard Worker 101*61c4878aSAndroid Build Coastguard Worker template <typename T> 102*61c4878aSAndroid Build Coastguard Worker struct Size { 103*61c4878aSAndroid Build Coastguard Worker T width; 104*61c4878aSAndroid Build Coastguard Worker T height; 105*61c4878aSAndroid Build Coastguard Worker }; 106*61c4878aSAndroid Build Coastguard Worker 107*61c4878aSAndroid Build Coastguard Worker template <typename T> 108*61c4878aSAndroid Build Coastguard Worker struct Vector2 { 109*61c4878aSAndroid Build Coastguard Worker T x; 110*61c4878aSAndroid Build Coastguard Worker T y; 111*61c4878aSAndroid Build Coastguard Worker }; 112*61c4878aSAndroid Build Coastguard Worker 113*61c4878aSAndroid Build Coastguard Worker } // namespace pw::display 114*61c4878aSAndroid Build Coastguard Worker 115*61c4878aSAndroid Build Coastguard Worker 116*61c4878aSAndroid Build Coastguard WorkerFramebuffer 117*61c4878aSAndroid Build Coastguard Worker=========== 118*61c4878aSAndroid Build Coastguard WorkerA framebuffer is a small class that provides access to a pixel buffer. It 119*61c4878aSAndroid Build Coastguard Workerkeeps a copy of the pixel buffer metadata and provides accessor methods for 120*61c4878aSAndroid Build Coastguard Workerthose values. 121*61c4878aSAndroid Build Coastguard Worker 122*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 123*61c4878aSAndroid Build Coastguard Worker 124*61c4878aSAndroid Build Coastguard Worker namespace pw::display { 125*61c4878aSAndroid Build Coastguard Worker 126*61c4878aSAndroid Build Coastguard Worker enum class PixelFormat { 127*61c4878aSAndroid Build Coastguard Worker None, 128*61c4878aSAndroid Build Coastguard Worker RGB565, 129*61c4878aSAndroid Build Coastguard Worker }; 130*61c4878aSAndroid Build Coastguard Worker 131*61c4878aSAndroid Build Coastguard Worker class Framebuffer { 132*61c4878aSAndroid Build Coastguard Worker public: 133*61c4878aSAndroid Build Coastguard Worker // Construct a default invalid framebuffer. 134*61c4878aSAndroid Build Coastguard Worker Framebuffer(); 135*61c4878aSAndroid Build Coastguard Worker 136*61c4878aSAndroid Build Coastguard Worker Framebuffer(void* data, 137*61c4878aSAndroid Build Coastguard Worker PixelFormat pixel_format, 138*61c4878aSAndroid Build Coastguard Worker pw::math::Size<uint16_t> size, 139*61c4878aSAndroid Build Coastguard Worker uint16_t row_bytes); 140*61c4878aSAndroid Build Coastguard Worker 141*61c4878aSAndroid Build Coastguard Worker Framebuffer(const Framebuffer&) = delete; 142*61c4878aSAndroid Build Coastguard Worker Framebuffer(Framebuffer&& other); 143*61c4878aSAndroid Build Coastguard Worker 144*61c4878aSAndroid Build Coastguard Worker Framebuffer& operator=(const Framebuffer&) = delete; 145*61c4878aSAndroid Build Coastguard Worker Framebuffer& operator=(Framebuffer&&); 146*61c4878aSAndroid Build Coastguard Worker 147*61c4878aSAndroid Build Coastguard Worker bool is_valid() const; 148*61c4878aSAndroid Build Coastguard Worker 149*61c4878aSAndroid Build Coastguard Worker pw::ConstByteSpan data() const; 150*61c4878aSAndroid Build Coastguard Worker pw::ByteSpan data(); 151*61c4878aSAndroid Build Coastguard Worker 152*61c4878aSAndroid Build Coastguard Worker PixelFormat pixel_format() const; 153*61c4878aSAndroid Build Coastguard Worker 154*61c4878aSAndroid Build Coastguard Worker pw::math::Size<uint16_t> size(); 155*61c4878aSAndroid Build Coastguard Worker 156*61c4878aSAndroid Build Coastguard Worker uint16_t row_bytes() const; 157*61c4878aSAndroid Build Coastguard Worker }; 158*61c4878aSAndroid Build Coastguard Worker 159*61c4878aSAndroid Build Coastguard Worker } // namespace pw::display 160*61c4878aSAndroid Build Coastguard Worker 161*61c4878aSAndroid Build Coastguard WorkerFrameBuffer is a moveable class that is intended to signify read/write 162*61c4878aSAndroid Build Coastguard Workerprivileges to the underlying pixel data. This makes it easier to track when the 163*61c4878aSAndroid Build Coastguard Workerpixel data may be read from, or written to, without conflict. 164*61c4878aSAndroid Build Coastguard Worker 165*61c4878aSAndroid Build Coastguard WorkerThe framebuffer does not own the underlying pixel buffer. In other words 166*61c4878aSAndroid Build Coastguard Workerthe deletion of a framebuffer will not free the underlying pixel data. 167*61c4878aSAndroid Build Coastguard Worker 168*61c4878aSAndroid Build Coastguard WorkerFramebuffers do not have methods for reading or writing to the underlying pixel 169*61c4878aSAndroid Build Coastguard Workerbuffer. This is the responsibility of the the selected graphics library which 170*61c4878aSAndroid Build Coastguard Workercan be given the pixel buffer pointer retrieved by calling ``data()``. 171*61c4878aSAndroid Build Coastguard Worker 172*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 173*61c4878aSAndroid Build Coastguard Worker 174*61c4878aSAndroid Build Coastguard Worker constexpr size_t kWidth = 64; 175*61c4878aSAndroid Build Coastguard Worker constexpr size_t kHeight = 32; 176*61c4878aSAndroid Build Coastguard Worker uint16_t pixel_data[kWidth * kHeight]; 177*61c4878aSAndroid Build Coastguard Worker 178*61c4878aSAndroid Build Coastguard Worker void DrawScreen(Framebuffer* fb) { 179*61c4878aSAndroid Build Coastguard Worker // Clear framebuffer to black. 180*61c4878aSAndroid Build Coastguard Worker std::memset(fb->data(), 0, fb->height() * fb->row_bytes()); 181*61c4878aSAndroid Build Coastguard Worker 182*61c4878aSAndroid Build Coastguard Worker // Set first pixel to white. 183*61c4878aSAndroid Build Coastguard Worker uint16_t* pixel_data = static_cast<uint16_t*>(fb->data()); 184*61c4878aSAndroid Build Coastguard Worker pixel_data[0] = 0xffff; 185*61c4878aSAndroid Build Coastguard Worker } 186*61c4878aSAndroid Build Coastguard Worker 187*61c4878aSAndroid Build Coastguard Worker Framebuffer fb(pixel_data, {kWidth, kHeight}, 188*61c4878aSAndroid Build Coastguard Worker PixelFormat::RGB565, 189*61c4878aSAndroid Build Coastguard Worker kWidth * sizeof(uint16_t)); 190*61c4878aSAndroid Build Coastguard Worker DrawScreen(&fb); 191*61c4878aSAndroid Build Coastguard Worker 192*61c4878aSAndroid Build Coastguard WorkerFramebufferPool 193*61c4878aSAndroid Build Coastguard Worker=============== 194*61c4878aSAndroid Build Coastguard WorkerThe FramebufferPool is intended to simplify the use of multiple framebuffers 195*61c4878aSAndroid Build Coastguard Workerwhen multi-buffered rendering is being used. It is a collection of framebuffers 196*61c4878aSAndroid Build Coastguard Workerwhich can be retrieved, used, and then returned to the pool for reuse. All 197*61c4878aSAndroid Build Coastguard Workerframebuffers in the pool share identical attributes. A framebuffer that is 198*61c4878aSAndroid Build Coastguard Workerreturned to a caller of ``GetFramebuffer()`` can be thought of as "on loan" to 199*61c4878aSAndroid Build Coastguard Workerthat caller and will not be given to any other caller of ``GetFramebuffer()`` 200*61c4878aSAndroid Build Coastguard Workeruntil it has been returned by calling ``ReleaseFramebuffer()``. 201*61c4878aSAndroid Build Coastguard Worker 202*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 203*61c4878aSAndroid Build Coastguard Worker 204*61c4878aSAndroid Build Coastguard Worker namespace pw::display { 205*61c4878aSAndroid Build Coastguard Worker 206*61c4878aSAndroid Build Coastguard Worker class FramebufferPool { 207*61c4878aSAndroid Build Coastguard Worker public: 208*61c4878aSAndroid Build Coastguard Worker using BufferArray = std::array<void*, FRAMEBUFFER_COUNT>; 209*61c4878aSAndroid Build Coastguard Worker 210*61c4878aSAndroid Build Coastguard Worker // Constructor parameters. 211*61c4878aSAndroid Build Coastguard Worker struct Config { 212*61c4878aSAndroid Build Coastguard Worker BufferArray fb_addr; // Address of each buffer in this pool. 213*61c4878aSAndroid Build Coastguard Worker pw::math::Size<uint16_t> dimensions; // width/height of each buffer. 214*61c4878aSAndroid Build Coastguard Worker uint16_t row_bytes; // row bytes of each buffer. 215*61c4878aSAndroid Build Coastguard Worker pw::framebuffer::PixelFormat pixel_format; 216*61c4878aSAndroid Build Coastguard Worker }; 217*61c4878aSAndroid Build Coastguard Worker 218*61c4878aSAndroid Build Coastguard Worker FramebufferPool(const Config& config); 219*61c4878aSAndroid Build Coastguard Worker virtual ~FramebufferPool(); 220*61c4878aSAndroid Build Coastguard Worker 221*61c4878aSAndroid Build Coastguard Worker uint16_t row_bytes() const; 222*61c4878aSAndroid Build Coastguard Worker 223*61c4878aSAndroid Build Coastguard Worker pw::math::Size<uint16_t> dimensions() const; 224*61c4878aSAndroid Build Coastguard Worker 225*61c4878aSAndroid Build Coastguard Worker pw::framebuffer::PixelFormat pixel_format() const; 226*61c4878aSAndroid Build Coastguard Worker 227*61c4878aSAndroid Build Coastguard Worker // Return a framebuffer to the caller for use. This call WILL BLOCK until a 228*61c4878aSAndroid Build Coastguard Worker // framebuffer is returned for use. Framebuffers *must* be returned to this 229*61c4878aSAndroid Build Coastguard Worker // pool by a corresponding call to ReleaseFramebuffer. This function will only 230*61c4878aSAndroid Build Coastguard Worker // return a valid framebuffer. 231*61c4878aSAndroid Build Coastguard Worker // 232*61c4878aSAndroid Build Coastguard Worker // This call is thread-safe, but not interrupt safe. 233*61c4878aSAndroid Build Coastguard Worker virtual pw::framebuffer::Framebuffer GetFramebuffer(); 234*61c4878aSAndroid Build Coastguard Worker 235*61c4878aSAndroid Build Coastguard Worker // Return the framebuffer to the pool available for use by the next call to 236*61c4878aSAndroid Build Coastguard Worker // GetFramebuffer. 237*61c4878aSAndroid Build Coastguard Worker // 238*61c4878aSAndroid Build Coastguard Worker // This may be called on another thread or during an interrupt. 239*61c4878aSAndroid Build Coastguard Worker virtual Status ReleaseFramebuffer(pw::framebuffer::Framebuffer framebuffer); 240*61c4878aSAndroid Build Coastguard Worker }; 241*61c4878aSAndroid Build Coastguard Worker 242*61c4878aSAndroid Build Coastguard Worker } // namespace pw::display 243*61c4878aSAndroid Build Coastguard Worker 244*61c4878aSAndroid Build Coastguard WorkerAn example use of the framebuffer pool is: 245*61c4878aSAndroid Build Coastguard Worker 246*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 247*61c4878aSAndroid Build Coastguard Worker 248*61c4878aSAndroid Build Coastguard Worker // Retrieve a framebuffer for drawing. May block if pool has no framebuffers 249*61c4878aSAndroid Build Coastguard Worker // to issue. 250*61c4878aSAndroid Build Coastguard Worker FrameBuffer fb = framebuffer_pool.GetFramebuffer(); 251*61c4878aSAndroid Build Coastguard Worker 252*61c4878aSAndroid Build Coastguard Worker // Draw to the framebuffer. 253*61c4878aSAndroid Build Coastguard Worker UpdateDisplay(&fb); 254*61c4878aSAndroid Build Coastguard Worker 255*61c4878aSAndroid Build Coastguard Worker // Return the framebuffer to the pool for reuse. 256*61c4878aSAndroid Build Coastguard Worker framebuffer_pool.ReleaseFramebuffer(std::move(fb)); 257*61c4878aSAndroid Build Coastguard Worker 258*61c4878aSAndroid Build Coastguard WorkerDisplayDriver 259*61c4878aSAndroid Build Coastguard Worker============= 260*61c4878aSAndroid Build Coastguard WorkerA DisplayDriver is usually the sole class responsible for communicating with the 261*61c4878aSAndroid Build Coastguard Workerdisplay controller. Its primary responsibilities are the display controller 262*61c4878aSAndroid Build Coastguard Workerinitialization, and the writing of pixel data when a display update is needed. 263*61c4878aSAndroid Build Coastguard Worker 264*61c4878aSAndroid Build Coastguard WorkerThis proposal supports multiple heterogenous display controllers. This could be: 265*61c4878aSAndroid Build Coastguard Worker 266*61c4878aSAndroid Build Coastguard Worker1. A single display of any given type (e.g. ILI9341). 267*61c4878aSAndroid Build Coastguard Worker2. Two ILI9341 displays. 268*61c4878aSAndroid Build Coastguard Worker3. Two ILI9341 displays and a second one of a different type. 269*61c4878aSAndroid Build Coastguard Worker 270*61c4878aSAndroid Build Coastguard WorkerBecause of this approach the DisplayDriver is defined as an interface: 271*61c4878aSAndroid Build Coastguard Worker 272*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 273*61c4878aSAndroid Build Coastguard Worker 274*61c4878aSAndroid Build Coastguard Worker namespace pw::display { 275*61c4878aSAndroid Build Coastguard Worker 276*61c4878aSAndroid Build Coastguard Worker class DisplayDriver { 277*61c4878aSAndroid Build Coastguard Worker public: 278*61c4878aSAndroid Build Coastguard Worker // Called on the completion of a write operation. 279*61c4878aSAndroid Build Coastguard Worker using WriteCallback = Callback<void(framebuffer::Framebuffer, Status)>; 280*61c4878aSAndroid Build Coastguard Worker 281*61c4878aSAndroid Build Coastguard Worker virtual ~DisplayDriver() = default; 282*61c4878aSAndroid Build Coastguard Worker 283*61c4878aSAndroid Build Coastguard Worker virtual Status Init() = 0; 284*61c4878aSAndroid Build Coastguard Worker 285*61c4878aSAndroid Build Coastguard Worker virtual void WriteFramebuffer(pw::framebuffer::Framebuffer framebuffer, 286*61c4878aSAndroid Build Coastguard Worker WriteCallback write_callback) = 0; 287*61c4878aSAndroid Build Coastguard Worker 288*61c4878aSAndroid Build Coastguard Worker virtual pw::math::Size<uint16_t> size() const = 0; 289*61c4878aSAndroid Build Coastguard Worker }; 290*61c4878aSAndroid Build Coastguard Worker 291*61c4878aSAndroid Build Coastguard Worker } // namespace pw::display 292*61c4878aSAndroid Build Coastguard Worker 293*61c4878aSAndroid Build Coastguard WorkerEach driver then provides a concrete implementation of the driver. Below is the 294*61c4878aSAndroid Build Coastguard Workerdefinition of the display driver for the ILI9341: 295*61c4878aSAndroid Build Coastguard Worker 296*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 297*61c4878aSAndroid Build Coastguard Worker 298*61c4878aSAndroid Build Coastguard Worker namespace pw::display { 299*61c4878aSAndroid Build Coastguard Worker 300*61c4878aSAndroid Build Coastguard Worker class DisplayDriverILI9341 : public DisplayDriver { 301*61c4878aSAndroid Build Coastguard Worker public: 302*61c4878aSAndroid Build Coastguard Worker struct Config { 303*61c4878aSAndroid Build Coastguard Worker // Device specific initialization parameters. 304*61c4878aSAndroid Build Coastguard Worker }; 305*61c4878aSAndroid Build Coastguard Worker 306*61c4878aSAndroid Build Coastguard Worker DisplayDriverILI9341(const Config& config); 307*61c4878aSAndroid Build Coastguard Worker 308*61c4878aSAndroid Build Coastguard Worker // DisplayDriver implementation: 309*61c4878aSAndroid Build Coastguard Worker Status Init() override; 310*61c4878aSAndroid Build Coastguard Worker void WriteFramebuffer(pw::framebuffer::Framebuffer framebuffer, 311*61c4878aSAndroid Build Coastguard Worker WriteCallback write_callback) override; 312*61c4878aSAndroid Build Coastguard Worker Status WriteRow(span<uint16_t> row_pixels, 313*61c4878aSAndroid Build Coastguard Worker uint16_t row_idx, 314*61c4878aSAndroid Build Coastguard Worker uint16_t col_idx) override; 315*61c4878aSAndroid Build Coastguard Worker pw::math::Size<uint16_t> size() const override; 316*61c4878aSAndroid Build Coastguard Worker 317*61c4878aSAndroid Build Coastguard Worker private: 318*61c4878aSAndroid Build Coastguard Worker enum class Mode { 319*61c4878aSAndroid Build Coastguard Worker kData, 320*61c4878aSAndroid Build Coastguard Worker kCommand, 321*61c4878aSAndroid Build Coastguard Worker }; 322*61c4878aSAndroid Build Coastguard Worker 323*61c4878aSAndroid Build Coastguard Worker // A command and optional data to write to the ILI9341. 324*61c4878aSAndroid Build Coastguard Worker struct Command { 325*61c4878aSAndroid Build Coastguard Worker uint8_t command; 326*61c4878aSAndroid Build Coastguard Worker ConstByteSpan command_data; 327*61c4878aSAndroid Build Coastguard Worker }; 328*61c4878aSAndroid Build Coastguard Worker 329*61c4878aSAndroid Build Coastguard Worker // Toggle the reset GPIO line to reset the display controller. 330*61c4878aSAndroid Build Coastguard Worker Status Reset(); 331*61c4878aSAndroid Build Coastguard Worker 332*61c4878aSAndroid Build Coastguard Worker // Set the command/data mode of the display controller. 333*61c4878aSAndroid Build Coastguard Worker void SetMode(Mode mode); 334*61c4878aSAndroid Build Coastguard Worker // Write the command to the display controller. 335*61c4878aSAndroid Build Coastguard Worker Status WriteCommand(pw::spi::Device::Transaction& transaction, 336*61c4878aSAndroid Build Coastguard Worker const Command& command); 337*61c4878aSAndroid Build Coastguard Worker }; 338*61c4878aSAndroid Build Coastguard Worker 339*61c4878aSAndroid Build Coastguard Worker } // namespace pw::display 340*61c4878aSAndroid Build Coastguard Worker 341*61c4878aSAndroid Build Coastguard WorkerHere is an example retrieving a framebuffer from the framebuffer pool, drawing 342*61c4878aSAndroid Build Coastguard Workerinto the framebuffer, using the display driver to write the pixel data, and then 343*61c4878aSAndroid Build Coastguard Workerreturning the framebuffer back to the pool for use. 344*61c4878aSAndroid Build Coastguard Worker 345*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 346*61c4878aSAndroid Build Coastguard Worker 347*61c4878aSAndroid Build Coastguard Worker FrameBuffer fb = framebuffer_pool.GetFramebuffer(); 348*61c4878aSAndroid Build Coastguard Worker 349*61c4878aSAndroid Build Coastguard Worker // DrawScreen is a function that will draw to the framebuffer's underlying 350*61c4878aSAndroid Build Coastguard Worker // pixel buffer using a drawing library. See example above. 351*61c4878aSAndroid Build Coastguard Worker DrawScreen(&fb); 352*61c4878aSAndroid Build Coastguard Worker 353*61c4878aSAndroid Build Coastguard Worker display_driver_.WriteFramebuffer( 354*61c4878aSAndroid Build Coastguard Worker std::move(framebuffer), 355*61c4878aSAndroid Build Coastguard Worker [&framebuffer_pool](pw::framebuffer::Framebuffer fb, Status status) { 356*61c4878aSAndroid Build Coastguard Worker // Return the framebuffer back to the pool for reuse once the display 357*61c4878aSAndroid Build Coastguard Worker // write is complete. 358*61c4878aSAndroid Build Coastguard Worker framebuffer_pool.ReleaseFramebuffer(std::move(fb)); 359*61c4878aSAndroid Build Coastguard Worker }); 360*61c4878aSAndroid Build Coastguard Worker 361*61c4878aSAndroid Build Coastguard WorkerIn the example above that the framebuffer (``fb``) is moved when calling 362*61c4878aSAndroid Build Coastguard Worker``WriteFramebuffer()`` passing ownership to the display driver. From this point 363*61c4878aSAndroid Build Coastguard Workerforward the application code may not access the framebuffer in any way. When the 364*61c4878aSAndroid Build Coastguard Workerframebuffer write is complete the framebuffer is then moved to the callback 365*61c4878aSAndroid Build Coastguard Workerwhich in turn moves it when calling ``ReleaseFramebuffer()``. 366*61c4878aSAndroid Build Coastguard Worker 367*61c4878aSAndroid Build Coastguard Worker``WriteFramebuffer()`` always does a write of the full framebuffer - sending all 368*61c4878aSAndroid Build Coastguard Workerpixel data. 369*61c4878aSAndroid Build Coastguard Worker 370*61c4878aSAndroid Build Coastguard Worker``WriteFramebuffer()`` may be a blocking call, but on some platforms the driver 371*61c4878aSAndroid Build Coastguard Workermay use a background write and the write callback is called when the write 372*61c4878aSAndroid Build Coastguard Workeris complete. The write callback **may be called during an interrupt**. 373*61c4878aSAndroid Build Coastguard Worker 374*61c4878aSAndroid Build Coastguard WorkerPixelPusher 375*61c4878aSAndroid Build Coastguard Worker=========== 376*61c4878aSAndroid Build Coastguard WorkerPixel data for Simple SPI based display controllers can be written to the 377*61c4878aSAndroid Build Coastguard Workerdisplay controller using ``pw_spi``. There are some controllers which use 378*61c4878aSAndroid Build Coastguard Workerother interfaces (RGB, MIPI, etc.). Also, some vendors provide an API for 379*61c4878aSAndroid Build Coastguard Workerinteracting with these display controllers for writing pixel data. 380*61c4878aSAndroid Build Coastguard Worker 381*61c4878aSAndroid Build Coastguard WorkerTo allow the drivers to be hardware/vendor independent the ``PixelPusher`` 382*61c4878aSAndroid Build Coastguard Workermay be used. This defines an interface whose sole responsibility is to write 383*61c4878aSAndroid Build Coastguard Workera framebuffer to the display controller. Specializations of this will use 384*61c4878aSAndroid Build Coastguard Worker``pw_spi`` or vendor proprietary calls to write pixel data. 385*61c4878aSAndroid Build Coastguard Worker 386*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 387*61c4878aSAndroid Build Coastguard Worker 388*61c4878aSAndroid Build Coastguard Worker namespace pw::display { 389*61c4878aSAndroid Build Coastguard Worker 390*61c4878aSAndroid Build Coastguard Worker class PixelPusher { 391*61c4878aSAndroid Build Coastguard Worker public: 392*61c4878aSAndroid Build Coastguard Worker using WriteCallback = Callback<void(framebuffer::Framebuffer, Status)>; 393*61c4878aSAndroid Build Coastguard Worker 394*61c4878aSAndroid Build Coastguard Worker virtual ~PixelPusher() = default; 395*61c4878aSAndroid Build Coastguard Worker 396*61c4878aSAndroid Build Coastguard Worker virtual Status Init( 397*61c4878aSAndroid Build Coastguard Worker const pw::framebuffer_pool::FramebufferPool& framebuffer_pool) = 0; 398*61c4878aSAndroid Build Coastguard Worker 399*61c4878aSAndroid Build Coastguard Worker virtual void WriteFramebuffer(framebuffer::Framebuffer framebuffer, 400*61c4878aSAndroid Build Coastguard Worker WriteCallback complete_callback) = 0; 401*61c4878aSAndroid Build Coastguard Worker }; 402*61c4878aSAndroid Build Coastguard Worker 403*61c4878aSAndroid Build Coastguard Worker } // namespace pw::display 404*61c4878aSAndroid Build Coastguard Worker 405*61c4878aSAndroid Build Coastguard WorkerDisplay 406*61c4878aSAndroid Build Coastguard Worker======= 407*61c4878aSAndroid Build Coastguard WorkerEach display has: 408*61c4878aSAndroid Build Coastguard Worker 409*61c4878aSAndroid Build Coastguard Worker1. One and only one display driver. 410*61c4878aSAndroid Build Coastguard Worker2. A reference to a single framebuffer pool. This framebuffer pool may be shared 411*61c4878aSAndroid Build Coastguard Worker with other displays. 412*61c4878aSAndroid Build Coastguard Worker3. A drawing thread, if so configured, for asynchronous display updates. 413*61c4878aSAndroid Build Coastguard Worker 414*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 415*61c4878aSAndroid Build Coastguard Worker 416*61c4878aSAndroid Build Coastguard Worker namespace pw::display { 417*61c4878aSAndroid Build Coastguard Worker 418*61c4878aSAndroid Build Coastguard Worker class Display { 419*61c4878aSAndroid Build Coastguard Worker public: 420*61c4878aSAndroid Build Coastguard Worker // Called on the completion of an update. 421*61c4878aSAndroid Build Coastguard Worker using WriteCallback = Callback<void(Status)>; 422*61c4878aSAndroid Build Coastguard Worker 423*61c4878aSAndroid Build Coastguard Worker Display(pw::display_driver::DisplayDriver& display_driver, 424*61c4878aSAndroid Build Coastguard Worker pw::math::Size<uint16_t> size, 425*61c4878aSAndroid Build Coastguard Worker pw::framebuffer_pool::FramebufferPool& framebuffer_pool); 426*61c4878aSAndroid Build Coastguard Worker virtual ~Display(); 427*61c4878aSAndroid Build Coastguard Worker 428*61c4878aSAndroid Build Coastguard Worker pw::framebuffer::Framebuffer GetFramebuffer(); 429*61c4878aSAndroid Build Coastguard Worker 430*61c4878aSAndroid Build Coastguard Worker void ReleaseFramebuffer(pw::framebuffer::Framebuffer framebuffer, 431*61c4878aSAndroid Build Coastguard Worker WriteCallback callback); 432*61c4878aSAndroid Build Coastguard Worker 433*61c4878aSAndroid Build Coastguard Worker pw::math::Size<uint16_t> size() const; 434*61c4878aSAndroid Build Coastguard Worker }; 435*61c4878aSAndroid Build Coastguard Worker 436*61c4878aSAndroid Build Coastguard Worker } // namespace pw::display 437*61c4878aSAndroid Build Coastguard Worker 438*61c4878aSAndroid Build Coastguard WorkerOnce applications are initialized they typically will not directly interact with 439*61c4878aSAndroid Build Coastguard Workerdisplay drivers or framebuffer pools. These will be utilized by the display 440*61c4878aSAndroid Build Coastguard Workerwhich will provide a simpler interface. 441*61c4878aSAndroid Build Coastguard Worker 442*61c4878aSAndroid Build Coastguard Worker``Display::GetFramebuffer()`` must always be called on the same thread and is not 443*61c4878aSAndroid Build Coastguard Workerinterrupt safe. It will block if there is no available framebuffer in the 444*61c4878aSAndroid Build Coastguard Workerframebuffer pool waiting for a framebuffer to be returned. 445*61c4878aSAndroid Build Coastguard Worker 446*61c4878aSAndroid Build Coastguard Worker``Display::ReleaseFramebuffer()`` must be called for each framebuffer returned by 447*61c4878aSAndroid Build Coastguard Worker``Display::GetFramebuffer()``. This will initiate the display update using the 448*61c4878aSAndroid Build Coastguard Workerdisplays associated driver. The ``callback`` will be called when this update is 449*61c4878aSAndroid Build Coastguard Workercomplete. 450*61c4878aSAndroid Build Coastguard Worker 451*61c4878aSAndroid Build Coastguard WorkerA simplified application rendering loop would resemble: 452*61c4878aSAndroid Build Coastguard Worker 453*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 454*61c4878aSAndroid Build Coastguard Worker 455*61c4878aSAndroid Build Coastguard Worker // Get a framebuffer for drawing. 456*61c4878aSAndroid Build Coastguard Worker FrameBuffer fb = display.GetFramebuffer(); 457*61c4878aSAndroid Build Coastguard Worker 458*61c4878aSAndroid Build Coastguard Worker // DrawScreen is a function that will draw to |fb|'s pixel buffer using a 459*61c4878aSAndroid Build Coastguard Worker // drawing library. See example above. 460*61c4878aSAndroid Build Coastguard Worker DrawScreen(&fb); 461*61c4878aSAndroid Build Coastguard Worker 462*61c4878aSAndroid Build Coastguard Worker // Return the framebuffer to the display which will be written to the display 463*61c4878aSAndroid Build Coastguard Worker // controller by the display's display driver. 464*61c4878aSAndroid Build Coastguard Worker display.ReleaseFramebuffer(std::move(fb), [](Status){}); 465*61c4878aSAndroid Build Coastguard Worker 466*61c4878aSAndroid Build Coastguard WorkerDrawing Library 467*61c4878aSAndroid Build Coastguard Worker=============== 468*61c4878aSAndroid Build Coastguard Worker``pw_display/draw`` was created for testing and verification purposes only. It is 469*61c4878aSAndroid Build Coastguard Workernot intended to be feature rich or performant in any way. This is small 470*61c4878aSAndroid Build Coastguard Workercollection of basic drawing primitives not intended to be used by shipping 471*61c4878aSAndroid Build Coastguard Workerapplications. 472*61c4878aSAndroid Build Coastguard Worker 473*61c4878aSAndroid Build Coastguard Worker.. code-block:: cpp 474*61c4878aSAndroid Build Coastguard Worker 475*61c4878aSAndroid Build Coastguard Worker namespace pw::display { 476*61c4878aSAndroid Build Coastguard Worker 477*61c4878aSAndroid Build Coastguard Worker void DrawLine(pw::framebuffer::Framebuffer& fb, 478*61c4878aSAndroid Build Coastguard Worker int x1, 479*61c4878aSAndroid Build Coastguard Worker int y1, 480*61c4878aSAndroid Build Coastguard Worker int x2, 481*61c4878aSAndroid Build Coastguard Worker int y2, 482*61c4878aSAndroid Build Coastguard Worker pw::color::color_rgb565_t pen_color); 483*61c4878aSAndroid Build Coastguard Worker 484*61c4878aSAndroid Build Coastguard Worker // Draw a circle at center_x, center_y with given radius and color. Only a 485*61c4878aSAndroid Build Coastguard Worker // one-pixel outline is drawn if filled is false. 486*61c4878aSAndroid Build Coastguard Worker void DrawCircle(pw::framebuffer::Framebuffer& fb, 487*61c4878aSAndroid Build Coastguard Worker int center_x, 488*61c4878aSAndroid Build Coastguard Worker int center_y, 489*61c4878aSAndroid Build Coastguard Worker int radius, 490*61c4878aSAndroid Build Coastguard Worker pw::color::color_rgb565_t pen_color, 491*61c4878aSAndroid Build Coastguard Worker bool filled); 492*61c4878aSAndroid Build Coastguard Worker 493*61c4878aSAndroid Build Coastguard Worker void DrawHLine(pw::framebuffer::Framebuffer& fb, 494*61c4878aSAndroid Build Coastguard Worker int x1, 495*61c4878aSAndroid Build Coastguard Worker int x2, 496*61c4878aSAndroid Build Coastguard Worker int y, 497*61c4878aSAndroid Build Coastguard Worker pw::color::color_rgb565_t pen_color); 498*61c4878aSAndroid Build Coastguard Worker 499*61c4878aSAndroid Build Coastguard Worker void DrawRect(pw::framebuffer::Framebuffer& fb, 500*61c4878aSAndroid Build Coastguard Worker int x1, 501*61c4878aSAndroid Build Coastguard Worker int y1, 502*61c4878aSAndroid Build Coastguard Worker int x2, 503*61c4878aSAndroid Build Coastguard Worker int y2, 504*61c4878aSAndroid Build Coastguard Worker pw::color::color_rgb565_t pen_color, 505*61c4878aSAndroid Build Coastguard Worker bool filled); 506*61c4878aSAndroid Build Coastguard Worker 507*61c4878aSAndroid Build Coastguard Worker void DrawRectWH(pw::framebuffer::Framebuffer& fb, 508*61c4878aSAndroid Build Coastguard Worker int x, 509*61c4878aSAndroid Build Coastguard Worker int y, 510*61c4878aSAndroid Build Coastguard Worker int w, 511*61c4878aSAndroid Build Coastguard Worker int h, 512*61c4878aSAndroid Build Coastguard Worker pw::color::color_rgb565_t pen_color, 513*61c4878aSAndroid Build Coastguard Worker bool filled); 514*61c4878aSAndroid Build Coastguard Worker 515*61c4878aSAndroid Build Coastguard Worker void Fill(pw::framebuffer::Framebuffer& fb, 516*61c4878aSAndroid Build Coastguard Worker pw::color::color_rgb565_t pen_color); 517*61c4878aSAndroid Build Coastguard Worker 518*61c4878aSAndroid Build Coastguard Worker void DrawSprite(pw::framebuffer::Framebuffer& fb, 519*61c4878aSAndroid Build Coastguard Worker int x, 520*61c4878aSAndroid Build Coastguard Worker int y, 521*61c4878aSAndroid Build Coastguard Worker pw::draw::SpriteSheet* sprite_sheet, 522*61c4878aSAndroid Build Coastguard Worker int integer_scale); 523*61c4878aSAndroid Build Coastguard Worker 524*61c4878aSAndroid Build Coastguard Worker void DrawTestPattern(); 525*61c4878aSAndroid Build Coastguard Worker 526*61c4878aSAndroid Build Coastguard Worker pw::math::Size<int> DrawCharacter(int ch, 527*61c4878aSAndroid Build Coastguard Worker pw::math::Vector2<int> pos, 528*61c4878aSAndroid Build Coastguard Worker pw::color::color_rgb565_t fg_color, 529*61c4878aSAndroid Build Coastguard Worker pw::color::color_rgb565_t bg_color, 530*61c4878aSAndroid Build Coastguard Worker const FontSet& font, 531*61c4878aSAndroid Build Coastguard Worker pw::framebuffer::Framebuffer& framebuffer); 532*61c4878aSAndroid Build Coastguard Worker 533*61c4878aSAndroid Build Coastguard Worker pw::math::Size<int> DrawString(std::wstring_view str, 534*61c4878aSAndroid Build Coastguard Worker pw::math::Vector2<int> pos, 535*61c4878aSAndroid Build Coastguard Worker pw::color::color_rgb565_t fg_color, 536*61c4878aSAndroid Build Coastguard Worker pw::color::color_rgb565_t bg_color, 537*61c4878aSAndroid Build Coastguard Worker const FontSet& font, 538*61c4878aSAndroid Build Coastguard Worker pw::framebuffer::Framebuffer& framebuffer); 539*61c4878aSAndroid Build Coastguard Worker 540*61c4878aSAndroid Build Coastguard Worker } // namespace pw::display 541*61c4878aSAndroid Build Coastguard Worker 542*61c4878aSAndroid Build Coastguard WorkerClass Interaction Diagram 543*61c4878aSAndroid Build Coastguard Worker========================= 544*61c4878aSAndroid Build Coastguard Worker.. mermaid:: 545*61c4878aSAndroid Build Coastguard Worker :alt: Framebuffer Classes 546*61c4878aSAndroid Build Coastguard Worker :align: center 547*61c4878aSAndroid Build Coastguard Worker 548*61c4878aSAndroid Build Coastguard Worker classDiagram 549*61c4878aSAndroid Build Coastguard Worker class FramebufferPool { 550*61c4878aSAndroid Build Coastguard Worker uint16_t row_bytes() 551*61c4878aSAndroid Build Coastguard Worker PixelFormat pixel_format() 552*61c4878aSAndroid Build Coastguard Worker dimensions() : Size~uint16_t~ 553*61c4878aSAndroid Build Coastguard Worker row_bytes() : uint16_t 554*61c4878aSAndroid Build Coastguard Worker GetFramebuffer() : Framebuffer 555*61c4878aSAndroid Build Coastguard Worker 556*61c4878aSAndroid Build Coastguard Worker BufferArray buffer_addresses_ 557*61c4878aSAndroid Build Coastguard Worker Size~uint16_t~ buffer_dimensions_ 558*61c4878aSAndroid Build Coastguard Worker uint16_t row_bytes_ 559*61c4878aSAndroid Build Coastguard Worker PixelFormat pixel_format_ 560*61c4878aSAndroid Build Coastguard Worker } 561*61c4878aSAndroid Build Coastguard Worker 562*61c4878aSAndroid Build Coastguard Worker class Framebuffer { 563*61c4878aSAndroid Build Coastguard Worker is_valid() : bool const 564*61c4878aSAndroid Build Coastguard Worker data() : void* const 565*61c4878aSAndroid Build Coastguard Worker pixel_format() : PixelFormat const 566*61c4878aSAndroid Build Coastguard Worker size() : Size~uint16_t~ const 567*61c4878aSAndroid Build Coastguard Worker row_bytes() uint16_t const 568*61c4878aSAndroid Build Coastguard Worker 569*61c4878aSAndroid Build Coastguard Worker void* pixel_data_ 570*61c4878aSAndroid Build Coastguard Worker Size~uint16_t~ size_ 571*61c4878aSAndroid Build Coastguard Worker PixelFormat pixel_format_ 572*61c4878aSAndroid Build Coastguard Worker uint16_t row_bytes_ 573*61c4878aSAndroid Build Coastguard Worker } 574*61c4878aSAndroid Build Coastguard Worker 575*61c4878aSAndroid Build Coastguard Worker class DisplayDriver { 576*61c4878aSAndroid Build Coastguard Worker <<DisplayDriver>> 577*61c4878aSAndroid Build Coastguard Worker Init() : Status 578*61c4878aSAndroid Build Coastguard Worker WriteFramebuffer(Framebuffer fb, WriteCallback cb): void 579*61c4878aSAndroid Build Coastguard Worker dimensions() : Size~uint16_t~ 580*61c4878aSAndroid Build Coastguard Worker 581*61c4878aSAndroid Build Coastguard Worker PixelPusher& pixel_pusher_ 582*61c4878aSAndroid Build Coastguard Worker } 583*61c4878aSAndroid Build Coastguard Worker 584*61c4878aSAndroid Build Coastguard Worker class Display { 585*61c4878aSAndroid Build Coastguard Worker DisplayDriver& display_driver_ 586*61c4878aSAndroid Build Coastguard Worker const Size~uint16_t~ size_ 587*61c4878aSAndroid Build Coastguard Worker FramebufferPool& framebuffer_pool_ 588*61c4878aSAndroid Build Coastguard Worker 589*61c4878aSAndroid Build Coastguard Worker GetFramebuffer() : Framebuffer 590*61c4878aSAndroid Build Coastguard Worker } 591*61c4878aSAndroid Build Coastguard Worker 592*61c4878aSAndroid Build Coastguard Worker class PixelPusher { 593*61c4878aSAndroid Build Coastguard Worker Init() : Status 594*61c4878aSAndroid Build Coastguard Worker WriteFramebuffer(Framebuffer fb, WriteCallback cb) : void 595*61c4878aSAndroid Build Coastguard Worker } 596*61c4878aSAndroid Build Coastguard Worker 597*61c4878aSAndroid Build Coastguard Worker <<interface>> DisplayDriver 598*61c4878aSAndroid Build Coastguard Worker FramebufferPool --> "FRAMEBUFFER_COUNT" Framebuffer : buffer_addresses_ 599*61c4878aSAndroid Build Coastguard Worker 600*61c4878aSAndroid Build Coastguard Worker Display --> "1" DisplayDriver : display_driver_ 601*61c4878aSAndroid Build Coastguard Worker Display --> "1" FramebufferPool : framebuffer_pool_ 602*61c4878aSAndroid Build Coastguard Worker DisplayDriver --> "1" PixelPusher : pixel_pusher_ 603*61c4878aSAndroid Build Coastguard Worker 604*61c4878aSAndroid Build Coastguard Worker--------------------- 605*61c4878aSAndroid Build Coastguard WorkerProblem investigation 606*61c4878aSAndroid Build Coastguard Worker--------------------- 607*61c4878aSAndroid Build Coastguard WorkerWith no direct display support in Pigweed and no example programs implementing 608*61c4878aSAndroid Build Coastguard Workera solution Pigweed developers are essentially on their own. Depending on their 609*61c4878aSAndroid Build Coastguard Workerhardware this means starting with a GitHub project with a sample application 610*61c4878aSAndroid Build Coastguard Workerfrom MCUXpresso or STMCube. Each of these use a specific HAL and may be 611*61c4878aSAndroid Build Coastguard Workercoupled to other frameworks, such as FreeRTOS. This places the burden of 612*61c4878aSAndroid Build Coastguard Workersubstituting the HAL calls with the Pigweed API, making the sample program 613*61c4878aSAndroid Build Coastguard Workerwith the application screen choice, etc. 614*61c4878aSAndroid Build Coastguard Worker 615*61c4878aSAndroid Build Coastguard WorkerThis chore is time consuming and often requires that the application developer 616*61c4878aSAndroid Build Coastguard Workeracquire some level of driver expertise. Having direct display support in 617*61c4878aSAndroid Build Coastguard WorkerPigweed will allow the developer to more quickly add display support. 618*61c4878aSAndroid Build Coastguard Worker 619*61c4878aSAndroid Build Coastguard WorkerThe primary use-case being targeted is an application with a single display 620*61c4878aSAndroid Build Coastguard Workerusing multiple framebuffers with display update notifications delivered during 621*61c4878aSAndroid Build Coastguard Workeran interrupt. The initial implementation is designed to support multiple 622*61c4878aSAndroid Build Coastguard Workerheterogenous displays, but that will not be the focus of development or testing 623*61c4878aSAndroid Build Coastguard Workerfor the first release. 624*61c4878aSAndroid Build Coastguard Worker 625*61c4878aSAndroid Build Coastguard WorkerTouch sensors, or other input devices, are not part of this effort. Display 626*61c4878aSAndroid Build Coastguard Workerand touch input often accompany each other, but to simplify this already large 627*61c4878aSAndroid Build Coastguard Workerdisplay effort, touch will be added in a separate activity. 628*61c4878aSAndroid Build Coastguard Worker 629*61c4878aSAndroid Build Coastguard WorkerThere are many other embedded libraries for embedded drawing. Popular libraries 630*61c4878aSAndroid Build Coastguard Workerare LVGL, emWin, GUIslice, HAGL, µGFX, and VGLite (to just name a few). These 631*61c4878aSAndroid Build Coastguard Workerexisting solutions generally offer one or more of: display drivers, drawing 632*61c4878aSAndroid Build Coastguard Workerlibrary, widget library. The display drivers usually rely on an abstraction 633*61c4878aSAndroid Build Coastguard Workerlayer, which they often refer to as a HAL, to interface with the underlying 634*61c4878aSAndroid Build Coastguard Workerhardware API. This HAL may rely on macros, or sometimes a structure with 635*61c4878aSAndroid Build Coastguard Workerfunction pointers for specific operations. 636*61c4878aSAndroid Build Coastguard Worker 637*61c4878aSAndroid Build Coastguard WorkerThe approach in this SEED was selected because it offers a low level API focused 638*61c4878aSAndroid Build Coastguard Workeron display update performance. It offers no drawing or GUI library, but should 639*61c4878aSAndroid Build Coastguard Workerbe easily interfaced with those libraries. 640*61c4878aSAndroid Build Coastguard Worker 641*61c4878aSAndroid Build Coastguard Worker--------------- 642*61c4878aSAndroid Build Coastguard WorkerDetailed design 643*61c4878aSAndroid Build Coastguard Worker--------------- 644*61c4878aSAndroid Build Coastguard WorkerThis proposal suggests no changes to existing APIs. All changes introduce new 645*61c4878aSAndroid Build Coastguard Workermodules that leverage the existing API. It supports static allocation of the 646*61c4878aSAndroid Build Coastguard Workerpixel buffers and all display framework objects. Additionally pixel buffers 647*61c4878aSAndroid Build Coastguard Workermay be hard-coded addresses or dynamically allocated from SRAM. 648*61c4878aSAndroid Build Coastguard Worker 649*61c4878aSAndroid Build Coastguard WorkerThe ``Framebuffer`` class is intended to simplify code that interacts with the 650*61c4878aSAndroid Build Coastguard Workerpixel buffer. It includes the pixel buffer format, dimensions, and the buffer 651*61c4878aSAndroid Build Coastguard Workeraddress. The framebuffer is 16 bytes in size (14 when packed). Framebuffer 652*61c4878aSAndroid Build Coastguard Workerobjects are created when requested and moved as a means of signifying ownership. 653*61c4878aSAndroid Build Coastguard WorkerIn other words, whenever code has an actual framebuffer object it is allowed 654*61c4878aSAndroid Build Coastguard Workerto both write to and read from the pixel buffer. 655*61c4878aSAndroid Build Coastguard Worker 656*61c4878aSAndroid Build Coastguard WorkerThe ``FramebufferPool`` is an object intended to simplify the management of a 657*61c4878aSAndroid Build Coastguard Workercollection of framebuffers. It tracks those that are available for use and 658*61c4878aSAndroid Build Coastguard Workerloans out framebuffers when requested. For single display devices this is 659*61c4878aSAndroid Build Coastguard Workergenerally not a difficult task as the application would maintain an array of 660*61c4878aSAndroid Build Coastguard Workerframebuffers and a next available index. In this case framebuffers are always 661*61c4878aSAndroid Build Coastguard Workerused in order and the buffer collection is implemented as a queue. 662*61c4878aSAndroid Build Coastguard Worker 663*61c4878aSAndroid Build Coastguard WorkerBecause RAM is often limited, the framebuffer pool is designed to be shared 664*61c4878aSAndroid Build Coastguard Workerbetween multiple displays. Because display rendering and update may be at 665*61c4878aSAndroid Build Coastguard Workerdifferent speeds framebuffers do not need to be retrieved 666*61c4878aSAndroid Build Coastguard Worker(via ``GetFramebuffer()``) and returned (via ``ReleaseFramebuffer()``) in the same 667*61c4878aSAndroid Build Coastguard Workerorder. 668*61c4878aSAndroid Build Coastguard Worker 669*61c4878aSAndroid Build Coastguard WorkerWhenever possible asynchronous display updates will be used. Depending on the 670*61c4878aSAndroid Build Coastguard Workerimplementation this usually offloads the CPU from the pixel writing to the 671*61c4878aSAndroid Build Coastguard Workerdisplay controller. In this case the CPU will initiate the update and using 672*61c4878aSAndroid Build Coastguard Workersome type of notification, usually an interrupt raised by a GPIO pin connected 673*61c4878aSAndroid Build Coastguard Workerto the display, will be notified of the completion of the display update. 674*61c4878aSAndroid Build Coastguard WorkerBecause of this the framebuffer pool ``ReleaseFramebuffer()`` call is interrupt 675*61c4878aSAndroid Build Coastguard Workersafe. 676*61c4878aSAndroid Build Coastguard Worker 677*61c4878aSAndroid Build Coastguard Worker``FramebufferPool::GetFramebuffer()`` will block indefinitely if no framebuffer 678*61c4878aSAndroid Build Coastguard Workeris available. This unburdens the application drawing loop from the task of 679*61c4878aSAndroid Build Coastguard Workermanaging framebuffers or tracking screen update completion. 680*61c4878aSAndroid Build Coastguard Worker 681*61c4878aSAndroid Build Coastguard WorkerTesting 682*61c4878aSAndroid Build Coastguard Worker======= 683*61c4878aSAndroid Build Coastguard WorkerAll classes will be accompanied by a robust set of unit tests. These can be 684*61c4878aSAndroid Build Coastguard Workerrun on the host or the device. Test applications will be able to run on a 685*61c4878aSAndroid Build Coastguard Workerworkstation (i.e. not an MCU) in order to enable tests that depend on 686*61c4878aSAndroid Build Coastguard Workerhardware available in most CPUs - like an MMU. This will enable the use of 687*61c4878aSAndroid Build Coastguard Worker`AddressSanitizer <https://github.com/google/sanitizers/wiki/AddressSanitizer>`_ 688*61c4878aSAndroid Build Coastguard Workerbased tests. Desktop tests will use 689*61c4878aSAndroid Build Coastguard Worker`Xvfb <https://www.x.org/releases/X11R7.6/doc/man/man1/Xvfb.1.xhtml>`_ to allow 690*61c4878aSAndroid Build Coastguard Workerthem to be run in a headless continuous integration environment. 691*61c4878aSAndroid Build Coastguard Worker 692*61c4878aSAndroid Build Coastguard WorkerPerformance 693*61c4878aSAndroid Build Coastguard Worker=========== 694*61c4878aSAndroid Build Coastguard WorkerDisplay support will include performance tests. Although this proposal does not 695*61c4878aSAndroid Build Coastguard Workerinclude a rendering library, it will include support for specific platforms 696*61c4878aSAndroid Build Coastguard Workerthat will utilize means of transferring pixel data to the display controller 697*61c4878aSAndroid Build Coastguard Workerin the background. 698*61c4878aSAndroid Build Coastguard Worker 699*61c4878aSAndroid Build Coastguard Worker------------ 700*61c4878aSAndroid Build Coastguard WorkerAlternatives 701*61c4878aSAndroid Build Coastguard Worker------------ 702*61c4878aSAndroid Build Coastguard WorkerOne alternative is to create the necessary port/HAL, the terminology varies by 703*61c4878aSAndroid Build Coastguard Workerlibrary, for the popular embedded graphics libraries. This would make it easier 704*61c4878aSAndroid Build Coastguard Workerfor Pigweed applications to add display support - bot only for those supported 705*61c4878aSAndroid Build Coastguard Workerlibraries. This effort is intended to be more focused on performance, which is 706*61c4878aSAndroid Build Coastguard Workernot always the focus of other libraries. 707*61c4878aSAndroid Build Coastguard Worker 708*61c4878aSAndroid Build Coastguard WorkerAnother alternative is to do nothing - leaving the job of adding display 709*61c4878aSAndroid Build Coastguard Workersupport to the developers. As a significant percentage of embedded projects 710*61c4878aSAndroid Build Coastguard Workercontain a display, it will beneficial to have built-in display support in 711*61c4878aSAndroid Build Coastguard WorkerPigweed. This will allow all user to benefit by the shared display expertise, 712*61c4878aSAndroid Build Coastguard Workercontinuous integration, testing, and performance testing. 713*61c4878aSAndroid Build Coastguard Worker 714*61c4878aSAndroid Build Coastguard Worker-------------- 715*61c4878aSAndroid Build Coastguard WorkerOpen questions 716*61c4878aSAndroid Build Coastguard Worker-------------- 717*61c4878aSAndroid Build Coastguard Worker 718*61c4878aSAndroid Build Coastguard WorkerParameter Configuration 719*61c4878aSAndroid Build Coastguard Worker======================= 720*61c4878aSAndroid Build Coastguard WorkerOne open question is what parameters to specify in initialization parameters 721*61c4878aSAndroid Build Coastguard Workerto a driver ``Init()`` function, which to set in build flags via ``config(...)`` 722*61c4878aSAndroid Build Coastguard Workerin GN, and which to hard-code into the driver. The most ideal, from the 723*61c4878aSAndroid Build Coastguard Workerperspective of reducing binary size, is to hard-code all values in a single 724*61c4878aSAndroid Build Coastguard Workerblock of contiguous data. The decision to support multiple displays requires 725*61c4878aSAndroid Build Coastguard Workerthat the display initialization parameters, at least some of them, be defined 726*61c4878aSAndroid Build Coastguard Workerat runtime and cannot be hard-coded into the driver code - that is, if the 727*61c4878aSAndroid Build Coastguard Workergoal is to allow two of the same display to be in use with different settings. 728*61c4878aSAndroid Build Coastguard Worker 729*61c4878aSAndroid Build Coastguard WorkerAdditionally many drivers support dozens of configuration values. The ILI9341 730*61c4878aSAndroid Build Coastguard Workerhas 82 different commands, some with complex values like gamma tables or 731*61c4878aSAndroid Build Coastguard Workermultiple values packed into a single register. 732*61c4878aSAndroid Build Coastguard Worker 733*61c4878aSAndroid Build Coastguard WorkerThe current approach is to strike a balance where the most commonly set 734*61c4878aSAndroid Build Coastguard Workervalues, for example display width/height and pixel format, are configurable 735*61c4878aSAndroid Build Coastguard Workervia build flags, and the remainder is hard-coded in the driver. If a developer 736*61c4878aSAndroid Build Coastguard Workerwants to set a parameter that is currently hard-coded in the driver, for 737*61c4878aSAndroid Build Coastguard Workerexample display refresh rate or gamma table, they would need to copy the display 738*61c4878aSAndroid Build Coastguard Workerdriver from Pigweed, or create a Pigweed branch. 739*61c4878aSAndroid Build Coastguard Worker 740*61c4878aSAndroid Build Coastguard Worker``Display::WriteFramebuffer()`` always writes the full framebuffer. It is expected 741*61c4878aSAndroid Build Coastguard Workerthat partial updates will be supported. This will likely come as a separate 742*61c4878aSAndroid Build Coastguard Workerfunction. This is being pushed off until needed to provide as much experience 743*61c4878aSAndroid Build Coastguard Workerwith the various display controller APIs as possible to increase the likelihood 744*61c4878aSAndroid Build Coastguard Workerof a well crafted API. 745*61c4878aSAndroid Build Coastguard Worker 746*61c4878aSAndroid Build Coastguard WorkerModule Hierarchy 747*61c4878aSAndroid Build Coastguard Worker================ 748*61c4878aSAndroid Build Coastguard WorkerAt present Pigweed's module structure is flat and at the project root level. 749*61c4878aSAndroid Build Coastguard WorkerThere are currently 134 top level ``pw_*`` directories. This proposal could 750*61c4878aSAndroid Build Coastguard Workersignificantly increase this count as each new display driver will be a new 751*61c4878aSAndroid Build Coastguard Workermodule. This might be a good time to consider putting modules into a hierarchy. 752*61c4878aSAndroid Build Coastguard Worker 753*61c4878aSAndroid Build Coastguard WorkerPixel Pusher 754*61c4878aSAndroid Build Coastguard Worker============ 755*61c4878aSAndroid Build Coastguard Worker``PixelPusher`` was created to remove the details of writing pixels from the 756*61c4878aSAndroid Build Coastguard Workerdisplay driver. Many displays support multiple ways to send pixel data. For 757*61c4878aSAndroid Build Coastguard Workerexample the ILI9341 supports SPI and a parallel bus for pixel transport. 758*61c4878aSAndroid Build Coastguard WorkerThe `STM32F429I-DISC1 <https://www.st.com/en/evaluation-tools/32f429idiscovery.html>`_ 759*61c4878aSAndroid Build Coastguard Workeralso has a display controller (`LTDC 760*61c4878aSAndroid Build Coastguard Worker<https://www.st.com/resource/en/application_note/an4861-lcdtft-display-controller-ltdc-on-stm32-mcus-stmicroelectronics.pdf>`_) 761*61c4878aSAndroid Build Coastguard Workerwhich uses an STM proprietary API. The ``PixelPusher`` was essentially created 762*61c4878aSAndroid Build Coastguard Workerto allow that driver to use the LTDC API without the need to be coupled in any 763*61c4878aSAndroid Build Coastguard Workerway to a vendor API. 764*61c4878aSAndroid Build Coastguard Worker 765*61c4878aSAndroid Build Coastguard WorkerAt present some display drivers use ``pw_spi`` to send commands to the display 766*61c4878aSAndroid Build Coastguard Workercontroller, and the ``PixelPusher`` for writing pixel data. It will probably 767*61c4878aSAndroid Build Coastguard Workerbe cleaner to move the command writes into the ``PixelPusher`` and remove any 768*61c4878aSAndroid Build Coastguard Worker``pw_spi`` interaction from the display drivers. At this time ``PixelPusher`` 769*61c4878aSAndroid Build Coastguard Workershould be renamed. 770*61c4878aSAndroid Build Coastguard Worker 771*61c4878aSAndroid Build Coastguard WorkerCopyrighted SDKs 772*61c4878aSAndroid Build Coastguard Worker================ 773*61c4878aSAndroid Build Coastguard WorkerSome vendors have copyrighted SDKs which cannot be included in the Pigweed 774*61c4878aSAndroid Build Coastguard Workersource code unless the project is willing to have the source covered by more 775*61c4878aSAndroid Build Coastguard Workerthan one license. Additionally some SDKs have no simple download link and the 776*61c4878aSAndroid Build Coastguard Workervendor requires that a developer use a web application to build and download 777*61c4878aSAndroid Build Coastguard Workeran SDK with the desired components. NXP's 778*61c4878aSAndroid Build Coastguard Worker`MCUXpresso SDK Builder <https://mcuxpresso.nxp.com/en/welcome>`_ is an example 779*61c4878aSAndroid Build Coastguard Workerof this. This download process makes it difficult to provide simple instructions 780*61c4878aSAndroid Build Coastguard Workerto the developer and for creating reliable builds as it may be difficult to 781*61c4878aSAndroid Build Coastguard Workerselect an older SDK for download. 782