\documentclass[a4paper,fontsize=14bp]{article} \input{../common-preamble} \input{../bmstu-preamble} \input{../fancy-listings-preamble} \setcounter{secnumdepth}{0} \numerationTop \begin{document} \thispagestyle{empty} \makeBMSTUHeader \makeReportTitle{лабораторной}{3}{Проектирование с применением ядра Nios II \\ и ОСРВ $\mu$C/OS-II}{Программное обеспечение встроенных систем}{}{доцент кафедры ИУ-3 \\ Федоров С.В.} \newpage \thispagestyle{empty} \tableofcontents \newpage \pagestyle{fancy} \section{Цель} Целью работы являлось освоение навыков проектирования программного обеспечения для операционных систем реального времени. Создание простого проекта программного обеспечения системы на кристалле Nios II на основе ОСРВ $\mu$C/OS-II. Изучение основных сервисов ОСРВ $\mu$C/OS-II. Реализация обработчика прерывания в системе на кристалле Nios II. Освоение методики обработки внешних событий в $\mu$C/OS-II. \section{Выполнение} \subsection{Часть I. Создание простой системы на основе $\mu$C/OS-II} В первой части работы была создана простая система на основе ОСРВ $\mu$C/OS-II. В приложении \hrf{appendix:pt1full} приведён полный листинг готовой программы. Единственным отличием от предложенной в исходном материале было добавление переключения светодиода по вызову задачи второго семафора, согласно методического материала. В листинге \hrf{lst:pt1change} представлен код, добавленный в тело функции \code{getsem\_task2}. \begin{lstlisting}[language=C, style=CCodeStyle, caption=Внесённые в исходный код изменения, label={lst:pt1change}] ... INT8U led; led = 1; while (1) { led = led << 1; if (led == 0) led = 1; IOWR_ALTERA_AVALON_PIO_DATA(GREEN_LED_BASE,led); ... \end{lstlisting} После внесения изменений и компиляции был изучен файл objdump, созданный системой. В листинге \hrf{lst:pt1objdump} приведён фрагмент файла. Исходя из данных в файле (на строках \hrf{line:pt1text} (\code{.text}), \hrf{line:pt1bss} (\code{.bss})), текст программы занял 105240 байт, а для неинициализированных данных было выделено 45288 байт. \begin{lstlisting}[style=ASMStyle, caption=Фрагмент файла objdump, label={lst:pt1objdump}] Sections: Idx Name Size VMA LMA File off Algn 0 .entry 00000020 00000000 00000000 00001000 2**5 CONTENTS, ALLOC, LOAD, READONLY, CODE 1 .exceptions 00000218 00000020 00000020 00001020 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 2 .text 00019b18 00000238 00000238 00001238 2**2<@\label{line:pt1text}@> CONTENTS, ALLOC, LOAD, READONLY, CODE 3 .rodata 00000d54 00019d50 00019d50 0001ad50 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .rwdata 00001c70 0001aaa4 0001c714 0001baa4 2**2 CONTENTS, ALLOC, LOAD, DATA, SMALL_DATA 5 .bss 0000b0e8 0001e384 0001e384 0001e384 2**2<@\label{line:pt1bss}@> ALLOC, SMALL_DATA 6 .sdram 00000000 0002946c 0002946c 0001d714 2**0 CONTENTS 7 .instruction_tcm 00000000 10000000 10000000 0001d714 2**0 CONTENTS 8 .comment 0000002d 00000000 00000000 0001d714 2**0 CONTENTS, READONLY \end{lstlisting} \subsection{Часть II. Реализация обработчиков прерываний в $\mu$C/OS-II} В приложении \hrf{appendix:pt2isr} представлен полный листинг программы, включающий обработку прерываний. Основным отличием является подключение функции обработки прерываний (в листинге \hrf{lst:addisr} представлены фрагмент фукнции инициализации со строкой подключения и функция обработчика). Также, согласно задания, функция \code{send\_task} была изменена таким образом, чтобы отправлять сообщения в очередь не по таймеру, а по сигналу от обработчика прерываний. \begin{lstlisting}[language=C,style=CCodeStyle,label={lst:addisr},caption=Функция обработки прерываний и изменённая функция \code{send\_task}] void isr_button(void* context, alt_u32 id) { INT32U value; INT8U return_code = OS_ERR_NONE; //inform entering isr OSIntEnter(); value = IORD_ALTERA_AVALON_PIO_DATA(BUTTONS_BASE); IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTONS_BASE,0); //send to queue return_code = OSQPostOpt(buttonqueue, (void *)value, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); IORD_ALTERA_AVALON_PIO_EDGE_CAP(BUTTONS_BASE); //inform leaving isr OSIntExit(); } void send_task(void* pdata) { INT8U return_code = OS_ERR_NONE; INT32U msg; while (1) { msg = (INT32U) OSQPend(buttonqueue, 0, &return_code); if (return_code != OS_ERR_NONE) continue; return_code = OSQPostOpt(msgqueue, (void*) msg, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); } } void initialize_task(void* pdata) { //... IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTONS_BASE, 0xf); IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTONS_BASE, 0x0); return_code = alt_irq_register(BUTTONS_IRQ, NULL, isr_button); //... } \end{lstlisting} Также для передачи сообщений была создана дополнительная очередь, хранящая сообщения от \code{send\_task} к \code{receive\_task}'ам. \begin{lstlisting}[language=C,style=CCodeStyle] //... OS_EVENT *buttonqueue; //Message queue pointer void *buttonqueueTbl[MSG_QUEUE_SIZE]; // Storage for messages //... int initOSDataStructs(void) { //... buttonqueue = OSQCreate(&buttonqueueTbl[0], MSG_QUEUE_SIZE); return 0; } \end{lstlisting} \section{Индивидуальное задание} К выполнению было выдано следующее индивидуальное задание: \textbf{\circled{11} Каждую кнопку и семисегментный индикатор обслуживает отдельная задача. После нажатия кнопки соответствующий индикатор начинает моргать с частотой 2 Гц и инкрементироваться каждую секунду, пока кнопка удерживается. Нажатия других кнопок при этом игнорируются. После отпускания кнопки моргание и инкремент прекращаются. } Для достижения поставленной цели в коде были применены три очереди (для передачи сообщений \textit{от прерывания} по нажатию кнопок к менеджеру сообщений для задач, обслуживающих кнопки, для сообщений \textit{от менеджера} задач непосредственно к задачам, и \textit{для семисегментного} индикатора). В программе реализована следующая логика: \begin{enumerate} \item В функции прерывания от кнопок в очередь для сообщений от прерывания отправляется сообщение со значением нажатых кнопок; \begin{lstlisting}[language=C,style=CCodeStyle] void isr_button(void* context, alt_u32 id) { INT32U value; INT8U return_code = OS_ERR_NONE; //inform entering isr OSIntEnter(); // read PIO value = IORD_ALTERA_AVALON_PIO_DATA(BUTTONS_BASE); IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTONS_BASE,0); //send to queue <@\lh{red}{return\_code = OSQPostOpt(buttonqueue,}@> <@\lh{red}{(void *)value,}@> <@\lh{red}{OS\_POST\_OPT\_BROADCAST);}@> alt_ucosii_check_return_code(return_code); IORD_ALTERA_AVALON_PIO_EDGE_CAP(BUTTONS_BASE); //inform leaving isr OSIntExit(); } \end{lstlisting} \item менеджер очередей ожидает сообщения в очереди прерываний, фильтрует нажатия (игнорирует любые \textit{комбинации} нажатых кнопок) и отправляет два сообщения: в очередь для кнопок (значения нажатых кнопок) и в очередь семисегментного индикатора (служебное сообщение о необходимости сбросить счётчик); \begin{lstlisting}[language=C,style=CCodeStyle] void task_manage(void* pdata) { INT8U return_code = OS_ERR_NONE; INT32U msg; while (1) { //when a message from ISR is pending msg = (INT32U) OSQPend(buttonqueue, 0, &return_code); if (return_code != OS_ERR_NONE) continue; // filter if more than one button is pressed and send to q if (msg == BTN_1_IRQ || msg == BTN_2_IRQ || msg == BTN_3_IRQ || msg == BTN_4_IRQ) { return_code = OSQPostOpt(msgqueue, (void*) msg, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); return_code = OSQPostOpt(ssegqueue, (void*) SEV_SEG_RESET, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); } } } \end{lstlisting} \item Каждая задача, обслуживающая кнопки ожидает сообщения в своей очереди, читает его и формирует сообщение в очередь для семисегментного индикатора. \begin{lstlisting}[language=C,style=CCodeStyle] void task_btn1(void* pdata) { INT8U return_code = OS_ERR_NONE; INT32U msg = 0; while (1) { // read from q msg = (INT32U)OSQPend(msgqueue, 0, &return_code); alt_ucosii_check_return_code(return_code); // if it's my btn - send to sseg task a shift for counter if (msg == BTN_1_IRQ) { //<@\lh{dkgreen}{аналогично для BTN 2, 3, 4}@> return_code = OSQPostOpt(ssegqueue, (void*) BTN_1_SHIFT, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); } } } \end{lstlisting} \item Таймер включается при инициализации и работает постоянно, вызывая функцию обработки прерываний два раза в секунду. В обработчике таймера в очередь семисегментного индикатора кладётся сообщение о факте срабатывания таймера. \begin{lstlisting}[language=C,style=CCodeStyle] void timer2Hz(void* ptmr, void* args) { INT8U return_code = OS_ERR_NONE; return_code = OSQPostOpt(ssegqueue, (void *)SEV_SEG_SWITCH, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); } \end{lstlisting} \item Задача, обслуживающая семисегментный индикатор ожидает сообщения в своей очереди и выключает индикатор или записывает в него предыдущее значение. Также задача перед записью (два раза в секунду) проверяет регистр прерываний от \code{BUTTONS\_PIO} (не нажата ли какая-то кнопка): если нажата - каждое второе срабатывание таймера инкрементирует предыдущее запомненное значение, а если не нажата - выставляет на флагах нули, разрешая таким образом обработчику прерываний от кнопок отправку сообщений в свою очередь и выставляет в счётчике 0; \begin{lstlisting}[language=C,style=CCodeStyle] void task_sseg(void *pdata) { INT8U return_code = OS_ERR_NONE; INT32U msg; INT32U buttons; INT32U value = 0; INT32U multiplier; while (1) { //pend q msg = (INT32U)OSQPend(ssegqueue, 0, &return_code); alt_ucosii_check_return_code(return_code); // is something pressed? buttons = IORD_ALTERA_AVALON_PIO_DATA(BUTTONS_BASE); // if only one is pressed if (buttons != 15) { // if msg from timer = switch visiblity switch (msg) { case SEV_SEG_SWITCH: isOn = ~isOn; break; case SEV_SEG_RESET: value = 0; break; case BTN_1_SHIFT: case BTN_2_SHIFT: case BTN_3_SHIFT: case BTN_4_SHIFT: multiplier = msg; break; default: printf("something went very wrong!"); } if (isOn) { IOWR_ALTERA_AVALON_PIO_DATA(SEVEN_SEG_BASE, -1); value++; } else { sevenseg_set_hex((value & 15) * multiplier); } } } } \end{lstlisting} \end{enumerate} Также была незначительно доработана функция вывода данных на семисегментный индикатор (расширена для использования всех четырёх индикаторов). \begin{lstlisting}[language=C,style=CCodeStyle] static void sevenseg_set_hex(int hex) { static alt_u8 segments[16] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, /* 0-9 */ 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E }; /* a-f */ unsigned int data = segments[hex & 15] | (segments[(hex >> 4) & 15] << 8) | (segments[(hex >> 8) & 15] << 16) | (segments[(hex >> 12) & 15] << 24); IOWR_ALTERA_AVALON_PIO_DATA(SEVEN_SEG_BASE, data); } \end{lstlisting} Полный листинг программы, решающей задачу представлен в приложении \hrf{appendix:indi}. \newpage \appendix \setcounter{secnumdepth}{5} \section*{Приложения} \addcontentsline{toc}{section}{Приложения} \renewcommand{\thesubsection}{\Alph{subsection}} \subsection{Полный листинг программы для простой системы} \label{appendix:pt1full} \begin{lstlisting}[language=C,style=CCodeStyle] #include #include #include #include "includes.h" #include "alt_ucosii_simple_error_check.h" #include "altera_avalon_pio_regs.h" /* Ñòåêè çàäà÷ */ #define TASK_STACKSIZE 1024 OS_STK initialize_task_stk[TASK_STACKSIZE]; OS_STK print_status_task_stk[TASK_STACKSIZE]; OS_STK getsem_task1_stk[TASK_STACKSIZE]; OS_STK getsem_task2_stk[TASK_STACKSIZE]; OS_STK receive_task1_stk[TASK_STACKSIZE]; OS_STK receive_task2_stk[TASK_STACKSIZE]; OS_STK send_task_stk[TASK_STACKSIZE]; /* Ïðèîðèòåòû çàäà÷ */ #define INITIALIZE_TASK_PRIORITY 6 #define PRINT_STATUS_TASK_PRIORITY 7 #define GETSEM_TASK1_PRIORITY 8 #define GETSEM_TASK2_PRIORITY 9 #define RECEIVE_TASK1_PRIORITY 10 #define RECEIVE_TASK2_PRIORITY 11 #define SEND_TASK_PRIORITY 12 /* Îáúÿâëåíèå î÷åðåäè */ #define MSG_QUEUE_SIZE 30 //Size of message queue used in example OS_EVENT *msgqueue; //Message queue pointer void *msgqueueTbl[MSG_QUEUE_SIZE]; // Storage for messages /* Îáúÿâëåíèå ñåìàôîðà */ OS_EVENT *shared_resource_sem; /* Ãëîáàëüíûå ïåðåìåííûå */ INT32U number_of_messages_sent = 0; INT32U number_of_messages_received_task1 = 0; INT32U number_of_messages_received_task2 = 0; INT32U getsem_task1_got_sem = 0; INT32U getsem_task2_got_sem = 0; char sem_owner_task_name[20]; /* Ïðîòîòèïû ôóíêöèé */ int initOSDataStructs(void); int initCreateTasks(void); void print_status_task(void* pdata) { while (1) { OSTimeDlyHMSM(0, 0, 3, 0); printf("****************************************************************\n"); printf("Hello From MicroC/OS-II Running on NIOS II. Here is the status:\n"); printf("\n"); printf("The number of messages sent by the send_task: %lu\n", number_of_messages_sent); printf("\n"); printf("The number of messages received by the receive_task1: %lu\n", number_of_messages_received_task1); printf("\n"); printf("The number of messages received by the receive_task2: %lu\n", number_of_messages_received_task2); printf("\n"); printf("The shared resource is owned by: %s\n", &sem_owner_task_name[0]); printf("\n"); printf("The Number of times getsem_task1 acquired the semaphore %lu\n", getsem_task1_got_sem); printf("\n"); printf("The Number of times getsem_task2 acquired the semaphore %lu\n", getsem_task2_got_sem); printf("\n"); printf("****************************************************************\n"); printf("\n"); } } void getsem_task1(void* pdata) { INT8U return_code = OS_NO_ERR; while (1) { OSSemPend(shared_resource_sem, 0, &return_code); alt_ucosii_check_return_code(return_code); strcpy(&sem_owner_task_name[0], "getsem_task1"); getsem_task1_got_sem++; OSSemPost(shared_resource_sem); OSTimeDlyHMSM(0, 0, 0, 100); } } void getsem_task2(void* pdata) { INT8U return_code = OS_NO_ERR; INT8U led; led=1; while (1) { led = led << 1; if (led == 0) led = 1; IOWR_ALTERA_AVALON_PIO_DATA(GREEN_LED_BASE,led); OSSemPend(shared_resource_sem, 0, &return_code); strcpy(&sem_owner_task_name[0], "getsem_task2"); alt_ucosii_check_return_code(return_code); getsem_task2_got_sem++; OSSemPost(shared_resource_sem); OSTimeDlyHMSM(0, 0, 0, 130); } } void send_task(void* pdata) { INT8U return_code = OS_NO_ERR; INT32U msg = 0; OS_Q_DATA queue_data; while (1) { return_code = OSQQuery(msgqueue, &queue_data); alt_ucosii_check_return_code(return_code); if(queue_data.OSNMsgs < MSG_QUEUE_SIZE) { return_code = OSQPostOpt(msgqueue, (void *)&msg, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); msg++; number_of_messages_sent++; } else { OSTimeDlyHMSM(0, 0, 1, 0); } } } void receive_task1(void* pdata) { INT8U return_code = OS_NO_ERR; INT32U *msg; while (1) { msg = (INT32U *)OSQPend(msgqueue, 0, &return_code); alt_ucosii_check_return_code(return_code); number_of_messages_received_task1++; OSTimeDlyHMSM(0, 0, 0, 333); } } void receive_task2(void* pdata) { INT8U return_code = OS_NO_ERR; INT32U *msg; while (1) { msg = (INT32U *)OSQPend(msgqueue, 0, &return_code); alt_ucosii_check_return_code(return_code); number_of_messages_received_task2++; OSTimeDlyHMSM(0, 0, 1, 0); } } void initialize_task(void* pdata) { INT8U return_code = OS_NO_ERR; initOSDataStructs(); initCreateTasks(); return_code = OSTaskDel(OS_PRIO_SELF); alt_ucosii_check_return_code(return_code); while (1); } int main (int argc, char* argv[], char* envp[]) { INT8U return_code = OS_NO_ERR; return_code = OSTaskCreate(initialize_task, NULL, (void *)&initialize_task_stk[TASK_STACKSIZE-1], INITIALIZE_TASK_PRIORITY); alt_ucosii_check_return_code(return_code); OSStart(); return 0; } int initOSDataStructs(void) { msgqueue = OSQCreate(&msgqueueTbl[0], MSG_QUEUE_SIZE); shared_resource_sem = OSSemCreate(1); return 0; } int initCreateTasks(void) { INT8U return_code = OS_NO_ERR; return_code = OSTaskCreate(getsem_task1, NULL, (void *)&getsem_task1_stk[TASK_STACKSIZE-1], GETSEM_TASK1_PRIORITY); return_code = OSTaskCreate(getsem_task2, NULL, (void *)&getsem_task2_stk[TASK_STACKSIZE-1], GETSEM_TASK2_PRIORITY); return_code = OSTaskCreate(receive_task1, NULL, (void *)&receive_task1_stk[TASK_STACKSIZE-1], RECEIVE_TASK1_PRIORITY); alt_ucosii_check_return_code(return_code); return_code = OSTaskCreate(receive_task2, NULL, (void *)&receive_task2_stk[TASK_STACKSIZE-1], RECEIVE_TASK2_PRIORITY); alt_ucosii_check_return_code(return_code); return_code = OSTaskCreate(send_task, NULL, (void *)&send_task_stk[TASK_STACKSIZE-1], SEND_TASK_PRIORITY); alt_ucosii_check_return_code(return_code); return_code = OSTaskCreate(print_status_task, NULL, (void *)&print_status_task_stk[TASK_STACKSIZE-1], PRINT_STATUS_TASK_PRIORITY); alt_ucosii_check_return_code(return_code); return 0; } \end{lstlisting} \subsection{Полный листинг программы с обработчиком прерываний} \label{appendix:pt2isr} \begin{lstlisting}[language=C,style=CCodeStyle] #include #include #include #include "includes.h" #include "alt_ucosii_simple_error_check.h" #include "altera_avalon_pio_regs.h" // <@\lh{dkgreen}{Стеки задач}@> #define TASK_STACKSIZE 1024 OS_STK initialize_task_stk[TASK_STACKSIZE]; OS_STK print_status_task_stk[TASK_STACKSIZE]; OS_STK getsem_task1_stk[TASK_STACKSIZE]; OS_STK getsem_task2_stk[TASK_STACKSIZE]; OS_STK receive_task1_stk[TASK_STACKSIZE]; OS_STK receive_task2_stk[TASK_STACKSIZE]; OS_STK send_task_stk[TASK_STACKSIZE]; // <@\lh{dkgreen}{Приоритеты задач}@> #define INITIALIZE_TASK_PRIORITY 6 #define PRINT_STATUS_TASK_PRIORITY 7 #define GETSEM_TASK1_PRIORITY 8 #define GETSEM_TASK2_PRIORITY 9 #define RECEIVE_TASK1_PRIORITY 10 #define RECEIVE_TASK2_PRIORITY 11 #define SEND_TASK_PRIORITY 12 // <@\lh{dkgreen}{Объявление очереди}@> #define MSG_QUEUE_SIZE 30 /*Size of message queue used in example*/ OS_EVENT *msgqueue; //Message queue pointer void *msgqueueTbl[MSG_QUEUE_SIZE]; // Storage for messages OS_EVENT *buttonqueue; //Message queue pointer void *buttonqueueTbl[MSG_QUEUE_SIZE]; // Storage for messages int btnLog[32]; int btnLogPtr = 0; // <@\lh{dkgreen}{Объявление семафора}@> OS_EVENT *shared_resource_sem; // <@\lh{dkgreen}{Глобальные переменные}@> INT32U number_of_messages_sent = 0; INT32U number_of_messages_received_task1 = 0; INT32U number_of_messages_received_task2 = 0; INT32U getsem_task1_got_sem = 0; INT32U getsem_task2_got_sem = 0; char sem_owner_task_name[20]; // <@\lh{dkgreen}{Прототипы функций}@> int initOSDataStructs(void); int initCreateTasks(void); static void sevenseg_set_hex(int hex) { static alt_u8 segments[16] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, //0-9 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E }; //a-f unsigned data = segments[hex & 15] | (segments[(hex > > 4)&15] << 8); IOWR_ALTERA_AVALON_PIO_DATA(SEVEN_SEG_BASE, data); } void print_status_task(void* pdata) { INT8U retCode = OS_ERR_NONE; INT8U bretCode = OS_ERR_NONE; OS_Q_DATA qData; OS_Q_DATA qbData; while (1) { OSTimeDlyHMSM(0, 0, 10, 0); printf("TIME: %10lu sec\n", OSTimeGet() / OS_TICKS_PER_SEC); retCode = OSQQuery(msgqueue, &qData); if (retCode == OS_ERR_NONE) { printf("MESSAGES: %7i\n", qData.OSNMsgs); } else { printf("QUEUE_ERR: %6i\n", retCode); } int p; for (p = 0; p < 32; ++p) printf("%d, ", btnLog[p]); printf("\n"); for (p = 0; p < 32; ++p) btnLog[p] = 0; btnLogPtr = 0; bretCode = OSQQuery(buttonqueue, &qbData); if (bretCode == OS_ERR_NONE) { printf("BTNS MSGS: %7i\n", qbData.OSNMsgs); } else { printf("QUEUE_ERR: %6i\n", bretCode); } printf("****************************************************************\n"); printf("Hello From MicroC/OS-II Running on NIOS II. Here is the status:\n"); printf("The number of messages sent by the send_task: %lu\n", number_of_messages_sent); printf("The number of messages received by the receive_task1: %lu\n", number_of_messages_received_task1); printf("The number of messages received by the receive_task2: %lu\n", number_of_messages_received_task2); printf("The shared resource is owned by: %s\n", &sem_owner_task_name[0]); printf("The Number of times getsem_task1 acquired the semaphore %lu\n", getsem_task1_got_sem); printf("The Number of times getsem_task2 acquired the semaphore %lu\n", getsem_task2_got_sem); printf("****************************************************************\n"); printf("\n"); } } void getsem_task1(void* pdata) { INT8U return_code = OS_NO_ERR; while (1) { OSSemPend(shared_resource_sem, 0, &return_code); alt_ucosii_check_return_code(return_code); strcpy(&sem_owner_task_name[0], "getsem_task1"); getsem_task1_got_sem++; OSSemPost(shared_resource_sem); OSTimeDlyHMSM(0, 0, 0, 100); } } void getsem_task2(void* pdata) { INT8U return_code = OS_NO_ERR; INT8U led; led = 1; while (1) { led = led << 1; if (led == 0) led = 1; IOWR_ALTERA_AVALON_PIO_DATA(GREEN_LED_BASE,led); OSSemPend(shared_resource_sem, 0, &return_code); strcpy(&sem_owner_task_name[0], "getsem_task2"); alt_ucosii_check_return_code(return_code); getsem_task2_got_sem++; OSSemPost(shared_resource_sem); OSTimeDlyHMSM(0, 0, 0, 130); } } void send_task(void* pdata) { INT8U return_code = OS_ERR_NONE; INT32U msg; while (1) { msg = (INT32U) OSQPend(buttonqueue, 0, &return_code); if (return_code != OS_ERR_NONE) continue; return_code = OSQPostOpt(msgqueue, (void*) msg, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); } } void receive_task1(void* pdata) { INT8U return_code = OS_ERR_NONE; INT32U msg; while (1) { msg = (INT32U)OSQPend(msgqueue, 0, &return_code); alt_ucosii_check_return_code(return_code); sevenseg_set_hex(msg); } } void receive_task2(void* pdata) { INT8U return_code = OS_NO_ERR; INT32U msg; while (1) { msg = (INT32U)OSQPend(msgqueue, 0, &return_code); alt_ucosii_check_return_code(return_code); printf("pressed %d", msg); if (btnLogPtr < 31) btnLog[btnLogPtr++] = msg; } } void isr_button(void* context, alt_u32 id) { INT32U value; INT8U return_code = OS_ERR_NONE; //inform entering isr OSIntEnter(); value = IORD_ALTERA_AVALON_PIO_DATA(BUTTONS_BASE); IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTONS_BASE,0); //send to queue return_code = OSQPostOpt(buttonqueue, (void *)value, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); IORD_ALTERA_AVALON_PIO_EDGE_CAP(BUTTONS_BASE); //inform leaving isr OSIntExit(); } void initialize_task(void* pdata) { INT8U return_code = OS_NO_ERR; initOSDataStructs(); initCreateTasks(); IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTONS_BASE, 0xf); IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTONS_BASE, 0x0); return_code = alt_irq_register(BUTTONS_IRQ, NULL, isr_button); return_code = OSTaskDel(OS_PRIO_SELF); alt_ucosii_check_return_code(return_code); while (1); } int main (int argc, char* argv[], char* envp[]) { INT8U return_code = OS_NO_ERR; return_code = OSTaskCreate(initialize_task, NULL, (void *)&initialize_task_stk[TASK_STACKSIZE-1], INITIALIZE_TASK_PRIORITY); alt_ucosii_check_return_code(return_code); OSStart(); return 0; } int initOSDataStructs(void) { msgqueue = OSQCreate(&msgqueueTbl[0], MSG_QUEUE_SIZE); buttonqueue = OSQCreate(&buttonqueueTbl[0], MSG_QUEUE_SIZE); shared_resource_sem = OSSemCreate(1); return 0; } int initCreateTasks(void) { INT8U return_code = OS_NO_ERR; return_code = OSTaskCreate(getsem_task1, NULL, (void *)&getsem_task1_stk[TASK_STACKSIZE-1], GETSEM_TASK1_PRIORITY); return_code = OSTaskCreate(getsem_task2, NULL, (void *)&getsem_task2_stk[TASK_STACKSIZE-1], GETSEM_TASK2_PRIORITY); return_code = OSTaskCreate(receive_task1, NULL, (void *)&receive_task1_stk[TASK_STACKSIZE-1], RECEIVE_TASK1_PRIORITY); alt_ucosii_check_return_code(return_code); return_code = OSTaskCreate(receive_task2, NULL, (void *)&receive_task2_stk[TASK_STACKSIZE-1], RECEIVE_TASK2_PRIORITY); alt_ucosii_check_return_code(return_code); return_code = OSTaskCreate(send_task, NULL, (void *)&send_task_stk[TASK_STACKSIZE-1], SEND_TASK_PRIORITY); alt_ucosii_check_return_code(return_code); return_code = OSTaskCreate(print_status_task, NULL, (void *)&print_status_task_stk[TASK_STACKSIZE-1], PRINT_STATUS_TASK_PRIORITY); alt_ucosii_check_return_code(return_code); return 0; } \end{lstlisting} \subsection{Полный листинг программы выполняющей индивидуальное задание} \label{appendix:indi} \begin{lstlisting}[language=C,style=CCodeStyle] #include #include #include #include "includes.h" #include "alt_ucosii_simple_error_check.h" #include "altera_avalon_pio_regs.h" /* Ñòåêè çàäà÷ */ #define TASK_STACKSIZE 1024 OS_STK initialize_task_stk[TASK_STACKSIZE]; OS_STK print_status_task_stk[TASK_STACKSIZE]; OS_STK task_btn1_stk[TASK_STACKSIZE]; OS_STK task_btn2_stk[TASK_STACKSIZE]; OS_STK task_btn3_stk[TASK_STACKSIZE]; OS_STK task_btn4_stk[TASK_STACKSIZE]; OS_STK task_sseg_stk[TASK_STACKSIZE]; OS_STK task_manage_stk[TASK_STACKSIZE]; /* Ïðèîðèòåòû çàäà÷ */ #define INITIALIZE_TASK_PRIORITY 6 #define PRINT_STATUS_TASK_PRIORITY 7 #define task_sseg_PRIORITY 9 #define task_btn1_PRIORITY 10 #define task_btn2_PRIORITY 11 #define task_btn3_PRIORITY 12 #define task_btn4_PRIORITY 13 #define task_manage_PRIORITY 14 #define SEV_SEG_SWITCH 2 #define SEV_SEG_RESET 3 #define BTN_1_IRQ 7 #define BTN_2_IRQ 11 #define BTN_3_IRQ 13 #define BTN_4_IRQ 14 #define BTN_1_SHIFT 4096 #define BTN_2_SHIFT 256 #define BTN_3_SHIFT 16 #define BTN_4_SHIFT 1 /* Îáúÿâëåíèå î÷åðåäè */ #define MSG_QUEUE_SIZE 30 //Size of message queue used in example OS_EVENT *msgqueue; //Message queue pointer void *msgqueueTbl[MSG_QUEUE_SIZE]; // Storage for messages OS_EVENT *buttonqueue; //Message queue pointer void *buttonqueueTbl[MSG_QUEUE_SIZE]; // Storage for messages OS_EVENT *ssegqueue; //Message queue pointer void *ssegqueueTbl[MSG_QUEUE_SIZE]; // Storage for messages int btnLog[32]; int btnLogPtr = 0; /* Ãëîáàëüíûå ïåðåìåííûå */ INT32U number_of_messages_sent = 0; INT32U number_of_messages_received_task1 = 0; INT32U number_of_messages_received_task2 = 0; volatile int isOn = 0; OS_TMR *Timer2Hz; /* Ïðîòîòèïû ôóíêöèé */ int initOSDataStructs(void); int initCreateTasks(void); static void sevenseg_set_hex(int hex) { static alt_u8 segments[16] = { 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, /* 0-9 */ 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E }; /* a-f */ unsigned int data = segments[hex & 15] | (segments[(hex >> 4) & 15] << 8) | (segments[(hex >> 8) & 15] << 16) | (segments[(hex >> 12) & 15] << 24); IOWR_ALTERA_AVALON_PIO_DATA(SEVEN_SEG_BASE, data); } void print_status_task(void* pdata) { INT8U retCode = OS_ERR_NONE; INT8U bretCode = OS_ERR_NONE; OS_Q_DATA qData; OS_Q_DATA qbData; while (1) { OSTimeDlyHMSM(0, 0, 10, 0); printf("TIME: %10lu sec\n", OSTimeGet() / OS_TICKS_PER_SEC); retCode = OSQQuery(msgqueue, &qData); if (retCode == OS_ERR_NONE) { printf("MESSAGES: %7i\n", qData.OSNMsgs); } else { printf("QUEUE_ERR: %6i\n", retCode); } int p; for (p = 0; p < 32; ++p) printf("%d, ", btnLog[p]); printf("\n"); for (p = 0; p < 32; ++p) btnLog[p] = 0; btnLogPtr = 0; bretCode = OSQQuery(buttonqueue, &qbData); if (bretCode == OS_ERR_NONE) { printf("BTNS MSGS: %7i\n", qbData.OSNMsgs); } else { printf("QUEUE_ERR: %6i\n", bretCode); } printf("****************************************************************\n"); printf("Hello From MicroC/OS-II Running on NIOS II. Here is the status:\n"); printf("The number of messages sent by the task_manage: %lu\n", number_of_messages_sent); printf("The number of messages received by the task_btn1: %lu\n", number_of_messages_received_task1); printf("The number of messages received by the task_btn2: %lu\n", number_of_messages_received_task2); printf("****************************************************************\n"); printf("\n"); } } void task_sseg(void *pdata) { INT8U return_code = OS_ERR_NONE; INT32U msg; INT32U buttons; INT32U value = 0; INT32U multiplier; while (1) { //pend q msg = (INT32U)OSQPend(ssegqueue, 0, &return_code); alt_ucosii_check_return_code(return_code); // is something pressed? buttons = IORD_ALTERA_AVALON_PIO_DATA(BUTTONS_BASE); // if only one is pressed if (buttons != 15) { // if msg from timer = switch visiblity switch (msg) { case SEV_SEG_SWITCH: isOn = ~isOn; break; case SEV_SEG_RESET: value = 0; break; case BTN_1_SHIFT: case BTN_2_SHIFT: case BTN_3_SHIFT: case BTN_4_SHIFT: multiplier = msg; break; default: printf("something went very wrong!"); } if (isOn) { IOWR_ALTERA_AVALON_PIO_DATA(SEVEN_SEG_BASE, -1); value++; } else { sevenseg_set_hex((value & 15) * multiplier); } } } } void task_manage(void* pdata) { INT8U return_code = OS_ERR_NONE; INT32U msg; while (1) { //when a message from ISR is pending msg = (INT32U) OSQPend(buttonqueue, 0, &return_code); if (return_code != OS_ERR_NONE) continue; // filter if more than one button is pressed and send to q if (msg == BTN_1_IRQ || msg == BTN_2_IRQ || msg == BTN_3_IRQ || msg == BTN_4_IRQ) { return_code = OSQPostOpt(msgqueue, (void*) msg, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); return_code = OSQPostOpt(ssegqueue, (void*) SEV_SEG_RESET, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); } } } void task_btn1(void* pdata) { INT8U return_code = OS_ERR_NONE; INT32U msg = 0; while (1) { // read from q msg = (INT32U)OSQPend(msgqueue, 0, &return_code); alt_ucosii_check_return_code(return_code); // if it's my btn - send to sseg task a shift for counter if (msg == BTN_1_IRQ) { return_code = OSQPostOpt(ssegqueue, (void*) BTN_1_SHIFT, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); } } } void task_btn2(void* pdata) { INT8U return_code = OS_ERR_NONE; INT32U msg = 0; while (1) { // read from q msg = (INT32U)OSQPend(msgqueue, 0, &return_code); alt_ucosii_check_return_code(return_code); // if it's my btn - send to sseg task a shift for counter if (msg == BTN_2_IRQ) { return_code = OSQPostOpt(ssegqueue, (void*) BTN_2_SHIFT, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); } } } void task_btn3(void* pdata) { INT8U return_code = OS_ERR_NONE; INT32U msg = 0; while (1) { // read from q msg = (INT32U)OSQPend(msgqueue, 0, &return_code); alt_ucosii_check_return_code(return_code); // if it's my btn - send to sseg task a shift for counter if (msg == BTN_3_IRQ) { return_code = OSQPostOpt(ssegqueue, (void*) BTN_3_SHIFT, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); } } } void task_btn4(void* pdata) { INT8U return_code = OS_ERR_NONE; INT32U msg = 0; while (1) { // read from q msg = (INT32U)OSQPend(msgqueue, 0, &return_code); alt_ucosii_check_return_code(return_code); // if it's my btn - send to sseg task a shift for counter if (msg == BTN_4_IRQ) { return_code = OSQPostOpt(ssegqueue, (void*) BTN_4_SHIFT, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); } } } void timer2Hz(void* ptmr, void* args) { INT8U return_code = OS_ERR_NONE; return_code = OSQPostOpt(ssegqueue, (void *)SEV_SEG_SWITCH, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); } void isr_button(void* context, alt_u32 id) { INT32U value; INT8U return_code = OS_ERR_NONE; //inform entering isr OSIntEnter(); // read PIO value = IORD_ALTERA_AVALON_PIO_DATA(BUTTONS_BASE); IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTONS_BASE,0); //send to queue return_code = OSQPostOpt(buttonqueue, (void *)value, OS_POST_OPT_BROADCAST); alt_ucosii_check_return_code(return_code); IORD_ALTERA_AVALON_PIO_EDGE_CAP(BUTTONS_BASE); //inform leaving isr OSIntExit(); } void initialize_task(void* pdata) { INT8U return_code = OS_ERR_NONE; Timer2Hz = OSTmrCreate(0, 5, OS_TMR_OPT_PERIODIC, timer2Hz, (void*) 0, "blink 2hz", &return_code); alt_ucosii_check_return_code(return_code); OSTmrStart(Timer2Hz, &return_code); alt_ucosii_check_return_code(return_code); initOSDataStructs(); initCreateTasks(); IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTONS_BASE, 0xf); IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTONS_BASE, 0x0); IOWR_ALTERA_AVALON_PIO_DATA(SEVEN_SEG_BASE, -1); return_code = alt_irq_register(BUTTONS_IRQ, NULL, isr_button); return_code = OSTaskDel(OS_PRIO_SELF); alt_ucosii_check_return_code(return_code); while (1); } int main (int argc, char* argv[], char* envp[]) { INT8U return_code = OS_ERR_NONE; return_code = OSTaskCreate(initialize_task, NULL, (void *)&initialize_task_stk[TASK_STACKSIZE-1], INITIALIZE_TASK_PRIORITY); alt_ucosii_check_return_code(return_code); OSStart(); return 0; } int initOSDataStructs(void) { msgqueue = OSQCreate(&msgqueueTbl[0], MSG_QUEUE_SIZE); buttonqueue = OSQCreate(&buttonqueueTbl[0], MSG_QUEUE_SIZE); ssegqueue = OSQCreate(&ssegqueueTbl[0], MSG_QUEUE_SIZE); return 0; } int initCreateTasks(void) { INT8U return_code = OS_ERR_NONE; return_code = OSTaskCreate(task_sseg, NULL, (void *)&task_sseg_stk[TASK_STACKSIZE-1], task_sseg_PRIORITY); alt_ucosii_check_return_code(return_code); return_code = OSTaskCreate(task_btn1, NULL, (void *)&task_btn1_stk[TASK_STACKSIZE-1], task_btn1_PRIORITY); alt_ucosii_check_return_code(return_code); return_code = OSTaskCreate(task_btn2, NULL, (void *)&task_btn2_stk[TASK_STACKSIZE-1], task_btn2_PRIORITY); alt_ucosii_check_return_code(return_code); return_code = OSTaskCreate(task_btn3, NULL, (void *)&task_btn3_stk[TASK_STACKSIZE-1], task_btn3_PRIORITY); alt_ucosii_check_return_code(return_code); return_code = OSTaskCreate(task_btn4, NULL, (void *)&task_btn4_stk[TASK_STACKSIZE-1], task_btn4_PRIORITY); alt_ucosii_check_return_code(return_code); return_code = OSTaskCreate(task_manage, NULL, (void *)&task_manage_stk[TASK_STACKSIZE-1], task_manage_PRIORITY); alt_ucosii_check_return_code(return_code); return_code = OSTaskCreate(print_status_task, NULL, (void *)&print_status_task_stk[TASK_STACKSIZE-1], PRINT_STATUS_TASK_PRIORITY); alt_ucosii_check_return_code(return_code); return 0; } \end{lstlisting} \end{document}