2022-12-02 00:05:50 +03:00
\documentclass [a4paper,fontsize=14bp] { article}
2023-10-24 15:47:15 +03:00
\input { settings/common-preamble}
\input { settings/bmstu-preamble}
\input { settings/fancy-listings-preamble}
2022-12-02 00:05:50 +03:00
\setcounter { secnumdepth} { 0}
\numerationTop
2023-10-24 15:47:15 +03:00
\def \makeyear { 2021}
\def \grpNum { 11М }
2022-12-02 00:05:50 +03:00
\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}
2023-10-24 15:47:15 +03:00
В первой части работы была создана простая система на основе О С Р В $ \mu $ C/OS-II. В приложении \hrf { appendix:pt1full} приведён полный листинг готовой программы. Единственным отличием от предложенной в исходном материале было добавление переключения светодиода по вызову задачи второго семафора, согласно методического материала. В листинге \hrf { lst:pt1change} представлен код, добавленный в тело функции \code { getsem_ task2} .
2022-12-02 00:05:50 +03:00
\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}
2023-10-24 15:47:15 +03:00
В приложении \hrf { appendix:pt2isr} представлен полный листинг программы, включающий обработку прерываний. Основным отличием является подключение функции обработки прерываний (в листинге \hrf { lst:addisr} представлены фрагмент фукнции инициализации с о строкой подключения и функция обработчика). Также, согласно задания, функция \code { send_ task} была изменена таким образом, чтобы отправлять сообщения в очередь не по таймеру, а по сигналу от обработчика прерываний.
\begin { lstlisting} [language=C,style=CCodeStyle,label={ lst:addisr} ,caption=Функция обработки прерываний и изменённая функция \code { send_ task} ]
2022-12-02 00:05:50 +03:00
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}
2023-10-24 15:47:15 +03:00
Также для передачи сообщений была создана дополнительная очередь, хранящая сообщения от \code { send_ task} к \code { receive_ task} 'ам.
2022-12-02 00:05:50 +03:00
\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}
2023-10-24 15:47:15 +03:00
\item Задача, обслуживающая семисегментный индикатор ожидает сообщения в своей очереди и выключает индикатор или записывает в него предыдущее значение. Также задача перед записью (два раза в секунду) проверяет регистр прерываний от \code { BUTTONS_ PIO} (не нажата ли какая-то кнопка): если нажата -- каждое второе срабатывание таймера инкрементирует предыдущее запомненное значение, а если не нажата -- выставляет на флагах нули, разрешая таким образом обработчику прерываний от кнопок отправку сообщений в свою очередь и выставляет в счётчике 0;
2022-12-02 00:05:50 +03:00
\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}