qmk / qmk_firmware

Open-source keyboard firmware for Atmel AVR and Arm USB families
https://qmk.fm
GNU General Public License v2.0
18k stars 38.69k forks source link

Different OLED font sizes #6650

Closed burlapsax closed 2 years ago

burlapsax commented 5 years ago

Is it possible to use larger than 6x8 fonts on the 128x32 SSD1306 display using the standalone OLED library packaged with qmk_firmware?

I have the display working fine with an old ADB keyboard. Currently it just shows a simple monitor of the highest-selected layer. 20190831_144949 This is based on the default glcdfont.c, with slightly modified characters but mostly the same and still on the 6x8 grid. (Sorry about the picture – I tried rotating it 180 degrees and re-uploading but it's still upside down...)

This is awesome, but the text is so small it's hard for me to read. I'd like to use a larger font size. Here is what I tried:

  1. copy the hex from glcdfont.c and convert to image
  2. open in an image editor and resize 200% (nearest neighbor / hard edges)
  3. save image and convert back to hex
  4. paste the result back into glcdfont.c, replacing the existing hex copied in step 1
  5. set OLED_FONT_WIDTH 12 and OLED_FONT_HEIGHT 16 in keyboards/converter/adb_usb/config.h
  6. make and flash

Here's what that looks like: 20190831_151540 It seems like it's displaying the full width of the 12x16 characters – but only horizontal cross-sections of them at the same height as the 6x8 font. Some are obviously the top halves of the character; others are less discernible.

I'm not sure whether this means OLED_FONT_HEIGHT is not behaving as expected, the steps I took were wrong, or that the library does not support different font sizes at all.

What can I do to display a different (specifically, larger) font size than 6x8 with this OLED library?

System Information

drashna commented 4 years ago

Tagging @XScorpion2 as they're the author of the OLED Driver feature, for help here.

And very neat/nice mod!

XScorpion2 commented 4 years ago

Adding tall font support is on my list of todos. I just haven't gotten around to it yet.

save image and convert back to hex

Depending on how you convert to hex, this result may or may not be correct.

su8044 commented 4 years ago

Did you ever find a solution? I'm having the same issue with a 128x64 display and the font is just too small and there is too much screen wasted

brickbots commented 4 years ago

Hi @XScorpion2! I'm happy to take this on as I'm interested in using larger font sizes myself. I've taken a look at the current code and I believe it shouldn't be too hard or memory intensive to support fonts that are multiples of 8 pixels tall with fixed (but arbitrary) width. I'm thinking 2x, 3x, 4x height to start.

One thing I've run into playing with this is the font format currently used. The comment in the font file: // Helidox 8x6 font with QMK Firmware Logo // Online editor: http://teripom.x0.com/

Refers to an online editor which seems defunct. I've found this one, which seems fairly well put together: http://oleddisplay.squix.ch/#/home

But generates variable width font files with a more complicated encoding/more overhead than we probably want here. In the future we can implement a fully raster system for the oled which is compatible with some of the existing GFX libs, but I think it will be difficult to get something this complex to fit memory along with all the core features.

Are we okay using our own font file format with no user-friendly tool to create them?
If so, we can slightly alter the current format to support taller fonts and include a few different font files that people can use. This will allow us to keep the implementation fairly lightweight, but provide a few font options in various sizes, with the ability to mix them on screen at once.

Here is what I propose:

I think this can all be done without breaking anything which relies on the existing behavior. And should allow mutiple font sizes on the display at once, memory allowing. Anyone with a custom font file may have to make some changes (i.e add the width/height bytes to the start), but I've not see to much of this browsing through the user space directories.

brickbots commented 4 years ago

I've done a bit more digging, and I think that this font file may be a good base:

https://lexus2k.github.io/ssd1306/ssd1306__fonts_8c_source.html

It looks like these are from the GLCD Font Creator program, and have a format very similar to what I was thinking, if you exclude the few non-fixed fonts. Here is an example of the preamble:

0x00, // 0x00 means fixed font type - the only type supported by the library
0x08, // 0x08 = 8 - font width in pixels
0x10, // 0x10 = 16 - font height in pixels
0x20, // Standard filler/delimiter before font data starts

Then the font data is a series of bytes from left to right / top to bottom. Unless anyone objects I'll grab this file as a base and see if I can make the required driver changes to support it.

zigotica commented 4 years ago

hi @brickbots @XScorpion2 any update on using custom 8x16 font? thank you

brickbots commented 4 years ago

Thanks for asking @zigotica. After my last update I got several fonts setup in the correct format and roughed in some code, but it's not working reliably yet. I'm sorry to say I've not spent much time on this since then, but your inquiry is good motivation for me to finish this up and get a merge request in.

Did you have any thoughts about the implementation of this, or just interest in the status and when it might be available?

zigotica commented 4 years ago

hi @brickbots and thank you. sorry i was out for hols. I didn't get my hands dirty with this just yet. was curious and found out no one had yet tackled this. pro micro size (ATmega32U4 free space) is an issue for sure, so options might be limited

zigotica commented 4 years ago

OK, retried using the 8x16 font suggested by @brickbots above,

#define OLED_FONT_H "keyboards/kyria/keymaps/zigotica/glcdfont.c"
#define OLED_FONT_WIDTH 8
#define OLED_FONT_HEIGHT 16

When running qmk compile (latest version, I am at cd73949) still complains about it:

Compiling: drivers/oled/oled_driver.c                                                              drivers/oled/oled_driver.c: In function 'oled_write_char':
drivers/oled/oled_driver.c:388:27: error: 'font' undeclared (first use in this function); did you mean 'float'?
     _Static_assert(sizeof(font) >= ((OLED_FONT_END + 1 - OLED_FONT_START) * OLED_FONT_WIDTH), "OLED_FONT_END references outside array");
                           ^~~~
                           float
drivers/oled/oled_driver.c:388:27: note: each undeclared identifier is reported only once for each function it appears in
drivers/oled/oled_driver.c:388:20: error: expression in static assertion is not an integer
     _Static_assert(sizeof(font) >= ((OLED_FONT_END + 1 - OLED_FONT_START) * OLED_FONT_WIDTH), "OLED_FONT_END references outside array");
                    ^~~~~~
 [ERRORS]
 |
 |
 |
make[1]: *** [.build/obj_kyria_rev1_zigotica/oled_driver.o] Error 1
make: *** [kyria:zigotica] Error 1
Make finished with errors

Apparently the sizeof is out of range. I think I saw a fix somewhere subtracting one to the size, but I'm not really sure it is 100% related, nor remember the link.

zigotica commented 4 years ago

OK I think my problem above is related to https://github.com/qmk/qmk_firmware/pull/8145 but that was merged in February

brickbots commented 4 years ago

Hi @zigotica ! Just to clarify a bit... I've thought about how this might work, and played around a bit on a branch, but I've not committed anything yet. So, for now I believe only the 8x8 fonts will work out of the box.

Sorry for any false hope here, I have started working on this (thanks again for pinging about it), but it will probably be a while before it's ready to issue a merge request as I want to try to enable a wider array of fonts without breaking all the other OLED stuff already in play :-)

XScorpion2 commented 4 years ago

A big part of the issue with going to larger font sizes is the structure of the buffer. Currently it's an array where each byte represents 8 pixels vertically, starting top left corner, going right, wrapping to the next row of pixels when we reach the end. 8 bit tall fonts take advantage of this layout by using a memcopy approach copying the 8 bits tall x N bytes wide pixel data directly to the buffer for performance. For increased size fonts (IE: 16 bit high by N bits wide), you would need to do 2 passes shifting the bits, and copying 1 byte at a time to the buffer in 2 passes to get the upper and lower bits. Now this could be improved by storing the font data itself differently, separating the upper bytes in one chunk and lower bytes in another chunk. The problem is I haven't done much digging into font creation apps that split the data up like that. The few I have tried instead go horizontal with their bits, so you could do an 8 bits wide, N bytes tall font.

brickbots commented 4 years ago

Indeed, anything other than 8x8 will definitely be less performant. I was hoping to get the most flexible, slowest case up and running (arbitrary placement of arbitrary sizes) and see how bad it would be. Then we could start to maybe set some conditions to speed it up... font sizes must be multiples of 8 high, or only limited to only specific placement in the buffer.

Might ultimately be a fools errand, but it would be nice to have a bit more flexibility on offer if we can make it user-friendly enough.

zigotica commented 4 years ago

Hey guys, thank you for the insights. I understand it's a hard problem to solve, given the small amount of free space in ATmega32U4 which is the most used micro, I guess.

Hi @zigotica ! Just to clarify a bit... I've thought about how this might work, and played around a bit on a branch, but I've not committed anything yet. So, for now I believe only the 8x8 fonts will work out of the box.

No pressure at all @brickbots I understood.

I was also thinking of creating an array and build each char (reduced to alphas and numbers) in 2 or 4 pieces and using a custom method to write each line in 2 runs. Kind of painting a logo but for words (lines actually). That should probably be doable, but again, space is limited. We'll see.

Thank you again

brickbots commented 4 years ago

@zigotica That's a great approach, and would definitely work and not require any core changes. You'd have to come up with a nice font file and a helper function in your keymap, but it's doable and would get you where you want to go.

Ultimately, it may actually be a good way of handling the bit more general case of double height chars. It's very much along the lines of what @XScorpion2 was talking about above with a specially encoded font file that works with the 8 bit memory structure.

XScorpion2 commented 4 years ago

@brickbots @zigotica Yup, that is pretty much what I was suggesting.

zigotica commented 4 years ago

Great then! I will let you know. Thank you both.

memco commented 3 years ago

Hi all, I have low vision and would love to be able to use a larger font so I can read the text. Any chance updates are coming soon?

BifbofII commented 3 years ago

I don't know if anybody is still working on this, but I have started some work on this issue and will create a PR draft soon. What I'm trying to implement is basically what was talked about by @brickbots and @XScorpion2 before, more details in the PR. Feedback is very welcome.

zvecr commented 2 years ago

This issue has been automatically closed because it has not had any recent activity. If this issue is still valid, re-open the issue and let us know.