- vừa được xem lúc

Stream Buffer trong FreeRTOS

0 0 2

Người đăng: delinux

Theo Viblo Asia


1. Giới thiệu về Stream Buffer

Trong hệ điều hành thời gian thực (RTOS) như FreeRTOS, Stream Buffer là một loại cơ chế truyền dữ liệu từ task này sang task khác hoặc giữa interrupt và task theo dạng luồng byte liên tục (stream of bytes).

Stream Buffer là giải pháp cực kỳ hữu ích trong các tình huống:

  • Truyền dữ liệu nhỏ và liên tục giữa các task (ví dụ: UART, SPI, CAN...)
  • Truyền dữ liệu từ ISR đến task mà không cần sử dụng queue (nhẹ hơn queue)
  • Giao tiếp giữa phần mềm với phần cứng qua DMA hoặc ngoại vi

2. Nguyên lý hoạt động

Một Stream Buffer là một vùng bộ nhớ kiểu FIFO. Task hoặc ISR sẽ ghi dữ liệu vào buffer và một task khác sẽ đọc dữ liệu này ra.

Ghi (Send) → từ một task hoặc từ ISR Đọc (Receive) → chỉ từ task (ISR không được phép đọc)

Các tính năng chính:

  • Hỗ trợ cơ chế blocking hoặc non-blocking
  • Không cần phân vùng dữ liệu như queue (dữ liệu là luồng byte thuần)
  • Có thể cấu hình trigger level để task nhận chỉ khi có đủ dữ liệu

3. Các thành phần chính

Thành phần Mô tả
xStreamBufferCreate() Tạo stream buffer
xStreamBufferSend() Gửi dữ liệu vào buffer
xStreamBufferReceive() Nhận dữ liệu từ buffer
xStreamBufferReset() Reset buffer
xStreamBufferIsFull() Kiểm tra buffer đã đầy chưa
xStreamBufferIsEmpty() Kiểm tra buffer đã rỗng chưa

4. Những lưu ý khi sử dụng Stream Buffer

4.1 Không dùng để truyền dữ liệu dạng khối rời rạc

Stream Buffer chỉ truyền dữ liệu dạng liên tục (liên byte), không hỗ trợ cấu trúc phân mảnh như Queue (phân định từng item). Nếu bạn muốn truyền các cấu trúc (struct) hoặc dữ liệu rời rạc, hãy dùng Message Buffer.

4.2 Không thể nhận dữ liệu trong ISR

Chỉ có thể gọi xStreamBufferSendFromISR() trong ngắt. Việc đọc (xStreamBufferReceive) chỉ được phép trong task.

4.3 Cẩn thận khi sử dụng Trigger Level

Trigger Level là ngưỡng byte tối thiểu để task được đánh thức khi có dữ liệu. Ví dụ:

xStreamBufferReceive(xBuffer, data, 10, portMAX_DELAY);
  • Nếu trong buffer có <10 byte, task sẽ block.
  • Chỉ khi có ≥10 byte trong buffer thì task mới được đánh thức.

⇒ Điều này giúp giảm overhead đánh thức task quá sớm nhưng cần cân nhắc kỹ.

4.4 Quản lý bộ nhớ

Stream Buffer dùng RAM nội bộ. Nếu bạn tạo nhiều buffer lớn (vd 1024 byte), hãy đảm bảo hệ thống đủ heap memory. Cấu hình trong FreeRTOSConfig.h:

#define configSUPPORT_DYNAMIC_ALLOCATION 1
#define configSTREAM_BUFFER_LENGTH_TYPE size_t

5. Mã nguồn minh họa

Mô tả:

  • Task A: Gửi dữ liệu "ABC" mỗi 2s
  • Task B: Đọc dữ liệu nếu đủ 3 byte

Code mẫu:

#include "FreeRTOS.h"
#include "task.h"
#include "stream_buffer.h"
#include <string.h>
#include <stdio.h> #define BUFFER_SIZE 64
#define TRIGGER_LEVEL 3 StreamBufferHandle_t xStreamBuffer; void vSenderTask(void *pvParameters) { const char *data = "ABC"; while (1) { size_t bytesSent = xStreamBufferSend(xStreamBuffer, data, strlen(data), pdMS_TO_TICKS(100)); printf("Sent %d bytes: %s\n", (int)bytesSent, data); vTaskDelay(pdMS_TO_TICKS(2000)); }
} void vReceiverTask(void *pvParameters) { uint8_t rxData[10]; while (1) { size_t bytesReceived = xStreamBufferReceive(xStreamBuffer, rxData, 3, portMAX_DELAY); rxData[bytesReceived] = '\0'; printf("Received %d bytes: %s\n", (int)bytesReceived, rxData); }
} int main(void) { xStreamBuffer = xStreamBufferCreate(BUFFER_SIZE, TRIGGER_LEVEL); if (xStreamBuffer == NULL) { printf("Failed to create stream buffer!\n"); while(1); } xTaskCreate(vSenderTask, "Sender", 256, NULL, 2, NULL); xTaskCreate(vReceiverTask, "Receiver", 256, NULL, 1, NULL); vTaskStartScheduler(); for (;;);
}

Kết quả trên UART console:

Sent 3 bytes: ABC
Received 3 bytes: ABC
Sent 3 bytes: ABC
Received 3 bytes: ABC

6. So sánh nhanh: Queue vs Stream Buffer vs Message Buffer

Tiêu chí Queue Stream Buffer Message Buffer
Kiểu dữ liệu item rời rạc chuỗi byte khối dữ liệu
Có thể dùng trong ISR Có (send/receive) Chỉ send Chỉ send
Blocking Receive
Ưu điểm Linh hoạt cho task-to-task Nhẹ, nhanh, phù hợp dữ liệu liên tục Truyền struct dễ dàng
Hạn chế Tốn RAM hơn Không truyền được struct trực tiếp Không đọc từ ISR

7. Ứng dụng thực tế

Truyền dữ liệu UART liên tục

DMA/ISR truyền byte vào stream buffer, task đọc và phân tích từng frame.

Truyền dữ liệu từ Sensor/ISR sang Task phân tích

Sensor update nhanh và ngắt sẽ send nhanh vài byte (vd: giá trị nhiệt độ). Task đọc, xử lý, hiển thị lên LCD.

Truyền Audio (PCM) từ ADC DMA sang xử lý FFT

ADC DMA → ISR → Stream Buffer → Task FFT

Logging hệ thống

Task gửi thông tin log (chuỗi byte) vào stream buffer. Một task duy nhất nhận và ghi vào thẻ SD hoặc gửi qua UART.


8. Kết luận

Stream Buffer là một công cụ mạnh mẽ và nhẹ nhàng cho các hệ thống nhúng cần giao tiếp dữ liệu byte liên tục. Sử dụng đúng cách giúp giảm tải CPU, giảm context switching, tăng hiệu suất truyền nhận và đơn giản hóa lập trình ISR.

Tuy nhiên, bạn cần hiểu rõ bản chất của Stream Buffer (dữ liệu byte liên tục, không phân mảnh) để dùng đúng mục đích. Nếu bạn cần truyền từng khối hoặc cấu trúc cụ thể → Message Buffer hoặc Queue sẽ phù hợp hơn.


Bình luận

Bài viết tương tự

- vừa được xem lúc

Giải mã AUTOSAR: Kiến trúc tiêu chuẩn ngành Automotive

Giới thiệu. AUTOSAR có vẻ khá xa lạ đối với người làm về công nghệ thông tin, nhưng đối với những bạn làm về Embedded System, đặc biệt là trong lĩnh vực Automotive, thì cũng.

0 0 33

- vừa được xem lúc

Từ khoá volatile trong lập trình C

Trong lập trình nhúng chắc hẵn bạn đã từng gặp phải tình huống khi chương trình C của bạn cho ra kết quả không đúng, mặc dù mã code có vẻ đúng? Một nguyên nhân có thể gây ra vấn đề này là việc tối ưu

0 0 34

- vừa được xem lúc

Giải mã AUTOSAR: Kiến trúc để đời ngành Automotive - Phần 2

Updating. Trong bài viết này, ta cùng tìm hiểu kỹ hơn về lớp trên cùng của kiến trúc, chính là lớp Application Layer (ASW).

0 0 28

- vừa được xem lúc

Con Trỏ Hàm - C/C++

Hàm Con Trỏ (Function Pointer) là gì. . Con trỏ tới hàm (A pointer to a function): Đây là biến lưu trữ địa chỉ hàm mà sau này có thể gọi bằng con trỏ này. .

0 0 25

- vừa được xem lúc

Cơ bản về WatchDog Timer trong hệ thống nhúng (Embedded System)

Khái Niệm. Trong hệ thống nhúng, a WatchDog Timer (Bộ đếm thời gian giám sát) là một thành phần hoặc tính năng của phần cứng được thiết kế để giám sát hoạt động của hệ thống và thực hiện hành động khắ

0 0 23

- vừa được xem lúc

Tối ưu hóa thời gian khởi động Nvidia Xavier

1. Vai trò.

0 0 20