Xinyuan-LilyGO / LilyGo-EPD47

GNU General Public License v3.0
402 stars 120 forks source link

rotate screen #9

Open kd8bxp opened 3 years ago

kd8bxp commented 3 years ago

is it possible to rotate the screen, from landscape to portrait? Thanks

lewisxhe commented 3 years ago

Can't rotate right now...

kd8bxp commented 3 years ago

Hopefully in the future?

lewisxhe commented 3 years ago

It should be possible in the future!

kd8bxp commented 3 years ago

My solution for now is to build a static text image using GIMP, with a size of 540x960, put the text I want displayed, and rotate the image. Then display that image...this works, but it is only static text - so not really practical. IMG_20210112_160640226

Of course using GIMP, rotating/resizing images is easy to do, however the aspect ratio will probably be off. IMG_20210112_155021817

I look forward to when this device natively supports rotating. Thanks.

mol21 commented 3 years ago

I agree it would be great if at least text can be rotated

kd8bxp commented 3 years ago

M5EPD driver (for the M5Paper) looks like it supports rotation, but I'm not sure what pins need to be changed to try with this display. I think they are using the same display, but are they using a different driver to drive it (?).

https://github.com/m5stack/M5EPD

This is the pin map for the M5Paper:

`#define M5EPD_MAIN_PWR_PIN 2

define M5EPD_CS_PIN 15

define M5EPD_SCK_PIN 14

define M5EPD_MOSI_PIN 12

define M5EPD_BUSY_PIN 27

define M5EPD_MISO_PIN 13

define M5EPD_EXT_PWR_EN_PIN 5

define M5EPD_EPD_PWR_EN_PIN 23

define M5EPD_KEY_RIGHT_PIN 39

define M5EPD_KEY_PUSH_PIN 38

define M5EPD_KEY_LEFT_PIN 37

define M5EPD_BAT_VOL_PIN 35

define M5EPD_PORTC_W_PIN 19

define M5EPD_PORTC_Y_PIN 18

define M5EPD_PORTB_W_PIN 33

define M5EPD_PORTB_Y_PIN 26

define M5EPD_PORTA_W_PIN 32

define M5EPD_PORTA_Y_PIN 25`

It has other sensors, and a SD card which wouldn't be needed, so a striped down version of the library? Does anyone know what needs to be changed?

G6EJD commented 3 years ago

I’ve only just started to look at this board and driver, have you tried reversing EPD_WIDTH and HEIGHT? I’ve seen examples that have been drawn in landscape with no obvious driver changes.

kd8bxp commented 3 years ago

the LilyGo driver is based on this https://github.com/vroland/epdiy driver - it appears to be in landscape to start with. I have thought about asking this same question on that repository, which maybe a good idea anyway. (If you read some of the post in that repository, you soon find out they reverse engineered the driver. So that's interesting) I know that M5Paper is using the same display, I don't know if it is using the same driver, M5Paper appears to be able to rotate the screen at least 90 degrees (one of the examples they have). and honestly I haven't tried anything with regards to the M5Paper driver.

With the driver provided by LilyGo I did try to change the EPD_WIDTH and HEIGHT with no luck (that would have been too simple honestly).

The pictures above, are really in landscape, just flipped and are static pictures -it was an idea that I had, it wasn't a good idea...but there you go. I created those images in GIMP and converted them to hex files for use on the board with the LilyGo driver.

I will play with the M5Paper driver a bit and see if I can get anything to work.

kd8bxp commented 3 years ago

This is the schematic for the M5Paper - https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/schematic/Core/m5paper/M5_PAPER_SCH.pdf This is the one @vke posted in the closed hardware thead (https://github.com/Xinyuan-LilyGO/LilyGo-EPD47/issues/2#issuecomment-757875009)

If I right, they are using two different drivers for the display (?) or am I looking at something wrong.

I tried the M5Paper library as is, with no luck, and then found the schematics.

fdufnews commented 3 years ago

As far as I understand how the driver works, all the graphics and text are drawn in the buffer and the buffer uploaded to the screen. So if you swap X and Y when drawing in the buffer I think you'll rotate the content of the screen.

kd8bxp commented 3 years ago

@fdufnews Seems like all I am able to get it to do is move text and images around on the screen using the framebuffer. perhaps I am not using the framebuffer correctly have you tested it? can you post an example. Thanks

G6EJD commented 3 years ago

I have not tried rotating yet, but I'm sure font rotation will not be achieved, yes drawing objects could have their x, y values reversed, but that's all.

kd8bxp commented 3 years ago

I am having to rotate the images in gimp before converting them to hex, it works, but it is one extra step. Of course if you are having to resize an image it only takes an extra couple of clicks to rotate it. So far that is the only way I've been able to rotate anything.

I used "Fontforge" to rotate some fonts, and converted them - but didn't have much luck getting more than 5 or 6 to display. I was trying to direct draw them, maybe I should try to load them into the buffer and see if I can't get a more then 5 or 6 characters to display. I'll give it a try and report back - but it quite a lot of extra steps to rotate a font, so still not the best option, it might be an "ok" work around for now, if loading into the buffer works that is.

kd8bxp commented 3 years ago

Loading the framebuffer with the font that I rotated, worked (mostly), my code is not pretty, and probably not ready to be shared. And it's a lot of work to rotate fonts, in fact I think I messed up the "i" when I did it...but proof of concept I guess.

IMG_20210125_193214712_HDR

maybe we can build some common rotated fonts, and make a function that can load the framebuffer with them. (?)

kd8bxp commented 3 years ago

@G6EJD Another proof of concept that isn't quite right, but someone who knows more can probably fix it. The idea is to rotate the font with a font editor, convert the font, then display the font. I used fontforge to do this, I kind of "winged" my way to doing it. I wrote a small function to load the framebuffer with a rotated font, the spacing is off, not sure how to fix that - I'm sure it's something simple that I'm over looking.
Also it has an issue if you load a 2nd or 3rd rotated char array, (see the picture) I'm not sure what it is doing, I cleared the framebuffer and it is still doing it. So this is very much an idea, a concept, a work in progress, and something that someone who knows something can probably fix. fontRotate.zip IMG_20210125_235739843 IMG_20210125_235707144_HDR

P.S. this still may not be the best idea, but I'm trying things out - and that is half the fun. LOL

G6EJD commented 3 years ago

I’ll have a look through this today, but I’ll also look at the driver data sheet as I’m guessing there may well be a hardware option to do this. Your method could be a solution, thanks for sharing.

G6EJD commented 3 years ago

Looking through the ED047TC1 data sheet there is mention of the display modes being Landscape and Portrait, so I assume from this it can be rotated by hardware/ Register control, I have not yet found the application notes if there are any or a more detailed description of the registers. This is promising.

G6EJD commented 3 years ago

So M5 Display driver is an IT8951 versus the ED047TC1 of the LilyGo EPD board.

Unfortunately, I have not found any reference to the driver registers/control but my instinct is it's usually used in portrait mode!

kd8bxp commented 3 years ago

So LilyGo EPD is bit banging the display (?) vs M5 using a driver chip (?) I have been looking for and all I see are various timings for the ED047TC1 but I don't see anything that says how to rotate it. But the datasheets do look like it will do both landscape and portrait. These all look like the same spec sheet... https://loboris.eu/ESP32/ED047TC1_datasheet.pdf https://www.syscom-prorep.net/media/images/upload/P-511-710-V1_ED047TC1%20Ver%201.0.pdf https://docplayer.net/61566900-Technical-specification-model-no-ed047tc1.html

And this is a forum post about the M5 paper which also has links to the display panel datasheet. https://community.m5stack.com/topic/2561/m5paper-schematic/7

G6EJD commented 3 years ago

That’s where I got to, but no register descriptions which would lead the way to rotating the display. I had a look through the M5 library but not find how they are rotating the display if at all.

kd8bxp commented 3 years ago

@G6EJD I guess we will just have to wait and see if Lilygo or @lewisxhe can come up with something, mean while I'll continue to do some of my ideas for work arounds, but I don't really like what I've done, lots of work for little pay off. Have a great day.

martinberlin commented 3 years ago

I'm supporting rotation in my class ED047TC1 both for the epaper and also for the touch screen. Proof of concept video here Note: I'm implementing also EPDiy class to send the parallel data but I have another Adafruit GFX layer in my class that handles rotation. At the same time if you implement the touch version, rotating the displays, also sends the rotation to the touch I2C layer so it's possible to keep on using touch coordinates.

kd8bxp commented 3 years ago

@martinberlin very nice!! Maybe one day it will work with the Arduino IDE as well (?)

martinberlin commented 3 years ago

Hi Leroy, If you look at the class ED047TC1 methods it's actually not too complicated. You need to keep rotation state and then update the X, Y before the epd_draw_pixel call (And I guess also in partial update if you want that it supports rotation). Actually EPDiy is a esp-idf component that can be used in arduino-esp32. I never tried to do so with mine and it's quite a long time I don't use arduino-esp32 since I like more IDF this days. I bet is not super complicated to port it, but looking at the class, all work is done by EPDiy in the background. I'm just adding C++ wrappers and some functionality. I guess you can use this as a base and do your own class.

kd8bxp commented 3 years ago

@martinberlin acutally I tried it today, was getting some compile errors, some where easy to fix, Still getting a large number of errors however - and I'm going to spend some time and see if I can work thou them. Part of them may be my fault. I mixed what you did with the library here, and the Adafruit_GFX library that was written for the Arduino IDE (when using your Adafruit_GFX library I was getting a bunch of errors related to it, so I tried the Arduino one, and those errors cleared.) The other errors are in the CalEPD library, dealing with various variables I believe. I'm going to work thou it, see if I can't get it to clear. But this maybe a little above my head. I'm impressed with your progress thou!!! Thanks.

martinberlin commented 3 years ago

You can also try CalEPD directly. Esp-IDF takes some days to master but is not super complicated. Both Cale and EPDiy are not hard to setup and compile. And it comes already with parallel demos in main/demos/parallel https://github.com/martinberlin/cale-idf/tree/refactor/oop/main/demos/parallel (Branch refactor/oop) Option B is to make your own display class. Less remix and just your own class with the methods you need (can use mine as an example) Thanks for the kind words about my work!

kd8bxp commented 3 years ago

Clearly I don't know what I'm doing here - I finally got it to compile by scaling a lot of it back, and just using a little bit of your code, the Adafrutit_GFX library, and this library from LilyGo.

When I upload the code to the board I get nothing but reboots. So clearly I've done something wrong, and not fully understanding what I've done. @G6EJD and @lewisxhe probably can get this working because I bet both know a lot more then me! :-)

I posted a gist with the errors I got, since it's not part of this project, and something I was trying I decided not to post the errors here, but if someone wants to look at them - https://gist.github.com/kd8bxp/ff9da93a377716176869aac121afd909

Using the Adafruit_GFX library as a wrapper sounds like a great idea, and hopefully someone can get it to work.

Thanks again @martinberlin

G6EJD commented 3 years ago

You must enable PSRAM in the compiler options!

martinberlin commented 3 years ago

@G6EJD maybe it will be cool to add a rotate option to this library? This can go from 0 (default) to 3 rotating 90° clockwise.

And it really does not need Adafruit GFX at all. I added that because I have a multi-epaper class where every model inherits the full GFX methods. But for rotation is not really needed. Like I mentioned, the only thing IMHO is to keep rotation state and be aware of it before drawing each pixel. Rotation is a very useful feature if you are using this display in some Firmware and you need to switch between landscape /portrait mode.

kd8bxp commented 3 years ago

@G6EJD PSRAM was enabled. (ESP32 Dev Module, with PSRAM enabled) and tried it with multiply boards, no luck. Clearly I don't understand what I'm doing, and I'm going to stop before I mess something up. And leave it in more capable hands.

martinberlin commented 3 years ago

@kd8bxp Leroy why don't you try to install ESP-IDF and make your first steps? It just take some days to get accostumed and then you can try my class and examples directly. In essence the C++ style is very similar to arduino-esp32 and all what is IDF specific is deep in the IO classes and so on. It's quise easy once you try to build custom Firmware and also use the examples to get advanced features like reading a BMP from WiFi, partial refresh demos and more. At least you can give it a try. I can help somehow if you join the EPDiy slack channel. Or you can also leave me a message at martin at luckycloud.de and I will try to help in case you get stuck. Also everything by Espressif is quite well documented and there is a lot of resources. Everytime I got stuck I found examples of someone that did something similar and I just had to follow. Before implementing first touch I had no idea how to handle I2C in IDF, just took me 3 or 4 days of research to see other examples and get it running.

kd8bxp commented 3 years ago

@martinberlin I made my first steps in ESP-IDF - got "Hello World" compiled - I'm still confused by a lot of what is going on. It's just different. And as you say will take some getting use to. I'm working my way though the tutorials thou, so we will see how it goes.

PS I also signed up on the cale website, but think I need to get ESP-IDF done first so I can compile the firmware correctly

martinberlin commented 3 years ago

Then you are almost there. I recommend using the branch refactor/oop since is the development one Repository to clone: https://github.com/martinberlin/cale-idf.git

In main/CMakeLists uncomment first parallel example and leave the rest commented.

Like that you can select what demo to compile. Then you have to run: menuconfig to set up the constants and ESP32 config. Easy steps:

Run idf.py menuconfig-> Component Config -> E-Paper driver and select: // Display type: LILYGO 4.7 ED047TC1 // Board: LILYGO T5-4.7 Epaper In the same section Component Config -> ESP32 Specifics -> Enable PSRAM

that’s important since with SPI ram this won’t run! And if that example runs correctly, then you can also prepare a screen URL in Cale and point the example to Cale-grayscale example (Remember that you need to uncomment only that source in main/CMakeLists.txt) For that you need to add in menuconfig also the screen url and your WiFI credentials, explained here: https://cale.es/firmware-idf

Then you just replace the epaper instanciation for the parallel instead of SPI in Cale-grayscale.cpp

#include "parallel/ED047TC1.h"
Ed047TC1 display;

that’s mostly it to try it. Then you can of course make your own cpp file and do your own thing. This is the point where is not far of arduino-ESP32 you just don’t need a setup() and loop() Follow the examples and you can do very fast some learning steps and start doing a lot of things with this epaper including partial refresh and touch.

kd8bxp commented 3 years ago

The other day I made progress with esp-idf and help from @martinberlin - Still getting the hang of esp-idf, but for sure the screen can be rotated with software. IMG_20210310_222119306

I still need to learn a lot - but progress is progress! Thanks again Martin

martinberlin commented 3 years ago

Glad that you found my component useful Leroy. IDF is a very nice framework and doing it this way you inherit all Adafruit GFX. Apart of rotation gives you all geometric functions and fonts. Adafruit has also a command line tool to generate C arrays from TrueType font files for those interested in trying new fonts in this nice epaper. Font used in your photo is Ubuntu: https://github.com/martinberlin/cale-idf/tree/master/components/Adafruit-GFX/Fonts/ubuntu rendered the C files using that tool. You just need to clean out PROGMEM types since it’s for arduino-ESP32

martinberlin commented 3 years ago

Quick question here @lewisxhe and team, It's going to be possible to do a software rotate in the epaper in a near future or shall I do something and make a pull request?

I ask because one user of your epaper made an issue in my repository to ask if it's possible to use my component in Arduino-esp32. But currently is not. So I though maybe I can help? Just tell me. And of course if there are some interest and some thumbs up feedback I will take my time to do it.

G6EJD commented 3 years ago

Hi Martin, I think there is no doubt that the vast majority of customers for this display will be using the Arduino IDE and there-in lies the answer for most🙂well done on the work by the way.

martinberlin commented 3 years ago

Alright so my 2 epapers are coming beginning next week so I will fork this and try to add a simple software rotate just as I did in my component. I don't use Arduino IDE but I use Platformio that I like much more. Arduino IDE makes me mad with their nasty library management. At least Platformio keeps all components in the project folder that makes all nicer (At the price of taking much more of your Hard-Disk space)

martinberlin commented 3 years ago

Introducing software rotation

Forked this and added it in this commit: https://github.com/martinberlin/LilyGo-EPD47-rotate/commit/03123d748c71fc543b453c081178bd7f26486c96

Note that my new parallel epaper comes next week so I could not really test it. But it's simple enough, so any of you can just point the Platformio lib_deps to my fork and try it out (Or just copy the small updated part to your library)

To try it just update platformio.ini lib_deps and remove old library from .pio/libdeps folder

lib_deps =
    Wire
    https://github.com/martinberlin/LilyGo-EPD47-rotate.git

Explanation: Just before the drawpixel, move around X and Y if necessary (0 is the default and should leave X & Y as is) Note like I commented before I did not tested this at all and it might be possible that also affects partial updates somehow (As rotation should be also applied there I think) But feel free to try it or at least review my code. Please note also that I just updated the examples/grayscale_test updating the platformio.ini with my forked copy and updating epd_rotation to 2 as an example.

0 is the default 1 90 ° right: Portrait 2 is landscape but 180° right 3 270 ° right: Portrait

cultur98 commented 3 years ago

Cool Martin! I will have a look on it next week.

kd8bxp commented 3 years ago

@martinberlin Got some errors, using both Arduino IDE 1.8.13 and Platform IO (which was recently updated, but I'm not sure what version it is). Both gave the same error - the wording was a little different (if I remember correctly). I tried to use my limited knowledge to fix, but no luck.

sketch/src/epd_driver.h:25:5: error: expected constructor, destructor, or type conversion before '(' token
 swap(T& a, T& b) {
     ^
grayscale_test:15:1: error: 'epd_rotation' does not name a type
 epd_rotation = 2;
 ^
exit status 1
'epd_rotation' does not name a type

There maybe a problem with the use of the name "epd_rotation" I commented that out in the sketch, and commenting out the swap(T& a, T& b) function, I think I made another change because of that. I was getting errors related to "epd_rotation" being re-declared in font.c - I looked and I didn't see it - the only way I was able to get it to compile was changing epd_driver.h uint8_t epd_rotation = 0; to #define epd_rotation 0 unfortunately I didn't save the error it gave me... just a heads up that something else might be going on.

martinberlin commented 3 years ago

Hi @kd8bxp it's fixed now. Please remove the .pio/libdeps LilyGoEPD47 folder (So it get's the new version)

And just try to compile again. Note that I added a setter to set rotation, just check the grayscale example. Try to do the following:


void setup() {
    epd_init();
    // Non tested: Update rotation (0 & 2: Landscape    1 & 3: Portrait)
    epd_set_rotation(3);
}

// Use epd_get_rotation() to retrieve the rotation state

In my tests I just tried to print a pixel like this after setting rotation to 3:

// x, y epd_draw_pixel(10,20,0x00,grayscale_img);

And in the Serial output I get: x:20 y: 529

Which means the x and y is being rotated on the switch. Resume of the update if any of you want to make a Code review: https://github.com/Xinyuan-LilyGO/LilyGo-EPD47/compare/master...martinberlin:master

Rainerlan commented 3 years ago

Hi @martinberlin,

I was following the discussion with great interest and very keen to try out your fix. Many thanks for the work you have spent!

What I found is the following (Using my weatherforecast sketch): 1) When using epd_set_rotation(1);

Yet I have not investigated in the issues - but probably you know what the problem may be?

kd8bxp commented 3 years ago

@martinberlin @Rainerlan I get no compile errors with the latest commit f0cbe75a10 I can also confirm that epd_set_rotation(3); causes resets and reboots (kernel panic) I can also confirm that rotate doesn't work with fonts.

It doesn't work using epd_draw_grayscale_image either.

I tried with both Arduino IDE and Platform.IO I also add a epd_set_rotation statement to the demo sketch with out any luck, and tried a couple of the sketches that I had written with out luck. I did not tried rotation of drawRect(), fillRect().

That's my report for what it is worth.

kd8bxp commented 3 years ago

@martinberlin I'll update my report - I checked the following:

epd_draw_hline epd_draw_vline epd_draw_circle epd_fill_circle epd_write_line epd_draw_triangle epd_draw_line all appear to work, however it doesn't look like there is any check for out of bound area. epd_draw_rect epd_fill_rect both appear to work as reported by @Rainerlan

epd_fill_triangle probably works, but I forgot to test that one. I think that is all of the draw elements, and those all appear to work.

That's my updated report

martinberlin commented 3 years ago

Thanks for the tests both! I will have to wait a few days so the new epaper comes. Already landed in Frankfurt am Main so it just needs 3 or 4 days if I'm lucky and is not stopped in customs.

**Rotation of elements drawn using drawRect(), fillRect() -> working perfect**

That's already something. No idea why with 3 panics, that needs more research, and probably to do a printf("x: %d y:%d\n",x,y) to debug in Serial where is trying to place the pixel.

**write_string() -> Strings are not being rotated**

That's because I wrongly assumed that all other functions including fonts (font.c) where calling epd_draw_pixel. But I was wrong like you discovered write_string() is a different thing. That needs research, since I don't think is enough just to rotate cursor x & y. Will need some help figuring out that one. With Adafruit GFX is easier since all drawing happens in drawPixel (Including the fonts) so rotation just needs to be placed there.

Another thing where probably needs to be calculated like I mentioned before is partial update. The best thing of course is to build this with Rotation in mind and not to add it afterwards as we are trying to do here.

kd8bxp commented 3 years ago

@martinberlin amazing work so far thou!!! Thanks for the hard work, I'm sure once you get your display you'll figure out what is going on.
There is also writeln and epd_draw_grayscale_image that need more research. I will be more than happy to test anything you want to try either before or after you get your display. Thanks again.

kd8bxp commented 3 years ago

@martinberlin It looks to me like epd_draw_grayscale_image and the fonts share this function in epd_driver.c

void IRAM_ATTR epd_draw_image(Rect_t area, uint8_t *data, enum DrawMode mode)
{

    uint8_t line[EPD_WIDTH / 2];
    memset(line, 255, EPD_WIDTH / 2);
    uint8_t frame_count = 15;

    SemaphoreHandle_t fetch_sem = xSemaphoreCreateBinary();
    SemaphoreHandle_t feed_sem = xSemaphoreCreateBinary();
    vTaskDelay(10);
    for (uint8_t k = 0; k < frame_count; k++) {
        OutputParams p1 = {
            .area = area,
            .data_ptr = data,
            .frame = k,
            .mode = mode,
            .done_smphr = fetch_sem,
        };
        OutputParams p2 = {
            .area = area,
            .data_ptr = data,
            .frame = k,
            .mode = mode,
            .done_smphr = feed_sem,
        };

        TaskHandle_t t1, t2;
        xTaskCreatePinnedToCore((void (*)(void *))provide_out, "privide_out", 8000,
                                &p1, 10, &t1, 0);
        xTaskCreatePinnedToCore((void (*)(void *))feed_display, "render", 8000, &p2,
                                10, &t2, 1);

        xSemaphoreTake(fetch_sem, portMAX_DELAY);
        xSemaphoreTake(feed_sem, portMAX_DELAY);

        vTaskDelete(t1);
        vTaskDelete(t2);
        vTaskDelay(5);
    }
    vSemaphoreDelete(fetch_sem);
    vSemaphoreDelete(feed_sem);
}  

but beyond that I'm not sure how to help or even if I am helping.

martinberlin commented 3 years ago

That are the two “data sinks” that feed the Epaper with parallel data. But rotation by software should happen previously. The buffer sent should be already rotated. As a resume rotation should happen in:

Sadly the drawing pixel is not centralized on one single method otherwise it will be much easier to implement.

martinberlin commented 3 years ago

@Rainerlan I could not reproduce what you commented about the rotation

Doing: epd_set_rotation(3); I get the circle I'm drawing rotated 270° like expected (No kernel panics) Next target is to make write string and epddraw**_image to work also respecting the software rotation.