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

1106 lines
41 KiB
TeX
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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