Hi @Allan153090 - this is something that’s bugged me for a while and would really increase PiicoDev’s accessibility.
In short - truly variable font sizes are kinda… hard - but it should be pretty straightforward to deploy an integer scaling to the font, ie. double or triple the size. Hopefully, that level of functionality is enough for most makers’ needs.
We’ll hit this today and I’ll update you here with our progress.
Ok so my initial enthusiasm has been nipped a bit - our PiicoDev OLED class depends on a built-in framebuffer for Pico which has a fixed font size (see image). This may take a little longer than anticipated.
Thank you for having a look at the problem. The searching I did last night didn’t turn up an easy solution. Twice the size should be fine.
It’s a little time-consuming, but the only practical approach I could think of was to define a function that returned a bitmap for each digit. And then (for example) parse a temperature reading (e.g. 23.4) into three individual function calls to return the bitmaps in order. Plus fiddling with the decimal place and append degrees Celsius on the end. Add then positioning on the screen.
Which is not a particularly elegant or general approach. Given that I only need indoor and outdoor temperatures here in Adelaide (post-climate change apocalypse say -10°C to +50°C) it will do the job.
Can you think of any simpler workarounds for my particular use case?
Simpler? Not really… You would have to hand-make the framebuffer like we do for the micro:bit or RPi
The following is the text method we use for micro:bit / pi. It loads the font file and draws the characters. You would have to redefine the framebuffer for Pico (assuming you’re using that) and add a size argument to this method. You can see that everything is working in blocks of 8. This is what would be scaled by the size parameter.
This is what I was initially going to try, before I rediscovered that the Pico’s framebuf class is pre-baked by MicroPython.
def text(self, text, x, y, c=1):
fontFile = open("font-pet-me-128.dat", "rb")
font = bytearray(fontFile.read())
for text_index in range(0, len(text)):
ind = 0
for col in range(8):
fontDataPixelValues = font[(ord(text[text_index])-32)*8 + col]
#ind = text_index * 8 + x * 8 + y * 128 + col
for i in range(0,7):
if fontDataPixelValues & 1 << i != 0:
x_coordinate = x + col + text_index * 8
y_coordinate = y+i
if x_coordinate < WIDTH and y_coordinate < HEIGHT:
self.pixel(x_coordinate, y_coordinate, c)
Adafruit use the same idea discussed above - scaling the font in integer multiples. The library linked is compiled for Arduino which means it doesn’t have the same challenges we face for unifying functionality for Pico, RPi, micro:bit (and others in the future!)
You could definitely achieve this, it would require dropping the MicroPython framebuf class used in PiicoDev_SSD1306.py and making your own. Not exactly for the faint-hearted but it’s what’s outlined in my previous reply.
thank you very much for going to the trouble of detailing than explanation above. I’m currently looking at “PiicoDev_SSD1306.py” (… “Ported by Peter Johnston at Core Electronics October 2021…”) from James46717 via Simple Relay Timer - Tutorial Australia.
I didn’t realise the inner workings of the frame buffer was such a pain.
I think the key though is your last statement “challenges we face for unifying functionality…”. That’s the really hard bit. All I can say is, keep up the good work!
As for my specific use case - I might put that challenge on hold for the moment.
I’m very keen to see what could be achieved by manipulating bitmaps programatically. Of course, the challenge would be to maintain cross-platform compatibility.
An alternative is the Adafruit PiOLED HAT for RPi which allows custom fonts and text sizes out of the box. Not sure if it could be made to work alongside my Piicodev setup as the Piicodev adapter occupies my GPIO.
The limitation of small font size was raised last January and it seems has not been solved. At the time the only solution I could see was to load graphic images. These are 128 x 64 pixel Portable Bitmap Image (PBM) files. If you only wanted say the numbers 0 - 9 it would be feasible to load one of ten PBM files created in Photoshop. But if you wanted a signed temperature in deg celsius this method obviously fails. To illustrate I have a test.pbm file but it will not upload. To create a PBM file on demand you would need the netpbmfile python library
but this is hardly an efficient or elegant solution.
I am presently using the OLED display in a weather station. It is also useful for displaying results when prototyping. It would be really nice to have a display which was not such a strain on the eyes. Is there any other hardware available?
Use case: Require temperature and humidity display in a larger font. Say -10.0 °C to +50.0 °C and 10% to 90% RH. Just need numbers (0-9) and some symbols (+,-,.,°C, %RH) . A total of 15 characters distinct required.
Jim’s code displays a larger font by parsing the required string into individual characters. It then manually constructs each character using the requisite number of lines (micropython primitives).
Key element of Jim’s code (paraphrased) (Broad description which omits the offsets required to correctly position the character on the display). Which is something I can work with.
What I had in mind was a process of fiddling with the pixels in the frame buffer. Is it possible to could convert a letter in a particular font to a (say) 16 x 16 bit-map / set of pixels. And then “place/overlay” the pixels/bits In the appropriate locations in the frame buffer (/memory locations),?
Or to borrow and reinterpret Michael’s description “hand make the frame buffer” ?
rinse and repeat until entire string has the appropriate pixels fiddled. And then display the frame buffer.
It’s got a very simplistic appeal. But forget any ideas of making this approach general or suitable for a wide range of platforms or displays. Strictly a one-off for a SSD1306 controller and a 128 x 64 display.
Any ideas anyone? Is this vaguely possible? Or am I just being cheerfully optimistic out of ignorance? Happy to accept advice from someone who knows what they’re doing. Although I suspect I know what the answer is…
At this stage, the most practical approach is to follow that in item # 3. I’ll let everyone know how it goes . Nothing happens quickly around here.
With a combo of James’s work, a bit of your time and the arc and circle functions (linked below), you should be able to collapse the functions used and add some of the basic characters. (having it scale nicely might be a bit harder)
Definitely - the FrameBuffer.pixel(x, y[, c]) command lets you set a single pixels value to on or off. A tool like this should speed things up!
I used the following function to make the text size smaller or bigger: static void SSD1331_char(unsigned char x, unsigned char y, char acsii, char size, char mode, unsigned short hwColor)
My tutorial is in my native language but the photos and code may help you understand how I did it. https://blog.techshopbd.com/tds-মিটার/
Hey everyone! We featured this forum topic in this week’s episode of The Factory - our fortnightly engineering catchup.
There’s some great ideas being thrown around for case-specific solutions. I’ve seen projects where people define numbers out of drawn lines, or use the .blit() method to overlay bitmap images.
I think the most accessible solution for the most people is the Pull Request that we discuss in the video. It should be pretty trivial to support font scaling within the framebuf class natively. If you’d like to see this feature get implemented into MicroPython then perhaps add your support to the PR - its a pretty simple one and perhaps just hasn’t garnered enough attention.
With all that being said, this is still an open source project - your ideas and code contributions are welcome! If you think you’ve come up with something that makes PiicoDev even just a little bit better then open an issue or PR on the GitHub repo!