Hướng dẫn tích hợp hệ điều hành uCOS-III vào dự án STM32 HAL

Quy trình chuyển đổi từ chương trình chạy trực tiếp (Bare-metal) sang RTOS

Việc tích hợp uCOS-III vào một dự án STM32 hiện có (sử dụng thư viện HAL và trình biên dịch MDK ARM) đòi hỏi sự thay đổi đồng bộ từ cấu trúc thư mục, tệp tin cấu hình đến logic điều khiển luồng trong Driver (BSP). Phương pháp tiếp cận hiệu quả nhất là so sánh sự khác biệt giữa phiên bản Bare-metal và phiên bản đã chạy uCOS-III để xác định các module cần điều chỉnh.

1. Cấu trúc thư mục và đường dẫn Include

Để trình biên dịch nhận diện được nhân hệ điều hành, cần bổ sung các đường dẫn chứa tệp tiêu đề (.h) vào mục cấu hình Project:
  • ....\uCOS-III\uC-CPU
  • ....\uCOS-III\uC-CPU\ARM-Cortex-M\ARMv7-M\RealView
  • ....\uCOS-III\uC-LIB
  • ....\uCOS-III\uCOS-III\Source
  • ....\uCOS-III\uCOS-III\Ports\ARM-Cortex-M\ARMv7-M\RealView
Đồng thời, mã nguồn uCOS-III phải được tổ chức thành các nhóm (Groups) trong IDE bao gồm: uC-CPU, uC-LIB, và uCOS-III Source/Ports.

2. Điều chỉnh hệ thống đếm thời gian (Timer)

Trong môi trường RTOS, SysTick thường được dành riêng cho nhân hệ điều hành. Do đó, logic khởi tạo Timer cần tách biệt dựa trên trạng thái của hệ thống thông qua một macro định nghĩa (ví dụ: RTOS_SDK_EN).
void ConfigSystemTimer(void)
{
    /* ... logic cấu hình khác ... */
    
#if RTOS_SDK_EN == 0
    // Nếu không dùng OS, cấu hình SysTick mặc định 1ms
    SysTick_Config(SystemCoreClock / 1000);
#endif
}

void Delay_Ms(uint32_t delay_val)
{
#if RTOS_SDK_EN == 1
    OS_ERR err;
    // Sử dụng hàm delay của OS để giải phóng CPU cho task khác
    OSTimeDlyHMSM(0, 0, 0, delay_val, OS_OPT_TIME_HMSM_STRICT, &err);
#else
    // Sử dụng vòng lặp hoặc timer cơ bản nếu không có OS
    Software_Wait_Ms(delay_val);
#endif
}

3. Quản lý vùng tranh chấp (Critical Sections) trong Driver

Các Driver ngoại vi như UART, I2C cần đảm bảo tính toàn vẹn dữ liệu khi có nhiều Task cùng truy cập. Việc sử dụng macro CPU_SR_ALLOC() là bắt buộc để quản lý thanh ghi trạng thái CPU khi vào/ra vùng bảo vệ.
static void UART_Transmit_Data(UART_Handler *dev, uint8_t *data, uint16_t size)
{
#if RTOS_SDK_EN == 1
    CPU_SR_ALLOC();
    CPU_CRITICAL_ENTER(); // Ngắt tất cả các ưu tiên thấp hơn để bảo vệ dữ liệu
#endif

    for(uint16_t idx = 0; idx < size; idx++) {
        // Thực hiện gửi dữ liệu
    }

#if RTOS_SDK_EN == 1
    CPU_CRITICAL_EXIT();
#endif
}

4. Tối ưu hóa hàm trễ Micro giây (Microsecond Delay)

Trong RTOS, các hàm delay ngắn (us) thường không nên dùng cơ chế Task Switching vì overhead lớn. Thay vào đó, hãy sử dụng chu kỳ đếm của CPU (DWT hoặc TS Counter) để đạt độ chính xác cao.
void Precise_Delay_US(uint32_t microseconds)
{
    uint32_t start_cycles, current_cycles;
    uint32_t total_required_cycles;
    
    start_cycles = (uint32_t)CPU_TS_TmrRd(); 
    total_required_cycles = microseconds * (SystemCoreClock / 1000000); 
    
    do {
        current_cycles = (uint32_t)CPU_TS_TmrRd() - start_cycles;
    } while(current_cycles < total_required_cycles);
}

5. Cấu hình Macro điều khiển trong bsp.h

Tạo một tệp tiêu đề chung để điều phối việc sử dụng tài nguyên giữa BSP và OS. Điều này giúp mã nguồn linh hoạt, có thể dễ dàng tắt/mở OS mà không cần sửa quá nhiều vị trí.
#define RTOS_SDK_EN 1

#if RTOS_SDK_EN == 1    
    #include "os.h"   
    #define LOCK_INTERRUPTS()    CPU_CRITICAL_ENTER()
    #define UNLOCK_INTERRUPTS()  CPU_CRITICAL_EXIT()
#else
    #define LOCK_INTERRUPTS()    __disable_irq()
    #define UNLOCK_INTERRUPTS()  __enable_irq()
#endif

6. Các tệp tin cấu hình ứng dụng bắt buộc

Ngoài mã nguồn nhân (Kernel), các tệp sau đây đóng vai trò cấu hình thông số hoạt động của uCOS-III:
  • app_cfg.h: Cấu hình mức ưu tiên và kích thước Stack cho các Task ứng dụng.
  • os_cfg.h: Bật/tắt các tính năng của Kernel (Semaphore, Mutex, Message Queue).
  • cpu_cfg.h: Định nghĩa các tham số liên quan đến CPU và bộ đếm thời gian.
  • os_app_hooks.c: Nơi chứa các hàm Hook khi hệ thống khởi tạo, chuyển đổi Task hoặc CPU nhàn rỗi.
Đối với dòng STM32H7 hoặc các chip có bộ đệm (Cache), cần lưu ý cấu hình MPU_ConfigCPU_CACHE_Enable trong hàm khởi tạo hệ thống để đảm bảo tính nhất quán dữ liệu khi sử dụng DMA kết hợp với RTOS.

Thẻ: uCOS-III STM32 HAL-Library RTOS embedded-systems

Đăng vào ngày 18 tháng 8 lúc 14:02