lexus2k / ssd1306

Driver for SSD1306, SSD1331, SSD1351, IL9163, ILI9341, ST7735, PCD8544, Nokia 5110 displays running on Arduino/ESP32/Linux (Rasperry) platforms
MIT License
681 stars 127 forks source link

Architectural improvements #34

Closed b-desconocido closed 6 years ago

b-desconocido commented 6 years ago

It is more like a proposal to improve the NanoEngine rather than issue. I thought it might be great to have an ability to pass driver callbacks (via functors, function pointers, tagging/specialization, etc) or driver objects instead of calling "ssd1331_fastDrawBuffer16" or "ssd1306_drawBuffer" inside NanoCanvas implementation. The idea behind tiled rendering is very great, but it isn't very easy to port this lib to the other platform / display controller - it takes way too much unnecessary effort.

lexus2k commented 6 years ago

Hello, I like your proposal. As I understand you mean to make NanoCanvas1, NanoCanvas8, NanoCanvas16 as templates, to have something likes this: NanoCanvas1<ssd1306_drawBufferFast>. So, using this way, it will be possible to port NanoCanvas and use even different LCD library. Is this what you meant?

b-desconocido commented 6 years ago

Not sure what is the best way to pass a blitter function into the NanoCanvas, i'm not a C++ master. It shouldn't be hard to understand for beginners, so maybe templates and some default aliases for predefined controllers will be good enough. It opens up some opportunities for more experienced developers, such as using any display controller, DMA (requires an ability to switch buffers for the canvas), color indexing (palettes) or some kind of visual effects. The blitter's signature looks exactly the same for me - x, y, buffer and it's length (or width and height), with an exception of monochrome display controllers which mostly are using page/bank mode. I was messing around to use same technic (tiled framebuffer + draw callback) yesterday and was pretty happy with the results - 8ms (might be improved) for drawing and 35ms (close to theoretical minimum) for copying whole data to the screen on the Blue Pill + 240x320 cheap Chinese TFT screen based on ILI9341 SPI at 36MHz, 16 bpp. Should be a bit less for drawing using DMA or indexed color mode. PS Sorry for my bad English, it isn't my native language and i hope you understand me.

lexus2k commented 6 years ago

Well, thank you. You gave me a lof of food for thoughts. I understand your point. To implement the idea, you described, first NanoCanvas classes need to be refactored. I made some initial rework, trying to make NanoCanvas1/8/16 still compatible with older library releases, but I didn't figure out yet on how to be with blt functions.

The main points are:

Making blitter function as template parameter leads to too complicated code. Another solution is to make blitter function as constructor argument, but this make the compiler to generate more code, which is not good for AVR controllers. And one more idea is to use virtual functions for blitter. I'm still looking for the best solution here.

You can find sketches of new NanoCanvas in https://github.com/lexus2k/ssd1306/tree/1.5_canvas branch.

Regarding speed, I have some local changes for the library, not yet committed, and those changes improve buffer copying by 30% on Atmega328p & ssd1306. By the way, you're talking about TFT with 36MHz SPI and theoretical minimum, and Atmega328 gives only 8MHz over SPI. Which controller do you use?

b-desconocido commented 6 years ago

I thought it is possible to make an alias using old canvas names (using current blitter by default) to keep compatibility and simplicity, but i'm not sure if it is the correct way. As for the MCU, I'm using Blue Pill (cheap Chinese clone), MCU is STM32F103C8T6, basic specs are the following:

I found this board very powerful, inexpensive, free IDE and tools available (CubeMX, TrueSTUDIO or Eclipse, gcc/gdb) and, most importantly, it is easy to debug using ST-Link/V2 (also around US$ 2). The live debugging, like conditional/unconditional breakpoints, call stack, memory/variable live view are crucial for me as for MCU newbie.

lexus2k commented 6 years ago

Oh, you have powerful controller. Please, check latest commit to https://github.com/lexus2k/ssd1306/tree/1.5_canvas branch. I;ve added example on how NanoCanvas blitter can be specified via NanoCanvasBase class. But I still doesn't like implementation, and it seems that the better way is to use virtual functions for the Blitter.

b-desconocido commented 6 years ago

Oh, that is almost exactly what i had in mind, thanks 😃 I'm currently messing around with templated version of my own crappy canvas, using CoordIntType/Width/Height/PixelFormat/ColorFormat as template parameters and other helper templates. What i'm trying to do is to separate color/pixel memory representation and access patterns (i know it is a waste of time, but good enough to study C++/C++11 and templates instead of reading useless foobar-like examples). It seems like gcc can output some nice binaries with very clever optimizations if it knows enough at the compile time.

lexus2k commented 6 years ago

Yeah, I agree. Initially I thought that implementing library in C-style is good point for small micro controllers. That's why i2c/spi/intf/lcd parts are implemented in C-style with pointers to selected functions during initialization. But modern tool-chains support c++ for all devices, and now I came to conclusion, that I it would be much better to implement low driver logic as template parameter for higher-level APIs. This would produce smaller code in flash and would give higher speed, since controller doesn't need to read pointer first to find out the place to jump to. The opposite side of templates: they require too much code to be placed to header files and make compilation slower.

b-desconocido commented 6 years ago

I wish i could help you somehow, but, so far, i couldn't get it to work with optimizations turned on, most likely due to the errors, undefined behavior or, much less likely, compiler bugs. I got some nasty artifacts on the screen when i turn on the compiler magic - my code definitely not conforms any standard and, most likely, i will rely on your library. So far i could maintain 50 fps drawing three 64x64x16bits images + chroma key, still not able to get DMA working reliably, still can't decide which way i should update changed parts of the screen (flagged tiles, independent partial updates or something else, like dynamic tile dimensions). Predefined tile width/height improves the pixel fill rate despite i have single_clock_multiplication-capable MCU, although not by a lot. As for the compile time, i can't really measure the difference between templates and non-templates. FLASH-memory usage is also hard to compare on the different platforms/compilers/libraries. That's what i got using STM32 HAL + reduced versions of C++/C libs: Dropbox

Anyway, i wish you a good luck. The idea is amazing and scales well on any MCU/screen. There must be a good, easy to use and powerful graphics library.

lexus2k commented 6 years ago

Thank you for the good wishes. I looked at the video, and I like it, it looks very nice. I like flagged tiles. They're easier to implement and understand.

Tried to build ssd1306 library for STM32, but Arduino IDE fails to compile C-files, if they call Arduino digital wire functions. They (STM32 support guys) did something completely with STM32 support in Arduino IDE (in some places #ifdef __cplusplus macros are missed).

Which toolchain do you use to compile programs for STM32?

b-desconocido commented 6 years ago

I like flagged tiles too, but sometimes it is faster to render "unaligned" tile and there is much less visible tearing at the borders of the tiles. It depends :D Haven't received my ATmega328Ps and ESP32 yet, so currently i'm tinkering with these STMs. Didn't try to setup Arduino environment either. I'm using "Atollic ARM Tools" (arm-atollic-eabi-gcc, arm-atollic-eabi-++, default in TrueSTUDIO) and "STM32 HAL" (from STM32CubeMX) for the initialization and low-level access as it correlates better with datasheets. The canvas itself isn't using any low level features, so i could try it when the atmega/esp will arrive.

lexus2k commented 6 years ago

I added support for stm32duino, and that package has support for Blue Pill as they say.

b-desconocido commented 6 years ago

Tnx, gonna check it next week. Also, finally i managed to get rid of DMA: i able to get over 110 fps on the same demo program 😃 Added a video to dropbox folder.

lexus2k commented 6 years ago

Sorry for delay, cool. I checked your last video, I'm impressed with the speed. And finally I decided to use virtual methods for blitter, because they make things simpler. I think that latest 1.5_canvas version is the one, I'm going to integrate to master branch to continue development there.

lexus2k commented 6 years ago

Finally I released 1.6.0, which allows to do customization for NanoCanvas objects

b-desconocido commented 6 years ago

Sorry for delayed response and thank you very much - finally i received my atmegas and gonna check your library.