Saya mencoba membuat RTOS semi-pre-emptive (koperasi) untuk mikrokontroler PIC x16. Dalam pertanyaan saya sebelumnya , saya telah belajar bahwa mengakses pointer stack perangkat keras tidak dimungkinkan dalam core ini. Saya telah melihat halaman ini di PIClist, dan inilah yang saya coba terapkan dengan menggunakan C.
Kompiler saya adalah Microchip XC8 dan saat ini saya sedang mengerjakan PIC16F616 dengan osilator RC internal 4MHz dipilih dalam bit konfigurasi.
Saya telah belajar bahwa saya dapat mengakses register PCLATH dan PCL dengan C, melihat file header kompiler saya. Jadi, saya mencoba menerapkan pengalih tugas sederhana.
Ini berfungsi seperti yang diinginkan dalam debugger jika saya menjeda debugger setelah restart, reset, dan mengatur PC pada kursor ketika kursor tidak pada baris pertama ( TRISA=0;
) tetapi pada baris lain (misalnya ANSEL=0;
). Pada awal pertama debugger saya mendapatkan pesan-pesan ini di Debugger Console
:
Launching
Programming target
User program running
No source code lines were found at current PC 0x204
Sunting: Saya tidak tahu apa yang membuatnya bekerja, tetapi debugger sekarang berfungsi dengan baik. Jadi, hilangkan output dan paragraf di atas.
Sunting: Mengubah definisi utama seperti ini membuat kode di bawah ini berfungsi. Ini memulai fungsi utama pada alamat program 0x0099
. Saya tidak tahu apa penyebabnya. Ini bukan solusi nyata. Saya sekarang menebak bahwa ada kesalahan khusus kompiler.
void main(void) @ 0x0099
{
Ini kode C saya:
/*
* File: main.c
* Author: abdullah
*
* Created on 10 Haziran 2012 Pazar, 14:43
*/
#include <xc.h> // Include the header file needed by the compiler
__CONFIG(FOSC_INTOSCIO & WDTE_OFF & PWRTE_ON & MCLRE_OFF & CP_OFF & IOSCFS_4MHZ & BOREN_ON);
/*
* INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN
* WDT disabled and can be enabled by SWDTEN bit of the WDTCON register
* PWRT enabled
* MCLR pin function is digital input, MCLR internally tied to VDD
* Program memory code protection is disabled
* Internal Oscillator Frequency Select bit : 4MHz
* Brown-out Reset Selection bits : BOR enabled
*/
/*
* OS_initializeTask(); definition will copy the PCLATH register to the task's PCLATH holder, which is held in taskx.pch
* This will help us hold the PCLATH at the point we yield.
* After that, it will copy the (PCL register + 8) to current task's PCL holder which is held in taskx.pcl.
* 8 is added to PCL because this line plus the "return" takes 8 instructions.
* We will set the PCL after these instructions, because
* we want to be in the point after OS_initializeTask when we come back to this task.
* After all, the function returns without doing anything more. This will initialize the task's PCLATH and PCL.
*/
#define OS_initializeTask(); currentTask->pch = PCLATH;\
currentTask->pcl = PCL + 8;\
asm("return");
/*
* OS_yield(); definition will do the same stuff that OS_initializeTask(); definition do, however
* it will return to "taskswitcher" label, which is the start of OS_runTasks(); definition.
*/
#define OS_yield(); currentTask->pch = PCLATH;\
currentTask->pcl = PCL + 8;\
asm("goto _taskswitcher");
/*
* OS_runTasks(); definition will set the "taskswitcher" label. After that it will change the
* current task to the next task, by pointing the next item in the linked list of "TCB"s.
* After that, it will change the PCLATH and PCL registers with the current task's. That will
* make the program continue the next task from the place it left last time.
*/
#define OS_runTasks(); asm("_taskswitcher");\
currentTask = currentTask -> next;\
PCLATH = currentTask->pch;\
PCL = currentTask->pcl;
typedef struct _TCB // Create task control block and type define it as "TCB"
{
unsigned char pch; // pch register will hold the PCLATH value of the task after the last yield.
unsigned char pcl; // pcl register will hold the PCL value of the task after the last yield.
struct _TCB* next; // This pointer points to the next task. We are creating a linked list.
} TCB;
TCB* currentTask; // This TCB pointer will point to the current task's TCB.
TCB task1; // Define the TCB for task1.
TCB task2; // Define the TCB for task2.
void fTask1(void); // Prototype the function for task1.
void fTask2(void); // Prototype the function for task2.
void main(void)
{
TRISA = 0; // Set all of the PORTA pins as outputs.
ANSEL = 0; // Set all of the analog input pins as digital i/o.
PORTA = 0; // Clear PORTA bits.
currentTask = &task1; // We will point the currentTask pointer to point the first task.
task1.next = &task2; // We will create a ringed linked list as follows:
task2.next = &task1; // task1 -> task2 -> task1 -> task2 ....
/*
* Before running the tasks, we should initialize the PCL and PCLATH registers for the tasks.
* In order to do this, we could have looked up the absolute address with a function pointer.
* However, it seems like this is not possible with this compiler (or all the x16 PICs?)
* What this compiler creates is a table of the addresses of the functions and a bunch of GOTOs.
* This will not let us get the absolute address of the function by doing something like:
* "currentTask->pcl=low(functionpointer);"
*/
fTask1(); // Run task1 so that we get the address of it and initialize pch and pcl registers.
currentTask = currentTask -> next; // Point the currentTask pointer to the next pointer which
fTask2(); // is task2. And run task2 so that we get the correct pch and pcl.
OS_runTasks(); // Task switcher. See the comments in the definitions above.
}
void fTask1(void)
{
OS_initializeTask(); // Initialize the task
while (1)
{
RA0 = ~RA0; // Toggle PORTA.0
OS_yield(); // Yield
RA0 = ~RA0; // Toggle PORTA.0
}
}
void fTask2(void)
{
OS_initializeTask(); // Initialize the task
while (1)
{
RA1 = ~RA1; // Toggle PORTA.1
OS_yield(); // Yield
RA1 = ~RA1; // Toggle PORTA.1
}
}
Dan di sini adalah file daftar pembongkaran yang dibuat kompiler saya. Mulai dari line 74
.
Saya telah memprogram chip yang sebenarnya, dan tidak ada perubahan pada PORTA sama sekali; itu tidak bekerja.
Apa alasan program saya tidak berfungsi?
Saya melihat-lihat daftar perakitan yang Anda berikan, dan tidak ada yang melompat keluar karena jelas rusak.
Jika saya jadi Anda, langkah saya selanjutnya adalah:
(1) Saya akan memilih metode lain untuk mengedipkan LED. "Masalah baca-modifikasi-tulis" yang terkenal dapat (atau mungkin tidak) dipicu oleh "XORWF PORTA, F" dalam daftar perakitan.
Mungkin sesuatu seperti:
(Jika Anda benar-benar ingin melihat penjelasan terperinci tentang mengapa "XORWF PORTA, F" sering menyebabkan masalah, lihat " Apa yang menyebabkan menyalakan pin output tunggal pada Microchip PIC16F690 untuk secara spontan mematikan pin lain pada port yang sama? "; " Apa yang terjadi ketika data ditulis ke LATCH? ";" Masalah Read-Modify-Write ";" Read before Write ")
(2) Saya akan langkah-tunggal melalui kode, memastikan bahwa variabel sedang diatur ke nilai yang diharapkan dan dalam urutan yang diharapkan. Saya tidak yakin apakah ada hardware debugger satu langkah untuk PIC16F616, tetapi ada banyak simulator mikrokontroler PIC yang sangat baik seperti PICsim yang dapat mensimulasikan chip seri PIC16.
Kode langkah-tunggal (dalam simulator atau dengan perangkat keras langkah-tunggal) adalah cara yang baik untuk memahami detail tentang apa yang sebenarnya terjadi, mengonfirmasi bahwa segala sesuatu terjadi seperti yang Anda inginkan, dan memungkinkan Anda melihat hal-hal yang hampir mustahil untuk melihat ketika menjalankan program dengan kecepatan penuh.
(3) Jika saya masih bingung, saya akan mencoba menerjemahkan kode untuk menggunakan array daripada pointer. Beberapa orang merasa menggunakan pointer agak rumit dan sulit untuk di-debug. Saya sering menemukan bahwa, dalam proses menerjemahkan kode penunjuk rumit ke dalam kode berorientasi array, saya mencari tahu apa bug itu. Bahkan jika saya akhirnya kembali ke kode pointer asli dan membuang versi array, latihan ini berguna karena membantu saya menemukan dan memperbaiki bug. (Terkadang kompiler dapat menghasilkan kode lebih pendek, lebih cepat dari kode berorientasi array, jadi ada kalanya saya membuang kode pointer asli dan menyimpan versi array).
Mungkin seperti itu
sumber
Saya pada dasarnya akan setuju dengan davidcary. Sepertinya itu bisa berhasil.
Saya menduga maksud Anda ini berfungsi dengan baik di simulator .
1) Periksa apakah tugas Anda bekerja sendiri, dalam lingkungan non-RTOS dalam chip nyata.
2) Melakukan debugging dalam-sirkuit. Langkah melalui program pada chip nyata, dan menonton semua variabel yang relevan untuk memastikan bahwa semuanya berjalan sesuai rencana.
sumber
Saya hanya melihat kode Anda sebentar, tetapi tidak masuk akal. Di beberapa tempat Anda menulis ke PCL, kemudian mengharapkannya untuk mengeluarkan instruksi lain setelah itu.
Seperti yang saya katakan sebelumnya, C tidak sesuai untuk jenis akses rendah register perangkat keras mendasar. Anda benar-benar perlu menggunakan perakitan untuk ini. Mencoba mencari tahu mengapa kode C tidak berfungsi hanya buang-buang waktu saja.
sumber
Di bawah ini adalah cara untuk melakukannya dengan perakitan in-line menggunakan kompiler XC8, dan berfungsi sekarang! Namun, saya perlu menambahkan mengembangkan lebih banyak kode untuk menyimpan dan mengembalikan
STATUS
register, yang tampaknya sedikit rumit daripada register normal.Sunting: Kode diubah. Silakan merujuk ke versi yang lebih lama dari posting ini untuk kode sebelumnya.
Dan di sini adalah file tajuk
RTOS.h
:sumber
Di bawah ini adalah cara mengimplementasikan perakitan menggunakan ini. Akses kode yang sama dengan pemformatan (tautan ke Pastebin) . Bagaimana itu bisa diperbaiki? Ini adalah program pertama saya di perakitan PIC, ada komentar yang dihargai.
sumber