-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Is it possible to suspend HardwareSerial to protect a global buffer? #8203
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
Comments
@SuGlider please help with triage, thanks. |
@techtoys - This task needs to send data to the sensor before receiving back the sensor response? Or the sensor is programmed to send data every 50ms? If possible, please provide a basic sketch, just to understand clearly what is your need and how it is currently done. |
Queues are a "protected global buffer", and can be used to signal data availability. See the example at https://github.com/espressif/arduino-esp32/tree/master/libraries/ESP32/examples/FreeRTOS/Queue |
There are a few ways to do not loose data while receiving and processing UART data:
Example: void setup () {
Serial1.setRxBufferSize(2048); // it will keep up to 2048 bytes received from UART_1 even if it is not read
Serial1.begin(115200);
}
char uart_processing_data[256];
void loop() {
// read and process the UART_1 data
Serial1.read(uart_processing_data, 256);
// wait or do something else
delay(100);
}
Example: // User callback to process Serial data as soon as it is available -- process all incoming data here!
void Serial_Data_Processor() {
// process the data the way it is necessary.
// For instance, just read and print the data in a different UART port
int incomingByte = 0; // for incoming serial data
// check for all available incoming data from UART 2
while (Serial2.available() > 0) {
// read the incoming byte:
incomingByte = Serial2.read();
// prints the received data to the console UART
Serial.print("I received: ");
Serial.println((char)incomingByte);
}
}
void setup () {
// UART 2 i connected to the sensor
Serial2.begin(9600);
// Sets the User Callback function "Serial_Data_Processor()"
Serial2.onReceive(Serial_Data_Processor);
// UART 0 for seeing the data from UART 2
Serial.begin(115200);
}
void loop() {
// Nothing to be done here... It is all done in the callback function.
}
|
I am using the callback method as you have mentioned in point #2 above but I think my practice of using unprotected global variables for message buffer My message format is fixed with this pattern: The sensor dispatches periodic messages at 4Hz and there are async. messages triggered by the user as well. As a result, there will be random messages interleave in the middle of periodic sensor messages in the period of 250ms. Example message: To receive the message, snippet of my code is like:
API of this module is:
As you have mentioned:
Although the internal From a book (Embedded Systems Building Blocks) written by Jean J Labrosse, there is a chapter on Serial Interface in Mirium RTOS. Although it is not FreeRTOS, the principle should be the same. Extract from the book it states:
Please notice that there are Disable interrupts and Enable interrupts. I tried this with ESP32 dialect but there is a wdt timeout error. That is why I am asking if there is function to suspend/resume HardwareSerial in this thread. |
Ok, I see. Maybe there are a few details about how the HardwareSerial::onReceive() callback works that can help you in order to let you make the best software design decisions: ESP32 HardwareSerial is based on the UART IDF 4.4 code and its ISR internal driver. 1- Every byte that arrives to the UART port will be stored in the ESP32 internal hardware FIFO up to a limit, by default of 120 bytes. When this limit is reached IDF will copy those 120 bytes to the Arduno HardwareSerial internal buffer and, only then, the Arduino sketch will be able to read them or to know that there is data available by using something like Note: 2- There is a second way to force the UART data to be copied to the HardwareSerial internal buffer, which is when a timout happens. This timeout is measured in number of UART symbols based on the actual baud rate of the serial port. Therefore, is just 4 bytes arrives, and nothing comes into the UART within TIMEOUT, the IDF driver will copy those 4 bytes to Arduino use it. It is possible to control those two parameters using the HardwareSerial API:
I think that you may try to use it with |
My baud rate is exactly 57600bps. Is the default FIFO 120bytes?
Is UART symbol meaning an 11-bit time? I found it from https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/uart.html, it states:
|
No, using 57600 or less, sets it to 1 in NOTE: If
Yes, UART symbol means 11 bits with 8E1 (1 start bit - 8 bits - 1 Parity bit - 1 stop bit). |
You can experiment with all of it by using a callback like this: void testingCallback() {
// Here I supose that it is using UART 0 (Serial), but it is possible to set a different call back for each UART
// by using, for instance, Serial1.onReceive() or Serial2.onReceive()
int nBytes = Serial.available();
Serial.printf("\nThere are %d bytes ready in the UART buffer\n", nBytes);
Serial.println("Received data:");
for (int i = 0; i < nBytes; i++) {
char c = Serial.read();
Serial.printf("'%c'[0x%x] ", c, c);
if (((i + 1) % 10) == 0) Serial.println();
}
} Use a Serial Terminal/Monitor and send N blocks of 64 characters (like the one below) in one time to the UART port: The call back will tell you how many bytes it has received. By default, for 57600 bps, it should tell you 1 by 1... Everything is about timing and how things happen in parallel! |
There are some examples about FIFO threshold, FIFO timeout and onReceive() in the |
SuGlider, thanks a lot for your help. |
Related area
HardwareSerial feature
Hardware specification
ESP32 PICO D4
Is your feature request related to a problem?
Using HardwareSerial to get sensor data with a buffer written as
uint8_t ser_buf[SIZE]
in the global space. A task is running to scan the availability of data in that buffer in a period of 250ms. Because it is not a fast scanning rate, from time to time I can see that the buffer is corrupted by new data coming from the sensor data acquisition task.Describe the solution you'd like
I wish to suspend HardwareSerial when there is new data in
ser_buf[]
and resume it after I have processed the data.Describe alternatives you've considered
I have increased the scanning period to 50ms to improve data integrity. It seems to work but I am still worry about intermittent data corruption.
Additional context
No response
I have checked existing list of Feature requests and the Contribution Guide
The text was updated successfully, but these errors were encountered: