Hệ điều hành thời gian thực cho các hệ thống nhúng Hệ điều hành thời gian thực (RTOS) cho các hệ thống nhúng rất khác so với hệ điều hành trên máy tính desktop như Windows hay UNIX : Thứ nhất, trên máy tính desktop hệ điều hành sẽ chiếm quyền điều khiển ngay sau khi máy được bật và sau đó mới cho chúng ta bắt đầu ứng dụng của mình. Chúng ta biên dịch và liên kết các ứng dụng của mình tách biệt với hệ điều hành. Ngược lại, trong một hệ thống nhúng, ứng dụng thường xuyên liên kết với RTOS. Tại lúc khởi động, ứng dụng nhận lấy quyền điều khiển đầu tiên và sau đó nó mới bắt đầu RTOS. Bởi vậy ứng dụng và RTOS phải có mối quan hệ chặt chẽ hơn. Thứ hai, rất nhiều RTOS không bảo vệ chính bản thân chúng một cách cẩn thận như hệ điều hành trên desktop. Thứ ba, để tiết kiệm bộ nhớ các RTOS mặc định chỉ bao gồm các dịch vụ cần thiết cho ứng dụng nhúng của chúng ta. Hầu hết các RTOS cho phép chúng ta cấu hình bao quát trước khi chúng ta liên kết chúng với ứng dụng. Thứ tư, hầu hết các điều hành trên máy desktop quan tâm đến hiệu năng trung bình trong khi các hệ điều hành thời gian thực lại quan tâm đến các giới hạn, thời gian đáp ứng. Ở trong phần này, chúng ta tìm hiểu khái niệm tác vụ - Task trong môi trường RTOS và vấn đề chia sẻ dữ liệu, semaphores, mailbox, queue… Ngoài ra, chúng ta còn xem xét vấn đề truyền thông liên quá trình, dịch vụ bộ định thời, quản lý bộ nhớ và tương tác giữa các thủ tục ngắt.Các hệ điều hành thời gian thực nhấn mạnh đến khả năng dự đoán và các ràng buộc về thời gian đáp ứng. Nói chung, hệ điều hành thời gian thực thường được phân thành ba kiểu lại chính là:
I. Giới thiệu 1. Sự cần thiết của RTOS và đặc điểm của một RTOS Do các yêu cầu khắt khe về thời gian, về việc sử dụng tài nguyên, và sự quan trọng của việc lập lịch, các RTOS đóng vai trò rất quan trọng trong phát triển hệ nhúng thời gian thực. Chúng giống như những thư viện, chúng ta có thể dùng, thêm bớt các dịch vụ cho phù hợp với ứng dụng nhúng thời gian thực để có thể phát triển ứng dụng nhúng thời gian thực một cách nhanh hơn, tin tưởng hơn. Vì vậy sự tồn tại của các RTOS là rất cần thiết và quan trọng. Trước khi xem xét các dịch vụ của hệ điều hành thời gian thực xác định, ta cần biết như thế nào để có thể đánh giá đây là hệ điều hành thời gian thực tốt, phù hợp với các ứng dụng nhúng thời gian thực của ta. Theo FQA cho comp.realtime: Một RTOS tốt chỉ khi có một nhân tốt. Một RTOS tốt sẽ có một tài liệu tốt và được phân phát cùng các công cụ tốt để phát triển và vận hành ứng dụng của chúng ta. Vì vậy, các tính toán về khoảng thời gian ngắt và thời gian chuyển mạch ngữ cảnh là rất quan trọng, cùng với các thông số khác làm nên một RTOS tốt. Cho ví dụ, một RTOS hỗ trợ nhiều dịch vụ có nhiều thuận lợi hơn một RTOS đơn giản. Thêm vào đó, có những đặc tả chính xác là rất quan trọng để nhận ra RTOS tốt. Theo comp.realtime thì các nhà sản xuất RTOS nên chỉ rõ các yếu tố: 1. Khoảng thời gian trễ ngắt - Interrupt Latency: là khoảng thời gian từ lúc ngắt tới lúc chạy tác vụ. Khoảng thời gian này phải tương thích với các đòi hỏi của
ứng dụng và phải dự đoán được. Các giá trị này phụ thuộc trên số lượng của các ngắt đồng thời chờ đợi. 2. Cho mỗi lời gọi hệ thống, thời gian tối đa được biết trước. Nó sẽ có thể đoán và không phụ thuộc vào số lượng các đối tượng trong hệ thống. 3. Thời gian cực đại của RTOS và điều khiển các mặt nạ ngắt. 4. Các mức ngắt hệ thống. 5. Trình thiết bị điều khiển các ngắt (IRQ: Interrupt ReQuest), thời gian cực đại của hệ thống mà trình thiết bị điều khiển ngắt thực hiện. Hệ điều hành thời gian thực tương tự như một hệ điều hành đa mục đích và cung cấp các chức năng như:
+ Giao tiếp với phần cứng ở lớp dưới + Lập lịch và xử lý ưu tiên + Quản lý bộ nhớ + Các dịch vụ vào ra + Hỗ trợ sự lựa chọn bộ vi xử lý + Tính khả chuyển tới các bộ vi xử lý khác + Tính mềm dẻo để phù hợp với các yêu cầu ứng dụng khác nhau + Hỗ trợ bộ đa vi xử lý + Mở rộng các dịch vụ như hỗ trợ mạng Theo những tiêu chuẩn POSIX - Một khuynh hướng giúp những nhà thiết kế di chuyển từ hệ điều hành thời gian thực này tới hệ điều hành thời gian thực khác. Đặc biệt, bất cứ RTOS nào tuân theo chuẩn POSIX đều chia sẻ một chuẩn API (giao diện lập trình ứng dụng). LynxOS là một RTOS tuân theo đầy đủ chuẩn POSIX. Một RTOS thường có tính mềm dẻo và có tính cấu trúc. Nó cho phép tích hợp thêm các dịch vụ gia tăng theo vòng tròn đồng tâm. Vòng trong cùng hay nhân cung cấp những đặc tính quan trọng nhất của hệ điều hành thời gian thực. Các đặc điểm khác có thể được thêm vào như một vòng ngoài khi cần thiết. Nhân nhỏ của một RTOS thích hợp cho một ứng dụng bộ xử lý nhỏ, trong khi những vòng ngoài có thể giúp đỡ xây dựng hệ thống thời gian thực lớn. Các RTOS thường cung cấp các mức xử lý ưu tiên. Các công việc ưu tiên cao hơn sẽ được thực hiện trước. Các RTOS thích hợp với các yêu cầu của hệ thống nhúng. Nó cung cấp khởi động từ ROM, cho những hệ thống không có bất cứ đĩa lưu trữ nào, như vậy giảm một cách đáng kể thời gian khởi động của hệ thống. Một vài ví dụ của các hệ điều hành thời gian thực là: VxWorks, QNX, LynxOS, µCOS, RTX-51… 2. Phân loại hệ điều hành thời gian thực
+ Hệ điều hành thời gian thực nhỏ với mục đích thương mại. + Hệ điều hành thời gian thực mở rộng tới UNIX và các hệ điều hành khác. + Các nhân cho mục đích nghiên cứu. a. Hệ điều hành thời gian thực nhỏ với mục đích thương mại Các hệ điều hành này thường nhỏ và nhanh. Như: QNX, PDOS, pSOS, VxWorks, Nulceus, ERCOS, EMERALDS, Windows CE, chúng có các đặc điểm
sau: + Có thời gian chuyển ngữ cảnh và thời gian đáp ứng nhanh. + Kích thước rất nhỏ. + Không có bộ nhớ ảo và có thể cố định mã, dữ liệu trong bộ nhớ. + Hệ thống đa tác vụ và chuẩn giao tiếp liên quá trình. Các mailbox, các sự kiện, các tín hiệu và các đèn báo được định nghĩa tốt. Những hệ điều hành này thường có các đặc tả tốt và có các công cụ tốt để phát triển các ứng dụng nhúng thời gian thực. Nó hỗ trợ các ràng buộc thời gian thực với các dịch vụ như: + Các giới hạn thời gian thực hiện. + Đồng hồ thời gian thực. + Lập lịch thứ tự ưu tiên. + Cảnh báo đặc biệt và thời gian quá hạn (timeout). + Hỗ trợ các hàng đơi thời gian thực. + Cung cấp việc xử lý độ trễ, treo hay kích hoạt việc thực hiện. b. Hệ điều hành thời gian thực mở rộng tới Unix và các hệ điều hành khác Các hệ điều hành này như: RT-UNIX, RT-LINUX, RT-MACH, RT-POSIX. Chúng chậm hơn và có khả năng dự đoán ít hơn so với các hệ điều hành thời gian thực thương mại ở trên nhưng chúng lại có nhiều chức năng và môi trường phát triển tốt hơn dựa trên tập các giao tiếp chuẩn và thân thiện. c. Các nhân cho mục đích nghiên cứu Các hệ điều hành này có các đặc điểm sau: + Hỗ trợ các thuật toán lập lịch thời gian thực và việc phân tích thời gian. + Hỗ trợ các dịch vụ cơ bản để đồng bộ thời gian thực. + Nhấn mạnh khả năng dự đoán hơn là hiệu năng trung bình. + Hỗ trợ cho khả năng chịu lỗi. Ví dụ như: Spring, MARS, HARTOS, MARUTI, ARTS, CHAOS, DARK. II. Các dịch vụ cơ bản 1. Tác vụ và các trạng thái tác vụ Xây dựng các khối cơ bản của phần mềm dưới RTOS là tác vụ - Task. Việc tạo ra các tác vụ dưới RTOS là rất đơn giản. Một tác vụ đơn giản chỉ là một thủ tục con. Tại một số điểm trong chương trình, chúng ta thực hiện một hoặc nhiều lời gọi tới một hàm trong RTOS để bắt đầu các tác vụ. Mỗi tác vụ trong RTOS luôn luôn ở một trong ba trạng thái chính: 1. Running: Với ý nghĩa bộ xử lý đang thực hiện tác vụ. Với một bộ xử lý thì chúng ta chỉ chạy một tác vụ tại một thời điểm nhất định. 2. Ready: Với ý nghĩa một số tác vụ khác sẵn sàng chạy nếu bộ xử lý rỗi. 3. Blocked: Với ý nghĩa tác vụ không sẵn sàng chạy kể cả khi bộ xử lý trong trạng thái nghỉ - Idle. Tác vụ ở trong trạng thái này vì chúng đợi một sự kiện bên ngoài tác động để kích hoạt nó trở lại trạng thái sẵn sàng. 2. Bộ lập lịch
Một phần của RTOS được gọi là bộ lập lịch, lưu vết các trạng thái của mỗi tác vụ và quyết định một tác vụ duy nhất sẽ đi vào trạng thái Running. Không giống như bộ lập lịch trong Windows hay UNIX, bộ lập lịch trong hầu hết các RTOS là khá đơn giản: Chúng nhìn vào mức ưu tiên được gán tới mỗi tác vụ và giữa những tác vụ đang sẵn sàng một tác vụ có mức ưu tiên cao nhất sẽ được thực hiện. Bộ lập lịch sẽ phục vụ tác vụ nào có mức ưu tiên cao hơn trong khi các tác vụ ưu tiên thấp hơn sẽ đợi cho đến khi giải phóng bộ xử lý khỏi tác vụ ưu tiên cao hơn. Bộ lập lịch giúp chúng ta biết tác vụ nào phải làm trước khi chúng ta thiết lập thứ tự ưu tiên. Để bộ lập lịch biết được tác vụ nào khoá và sẵn sàng thì RTOS cung cấp một tập các hàm mà tác vụ có thể gọi để bộ lập lịch nhận biết được các sự kiện mà các tác vụ này đang đợi tín hiệu để sự kiện xảy ra đó. Nếu tất cả tác vụ đều bị khoá, không thể chờ được tín hiệu nào làm cho các tác vụ trở lại trạng thái sẵn sàng bên trong hay bên ngoài RTOS thì ta nói rằng hệ thống của chúng ta bị hỏng, phần mềm chúng ta thiết kế bị lỗi. Nếu hai tác vụ cùng mức ưu tiên sẵn sàng, thì nó phụ thuộc vào cách xử lý của RTOS mà chúng ta sử dụng. Ít nhất một hệ thống giải quyết vấn đề này là việc không bao giờ cho phép hai tác vụ có cùng mức ưu tiên, một số khác sử dụng phân chia thời gian (time-slice) giữa các tác vụ đó, một số khác lại chạy một tác vụ bất kỳ cho đến khi nó bị khoá. Nếu một tác vụ đang chạy, có một tác vụ khác ưu tiên cao hơn được kích hoạt thì RTOS sẽ dừng tác vụ đang chạy và sẽ chạy tác vụ ưu tiên cao hơn kia. Tác vụ có mức ưu tiên thấp hơn sẽ khoá. 3. Tác vụ và dữ liệu Mỗi tác vụ có một ngữ cảnh riêng, bao gồm giá trị thanh ghi, bộ đếm chương trình và một stack. Tất cả những dữ liệu khác được chia sẻ giữa các tác vụ. Khi chúng ta sử dụng biến chia sẻ dữ liệu giữa các tác vụ, điều đó rất dễ dàng để chuyển dữ liệu từ tác vụ này tới tác vụ khác: hai tác vụ cần phải truy nhập tới cùng biến. Tuy nhiên, vấn đề chia sẻ dữ liệu rất dễ dẫn tới việc không nhất quán trong chương trình và có thể gây sụp đổ hệ thống của chúng ta, vì vậy cần có các biện pháp trong RTOS để giải quyết vấn đề này. 4. Đèn báo và chia sẻ dữ liệu (Semaphore) Semaphore có thể giải quyết vấn đề trong chia sẻ dữ liệu. Khi đó chỉ có một tác vụ có thể nắm quyền sử dụng đèn báo tại một thời điểm. Các tác vụ khác dù có ưu tiên cao hơn vẫn phải chờ đến khi giải phóng đèn báo vì vậy mà đèn báo có thể ngăn chặn việc chia sẻ dữ liệu dẫn đến lỗi. Đèn báo có hai hàm liên quan là take và release. Hàm take nắm lấy quyền sử dụng đèn báo tại thời gian đó và hàm release là hàm giải phóng đèn báo sau khi sử dụng xong. Chúng ta có thể sử dụng đèn báo như tín hiệu để giao tiếp giữa các tác vụ với nhau hoặc giữa hàm ngắt và tác vụ. Tuy đèn báo không thể giải quyết mọi vấn đề về chia sẻ dữ liệu nhưng hệ thống của chúng ta có thể làm việc tốt hơn, ít thời gian hơn khi chúng ta sử dụng đèn báo. Vấn đề ở đây là đèn báo chỉ làm việc tốt khi chúng ta sử dụng chúng đúng đắn. Nhưng trong thực tế thì chúng ta gặp phải một số vấn đề như:
- Quên lấy quyền sử dụng đèn báo trước khi sử dụng. - Quên giải phóng đèn báo khi sử dụng xong, điều đó có thể gây ra treo chương trình của chúng ta. - Nắm lấy quyền sử dụng đèn báo lỗi. Nếu chúng ta đang sử dụng nhiều đèn báo, thì việc lấy quyền sử dụng đèn báo còn phụ thuộc vào các đèn báo khác, đôi khi chúng ta quên nên gây ra lỗi rất lớn. - Giữ một đèn báo trong thời gian quá lâu. Vấn đề này có thể vi phạm thời gian đáp ứng trong hệ thống nhúng thời gian thực của chúng ta. Một vấn đề được gọi là thứ tự ưu tiên đảo ngược (Priority Inversion), nếu tác vụ C có mức ưu tiên thấp đang giữ đèn báo và phải nhường quyền sử dụng bộ xử lý cho tác vụ B có quyền ưu tiên trung bình. Và một tác vụ có quyền ưu tiên cao là A muốn sử dụng đèn báo mà C đang nắm giữ, nhưng C không thể giải phóng cho đến khi nó chiếm quyền sử dụng bộ xử lý. Một số RTOS giải quyết vấn đề này bằng cách kế thừa mức ưu tiên, chúng tạm thời nâng mức ưu tiên tác vụ C để chạy và giải phóng đèn báo cho tác vụ A. III. Các dịch vụ mở rộng của RTOS thương mại 1. Message Queues, Mailboxes và Piles a. Hàng đợi - Queue Các tác vụ phải có khả năng giao tiếp với nhau để kết hợp các hoạt động và để chia sẻ dữ liệu. Hầu hết RTOS kết hợp của một số dịch vụ như: hàng các đợi thông điệp, các mailboxe, các pipe cho mục đích này. Tính năng xác định của các dịch vụ này phụ thuộc vào RTOS, chúng ta phải đọc hướng dẫn mà RTOS đó đưa ra. Hầu hết RTOS yêu cầu chúng ta phải khởi tạo hàng đợi trước khi chúng ta sử dụng chúng bằng việc gọi hàm cung cấp cho mục đích này. Một số hệ thống cho phép chúng ta cấp phát bộ nhớ mà RTOS sẽ quản lý như một hàng đợi. Hầu hết các RTOS cho phép ta sử dụng nhiều hàng đợi nếu chúng ta muốn. Chúng ta thêm một số thông số để định danh hàng đợi và từ đó chúng ta có thể đọc, ghi vào hàng đợi đó. Nếu chúng ta cố ghi vào hàng đợi khi nó đã đầy, RTOS sẽ trả lại một thông báo lỗi để chúng ta biết hoạt động đó bị hỏng hoặc là hoạt động đó phải bị khoá cho đến khi có một tác vụ đọc dữ liệu khỏi hàng đợi. Rất nhiều RTOS sử dụng một hàm để đọc từ một hàng đợi nếu có dữ liệu trong hàng đợi và sẽ trả ra một lỗi nếu hàng đợi rỗng. Và hàm này sẽ ở trạng thái khoá (block) nếu hàng đợi rỗng. Số byte dữ liệu mà RTOS ghi vào hàng đợi trong một lời gọi có thể không chính xác với số byte dữ liệu chúng ta muốn ghi. Rất nhiều RTOS không mềm dẻo về vấn đề này nhưng có một số RTOS cho phép chúng ta ghi lên một hàng đợi trong một lần gọi số lượng byte mang đến bằng một con trỏ hàm. b. Mailbox Nói chung, mailbox là giống hàng đợi. Mặc định RTOS có các hàm để tạo, đọc và ghi vào mailbox và có lẽ các hàm này sẽ kiểm tra xem mailbox có chứa được hay không bất kỳ một thông điệp nào. Khi mailbox không cần thiết nữa thì nó sẽ
được huỷ để giải phóng bộ nhớ. Trong các RTOS thì mailbox có những đặc điểm riêng: + Một số RTOS cho phép chính xác số lượng thông điệp trong mỗi mailbox, con số này chúng ta có thể chọn khi tạo mailbox, một số khác thì chỉ cho phép một thông điệp trong một mailbox tại một thời điểm. Một thông điệp được ghi tới mailbox, mailbox sẽ đầy khi đó các thông điệp khác chỉ có thể ghi tới mailbox khi thông điệp đầu được đọc. + Trong một số RTOS, số lượng của thông điệp trong mỗi mailbox là không bị giới hạn. Chỉ có một giới hạn là tổng số thông điệp trong tất cả các mailbox trong hệ thống. + Trong một số RTOS, chúng ta có thể ưu tiên các thông điệp trong mailbox. Các thông điệp ưu tiên cao hơn sẽ được đọc trước các thông điệp có ưu tiên thấp hơn, không phụ thuộc vào thứ tự chúng được ghi vào mailbox. c. Pipe Các pipe cũng rất giống hàng đợi. RTOS có thể tạo chúng, ghi lên chúng, đọc từ chúng… Nhưng trong mỗi RTOS chúng cũng có những đặc điểm riêng: + Một số RTOS cho phép chúng ta ghi thông điệp với độ dài tuỳ ý lên trên pipe (không giống như mailbox và queue độ dài thông điệp là cố định). + Pipe trong một số RTOS là toàn bộ hướng byte: Nếu task A ghi 11 byte tới pipe và sau đó task B ghi 19 byte tới pipe, sau đó nếu task C đọc 14 byte từ pipe, nó sẽ nhận được 11 byte của task A đã ghi cộng với 3 byte đầu tiên mà task B đã ghi. + Một số RTOS sử dụng hàm thư viện chuẩn C là fread và fwrite để đọc và ghi tới pipe. d. Sử dụng queue, mailbox, pipe Mặc dù queue, mailbox, pipe có thể làm vấn đề chia sẻ dữ liệu giữa các tác vụ trở lên dễ dàng hơn nhưng nó cũng rất dễ gây ra lỗi trong hệ thống của chúng ta. Đây là một số kinh nghiệm khi sử dụng chúng: + Hầu hết RTOS không giới hạn tác vụ nào có thể đọc, ghi vào queue, mailbox, pipe vì vậy chúng ta phải đảm bảo rằng các tác vụ được sử dụng là chính xác tại mỗi thời điểm. + RTOS không đảm bảo rằng dữ liệu được ghi vào trong queue, mailbox, pipe sẽ đúng với tác vụ đọc nó. Ví dụ một tác vụ ghi vào một số nguyên và tác vụ khác đọc và coi nó một con trỏ. + Chạy ra ngoài không gian queue, mailbox hoặc pipe sẽ gây ra một sự phá huỷ trong phần mềm nhúng. + Chuyển con trỏ từ một tác vụ này tới tác vụ khác thông qua một queue, mailbox hoặc pipe là cách để tạo ra chia sẻ dữ liệu. Chúng ta tránh dùng hàm malloc và free. 2. Chức năng bộ định thời (Timer Functions) Hầu hết các RTOS đều duy trì nhịp đập của bộ định thời. Bộ định thời này ngắt một cách định kỳ và được sử dụng cho các dịch vụ thời gian của RTOS. Khoảng
thời gian giữa các ngắt được gọi là một đơn vị thời gian của hệ thống (System Tick). Hầu hết các RTOS thường sử dụng dịch vụ thời gian để: + Một tác vụ có thể khoá chính bản thân nó sau một số đơn vị thời gian xác định. + Một tác vụ sẽ bị giới hạn bao nhiêu đơn vị thời gian của hệ thống khi nó đợi một đèn báo, hàng đợi... + Chương trình của chúng ta có thể điều khiển RTOS gọi một hàm xác định sau một số đơn vị thời gian của hệ thống. 3. Các sự kiện - Event Một dịch vụ khác của RTOS đưa ra là quản lý các sự kiện bên trong hệ thống. Mỗi sự kiện cơ bản là một cờ boolean mà các tác vụ có thể thiết lập, thiết lập lại và có thể có các tác vụ khác nhau cùng đợi nó. Một số đặc điểm của sự kiện trong các RTOS là: + Nhiều hơn một tác vụ có thể cùng bị khoá đợi cho một sự kiện, RTOS sẽ giải phóng tất cả chúng và thực hiện chúng theo thứ tự ưu tiên khi sự kiện xảy ra. + RTOS mặc định hình thành một nhóm các sự kiện và các tác vụ đợi cho bất kỳ tập con nào của nhóm sự kiện xảy ra. + Các hệ điều hành thời gian thực khác nhau đưa ra các cách khác nhau để thiết lập lại một sự kiện sau khi nó đã xảy ra và các tác vụ đợi sự kiện đó sẽ được giải phóng. Một số RTOS thiết lập lại các sự kiện một cách tự động, một số khác đòi hỏi các tác vụ phần mềm của chúng ta phải tự làm. Chúng ta sử dụng các queue, mailbox, pipe, semaphore, và các sự kiện cho việc giao tiếp giữa 2 tác vụ hoặc giữa một ngắt và một tác vụ. Nhưng chúng có một số đặc điểm riêng: + Semaphore là phương thức nhanh nhất và đơn giản nhất. Tuy nhiên, không nhiều thông tin có thể thông qua một semaphore. Chỉ một bit thông điệp được chuyển để thông báo semaphore được giải phóng. + Sự kiện là ít phức tạp hơn semaphore nhưng lại tiêu tốn nhiều thời gian bộ xử lý hơn semaphore. Sự dụng các sự kiện thuận lợi hơn semaphore ở chỗ: một tác vụ đợi một hay nhiều sự kiện trong cùng thời gian trong khi nó chỉ đợi một semaphore. + Hàng đợi cho phép chúng ta gửi một số lượng lớn thông tin từ tác vụ này tới tác vụ khác. Cho dù tác vụ chỉ đợi trên một hàng đợi tại một thời điểm nhưng sự thật là chúng cho phép chúng ta có thể gửi dữ liệu thông qua một hàng đợi làm nó linh hoạt hơn một sự kiện. Sự bất lợi là khi đọc và ghi thông điệp sẽ chiếm nhiều thời gian bộ xử lý và rất dễ mắc phải lỗi trong chương trình của chúng ta. Mailboxe và pipe có cùng đặc điểm với queue. 4. Các hàm ngắt trong môi trường RTOS Các hàm ngắt trong hầu hết các môi trường RTOS phải tuân theo hai quy tắc, điều này không áp dụng cho mã của tác vụ: Quy tắc 1: Một hàm ngắt không được gọi bất kỳ hàm RTOS nào mà những hàm đó có thể khoá lời gọi. Bởi vậy thủ tục ngắt không sử dụng đèn báo, không đọc từ các hàng đợi hoặc mailbox khi các hàng đợi và mailbox rỗng, không đợi các sự kiện... Nếu hàm ngắt gọi một hàm RTOS và bị khoá, thì tác vụ đang chạy khi ngắt xảy ra sẽ mãi bị khoá, thậm chí tác vụ này có quyền ưu tiên cao nhất. Ngoài
ra, hầu hết các hàm ngắt phải chạy để hoàn thành việc thiết lập lại phần cứng để sẵn sàng cho ngắt tiếp theo. Quy tắc 2: Một hàm ngắt có thể không gọi bất kỳ hàm RTOS nào những hàm có thể gây ra cho RTOS chuyển tới chạy các tác vụ trừ khi RTOS biết đó là một hàm ngắt và không là một tác vụ trong lúc đang thực hiện hàm ngắt. Nếu thủ tục ngắt phá vỡ quy tắc này thì RTOS có thể chuyển việc điều khiển từ hàm ngắt tới chạy một tác vụ khác, và hàm ngắt có thể không hoàn thành sau một thời gian dài, vì vậy khoá tất cả các ngắt có mức ưu tiên thấp hơn và có thể là tất cả các ngắt khác. Thay đổi nội dung bởi: Fairytale, 24-08-2008 lúc 01:01. Fairytale Xem hồ sơ Gửi nhắn tin tới Fairytale Tìm bài gửi bởi Fairytale #2 24-08-2008, 12:59
Fairytale Quản trị viên
Tham gia ngày: May 2008 Bài gửi: 51 Thanks: 44 Thanked 11 Times in 6 Posts
Ðề: Hệ điều hành thời gian thực cho các hệ thống nhúng IV. Thiết kế hệ thống nhúng thời gian thực Việc thiết kế một hệ thống thời gian thực là khó khăn hơn ứng dụng trên desktop. Chúng ta phải trả lời các câu hỏi: Hệ thống phải làm gì? Và thời hạn hoàn thành xử lý là bao lâu? Chúng ta phải biết hệ thống phải hoạt động trong bao lâu và biết các giới hạn tiêu chuẩn của nó. Nếu giới hạn là cứng nhắc thì hệ thống của chúng ta là hệ thống thời gian thực cứng, trong trường hợp ngược lại nó là hệ thống thời gian thực mềm. Chúng ta cũng phải biết phần cứng nào chúng ta sử dụng và tốc độ của nó như thế nào (tốc độ bộ vi xử lý, bộ nhớ, thanh ghi...). Việc thiết kế phần mềm nói chung như: cấu trúc, module hoá, đóng gói, và khả năng bảo trì vẫn được áp dụng trong thiết kế hệ nhúng. Trong nhiều phần mềm nhúng, sự kiện gây ra các ngắt sau đó phát tín hiệu để kích hoạt tác vụ thực hiện. Hệ thống sẽ không làm gì khi không có ngắt, tác vụ sẽ bị khoá trừ khi có sự kiện kích hoạt chúng. Và hàm ngắt ngắn là tốt hơn vì hàm ngắt được ưu tiên hơn các tác vụ. Chúng ta nên sử dụng ít tác vụ nhất có thể vì nhiều tác vụ sẽ gia tăng việc có nhiều lỗi, tiêu tốn nhiều thời gian bộ vi xử lý trong RTOS và cần nhiều không
gian bộ nhớ. Các xử lý có mức ưu tiên khác nhau phải ở trong các tác vụ khác nhau. Một tác vụ có cấu trúc tốt là một tác vụ bị khoá, đợi một thông điệp và chỉ ra các công việc tiếp theo phải thực hiện. Các tác vụ thường xuyên có cấu trúc như các máy trạng thái. Không nên tạo ra và huỷ các tác vụ khi hệ thống đang chạy. Nên tạo ra tất cả tác vụ khi hệ thống bắt đầu. Chắc chắn khi chúng ta thực sự cần phân chia thời gian. Giới hạn danh sách các hàm trong RTOS cho phép chúng ta xây dựng hệ thống nhỏ hơn bằng việc xây dựng một vỏ xung quanh nhân RTOS và có thể tạo mã linh động hơn. Chúng ta nên đóng gói việc sử dụng đèn báo, hàng đợi... trong một module, việc giao tiếp giữa các module được thực hiện bằng một lời gọi hàm. Phải đảm bảo rằng một hệ thống thời gian thực cứng có các giới hạn của nó, phải dự đoán được các tác vụ trong trường hợp thực hiện tồi nhất. Chúng ta phải tiết kiệm không gian mã trong hệ thống bằng việc cấu hình RTOS chính xác, bằng việc giới hạn số hàm thư viện C và bằng việc kiểm tra đầu ra của bộ biên dịch C hoặc có thể chúng ta viết mã trong ngôn ngữ Assemply thay vì viết trong ngôn ngữ C. Fairytale Xem hồ sơ Gửi nhắn tin tới Fairytale Tìm bài gửi bởi Fairytale #3 24-08-2008, 12:59
Fairytale Quản trị viên
Tham gia ngày: May 2008 Bài gửi: 51 Thanks: 44 Thanked 11 Times in 6 Posts
Ðề: Hệ điều hành thời gian thực cho các hệ thống nhúng V. Giới thiệu một số hệ điều hành thời gian thực 1. RTX51-Real Time Operating System RTX51 là một hệ điều hành thời gian thực đa tác vụ cho họ vi điều khiển 8051. RTX51 là một hệ thống đơn giản được thiết kế cho các phần mềm có độ phức tạp và có giới hạn chính xác về thời gian đáp ứng. RTX51 có các công cụ rất
mạnh để quản lý các tác vụ. Có hai phiên bản của RTX51: RTX51 Full cho phép thực hiện cả chuyển mạch xoay vòng và chuyển tác vụ với 4 mức ưu tiên, có thể hoạt động cùng với các hàm ngắt một cách song song. RTX51 chuyển các tín hiệu, chuyển các thông điệp sử dụng một hệ thống mailbox và các semaphore. Hàm os_wait của RTX51 có thể đợi cho các sự kiện: ngắt, timeout, thông điệp từ tác vụ hoặc ngắt, semaphore. RTX51 Tiny là một tập con của RTX51 Full. RTX51 Tiny dễ dàng chạy trên một chip không có bộ nhớ dữ liệu ngoài. Tuy nhiên chương trình sử dụng RTX51 Tiny có thể truy nhập sử dụng bộ nhớ ngoài. RTX51 Tiny cho phép chuyển mạch xoay vòng giữa các tác vụ, hỗ trợ chuyển các thông điệp và có thể hoạt động cùng với các hàm ngắt một cách song song. Hàm os_waitcủa RTX51 có thể đợi cho các sự kiện: timeout, tín hiệu từ tác vụ hoặc ngắt.
Bảng 1: So sánh RTX Full và RTX Tiny 2. ARTX-Advanced Real Time Operating System ARTX Kernel là một hệ điều hành thời gian thực nó cho phép chúng ta tạo ứng dụng mà ứng dụng này có thể đồng thời thực hiện nhiều tác vụ. Điều này thường xuyên đòi hỏi trong các ứng dụng nhúng thời gian thực. ARTX Kernel sử dụng lập lịch linh động các nguồn dữ liệu của hệ thống như CPU và bộ nhớ để đưa ra một số cách giao tiếp giữa các tác vụ. ARTX Kernel là một RTOS tốt, dễ dàng để sử dụng và làm việc cùng với tất cả các vi điều khiển họ ARM. Hệ điều hành ARTX được viết bằng việc sử dụng các hàm chuẩn và bộ biên dich C cùng với bộ biên dịch Keil™ CARM. Thêm vào đó, ngôn ngữ C cho phép chúng ta khai báo các tác vụ dễ dàng mà không cần sử dụng các stack phức tạp và sự đa dạng trong cấu hình.
Bảng 4.2: So sánh ARTX và RTX 3. µC/OS µC/OS là nhân một hệ điều hành thời gian thực do J. Labrosse xây dựng. Nó là nhân hệ điều hành thời gian thực có tính khả chuyển cao, mềm dẻo, có tính năng ưu tiên, thời gian thực và đa tác vụ. µC/OS hỗ trợ các tính năng sau: + Bộ lập lịch + Truyền thông điệp + Đồng bộ và chia sẻ dữ liệu giữa các tác vụ + Quản lý bộ nhớ
+ Các thiết bị vào ra + Hệ thống file + Mạng µC/OS hỗ trợ nhiều bộ vi xử lý và rất gọn nhẹ để sử dụng cho nhiều hệ thống nhúng. Phiên bản µC/OS-II tăng cường thêm khả năng đặt tên tới mỗi đối tượng của nhân. Đặc biệt với phiên bản V2.6, chúng ta có thể gán tên tới một tác vụ, đèn báo, mailbox, hàng đợi, một nhóm sự kiện hay một vùng bộ nhớ. Do đó, bộ phất hiện lỗi có thể hiển thị tên của những đối tượng đó, và cho phép chúng ta nhanh chóng xem thông tin về những đối tượng. Ngoài ra, V2.6 cho phép bộ sửa lỗi đọc thông tin cấu hình của một ứng dụng và hiểu thị những thông tin đó. 4. QNX Neutrino QNX Neutrino là chuẩn mực cho các ứng dụng nhúng thời gian thực. Nó có thể co giãn tới một kích thước rất nhỏ và cung cấp nhiều tác vụ hoạt động đồng thời, các tiến trình, điều khiển lập lịch thứ tự ưu tiên và chuyển ngữ cảnh nhanh… tất cả các thành phần cơ bản của một ứng dụng nhúng thời gian thực. Hơn nữa, nhà cung cấp OS tương thích với chuẩn thời gian thực POSIXstandard API. QNX Neutrino là rất mềm dẻo. Người phát triển có thể dễ dàng tuỳ biến OS cho phù hợp với ứng dụng của mình. Từ một cấu hình cơ bản nhất của một nhân nhỏ (microkernel) cùng với một vài module nhỏ tới một hệ thống được trang bị phát triển mạng diện rộng để phục vụ hàng trăm người dùng. QNX Neutrino đạt được mức độ chuyên môn hoá về tính hiệu quả, tính module hoá và tính đơn giản với hai yếu tố cơ bản sau: + Kiến trúc microkernel + Giao tiếp liên quá trình dựa trên thông điệp a. Kiến trúc microkernel Tại tầng thấp nhất, microkernel chứa đựng một vài đối tượng cơ bản và các hàm để thao tác với chúng. OS là được xây dựng từ các đối tượng cơ bản này. Một số nhà phát triển cho rằng microkernel nên được thực thi hoàn toàn ở trong mã assembly cho lý do kích thước và hiệu năng. Nhưng, việc thực thi của QNX dựa chủ yếu vào mã C. Các mục tiêu kích thước và hiệu năng đạt được thông qua việc tinh lọc các thuật toán và cấu trúc dữ liệu hơn là việc tối ưu thông qua mức viết mã bằng assembly. QNX Neutrino microkernel có nhân hỗ trợ các dịch vụ sau: 1. Các tiến trình 2. Truyền thông điệp 3. Các tín hiệu 4. Các đồng hồ 5. Các bộ định thời 6. Điều khiển các ngắt 7. Các đèn báo 8. Các khoá loại trừ lẫn nhau (mutexes) Vòng đời của tiến trình Số lượng các tiến trình trong một xử lý có thể rất đa dạng, cùng với các tiến trình
là được tạo và được huỷ một cách tự động. Việc tạo tiến trình (pthread_create()) liên quan tới việc cấp phát và khởi tạo nguồn dữ liệu cần thiết bên trong không gian địa chỉ của xử lý (ví dụ: thread stack) và việc bắt đầu thực hiện của tiến trình tại một số hàm trong không gian địa chỉ. Chấm dứt tiến trình (pthread_exit(), pthread_cancel()) liên quan tới việc dừng tiến trình và phục hồi lại nguồn dữ liệu của tiến trình. Khi một tiến trình thực hiện, trạng thái của nó nói chung có thể được mô tả như là ở một trong hai trạng thái "ready" hoặc "blocked." - CONDVAR: Tiến trình bị khoá trên một biến điều kiện (ví dụ: nó được gọi bởi hàm pthread_condvar_wait()). - DEAD: Tiến trình đã chấm dứt và đang đợi được ghép cùng một tiến trình khác. - INTERRUPT: Tiến trình bị khoá và đợi cho một ngắt (ví dụ: nó được gọi bởi hàm InterruptWait()). - JOIN: Tiến trình bị khoá đợi để ghép với một tiến trình khác (ví dụ: nó được gọi bởi hàm pthread_join()). - MUTEX: Tiến trình bị khoá trên một khoá loại trừ lẫn nhau (ví dụ: nó được gọi bởi hàm pthread_mutex_lock()). - NANOSLEEP: Tiến trình đang ngủ cho một khoảng thời gian ngắn (ví dụ: nó được gọi bởi hàm nanosleep()). - NET_REPLY: Tiến trình đang đợi cho sự đáp lại tới việc phân phát qua mạng (ví dụ: nó được gọi bởi hàm MsgReply*()). - NET_SEND: Tiến trình đang đợi cho một xung hoặc tín hiệu tới việc phân phát qua mạng (ví dụ: nó được gọi bởi hàm MsgSendPulse(), MsgDeliverEvent(), hoặc SignalKill()). - READY: Tiến trình đang đợi cho được thực hiện trong khi bộ xử lý thực hiện một tiến trình khác có mức ưu tiên cao hơn hoặc bằng tiến trình đó. - RECEIVE: Tiến trình bị khoá đợi nhận được một thông điệp (ví dụ: nó được gọi bởi hàm MsgReceive()). - REPLY: Tiến trình bị khoá đợi một thông điệp đáp lại (ví dụ: nó được gọi bởi hàm MsgSend() và server đã nhận được thông điệp đó). - RUNNING: Tiến trình đang được thực hiện bởi bộ xử lý. - SEM: Tiến trình đang đợi cho một đèn báo giải phóng (ví dụ: nó được gọi bởi hàm SyncSemWait()). - SEND: Tiến trình là bị khoá chờ thông điệp gủi (ví dụ: nó được gọi bởi hàm MsgSend() nhưng server chưa nhận được thông điệp). - SIGSUSPEND: Tiến trình bị khoá đợi cho một tín hiệu (ví dụ: nó được gọi bởi hàm sigsuspend()). - SIGWAITINFO: Tiến trình bị khoá đợi cho một tín hiệu (ví dụ: nó được gọi bởi hàm sigwaitinfo()). - STACK: Tiến trình đang đợi cho một không gian địa chỉ ảo được cấp phát cho stack của tiến trình đó. - STOPPED: Tiến trình bị khoá đợi cho tín hiệu SIGCONT. - WAITCTX: Tiến trình đang đợi cho không phải một số nguyên (ví dụ: dấu phẩy động) để trở thành có giá trị cho việc sử dụng. - WAITPAGE: Tiến trình đang đợi cho một không gian bộ nhớ ảo được cấp phát.
- WAITTHREAD: Tiến trình đang đợi cho một tiến trình con kết thúc được tạo bởi chính nó (ví dụ: nó được gọi bởi hàm ThreadCreate()). b. Giao tiếp liên quá trình dựa trên việc truyền thống điệp QNX là hệ điều hành thương mại đầu tiên sử dụng truyền thông điệp liên quá trình. Trong QNX Neutrino, một thông điệp là một gói các byte được truyền đi từ tiến trình này đến tiến trình khác. QNX cung cấp chức năng đồng bộ để truyền thông điệp từ một tiến trình tới tiến trình khác. Tiến trình phải thay đổi trạng thái của nó khi truyền, nhận và đáp lại thông điệp. Biết được trạng thái của chúng và thứ tự ưu tiên của chúng, microkerel có thể lập lịch tất cả các thông điệp. Các thuật toán lập lịch: QNX Neutrino cung cấp các thuật toán lập lịch sau: * Vào trước ra trước (FIFO) * Xoay vòng (round-robin) * Lập lịch rời rạc (sporadic) Kết luận: Trong bài này chúng ta đã tìm hiểu các dịch vụ cơ bản nhất của một nhân hệ điều hành thời gian thực nói chung. Các hệ điều hành thương mại thường có các dịch vụ khác như quản lý file, quản lý thiết bị, quản lý mạng… Và thông thường chúng cho phép cấu hình việc sử dụng các dịch vụ của chúng tuỳ theo ứng dụng nhúng của chúng ta.