Xiao ESP32c3 with Round Display: Touch not working with wifi

Hello! I’ve been working on a project with a xiao ESP32c3 and a round display. I’ve got a lot working, but when I enable wifi I seem to have problems with the touch screen. Is it supported to use WiFi and touch screen at the same time?

… i would not know of any reason why the wifi would not work with the round display… the only think i could think is that the Wifi subsystem uses a dedicated core, so that it can do its wifi stuff continuiously without interuption… the touch process probably also probably likes to run uninterupted. Therefore if the touch is trying to run in the same core as the wifi… this would probably cause a problem… I dont know if you understand the programming well enough to tell what core it is running on… i also dont understand that well… but that is probably the problem… I know the whole touch process is funny acting to begin with…

I think the esp32c3 is just single core, so that might be the problem? I found this which seems to indicate that GPIO is a problem. Could this be affecting the touch screen function?

… it may be technically single core… but the wifi and bluetooth subsystems run in a dedicated processing area… the wifi should not require any gpio to function… but if the gpio is not properly configured it would not work… i am assumung you have a non wifi code that runs correctly?

HI there,
SoCan you post up the code you are using?, Use the code tags above “</>” and paste it in there.
I don’t think that LIB is current BTW, So I would retest using the more Current Seeed Specific for round display(other threads) and try that.
Which Touch driver and Pin are you using?
HTH
GL :slight_smile: PJ :v:

Afaik , there isn’t an issue and it does work.:+1:

Sorry my code isn’t the best, its an amalgamation of a bunch of other peoples projects, so maybe there is another bug in here. Best I can tell the problem only occurs when the “high power” task is set to high power mode (wifi turns on). It also happens if I inline the tasks so that wifi and display are happening in the same task.

Hi there,
No worries , ALL code is Garbage LOL, what my old instructor used to say. :smile:
I’ll try a compile on it see what I get ,
In the mean Time I loaded up a C3 on my Round display and Rolled back to BSP 2.0.17
I ran the Hardware test under the “Seeed Round Display Examples” the touch screen works good, so I went and Added the WIfi to it and made it display the Wifi name and Ip address it gets.
Try that see if it works for you?

Should look like this…

Slider touch still works fine…:+1:

#include <lvgl.h>

// uncomment a library for display driver
//#define USE_TFT_ESPI_LIBRARY
#define USE_ARDUINO_GFX_LIBRARY

#include "lv_xiao_round_screen.h"
#include "lv_hardware_test.h"

#include <WiFi.h>

const char *ssid     = "PUT YOURS HERE";
const char *password = "SEEEDaliscous";

// Declare the WiFi SSID/IP label and a flag for toggling
static lv_obj_t *wifi_label;
static bool show_ssid = true;

// Timer callback to alternate between SSID and IP address
void wifi_label_update_cb(lv_timer_t *timer) {
    if (show_ssid) {
        // Display SSID
        lv_label_set_text(wifi_label, ssid);
    } else {
        // Display IP address
        String ip = WiFi.localIP().toString();
        lv_label_set_text(wifi_label, ip.c_str());
    }
    show_ssid = !show_ssid;  // Toggle between SSID and IP
}

void setup()
{
    Serial.begin( 115200 );  //prepare for possible serial debug 
    Serial.println( "XIAO round screen - LVGL_Arduino" );
    Serial.print("Connecting to ");
    Serial.println(ssid);

    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());

    lv_init();

    lv_xiao_disp_init();
    lv_xiao_touch_init();

    // Run the hardware test
    lv_hardware_test();

    // Create a label to display the WiFi SSID or IP address
    wifi_label = lv_label_create(lv_scr_act());
    lv_label_set_text(wifi_label, ssid);  // Initially set the label text to the WiFi SSID
    lv_obj_set_pos(wifi_label, 65, 150);  // Position the label between the slider and the TF-card

    // Create a timer to alternate the label content every 3 seconds
    lv_timer_create(wifi_label_update_cb, 3000, NULL);
}

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

HTH
GL :slight_smile: PJ :v:

serial output…

Connecting to GlassSurf-2.4
.
WiFi connected
IP address: 
192.168.1.188
XIAO round screen - LVGL_Arduino
2 Likes

Thanks I’ll give that a try!

HI there,
Ok
Your code appears to work BTW, here is the output.

serial output:
State: 0, hp: 0
State: 0, hp: 0
State: 0, hp: 0
State: 0, hp: 0
State: 0, hp: 0
State: 0, hp: 0
State: 0, hp: 0

compiler output

FQBN: esp32:esp32:XIAO_ESP32C3
Using board 'XIAO_ESP32C3' from platform in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.0.5
Using core 'esp32' from platform in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.0.5
edit_4_brevity...
Using library SPI at version 3.0.5 in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.0.5\libraries\SPI 
Using library TFT_eSPI at version 2.5.43 in folder: D:\Arduino_projects\libraries\TFT_eSPI 
Using library FS at version 3.0.5 in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.0.5\libraries\FS 
Using library SPIFFS at version 3.0.5 in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.0.5\libraries\SPIFFS 
Using library I2C BM8563 RTC at version 1.0.4 in folder: D:\Arduino_projects\libraries\I2C_BM8563_RTC 
Using library Wire at version 3.0.5 in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.0.5\libraries\Wire 
Using library Seeed Arduino Round display at version 1.0.0 in folder: D:\Arduino_projects\libraries\Seeed_Arduino_Round_display 
Using library lvgl at version 8.3.7 in folder: D:\Arduino_projects\libraries\lvgl 
Using library WiFi at version 3.0.5 in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.0.5\libraries\WiFi 
Using library Networking at version 3.0.5 in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.0.5\libraries\Network 
Using library HTTPClient at version 3.0.5 in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.0.5\libraries\HTTPClient 
Using library NetworkClientSecure at version 3.0.5 in folder: C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.0.5\libraries\NetworkClientSecure 
"C:\\Users\\Dude\\AppData\\Local\\Arduino15\\packages\\esp32\\tools\\esp-rv32\\2302/bin/riscv32-esp-elf-size" -A "C:\\Users\\Dude\\AppData\\Local\\Temp\\arduino\\sketches\\F2968E4704A032EC402C92A433B27890/sketch_oct19a.ino.elf"
Sketch uses 1000584 bytes (76%) of program storage space. Maximum is 1310720 bytes.
Global variables use 35124 bytes (10%) of dynamic memory, leaving 292556 bytes for local variables. Maximum is 327680 bytes.
"C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\tools\esptool_py\4.6/esptool.exe" --chip esp32c3 --port "COM3" --baud 921600  --before default_reset --after hard_reset write_flash  -z --flash_mode keep --flash_freq keep --flash_size keep 0x0 "C:\Users\Dude\AppData\Local\Temp\arduino\sketches\F2968E4704A032EC402C92A433B27890/sketch_oct19a.ino.bootloader.bin" 0x8000 "C:\Users\Dude\AppData\Local\Temp\arduino\sketches\F2968E4704A032EC402C92A433B27890/sketch_oct19a.ino.partitions.bin" 0xe000 "C:\Users\Dude\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.0.5/tools/partitions/boot_app0.bin" 0x10000 "C:\Users\Dude\AppData\Local\Temp\arduino\sketches\F2968E4704A032EC402C92A433B27890/sketch_oct19a.ino.bin" 

HTH
GL :slight_smile: PJ :v:

2 Likes

I’m beginning to suspect the problem is to do with FreeRTOS. The problem comes up when the high power task is created, which is programmed to happen when battery level is high enough (looks like your battery pin is disabled from the dip switches, which is why the application seems to be working for you). I suspect if you were to enable battery level measurement you might start to see some bugs.

I’m going to try rewriting the application using just the standard arduino setup and loop and update here after!


#include <SPI.h>
#include <TFT_eSPI.h>
#include "I2C_BM8563.h"
#define USE_TFT_ESPI_LIBRARY
#include "lv_xiao_round_screen.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <WiFi.h>
#include <HTTPClient.h>

// TFT_eSPI tft = TFT_eSPI();
TFT_eSprite img = TFT_eSprite(&tft);
I2C_BM8563 rtc(I2C_BM8563_DEFAULT_ADDRESS, Wire);

const char *ntpServer = "time.cloudflare.com";
const char *ssid = "ST";
const char *password = "test1234";

// TimerHandle_t hp_timer;

// #define USE_TFT_ESPI_LIBRARY

#define NUM_ADC_SAMPLE 20
#define BATTERY_DEFICIT_VOL 1850
#define BATTERY_FULL_VOL 2450

// https://rgbcolorpicker.com/565
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define YELLOW 0xFFE0
#define GREY 0x4a49
#define TEAL 0x063f
#define DARK_GREY 0x3186
#define TEXT_COLOR 0xFFFF
#define SCALE0 0xC655
#define SCALE1 0x5DEE

#define DEG2RAD 0.0174532925

#define BATLVLFORHP 25

// TL_DATUM = 0 = Top left
// TC_DATUM = 1 = Top centre
// TR_DATUM = 2 = Top right
// ML_DATUM = 3 = Middle left
// MC_DATUM = 4 = Middle centre
// MR_DATUM = 5 = Middle right
// BL_DATUM = 6 = Bottom left
// BC_DATUM = 7 = Bottom centre
// BR_DATUM = 8 = Bottom right

double center_x = 120;
double center_y = 120;

int currentScreen = 0;

lv_coord_t touchX, touchY;
uint32_t primary_color = WHITE;

unsigned long currentTime = 0;
unsigned long timeBatCheck = 0;
unsigned long timeHP = 0;
I2C_BM8563_TimeTypeDef timeStruct;

int currentBattery = 0;

int high_power_state = 0;

bool init_wifi = false;

void state_machine_task()
{
  if (chsc6x_is_pressed())
  {
    printf("Pressed\n");
  }

  switch (currentScreen)
  {
  case 0:
    if (chsc6x_is_pressed())
    {
      currentScreen = 1;
      tft.fillScreen(BLACK);
      delay(300);
    }
    else
    {
      rtc.getTime(&timeStruct);
      // printf("%d H %d m %d s\n", timeStruct.hours, timeStruct.minutes, timeStruct.seconds);
      drawClock(timeStruct.hours * 60 + timeStruct.minutes + timeStruct.seconds / 60.0);
    }
    break;
  case 1:
    if (chsc6x_is_pressed())
    {
      chsc6x_get_xy(&touchX, &touchY);
      tft.fillScreen(BLACK);
      delay(300);
      if (touchX < center_x && touchY < center_y) // Top Left
      {
        currentScreen = 0;
      }
      else if (touchX >= center_x && touchY < center_y) // Top Right
      {
        primary_color = RED;
      }
      else if (touchX >= center_x && touchY >= center_y) // BOT Right
      {
        primary_color = BLUE;
      }
      else if (touchX < center_x && touchY >= center_y) // BOT LEFT
      {
        primary_color = WHITE;
      }
    }
    else
    {
      img.createSprite(240, 240);
      img.fillScreen(TFT_TRANSPARENT);
      int arrow_x = 40;
      int arrow_y = 65;
      img.fillTriangle(arrow_x, arrow_y, arrow_x + 15, arrow_y + 10, arrow_x + 15, arrow_y - 10, primary_color);
      img.fillRect(arrow_x + 15, arrow_y - 2, 15, 5, primary_color);
      img.fillCircle(180, 60, 10, RED);
      img.fillCircle(180, 180, 10, BLUE);
      img.fillCircle(60, 180, 10, WHITE);
      img.pushSprite(0, 0, TFT_TRANSPARENT);
      img.deleteSprite();
    }
    break;
  }
}

void high_power_task()
{
  if (currentTime - timeHP < 1000)
  {
    return;
  }
  timeHP = currentTime;
  printf("State: %d\n", high_power_state);
  switch (high_power_state)
  {
  case 0: // Low power
    // if (currentBattery > BATLVLFORHP)
    if (true)
    {
      high_power_state = 1;
      init_wifi = false;
    }
    break;
  case 1: // Go to high power
    if (!init_wifi)
    {

      WiFi.disconnect();
      WiFi.mode(WIFI_STA);
      WiFi.enableSTA(true);
      WiFi.begin(ssid, password);
      init_wifi = true;
    }

    if (WiFi.status() == WL_CONNECTED)
    {
      high_power_state = 2;
    }
    // if (currentBattery < BATLVLFORHP)
    if (false)
    {
      high_power_state = 3;
    }
    break;
  case 2: // Hight power
    // if (currentBattery < BATLVLFORHP)
    if (false)
    {
      high_power_state = 3;
    }
    break;
  case 3: // Go to low power
    WiFi.mode(WIFI_OFF);
    WiFi.disconnect();
    high_power_state = 0;
    break;
  }

  // if (currentBattery < BATLVLFORHP)
  // {
  //   xTimerStop(hp_timer, 0);
  // }
  // // Connect to an access point
  // Serial.print("Connecting to Wi-Fi ");
  // WiFi.begin(ssid, password);
  // Serial.print(" At this point ");
  // while (WiFi.status() != WL_CONNECTED)
  // {
  //   delay(500);
  //   Serial.print(".");
  // }
  // Serial.println(" CONNECTED");

  // // Set ntp time to local
  // configTime(6 * 3600, 0, ntpServer);

  // // Get local time
  // struct tm timeInfo;
  // if (getLocalTime(&timeInfo))
  // {
  //   printf("Got local time");
  //   // Set RTC time
  //   I2C_BM8563_TimeTypeDef timeStruct;
  //   timeStruct.hours = timeInfo.tm_hour;
  //   timeStruct.minutes = timeInfo.tm_min;
  //   timeStruct.seconds = timeInfo.tm_sec;
  //   rtc.setTime(&timeStruct);

  //   // Set RTC Date
  //   I2C_BM8563_DateTypeDef dateStruct;
  //   dateStruct.weekDay = timeInfo.tm_wday;
  //   dateStruct.month = timeInfo.tm_mon + 1;
  //   dateStruct.date = timeInfo.tm_mday;
  //   dateStruct.year = timeInfo.tm_year + 1900;
  //   rtc.setDate(&dateStruct);
  // }
}

void battery_level_percent()
{
  if (currentTime - timeBatCheck < 1000)
  {
    return;
  }
  timeBatCheck = currentTime;

  int32_t mvolts = 0;
  for (int8_t i = 0; i < NUM_ADC_SAMPLE; i++)
  {
    mvolts += analogReadMilliVolts(D0);
    delay(1);
  }
  mvolts /= NUM_ADC_SAMPLE;
  int32_t level = (mvolts - BATTERY_DEFICIT_VOL) * 100 / (BATTERY_FULL_VOL - BATTERY_DEFICIT_VOL); // 1850 ~ 2100
  level = (level < 0) ? 0 : ((level > 100) ? 100 : level);
  int prev_Battery = currentBattery;
  currentBattery = level;
}

void drawClock(double minutes)
{
  int x = 0;
  int y = 0;

  img.createSprite(240, 240);
  img.fillScreen(TFT_TRANSPARENT);

  // Draw the background
  img.drawArc(center_x, center_y, 117, 90, 0, 360, BLACK, BLACK);

  // Draw the hour ticks
  for (int i = 0; i < 12; i++)
  {
    int a = i * 30;
    int dx = 116 * cos((a - 90) * DEG2RAD) + center_x;
    int dy = 116 * sin((a - 90) * DEG2RAD) + center_y;
    img.fillCircle(dx, dy, 2, DARK_GREY);
  }

  // Draw the tracks
  img.drawArc(center_x, center_y, 112, 110, 0, 360, DARK_GREY, BLACK);
  img.drawArc(center_x, center_y, 97, 95, 0, 360, DARK_GREY, BLACK);

  // Draw the minute hand
  double minute_hand_angle = ((fmod(minutes, 60.0) * 6) - 90) * DEG2RAD;
  x = 111 * cos(minute_hand_angle) + center_x;
  y = 111 * sin(minute_hand_angle) + center_y;
  img.fillCircle(x, y, 3, primary_color);

  // Draw the hour hand
  double hour_hand_angle = ((minutes * 360 / 720) - 90) * DEG2RAD;
  x = 96 * cos(hour_hand_angle) + center_x;
  y = 96 * sin(hour_hand_angle) + center_y;
  img.fillCircle(x, y, 5, primary_color);

  // Draw the battery level
  int16_t textWidth = img.textWidth("000"); // Estimate the maximum width for a 3-digit number
  int16_t textHeight = 24;                  // Adjust based on text size
  img.fillRect(center_x - (textWidth / 2), 180, textWidth, textHeight, BLACK);
  img.setTextSize(2);
  img.drawCentreString(String(currentBattery) + "%", center_x, 180, 1);

  // Update the high power indicator
  uint32_t color = BLACK;
  if (high_power_state == 1)
  {
    color = TEAL;
  }
  if (high_power_state == 2)
  {
    color = GREEN;
  }
  img.drawSmoothArc(center_x, center_y, 72, 65, 140, 220, color, BLACK, true);

  img.pushSprite(0, 0, TFT_TRANSPARENT);
  img.deleteSprite();
}

void setup()
{
  // WiFi.mode(WIFI_STA);
  // WiFi.disconnect();

  // lv_init();

  // lv_xiao_disp_init();
  lv_xiao_touch_init();

  Serial.begin(9600);

  // Start I2C and RTC
  Wire.begin();
  rtc.begin();

  pinMode(TOUCH_INT, INPUT_PULLUP);

  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
  // WiFi.enableSTA(true);

  tft.begin();
  tft.setRotation(0);
  tft.fillScreen(BLACK);

  //   /*Initialize the display buffer*/
  // static lv_disp_draw_buf_t draw_buf;
  // static lv_color_t buf[ SCREEN_WIDTH * LVGL_BUFF_SIZE ];
  // lv_disp_draw_buf_init( &draw_buf, buf, NULL, SCREEN_WIDTH * LVGL_BUFF_SIZE );
  // /*Initialize the display driver for lvgl*/
  // static lv_disp_drv_t disp_drv;
  // lv_disp_drv_init( &disp_drv );
  // disp_drv.hor_res = SCREEN_WIDTH;
  // disp_drv.ver_res = SCREEN_HEIGHT;
  // disp_drv.flush_cb = xiao_disp_flush;
  // disp_drv.draw_buf = &draw_buf;
  // lv_disp_drv_register( &disp_drv );

  static lv_indev_drv_t indev_drv;
  lv_indev_drv_init(&indev_drv);
  indev_drv.type = LV_INDEV_TYPE_POINTER;
  indev_drv.read_cb = chsc6x_read;
  lv_indev_drv_register(&indev_drv);

  img.setColorDepth(16);
}

void loop()
{
  currentTime = millis();
  battery_level_percent();
  high_power_task();
  state_machine_task();
}

No, that doesn’t seem to be it. I changed it to use loop and setup (no FreeRTOS stuff at all) and am experiencing the same error. The difference between my application and the modified example you sent seems to be that I am connecting to wifi while writing to the display, whereas you connect before displaying anything, and then just query IP info in the loop.

For the code I just posted, I commented out the battery detection code and just set it to true so you can see the error. You can change the true in line 152 to false (which then doesn’t turn on wifi) and the application starts working.

sounds like you need to revise your code… just like i thought it was

HI there,
Ok I have a battery I can connect also, time permitting I’ll try it out tomorrow.
SO is it the Touch interrupt callback not firing? when you enable the WiFi ?
Well some good news is it all the newer BSP and LIB’s so there’s that :sweat_smile:
Is the fail , it freezes or doesn’t work at all? the wifi shouldn’t block Albeit but microseconds if so. Touch should still register.
HTH
GL :slight_smile: PJ :v:

Your close ,you’ll get it , seems timer related. I’ll try :+1:

1 Like

Thank you for trying to help! I’ve revised the code and I have a much simpler example that demonstrates the problem. There is an animation in the center. After 10 loops of the animation, I try to turn on wifi and everything freezes:

#include <SPI.h>
#include <TFT_eSPI.h>
#include "I2C_BM8563.h"
#define USE_TFT_ESPI_LIBRARY
#include "lv_xiao_round_screen.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <WiFi.h>
#include <HTTPClient.h>

TFT_eSprite img = TFT_eSprite(&tft);

const char *ssid = "ST";
const char *password = "test1234";


// https://rgbcolorpicker.com/565
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0

double center_x = 120;
double center_y = 120;

lv_coord_t touchX, touchY;

bool init_wifi = false;
bool connected_wifi = false;

void setup() {

  Serial.begin(9600);

  // Start I2C
  Wire.begin();

  WiFi.disconnect();
  WiFi.mode(WIFI_OFF);
  // WiFi.enableSTA(true);

  tft.begin();
  tft.setRotation(0);
  tft.fillScreen(BLACK);

  static lv_indev_drv_t indev_drv;
  lv_indev_drv_init(&indev_drv);
  indev_drv.type = LV_INDEV_TYPE_POINTER;
  indev_drv.read_cb = chsc6x_read;
  lv_indev_drv_register(&indev_drv);

  img.setColorDepth(16);
}

int rad = 0;
uint32_t color = GREEN;
int cnt = 0;

void loop() {

  // Process button inputs to color animation
  if (chsc6x_is_pressed()) {
    chsc6x_get_xy(&touchX, &touchY);
    if (touchX > center_x) {
      color = RED;
    } else {
      color = GREEN;
    }
  }

  // Drive the animation
  int rad = cnt % 40;

  // Draw some buttons and a simple animation
  img.createSprite(240, 240);
  img.fillScreen(BLACK);
  img.drawCircle(center_x, center_y, 40, WHITE);
  img.drawCircle(center_x, center_y, rad, color);
  img.fillCircle(center_x + 80, center_y, 10, RED);
  img.fillCircle(center_x - 80, center_y, 10, GREEN);
  img.fillCircle(center_x, center_y - 80, 10, init_wifi ? connected_wifi ? GREEN : BLUE : BLACK);
  img.pushSprite(0, 0, TFT_TRANSPARENT);
  img.deleteSprite();

  // Enable wifi after 400 cnts have passed
  if (cnt > 400)
  {
    // On first loop initialize wifi
    if (!init_wifi) {
      WiFi.mode(WIFI_STA);
      WiFi.enableSTA(true);
      WiFi.begin(ssid, password);
      init_wifi = true;
    }

    // On every subsequent loop, check connection status
    if (WiFi.status() == WL_CONNECTED) {
      connected_wifi = true;
    }
  } 

  cnt++;
}
1 Like

thanks… hopefully we can find the root of the problem

1 Like

Did you try inserting some debugging printf statements? Which part of WiFi initialization is causing the freeze?

Obviously any crash inside of WiFi initialization is going to then freeze the animations since the loop will stop running.

If you comment out all animation code, but leave the rest as is…does it work? (perhaps instead of animation replace with simple printf() command?

Thats the strange part. The screen freezes, but code execution continues as normal. I did insert print statements to try to find what might be causing this, but as far as I can tell looking at them, there isn’t anything wrong. Just the screen stops updating…

Hi there,
Can you provide the compiler output from this code?
just first 3 lines and the last 10 or so before it begins upload.
TIA
I’ll look and see what it does.
:+1:

HTH
GL :slight_smile: PJ :v: