1106 lines
41 KiB
TeX
1106 lines
41 KiB
TeX
|
\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 <stdio.h>
|
|||
|
#include <unistd.h>
|
|||
|
#include <string.h>
|
|||
|
#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 <stdio.h>
|
|||
|
#include <unistd.h>
|
|||
|
#include <string.h>
|
|||
|
#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 <stdio.h>
|
|||
|
#include <unistd.h>
|
|||
|
#include <string.h>
|
|||
|
#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}
|
|||
|
|