arduino-esp32
ESP32のArduinoは、ESP-IDFで実装されたものであり、そのESP-IDFもまた、FreeRTOSを利用して実装されたものだである。
setup()
とloop()
main関数はarduino-esp32/blob/master/cores/esp32/main.cpp
で定義される。
void loopTask(void *pvParameters)
{
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SERIAL)
// sets UART0 (default console) RX/TX pins as already configured in boot or as defined in variants/pins_arduino.h
.setPins(gpioNumberToDigitalPin(SOC_RX0), gpioNumberToDigitalPin(SOC_TX0));
Serial0#endif
#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
();
printBeforeSetupInfo#else
if(shouldPrintChipDebugReport()){
();
printBeforeSetupInfo}
#endif
();
setup#if ARDUHAL_LOG_LEVEL >= ARDUHAL_LOG_LEVEL_DEBUG
();
printAfterSetupInfo#else
if(shouldPrintChipDebugReport()){
();
printAfterSetupInfo}
#endif
for(;;) {
#if CONFIG_FREERTOS_UNICORE
();
yieldIfNecessary#endif
if(loopTaskWDTEnabled){
();
esp_task_wdt_reset}
();
loopif (serialEventRun) serialEventRun();
}
}
extern "C" void app_main()
{
#if ARDUINO_USB_CDC_ON_BOOT && !ARDUINO_USB_MODE
.begin();
Serial#endif
#if ARDUINO_USB_MSC_ON_BOOT && !ARDUINO_USB_MODE
.begin();
MSC_Update#endif
#if ARDUINO_USB_DFU_ON_BOOT && !ARDUINO_USB_MODE
.enableDFU();
USB#endif
#if ARDUINO_USB_ON_BOOT && !ARDUINO_USB_MODE
.begin();
USB#endif
= false;
loopTaskWDTEnabled ();
initArduino(loopTask, "loopTask", getArduinoLoopTaskStackSize(), NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
xTaskCreateUniversal}
ESP-IDFではmain関数をapp_main()
と呼ぶ。
ここでやってることはオリジナルArduinoと大体同じ。
オリジナルArduinoと違うのは、FreeRTOSの機能で実質main関数loopTask()
のタスクを作っている。xTaskCreateUniversal()
の最後の引数はコアの指定。
Arduino IDEの実行コア選択メニューもここのマクロを弄っているのだろう。
Xtensa系のESP32大体コア二つ付いてるんだけど、Arduinoだと基本的に一つしか使わない感じ。
ちなみにオリジナルArduinoのmain関数は
int main(void)
{
();
init
();
initVariant
#if defined(USBCON)
.attach();
USBDevice#endif
();
setup
for (;;) {
();
loopif (serialEventRun) serialEventRun();
}
return 0;
}
うん。
ESP32のデュアルコアの扱いについても、基本的にFreeRTOSのタスク関連のAPIでやる。
シリアル
本家Arduinoのシリアルライブラリーに加えて、arduino-esp32のシリアルにはコールバック的な機能がある。
void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout)
{
();
HSERIAL_MUTEX_LOCK// function may be NULL to cancel onReceive() from its respective task
= function;
_onReceiveCB
// setting the callback to NULL will just disable it
if (_onReceiveCB != NULL) {
// When Rx timeout is Zero (disabled), there is only one possible option that is callback when FIFO reaches 120 bytes
= _rxTimeout > 0 ? onlyOnTimeout : false;
_onReceiveTimeout
// in case that onReceive() shall work only with RX Timeout, FIFO shall be high
// this is a work around for an IDF issue with events and low FIFO Full value (< 3)
if (_onReceiveTimeout) {
(_uart, 120);
uartSetRxFIFOFull("OnReceive is set to Timeout only, thus FIFO Full is now 120 bytes.");
log_w}
// this method can be called after Serial.begin(), therefore it shall create the event task
if (_uart != NULL && _eventTask == NULL) {
(this); // Create event task
_createEventTask}
}
();
HSERIAL_MUTEX_UNLOCK}
他にはonReceiveError()
もある。
#define HSERIAL_MUTEX_LOCK() do {} while (xSemaphoreTake(_lock, portMAX_DELAY) != pdPASS)
#define HSERIAL_MUTEX_UNLOCK() xSemaphoreGive(_lock)
これらもFreeRTOSのタスクで実装している。
void HardwareSerial::_createEventTask(void *args)
{
// Creating UART event Task
(_uartEventTask, "uart_event_task", ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE, this, ARDUINO_SERIAL_EVENT_TASK_PRIORITY, &_eventTask, ARDUINO_SERIAL_EVENT_TASK_RUNNING_CORE);
xTaskCreateUniversalif (_eventTask == NULL) {
(" -- UART%d Event Task not Created!", _uart_nr);
log_e}
}
Wireについて、オリジナルArduinoもonReceive()
があって、それはAVRのISRで実装しているらしいけど、どうやって動いているのかはわからない。
組込み開発わからん。
なんか適当に書いちゃったけど内容が薄ぺらいわりに間違いもあるかもしれん。
申し訳ない。