Hi,
I see unexpected timings on serial, made a SerialTest to show it, baudrate in this is 19200.
My application on ESP32 communicates to ATMega328P via Serial1 connection, ESP32 sends message, AtMega replies.
For the testing I write all incoming ATmega characters to Serial2, on a char by char base, not waiting for the full message to arrive.
I also toggle pin 25 to know the timing.
Full test app is
#include "Arduino.h"
void setup()
{
Serial.begin(115200);
Serial1.begin(19200, SERIAL_8N1, 16, 17);
Serial2.begin(19200, SERIAL_8N1, 23, 19);
pinMode(25,OUTPUT);
digitalWrite(25,LOW);
}
uint8_t msg[] = {0xAA,0x3A,0x24,0x08,0x01,0x72};
void loop()
{
if (Serial.available()) // Initiate one message to ATMega
{
uint8_t c = Serial.read();
Serial1.write(msg,6);
}
if (Serial1.available()) // ATMega reply is coming in
{
uint8_t c = Serial1.read();
Serial2.write(c); // Write to Serial2 for debugging.
digitalWrite(25,!digitalRead(25));
}
}
What happens is :
ESP32 sends message
ATMega replies immediately, first character start coming in after 120 us, first char complete in after 625 us.
But the Serial1.read() only returns true 3200 us after first char complete -> This is what I do not understand, I expected it a very short period after complete.
The timing is shown in the logic analyzer output.
White : Serial1 from ESP to ATmega
Green : Serial1 from ATMega to ESP
Brown : Serial2 from ESP
Grey : Pin25 (toggle)
@hreintke The Serial()
driver code uses the 128 byte hardware fifo's of the UART. There are two case that trigger the emptying of the Fifo.:
The Serial()
object only sees the receive queue. So until either of those two cases happen, the data is only in the hardware Fifo.
You can change this behavior by adjusting the trigger points and recompiling. in cores\esp32\esp32-hal-uart.c
line 102:
void uartEnableInterrupt(uart_t* uart)
{
UART_MUTEX_LOCK();
uart->dev->conf1.rxfifo_full_thrhd = 112;
uart->dev->conf1.rx_tout_thrhd = 2;
uart->dev->conf1.rx_tout_en = 1;
uart->dev->int_ena.rxfifo_full = 1;
uart->dev->int_ena.frm_err = 1;
uart->dev->int_ena.rxfifo_tout = 1;
uart->dev->int_clr.val = 0xffffffff;
esp_intr_alloc(UART_INTR_SOURCE(uart->num), (int)ESP_INTR_FLAG_IRAM, _uart_isr, NULL, &uart->intr_handle);
UART_MUTEX_UNLOCK();
}
reduce the trigger thresholduart->dev->conf1.rxfifo_full_thrhd = 112;
it needs to be above zero.
rx_tout_thrhd
is defined as a seven bit value max range is 127, min it zero, but 1 is actually lower range.
Chip revision is higher than the one configured in menuconfig. Suggest to upgrade it.
@lbernstone @me-no-dev
Based on the info from you yesterday I am looking into the serial/serial interrupts.
Still working on that but I noticed that static void IRAM_ATTR _uart_isr(void *arg)
is always called twice.
Does not have a functional influence but don't know if that is expected/intentional.
Sketch :
#include "Arduino.h"
void setup()
{
pinMode(25,OUTPUT);
digitalWrite(25,LOW);
pinMode(26,OUTPUT);
digitalWrite(26,LOW);
Serial.begin(115200);
}
void loop()
{
if (Serial.available())
{
Serial.write(Serial.read());
}
}
Added two pin toggles to _usart_isr
static void IRAM_ATTR _uart_isr(void *arg)
{
uint8_t i, c;
BaseType_t xHigherPriorityTaskWoken;
uart_t* uart;
digitalWrite(25,HIGH); // ----> Brown toggle
for(i=0;i<3;i++){
uart = &_uart_bus_array[i];
if(uart->intr_handle == NULL){
continue;
}
uart->dev->int_clr.rxfifo_full = 1;
uart->dev->int_clr.frm_err = 1;
uart->dev->int_clr.rxfifo_tout = 1;
while(uart->dev->status.rxfifo_cnt || (uart->dev->mem_rx_status.wr_addr != uart->dev->mem_rx_status.rd_addr)) {
digitalWrite(26,HIGH); // ----> Grey toggle
c = uart->dev->fifo.rw_byte;
if(uart->queue != NULL && !xQueueIsQueueFullFromISR(uart->queue)) {
xQueueSendFromISR(uart->queue, &c, &xHigherPriorityTaskWoken);
}
digitalWrite(26,LOW); // ----> Grey toggle
}
}
digitalWrite(25,LOW); // ----> Brown toggle
if (xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR();
}
}
In the Logicanalyzer :
White : Serial Receive
Green : Serial Transmit
Brown : Pulse on _usart_isr
Grey : Pulse on char transfer from fifo to queue
Picture 1 : Receive and transmit of one char
Picture 2 : Detail of usart_isr + start of transmit