Skip to content

how to use esp32-hal in arduino,example esp32-hal-uart.h for serial interrupt in arduino? #6102

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
zouzhe1 opened this issue Jan 6, 2022 · 7 comments · Fixed by #6134
Closed
1 task done
Assignees
Labels
Status: Solved Type: Feature request Feature request for Arduino ESP32

Comments

@zouzhe1
Copy link

zouzhe1 commented Jan 6, 2022

Board

esp32

Device Description

esp32

Hardware Configuration

esp32

Version

latest master

IDE Name

platformio

Operating System

win10

Flash frequency

40

PSRAM enabled

no

Upload speed

9600

Description

i want to use serial hardware interrupt in arduino,but i found the arduino api serialEvent() is not really hardware serial interrupt.so,i fonud some in .platformio\packages\framework-arduinoespressif32\cores\esp32 ,esp32-hal-uart.c and esp32-hal-uart.h
i think this two file can help me. but i dont find any help document about this HAL file.

//example this function
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted);

what uart_nr? what config? what queueLen?i dontknow rev data len. what inverted?

Sketch

//example this function
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted);

what uart_nr?   what config?  what queueLen?i dontknow rev data len. what inverted?

Debug Message

....

Other Steps to Reproduce

No response

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

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.
@zouzhe1 zouzhe1 added the Status: Awaiting triage Issue is waiting for triage label Jan 6, 2022
@SuGlider SuGlider added the Type: Question Only question label Jan 7, 2022
@SuGlider
Copy link
Collaborator

SuGlider commented Jan 7, 2022

Hi @zouzhe1
Currently Arduino Core version 2.0.2 uses UART IRQ to fill up buffer in Arduino Serial. I guess that what you are looking is some sort of a callback function that will react immediately when a byte arrives in the UART - which you describe as Serial Interrupt.

This can be achieved using a Free RTOS Task that keeps waiting for an event to arrive in its queue, based on IDF call uart_driver_install(), as described in IDF Ref - uart_driver_install

The event UART_DATA is the one that you are looking for. An example of this task and functionality can be found in IDF Queue Processing

Specific Questions

i want to use serial hardware interrupt in arduino,but i found the arduino api serialEvent() is not really hardware serial interrupt.so,i fonud some in .platformio\packages\framework-arduinoespressif32\cores\esp32 ,esp32-hal-uart.c and esp32-hal-uart.h
i think this two file can help me. but i dont find any help document about this HAL file.

Correct, serialEvent() is not a real hardware serial interrupt. It is executed, as Arduino Framework defines, at the end of the execution of loop() whenever there is data buffered by the UART.

Please note that PlatformIO is still using ESP32 Arduino Core version 1.0.6, thus it is an old version of the UART driver. Currently we don't support it anymore and there won't be any updates to this version.
UART has been refactored to use IDF in Arduino Core version 2.0.0+ as I explained above.

//example this function
uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t queueLen, bool inverted);

what uart_nr?

uart_nr is the UART ID, for instance, 0 is Serial, 1 is Serial1 and 2 is Serial 2 (this last one is not applicable for ESP32-S2 and ESP32-C3).
REF

what config?

config is a data structure that describes the UART configuration, such as 8 bits, Even Parity, no Stop Bits.
REF

what queueLen?

queueLen is the size of the UART driver buffer, in bytes.

i dontknow rev data len. what inverted?

inverted is a feature that ESP32 chip has that allows the chip to invert the signal polarity.
ESP32 UART uses High Signal (3.3 volts) as idle bus and signals are Low (0 volt). Inverting it is for very specific usage, that is not UART electrical protocol compatible.

@zouzhe1
Copy link
Author

zouzhe1 commented Jan 9, 2022

@SuGlider Thank you for your answer
1,I changed the platform's Arduino Core to the latest 2.0.2, and it can compile and run normally.
2,Do you mean that 2.0.2 supports serial port hardware interrupt and 1.0.6 does not support serial port hardware interrupt?
3,I tried to use the freertos method you introduced, but this seems to require IDF. Is it the platform's default arduino framework, which cannot directly call the functions of IDF?
4,i found this link,does this operation need to build the idf compilation environment first? under win10
link
5,I'm curious, esp32 is a Chinese company, but their materials are all in English, and the community doesn't even have a convenient place to communicate. i am Chinese too. I'm new to programming, thanks for your help.

@SuGlider
Copy link
Collaborator

SuGlider commented Jan 9, 2022

@zouzhe1

2,Do you mean that 2.0.2 supports serial port hardware interrupt and 1.0.6 does not support serial port hardware interrupt?

Both versions 1.06 and 2.0.2 use serial port hardware interrupt to provide an Arduino Serial Hardware API to users.
Version 1.0.6 has been implemented by code that directly manipulates ESP32 registers and memory mapped peripherals, as a bare metal application layer.
Version 2.0.2 uses IDF layer as its base, thus it implements a layer that uses IDF as middleware in between ESP32 register manipulation and Arduino API for Serial Hardware.

The software architecture makes 2.0.2 and 1.0.6 so different.

Currently there is no implemented Arduino API IRQ call back functionality in both cases, 1.0.6 nor 2.0.2. So I think that none of them will solve your request at this time.

3,I tried to use the freertos method you introduced, but this seems to require IDF. Is it the platform's default arduino framework, which cannot directly call the functions of IDF?

IDF 4.4 is fully included in the ESP32 Arduino Core 2.0.0+. You can use IDF calls as it is part of your Arduino Sketch code.
But because the version 2.0.2 uses IDF as well to implement Arduino API, the final Arduino sketch code shall be careful in mixing Arduino with IDF calls.
For instance, if the Sketch uses Serial.begin(), it shall not try to install the UART IDF driver on top of it.
In that case, you will need to partially implement your own Serial layer using IDF directly and avoid using Arduino Serial Layer.

Note that the current Serial Hardware code in Arduino Layer is builton top of IDF calls, for example, Serial.begin() becomes:
https://github.com/espressif/arduino-esp32/blob/master/cores/esp32/esp32-hal-uart.c#L109-L163

You may use this code to create your own Serial Begin(), for instance, by creating your own MySerialBegin() and adding the IDF piece of code to deal with UART Events plus a Task to treat those events. At the end everything is just C code.

4,i found this link,does this operation need to build the idf compilation environment first? under win10 link

Arduino as an ESP-IDF component is a different way to build an application based on Arduino API.
It is actually an IDF Application and uses all IDF building tools and methods instead.
Arduino API becomes just a Component as any other IDF component that your project may use.
Thus, it's possible to include Arduino API calls to this IDF application.

5,I'm curious, esp32 is a Chinese company, but their materials are all in English, and the community doesn't even have a convenient place to communicate. i am Chinese too. I'm new to programming, thanks for your help.

I am sure that there is excellent Chinese language based web sites, blogs, forums, and other Intenet resources.
ESPRESSIF has both Chinese and English documentation. But I agree with you that most of the Arduino documentation is in English. I do not speak Chinese, thus I don't have knowledge of a good Chinese written website with ESP32 documentation that you could use.

ESPRESSIF has a Chinese version about the documentation and a Chinese Forum Site- I hope it suits your needs:
https://docs.espressif.com/projects/esp-idf/zh_CN/latest/esp32/
https://www.esp32.com/viewforum.php?f=24&sid=01d85bf3399c2ceee9f9dded517797bd

@VojtechBartoska VojtechBartoska removed the Status: Awaiting triage Issue is waiting for triage label Jan 10, 2022
@SuGlider SuGlider self-assigned this Jan 12, 2022
@SuGlider SuGlider added Status: In Progress ⚠️ Issue is in progress Type: Feature request Feature request for Arduino ESP32 Status: To be implemented Selected for Development and removed Type: Question Only question labels Jan 12, 2022
@SuGlider
Copy link
Collaborator

@zouzhe1

A potential solution is being implemented.
It's the Serial.onReceive(function)

As soon as any data arrives UART RX, function() will called.

Example:

void UART_RX_IRQ(){
  uint16_t size = Serial.available();
  Serial.printf("Got %d bytes on Serial to read\n", size);
  while(Serial.available()) {
    Serial.write(Serial.read());
  }
  Serial.printf("\nSerial data processed!\n");
}

void setup() {
  Serial.begin(115200);
  Serial.onReceive(UART_RX_IRQ);
  Serial.println("Send data to UART0 in order to activate the RX callback");
}

void loop() {
  Serial.println("Sleeping for 10 seconds...");
  delay(10000);
}

Would that work for you?

@zouzhe1
Copy link
Author

zouzhe1 commented Apr 13, 2022

@SuGlider Thank you very much for adding this new feature.

@Murugesh-Hobbyist
Copy link

Murugesh-Hobbyist commented Mar 20, 2024

@zouzhe1

A potential solution is being implemented. It's the Serial.onReceive(function)

As soon as any data arrives UART RX, function() will called.

Example:

void UART_RX_IRQ(){
  uint16_t size = Serial.available();
  Serial.printf("Got %d bytes on Serial to read\n", size);
  while(Serial.available()) {
    Serial.write(Serial.read());
  }
  Serial.printf("\nSerial data processed!\n");
}

void setup() {
  Serial.begin(115200);
  Serial.onReceive(UART_RX_IRQ);
  Serial.println("Send data to UART0 in order to activate the RX callback");
}

void loop() {
  Serial.println("Sleeping for 10 seconds...");
  delay(10000);
}

Would that work for you?

Thanks a lot! This works great and to addon,
this method is not working while we enable "USB CDC On Boot" in Arduino IDE as I'm using ESP32S3-Zero.
and is there any way to return the serial/processed value from "void UART_RX_IRQ()" to global variable "x"?

Because it doesn't recognise user defined global variables.

@SuGlider
Copy link
Collaborator

SuGlider commented Mar 20, 2024

this method is not working while we enable "USB CDC On Boot" in Arduino IDE as I'm using ESP32S3-Zero.

HardwareSerial::onReceive() is only available for UART.
When USB CDC On Boot is enabled, Serial becomes the CDC port and UART0 becomes Serial0.
Therefore it is possible to active it by calling Serial0.onReceive(...)
The same for the other 2 UARTs, Serial1.onReceive(...) and Serial2.onReceive(...)

is there any way to return the serial/processed value from "void UART_RX_IRQ()" to global variable "x"?
Because it doesn't recognise user defined global variables.

Not sure what exactly is the goal with the "global variable X".
A possible example:

// this will make UART0 work for any case (using or not USB)
#if ARDUINO_USB_CDC_ON_BOOT
#define UART0 Serial0
#else
#define UART0 Serial
#endif

String X = "";   // global variable to keep the results from onReceive()
const uint32_t communicationTimeout_ms = 500; // a pause of half second in the UART transmission is considered end of transmission.

void UART_RX_IRQ() {
  uint32_t now = millis(); // track timeout

  while ( (millis() - now) < communicationTimeout_ms) {
    if (UART0.available()) {
      X += (char) UART0.read();
      now = millis();  // reset the timer
    }
  }
}

void setup() {
  UART0.begin(115200);
  UART0.onReceive(UART_RX_IRQ);
  UART0.println("Send data to UART0 in order to activate the RX callback");
}

uint32_t counter = 0;
void loop() {
  if (X.length() > 0) {
    // process the received data from UART0 - example, just print it beside a counter
    UART0.print("[");
    UART0.print(counter++);
    UART0.print("] ");
    UART0.println(X);
    X = "";  // reset X for the next UART reading.
  }
  UART0.println("Sleeping for 1 second...");
  delay(1000);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Solved Type: Feature request Feature request for Arduino ESP32
Projects
Development

Successfully merging a pull request may close this issue.

4 participants