russhughes / st7789_mpy

Fast MicroPython driver for ST7789 display module written in C
Other
533 stars 108 forks source link

Hershey draw segfault #39

Closed jdtsmith closed 3 years ago

jdtsmith commented 3 years ago

First thanks very much for doing this. I've wanted to move off the Loboris port to mainline MP for an old project, and a decent feature-full driver for my TTGO display was the sticking point.

I've been experimenting with your new v1.16 firmware.bin (Lily TTGO T-Display 135x240), and have encountered some issues with the draw command, using the concepts from the "hershey.py" example.

First a couple minor things: the gotheng and romant are not frozen in, so this example only runs if those are removed. Also, the rotation= keyword to the ST7789 method does not alter the logical width() and height(), unlike a separate call to rotation().

More concerning is that the draw method leads to non-drawing, freezes, or segfaults when used at the MP prompt, or indeed anywhere outside its creation context.

For example, with this simple main.py:

from machine import Pin, SPI
import st7789
import romand

tft = st7789.ST7789(
    SPI(1, baudrate=30000000, sck=Pin(18), mosi=Pin(19)),
    135, 240,
    reset=Pin(23, Pin.OUT),
    cs=Pin(5, Pin.OUT),
    dc=Pin(16, Pin.OUT),
    backlight=Pin(4, Pin.OUT),
    buffer_size=64800)

tft.init()
tft.rotation(1)

The following occurs directly at the prompt:

>>> tft.draw(romand,"TEST1234IS",0,32, 0xe000)
Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.

Core  0 register dump:
PC      : 0x400d3749  PS      : 0x00060c30  A0      : 0x800de01c  A1      : 0x3ffccf00  
A2      : 0x00000004  A3      : 0x3ffcd0cc  A4      : 0x000c000e  A5      : 0x00000006  
A6      : 0xfffffffb  A7      : 0x3ffccf00  A8      : 0x800d373d  A9      : 0x3ffcced0  
A10     : 0x00000001  A11     : 0x00000001  A12     : 0x00000000  A13     : 0x00000006  
A14     : 0x00000006  A15     : 0x3ffcced0  SAR     : 0x00000001  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x00000004  LBEG    : 0x4000c46c  LEND    : 0x4000c477  LCOUNT  : 0x00000000  

Backtrace:0x400d3746:0x3ffccf00 0x400de019:0x3ffccfa0 0x400e3b2d:0x3ffccfd0 0x400e3c5a:0x3ffccff0 0x400e5c35:0x3ffcd010 0x400de098:0x3ffcd0b0 0x400e3b2d:0x3ffcd120 0x400e3b56:0x3ffcd140 0x4010d59f:0x3ffcd160 0x4010d8b1:0x3ffcd1f0 0x400f463c:0x3ffcd230

This occurs whether or not I let the driver dynamically allocate memory or set the buffer size in advance (as here). What is strange is if I put this single call to draw at the end of main.py it works as expected.

I can get the hershey.py example working (once I removed the missing fonts). But ONLY if I initialize and immediately use the ST7789 object in the same context (e.g. in that example module's main). I can't import the ST7789 object from another module, pass it in as an argument to another method, or use it from the REPL, etc. — this always leads to freezes or segfaults.

I haven't seen this with normal bitmap fonts, only the Hershey fonts and their draw method.

Thanks again for your work on this.

russhughes commented 3 years ago

I will look into this. I haven't done much with the Hershey fonts since version 1.12 so they may need some changes.

russhughes commented 3 years ago

I have fixed the segfault issue but I'm not seeing the rotation issue.

from machine import Pin, SPI
import st7789

rot=0
tft = st7789.ST7789(
    SPI(1, baudrate=30000000, sck=Pin(18), mosi=Pin(19)),
    135, 240,
    reset=Pin(23, Pin.OUT),
    cs=Pin(5, Pin.OUT),
    dc=Pin(16, Pin.OUT),
    backlight=Pin(4, Pin.OUT),
    rotation=rot)

tft.init()
print("before rotation:", tft.width(), tft.height())
tft.rotation(rot)
print("after rotation:", tft.width(), tft.height())

For rot= 0, 1, 2, 3 tft.width() and tft.height() return the numbers I would expect.

rot=0
before rotation: 135 240
after rotation: 135 240

rot=1
before rotation: 240 135
after rotation: 240 135

rot=2
before rotation: 135 240
after rotation: 135 240

rot=3
before rotation: 240 135
after rotation: 240 135
jdtsmith commented 3 years ago

Great, thanks! The draw segfaults are confirmed to be fixed in some testing. I did notice that draw insists on 5 or more arguments, despite the docs mentioning that fg and bg are both optional.

Also, do you have any tips or build settings for building your firmware files for the various targets like TTGO display? As mentioned mine following your default instructions with MPv1.16 uses too much RAM.

russhughes commented 3 years ago

See https://github.com/russhughes/st7789_mpy/issues/40#issuecomment-904740149 for information about making more flash space available if you are running out of flash. If you are running out of RAM you need to reduce your buffer_size=64800 if possible. The only reason to have a buffer that size would be for fullscreen bitmaps. You could tile or split your bitmaps to reduce the RAM needed or use jpg's with the SLOW draw method. You can save RAM by freezing your bitmaps in flash so they can be read directly from flash with little RAM use.

I will fix the parameter issue tonight.

jdtsmith commented 3 years ago

Thanks. Even with dynamic buffer allocation I don't have enough RAM for a JPG (though perhaps with SLOW it would work). Something like 60K (mine) vs. 109K (yours) free. I'll looking into altering the app boundary.

russhughes commented 3 years ago

The write method returns the width of the string as printed in pixels since it could be using a proportional spaced front. The REPL will print any returned values. You should not see prints when run using import.

jdtsmith commented 3 years ago

This always gets me. Thanks.