lexus2k / lcdgfx

Driver for LCD displays running on Arduino/Avr/ESP32/Linux (including Rasperry) platforms
MIT License
357 stars 51 forks source link

Esp8266 #20

Closed colesnicov closed 3 years ago

colesnicov commented 4 years ago

ESP8266-RTOS-SDK support?

lexus2k commented 4 years ago

No support for IDF style ESP8266, if you know macro to detect ESP8266 platform in ESP8266-RTOS-SDK, let me know. The macro below doesn't work.

#if defined(ESP8266)
...
#endf
colesnicov commented 4 years ago

I'm thinking, I'm thinking ... I can see here https://github.com/lexus2k/lcdgfx/blob/20bc2052f4416e34a73c68316ab13eda91315950/src/lcd_hal/io.h#L64, how you detect ESP32.

I use this trick to detect ESP32 or ESP8266 on my projects:

#include <sdkconfig.h>
#if defined( CONFIG_IDF_TARGET_ESP32 )
// stuffs and includes for ESP32
#elif defined( CONFIG_IDF_TARGET_ESP8266 )
// stuffs and includes for ESP8266
#endif

Let me show you possible solutions:

#elif defined(__XTENSA__) && !defined(ARDUINO)
  #define ESP_TARGET // may not be needed
  #include <sdkconfig.h>

  #if defined( CONFIG_IDF_TARGET_ESP32 )
    // stuffs and includes for ESP32

    #include "esp/io.h"
    #ifdef __cplusplus
    #include "esp/esp32_i2c.h"
    #include "esp/esp32_spi.h"
  #endif

  #elif defined( CONFIG_IDF_TARGET_ESP8266 )
      // stuffs and includes for ESP8266

    #include "driver/gpio.h"
    #include "driver/i2c.h"
    #include "driver/spi.h"
  #endif

#elif  

Yes, maybe it's a little crooked but, functional.. :)

lexus2k commented 4 years ago

I made initial commit with ESP8266 support, but I didn't test it. If you can check, it would be nice.

colesnicov commented 4 years ago

Hello. I tried. It doesn't work. I don't have SPI OLED, I tried I2C. In the lcd_hal / esp / esp8266_spi.cpp file on line 167, the compiler reports an error: The second argument must be passed as a reference. I2C also doesn't work. Code from the nanoEngine / snowflakes example. Lots of red bugs. I don't have time for it now, then maybe I'll look at it later, or I'll wait until it's done :)

colesnicov commented 4 years ago

But just a short listing:

I (462) reset_reason: RTC reset 4 wakeup 0 store 4, reason is 7
I (465) gpio: GPIO[2]| InputEn: 0| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0 
I (479) gpio: GPIO[5]| InputEn: 0| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0 
Guru Meditation Error: Core  0 panic'ed (StoreProhibited). Exception was unhandled.
Core 0 register dump:
PC      : 0x4000df64  PS      : 0x00000030  A0      : 0x4021fefc  A1      : 0x3ffed450  
0x4021fefc: i2c_param_config at /home/denis/esp/ESP8266_RTOS_SDK/components/esp8266/driver/i2c.c:472

A2      : 0x00000000  A3      : 0x3ffed470  A4      : 0x00000018  A5      : 0x00000000  
A6      : 0x00000000  A7      : 0x00000002  A8      : 0x3ffed480  A9      : 0x00000090  
A10     : 0x4022f6ea  A11     : 0x00000020  A12     : 0x3ffed470  A13     : 0x3ffe9638  
A14     : 0x00000000  A15     : 0x00000000  SAR     : 0x0000001b  EXCCAUSE: 0x0000001d  

Backtrace: 0x4000df64:0x3ffed450 0x4021fefc:0x3ffed450 0x4021e280:0x3ffed470 0x4021e7fd:0x3ffed4a0 0x4021478e:0x3ffed4b0 0x402148ac:0x3ffed4d0 
0x4021fefc: i2c_param_config at /home/denis/esp/ESP8266_RTOS_SDK/components/esp8266/driver/i2c.c:472

0x4021e280: EspI2c::begin() at /home/denis/Projects/esp8266/ssd1603/components/lcdgfx-1.0.0_dev/src/lcd_hal/esp/esp8266_i2c.cpp:63

0x4021e7fd: DisplaySSD1306_128x64_I2C::begin() at /home/denis/Projects/esp8266/ssd1603/components/lcdgfx-1.0.0_dev/src/v2/lcd/ssd1306/lcd_ssd1306.cpp:71

0x4021478e: setup() at /home/denis/Projects/esp8266/ssd1603/main/user_main.cpp:252

0x402148ac: main_task(void*) at /home/denis/Projects/esp8266/ssd1603/main/user_main.cpp:316 (discriminator 1)
lexus2k commented 4 years ago

Thank you for the logs. I don't have esp8266 by hand right now. Axctually, I didn't find the root cause for the crash, because call to i2c_param_config looks good

    i2c_config_t conf{};
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = static_cast<gpio_num_t>(m_sda);
    conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
    conf.scl_io_num = static_cast<gpio_num_t>(m_scl);
    conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
    //    conf.master.clk_speed = m_frequency;
    i2c_param_config( static_cast<i2c_port_t>(m_busId), &conf );
esp_err_t i2c_param_config(i2c_port_t i2c_num, const i2c_config_t *i2c_conf)
{
    I2C_CHECK((i2c_num >= 0) && (i2c_num < I2C_NUM_MAX), I2C_NUM_ERROR_STR, ESP_ERR_INVALID_ARG);
    I2C_CHECK(i2c_conf != NULL, I2C_ADDR_ERROR_STR, ESP_ERR_INVALID_ARG);
    I2C_CHECK(i2c_conf->mode < I2C_MODE_MAX, I2C_MODE_ERR_STR, ESP_ERR_INVALID_ARG);                                                                                                        
    esp_err_t ret = i2c_set_pin(i2c_num, i2c_conf->sda_io_num, i2c_conf->scl_io_num,
                                i2c_conf->sda_pullup_en, i2c_conf->scl_pullup_en, i2c_conf->mode);
...

I took i2c initialization for ESP8266 from IDF examples. So, it looks like the busId could be the only wrong arg value, which was passed to display object constructor. I can fix that by forcing busId to be 0 for ESP8266 (since it has only one i2c hardware module).

colesnicov commented 4 years ago

I have a Wemos D1, I can test it, but now I don't have much time for it, work around the barracks .. Maybe on Sunday I could test it better. It depends on whether the error is in the configuration or in the parameter.

lexus2k commented 4 years ago

It seems that both i2c and spi now work on ESP8266 RTOS SDK. (v1.0.0_dev branch)

colesnicov commented 4 years ago

I'm sorry, but I don't have time now. As soon as I get to it, I'll test it.

colesnicov commented 4 years ago

as I look at one of the commit, it seems that the solution was to move the I2C configuration to the line with the installation of the I2C driver. It immediately occurred to me at the time that the driver was not installed, but in most cases the SDK would tell you that the driver was not installed. Do you know what the error was?

lexus2k commented 4 years ago

Yeah, that looks strange for me too. But that is what they do in their example:

static esp_err_t i2c_example_master_init()
{
    int i2c_master_port = I2C_EXAMPLE_MASTER_NUM;
    i2c_config_t conf;
    conf.mode = I2C_MODE_MASTER;
    conf.sda_io_num = I2C_EXAMPLE_MASTER_SDA_IO;
    conf.sda_pullup_en = 1;
    conf.scl_io_num = I2C_EXAMPLE_MASTER_SCL_IO;
    conf.scl_pullup_en = 1;
    conf.clk_stretch_tick = 300; // 300 ticks, Clock stretch is about 210us, you can make changes according to the actual situation.
    ESP_ERROR_CHECK(i2c_driver_install(i2c_master_port, conf.mode));
    ESP_ERROR_CHECK(i2c_param_config(i2c_master_port, &conf));
    return ESP_OK;
}
colesnicov commented 4 years ago

I think the problem was that you first called i2c_param_config(...) before calling the i2c_driver_install(...) function.

colesnicov commented 3 years ago

It's so complicated! where can I do to set I2C pins?

lexus2k commented 3 years ago

@colesnicov I reopened the issue to continue discussion.

It's so complicated! where can I do to set I2C pins?

Not really. Constructor accepts the following args: DisplaySSD1306_128x64_I2C( int8_t rstPin, const SPlatformI2cConfig &config = { -1, 0x3C, -1, -1, 0 } )

So you may specify different pins: { -1, 0x3C, SCL, SDA, 0}

DisplaySSD1306_128x64_I2C display( -1, { -1, 0x3C, SCL, SDA, 0 } );
colesnicov commented 3 years ago

Good day. So, after a while, I got to it again. I use the 'MASTER' branch. I unzipped lcdgfx to the components folder. I get a lot of bugs, again.. :

denis@denis-pc:~/Projects/esp8266/test_oled$ make
Toolchain path: /home/denis/esp/xtensa-lx106-elf/bin/xtensa-lx106-elf-gcc
Toolchain version: crosstool-ng-1.22.0-100-ge567ec7
Compiler version: 5.2.0
Python requirements from /home/denis/esp/ESP8266_RTOS_SDK/requirements.txt are satisfied.
Project is not inside a git repository, or git repository has no commits
will not use 'git describe' to determine PROJECT_VER.
App "test_oled" version: 1
CXX build/lcdgfx/src/lcd_hal/esp/esp8266_spi.o
/home/denis/Projects/esp8266/test_oled/components/lcdgfx/src/lcd_hal/esp/esp8266_spi.cpp: In function 'void spi_event_callback(int, void*)':
/home/denis/Projects/esp8266/test_oled/components/lcdgfx/src/lcd_hal/esp/esp8266_spi.cpp:59:13: error: 'start_bit' was not declared in this scope
             start_bit = 1;
             ^
/home/denis/Projects/esp8266/test_oled/components/lcdgfx/src/lcd_hal/esp/esp8266_spi.cpp:64:14: error: 'start_bit' was not declared in this scope
              start_bit = 0;
              ^
/home/denis/Projects/esp8266/test_oled/components/lcdgfx/src/lcd_hal/esp/esp8266_spi.cpp: In member function 'void EspSpi::forceSpiTransfer()':
/home/denis/Projects/esp8266/test_oled/components/lcdgfx/src/lcd_hal/esp/esp8266_spi.cpp:162:30: error: cannot convert 'spi_trans_t' to 'spi_trans_t*' for argument '2' to 'esp_err_t spi_trans(spi_host_t, spi_trans_t*)'
         spi_trans( m_spi , t );
                              ^
/home/denis/Projects/esp8266/test_oled/components/lcdgfx/src/lcd_hal/esp/esp8266_spi.cpp:167:13: error: 'start_bit' was not declared in this scope
     while ( start_bit > 0 ) { lcd_delay(0); };
             ^
At global scope:
cc1plus: warning: unrecognized command line option '-Wno-frame-address'
/home/denis/esp/ESP8266_RTOS_SDK/make/component_wrapper.mk:291: recipe for target 'src/lcd_hal/esp/esp8266_spi.o' failed
make[1]: *** [src/lcd_hal/esp/esp8266_spi.o] Error 1
/home/denis/esp/ESP8266_RTOS_SDK/make/project.mk:571: recipe for target 'component-lcdgfx-build' failed
make: *** [component-lcdgfx-build] Error 2
lexus2k commented 3 years ago

Fixed on dev_branch. Please check.

colesnicov commented 3 years ago

Hello. So, I switched to the 'origin / v1.0.0_dev' branch. This is what my test code looks like:

#include <esp_err.h>
#include <esp_event.h>
#include <esp_netif.h>
#include <esp_system.h>
#include <nvs_flash.h>
#include <spi_flash.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "lcdgfx.h"

#define SCL_PIN         GPIO_NUM_2
#define SDA_PIN         GPIO_NUM_4

DisplaySSD1306_128x64_I2C display(-1, { -1, 0x3C, SCL_PIN, SDA_PIN, 0 });

/*
 * Define snowflake images directly in flash memory.
 * This reduces SRAM consumption.
 * The image is defined from bottom to top (bits), from left to right (bytes).
 */
const PROGMEM uint8_t snowFlakeImage[8][8] = {
        { 0B00111000, 0B01010100, 0B10010010, 0B11111110, 0B10010010,
                0B01010100, 0B00111000, 0B00000000 }, { 0B00010000, 0B01010100,
                0B00111000, 0B11101110, 0B00111000, 0B01010100, 0B00010000,
                0B00000000 }, { 0B00111000, 0B00010000, 0B10111010, 0B11101110,
                0B10111010, 0B00010000, 0B00111000, 0B00000000 }, { 0B00011000,
                0B01011010, 0B00100100, 0B11011011, 0B11011011, 0B00100100,
                0B01011010, 0B00011000 }, { 0B00010000, 0B00111000, 0B01010100,
                0B11101110, 0B01010100, 0B00111000, 0B00010000, 0B00000000 }, {
                0B10000010, 0B00101000, 0B01101100, 0B00010000, 0B01101100,
                0B00101000, 0B10000010, 0B00000000 }, { 0B01000100, 0B10101010,
                0B01101100, 0B00010000, 0B01101100, 0B10101010, 0B01000100,
                0B00000000 }, { 0B00101000, 0B01010100, 0B10111010, 0B01101100,
                0B10111010, 0B01010100, 0B00101000, 0B00000000 }, };

typedef NanoEngine1<DisplaySSD1306_128x64_I2C> NanoEngineDemo;

NanoEngineDemo engine(display);

class SnowFlake: public NanoFixedSprite<NanoEngineDemo::TilerT>
{
public:
    SnowFlake() :
            NanoFixedSprite<NanoEngineDemo::TilerT>( { 0, 0 }, { 8, 8 },
                    nullptr)
    {
    }

    bool isAlive()
    {
        return hasTiler();
    }

    void generate()
    {
        setBitmap(&snowFlakeImage[lcd_random(8)][0]);
        /* Set initial position in scaled coordinates */
        /* We do not use getTiler().getDisplay() here, because if snowflake is not placed to
         engine, it has no tiler */
        scaled_position = { lcd_random(display.width() * 8), -8 * 8 };
        /* Use some random speed */
        speed = { lcd_random(-16, 16), lcd_random(4, 12) };
        /* After countdown timer ticks to 0, change X direction */
        timer = lcd_random(24, 48);
        moveTo(scaled_position / 8);
    }

    void update() override
    {
        scaled_position += speed;
        timer--;
        if (0 == timer)
        {
            /* Change movement direction */
            speed.x = lcd_random(-16, 16);
            timer = lcd_random(24, 48);
        }
        moveTo(scaled_position / 8);
        if (y() >= static_cast<lcdint_t>(getTiler().getDisplay().height()))
        {
            getTiler().remove(*this);
        }
    }

private:
    NanoPoint scaled_position;
    NanoPoint speed;
    uint8_t timer;
};

static const uint8_t maxCount = 12;

/* These are our snow flakes */
SnowFlake snowFlakes[maxCount];

void setup()
{
    display.begin();

//    display.128x64_i2c_init();
//    display.96x64_spi_init(3,4,5);
//    ssd1351_128x128_spi_init(3,4,5);
//    il9163_128x128_spi_init(3,4,5);

    engine.setFrameRate(30);
    engine.begin();

    engine.getCanvas().setMode(CANVAS_MODE_TRANSPARENT);
    engine.refresh();
}

void addSnowFlake()
{
    for (uint8_t i = 0; i < maxCount; i++)
    {
        if (!snowFlakes[i].isAlive())
        {
            snowFlakes[i].generate();
            engine.insert(snowFlakes[i]);
            break;
        }
    }
}

static uint8_t globalTimer = 3;

void loop()
{
    if (!engine.nextFrame())
        return;
    if (0 == (--globalTimer))
    {
        /* Try to add new snowflake every ~ 90ms */
        globalTimer = 3;
        addSnowFlake();
    }
    engine.update();
    engine.display();
}

extern "C" void app_main()
{
    ESP_ERROR_CHECK(nvs_flash_init());
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    /* Print chip information */
    esp_chip_info_t chip_info;
    esp_chip_info(&chip_info);
    printf("This is ESP8266 chip with %d CPU cores, WiFi, ", chip_info.cores);

    printf("silicon revision %d, ", chip_info.revision);

    printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
            (chip_info.features & CHIP_FEATURE_EMB_FLASH) ?
                    "embedded" : "external");

    setup();
    while (1)
    {
        loop();
    }
}

I'm getting this error:

denis@denis-pc:~/Projects/esp8266/test_oled$ make 
Toolchain path: /home/denis/esp/xtensa-lx106-elf/bin/xtensa-lx106-elf-gcc
Toolchain version: crosstool-ng-1.22.0-100-ge567ec7
Compiler version: 5.2.0
Python requirements from /home/denis/esp/ESP8266_RTOS_SDK/requirements.txt are satisfied.
Project is not inside a git repository, or git repository has no commits
will not use 'git describe' to determine PROJECT_VER.
App "test_oled" version: 1
CXX build/lcdgfx/src/lcd_hal/esp/esp8266_spi.o
/home/denis/Projects/esp8266/test_oled/components/lcdgfx/src/lcd_hal/esp/esp8266_spi.cpp: In member function 'void EspSpi::forceSpiTransfer()':
/home/denis/Projects/esp8266/test_oled/components/lcdgfx/src/lcd_hal/esp/esp8266_spi.cpp:164:30: error: cannot convert 'spi_trans_t' to 'spi_trans_t*' for argument '2' to 'esp_err_t spi_trans(spi_host_t, spi_trans_t*)'
         spi_trans( m_spi , t );
                              ^
At global scope:
cc1plus: warning: unrecognized command line option '-Wno-frame-address'
/home/denis/esp/ESP8266_RTOS_SDK/make/component_wrapper.mk:291: recipe for target 'src/lcd_hal/esp/esp8266_spi.o' failed
make[1]: *** [src/lcd_hal/esp/esp8266_spi.o] Error 1
/home/denis/esp/ESP8266_RTOS_SDK/make/project.mk:571: recipe for target 'component-lcdgfx-build' failed
make: *** [component-lcdgfx-build] Error 2