B4R Question ESP32-2424S012

daveinhull

Active Member
Licensed User
Longtime User
Hi,

I've just got an ESP-2424D012 which is an ESP32 with integrated 240x240 round display, see attached specification.
The sample code that comes with it is in C and I can work with it and successfully upload to the device, but would very much like to work in B4R.
It appears to use a libary called LGFX. In Ardunio it uses ESP32C2 Dev Module, but I can't find that in B4R, althogh there are similar.

Can anyone start me off in the right direction to use B4X with this device.

I did take a look at a coding exmaple for a similar ESP32 with integrated display by Peter Simpson, but alothough it connects to my network, nothing happens so I guess I'm using the wrong libary or board (don't know how to reference the link)
https://www.b4x.com/android/forum/t...led-display-connected-to-wifi-inline-c.81149/

B4R Code Snippet ESP32 with built in OLED display connected to WiFi - Inline C​

Many thanks
Dave
 

peacemaker

Expert
Licensed User
Longtime User
  1. "ESP32-2424D012" looks like more correct than yours ESP-2424D012.
  2. Search the circuit diagram of the device and understand how the peripherals are connected, the pinout. https://github.com/arendst/Tasmota/discussions/19487
  3. Identify the peripherals, like the display https://www.buydisplay.com/download/ic/GC9A01A.pdf
  4. Select "ESP32S3 Dev module" among the B4X boards and try to make sketch in B4X using the pinout
  5. Use inline-C code from the examples for important parts, if impossible to make it on B4R language.
p.s. https://github.com/carlfriess/GC9A01_demo
 
Last edited:
Upvote 0

daveinhull

Active Member
Licensed User
Longtime User
Hi,


I've done some work on investigating what to do, but I'm rapidly coming to the extent of my knowledge, particularly with regard to libraries and inline code.

I've got the ESP32 pin-outs and the SPI bus rESP32 library so I can talk to the display. I've got information on the display (GC9A01A), but this is where I get stuck. I've got the C code for the device and it uses the LGFX library in Arduino, but from other searches on the internet it looks like it can also use the Adafruit_GC9A01A library which looks a little simpler and more well supported that the LGFX (might be wrong there).

I've see Erel's rAdafruitGFX displays library (although not best for this devices, but principles should be similar), but struggling to get everything linked together, i.e. the relationship be SPI bus library and the Adafruit GFX library, or how to actually control the display.

I guess what I'm going have to do is produce a wrapper for the Adafruit_GC9A01A library (but no idea how to start that) or use in-line C code (not sure how to do this).

If any one could give me some initial code to use the GC9A01A, maybe just to initialise it and set the screen to a colour then I can work from that and do more based on that code and the other examples I've got in C.

Also, I'd very much like to learn how to produce a wrapper/library, so could someone point me in the direction of any guides and/or maybe produce a simple GC9A01A library with say just one or 2 functions in it and I'll take it from there?

Hope someone can help
Thanks
Dave

[EDIT: referenced wrong library, should havebeen rAdafruit GFX)
 
Last edited:
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
Upvote 0

daveinhull

Active Member
Licensed User
Longtime User
Hi,

So, I've been going around and round in circles over the last few weeks and would really appreciate some further help.

I've downloaded loads of examples in both Arduino IDE and B4X, read many articles and tutorials, again in both environments, tried writing some wrappers for the LVGL library, even tried writing my own code to access the display, and also tried in-line C code - all getting me totally confused.

The thing is I can just go into the Arduino IDE and write what I want in C, but hate the language and would much prefer to stay in the B4R environment (old school Coral 66, ADA, Pascal, Modula 2 background, much cleaner code than all the symbols, marks and whatever’s )

I got some C code to work (in the Arduino IDE), which I then put in-line in B4R (not sure if I've done it correctly), but it just doesn't seem to compile.

Please, some help would be appreciated.

B4X:
#Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 600
#End Region
'Ctrl+Click to open the C code folder: ide://run?File=%WINDIR%\System32\explorer.exe&Args=%PROJECT%\Objects\Src

Sub Process_Globals
    Public Serial1 As Serial
    Private wifi As ESP8266WiFi
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")

End Sub


#if C
// Include the libraries
#define LGFX_USE_V1
#include "Arduino.h"
#include <lvgl.h>
#include "demos/lv_demos.h"
#include <LovyanGFX.hpp>
#include <Ticker.h>

#define off_pin 35
#define buf_size 120

class LGFX : public lgfx::LGFX_Device
{

  lgfx::Panel_GC9A01 _panel_instance;

  lgfx::Bus_SPI _bus_instance;

public:
  LGFX(void)
  {
    {
      // Configuring the SPI bus
      auto cfg = _bus_instance.config();
      cfg.spi_host = SPI2_HOST;          // Select the SPI to use ESP32-S2,C3 : SPI2_HOST or SPI3_HOST / ESP32 : VSPI_HOST or HSPI_HOST
      // *With the ESP-IDF version upgrade, the description of VSPI_HOST and HSPI_HOST will be deprecated, so if an error occurs, please use SPI2_HOST and SPI3_HOST instead.
      cfg.spi_mode = 0;                  // Set SPI communication mode (0 ~ 3)
      cfg.freq_write = 80000000;         // SPI clock during transmission (up to 80MHz, rounded to the value obtained by dividing 80MHz by an integer)
      cfg.freq_read = 20000000;          // SPI clock when receiving
      cfg.spi_3wire = true;              // Set true if receiving is done using MOSI pin
      cfg.use_lock = true;               //Set to true when using transaction lock
      cfg.dma_channel = SPI_DMA_CH_AUTO; // Set the DMA channel to use (0=DMA not used / 1=1ch / 2=ch / SPI_DMA_CH_AUTO=automatic setting)
      // * Due to the ESP-IDF version upgrade, SPI_DMA_CH_AUTO (automatic setting) is recommended for the DMA channel. Specifying 1ch or 2ch is not recommended.
      cfg.pin_sclk = 6;                  // Set SPI SCLK pin number
      cfg.pin_mosi = 7;                  // Set SPI CLK pin number
      cfg.pin_miso = -1;                 // Set SPI MISO pin number (-1 = disable)
      cfg.pin_dc = 2;                    // Set SPI D/C pin number (-1 = disable)

      _bus_instance.config(cfg);              // Reflect the settings on the bus.
      _panel_instance.setBus(&_bus_instance); // Set the bus on the panel.
    }

    {
      // Set display panel control.
      auto cfg = _panel_instance.config(); // Get the structure for display panel settings.
      cfg.pin_cs = 10;   // Pin number to which CS is connected (-1 = disable)
      cfg.pin_rst = -1;  // Pin number to which RST is connected (-1 = disable)
      cfg.pin_busy = -1; // Pin number to which BUSY is connected (-1 = disable)
      // * The following setting values are general initial values set for each panel and the pin number to which BUSY is connected (-1 = disable), so please comment out any unknown items and try again.
      cfg.memory_width = 240;   // Maximum width supported by driver IC
      cfg.memory_height = 240;  // Maximum height supported by driver IC
      cfg.panel_width = 240;    // Actual displayable width
      cfg.panel_height = 240;   // Actual display height
      cfg.offset_x = 0;         // Panel X direction offset amount
      cfg.offset_y = 0;         // Panel Y direction offset amount
      cfg.offset_rotation = 0;  // The offset of the value in the direction of rotation is 0~7 (4~7 is inverted)
      cfg.dummy_read_pixel = 8; // The number of dummy bits to read before reading the pixel
      cfg.dummy_read_bits = 1;  // The number of virtual read bits before reading data other than pixels
      cfg.readable = false;     // Set to true if data can be read
      cfg.invert = true;        // Set to true if the panel's light and dark are inverted
      cfg.rgb_order = false;    // Set to true if the red and blue colors of the panel are swapped
      cfg.dlen_16bit = false;   // Set to true for panels that send data length in 16-bit units
      cfg.bus_shared = false;   // Set to true if the bus is shared with the SD card (use drawJpgFile etc. to perform bus control)

      _panel_instance.config(cfg);
    }
    setPanel(&_panel_instance); //Set the panel to use.
  }
};

// Create an instance of the prepared class.
LGFX tft;

/*Change to your screen resolution*/
static const uint32_t screenWidth = 240;
static const uint32_t screenHeight = 240;

static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[2][screenWidth * buf_size];

/* Display flushing */
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
  if (tft.getStartCount() == 0)
  {
    tft.endWrite();
  }

  tft.pushImageDMA(area->x1, area->y1, area->x2 - area->x1 + 1, area->y2 - area->y1 + 1, (lgfx::swap565_t *)&color_p->full);

  lv_disp_flush_ready(disp); /* tell lvgl that flushing is done */
}

Ticker ticker;

void setup()
{

  Serial.begin(115200); /* prepare for possible serial debug */
  Serial.println("I am LVGL_Arduino");

  tft.init();
  tft.initDMA();
  tft.startWrite();
  tft.setColor(0, 0, 0);

  lv_init();

  lv_disp_draw_buf_init(&draw_buf, buf[0], buf[1], screenWidth * buf_size);

  /*Initialize the display*/
  static lv_disp_drv_t disp_drv;
  lv_disp_drv_init(&disp_drv);
  /*Change the following line to your display resolution*/
  disp_drv.hor_res = screenWidth;
  disp_drv.ver_res = screenHeight;
  disp_drv.flush_cb = my_disp_flush;
  disp_drv.draw_buf = &draw_buf;
  lv_disp_drv_register(&disp_drv);

  /* Create simple label */
  lv_obj_t *label = lv_label_create( lv_scr_act() );
  lv_label_set_text( label, "Hello Arduino! (V8.0.X)" );
  lv_obj_align( label, LV_ALIGN_CENTER, 0, 0 );

  //ui_mian(); // watch

  Serial.println("Setup done");

  pinMode(3, OUTPUT);
  digitalWrite(3, HIGH);

  pinMode(0, INPUT);
}

void loop()
{
  lv_timer_handler(); /* let the GUI do its work */
  delay(5);
}

#End if
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
I think, no another way (cheaper and faster) for the MCU programming, than only to use the C-code and C-libs already debugged well.
See my latest posts into CODE SNIPPET forum, for the sensors: if a lib for the sensors exists - it's rather easy to use it as inline-C.

Or you can rewrite ALL THE CODE of a lib to B4R from the scratch.
 
Upvote 0

KiloBravo

Active Member
Licensed User
Candide, one of the members on this forum, created a tool to wrap libraries. I am going to try and use it ASAP.
I know Candide has posted a LOT of wrapped libraries on the forum so it must work!

 
Upvote 0

daveinhull

Active Member
Licensed User
Longtime User
@peacemaker, thanks for your persuerance and quick responses, but could you maybe tell me why the in-line code (in the exmaple) does not work?

@KiloBrava, interesting I will take a look at the tool and see what I can do with it. Which libraries are you going to to try to wrap?
Please keep me in the loop and I will keep you in the loop with any progress I make - Many Thanks
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
As i told - see my code examples for different sensors, and make accordingly (the examples are by the github-links and my solutions). From B4R the native C-subs should be called passing the parameter and reading the public variable from C-code and assigning the results to some other public B4R variables.
"setup" and "loop" names of the subs, seem, to be renamed, but no idea for sure, i do not know C-language in whole, just learning by intuition, analogies and examples, googling each key output log message.
 
Upvote 0

daveinhull

Active Member
Licensed User
Longtime User
Hello again,

I've just noticed that in the baove code snippet I get a compile error saying multipe definitions of Setup and Loop, can anyone say why this is happeneing as I appear to have only declared them one?

Thanks
Dave
 
Upvote 0

peacemaker

Expert
Licensed User
Longtime User
Google and learn how Arduino works. B4R is transpiller over the Arduino.
Make unique sub names, try to change anything, if you cannot learn during this programming work recursively - you won't finish it.

Maybe better for your project just use only Arduino, without B4R.
 
Upvote 0

daveinhull

Active Member
Licensed User
Longtime User
I get that and I appreciate your concern of my learning, but sometime even people learning need a more direct approach than to simply say "read and learn".

Well, given what you say, I should just abandon B4R and go back to the Arduino IDE which I can easily use (did so for many years before finding B4R), but as I said I prefer B4R.
The inline code compiles perfectly n the Arduino environment, so I was specifically asking someone for some help to get me over a particular error as I can't see where I've declared Setup and Loop more than once. This is all part of learning – imagine a student struggling to understand someone in class and asking the teach for help and all the teacher says is “learn more”
I appreciate your initial guidance, but if you continue to just say learn more, I would respectively ask you not to reply – I’m trying to do that and don’t need constantly telling.
 
Upvote 0

KiloBravo

Active Member
Licensed User
I have not looked at your B4R code in depth. But try renaming SetUp and Loop to my_Setup and myLoop.
Also you should be using RunNative. Call it in B4R like RunNative("mySetup,Null). I would probably not call Loop.
or replace it and again call it from B4R with RunNative. Good Luck!

Search the forum for RunNative plenty of examples.
 
Upvote 0

daveinhull

Active Member
Licensed User
Longtime User
@KiloBravo, many thanks for the suggestion which I'll give it a tried. I did realise I needed to use RunNative.... but was just trying to get things to compile first.
 
Upvote 0

KiloBravo

Active Member
Licensed User
If you use this library it has no dependencies. https://github.com/carlfriess/GC9A01_demo
You could rewrite that Lib in B4R. I did something similar for a Nunchuk with I2C comms.
You can see the B4R code here. I have links to the C library as comments in the B4R code.

The communication for GC9A01 is SPI. Candide wrapped an SPI Library. It works I have used it.

The GC9A01 is relatively simple. You just send commands and data over the SPI interface. Explained in the Datasheet.
If it works in Arduino then the SPI comms work. It is just a matter of converting it to B4R code.

The examples should get you started. It would be a lot easier to convert the GC9A01 C lib to B4R code, than trying to wrap libraries on top of libraries that are designed for generic hardware and interfaces. IMHO.
 
Upvote 0

daveinhull

Active Member
Licensed User
Longtime User
@KiloBravo many thanks for the ongoing support. Actually, I had already found that library and had started to see what I could do with it. My initial thought was to produce a wrapper for it using the tool you previously mentioned, but I keep getting errors with the tool. However, as I looked at it further I was starting to think I could actually just rewrite the code, you've certainly given me some boost in going in that direction 💪👍👍👍

Thanks
Dave
 
Upvote 0

KiloBravo

Active Member
Licensed User
Just take it one step at a time. Send a command over SPI and see if you get a response. Then build from that and use plenty of LOG statements. Since it works in Arduino you should not have to set the "type" of interface again. That should be very helpful.
Good Luck!
 
Upvote 0

daveinhull

Active Member
Licensed User
Longtime User
@KiloBravo thanks, spent all day on it. I've concatenated the example given into a single .ino file (so I can work on it).
It compiles under Arduino IDE and I can switch the back light on and off, but it doesn't do what the example is designed to do, just blank screen.
I've found that there are a lot of undocumented commands being used during the .Init routine which are not in the GC9A01 data sheet, so not sure what they are doing.
My immediate concerns are around the use of the SPI pins on my board and those in the Arduino SPI library (the library assumes standard pins and you can change them).
I've tried matching the pins to the examples I have that I do know works, but I can't get it working - at the moment.
The example code is very simple and fully understandable, so it must be something that is going on in the Initialisation sequences. It’s very difficult to find the same initialisation sequence in the LVGL library, but I'm still looking.
 
Upvote 0

KiloBravo

Active Member
Licensed User
gc9a01PINS.png
 
Upvote 0
Top