Jump to content

crteensy

Members
  • Posts

    111
  • Joined

  • Last visited

Posts posted by crteensy

  1. I see. Thanks for your effort! With that explanation I might have come up with a suitable solution as well, but if you want to work on it that's great.

    Even with the ILI9341 I would have probably made the same mistake. There was no sign of the static-inline-ness in the board header being that important, so I would have pushed as much logic into the cpp file as I have now. Also I'm not aiming for speed now, just for a working implementation. The one pixel function looked more attractive than three for streaming...

  2. Of course you need see code - here are my current driver files.

    gdisp_lld_config.h:

    #ifndef GDISP_LLD_CONFIG_H
    #define GDISP_LLD_CONFIG_H

    #if GFX_USE_GDISP

    /*===========================================================================*/
    /* Driver hardware support. */
    /*===========================================================================*/

    #define GDISP_HARDWARE_DRAWPIXEL TRUE
    #define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565

    #endif /* GFX_USE_GDISP */

    #endif // GDISP_LLD_CONFIG_H

    gdisp_lld_ssd1351.c: (see gdisp_lld_draw_pixel(), please)

    #include 

    #if GFX_USE_GDISP

    #define GDISP_DRIVER_VMT GDISPVMT_SSD1351
    #include "gdisp_lld_config.h"
    #include "src/gdisp/gdisp_driver.h"

    #include "board_ssd1351.h"

    /*===========================================================================*/
    /* Driver local definitions. */
    /*===========================================================================*/

    #ifndef GDISP_SCREEN_HEIGHT
    #define GDISP_SCREEN_HEIGHT 128
    #endif
    #ifndef GDISP_SCREEN_WIDTH
    #define GDISP_SCREEN_WIDTH 128
    #endif
    #ifndef GDISP_INITIAL_CONTRAST
    #define GDISP_INITIAL_CONTRAST 100
    #endif
    #ifndef GDISP_INITIAL_BACKLIGHT
    #define GDISP_INITIAL_BACKLIGHT 100
    #endif

    #define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER<<0)

    /*===========================================================================*/
    /* Driver local functions. */
    /*===========================================================================*/

    // none

    /*===========================================================================*/
    /* Driver exported functions. */
    /*===========================================================================*/

    LLDSPEC bool_t gdisp_lld_init(GDisplay *g)
    {
    init_board(g);
    return TRUE;
    }

    #if GDISP_HARDWARE_DRAWPIXEL
    LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g)
    {
    board_drawPixel(g, g->p.x, g->p.y, g->p.color); <- // NOT called, apparently
    }
    #endif

    #endif // GFX_USE_GDISP

    board_ssd1351.h: declares my board_drawPixel() function

    #ifndef BOARD_SSD1351_H
    #define BOARD_SSD1351_H

    // pin numbers for teensyduino code
    #define SSD1351_DC 14
    #define SSD1351_R 15
    #define SSD1351_CS 16

    #ifdef __cplusplus
    extern "C" {
    #endif // __cplusplus

    void init_board(GDisplay *g);

    void board_drawPixel(GDisplay* g, coord_t x, coord_t y, color_t c);

    void post_init_board(GDisplay *g);

    void setpin_reset(GDisplay *g, bool_t state);

    void acquire_bus(GDisplay *g);

    void release_bus(GDisplay *g);

    void write_cmd(GDisplay *g, uint8_t cmd);

    void write_data(GDisplay *g, uint8_t data);
    void write_datap(GDisplay *g, const uint8_t* data, uint16_t length);

    #ifdef __cplusplus
    }
    #endif // __cplusplus

    #endif // BOARD_SSD1351_H

    and the board_ssd1351.cpp: implements board_drawPixel(), which draws on the display I connected to my controller. I have verified that the function works; I can draw pixels when I call it in my main().

    #include 
    #include

    #include
    #include "board_ssd1351.h"

    static SPISettings settings(12000000, MSBFIRST, SPI_MODE0);

    void select()
    {
    digitalWriteFast(SSD1351_CS, 0);
    }

    void deselect()
    {
    digitalWriteFast(SSD1351_CS, 1);
    }

    void command()
    {
    digitalWriteFast(SSD1351_DC, 0);
    }

    void data()
    {
    digitalWriteFast(SSD1351_DC, 1);
    }

    void write_data(GDisplay *g, uint8_t data); // see below

    void home(GDisplay *g)
    {
    acquire_bus(g);
    write_cmd(g, 0x15); // set column address
    write_data(g, 0x00); // start
    write_data(g, 0x7F); // end

    write_cmd(g, 0x75); // set row address
    write_data(g, 0x00); // start
    write_data(g, 0x7F); // end

    write_cmd(g, 0x5C); // write to RAM
    release_bus(g);
    }

    void init_board(GDisplay *g)
    {
    pinMode(SSD1351_R, OUTPUT);
    setpin_reset(g, TRUE);
    pinMode(SSD1351_CS, OUTPUT);
    deselect();
    pinMode(SSD1351_DC, OUTPUT);
    delay(50);
    setpin_reset(g, FALSE);
    delay(50);

    acquire_bus(g);
    write_cmd(g, 0xFD); // set command lock
    write_data(g, 0x12); // unlock OLED driver IC

    write_cmd(g, 0xFD); // set command lock
    write_data(g, 0xB1); // make commands A1, B1, B3, BB, BE, C1 accesible in unlocked state

    write_cmd(g, 0xAE); // sleep mode ON (display off)

    write_cmd(g, 0xB3); // Front clock divider / osc freq
    write_data(g, 0xF1); // Osc = 0xF; div = 2

    write_cmd(g, 0xCA); // set MUX ratio
    write_data(g, 127);

    write_cmd(g, 0xA0); // Set re-map / color depth
    write_data(g, 0b01110100);
    // [0] : address increment (0: horizontal, 1: vertical, reset 0)
    // [1] : column remap (0: 0..127, 1: 127..0, reset 0)
    // [2] : color remap (0: A->B->C, 1: C->B->A, reset 0)
    // [3] : reserved
    // [4] : column scan direction (0: top->down, 1: bottom->up, reset 0)
    // [5] : odd/even split COM (0: disable, 1: enable, reset 1)
    // [6..7] : color depth (00,01: 65k, 10: 262k, 11: 262k format 2)

    write_cmd(g, 0x15); // Set Column address
    write_data(g, 0x00); // start
    write_data(g, 0x7F); // end

    write_cmd(g, 0x75); // set row address
    write_data(g, 0x00); // start
    write_data(g, 0x7F); // end

    write_cmd(g, 0xA1); // set display start line
    write_data(g, 0x00); // 0

    write_cmd(g, 0xA2); // set display offset
    write_data(g, 0x00); // 0

    write_cmd(g, 0xB5); // set GPIO
    write_data(g, 0x00); // both HiZ, input disabled

    write_cmd(g, 0xAB); // function select
    write_data(g, 0x01); // enable internal VDD regulator

    write_cmd(g, 0xB1); // set reset / pre-charge period
    write_data(g, 0x32); // phase 2: 3 DCLKs, phase 1: 5 DCLKs

    write_cmd(g, 0xBE); // set VComH voltage
    write_data(g, 0x05); // 0.82*Vcc

    write_cmd(g, 0xBB); // set pre-charge voltage
    write_data(g, 0x17); // 0.6*Vcc

    write_cmd(g, 0xA6); // set display mode: reset to normal display

    write_cmd(g, 0xC1); // set contrast current for A,B,C
    write_data(g, 0xC8);
    write_data(g, 0x80);
    write_data(g, 0xC8);

    write_cmd(g, 0xC7); // master contrast current control
    write_data(g, 0x0F); // no change

    write_cmd(g, 0xB4); // set segment low voltage
    write_data(g, 0xA0); // external VSL
    write_data(g, 0xB5); // hard value
    write_data(g, 0x55); // hard value

    write_cmd(g, 0xB6); // set second pre-charge period
    write_data(g, 0x01); // 1 DCLKs

    write_cmd(g, 0xAF); // sleep mode OFF (display on)
    // write_cmd(g, 0x5C); // write to RAM
    release_bus(g);

    delay(50);

    home(g);

    Serial.println("board init");
    }

    void post_init_board(GDisplay *g)
    {
    (void) g;
    }

    void setpin_reset(GDisplay *g, bool_t state)
    {
    (void) g;
    (void) state;
    if(state)
    {
    digitalWriteFast(SSD1351_R, 0);
    }
    else
    {
    digitalWriteFast(SSD1351_R, 1);
    }
    }

    void acquire_bus(GDisplay *g)
    {
    SPI.beginTransaction(settings);
    select();
    (void) g;
    }

    void release_bus(GDisplay *g)
    {
    deselect();
    SPI.endTransaction();
    (void) g;
    }

    void write_cmd(GDisplay *g, uint8_t cmd)
    {
    (void) g;
    (void) cmd;
    command();
    SPI.transfer(cmd);
    data();
    }

    void write_data(GDisplay *g, uint8_t data)
    {
    SPI.transfer(data);
    }

    void write_data(GDisplay *g, const uint8_t* data, uint16_t length)
    {
    (void) g;
    (void) data;
    (void) length;
    for (uint8_t i = 0; i < length; i++)
    while(length)
    {
    SPI.transfer(data[i]);
    }
    }

    void write_datap(GDisplay *g, const uint8_t* data, uint16_t length)
    {
    write_data(g, data, length);
    }

    void board_drawPixel(GDisplay* g, coord_t x, coord_t y, color_t c)
    {
    Serial.printf("pixel @ %d %d : %4x\n", x, y, c);

    acquire_bus(g);

    write_cmd(g, 0x15);
    write_data(g, x);
    write_data(g, 127);

    write_cmd(g, 0x75);
    write_data(g, y);
    write_data(g, 127);

    write_cmd(g, 0x5C);
    write_data(g, c >> 8);
    write_data(g, c & 0xFF);

    release_bus(g);
    }

    main.cpp: this is where I draw "manually" in loop()

    #include 
    #include
    #include

    #include

    void setup()
    {
    // pinMode(LED_BUILTIN, OUTPUT);
    while(!Serial.available());
    while(Serial.available())
    {
    Serial.read();
    }
    Serial.println("Start");
    SPI.begin();

    coord_t width, height;
    coord_t i, j;

    // Initialize and clear the display
    gfxInit();

    // Get the screen size
    width = gdispGetWidth();
    height = gdispGetHeight();

    // Code Here
    gdispDrawBox(10, 10, width/2, height/2, Yellow);
    gdispFillArea(width/2, height/2, width/2-10, height/2-10, Blue);
    gdispDrawLine(5, 30, width-50, height-40, Red);

    for(i = 5, j = 0; i < width && j < height; i += 7, j += i/20)
    gdispDrawPixel(i, j, White);

    // while(TRUE) {
    // gfxSleepMilliseconds(500);
    // }
    }

    void loop()
    {
    static uint8_t x = 0;
    static uint8_t y = 0;
    // board_drawPixel(nullptr, x, y, Red); // <- WORKS
    gdispDrawPixel(x, y, Red); // <- nothing happens
    x++;
    if (x >= 0x80)
    {
    x = 0;
    y++;
    if (y >= 0x80)
    {
    y = 0;
    }
    }
    }

  3. OK, at least I have a compiling set of files now, at least for the Teensy LC.

    When I try to compile for Teensy 3.1, something in my build setup is hiding _ebss, which is defined in the linker script for both platforms (LC and 3.1 have different linker scripts, but both scripts define _ebss). I'll also post this problem in PJRC's forum where the teensyduino people are.

    Here are my files for a dummy driver that calls the C++ interface via the board header.

    ugfxconf.h:

    #ifndef _GFXCONF_H
    #define _GFXCONF_H

    #define GFX_USE_OS_RAW32 TRUE
    #define GFX_NO_OS_INIT TRUE
    #define GFX_USE_GDISP TRUE

    #endif /* _GFXCONF_H */

    os.c:

    #include 
    #include

    systemticks_t gfxSystemTicks(void)
    {
    return millis();
    }

    systemticks_t gfxMillisecondsToTicks(delaytime_t ms)
    {
    return ms;
    }

    gdisp_lld_config.h:

    #ifndef GDISP_LLD_CONFIG_H
    #define GDISP_LLD_CONFIG_H

    #if GFX_USE_GDISP

    /*===========================================================================*/
    /* Driver hardware support. */
    /*===========================================================================*/

    #define GDISP_HARDWARE_FLUSH TRUE // This controller requires flushing
    #define GDISP_HARDWARE_DRAWPIXEL TRUE
    #define GDISP_HARDWARE_PIXELREAD FALSE
    #define GDISP_HARDWARE_CONTROL FALSE
    #define GDISP_HARDWARE_FILLS FALSE

    #define GDISP_LLD_PIXELFORMAT GDISP_PIXELFORMAT_RGB565
    // This controller supports a special gdispControl() to inverse the display.
    // Pass a parameter of 1 for inverse and 0 for normal.
    #define GDISP_CONTROL_INVERSE (GDISP_CONTROL_LLD+0)

    #endif /* GFX_USE_GDISP */

    #endif // GDISP_LLD_CONFIG_H

    gdisp_lld_ssd1351.c: minimal, but should provide the required interface; the low-level magic will be in the board file as suggested

    #include 

    #if GFX_USE_GDISP

    #define GDISP_DRIVER_VMT GDISPVMT_SSD1351
    #include "gdisp_lld_config.h"
    #include "src/gdisp/gdisp_driver.h"

    #include "board_ssd1351.h"

    /*===========================================================================*/
    /* Driver local definitions. */
    /*===========================================================================*/

    #ifndef GDISP_SCREEN_HEIGHT
    #define GDISP_SCREEN_HEIGHT 128
    #endif
    #ifndef GDISP_SCREEN_WIDTH
    #define GDISP_SCREEN_WIDTH 128
    #endif
    #ifndef GDISP_INITIAL_CONTRAST
    #define GDISP_INITIAL_CONTRAST 100
    #endif
    #ifndef GDISP_INITIAL_BACKLIGHT
    #define GDISP_INITIAL_BACKLIGHT 100
    #endif

    #define GDISP_FLG_NEEDFLUSH (GDISP_FLG_DRIVER<<0)

    /*===========================================================================*/
    /* Driver local functions. */
    /*===========================================================================*/

    // Some common routines and macros
    #define RAM(g) ((uint8_t *)g->priv)
    #define write_cmd2(g, cmd1, cmd2) { write_cmd(g, cmd1); write_cmd(g, cmd2); }
    #define write_cmd3(g, cmd1, cmd2, cmd3) { write_cmd(g, cmd1); write_cmd(g, cmd2); write_cmd(g, cmd3); }

    // Some common routines and macros
    #define delay(us) gfxSleepMicroseconds(us)
    #define delayms(ms) gfxSleepMilliseconds(ms)

    #define xyaddr(x, y) (SSD1306_PAGE_OFFSET + (x) + ((y)>>3)*SSD1306_PAGE_WIDTH)
    #define xybit(y) (1<<((y)&7))


    /*===========================================================================*/
    /* Driver exported functions. */
    /*===========================================================================*/

    LLDSPEC bool_t gdisp_lld_init(GDisplay *g)
    {
    init_board(g);
    return TRUE;
    }

    #if GDISP_HARDWARE_DRAWPIXEL
    LLDSPEC void gdisp_lld_draw_pixel(GDisplay *g)
    {
    }
    #endif

    #if GDISP_HARDWARE_FLUSH
    LLDSPEC void gdisp_lld_flush(GDisplay *g)
    {
    }
    #endif

    #endif // GFX_USE_GDISP

    board_ssd1351.h: just declarations, most of them are probably not necessary

    #ifndef BOARD_SSD1351_H
    #define BOARD_SSD1351_H

    #ifdef __cplusplus
    extern "C" {
    #endif // __cplusplus

    void init_board(GDisplay *g);

    void post_init_board(GDisplay *g);

    void setpin_reset(GDisplay *g, bool_t state);

    void acquire_bus(GDisplay *g);

    void release_bus(GDisplay *g);

    void write_cmd(GDisplay *g, uint8_t cmd);

    void write_data(GDisplay *g, uint8_t* data, uint16_t length);

    #ifdef __cplusplus
    }
    #endif // __cplusplus

    #endif // BOARD_SSD1351_H

    board_ssd1351.cpp: currently just dummy implementations to see what happens

    #include 

    #include
    #include "board_ssd1351.h"

    void init_board(GDisplay *g)
    {
    (void) g;
    Serial.println("board init");
    }

    void post_init_board(GDisplay *g)
    {
    (void) g;
    }

    void setpin_reset(GDisplay *g, bool_t state)
    {
    (void) g;
    (void) state;
    }

    void acquire_bus(GDisplay *g)
    {
    (void) g;
    }

    void release_bus(GDisplay *g)
    {
    (void) g;
    }

    void write_cmd(GDisplay *g, uint8_t cmd)
    {
    (void) g;
    (void) cmd;
    }

    void write_data(GDisplay *g, uint8_t* data, uint16_t length)
    {
    (void) g;
    (void) data;
    (void) length;
    }

    That linker issue is surely a bit disturbing, but I can keep on writing useful code for the LC.

  4. Turns out the undefined reference was related to C/C++ mixing - nevermind.

    This is going to be the hardest part of my afternoon because I need teensyduino functions and classes, which are mainly written in C++. I can't see a way of keeping them apart completely, but I'll do my best to make a clean split. C++ does not by itself mean that memory usage will be higher, or that hidden things happen. Of course, if I try to use a bunch of std::vectors then I'll run into problems. But bad code can be written just as easily in C.

  5. Yes, starting with a similar driver (I picked the SSD1306) seems to be a good starting point. However, I'm having one problem during the linking stage (I solved some others, they were easier to fix):

    The linker complains

    disp.c:(.text._gdispInit+0x40): undefined reference to `GDISPVMT_OnlyOne'

    I have not added any define in gfxconf.h, so ugfx should default to an external declaration of

    extern const GDISPVMT const		GDISPVMT_OnlyOne[1];

    in _gdispInit. I can't find the place where it is actually defined.

  6. For starting you really just need the init() and the setPixel() routine.

    You mean gdisp_lld_init() and gdisp_lld_draw_pixel() in the point-and-block-model?

    When I want to mix with the Window model, can I just add functions like e.g. gdisp_lld_write_start(), gdisp_lld_write_color() and gdisp_lld_write_stop()? This is not 100% clear in the source (src/gdisp/gdisp_driver.h, lines 127..135):

    Either GDISP_HARDWARE_STREAM_WRITE or GDISP_HARDWARE_DRAWPIXEL must be provided by the driver

    Is that an exclusive or?

    Either way, if I'm understanding this correctly I have to define GDISP_HARDWARE_DRAWPIXEL and/or GDISP_HARDWARE_STREAM_WRITE in my gdisp_lld_config.h for ugfx to understand how to draw on my display. If that is the case then I think I'm slowly getting it...

    Some more questions:

    - What effect should GDISP_HARDWARE_FLUSH have on my display and when exactly is gdisp_lld_flush() called? Is the purpose of this function to push all pending pixel writes or other commands to the display before any further drawing is done?

    - How does ugfx know which driver to use? In the demos (ugfx/demos/modules/gdisp/basics/main.c or gfxconf.h) I see no sign of an actual display being used.

  7. I don't quite understand what you say about the defines in gdisp_lld_config.h. Take for example line 17 in ugfx/drivers/gdisp/PCD8544/gdisp_lld_config.h:

    #define GDISP_HARDWARE_FLUSH			TRUE		// This controller requires flushing

    By the comment this line seems to tell ugfx something about the controller. OTOH, you say

    If you write your own driver then you're free to do it as you like.

    but I'm certainly not free to do as I like when I want ugfx to understand my controller features. Or am I getting this totally wrong?

  8. Thank you, so for now I'll just try to write a driver that works without a framebuffer.

    How can I mix C++ into my ugfx display driver? Is there a commonly recommended, documented way of doing that? I've gotten ugfx to compile with teensyduino up to the point where I need to write the actual display driver. Now it gets tricky because it's common to call C functions in C++, but not the other way around.

  9. Hi,

    I'm new to ugfx and considered writing my own graphics library after trying u8lib and adafruit_gfx. Before I really do that I'd like to give it a try with ugfx. I already found the wiki and looked for buffers and paging. I'm not sure if I really need that, but the Teensy hardware I'd like to use doesn't have enough RAM for a whole frame. So my first question is:

    Is it possible to have a paged frame buffer (1/4th or 1/8th) with ugfx? If not, is the window display driver model a suitable workaround? (Would you recommend not to use a paged buffer?)

    I have applications that use only one color channel of an OLED display (dimmable red, for eyes adapted to darkness). My canvas can essentially be monochrome in such a case, and the mapping form monochrome to dimmed color is done by the display driver. Is that possible with ugfx? Are monochrome (or less-than-8-bit in general) colors packed in memory or does a pixel always occupy at least one byte?

    Regards

    Christoph

×
×
  • Create New...