部落格主頁:連結。轉載請註明出處!
由於需要在stm32上使用USB Host CDC-ECM,連線EC20傳送資料到伺服器,接觸到了ThreadX實時作業系統。
在調研過程中,發現stm32官方USB庫內只有Device ECM類,無法作為host連線網路卡;
電腦上經常使用的tinyusb,對stm裝置的device支援較差;
此外還有lrndis、TeenyUSB,提供了host ecm類的支援,但使用並不方便,且有的已很少有人維護(小開源專案難免如此)。
最終決定使用微軟的Azure RTOS ThreadX全家桶,利用NetX Duo+USBX實現對ECM網路卡的支援。ThreadX的效能和儲存佔用都最佳化得很好,且中介軟體齊全,免去了很多自己配置的麻煩。目前ThreadX已經開源,並加入CubeMX,直接使用視覺化介面就可完成配置,解決一些小坑之後十分方便,遂寫此隨筆以作記錄、分享。
本文使用的工具包括CubeMX、MDK,內容假設閱讀者已基本掌握這兩個軟體的使用。在學習過程中,參考了另兩篇教程,附上鍊接:
https://juejin.cn/post/7099829592713592840
https://blog.csdn.net/wallace89/article/details/114941859
一、CubeMX生成模板
1. 配置RCC、時鐘、SYS、GPIO
RCC設定外部晶振,這個根據板子情況調整,我這裡高低速都是外部晶振
時鐘配置,和平時一樣,可以輸入HCLK讓cubemx自動設定,也可手動調,48MHz時鐘一定要有
系統設定內,debug根據板子設定,我使用的是jlink的SW除錯口,所以選擇serial wire。時基源選擇任意一個沒用到的TIM。
最後配置板子上三個LED燈的GPIO,根據自己板子上情況修改。
2. 配置串列埠和USB
根據板子,配置串列埠用於除錯
配置USB FS,用於和EC20通訊
3. 重頭戲:配置Azure RTOS
首先安裝所需軟體包
我用的MCU是stm32f4系列,因此找到AZRTOS-F4。勾選Core以及需要使用的USBX-UX Host Class CDC ECM,會提示所選的包還有依賴項沒選上,根據提示補齊。如果不需要USB和網路,只選擇threadx core就行.
回到主介面,可以看到左邊X-CUBE-AZRTOS-F4變得可選,點選開啟配置。
可以根據需要修改配置,我這裡基本保持預設,後面有需求再修改。
4. 生成專案模板
常規操作,注意:1. IDE選用自己使用的;2. 增大堆疊,我均改為0x2000;3. .c/.h分開
二、Keil內編寫跑馬燈程式碼
1. 編輯app_azure_rtos.h
增加對GPIO、串列埠、printf的支援,程式碼:
/* USER CODE BEGIN Includes */
#include "main.h"
#include "stdio.h"
#include "usart.h"
#if 1
__asm__(".global __use_no_semihosting");
FILE __stdout;
//define function _sys_exit() to avoid using semi-hosting mode
void _sys_exit(int x)
{
x = x;
}
//redefine function fputc to redirect output
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart6, (uint8_t *)&ch, 1, 0x10);
return ch;
}
#endif
/* USER CODE END Includes */
增加執行緒函式申明
/* USER CODE BEGIN EFP */
void app1_LED123(ULONG thread_input);
/* USER CODE END EFP */
2. 編輯app_azure_rtos.h
檔案前面增加執行緒引數設定
/* USER CODE BEGIN PD */
//defination of app1
#define APP1_PRIO 15u //優先順序,越大越不優先
#define APP1_STACKSIZE 1024u //堆疊大小,注意大於cubemx內設定的最低大小
static TX_THREAD app1_TCB; //執行緒控制塊
static uint8_t app1_STACK[APP1_STACKSIZE]; //堆疊
/* USER CODE END PD */
在 tx_application_define函式內,增加建立執行緒的操作,並串列埠顯示建立狀態。
/* USER CODE BEGIN tx_application_define */
printf("tx_application_define\n");
UINT status = tx_thread_create(&app1_TCB,
"app1_led123",
app1_led123,
0,
&app1_STACK[0],
APP1_STACKSIZE,
APP1_PRIO,
APP1_PRIO,
TX_NO_TIME_SLICE,
TX_AUTO_START);
printf("thread create status:%d\n", status);
/* USER CODE END tx_application_define */
這裡遇到一個坑,我的堆疊大小起初設定得低於cubemx中指定的400B,因此執行緒建立失敗。可透過status的值判斷是否是執行緒建立失敗導致的問題。
最後,在檔案末尾編寫跑馬燈執行緒程式碼:
/* USER CODE BEGIN 0 */
void app1_led123(ULONG thread_input)
{
printf("app1_led123 start\n");
while(1) {
HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
tx_thread_sleep(10);
HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
tx_thread_sleep(10);
HAL_GPIO_TogglePin(LED3_GPIO_Port, LED3_Pin);
tx_thread_sleep(10);
}
}
/* USER CODE END 0 */
3. 設定編譯和除錯引數
在魔法棒內設定使用v6編譯器、勾選上microlib。debug選項卡內也選擇自己使用的偵錯程式。
v6編譯器的速度快了相當多,尤其是在帶RTOS的專案裡,需要選上。
設定完成,即可編譯下載,執行自己的程式!
——————THE END——————
部落格主頁:連結。轉載請註明出處!