lcdgfx icon indicating copy to clipboard operation
lcdgfx copied to clipboard

Rotate SH1107 to landscape

Open guhland opened this issue 2 years ago • 14 comments

I want to rotate the display 90 degrees.

https://github.com/lexus2k/lcdgfx/issues/48

This issue is about the same topic. It mentions that I could use canvas and write my own method to rotate the display. How would I go about doing that?

There has to be a way to do this.

guhland avatar Nov 18 '21 19:11 guhland

I have the same problem

Pedrohpcavalcante avatar Feb 20 '22 18:02 Pedrohpcavalcante

The 1-bit canvas has the associated buffer with it, where pixels are represented the same way, as described in display controllers datasheets.

For example, if canvas size is 128x64, then each row consists of 128 bytes and each byte row describes 8 rows of pixels on the display. Because each byte is 8 vertical pixels (1 bit per pixel). This is done for speed.

So, the address of each pixel can be described as:

buffer_index = x + (y / 8) * width;
bit_index = y & 0x07;

In your case, since you want to have vertical orientation you need have 1bitx64x128 canvas. Then you draw what you need in the canvas, and the rotate the content. The rotation must result in the different buffer 1bitx128x64. So, you need something like this:

new_width = height;
new_height = width;
for(x=0; x<64; x++)
    for(y=0; y<128; y++)
    {
        uint8_t pixel = (m_buffer[x + (y / 8) * width] >> (y & 0x07)) & 0x01; // width is 64 here
        new_buffer[y + (x / 8) * new_width] |= pixel << (x & 0x07); // width is 128 here
    }

Another way is to rewrite all display 1-bit functions - a bit time consuming development.

lexus2k avatar Feb 24 '22 01:02 lexus2k

Okay I sort of follow what is going on here. I am not 100 percent on it, but it looks like you are getting the pixel from the buffer and then writing it to a new location in a new buffer. Here is what I wrote for a rotate function for in canvas.cpp:

template <> void NanoCanvasOps<1>::rotate()
{
    lcdint_t new_width = height();
    lcdint_t new_height = width();
    uint8_t new_buffer[new_width * new_height * 1];
    for ( int x = 0; x < 64; x++ )
    {
        for ( int y = 0; y < 128; y++ )
        {
            uint8_t pixel = (m_buf[x + (y / 8) * width()] >> (y & 0x07)) & 0x01; // width is 64 here
            new_buffer[y + (x / 8) * new_width] |= pixel << (x & 0x07);          // width is 128 here
        }
    }
m_buf = new_buffer;
}

This does not work. What am I doing wrong? Let me know if you need more info or a picture...

guhland avatar Feb 24 '22 20:02 guhland

The code doesn't work because you assign a pointer to the locally allocated array: new_buffer is defined inside the function.

lexus2k avatar Mar 04 '22 01:03 lexus2k

I added enhancement label. Once I have free time, this feature will be implemented.

lexus2k avatar Mar 05 '22 05:03 lexus2k

Hi @guhland

Good news that I implemented rotate method for 1-bit displays.

NanoCanvas<64,32,1> canvas;
NanoCanvas<32,64,1> rotatedCanvas;

void setup()
{
    /* Initialize and clear display */
    display.begin();
    display.clear();
    canvas.setMode( CANVAS_MODE_TRANSPARENT );
    canvas.clear();
    canvas.drawBitmap1( 5, 8, 8, 8, heartImage );
    canvas.drawRect(0,0,63,31);
    canvas.rotateCW(rotatedCanvas);
}


void loop()
{
    lcd_delay(40);

    /* Now, draw original canvas on the display */
    display.drawCanvas( 0, 0, canvas );
    /* Now, draw rotated canvas on the display */
    display.drawCanvas( 80, 0, rotatedCanvas );
}

The band news is that such rotation requires 2X SRAM memory. But as long as you're using powerful microcontrollers that doesn't matter.

lexus2k avatar Mar 09 '22 04:03 lexus2k

Thanks a bunch for your support. I had something working similarly with the pseudocode you provided before. This is working better. However, I have a issue a ran into before where the only the rotated "left" half of the screen will print anything. I am using a 64x128 display. Let me know if you need more info.

guhland avatar Mar 15 '22 20:03 guhland

Hi

It would be nice to have full sketch example (as simple as possible), that doesn't work in your case. So I can run tests and figure out what's wrong.

lexus2k avatar Mar 15 '22 21:03 lexus2k

#include "lcdgfx.h"

NanoCanvas<64,128,1> canvas;
NanoCanvas<128,64,1> rotatedCanvas;

int main(){

    /* Initialize and clear display */
    DisplaySH1107_64x128_I2C display(-1,{-1, 0x3C, -1, -1 , 0});
    display.begin();
    display.clear();
    canvas.setMode( CANVAS_MODE_TRANSPARENT );
    canvas.clear();
    canvas.setFixedFont(ssd1306xled_font5x7);
    canvas.printFixed(5,5,"test1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
    canvas.rotateCW(rotatedCanvas);
    lcd_delay(40);

    /* Now, draw original canvas on the display */
    //display.drawCanvas( 0, 0, canvas );
    /* Now, draw rotated canvas on the display */
    display.drawCanvas( 63, 0, rotatedCanvas );
       

    display.end();
    return 0;

}

The added "!" are just to make sure it would normally fit the entire screen.

guhland avatar Mar 17 '22 13:03 guhland

Hi,

I slightly modified your example to run in Arduino IDE. Please, find my comments below

#include "lcdgfx.h"

DisplaySH1107_64x128_I2C display(-1,{-1, 0x3C, -1, -1 , 0});

NanoCanvas<128,64,1> canvas; // <<< Change (64,128) to (128,64) as you would like to have it in landscape mode
NanoCanvas<64,128,1> rotatedCanvas; // <<< Change (128,64) to (64,128) as you need to rotate canvas before displaying

void setup()
{
    /* Initialize and clear display */
    display.begin();
    display.clear();
    canvas.setMode( CANVAS_MODE_TRANSPARENT | CANVAS_TEXT_WRAP_LOCAL ); // <<< Set text wrap local mode
    canvas.clear();
    canvas.setFixedFont(ssd1306xled_font5x7);
    canvas.printFixed(5,5,"test1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
    canvas.rotateCW(rotatedCanvas);
}

void loop()
{
    lcd_delay(40);
    /* Now, draw original canvas on the display */
    //display.drawCanvas( 0, 0, canvas );
    /* Now, draw rotated canvas on the display */
    display.drawCanvas( 0, 0, rotatedCanvas ); // <<< change (63,0) to (0,0) since you need to draw canvas on the entire display without any shift
}

lexus2k avatar Mar 17 '22 21:03 lexus2k

So following what you wrote here. I am still only able to print to half of the screen. Only this time being the top half instead of the right. However, if I remove the offset like you suggested, Nothing prints. Right now I am at a offset of 95.... Thoughts?

guhland avatar Mar 18 '22 14:03 guhland

This is how it looks like if to run the example provided by you: image

This is how the display looks like, if to apply my recommendations: image

If the issue relates to some specific hardware you have, I need much more information on the setup, including the display hardware part number, datasheet for your display, CPU/MCU hardware part number (maybe board description), etc.

lexus2k avatar Mar 19 '22 00:03 lexus2k

I am using a raspberry pi 4 4GB right now. I have plans to use the display with other things. Testing with the pi right now. I am able to get your second image. However, I cannot print to the bottom half. oledissue

guhland avatar Mar 21 '22 12:03 guhland

изображение

If the issue relates to some specific hardware you have, I need much more information on the setup, including the display hardware part number, datasheet for your display, CPU/MCU hardware part number (maybe board description), etc.

Without details on your setup I can do nothing. I know that you have Raspberry Pi, and since it's 64-bit, the data types, used by the library is not the issue in your case.

lexus2k avatar Mar 22 '22 22:03 lexus2k