- CMSIS (Common Microcontroller Software Interface Standard) là Tiêu chuẩn Giao Diện phần mềm Vi Điều Khiển, một tiêu chuẩn được phát triển bởi ARM để đơn giản hóa việc phát triển phần mềm cho các vi điều kiển lõi Cortex ARM M/A
- CMSIS có nhiều thành phần: Driver, DSP, Core, NN, Device,...và trong đó CMSIS-RTOS là tiêu chuẩn giao diện lập trình của hệ điều hành thời gian thực (RTOS)
Thành phần | Mô tả |
---|---|
FreeRTOS | Là hệ điều hành thời gian thực RTOS mã nguồn mở, cung cấp API riêng để tạo task, queue, semaphore,... |
CMSIS-RTOS | Là lớp trừu tượng hóa (Abstraction Layer) do ARM thiết kế để cung cấp một bộ API RTOS chung có thể dùng mọi RTOS khác nhau (FreeRTOS, RTX, Zephyr,...) |
CMSIS-RTOS v1/v2 | Là hai phiên bản khác nhau của chuẩn CMSIS-RTOS. STM32 hỗ trợ cả hai, nhưng v2 là bản mới hơn, hỗ trợ nhiều tính năng và tương thích với HAL/STM32_WPAN |
- Khi dùng
"FreeRTOS.h"
cần include nhiều thư viện như"task.h"
,"queue.h"
,"semphr.h"
- CMSIS-V1 (2013) là API được chuẩn hóa từ FreeRTOS API thành
"cmsis_os.h"
. Chỉ cần khai báo thế thôi là đủ. - CMSIS-V2 (2018) là phiên bản nâng cấp của V1, hỗ trợ nhiều tính năng hơn và tích hợp các gói Middleware cho BLE, USB, FATFS, LoRa, ThreadX,...để có thể dùng chung API RTOS của CMSIS-RTOS thay vì dùng FreeRTOS trực tiếp, thư viện khi đó sẽ là
"cmsis_os2.h"
ỨNG DỤNG NGƯỜI DÙNG (User App)
│
├── Gọi API CMSIS-RTOS (osThreadNew, osDelay, osMessageQueue...)
│
├── Lớp Adapter (CMSIS-RTOS → FreeRTOS)
│
└── FreeRTOS Kernel (xTaskCreate, vTaskDelay, xQueueSend...)
- Trước khi có CMSIS-RTOS, mỗi RTOS đều có API riêng:
RTOS | Ví dụ hàm tạo task |
---|---|
FreeRTOS | xTaskCreate() |
Keil RTX | os_tsk_create() |
µC/OS-II | OSTaskCreate() |
ThreadX | tx_thread_create() |
Zephyr | k_thread_create() |
- Điều này dẫn đến vấn đề: Khi bạn muốn chuyển sang RTOS khác -> Toàn bộ code ứng dụng phải viết lại, vì API khác nhau hoàn toàn
👉GIẢI PHÁP: ARM phải tạo ra CMSIS để thống nhất các API lại thành 1 chuẩn cho mọi vi điều khiển Cortex-M
Trong FreeRTOS tạo task bằng cách truyền các tham số vào hàm:
void task(void *pvParameters);
TaskHandle_t taskHandle = NULL;
xTaskCreate("task_name", task, 128, NULL, 1, &taskHandle);
Trong CMSIS-V1, việc tạo task dùng struct osThreadDef()
và con trỏ kiểu C:
osThreadDef(task_name, task, osPriorityNormal, 1, 0);
osThreadId taskHandle = osThreadCreate(osThread(task_name), NULL);
osKernelStart(); // Bat dau chạy task
Còn CMSIS-V2 thì chuyển sang dạng object handle + attribute struct:
void task(void *pvParameters);
const osThreadAttr_t task_attr = {
.name = "task_name",
.stack_size = 512,
.priority = (osPriority_t)osPriorityNormal
};
osThreadId_t taskHandle = osThreadNew(task, NULL, &task_attr);
- Dưới lớp CMSIS-V2, vẫn là FreeRTOS gốc.
- Các hàm như
osThreadNew()
thực chất gọi lạixTaskCreateStatic()
hoặcxTaskCreate()
- Do đó, nếu bạn dùng CMSIS-V2 hay CMSIS-V2, bạn không nên pha lẫn các API của FreeRTOS gốc vì CMSIS-RTOS có quản lý riêng các Object ID (handle)
Chức năng | FreeRTOS API (gốc) | CMSIS-RTOS V1 | CMSIS-RTOS V2 |
---|---|---|---|
Tạo task | xTaskCreate() |
xTaskCreatePinnedToCore() |
osThreadCreate() |
Bắt đầu Scheduler | vTaskStartScheduler() |
osKernelStart() |
osKernelStart() |
Delay | vTaskDelay() |
osDelay() |
osDelay() |
Semaphore tạo | xSemaphoreCreateBinary() |
osSemaphoreCreate() |
osSemaphoreNew() |
Semaphore lấy | xSemaphoreTake() |
osSemaphoreWait() |
osSemaphoreAcquire() |
Semaphore trả | xSemaphoreGive() |
osSemaphoreRelease() |
osSemaphoreRelease() |
Queue tạo | xQueueCreate() |
osMessageCreate() |
osMessageQueueNew() |
Queue gửi | xQueueSend() |
osMessagePut() |
osMessageQueuePut() |
Queue nhận | xQueueReceive() |
osMessageGet() |
osMessageQueueGet() |
Mutex tạo | xSemaphoreCreateMutex() |
osMutexCreate() |
osMutexNew() |
Mutex lấy | xSemaphoreTake() |
osMutexWait() |
osMutexAcquire() |
Mutex trả | xSemaphoreGive() |
osMutexRelease() |
osMutexRelease() |
Timer tạo | xTimerCreate() |
osTimerCreate() |
osTimerNew() |
Start Timer | xTimerStart() |
osTimerStart() |
osTimerStart() |
Lấy tên task | pcTaskGetTaskName() |
như FreeRTOS | osThreadGetName() |
Lấy ID task | xTaskGetCurrentTaskHandle() |
osThreadGetId() |
osThreadGetId() |