setFontCustom bitmap format vs vertical_byte:true - GT24L24A2Y fontchip in F07 fitness tracker #7621
Replies: 1 comment
-
Posted at 2020-05-30 by @allObjects ...next thing is a Femto Espruino with plug-able SPI chips like 40+ years ago the PC with 'user'-plug-able io/memory/what-ever cards... ;-) Posted at 2020-05-30 by @fanoush Got it partly solved. I can at least draw it to screen letter by letter. I also mapped the fontchip as ordinary flash via SPIFLASH in board file so it is accesible via Flash module and it can be easily read. Then I found Graphics.asImage which works only when called with asImage("string") (not "object" due to vertical_byte:true ?) and I can draw it via drawImage. so e.g. to draw big digit "3" from the 40x64 font I do it like this:
So it works and I can make my own drawString letter by letter. May be even better for large clock numbers. Also looks like the first byte of each letter is real letter width so the font is in fact proportional (and I need to zero the data before drawing). Is there way to draw only part of larger image? The width is 40 but letter '1' is only 33 pixels wide. I don't see any way to take/draw only some part of the image both in Graphics.asImage and Graphics.drawImage. Maybe transparency could solve it too but there is no way to provide that either with asImage("string") or drawImage options. Posted at 2020-05-30 by @fanoush Tried to avoid vertical_byte:true in final image to feed it to createCustomFont but it made no difference - still see random garbage. I made following method to convert it to single buffer which is not in vertical format
and the result is attached, but when creating font from it like this
or this
it is still not right so the format is still something else. Attachments: Posted at 2020-05-31 by @MaBecker take a look at this online tool http://ebfc.mattbrailsford.com/ Posted at 2020-05-31 by @fanoush I know about it, not sure how it could help me in this case. I am trying to do it directly on the device on the fly as the data is already there. More helpful is this https://github.com/espruino/Espruino/blob/master/scripts/create_custom_font.js but still I didn't get what is correct format from that code. The page http://www.espruino.com/Fonts#custom-fonts says "You'll need a string containing a column-first, most significant bit first, 1 bit per pixel bitmap" which is still not enough for me to understand. Also when looking at font sources like https://github.com/espruino/Espruino/blob/master/libs/graphics/bitmap_font_6x8.c it looks like the data is in rows, not columns. Posted at 2020-05-31 by @fanoush I guess I got it, fontchip has data in columns too but second byte is 8 bits from second column (= {vertical_byte:true})while espruino custom font array need all bytes of first column first an then second column starts. So i'll try to swap the bytes around and see. Posted at 2020-05-31 by @allObjects @fanoush, I like our dedication to details... the challenges get you really going! Posted at 2020-05-31 by @fanoush got it working, last catch was lsb to msb conversion (did via table, named M2L in code below)
then to set font https://github.com/RichardBsolut/GT24L24A2Y#font-clock-2-34x48 I use it like
however the code is a bit slow for fonts with more characters so I need to ping the watchdog and BTW found out that GT24L24A2Y is otherwise pretty normal 2MB SPI flash that I can write and erase and space over 0x1A3000 is empty so I could perhaps convert those fonts once and write back in better format to load them directly next time Posted at 2020-06-01 by @gfwilliams Great! Glad you got it sorted! You can do It's possible that you could read the data with Posted at 2020-06-01 by @fanoush It could help for lsb to msb conversion but there is at least one other issue: there is no As for rotation, yes maybe this could do it after all in one extra step, render it from first one with vertical_byte to second one (already done in post #4 - the single bitmap with all letters, this rotates columns into rows) but also setup rotation on destination (so rows are written back to columns in correct order.) Not sure when the rotation is applied - if the bytes are indeed stored rotated or when later reading pixels from it, will check. Anyway the biggest issue for me was to understand format of data that Graphics.setFontCustom accepts, the rest is more clear now. There is even arm native library for this fontchip in some github procects (e.g. here or here) so I could use it to get all fonts out of it and with proper encoding. As maybe there are more fonts there than documented at https://github.com/RichardBsolut/GT24L24A2Y Posted at 2020-06-03 by @gfwilliams Ahh - I think this is what you need - this code creates the font in Graphics directly: https://github.com/espruino/EspruinoDocs/blob/master/modules/Font5x7Numeric7Seg.js
If there's somewhere you think I can improve the docs around I guess there's the possibility that something that renders direct from flash could be built into Graphics, or that Posted at 2020-08-25 by @fanoush I am back to this topic since the DK08 watch clock screen could use some nice fonts and has this fontchip too. (BTW it is in sale for $14 now) Thanks for the last suggestion, tried again and it (almost) works!!! The
However currently the biggest issue for me is that setFontCustom accepts only String type as the font bitmap and I have byte array. Unfortunately for larger fonts than just few letters E.toString() mostly returns 'undefined' possibly because the font buffer is too big so it cannot make flat string out out of that due to low/fragmented memory. Is there Uint8Array to String conversion that would always succeed i.e. share the same buffer? or could setFontCustom easily accept Uint8Array too? Now it fails with Posted at 2020-08-26 by @fanoush just a followup - I found kind of a workaround for converting big array to string - writing it to Storage :-) Hopefully there is even advantage that the font data is used directly from flash, saving RAM. Here is code snippet that creates font, writes it to Storage and then creates font from that. And it shows on screen just fine :-)
But anyway method to change type of byte array to string in place and share same data would be nice to have. Posted at 2020-08-26 by @gfwilliams Just looked at this and Is there a reason you're doing Posted at 2020-08-26 by @fanoush
no, just took it from your example in post #12, will check if it makes difference, I think I tried both. I have like 900 out of 2600 variables still free, with e.g. 176x176x4bit framebuffer allocated and also some Inline C code so there is memory but can be fragmented. This is 64x40 font so relatively large but even when taking just number digits (10 letters) E.toString often fails in this case. Will check what trace does, thanks. Posted at 2020-08-26 by @fanoush I now just return whole Graphics from createFont and here is copy of session where E.toString fails, no asImage used this time
I guess the main issue is that https://www.espruino.com/Reference#l_E_toString says "Returns A String (or undefined if a Flat String cannot be created)" In this case I'd be happy with non flat string - the Posted at 2020-08-28 by @fanoush I tried to replicate the issue in Bangle emulator and also other nrf52 board and with simple allocations of Graphics.createArrayBuffer until memory is low and calling E.toString on the buffers it just works. Maybe the memory is not fragmented enough. Those graphics buffers should be always guaranteed to be flat strings already? I am also suspecting possible memory corruption from my InlineC code now since I also have some random hangs and watchdog reboots after my code runs for some time. Posted at 2020-08-28 by @gfwilliams I guess it could be a memory corruption issue? The new Espruino builds will automatically defragment memory if they have trouble allocating a Flat String, so ideally it wouldn't fail. But it's a bit frustrating not being able to get the backing string out of the ArrayBuffer - I was sure there was a way to do it, but it seems not... Posted at 2020-08-28 by @fanoush
how new is new approximately? Days/weeks? Would it move e.g. inline C binary around? Or other flat strings so older E.getAddressOf is no longer valid? just asking, currently I take getAddressOf(x,true) immediately before calling native code and the code is position independent anyway so hopefully it does not matter. And there is no real multithreading so this should not happen when Inline C code is running(?) as you probably don't allocate stuff that could cause this defragmentation from interrrupt handler. I'll check for the memory corruption on other board with swd available, add same/similar code until it breaks. Posted at 2020-08-30 by @fanoush Well, I guess I had several issues at once, possibly also memory corruption due some instability (did try to enable internal DCDC like 14 days ago, it was unstable so I turned it back off, restarted, rebooted but maybe it still left the cpu still in some broken state as very same code that was randomly unstable in now stable). But after trying with different device it looks like maybe there is some memory leak? I create software spi via new SPI() then delete it and variables go down by one. Tried few times and always free variables go down by one after deleting it. Also E.dumpFragmentation() shows some suspicious 'L' near the end which seems to be increasing after each attempt, see full log here Posted at 2020-08-30 by @fanoush also with clean device
EDIT: Posted at 2020-08-31 by @fanoush created espruino/Espruino#1923 , looks like it is more complicated and a bit off-topic here Posted at 2020-08-31 by @gfwilliams Wow, thanks! Just tracked this down and will fix it in a second - amazed this was never spotted before! Posted at 2020-08-31 by @gfwilliams Ok, latest version has this fixed Posted at 2020-08-31 by @fanoush Yes, now it is fixed, thanks. I hoped it would help with memory fragmentation in my case so that E.toString() would work on the font but it wasn't enough. There is probably too much fragmentation already so even without this locked/leaked SPI variable(s) it doesn't work and still return undefined. Also E.defrag() does not help. The
Attachments: Posted at 2020-09-01 by @gfwilliams That's a shame - still, you've got extremely high memory usage there. IIRC the defrag won't move flat strings - I was concerned about what you'd mentioned earlier - moving stuff that you had a pointer to. Posted at 2020-09-01 by @fanoush Yes, memory usage is high, this is actually with code uploaded to ram so it can be better. Still before trying to create the font, ther are like ~500 variables free so was hoping this could work. This is more like stress test of Espruino memory, not that I couldn't do it better. There are quite a lot of flat strings, more than I expected, any way to find them? Can it be the javascript code that is uploaded? I guess the main thing from this is that it would be nice to get non-flat string from the array buffer somehow so it is not need to call E.toString on large arrays.
Maybe it could be some flag to E.defrag() to force it when called explicitly. I can handle that in my own code if I can call it myself with that flag when needed, now sure how much espruino internal usage of flat strings would break (if there is any). Posted at 2020-09-01 by @gfwilliams
Yes - if there's a decent size string to allocate Espruino will try and use a flat string since it's more space efficient, so that could be it. Using And yes, potentially compacting flat strings could be added. I think it just felt non-trivial at the time so I didn't add it. But yeah, ideally there'd be a way to get the string from an arraybuffer. I guess I could add a non-standard function like Posted at 2020-09-01 by @fanoush
Yes, if E.toString is taken and not usable for this then why not.
can I call a2.getBackingString() to get string of 3 bytes or is this method for underlying a2.buffer buffer. In first case there could be Posted at 2020-09-04 by @gfwilliams
Afraid not - I couldn't make it reference just part of a String, it's got to be the whole thing |
Beta Was this translation helpful? Give feedback.
-
Posted at 2020-05-30 by @fanoush
Hello,
was trying to use fonts included in GT24L24A2Y SPI font chip, these chips are often used in smart watches and fitness trackers to provide fonts in many languages. Basically it is relatively normal SPI flash memory with font data is some format. Th structure of fixed width fonts for this chip is documented here https://github.com/RichardBsolut/GT24L24A2Y I tried to read is as ordinary SPI flash via W25 module into
Graphics.createArrayBuffer
and it works and the description of offsets and sizes looks correct and I can see letters when I create buffer in correct format. However the buffer must be created withvertical_byte:true
parameter. If I put the data directly intosetFontCustom
it is not looking good because it does not accept this vertical format.Any idea how to load/convert/rotate such font data in memory via some Espruino graphics/bitmap/image magic so I could then pass the buffer directly to setFontCustom ?
I have attached screenshot how I can load individual letters of https://github.com/RichardBsolut/GT24L24A2Y#font-clock-4-22x32
And BTW here is video of example code running on this fittness tracker, it is mostly same as P8 smartwatch code linked previously here. This F07 is ~$14-$16 aliexpress item and can be updated to Espruino without taking apart.
Attachments:
Beta Was this translation helpful? Give feedback.
All reactions