
Dalam artikel tugas ketiga dan terakhir ini, saya akan melihat struktur data Nucleus SE dan menjelaskan panggilan RTOS API yang tidak diterapkan di Nucleus SE, serta masalah kompatibilitas lainnya.
Artikel sebelumnya dalam seri:
Artikel # 12. Layanan untuk bekerja dengan tugasArtikel # 11. Tugas: konfigurasi dan pengantar APIArtikel # 10. Penjadwal: fitur canggih dan pelestarian konteksArtikel # 9. Penjadwal: implementasiArtikel # 8. Nucleus SE: Desain dan Penyebaran InternalArtikel # 7. Nucleus SE: PendahuluanArtikel # 6. Layanan RTOS lainnyaArtikel # 5. Interaksi tugas dan sinkronisasiArtikel # 4. Tugas, pengalihan konteks, dan interupsiArtikel # 3. Tugas dan PerencanaanArtikel # 2. RTOS: Struktur dan mode waktu-nyata
Artikel # 1. RTOS: pengantar.
Struktur data
Tugas menggunakan berbagai struktur data (baik dalam RAM dan ROM), yang, seperti objek Nucleus SE lainnya, adalah seperangkat tabel yang ukurannya sesuai dengan jumlah tugas dan parameter yang dipilih.
Saya sangat merekomendasikan kode aplikasi mengakses struktur data ini menggunakan fungsi API, dan tidak secara langsung. Ini menghindari efek samping yang tidak diinginkan, ketidakcocokan dengan versi Nucleus SE yang akan datang, dan juga menyederhanakan porting aplikasi ke Nucleus RTOS. Untuk pemahaman yang lebih baik tentang pengoperasian kode panggilan layanan dan proses debugging, deskripsi terperinci dari struktur data diberikan di bawah ini.
Struktur Data Kernel Hosted dalam RAM
Struktur data ini meliputi:
NUSE_Task_Context [] [] - array dua dimensi dari tipe
ADDR , memiliki satu baris untuk setiap tugas. Jumlah kolom tergantung pada arsitektur controller dan ditentukan oleh simbol
NUSE_REGISTERS , yang didefinisikan dalam
nuse_types.h . Array ini digunakan oleh penjadwal untuk menyimpan konteks setiap tugas dan telah dijelaskan secara rinci di bagian "Menyimpan Konteks" artikel # 10. Tidak dibuat jika penjadwal RTC digunakan.
NUSE_Task_Signal_Flags [] - larik tipe
U8 , dibuat jika sinyal diaktifkan, dan berisi 8 flag sinyal untuk setiap tugas. Sinyal akan dibahas dalam salah satu artikel berikut.
NUSE_Task_Timeout_Counter [] adalah larik tipe
U16 , terdiri dari pengurangan penghitung untuk setiap tugas dan dibuat jika panggilan ke API
NUSE_Task_Sleep () diaktifkan.
NUSE_Task_Status [] - larik tipe U8, berisi status setiap tugas -
NUSE_READY atau menangguhkan status. Dibuat hanya jika penangguhan tugas diaktifkan.
NUSE_Task_Blocking_Return [] - larik tipe U8, dibuat jika pemblokiran panggilan API diaktifkan. Ini berisi kode kembali yang akan digunakan setelah memblokir panggilan API. Biasanya berisi
NUSE_SUCCESS atau kode yang menunjukkan bahwa objek telah disetel ulang (misalnya,
NUSE_MAILBOX_WAS_RESET ).
NUSE_Task_Schedule_Count [] - larik tipe
U16 , berisi penghitung untuk setiap tugas dan dibuat hanya jika jumlah penjadwal telah diaktifkan.
NUSE_Task_Context [] [] diinisialisasi terutama oleh nol, kecuali untuk entri yang berkaitan dengan register status (register status, SR), penghitung program (penghitung program, PC) dan penunjuk tumpukan (penunjuk tumpukan, SP), yang diberi nilai awal (lihat "Data dalam ROM "di bawah), dan semua struktur data lainnya
NUSE_Init_Task () ditugaskan nol ketika memulai Nucleus SE. Salah satu artikel berikut akan berisi daftar lengkap prosedur awal Nucleus SE dengan uraiannya.
Berikut ini adalah definisi dari struktur data yang terkandung dalam file nuse_init.c.

Data pengguna RAM
Pengguna harus menentukan tumpukan untuk setiap tugas (jika penjadwal RTC tidak digunakan). Ini haruslah array
ADDR , yang biasanya didefinisikan dalam
nuse_config.c . Alamat dan ukuran tumpukan harus ditempatkan dalam entri tugas
NUSE_Task_Stack_Base [] dan
NUSE_Task_Stack_Size [], masing-masing (lihat Data dalam ROM).
Data ROM
ROM menyimpan dari satu hingga empat struktur data yang terkait dengan tugas. Jumlah pasti tergantung pada parameter yang dipilih:
NUSE_Task_Start_Address [] adalah larik jenis
ADDR yang memiliki satu entri untuk setiap tugas, yang merupakan penunjuk ke titik entri kode untuk tugas tersebut.
NUSE_Task_Stack_Base [] adalah larik tipe
ADDR yang memiliki satu entri untuk setiap tugas, yang merupakan penunjuk ke alamat dasar tumpukan untuk tugas tersebut. Array ini dibuat jika ada penjadwal selain RTC yang digunakan.
NUSE_Task_Stack_Size [] adalah larik tipe
U16 yang memiliki satu entri untuk setiap tugas, yang menunjukkan ukuran tumpukan untuk tugas tersebut (dalam kata-kata). Array ini dibuat jika ada penjadwal selain RTC yang digunakan.
NUSE_Task_Initial_State [] adalah larik tipe
U8 , memiliki satu entri untuk setiap tugas, yang menunjukkan status awal tugas. Ini dapat berupa
NUSE_READY atau
NUSE_PURE_SUSPEND . Array ini dibuat jika dukungan untuk keadaan awal tugas dipilih.
Struktur data ini dideklarasikan dan diinisialisasi (secara statis) di
nuse_config.c :

Jumlah memori untuk menyimpan data tugas (Footprint Data Tugas)
Seperti semua objek inti Nucleus SE, jumlah memori yang diperlukan untuk menyimpan data dapat diprediksi.
Ukuran ROM (dalam byte) diperlukan untuk semua tugas aplikasi:
NUSE_TASK_NUMBER * sizeof (ADDR)Plus, jika ada penjadwal selain RTC dipilih:
NUSE_TASK_NUMBER * (sizeof (ADDR) +2)Plus, jika dukungan untuk keadaan awal tugas dipilih:
NUSE_TASK_NUMBERUntuk menyimpan data dalam RAM, jumlah memori (dalam byte) ditentukan oleh parameter yang dipilih, dan dapat memiliki nilai nol jika tidak ada parameter yang dipilih.
Jika penjadwal selain RTC dipilih:
NUSE_TASK_NUMBER * NUSE REGISTERS * sizeof (ADDR)Plus, jika dukungan sinyal dipilih:
NUSE_TASK_NUMBERPlus, jika panggilan ke NUSE_Task_Sleep () API diaktifkan:
NUSE_TASK_NUMBER * 2Plus, jika penangguhan tugas diaktifkan:
NUSE_TASK_NUMBERPlus, jika pemblokiran panggilan API diaktifkan:
NUSE_TASK_NUMBERPlus, jika penghitung penjadwal diaktifkan:
NUSE_TASK_NUMBER * 2Panggilan API tidak diterapkan di Nucleus SE
Di bawah ini adalah tujuh panggilan API yang tersedia di Nucleus RTOS yang tidak diterapkan di Nucleus SE.
Buat Tugas
Panggilan API ini menciptakan tugas aplikasi. Nucleus SE tidak memerlukan fitur ini karena tugas dibuat secara statis.
Prototipe panggilan:
STATUS NU_Create_Task (NU_TASK * tugas, CHAR * nama, VOID (* task_entry) (TIDAK DITANDATANGANI, VOID *), argc TIDAK TANDA, VOID * stack_address, stack_address yang TIDAK DITANDATANGANI, prioritas TAMBAHAN, ukuran OPSI, prioritas OPSI, prioritas waktu TANDA, prioritas OPTION, OPTION prioritasParameter:
task - pointer ke blok kontrol tugas pengguna, dapat digunakan sebagai pegangan / tautan ("handle") dari tugas dalam panggilan API lainnya;
name - pointer ke nama tugas, string 7-karakter dengan nol penghentian;
task_entry - menunjukkan fungsi input untuk tugas;
argc - Elemen data yang tidak
ditandai yang dapat digunakan untuk meneruskan informasi awal ke tugas;
argv - pointer yang dapat digunakan untuk mengirimkan informasi ke tugas;
stack_address - mengatur sektor awal memori untuk tumpukan tugas;
stack_size - menunjukkan jumlah byte di stack;
priority - menunjukkan nilai prioritas tugas: dari 0 hingga 255, di mana angka yang lebih rendah sesuai dengan prioritas tertinggi;
time_slice - menunjukkan jumlah
irisan waktu maksimum yang dapat dilewati selama tugas ini. Nilai "0" menonaktifkan pengiris waktu untuk tugas ini;
preempt - menunjukkan apakah tugas digantikan atau tidak. Mungkin memiliki nilai
NU_PREEMPT dan
NU_NO_PREEMPT ;
auto_start - menunjukkan status awal tugas.
NU_START berarti bahwa tugas tersebut siap untuk dieksekusi, dan
NU_NO_START berarti bahwa tugas tersebut ditangguhkan.
Nilai pengembalian:
NU_SUCCESS - menunjukkan keberhasilan penyelesaian layanan;
NU_INVALID_TASK - menunjukkan bahwa penunjuk ke unit kontrol tugas adalah
NULL ;
NU_INVALID_ENTRY - menunjukkan bahwa penunjuk ke fungsi input tugas adalah
NULL ;
NU_INVALID_MEMORY - menunjukkan bahwa sektor memori yang ditetapkan oleh parameter stack_address adalah nol (
NULL );
NU_INVALID_SIZE - menunjukkan bahwa ukuran tumpukan yang ditentukan tidak cukup;
NU_INVALID_PREEMPT - menunjukkan bahwa parameter
preempt diatur secara tidak benar;
NU_INVALID_START - menunjukkan bahwa parameter
auto_start diatur secara tidak benar.
Hapus Tugas
Panggilan API ini menghapus tugas aplikasi yang dibuat sebelumnya yang harus
Selesai atau
Dihentikan . Panggilan ini juga tidak perlu untuk Nucleus SE, karena tugas dibuat secara statis dan tidak dapat dihapus.
Prototipe panggilan:
STATUS NU_Delete_Task (tugas NU_TASK *);Parameter:
penunjuk tugas ke blok kontrol tugas
Nilai pengembalian:
NU_SUCCESS - menunjukkan keberhasilan penyelesaian layanan;
NU_INVALID_TASK - menunjukkan bahwa penunjuk ke tugas diatur secara tidak benar;
NU_INVALID_DELETE - Menunjukkan bahwa tugas tidak dalam status Selesai atau Dihentikan.
Dapatkan Penunjuk Tugas
Panggilan API ini membuat daftar petunjuk berurutan untuk semua tugas dalam sistem. Tidak diperlukan dalam Nucleus SE, karena tugas diidentifikasi menggunakan indeks sederhana, bukan pointer.
Prototipe panggilan:
NU_Task_Pointers TIDAK DITANDATANGANI (NU_TASK ** pointer_list, maksimum_pointers UNSIGNED);Parameter:
pointer_list - pointer ke array pointer
NU_TASK . Array ini akan diisi dengan pointer ke tugas-tugas yang diinstal dalam sistem;
maximum_pointers - jumlah maksimum pointer yang dapat ditempatkan dalam array.
Nilai pengembalian:
Jumlah pointer
NU_TASK ditempatkan dalam array.
Ubah Prioritas Tugas
Panggilan API ini memberi tugas prioritas baru. Dalam Nucleus SE, itu tidak diperlukan, karena prioritas tugas adalah konstan.
Prototipe panggilan:
OPTION NU_Change_Priority (tugas NU_TASK *, OPTION new_priority);Parameter:
tugas - pointer ke blok kontrol tugas;
new_priority - menetapkan prioritas dari 0 hingga 255.
Nilai pengembalian:
Nilai prioritas tugas sebelumnya.
Ubah Algoritma Preemption Tugas
Panggilan API ini mengubah urutan penyelesaian tugas yang sedang berlangsung. Nucleus SE tidak membutuhkannya karena menggunakan algoritma penjadwalan yang lebih sederhana.
Prototipe panggilan:
OPTION NU_Change_Preemption (preempt OPTION);Parameter:
preempt - algoritma
preemptive baru, menerima
NU_PREEMPT atau
NU_NO_PREEMPTNilai pengembalian:
Algoritma sebelumnya untuk crowding out tugas.
Ubah Irisan Waktu Tugas
Panggilan API ini mengubah irisan waktu tugas tertentu. Nucleus SE tidak membutuhkannya, karena irisan waktu tugas sudah diperbaiki.
Prototipe panggilan:
NU_Change_Time_Slice UNSIGNED (tugas NU_TASK *, UNSIGNED time_slice);Parameter:
tugas - pointer ke blok kontrol tugas;
time_slice - jumlah maksimum
irisan waktu yang dapat berlalu selama tugas ini, nilai nol bidang ini menonaktifkan kuantisasi waktu untuk tugas ini.
Nilai pengembalian:
Nilai sebelumnya dari kuantum waktu tugas.
Hentikan Tugas
Panggilan API ini menyelesaikan tugas tertentu. Nucleus SE tidak memerlukan ini karena keadaan
Dihentikan tidak didukung.
Prototipe panggilan:
STATUS NU_Terminate_Task (tugas NU_TASK *);Parameter:
task - pointer ke blok kontrol tugas.
Nilai pengembalian:
NU_SUCCESS - menunjukkan keberhasilan penyelesaian layanan;
NU_INVALID_TASK - Menunjukkan bahwa penunjuk tugas salah.
Kompatibel dengan RTOS Inti
Ketika mengembangkan Nucleus SE, salah satu tujuan utama adalah untuk memastikan tingkat kompatibilitas kode yang tinggi dengan Nucleus RTOS. Tugas tidak terkecuali dan, dari sudut pandang pengguna, mereka diimplementasikan dalam banyak cara yang sama seperti pada Nucleus RTOS. Ada beberapa area yang tidak kompatibel di mana saya sampai pada kesimpulan bahwa ketidakcocokan seperti itu akan dapat diterima, mengingat bahwa kode akhir lebih mudah dipahami dan dapat menggunakan memori lebih efisien. Namun, selain ketidakcocokan ini, sisa panggilan Nucleus RTOS API dapat digunakan hampir secara langsung sebagai panggilan Nucleus SE. Salah satu artikel berikut akan memberikan rincian lebih lanjut tentang transisi dari Nucleus RTOS ke Nucleus SE
Pengidentifikasi Objek
Dalam Nucleus RTOS, semua objek dijelaskan oleh struktur data (unit kontrol) yang dari tipe tertentu. Penunjuk ke unit kontrol ini berfungsi sebagai pengidentifikasi untuk tugas tersebut. Di Nucleus SE, saya memutuskan bahwa diperlukan pendekatan yang berbeda untuk penggunaan memori yang efisien. Semua objek kernel dijelaskan oleh satu set tabel dalam RAM dan / atau ROM. Ukuran tabel ini ditentukan oleh jumlah jenis objek. Pengidentifikasi objek tertentu adalah indeks dalam tabel ini. Jadi saya mendefinisikan
NUSE_TASK sebagai setara dengan
U8 . Variabel jenis ini (bukan penunjuk) berfungsi sebagai pengidentifikasi untuk tugas. Ini adalah ketidakcocokan kecil yang mudah diketahui jika kode porting ke atau dari Nucleus RTOS. Pengidentifikasi objek biasanya disimpan dan dikirim tidak berubah.
Nucleus RTOS juga mendukung penamaan tugas. Nama-nama ini hanya digunakan untuk debugging. Saya mengecualikan mereka dari Nucleus SE untuk menghemat memori.
Status tugas
Dalam Nucleus RTOS, tugas bisa di salah satu dari beberapa negara:
Eksekusi ,
Siap ,
Ditangguhkan (yang mengarah ke ketidakpastian: tugas dalam keadaan siaga atau diblokir oleh panggilan API),
Dihentikan, atau Selesai.
Nucleus SE juga mendukung status
Eksekusi dan
Siap . Ketiga opsi
Penangguhan didukung secara opsional.
Dihentikan dan Selesai tidak didukung. Tidak ada panggilan API untuk menyelesaikan tugas. Fungsi tugas eksternal seharusnya tidak pernah mengembalikan nilai baik secara eksplisit maupun implisit (ini akan menghasilkan status
jadi dalam Nucleus RTOS).
Panggilan API yang belum direalisasi
Nucleus RTOS mendukung 16 panggilan kantor untuk bekerja dengan tugas. Dari jumlah tersebut, 7 tidak diimplementasikan dalam Nucleus SE. Deskripsi mereka, serta alasan pengecualian mereka dijelaskan di atas.
Pada artikel selanjutnya, kita akan mulai melihat manajemen memori RTOS.
Tentang Pengarang: Colin Walls telah bekerja di industri elektronik selama lebih dari tiga puluh tahun, mencurahkan sebagian besar waktunya untuk firmware. Dia sekarang adalah seorang insinyur firmware di Mentor Embedded (sebuah divisi dari Mentor Graphics). Colin Walls sering berbicara di konferensi dan seminar, penulis berbagai artikel teknis dan dua buku tentang firmware. Tinggal di Inggris.
Blog profesional
Colin , email: colin_walls@mentor.com.