BMSTU/01-ess-lab-03-report.tex

1106 lines
41 KiB
TeX
Raw Normal View History

\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}