Skip to content

After receiving data through the serial port of the ESP32 chip, there will be a delay of several tens of mS before replying #8850

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
jackwayjun opened this issue Nov 8, 2023 · 8 comments
Assignees
Labels
Status: Community help needed Issue need help from any member from the Community. Type: Question Only question

Comments

@jackwayjun
Copy link

Board

ESP32 Dev Module

Device Description

#define JSON_LEN 100
uint32_t lastRxTime;
uint32_t waitTime =500;

uint32_t Time1 = 0;
uint32_t Time2;
uint32_t Time3;
uint32_t Time4;

void checkComm(void) {
static uint8_t serialBuff[JSON_LEN] = { 0 };
static uint16_t receCount = 0;

if (Serial.available()) {
if (Time1 == 0) {
Time1 = micros();
}
if (receCount < JSON_LEN) {
serialBuff[receCount] = Serial.read();
lastRxTime =micros();
if (lastRxTime == 0)
lastRxTime = 1;
receCount++;
} else {
receCount = 0;
lastRxTime = 0;
}
}

if (lastRxTime != 0 && micros() - lastRxTime >= waitTime) {

Time2 = micros();
Time3 = Time2 - Time1;



Serial.println(Time1);
Serial.println(Time2);
Serial.println(Time3);
Serial.flush();
Time4 = micros() - Time2;
Serial.println(Time4);


memset(serialBuff, 0, sizeof(serialBuff));
receCount = 0;
lastRxTime = 0;
Time1 = 0;

}
}

void setup() {
Serial.begin(115200);
while (!Serial)
;
}

void loop() {
checkComm();
}

Hardware Configuration

normal

Version

v2.0.7

IDE Name

Arduino

Operating System

Win 11

Flash frequency

40

PSRAM enabled

no

Upload speed

115200

Description

After receiving data through the serial port of the ESP32 chip, there will be a delay of several tens of mS before replying.
We need it reply in 5mS

Sketch

#define JSON_LEN 100
uint32_t lastRxTime;
uint32_t waitTime =500;

uint32_t Time1 = 0;
uint32_t Time2;
uint32_t Time3;
uint32_t Time4;

void checkComm(void) {
  static uint8_t serialBuff[JSON_LEN] = { 0 };
  static uint16_t receCount = 0;


  if (Serial.available()) {
    if (Time1 == 0) {
      Time1 = micros();
    }
    if (receCount < JSON_LEN) {
      serialBuff[receCount] = Serial.read();
      lastRxTime =micros();
      if (lastRxTime == 0)
        lastRxTime = 1;
      receCount++;
    } else {
      receCount = 0;
      lastRxTime = 0;
    }
  }

  if (lastRxTime != 0 && micros() - lastRxTime >= waitTime) {

    Time2 = micros();
    Time3 = Time2 - Time1;



    Serial.println(Time1);
    Serial.println(Time2);
    Serial.println(Time3);
    Serial.flush();
    Time4 = micros() - Time2;
    Serial.println(Time4);


    memset(serialBuff, 0, sizeof(serialBuff));
    receCount = 0;
    lastRxTime = 0;
    Time1 = 0;
  }
}

void setup() {
  Serial.begin(115200);
  while (!Serial)
    ;
}

void loop() {
  checkComm();
}

Debug Message

no

Other Steps to Reproduce

no

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.
@jackwayjun jackwayjun added the Status: Awaiting triage Issue is waiting for triage label Nov 8, 2023
@SuGlider SuGlider self-assigned this Nov 8, 2023
@lbernstone
Copy link
Contributor

Do you actually have a fixed length payload? If so, using the onReceive cb, and then readBytes should be a good bit faster than reading bytes out of the queue one at a time. Otherwise, you are kinda stuck polling and figuring out if the sender is done, which is inherently slow.

@SuGlider
Copy link
Collaborator

SuGlider commented Nov 8, 2023

Shouldn't uint32_t waitTime =500; be 5000 instead? 5000us = 5ms

@SuGlider SuGlider closed this as completed Nov 8, 2023
@SuGlider SuGlider reopened this Nov 8, 2023
@SuGlider
Copy link
Collaborator

SuGlider commented Nov 8, 2023

Anyway, I guess this is not an Arduino Core issue, but more a question about how to implement it using Arduino.

@SuGlider SuGlider added Type: Question Only question Status: Community help needed Issue need help from any member from the Community. and removed Status: Awaiting triage Issue is waiting for triage labels Nov 8, 2023
@SuGlider SuGlider removed their assignment Nov 8, 2023
@SuGlider
Copy link
Collaborator

SuGlider commented Nov 8, 2023

As @lbernstone suggested it can done using onReceive() call back, which works similar to an ISR, running the callback function whenever there is data available in the UART.

something like this:

#define JSON_LEN 100

void gotUARTbytes(void) {
  static uint8_t serialBuff[JSON_LEN] = { 0 };
  static uint16_t receCount = 0;
  static unsigned long startReadTime = 0;

  if (receCount == 0) {
    startReadTime = micros();
  }

  uint16_t readLength = Serial.read(&serialBuff[receCount], JSON_LEN - receCount);
  receCount += readLength;

  if (receCount >= 100) {
    Serial.printf("\nTime to receive %d bytes = %ld us\n", receCount, micros() - startReadTime);
    receCount = 0;
  }
}

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.onReceive(gotUARTbytes);  // all is done in gotUARTbytes
}

void loop() {
}

Output --- Receives 100 bytes in less than 50 micro seconds.

ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
[     4][D][esp32-hal-cpu.c:244] setCpuFrequencyMhz(): PLL: 480 / 2 = 240 Mhz, APB: 80000000 Hz

Time to receive 100 bytes = 45 us

Time to receive 100 bytes = 20 us

Time to receive 100 bytes = 29 us

Time to receive 100 bytes = 19 us

Time to receive 100 bytes = 20 us

@jackwayjun
Copy link
Author

I send a character through a computer serial port, and the interval between receiving replies is very long, with 146-91=55mS. I am not sure why there is such a long delay. Is there a problem with my program?Please check the below, Thanks

[2023-11-09 10:08:04.091]# SEND ASCII>

[2023-11-09 10:08:04.146]# RECV ASCII>
370010002
370010618
616
2393

[2023-11-09 10:08:39.402]# SEND ASCII>

[2023-11-09 10:08:39.457]# RECV ASCII>
405323125
405323701
576
2358

@jackwayjun
Copy link
Author

I test this code, the reply is 555-496=59mS, What caused the delay?Thanks!
[2023-11-09 10:43:04.496]# SEND ASCII>
#11

[2023-11-09 10:43:04.555]# RECV ASCII>

Time to receive 3 bytes = 21 us

`#define JSON_LEN 100

void gotUARTbytes(void) {
static uint8_t serialBuff[JSON_LEN] = { 0 };
static uint16_t receCount = 0;
static unsigned long startReadTime = 0;

if (receCount == 0) {
startReadTime = micros();
}

uint16_t readLength = Serial.read(&serialBuff[receCount], JSON_LEN - receCount);
receCount += readLength;

if (receCount >= 1) {
Serial.printf("\nTime to receive %d bytes = %ld us\n", receCount, micros() - startReadTime);
receCount = 0;
}
}

void setup() {
Serial.begin(115200);
while (!Serial);
Serial.onReceive(gotUARTbytes); // all is done in gotUARTbytes
}

void loop() {
}`

@SuGlider
Copy link
Collaborator

SuGlider commented Nov 9, 2023

I test this code, the reply is 555-496=59mS, What caused the delay?Thanks!

At 115200 bits per second, a UART transmission of just one character takes about 10 to 11 bits in time, which means about 90 microseconds. Therefore the transmssion of 100 bytes takes 9000 microseconds, or 9 ms. Sending back a short reply to the computer may take, maybe, 1ms. But there is the time that the computer takes to receive, process it and tell how long it took.

This "long time" of 59 ms may be due to the computer processing for sending and receiving...

My suggestion is to use UART1 RX and TX pins (or like in the example, it uses internal loopback) and run a test using only the ESP32 to check how long does it take to send, receive, process and report back.

UART1 ---> RX1<<-->>TX1 (can be done with a wire or internally to the ESP32, like a software loopback)

As expected this example reports that ot takes 9ms to send/receive 100 bytes.

Example:
(based on https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP32/examples/Serial/RxTimeout_Demo/RxTimeout_Demo.ino)

#include <Arduino.h>

// There are two ways to make this sketch work:
// By physically connecting the pins 4 and 5 and then create a physical UART loopback,
// Or by using the internal IO_MUX to connect the TX signal to the RX pin, creating the
// same loopback internally.
#define USE_INTERNAL_PIN_LOOPBACK 1   // 1 uses the internal loopback, 0 for wiring pins 4 and 5 externally

#define DATA_SIZE 100   // 100 bytes - under fifo limit of 127 bytes
#define BAUD 115200     // Any baudrate from 300 to 115200
#define TEST_UART 1     // Serial1 will be used for the loopback testing with different RX FIFO FULL values
#define RXPIN 4         // GPIO 4 => RX for Serial1
#define TXPIN 5         // GPIO 5 => TX for Serial1

void setup() {
  // UART0 will be used to log information into Serial Monitor
  Serial.begin(115200);

  // UART1 will have its RX<->TX cross connected
  // GPIO4 <--> GPIO5 using external wire
  Serial1.begin(BAUD, SERIAL_8N1, RXPIN, TXPIN); // Rx = 4, Tx = 5 will work for ESP32, S2, S3 and C3
#if USE_INTERNAL_PIN_LOOPBACK
  uart_internal_loopback(TEST_UART, RXPIN);
#endif

  Serial.printf("\n\n================================\nTest Case\n================================\n");
  testAndReport();
}

void loop() {
}

void testAndReport() {
  // Let's send 100 bytes from Serial1 rx<->tx and mesaure time to send and receive
  uint8_t bytesReceived = 0;
  uint8_t dataSent[DATA_SIZE], dataReceived[DATA_SIZE];
  uint8_t i;
  // initialize all data
  for (i = 0; i < DATA_SIZE; i++) {
    dataSent[i] = '0' + (i % 10); // fill it with a repeated sequence of 0..9 characters
    dataReceived[i] = 0;
  }

  Serial.printf("Testing the time for receiving %d bytes at %d baud:", DATA_SIZE, BAUD);
  Serial.flush(); // wait Serial FIFO to be empty and then spend almost no time processing it

  uint32_t now = millis(); // considere the time to send data and received it
  size_t sentBytes = Serial1.write(dataSent, sizeof(dataSent));
  while (bytesReceived < DATA_SIZE) {
    bytesReceived += Serial1.read(dataReceived, DATA_SIZE);
    // safety for array limit && timeout... in 5 seconds...
    if (millis() - now > 5000) break;
  }

  Serial.printf("\nIt has sent %d bytes from Serial1 TX to Serial1 RX\n", sentBytes);
  uint32_t pastTime = millis() - now; // cosideres "some time" to replay back... line above.
  Serial.printf("It took %d milliseconds to read %d bytes\n", pastTime, bytesReceived);
  Serial.print("Received data: [");
  Serial.write(dataReceived, DATA_SIZE);
  Serial.println("]");
  Serial.println("========================\nFinished!");
}

@SuGlider SuGlider self-assigned this Nov 9, 2023
@jackwayjun
Copy link
Author

Thanks very much, I test it, it is the computer processing for sending and receiving , TXD connect to RXD, the computer have about 60mS delay.

[2023-11-10 11:21:07.920]# SEND ASCII>
#11

[2023-11-10 11:21:07.981]# RECV ASCII>
#11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Community help needed Issue need help from any member from the Community. Type: Question Only question
Projects
None yet
Development

No branches or pull requests

3 participants