Làm thế nào để áp dụng RTOS vào dự án hiện tại ?? Lâu lắm mới có quay trở lại mặt đất, sau bài thần gió về lý thuyết RTOS cơ bản chắc các bạn cũng biết được sơ sơ về RTOS nó có gì, ứng dụng nó ra làm sao, nói chung là toàn gió, đọc xong rồi thôi, chẳng biết tạo 1 project thực tế thì nó như thế nào, mấy cái hướng dẫn thì ba vớ linh tinh toàn hướng dẫn blink LED xong hết. Nay mình sẽ chia sẻ 1 chút nho nhỏ về ứng dụng cụ thể RTOS các bạn làm rõ vấn đề đó

Giới thiệu

Mình vào vấn đề chính luôn, trong bài viết này sẽ gồm có 2 phần, 1 phần là dự án chưa dùng RTOS và cái sau đó là chuyển cái non-RTOS này sang RTOS, nếu bình thường thì chỉ 2 task là blink LED 1 và blink LED 2 là xong rồi, đây thì phức tạp hơn 1 xíu xiu, mình sẽ đọc gyroscope và hiển thị giá trị đó qua cổng USB, khi nghiêng ngả kit về các phía sẽ có LED sáng theo để dễ quan sát

Trong bài viết mình sẽ không nói cụ thể vào cách tạo project như thế nào nhưng sẽ có các lưu ý về cách tận dụng các nguồn sẵn có từ ST cũng như các khác biệt sau khi bạn gen code từ cubemx

Chuẩn bị

Phần cứng

  • STM32F407 Discovery (hàng có sẵn nên mình dùng)
  • 2 sợi cáp USB mini và micro cho ST-Link và USB debug (2 cổng usb có sẵn trên kit)

Phần mềm

  • CubeMX phiên bản mới nhất (nhiều bug) và thư viện cubemx cho STM32F4
  • Keil C v5 (khuyến khích dùng bản Lite hạn chế dùng lậu)
  • Teraterm
  • Virtual COM port

Project

Non-RTOS

Lời hay không bằng cho ngay cái hình, thôi các bạn nhìn hình bên dưới để biết nội dung chính mình cần làm nhé

Nhìn vào hình thì chúng ta có thể biết được việc cần làm là đọc dữ liệu từ gyro là L3GD20, con này có sẵn trên kit F4 thông qua SPI, sau đó xuất giá trị  đọc được này lên máy tính thông qua công USB VCOM (USB CDC), ngoài ra có phần GPIO để kết nối với 4 LED sẵn có, cứ nghiêng bên nào thì LED bên đó sáng

Hình minh họa về gyro trên kit và cổng USB các bạn có thể xem tham khảo

Flowchart

Flowchart của chúng ta sẽ đơn giản như sau

  • Khởi tạo USB
  • Khởi tạo gyroscope
  • Lấy dữ liệu thô từ gyroscope
  • Gửi dữ liệu này thông qua USB host
  • Xử lý dữ liệu từ gyroscope và blink với LED tương ứng

Nếu bạn muốn coi thẳng luôn trong code có gì thì có thể mở project keil MDK trong thư mục F4-Gyro lên build và nạp xuống để xem kết quả.

Nếu muốn tăng độ khó của game lên thì bạn có thể tự tạo ra một project ban đầu với các lưu ý như sau.

CubeMX

  • Tạo project với các thiết lập mặc định của F407 Discovery (Initialize all peripherals with their default Mode)
  • Chọn USB_OTG_FS ModeDevice OnlyUSB_DEVICECommunication Device Class(Virtual Port Com)
  • Các phần còn lại cứ để mặc định không sao cả, sau đó gen code

ARM Keil C

  • Chỉnh lại thư viện USB-CDC, chỗ này sau khi gen code từ cubemx có thể đã có bug làm máy tính hiện ra driver có dấu chấm than, để hết lỗi bạn có thể vào usbd_cdc.h, chỉnh lại thành1#define CDC_DATA_HS_MAX_PACKET_SIZE 64
  • Add thêm Driver BSP của STM32F4 để có thể read được data từ gyro, chúng ta cần add 4 file vào project là lis302dl.c, lis3dsh.c, stm32f4_discovery.cstm32f4_discovery_accelerometer.c, driver này bạn có thể tìm được ở C:\Users\XXX\STM32Cube\Repository\STM32Cube_FW_F4_V1.21.0\Drivers\BSP
  • Ở chương trình chính (file main.c) thì trong vòng lặp vô tận chúng ta chỉ làm 1 việc duy nhất là đọc data, delay, gửi data qua usb, kiểm tra giá trị data và blink LED.

Tương ứng với flowchart ban đầu sẽ có 1 số hàm tương ứng tượng trưng như sau

  • Khởi tạo USB (MX_USB_DEVICE_Init)
  • Khởi tạo gyroscope (BSP_ACCELERO_Init)
  • Lấy dữ liệu thô từ gyroscope (BSP_ACCELERO_GetXYZ)
  • Gửi dữ liệu này thông qua USB host(Send_Data_to_USB)
  • Xử lý dữ liệu từ gyroscope và blink với LED tương ứng (BSP_LED_On/BSP_LED_Off)

Lưu ý: Với các đoạn code trong cubemx thì các bạn nên giữ nguyên cấu trúc của code mà cubemx sinh ra, không nên xóa các comment có sẵn trong code nếu bạn còn muốn sử dụng lại code cũ và add thêm các config mới, thường code của chúng ta sẽ nằm giữa đoạn /* USER CODE BEGIN xx *//* USER CODE END xx */

Kết quả

Sau khi nạp chương trình xuống thì ta cắm usb ở cổng micro vào máy tính, kiểm tra driver ok chưa ? máy tính có nhận không ? Nếu có nghĩa là phần Init USB đã thành công.

Kết nối với teraterm và config như hình bên dưới(Setup -> Terminal chọn Receive là LF) để có thể xem được dữ liệu, tốc độ baudrate của các bạn có thể là 9600 hoặc 115200 đều được nhé, USB CDC sẽ tự config baud tương ứng với baud của bạn

Thực hiện di chuyển board để có thể quan sát được dữ liệu cảm biến thay đổi

RTOS

Sau khi đã code được cơ bản yêu cầu thì chúng ta sẽ chuyển project ở trên từ nonRTOS sang RTOS. Khi đó ứng dụng sẽ được tổ chức thành 2 task

  • Task 01 làm nhiệm vụ kết nối cổng USB, gửi dữ liệu nhận được từ gyroscope sang USB host
  • Task 02 thì sẽ đọc dữ liệu từ gyroscope và blink LED tương ứng với dữ liệu từ gyroscope này

Flowchart

Ta sẽ có hình ảnh so sánh về flow của việc không dùng và dùng RTOS

Cụ thể thì các task sẽ hoạt động như thế nào

Task 01 (USB)

  • Sau khi init ngoại vi của USB thì sẽ đợi USB host cấu hình virtual comport trước khi thực thi, nghĩa là STM32F4 cấu hình xong USB thì PC sẽ cấu hình comport ảo, kết thúc sẽ là kiểm tra hardware ta thấy nhận cổng COM, nếu lỗi thì sẽ không nhận COM hoặc có dấu chấm than vàng
  • Gửi 1 Signal tới Task 2 để thực thi
  • Lấy dữ liệu của gyroscope từ mail queue và gửi nó ra USB host
  • Tiếp tục lặp lại quá trình trên liên tục

Task 02 (Gyroscope và LED)

  • Sau khi init gyroscrope thì task 02 sẽ đợi task 01 gửi signal tới trước khi thực thi
  • Lấy data của gyroscope và gửi tới Task 01 sử dụng mail queue
  • Blink LED dựa trên data của gyroscrope

Với chương trình của RTOS này các bạn có thể tham khảo project mình đã tạo sẵn ở thư mục Gyro-RTOS

CubeMX

Nếu bạn vẫn thích em yêu khoa học như project non RTOS trên thì chúng ta copy file CubeMX đã tạo ở non-RTOS ra một chỗ khác, sau đó cấu hình thêm như sau

  • Enable RTOS bằng cách chọn FreeRTOS -> Enable
  • Đổi time base mặc định của source từ Systick sang TIM6 bằng cách SYS-> Timebase Source -> TIM6 vì FreeRTOS sẽ dùng Systick nên để tránh xung đột thì ta cho nó sang time base khác là TIM6
  • Cấu hình tab FreeRTOS
  • Thay đổi task mặc định thành task với các thông số Task01 – osPriorityNormal – 256 – StartTask01
  • Thêm một task thứ 2 với thông số Task02 – osPriorityNormal – 128 – StartTask02
  • Lưu lại và gen config

ARM Keil C

Gen code xong chúng ta phải chú ý điều chỉnh thêm ở project của Keil C thêm ít nữa

  • Add thư viện BSP vào như ở trên nonRTOS
  • Sửa bug của thư viện USB Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc/usbd_cdc. #define CDC_DATA_HS_MAX_PACKET_SIZE 64
  • Điều chỉnh lại code trong main.c
  • Define mail queue với hàm osMailQId.
  • Tạo và cấp phát bộ nhớ cho mail queue với hàm osMailQDef()osMailCreate()
  • Thêm 2 hàm USB_Task tương ứng task 01 và GYRO_Task() là task 02
  • Chỉnh lai code usbd_cdc_if.c để set signal bằng hàm osSignalSet() trong case CDC_SET_LINE_CODING, cần thêm #include "cmsis_os.h"

Bạn có thể xem các API name có thể dùng tại file cmisis_rtos.c

Kết quả

Các bạn nạp code xuống sau đó thực hiện các bước test lại như project non-RTOS và quan sát kết quả

Tạm kết

Vậy là mình đã hướng dẫn xong sơ bộ về việc code một project để đọc dữ liệu cảm biến và hiển thị giá trị đó lên PC thông qua giao tiếp USB và chuyển project này về FreeRTOS, mình nghĩ các bạn có thể đọc chút qua về lý thuyết, xem qua code của mình làm và tự thực hành việc code nonRTOS và chuyển sang RTOS, sau đó có thể áp dụng được vào cho chính dự án của các bạn. Tất nhiên trong quá trình làm sẽ có nhiều lỗi xảy ra, nếu gặp lỗi về USB bạn có thể tham khảo video về USB-CDC này để test thử (lưu ý là nhớ sửa lại code về 64 khi gen xong CubeMX nhé), ngoài ra nếu bạn còn câu hỏi nào khác có thể hỏi bên dưới bài viết, mình sẽ cố gắng hỗ trợ các bạn hết mức có thể.