Jump to content

    

ucos+nios+isr

Доброго времени суток.

Создаю в eclipse проект на основе примера hello usoc. В нем есть две задачи, которые попеременно выводят в консоль сообщения, все вроде бы просто и понятно. В моей процессорной системе (Nios) есть порт (input) PIO. Он настроен на генерацию прерываний по нажатию на кнопку на моем борде. Если говорить о "чистом " C коде, то как зарегистрировать прерывания и описать их обработчик мне известно (через ф-ию alt_irq_register() и т.д.). В примере hello usoc я так и сделал, вот пример кода:

 

#include <stdio.h>

#include "includes.h"

#include "system.h"

#include "altera_avalon_pio_regs.h"

//#include "altera_avalon_pio_regs.h"

/* Definition of Task Stacks */

#define TASK_STACKSIZE 2048

OS_STK task1_stk[TASK_STACKSIZE];

OS_STK task2_stk[TASK_STACKSIZE];

 

/* Definition of Task Priorities */

 

#define TASK1_PRIORITY 1

#define TASK2_PRIORITY 8

volatile int buttons=0;

int led=0;

static void button_isr( void * base, alt_u32 id )

{

buttons = IORD_ALTERA_AVALON_PIO_EDGE_CAP(base);

IOWR_ALTERA_AVALON_PIO_EDGE_CAP(base,0x3);

}

 

 

void task1(void* pdata)

{

 

while (1)

{

if (buttons != 0)

{

switch (buttons) {

case 1:

alt_printf("Нажата кнопка pb_left\n ");

if (led == 0x80||led==0x00 )

led = 0x01;

else

led = led << 1;

buttons = 0;

break;

 

case 2:

alt_printf("Нажата кнопка pb_right\n ");

if (led == 0x01 ||led==0x00 )

led = 0x80;

else

led = led >> 1;

buttons = 0;

break;

 

default:

buttons = 0;

break;

}

IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE,led);

}

printf("Hello from task1\n");

//OSTimeDlyHMSM(0, 0, 1, 0);

}

}

void task2(void* pdata)

{

while (1)

{

alt_irq_register(BUTTONS_IRQ, (void*)BUTTONS_BASE, button_isr);

printf("Hello from task2\n");

//OSTimeDlyHMSM(0, 0, 1, 0);

}

}

/* The main function creates two task and starts multi-tasking */

int main(void)

{

IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE,0x00);

IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTONS_BASE, 0x3);

IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTONS_BASE, 0x3);

alt_irq_register(BUTTONS_IRQ, (void*)BUTTONS_BASE, button_isr);

 

OSTaskCreateExt(task1,

NULL,

(void *)&task1_stk[TASK_STACKSIZE-1],

TASK1_PRIORITY,

TASK1_PRIORITY,

task1_stk,

TASK_STACKSIZE,

NULL,

0);

 

 

OSTaskCreateExt(task2,

NULL,

(void *)&task2_stk[TASK_STACKSIZE-1],

TASK2_PRIORITY,

TASK2_PRIORITY,

task2_stk,

TASK_STACKSIZE,

NULL,

0);

OSStart();

 

return 0;

}

 

Но я чувствую, что в ucos такая работа с прерываниями некорректна.

Подскажите пожалуйста, какова идеология работы с прерываниями под ucos, и как должен выглядеть обработчик прерываний в моем случае, то есть описанный штатными средствами операционной системы?

Если есть возможность поделитесь простым примером, от которого можно оттолкнутся.

Share this post


Link to post
Share on other sites

Обработчик как обработчик. Можете поллингом сделать:

 

while(1)

{

if(BUTTON_PRESSED()) ...

}

 

Будет и просто, и без volatile, и антидребезг заодно.

Share this post


Link to post
Share on other sites

Правильно ли я Вас понял, Вы предлагаете не использовать обработчик прерываний, а просто считывать состояние порта PIO?

 

Share this post


Link to post
Share on other sites

Тогда я Вас понял, такой вариант тоже возможен, но только меня интересует именно синтаксис описания прерывания штатными средствами OC, может кто-нибудь поделится опытом?

Share this post


Link to post
Share on other sites
Тогда я Вас понял, такой вариант тоже возможен, но только меня интересует именно синтаксис описания прерывания штатными средствами OC, может кто-нибудь поделится опытом?

Использовал на другом процессоре.

Нет там никаких штатных средств описания прерывания, есть только общие слова (ucos-ii)

YourISR:

Save all CPU registers;

Call OSIntEnter() or, increment OSIntNesting directly;

Execute user code to service ISR;

Call OSIntExit();

Restore all CPU registers;

Execute a return from interrupt instruction;

Остальное происходит как описано в даташите на процессор, единственное нельзя ожидать событий от RTOS в прерываниях.

Share this post


Link to post
Share on other sites

Штатные средства ОС такие, что обработчик прерывания вызывается через враппер, который делает всю работу по входу/выходу из прерывания. Если у вас вектор прерываний настроен на работу через этот враппер, то свой обработчик записываете в таблицу обработчиков ОС и он выполнится без дополнительных телодвижений.

Share this post


Link to post
Share on other sites

void task2(void* pdata)
{
while (1)
{
alt_irq_register(BUTTONS_IRQ, (void*)BUTTONS_BASE, button_isr);
printf("Hello from task2\n");
//OSTimeDlyHMSM(0, 0, 1, 0);
}
}

Это вообще ... какая-то, в бесконечном цикле регить обработчик....

 

А вообще, более правильный механизм выглядит так:

1. регим обработчик прерывания

2. заводим семафор

3. заводим таск, которому нужно это прерывание

4. в обработчике прерывания взводим семафор

5. в таске, в начале тела ждем семафора, после чего делаем то, что надо, сбрасываем семафор

ну, это примерная модель, а уже для каждого конкретного случая может немного изменяться.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this