[Arduino][ESP8266] ESP8266 開發指南 – 軟體架構篇
[Arduino][ESP8266]
ESP8266 開發指南 – 軟體架構篇
ESP8266 RTOS / non-OS SDK
ESP8266 開發板有RTOS SDK 和 Non-OS SDK兩種開發環境,RTOS SDK是架構在FreeRTOS,
也就是說整個軟體程式是跑在 multi-tasking OS上,但因為Espressif 釋出配合Arduino 的開發
package 卻是Non-OS 版本,所以網路上分享的ESP8266軟體程式絕大多數是Non-OS 的版本。
也就是說整個軟體程式是跑在 multi-tasking OS上,但因為Espressif 釋出配合Arduino 的開發
package 卻是Non-OS 版本,所以網路上分享的ESP8266軟體程式絕大多數是Non-OS 的版本。
因此,本篇文章接下來要說明的軟體架構是針對Non-OS SDK版本。
若讀者想要研究 ESP8266 RTOS SDK 的版本,可參考在 GitHub 上的資訊ESP8266_RTOS_SDK
Non-OS = Super Loop ?
從Non-OS 字面上,我們可以說 ESP8266 Non-OS 程式就是以 Super-loop 形式在執行你的程式碼?
或換句話說,ESP8266 的Tensilica L106 32-bit CPU除了中斷ISR 外,都在跑你loop() 函數內的程式碼 ?
事實如何? 讓我們來看看ESP8266 的code entry 吧!
Code Entry
上圖是從 core_esp8266_main.cpp 截取的程式碼。
執行順序是 user_init() ->loop_task) ->loop_wrapper()
而圖中被紅框的setup()以及loop()就是你Arduino 的entry function
看完上圖的code entry解說後,你還覺得ESP8266的軟體架構是和
Arduino UNO一樣的 “super-loop” 軟體執行形式?
Arduino UNO一樣的 “super-loop” 軟體執行形式?
還是和你想像的不一樣?!😊😊😊
Code Structure
Espressif 對ESP8266 Code Structure 定義有以下兩段敘述
首先是下面這截圖
這段說到了 “ESP8266 Non-OS SDK does not schedule tasks or preempt the user functions”
但在下面的這段敘述,又提到了 “User tasks”,把 Task 概念又帶進Non-OS SDK.
文中的Application functions, Callback functions 以及 Interrupt Service Routines 在原文的定義解說和
我們的認知並無不同,但要注意的是 “User tasks”。
我們的認知並無不同,但要注意的是 “User tasks”。
將這兩段和Non-OS 以及Tasks最相關敘述再放在一起看:
A: ESP8266 Non-OS SDK does schedule tasks or preempt the user functions.
B: Non-OS SDK can only support up to 3 tasks at time.
C: User tasks are normally used when a function cannot be called.
從A, B, C 這3段敘述,再加上先前code entry,細細品味後,我做了以下3點結論:
1. ESP8266 Non-OS 版本並不是單純super-loop的軟體架構;
它導入Task 以及 Task Priority的概念,甚至有Task 切換的動作,只是Task 切換的動作
不是被動被OS切換,而是主動的交出執行權。
2. Task 間的切換是透過 esp_schedule();
但為何不是 run_scheduled_functions() 而是 esp_schedule() ?
因為Trace code 後可清楚知道,run_scheduled_functions() 是 draft version, not stable,
而esp_schedule() 除了在 loop_task被執行外,在Timer()函數也會被執行。
3. ESP8266 Non-OS 版本至少存在2 個tasks;
從code entry 我們看到loop_task,而另一個task,我則認為是ESP8266 WiFi MAC ,
否則WiFi software service 要在哪裡執行? 另外一個思維是因為Espressif為了保護 WiFi MAC,
不想user call 直接呼叫WiFi MAC,所以搞出半套Task的概念,就是想利用類似Linux 的
kernel / user space 機制來保護 WiFi MAC。
1. ESP8266 Non-OS 版本並不是單純super-loop的軟體架構;
它導入Task 以及 Task Priority的概念,甚至有Task 切換的動作,只是Task 切換的動作
不是被動被OS切換,而是主動的交出執行權。
2. Task 間的切換是透過 esp_schedule();
但為何不是 run_scheduled_functions() 而是 esp_schedule() ?
因為Trace code 後可清楚知道,run_scheduled_functions() 是 draft version, not stable,
而esp_schedule() 除了在 loop_task被執行外,在Timer()函數也會被執行。
3. ESP8266 Non-OS 版本至少存在2 個tasks;
從code entry 我們看到loop_task,而另一個task,我則認為是ESP8266 WiFi MAC ,
否則WiFi software service 要在哪裡執行? 另外一個思維是因為Espressif為了保護 WiFi MAC,
不想user call 直接呼叫WiFi MAC,所以搞出半套Task的概念,就是想利用類似Linux 的
kernel / user space 機制來保護 WiFi MAC。
所以,透過以上的結論,可以清楚的知道 :
ESP8266 Non-OS 軟體版本 不等於 Super-loop 軟體執行程序,而是存在著Task 的切換
了解了這個事實後,對於在編寫ESP8266的程式時,又該如何?
Coding Suggestion
1. 雖然 ESP8266 是 Non-OS版本, 不存在 RTOS, 但還是請盡可能用 task-based 思維來 Programming。2. 使用event-driven 來設計你的程式碼為最佳。
3. 迫不得已要使用到輪詢(polling),強烈建議使用system timer function,不要使用 loop 迴圈,
那樣會block CPU ,影響Task 的切換。
4. Do not occupy CPU for more than 15ms。
Timer Task : 3rd Task ?
為了不混淆焦點,所以我把Timer Task 留在文章最後才提。
這 Timer Task 是否和 WiFi MAC 共用一個Task,或是第3個Task,我不清楚,
因為Espressif 並未釋出原始碼,但有一點很清楚,
就是” ESP8266 Non-OS 版本至少存在2 個tasks”。
這 Timer Task 是否和 WiFi MAC 共用一個Task,或是第3個Task,我不清楚,
因為Espressif 並未釋出原始碼,但有一點很清楚,
就是” ESP8266 Non-OS 版本至少存在2 個tasks”。
因為,在 ESP8266 Non-OS SDK API Reference 這份文件的Software Timer 章節就提到了,
os_timer APIs 是執行在 Task,所以加上loop_task 就至少2個Task 了。文中還提到,
因為os_timer APIs是執行在 Task,所以os_timer 函數不是很精準,想要精準的timer ,
請使用 Hardware timer,更精準的說,就是要你用hardware timer interrupt.
os_timer APIs 是執行在 Task,所以加上loop_task 就至少2個Task 了。文中還提到,
因為os_timer APIs是執行在 Task,所以os_timer 函數不是很精準,想要精準的timer ,
請使用 Hardware timer,更精準的說,就是要你用hardware timer interrupt.
所以,這又延伸出另一個問題 => delay() function 不是很準,因為它就是用os_timer 做出來的!
相信有用過ESP8266 delay() 這函數的人,對這句話都相當有感吧,尤其當你的程式愈發龐大時,
更加不精準☹☹☹。
相信有用過ESP8266 delay() 這函數的人,對這句話都相當有感吧,尤其當你的程式愈發龐大時,
更加不精準☹☹☹。
感謝閱讀,文章若對你有幫助,請點個讚,謝謝!