diff options
author | Chris Mumford <cmumford@google.com> | 2023-09-12 23:46:42 +0000 |
---|---|---|
committer | CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-09-12 23:46:42 +0000 |
commit | eb7ded3f1a7c9574f0ff22a98cc21a9d597e55ad (patch) | |
tree | 8b5548a22fe66c072ec8c2370de1cba971694ad3 /seed | |
parent | ded929be2ec1b5b577c07ed0859e3186a34a0040 (diff) | |
download | pigweed-eb7ded3f1a7c9574f0ff22a98cc21a9d597e55ad.tar.gz |
SEED-0104: Display Support
A SEED to propose Pigweed support for video displays. This proposes
low level driver and framebuffer support. The actual drawing will be
left to a separate drawing library to be selected by the application
development team.
Change-Id: If8f5b51d04267908c816610246714fcb2db3c834
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/150793
Reviewed-by: Anthony DiGirolamo <tonymd@google.com>
Reviewed-by: Armando Montanez <amontanez@google.com>
Commit-Queue: Auto-Submit <auto-submit@pigweed-service-accounts.iam.gserviceaccount.com>
Pigweed-Auto-Submit: Anthony DiGirolamo <tonymd@google.com>
Presubmit-Verified: CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>
Diffstat (limited to 'seed')
-rw-r--r-- | seed/0000-index.rst | 2 | ||||
-rw-r--r-- | seed/0104-display-support.rst | 785 | ||||
-rw-r--r-- | seed/BUILD.gn | 5 |
3 files changed, 791 insertions, 1 deletions
diff --git a/seed/0000-index.rst b/seed/0000-index.rst index 179719fd9..74b456a83 100644 --- a/seed/0000-index.rst +++ b/seed/0000-index.rst @@ -13,7 +13,7 @@ All pending, active, and resolved SEEDs are listed below. 0101-pigweed.json 0102-module-docs 0103: pw_protobuf: Past, present, and future<https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/133971> - 0104: display support<https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/150793> + 0104-display-support 0105: Nested Tokens and Tokenized Args <https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/154190> 0106: Project Template <https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/155430> 0107-communications diff --git a/seed/0104-display-support.rst b/seed/0104-display-support.rst new file mode 100644 index 000000000..948a4cfcb --- /dev/null +++ b/seed/0104-display-support.rst @@ -0,0 +1,785 @@ +.. _seed-0104: + +===================== +0104: Display Support +===================== +.. seed:: + :number: 104 + :name: Display Support + :status: Accepted + :proposal_date: 2023-06-12 + :cl: 150793 + +------- +Summary +------- +Add support for graphics displays. This includes display drivers for a few +popular display controllers, framebuffer management, and a framework to simplify +adding a graphics display to a Pigweed application. + +---------- +Motivation +---------- +Pigweed currently has no specific support for a display device. Projects that +require a display currently must do the full implementation, including the +display driver in most instances, to add display support. + +This proposes the addition of a basic framework for display devices, as well +as implementations for a few common Pigweed test devices - specifically the +STM32F429I. This enables developers to quickly and easily add display support +for supported devices and an implementation to model when adding new device +support. + +--------------- +Proposal +--------------- +This proposes no changes to existing modules, but suggests several new modules +that together define a framework for rendering to displays. + + +New Modules +----------- + +.. list-table:: + :widths: 5 45 + :header-rows: 1 + + * - Module + - Function + + * - pw_display + - Manage draw thread, framebuffers, and driver + + * - pw_display_driver + - Display driver interface definition + + * - pw_display_driver_ili9341 + - Display driver for the ILI9341 display controller + + * - pw_display_driver_imgui + - Host display driver using `Dear ImGui <https://www.dearimgui.com/>`_ + + * - pw_display_driver_mipi + - Display driver for `MIPI DSI <https://www.mipi.org/specifications/dsi>`_ controllers + + * - pw_display_driver_null + - Null display driver for headless devices + + * - pw_display_driver_st7735 + - Display driver for the `ST7735 <https://www.displayfuture.com/Display/datasheet/controller/ST7735.pdf>`_ display controller + + * - pw_display_driver_st7789 + - Display driver for the ST7789 display controller + + * - pw_simple_draw + - Very basic drawing library for test purposes + + * - pw_framebuffer + - Manage access to pixel buffer. + + * - pw_framebuffer_mcuxpresso + - Specialization of the framebuffer for the MCUxpresso devices + + * - pw_geometry + - Basic shared math types such as 2D vectors, etc. + + * - pw_pixel_pusher + - Transport of pixel data to display controller + + +Math +---- +``pw_geometry`` contains two helper structures for common values usually used as +a pair. + +.. code-block:: cpp + + namespace pw::math { + + template <typename T> + struct Size { + T width; + T height; + }; + + template <typename T> + struct Vector2 { + T x; + T y; + }; + + } // namespace pw::math + + +Framebuffer +----------- +A framebuffer is a small class that provides access to a pixel buffer. It +keeps a copy of the pixel buffer metadata and provides accessor methods for +those values. + +.. code-block:: cpp + + namespace pw::framebuffer { + + enum class PixelFormat { + None, + RGB565, + }; + + class Framebuffer { + public: + // Construct a default invalid framebuffer. + Framebuffer(); + + Framebuffer(void* data, + PixelFormat pixel_format, + pw::math::Size<uint16_t> size, + uint16_t row_bytes); + + Framebuffer(const Framebuffer&) = delete; + Framebuffer(Framebuffer&& other); + + Framebuffer& operator=(const Framebuffer&) = delete; + Framebuffer& operator=(Framebuffer&&); + + bool is_valid() const; + + pw::ConstByteSpan data() const; + pw::ByteSpan data(); + + PixelFormat pixel_format() const; + + pw::math::Size<uint16_t> size(); + + uint16_t row_bytes() const; + }; + + } // namespace pw::framebuffer + +FrameBuffer is a moveable class that is intended to signify read/write +privileges to the underlying pixel data. This makes it easier to track when the +pixel data may be read from, or written to, without conflict. + +The framebuffer does not own the underlying pixel buffer. In other words +the deletion of a framebuffer will not free the underlying pixel data. + +Framebuffers do not have methods for reading or writing to the underlying pixel +buffer. This is the responsibility of the the selected graphics library which +can be given the pixel buffer pointer retrieved by calling ``data()``. + +.. code-block:: cpp + + constexpr size_t kWidth = 64; + constexpr size_t kHeight = 32; + uint16_t pixel_data[kWidth * kHeight]; + + void DrawScreen(Framebuffer* fb) { + // Clear framebuffer to black. + std::memset(fb->data(), 0, fb->height() * fb->row_bytes()); + + // Set first pixel to white. + uint16_t* pixel_data = static_cast<uint16_t*>(fb->data()); + pixel_data[0] = 0xffff; + } + + Framebuffer fb(pixel_data, {kWidth, kHeight}, + PixelFormat::RGB565, + kWidth * sizeof(uint16_t)); + DrawScreen(&fb); + +FramebufferPool +--------------- + +The FramebufferPool is intended to simplify the use of multiple framebuffers +when multi-buffered rendering is being used. It is a collection of framebuffers +which can be retrieved, used, and then returned to the pool for reuse. All +framebuffers in the pool share identical attributes. A framebuffer that is +returned to a caller of ``GetFramebuffer()`` can be thought of as "on loan" to +that caller and will not be given to any other caller of ``GetFramebuffer()`` +until it has been returned by calling ``ReleaseFramebuffer()``. + +.. code-block:: cpp + + namespace pw::framebuffer_pool { + + class FramebufferPool { + public: + using BufferArray = std::array<void*, FRAMEBUFFER_COUNT>; + + // Constructor parameters. + struct Config { + BufferArray fb_addr; // Address of each buffer in this pool. + pw::math::Size<uint16_t> dimensions; // width/height of each buffer. + uint16_t row_bytes; // row bytes of each buffer. + pw::framebuffer::PixelFormat pixel_format; + }; + + FramebufferPool(const Config& config); + virtual ~FramebufferPool(); + + uint16_t row_bytes() const; + + pw::math::Size<uint16_t> dimensions() const; + + pw::framebuffer::PixelFormat pixel_format() const; + + // Return a framebuffer to the caller for use. This call WILL BLOCK until a + // framebuffer is returned for use. Framebuffers *must* be returned to this + // pool by a corresponding call to ReleaseFramebuffer. This function will only + // return a valid framebuffer. + // + // This call is thread-safe, but not interrupt safe. + virtual pw::framebuffer::Framebuffer GetFramebuffer(); + + // Return the framebuffer to the pool available for use by the next call to + // GetFramebuffer. + // + // This may be called on another thread or during an interrupt. + virtual Status ReleaseFramebuffer(pw::framebuffer::Framebuffer framebuffer); + }; + + } // namespace pw::framebuffer + +An example use of the framebuffer pool is: + +.. code-block:: cpp + + // Retrieve a framebuffer for drawing. May block if pool has no framebuffers + // to issue. + FrameBuffer fb = framebuffer_pool.GetFramebuffer(); + + // Draw to the framebuffer. + UpdateDisplay(&fb); + + // Return the framebuffer to the pool for reuse. + framebuffer_pool.ReleaseFramebuffer(std::move(fb)); + +DisplayDriver +------------- + +A DisplayDriver is usually the sole class responsible for communicating with the +display controller. Its primary responsibilities are the display controller +initialization, and the writing of pixel data when a display update is needed. + +This proposal supports multiple heterogenous display controllers. This could be: + +1. A single display of any given type (e.g. ILI9341). +2. Two ILI9341 displays. +3. Two ILI9341 displays and a second one of a different type. + +Because of this approach the DisplayDriver is defined as an interface: + +.. code-block:: cpp + + namespace pw::display_driver { + + class DisplayDriver { + public: + // Called on the completion of a write operation. + using WriteCallback = Callback<void(framebuffer::Framebuffer, Status)>; + + virtual ~DisplayDriver() = default; + + virtual Status Init() = 0; + + virtual void WriteFramebuffer(pw::framebuffer::Framebuffer framebuffer, + WriteCallback write_callback) = 0; + + virtual pw::math::Size<uint16_t> size() const = 0; + }; + + } // namespace pw::display_driver + +Each driver then provides a concrete implementation of the driver. Below is the +definition of the display driver for the ILI9341: + +.. code-block:: cpp + + namespace pw::display_driver { + + class DisplayDriverILI9341 : public DisplayDriver { + public: + struct Config { + // Device specific initialization parameters. + }; + + DisplayDriverILI9341(const Config& config); + + // DisplayDriver implementation: + Status Init() override; + void WriteFramebuffer(pw::framebuffer::Framebuffer framebuffer, + WriteCallback write_callback) override; + Status WriteRow(span<uint16_t> row_pixels, + uint16_t row_idx, + uint16_t col_idx) override; + pw::math::Size<uint16_t> size() const override; + + private: + enum class Mode { + kData, + kCommand, + }; + + // A command and optional data to write to the ILI9341. + struct Command { + uint8_t command; + ConstByteSpan command_data; + }; + + // Toggle the reset GPIO line to reset the display controller. + Status Reset(); + + // Set the command/data mode of the display controller. + void SetMode(Mode mode); + // Write the command to the display controller. + Status WriteCommand(pw::spi::Device::Transaction& transaction, + const Command& command); + }; + + } // namespace pw::display_driver + +Here is an example retrieving a framebuffer from the framebuffer pool, drawing +into the framebuffer, using the display driver to write the pixel data, and then +returning the framebuffer back to the pool for use. + +.. code-block:: cpp + + FrameBuffer fb = framebuffer_pool.GetFramebuffer(); + + // DrawScreen is a function that will draw to the framebuffer's underlying + // pixel buffer using a drawing library. See example above. + DrawScreen(&fb); + + display_driver_.WriteFramebuffer( + std::move(framebuffer), + [&framebuffer_pool](pw::framebuffer::Framebuffer fb, Status status) { + // Return the framebuffer back to the pool for reuse once the display + // write is complete. + framebuffer_pool.ReleaseFramebuffer(std::move(fb)); + }); + +In the example above that the framebuffer (``fb``) is moved when calling +``WriteFramebuffer()`` passing ownership to the display driver. From this point +forward the application code may not access the framebuffer in any way. When the +framebuffer write is complete the framebuffer is then moved to the callback +which in turn moves it when calling ``ReleaseFramebuffer()``. + +``WriteFramebuffer()`` always does a write of the full framebuffer - sending all +pixel data. + +``WriteFramebuffer()`` may be a blocking call, but on some platforms the driver +may use a background write and the write callback is called when the write +is complete. The write callback **may be called during an interrupt**. + +PixelPusher +----------- +Pixel data for Simple SPI based display controllers can be written to the +display controller using ``pw_spi``. There are some controllers which use +other interfaces (RGB, MIPI, etc.). Also, some vendors provide an API for +interacting with these display controllers for writing pixel data. + +To allow the drivers to be hardware/vendor independent the ``PixelPusher`` +may be used. This defines an interface whose sole responsibility is to write +a framebuffer to the display controller. Specializations of this will use +``pw_spi`` or vendor proprietary calls to write pixel data. + +.. code-block:: cpp + + namespace pw::pixel_pusher { + + class PixelPusher { + public: + using WriteCallback = Callback<void(framebuffer::Framebuffer, Status)>; + + virtual ~PixelPusher() = default; + + virtual Status Init( + const pw::framebuffer_pool::FramebufferPool& framebuffer_pool) = 0; + + virtual void WriteFramebuffer(framebuffer::Framebuffer framebuffer, + WriteCallback complete_callback) = 0; + }; + + } // namespace pw::pixel_pusher + +Display +------- + +Each display has: + +1. One and only one display driver. +2. A reference to a single framebuffer pool. This framebuffer pool may be shared + with other displays. +3. A drawing thread, if so configured, for asynchronous display updates. + +.. code-block:: cpp + + namespace pw::display { + + class Display { + public: + // Called on the completion of an update. + using WriteCallback = Callback<void(Status)>; + + Display(pw::display_driver::DisplayDriver& display_driver, + pw::math::Size<uint16_t> size, + pw::framebuffer_pool::FramebufferPool& framebuffer_pool); + virtual ~Display(); + + pw::framebuffer::Framebuffer GetFramebuffer(); + + void ReleaseFramebuffer(pw::framebuffer::Framebuffer framebuffer, + WriteCallback callback); + + pw::math::Size<uint16_t> size() const; + }; + + } // namespace pw::display + +Once applications are initialized they typically will not directly interact with +display drivers or framebuffer pools. These will be utilized by the display +which will provide a simpler interface. + +``Display::GetFramebuffer()`` must always be called on the same thread and is not +interrupt safe. It will block if there is no available framebuffer in the +framebuffer pool waiting for a framebuffer to be returned. + +``Display::ReleaseFramebuffer()`` must be called for each framebuffer returned by +``Display::GetFramebuffer()``. This will initiate the display update using the +displays associated driver. The ``callback`` will be called when this update is +complete. + +A simplified application rendering loop would resemble: + +.. code-block:: cpp + + // Get a framebuffer for drawing. + FrameBuffer fb = display.GetFramebuffer(); + + // DrawScreen is a function that will draw to |fb|'s pixel buffer using a + // drawing library. See example above. + DrawScreen(&fb); + + // Return the framebuffer to the display which will be written to the display + // controller by the display's display driver. + display.ReleaseFramebuffer(std::move(fb), [](Status){}); + +Simple Drawing Module +--------------------- + +``pw_simple_draw`` was created for testing and verification purposes only. It is +not intended to be feature rich or performant in any way. This is small +collection of basic drawing primitives not intended to be used by shipping +applications. + +.. code-block:: cpp + + namespace pw::draw { + + void DrawLine(pw::framebuffer::Framebuffer& fb, + int x1, + int y1, + int x2, + int y2, + pw::color::color_rgb565_t pen_color); + + // Draw a circle at center_x, center_y with given radius and color. Only a + // one-pixel outline is drawn if filled is false. + void DrawCircle(pw::framebuffer::Framebuffer& fb, + int center_x, + int center_y, + int radius, + pw::color::color_rgb565_t pen_color, + bool filled); + + void DrawHLine(pw::framebuffer::Framebuffer& fb, + int x1, + int x2, + int y, + pw::color::color_rgb565_t pen_color); + + void DrawRect(pw::framebuffer::Framebuffer& fb, + int x1, + int y1, + int x2, + int y2, + pw::color::color_rgb565_t pen_color, + bool filled); + + void DrawRectWH(pw::framebuffer::Framebuffer& fb, + int x, + int y, + int w, + int h, + pw::color::color_rgb565_t pen_color, + bool filled); + + void Fill(pw::framebuffer::Framebuffer& fb, + pw::color::color_rgb565_t pen_color); + + void DrawSprite(pw::framebuffer::Framebuffer& fb, + int x, + int y, + pw::draw::SpriteSheet* sprite_sheet, + int integer_scale); + + void DrawTestPattern(); + + pw::math::Size<int> DrawCharacter(int ch, + pw::math::Vector2<int> pos, + pw::color::color_rgb565_t fg_color, + pw::color::color_rgb565_t bg_color, + const FontSet& font, + pw::framebuffer::Framebuffer& framebuffer); + + pw::math::Size<int> DrawString(std::wstring_view str, + pw::math::Vector2<int> pos, + pw::color::color_rgb565_t fg_color, + pw::color::color_rgb565_t bg_color, + const FontSet& font, + pw::framebuffer::Framebuffer& framebuffer); + + } // namespace pw::draw + +Class Interaction Diagram +------------------------- + +.. mermaid:: + :alt: Framebuffer Classes + :align: center + + classDiagram + class FramebufferPool { + uint16_t row_bytes() + PixelFormat pixel_format() + dimensions() : Size~uint16_t~ + row_bytes() : uint16_t + GetFramebuffer() : Framebuffer + + BufferArray buffer_addresses_ + Size~uint16_t~ buffer_dimensions_ + uint16_t row_bytes_ + PixelFormat pixel_format_ + } + + class Framebuffer { + is_valid() : bool const + data() : void* const + pixel_format() : PixelFormat const + size() : Size~uint16_t~ const + row_bytes() uint16_t const + + void* pixel_data_ + Size~uint16_t~ size_ + PixelFormat pixel_format_ + uint16_t row_bytes_ + } + + class DisplayDriver { + <<DisplayDriver>> + Init() : Status + WriteFramebuffer(Framebuffer fb, WriteCallback cb): void + dimensions() : Size~uint16_t~ + + PixelPusher& pixel_pusher_ + } + + class Display { + DisplayDriver& display_driver_ + const Size~uint16_t~ size_ + FramebufferPool& framebuffer_pool_ + + GetFramebuffer() : Framebuffer + } + + class PixelPusher { + Init() : Status + WriteFramebuffer(Framebuffer fb, WriteCallback cb) : void + } + + <<interface>> DisplayDriver + FramebufferPool --> "FRAMEBUFFER_COUNT" Framebuffer : buffer_addresses_ + + Display --> "1" DisplayDriver : display_driver_ + Display --> "1" FramebufferPool : framebuffer_pool_ + DisplayDriver --> "1" PixelPusher : pixel_pusher_ + +--------------------- +Problem investigation +--------------------- +With no direct display support in Pigweed and no example programs implementing +a solution Pigweed developers are essentially on their own. Depending on their +hardware this means starting with a GitHub project with a sample application +from MCUXpresso or STMCube. Each of these use a specific HAL and may be +coupled to other frameworks, such as FreeRTOS. This places the burden of +substituting the HAL calls with the Pigweed API, making the sample program +with the application screen choice, etc. + +This chore is time consuming and often requires that the application developer +acquire some level of driver expertise. Having direct display support in +Pigweed will allow the developer to more quickly add display support. + +The primary use-case being targeted is an application with a single display +using multiple framebuffers with display update notifications delivered during +an interrupt. The initial implementation is designed to support multiple +heterogenous displays, but that will not be the focus of development or testing +for the first release. + +Touch sensors, or other input devices, are not part of this effort. Display +and touch input often accompany each other, but to simplify this already large +display effort, touch will be added in a separate activity. + +There are many other embedded libraries for embedded drawing. Popular libraries +are LVGL, emWin, GUIslice, HAGL, µGFX, and VGLite (to just name a few). These +existing solutions generally offer one or more of: display drivers, drawing +library, widget library. The display drivers usually rely on an abstraction +layer, which they often refer to as a HAL, to interface with the underlying +hardware API. This HAL may rely on macros, or sometimes a structure with +function pointers for specific operations. + +The approach in this SEED was selected because it offers a low level API focused +on display update performance. It offers no drawing or GUI library, but should +be easily interfaced with those libraries. + +--------------- +Detailed design +--------------- + +This proposal suggests no changes to existing APIs. All changes introduce new +modules that leverage the existing API. It supports static allocation of the +pixel buffers and all display framework objects. Additionally pixel buffers +may be hard-coded addresses or dynamically allocated from SRAM. + +The ``Framebuffer`` class is intended to simplify code that interacts with the +pixel buffer. It includes the pixel buffer format, dimensions, and the buffer +address. The framebuffer is 16 bytes in size (14 when packed). Framebuffer +objects are created when requested and moved as a means of signifying ownership. +In other words, whenever code has an actual framebuffer object it is allowed +to both write to and read from the pixel buffer. + +The ``FramebufferPool`` is an object intended to simplify the management of a +collection of framebuffers. It tracks those that are available for use and +loans out framebuffers when requested. For single display devices this is +generally not a difficult task as the application would maintain an array of +framebuffers and a next available index. In this case framebuffers are always +used in order and the buffer collection is implemented as a queue. + +Because RAM is often limited, the framebuffer pool is designed to be shared +between multiple displays. Because display rendering and update may be at +different speeds framebuffers do not need to be retrieved +(via ``GetFramebuffer()``) and returned (via ``ReleaseFramebuffer()``) in the same +order. + +Whenever possible asynchronous display updates will be used. Depending on the +implementation this usually offloads the CPU from the pixel writing to the +display controller. In this case the CPU will initiate the update and using +some type of notification, usually an interrupt raised by a GPIO pin connected +to the display, will be notified of the completion of the display update. +Because of this the framebuffer pool ``ReleaseFramebuffer()`` call is interrupt +safe. + +``FramebufferPool::GetFramebuffer()`` will block indefinitely if no framebuffer +is available. This unburdens the application drawing loop from the task of +managing framebuffers or tracking screen update completion. + +Testing +------- +All classes will be accompanied by a robust set of unit tests. These can be +run on the host or the device. Test applications will be able to run on a +workstation (i.e. not an MCU) in order to enable tests that depend on +hardware available in most CPUs - like an MMU. This will enable the use of +`AddressSanitizer <https://github.com/google/sanitizers/wiki/AddressSanitizer>`_ +based tests. Desktop tests will use +`Xvfb <https://www.x.org/releases/X11R7.6/doc/man/man1/Xvfb.1.xhtml>`_ to allow +them to be run in a headless continuous integration environment. + +Performance +----------- +Display support will include performance tests. Although this proposal does not +include a rendering library, it will include support for specific platforms +that will utilize means of transferring pixel data to the display controller +in the background. + +------------ +Alternatives +------------ + +One alternative is to create the necessary port/HAL, the terminology varies by +library, for the popular embedded graphics libraries. This would make it easier +for Pigweed applications to add display support - bot only for those supported +libraries. This effort is intended to be more focused on performance, which is +not always the focus of other libraries. + +Another alternative is to do nothing - leaving the job of adding display +support to the developers. As a significant percentage of embedded projects +contain a display, it will beneficial to have built-in display support in +Pigweed. This will allow all user to benefit by the shared display expertise, +continuous integration, testing, and performance testing. + +-------------- +Open questions +-------------- + +Parameter Configuration +----------------------- +One open question is what parameters to specify in initialization parameters +to a driver ``Init()`` function, which to set in build flags via ``config(...)`` +in GN, and which to hard-code into the driver. The most ideal, from the +perspective of reducing binary size, is to hard-code all values in a single +block of contiguous data. The decision to support multiple displays requires +that the display initialization parameters, at least some of them, be defined +at runtime and cannot be hard-coded into the driver code - that is, if the +goal is to allow two of the same display to be in use with different settings. + +Additionally many drivers support dozens of configuration values. The ILI9341 +has 82 different commands, some with complex values like gamma tables or +multiple values packed into a single register. + +The current approach is to strike a balance where the most commonly set +values, for example display width/height and pixel format, are configurable +via build flags, and the remainder is hard-coded in the driver. If a developer +wants to set a parameter that is currently hard-coded in the driver, for +example display refresh rate or gamma table, they would need to copy the display +driver from Pigweed, or create a Pigweed branch. + +``Display::WriteFramebuffer()`` always writes the full framebuffer. It is expected +that partial updates will be supported. This will likely come as a separate +function. This is being pushed off until needed to provide as much experience +with the various display controller APIs as possible to increase the likelihood +of a well crafted API. + +Module Hierarchy +---------------- +At present Pigweed's module structure is flat and at the project root level. +There are currently 134 top level ``pw_*`` directories. This proposal could +significantly increase this count as each new display driver will be a new +module. This might be a good time to consider putting modules into a hierarchy. + +Pixel Pusher +------------ +``PixelPusher`` was created to remove the details of writing pixels from the +display driver. Many displays support multiple ways to send pixel data. For +example the ILI9341 supports SPI and a parallel bus for pixel transport. +The `STM32F429I-DISC1 <https://www.st.com/en/evaluation-tools/32f429idiscovery.html>`_ +also has a display controller (`LTDC <https://www.st.com/resource/en/application_note/an4861-lcdtft-display-controller-ltdc-on-stm32-mcus-stmicroelectronics.pdf>`_) +which uses an STM proprietary API. The ``PixelPusher`` was essentially created +to allow that driver to use the LTDC API without the need to be coupled in any +way to a vendor API. + +At present some display drivers use ``pw_spi`` to send commands to the display +controller, and the ``PixelPusher`` for writing pixel data. It will probably +be cleaner to move the command writes into the ``PixelPusher`` and remove any +``pw_spi`` interaction from the display drivers. At this time ``PixelPusher`` +should be renamed. + +Copyrighted SDKs +---------------- +Some vendors have copyrighted SDKs which cannot be included in the Pigweed +source code unless the project is willing to have the source covered by more +than one license. Additionally some SDKs have no simple download link and the +vendor requires that a developer use a web application to build and download +an SDK with the desired components. NXP's +`MCUXpresso SDK Builder <https://mcuxpresso.nxp.com/en/welcome>`_ is an example +of this. This download process makes it difficult to provide simple instructions +to the developer and for creating reliable builds as it may be difficult to +select an older SDK for download. diff --git a/seed/BUILD.gn b/seed/BUILD.gn index 9853e34dc..5ad6c1dcd 100644 --- a/seed/BUILD.gn +++ b/seed/BUILD.gn @@ -23,6 +23,7 @@ pw_doc_group("docs") { ":0002", ":0101", ":0102", + ":0104", ":0107", ":0108", ] @@ -45,6 +46,10 @@ pw_doc_group("0102") { sources = [ "0102-module-docs.rst" ] } +pw_doc_group("0104") { + sources = [ "0104-display-support.rst" ] +} + pw_doc_group("0107") { sources = [ "0107-communications.rst" ] } |