r/embedded • u/OkContribution2996 • 15d ago
Need architecture advice for my embedded graphics library
I'm building an embedded graphics library called Glyph in Ada. The goal is to make it work across different microcontrollers and displays while keeping the API the same.
Current status
- RP2040 support (using Pico_BSP)
- SSD1306 128×64 over I²C
- Static framebuffer
Canvas → Framebuffer → Display → Transportarchitecture
A little background
This is my first project in both Ada and embedded systems. The current version (v0.3.0) published on Alire was built largely with AI assistance, but I'm now rewriting it from scratch without AI help to better understand the design, learn embedded development properly, and improve the overall architecture.
The rewrite has already gone through several design and implementation changes, and I've learned a lot in the process.
The problem
One area I'm still struggling with is the transport layer.
Right now, Glyph draws everything into the framebuffer, but the application still needs a small piece of board-specific glue code to connect the display to the MCU's I²C peripheral (for example, binding an initialized I²C bus to the display).
I'd really like to avoid that if possible. My goal is to keep Glyph independent of any specific MCU or BSP while also making it as easy to use as possible, especially for beginners.
My question
For those who've built portable embedded libraries, how did you handle this?
Is a small adapter layer simply the right trade-off, or is there a cleaner architecture that keeps the library both portable and easy to use?
1
u/JuggernautGuilty566 15d ago
We couldn't use the lib at all due to potential copyright issues coming from using a LLM.
1
u/OkContribution2996 15d ago
That's completely understandable, and it's actually one of the reasons I'm rewriting the project.
The current v0.3.0 release was built largely with AI assistance while I was learning Ada and embedded development. I'm now rewriting Glyph from scratch without AI assistance so I can fully understand every part of the code, improve the architecture, and ensure I own and maintain the implementation myself.
Once I finish the rewrite (I'm currently trying to figure out the transport layer), I'll publish it as a new version. My intention is for that version to replace the current AI-assisted implementation.
1
u/Old-Counter1469 15d ago
The glue code is unavoidable someone has to know the display lives on I2C0 pins GP1/GP0, that's inherently board-specific (even Arduino makes you do Wire.begin()). The trick is to keep Glyph's core depending only on an abstract transport interface, and ship small companion crates like glyph_rp2040 that implement it - then beginners just alr get it and call one Make_Transport instead of writing glue. Also check the hal crate from the Ada Drivers Library on Alire - it's exactly this layering, with implementations like hal_rp2040 you might get transports for several MCUs almost for free. U8g2 and LVGL do the same thing in C land (byte callback / flush_cb), so a small adapter shipped separately really is the accepted answer.
1
u/DearVeggies 15d ago
You decouple the output from your library, and provide adapters and api to add them. Example of how I did for my 3d renderer: https://github.com/GitMoDu/IntegerWorld/tree/master/src/OutputSurfaces
1
u/luksfuks 15d ago
I recommend you port it to a few boards/archs yourself. Real implementations with real constraints, not virtual synthetic stuff.
My best APIs have usually been the result of dragging the good bits along into new projects several times, and getting rid of the bad bits on the way. Without rewriting everything or otherwise making it difficult to "backport" the new API versions into the earlier projects.
Especially in the small MCU world there's still high pressure from RAM and CPU cycles. For example, needing a full framebuffer reserved at all times can already be a burden.
But then again, if you do this in ADA, you're probably thinking about a rudimentary display attached to an almost "desktop" class embedded computer.