Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Прерывание от таймера в AT91SAM7X256
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > FreeRTOS
ZAA
Используем FreeRTOS. ВОзникла необходимость использования таймера. Вроде просто так таймер запускается и работает, а вот прерывания не обрабатывает. Я подозреваю, что функцию обработки прерывания нельзя объявлять, как обычную функцию. Наверное, надо прописывать ещё вектор прерывания от таймера где-то там. В том и проблема, что не очень хорошо разбираюсь во всяких там секциях памяти, размещении векторов и т. д (по крайней мере в этом контроллере). Как бы это попроще организовать??? help.gif
ТЕкст (кстати стандартный) приведен ниже:
//ф-ия обработки прерывания
void timer1_c_irq_handler(void)
{
AT91PS_TC TC_pt = AT91C_BASE_TC1;
unsigned int dummy;
//* Acknowledge interrupt status
dummy = TC_pt->TC_SR;
//* Suppress warning variable "dummy" was set but never used
dummy = dummy;
count_timer0_interrupt++;
vParTestToggleLED( 2 );
}

void AT91F_TC_Open ( AT91PS_TC TC_pt, unsigned int Mode, unsigned int TimerId)
{
unsigned int dummy;
AT91F_PMC_EnablePeriphClock ( AT91C_BASE_PMC, 1<< TimerId ) ;
AT91C_BASE_PMC->PMC_PCER = (1<<AT91C_ID_TC1);
TC_pt->TC_CCR = AT91C_TC_CLKDIS ;
TC_pt->TC_IDR = 0xFFFFFFFF ;

dummy = TC_pt->TC_SR;

TC_pt->TC_CMR = Mode ;

TC_pt->TC_CCR = AT91C_TC_CLKEN ;
}

void timer_init ( void )
{
unsigned int oldHandler;
unsigned int mask ;
AT91S_AIC *pAIC = AT91C_BASE_AIC;
AT91S_TC *pTMR = AT91C_BASE_TC1;

//init the timer interrupt counter
count_timer0_interrupt=0;
count_timer1_interrupt=0;

//* Open timer1
AT91F_TC_Open(AT91C_BASE_TC1,TC_CLKS_MCK128,AT91C_ID_TC1);

//* Open Timer 1 interrupt
AT91F_AIC_ConfigureIt ( AT91C_BASE_AIC, AT91C_ID_TC1, TIMER1_INTERRUPT_LEVEL,AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, timer1_c_irq_handler);
AT91C_BASE_TC1->TC_IER = AT91C_TC_CPCS; // IRQ enable CPC
AT91F_AIC_EnableIt (AT91C_BASE_AIC, AT91C_ID_TC1);

//* Start timer1
//AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG ;

}

P.S. Знаю, что подобные посты уже были, но хотелось бы ещё раз остановиться на данной проблеме! Спасибо заранее за ответы.
aaarrr
Цитата(ZAA @ May 22 2008, 09:35) *
Я подозреваю, что функцию обработки прерывания нельзя объявлять, как обычную функцию.

Нельзя. Как правильно объявить прерывание ищите в документации на компилятор.

Цитата(ZAA @ May 22 2008, 09:35) *
P.S. Знаю, что подобные посты уже были, но хотелось бы ещё раз остановиться на данной проблеме! Спасибо заранее за ответы.

Были уже сотню раз. Пользуйтесь поиском.
_4afc_
Цитата(aaarrr @ May 22 2008, 09:40) *
Нельзя. Как правильно объявить прерывание ищите в документации на компилятор.
Были уже сотню раз. Пользуйтесь поиском.

А вот в WinARM обработчики - это обычные функции. Ибо вход в во все прерывания всё-равно один и далее ваша функция вызывается как обычная подпрограмма. Надо только поместить указатель на подпрограмму в соответствующий регистр AIC, что делает не компилятор, а специальная подпрограмма AT91F_AIC_ConfigureIt.
Разница в выходе из обработчика, только в прерываниях по уровню и фронту.
Надо смотреть какой реализован за вас.
aaarrr
Цитата(_4afc_ @ May 22 2008, 11:06) *
Обработчики - это обычные функции. Ибо вход в во все прерывания всё-равно один и далее ваша функция вызывается как обычная подпрограмма.

Представьте себе, далеко не всегда. Более того, обработчики обычно вызываются именно в IRQ режиме. А то, как именно будет вызвана функция, определяется кодом, стартующим с адреса 0x18.

Цитата(_4afc_ @ May 22 2008, 11:06) *
Надо только поместить указатель на подпрограмму в соответствующий регистр AIC, что делает не компилятор, а специальная подпрограмма AT91F_AIC_ConfigureIt.

У любителей использования "специальных подпрограмм AT91F_" обычно плохо с мат. частью.

Цитата(_4afc_ @ May 22 2008, 11:06) *
Разница в выходе из обработчика, только в прерываниях по уровню и фронту.
Надо смотреть какой реализован за вас.

Чушь.

Цитата(_4afc_ @ May 22 2008, 11:06) *
Не путайте божый дар (ARM) с яичницей(AVR).

lol.gif
ZAA
НУ вот, ничего конкретного... crying.gif а ведь хотя бы один маааленький совет может натолкнуть на верный путь
aaarrr
Чтобы получить маааленький совет, укажите:
1. Какой используется компилятор.
2. Какой порт FreeRTOS.
ZAA
Цитата(aaarrr @ May 22 2008, 12:00) *
Чтобы получить маааленький совет, укажите:
1. Какой используется компилятор.
2. Какой порт FreeRTOS.


Я делаю проект в Eclipse для AT91SAM7X256. А компилятор - gcc (который из эклипсовского gnu-армовского набора инструментов). Пыталась найти что-то подобное в инфе про gcc, но безрезультатно...Видимо, или ищу не там, или не то...
А вообще без отладчика тяжко программу писать...
sla000
Цитата(ZAA @ May 22 2008, 19:24) *
Я делаю проект в Eclipse для AT91SAM7X256. А компилятор - gcc (который из эклипсовского gnu-армовского набора инструментов). Пыталась найти что-то подобное в инфе про gcc, но безрезультатно...Видимо, или ищу не там, или не то...
А вообще без отладчика тяжко программу писать...


Тяжело но можно, а потом когда привыкаешь так даже проще )

По вашему случаю рекомендую этот код компилить в ARM режиме, либо разделить код на 2 части и в ARM компилить функцию прерывания, а в THUMB (в котором скомпилен FreeRTOS для SAM7X256) скомпилировать все остальное. Кроме того обратите внимание как обрамлен код прерывания в уже имеющихся прерываниях FreeRTOS. То как сделано сейчас просто уронит ось когда наконец заработает.
ZAA
Цитата(sla000 @ May 23 2008, 06:08) *
Тяжело но можно, а потом когда привыкаешь так даже проще )

По вашему случаю рекомендую этот код компилить в ARM режиме, либо разделить код на 2 части и в ARM компилить функцию прерывания, а в THUMB (в котором скомпилен FreeRTOS для SAM7X256) скомпилировать все остальное. Кроме того обратите внимание как обрамлен код прерывания в уже имеющихся прерываниях FreeRTOS. То как сделано сейчас просто уронит ось когда наконец заработает.

спасибо вам! Я попробую. Ещё встречный вопрос. Надо секцию, отвечающую за прерывания. размещать в Csatartup.c? Там же где и секции .text, .bss? Может быть. вы мне подскажете какой-нибудь источник, в котором хотя бы в общих словах рассказывается о принципах написания ассемблерных файлов для этого контроллера. ну в смысле всяких там секций и т п, а то с этим туговато. а без этого никак crying.gif Спасибо!
И ещё: что вы имеете ввиду под "То как сделано сейчас просто уронит ось когда наконец заработает"?
sla000
Цитата(ZAA @ May 23 2008, 11:10) *
Надо секцию, отвечающую за прерывания. размещать в Csatartup.c? Там же где и секции .text, .bss?


Нет, гляньте в мейкфайл, там есть список файлов SRC и SRCARM, так вот, если вы создадите файлик с телом перывания, то его надо добавить в список SRCARM. Так он скомпилится в ARM режиме. Соответсвенно всю остальную требуху - инициализацию таймера и т.п. можно запихнуть в SRC, тогда они скомпилятся в THUMB.

Цитата(ZAA @ May 23 2008, 11:10) *
Может быть. вы мне подскажете какой-нибудь источник, в котором хотя бы в общих словах рассказывается о принципах написания ассемблерных файлов для этого контроллера. ну в смысле всяких там секций и т п, а то с этим туговато. а без этого никак crying.gif Спасибо!


Да не переживайте вы так ) зачем вам вообще надо программировать на асме? Ну если уж так интересно читайте документацию на архитектуру ARM7TDMI есть на сайте ATMEL.

Цитата(ZAA @ May 23 2008, 11:10) *
И ещё: что вы имеете ввиду под "То как сделано сейчас просто уронит ось когда наконец заработает"?


У FreeRTOS есть совершенно четкие указания как должно выглядеть прерывание. Если им не следовать результат непредсказуем, но 100% что все пойдет не так как должно. Как должно быть обрамлено прерывание можно почитать тут:
http://www.freertos.org/portsam7xlwIP.html
ZAA
Цитата(sla000 @ May 23 2008, 08:36) *
Нет, гляньте в мейкфайл, там есть список файлов SRC и SRCARM, так вот, если вы создадите файлик с телом перывания, то его надо добавить в список SRCARM. Так он скомпилится в ARM режиме. Соответсвенно всю остальную требуху - инициализацию таймера и т.п. можно запихнуть в SRC, тогда они скомпилятся в THUMB.
Да не переживайте вы так ) зачем вам вообще надо программировать на асме? Ну если уж так интересно читайте документацию на архитектуру ARM7TDMI есть на сайте ATMEL.
У FreeRTOS есть совершенно четкие указания как должно выглядеть прерывание. Если им не следовать результат непредсказуем, но 100% что все пойдет не так как должно. Как должно быть обрамлено прерывание можно почитать тут:
http://www.freertos.org/portsam7xlwIP.html

Огромное Вам спасибо! Я постараюсь разобраться!!!
ZAA
Цитата(sla000 @ May 23 2008, 08:36) *
Нет, гляньте в мейкфайл, там есть список файлов SRC и SRCARM, так вот, если вы создадите файлик с телом перывания, то его надо добавить в список SRCARM. Так он скомпилится в ARM режиме. Соответсвенно всю остальную требуху - инициализацию таймера и т.п. можно запихнуть в SRC, тогда они скомпилятся в THUMB.


Уважаемый sla000!!! Я следую Вашим советам, но все равно не хочет этот таймер рботать. Уж руки просто опускаются!
Я объявляю в файлике interrupt_timer (который компилируется в ARM-mode) 2 функции (как сказано на сайте фриртоса):

void vTIMER_ISR_Handler( void )
{
portBASE_TYPE xTaskWokenByPost = pdFALSE;
static volatile unsigned portLONG ulNextMessage = 0;
xISRStatus *pxMessage;
AT91PS_TC TC_pt = AT91C_BASE_TC1;
unsigned int dummy;
//* Acknowledge interrupt status
dummy = TC_pt->TC_SR;
//* Suppress warning variable "dummy" was set but never used
dummy = dummy;
count_timer1_interrupt++;
vParTestToggleLED(3);
AT91C_BASE_AIC->AIC_EOICR = 0;
}


void vTIMER_ISR_Wrapper( void )
{
/* Save the context of the interrupted task. */
portSAVE_CONTEXT();

/* Call the handler itself. This must be a separate function as it uses
the stack. */
vTIMER_ISR_Handler();

/* Restore the context of the task that is going to
execute next. This might not be the same as the originally
interrupted task.*/
portRESTORE_CONTEXT();
}


Обе эти функции объявлены в файле interrupt_timer.h так:
void vTIMER_ISR_Wrapper( void ) __attribute__((naked));
void vTIMER_ISR_Handler( void );

Потом в init_timer.c (компилируется в THUMB-mode) настраиваю таймер1 (тоже вроде стандартная последовательность) и вызываю обработчик прерывания:
void timer_init ( void )
//* Begin
{
AT91S_AIC *pAIC = AT91C_BASE_AIC;
AT91S_TC *pTMR = AT91C_BASE_TC1;
//* Open timer1
AT91F_TC_Open(AT91C_BASE_TC1,TC_CLKS_MCK128,AT91C_ID_TC1);
AT91C_BASE_PMC->PMC_PCER = (1<<AT91C_ID_TC1);
AT91C_BASE_TC1->TC_CMR=AT91C_TC_CLKS_TIMER_DIV4_CLOCK | AT91C_TC_CPCSTOP;

//* Open Timer 1 interrupt
AT91F_AIC_ConfigureIt ( AT91C_BASE_AIC, AT91C_ID_TC1, TIMER0_INTERRUPT_LEVEL,AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) )vTIMER_ISR_Wrapper);
//AT91C_BASE_TC1->TC_IER = AT91C_TC_CPCS; // IRQ enable CPC
AT91C_BASE_TC1->TC_RC = 0xFFFF;
//AT91F_AIC_EnableIt (AT91C_BASE_AIC, AT91C_ID_TC1);

AT91C_BASE_TC1->TC_CCR=AT91C_TC_CLKEN;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG ;
}

В чем косяк может быть? help.gif Помогите пожалуйста!!!
KolyanV
Цитата(ZAA @ May 24 2008, 21:58) *
В чем косяк может быть? help.gif Помогите пожалуйста!!!

Не уверен, но, может быть, вместо
Код
AT91C_BASE_AIC->AIC_EOICR = 0;

надо
Код
AT91C_BASE_AIC->AIC_EOICR =AT91C_ID_TC1;
aaarrr
Цитата(ZAA @ May 24 2008, 22:58) *
AT91F_TC_Open(AT91C_BASE_TC1,TC_CLKS_MCK128,AT91C_ID_TC1);
AT91C_BASE_PMC->PMC_PCER = (1<<AT91C_ID_TC1);
AT91C_BASE_TC1->TC_CMR=AT91C_TC_CLKS_TIMER_DIV4_CLOCK | AT91C_TC_CPCSTOP;

Timer1 сконфигурирован в Capture Mode, а бит CPCSTOP существует в Waveform Mode.

Цитата(ZAA @ May 24 2008, 22:58) *
//AT91C_BASE_TC1->TC_IER = AT91C_TC_CPCS; // IRQ enable CPC
AT91C_BASE_TC1->TC_RC = 0xFFFF;
//AT91F_AIC_EnableIt (AT91C_BASE_AIC, AT91C_ID_TC1);

Присутствующим остается только гадать, почему разрешение оказалось закомментировано?


P.S. OFF. Еще раз пройдусь по AT91F_: Человеки! Ну зачем вы пользуетесь этой дрянью? Ведь код становится понять совершенно невозможно, а жизнь они никак облегчить не могут в силу своей примитивности.

Цитата(KolyanV @ May 25 2008, 00:35) *
Не уверен, но, может быть

Не может. В EOICR можно писать что угодно.
ZAA
Цитата(aaarrr @ May 25 2008, 00:30) *
Timer1 сконфигурирован в Capture Mode, а бит CPCSTOP существует в Waveform Mode.
Присутствующим остается только гадать, почему разрешение оказалось закомментировано?
P.S. OFF. Еще раз пройдусь по AT91F_: Человеки! Ну зачем вы пользуетесь этой дрянью? Ведь код становится понять совершенно невозможно, а жизнь они никак облегчить не могут в силу своей примитивности.

Поправки в настройке таймера не помогли crying.gif Не хочет он прерываться. У меня не включено ни одной задачи. Просто в файле main.c инициализируется и запускается таймер. Такое подозрение, что тут сама ОС не дает ему запуститься... И ещё в чем разница между void vTIMER_ISR_Wrapper( void ) __attribute__((naked)); и void vTIMER_ISR_Wrapper( void ) __attribute__((interrupt("IRQ"))); ?
КАк не навредить-то собственным FreeRTOSовским перрываниям и получить это несчастное прерывание по таймеру, например по TC1 (ну или TC0)???
aaarrr
Цитата(ZAA @ May 25 2008, 11:10) *
У меня не включено ни одной задачи. Просто в файле main.c инициализируется и запускается таймер.

А vTaskStartScheduler() вызывается? Без него portSAVE_CONTEXT() и portRESTORE_CONTEXT() работать правильно не будут.

Цитата(ZAA @ May 25 2008, 11:10) *
И ещё в чем разница между void vTIMER_ISR_Wrapper( void ) __attribute__((naked)); и void vTIMER_ISR_Wrapper( void ) __attribute__((interrupt("IRQ"))); ?

В первом случае компилятор не будет создавать никакого обрамления для функции, в том числе и сохранения регистров, во втором создаст обрамление для IRQ (сохранение регистров + модификация адреса возврата).
ZAA
Цитата(aaarrr @ May 25 2008, 13:12) *
А vTaskStartScheduler() вызывается? Без него portSAVE_CONTEXT() и portRESTORE_CONTEXT() работать правильно не будут.
В первом случае компилятор не будет создавать никакого обрамления для функции, в том числе и сохранения регистров, во втором создаст обрамление для IRQ (сохранение регистров + модификация адреса возврата).

Спасибо за разъяснение! Это получается, мне надо для таймера отдельный Task создавать, в котором и будет таймер прерываться?
aaarrr
Нет, отдельный task создавать не нужно. Вы шедулер-то пробовали запускать? Работает?
ZAA
Цитата(aaarrr @ May 25 2008, 18:38) *
Нет, отдельный task создавать не нужно. Вы шедулер-то пробовали запускать? Работает?

Вот только недавно получилось один раз все-таки зайти в прерывание!!!!! (благодаря Вашему совету, спасибо smile.gif ). ТОлько вот выполняется оно 1 раз (счетчик, который там внутри все время равен 1). Сейчас хоть есть от чего отталкиваться! Да, Sheduler я запускаю после вызова timer_init в файле main.c
Ещё раз спасибо! Если возникнут ещё проблемы, спрошу 05.gif
aaarrr
CPCSTOP не забыли убрать?
ZAA
Цитата(aaarrr @ May 25 2008, 19:43) *
CPCSTOP не забыли убрать?

Я понимаю, что Вам надоело наверное на такие вопросы отвечать, но все же... 05.gif
Я проверяю CPCSTOP строчкой
if((AT91C_BASE_TC1->TC_CMR && AT91C_TC_CPCSTOP) != AT91C_TC_CPCSTOP)
{
vParTestToggleLED(3);
}
Лампочка загорается, т е этот бит не равен 1.
Такое ощущение, что как-то этот самый шедулер не хочет с прерыванием нормально работать.
В файле main.c ф-ия main выглядит так:

int main( void )
{
prvSetupHardware();

timer_init();
vParTestToggleLED(0);

/* Start the scheduler.

vTaskStartScheduler();

/* We should never get here as control is now taken by the scheduler. */
return 0;
}
То есть timer_init должна вызываться один раз, потом в ней настраивается и запускается таймер и дальше он уже должен работать по прерываним?
Ф-ия timer_init выглядит так:
AT91C_BASE_PMC->PMC_PCER = (1<<AT91C_ID_TC1);
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | AT91C_TC_WAVESEL_UP_AUTO
| AT91C_TC_WAVE;

AT91C_BASE_TC1->TC_IER = (1<<4); //прерывание RC Compare

AT91C_BASE_TC1->TC_RC = 0x00FF;

AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC1] = (unsigned int) vTIMER_ISR_Handler;
AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC1] = ( AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 0x5 );
AT91C_BASE_AIC->AIC_ICCR = (1<<AT91C_ID_TC1);
AT91C_BASE_AIC->AIC_IECR = (1<<AT91C_ID_TC1);
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
vParTestToggleLED(1);

обработчик прерывания:
void vTIMER_ISR_Handler( void )
{
int i;
AT91PS_TC TC_pt = AT91C_BASE_TC1;
unsigned int dummy;

AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_TC1);

//* Acknowledge interrupt status
dummy = AT91C_BASE_TC1->TC_SR;
//* Suppress warning variable "dummy" was set but never used
dummy = dummy;

if((AT91C_BASE_TC1->TC_SR && AT91C_TC_CPCS) == AT91C_TC_CPCS)
{
vParTestToggleLED(2);
count_timer1_interrupt++;
}
AT91C_BASE_AIC->AIC_EOICR = 0x00;
}
И еще, не надо ли в конце обработчика вызывать функцию portYIELD_FROM_ISR()?
aaarrr
Цитата(ZAA @ May 25 2008, 22:26) *
AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC1] = (unsigned int) vTIMER_ISR_Handler;

Почему здесь Handler, а не Wrapper?

Цитата(ZAA @ May 25 2008, 22:26) *
void vTIMER_ISR_Handler( void )
{
...
AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_TC1);

Это действие лишнее.

Цитата(ZAA @ May 25 2008, 22:26) *
И еще, не надо ли в конце обработчика вызывать функцию portYIELD_FROM_ISR()?

Не обязательно.

Цитата(ZAA @ May 25 2008, 22:26) *
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;

Это я бы разделил на две операции: trigger нужно делать, когда тактирование уже разрешено.
ZAA
Цитата(aaarrr @ May 26 2008, 05:56) *
Почему здесь Handler, а не Wrapper?
Это действие лишнее.
Не обязательно.
Это я бы разделил на две операции: trigger нужно делать, когда тактирование уже разрешено.

И снова спасибо большое! бУду пробовать! smile.gif
ZAA
Цитата(aaarrr @ May 26 2008, 05:56) *
Почему здесь Handler, а не Wrapper?


Большое, большое Вам спасибо!!! Дело действительно было в Wrapper! Сейчас начну с прерываниями от UART разбираться smile.gif
aaarrr
И Вам спасибо за отсутствие AT91F_ в исходниках wink.gif
ZAA
Цитата(aaarrr @ May 26 2008, 16:03) *
И Вам спасибо за отсутствие AT91F_ в исходниках wink.gif


Уважаемый aaarrr! Для реализации прерываний USART можно пользоваться обработчиком прерывания, аналогичным обработчику таймера, т е например uart_Wrapper и uart_Handler (как у меня было с таймером)?
И ещё, имеет ли разницу, буду я использовать DBGU или же USART? Когда конфигурирую как DBGU, хотя бы посылается и принимается байт по RS232. USART же упорно не хочет работать... sad.gif 05.gif

P.S. простите за беспокойство ещё раз)
aaarrr
Цитата(ZAA @ May 27 2008, 21:31) *
Для реализации прерываний USART можно пользоваться обработчиком прерывания, аналогичным обработчику таймера, т е например uart_Wrapper и uart_Handler (как у меня было с таймером)?

Можно так. Можно и просто оформить прерывание как
Код
void isr_handler( void ) __attribute__((interrupt("IRQ")))
{
    ...
}

если не собираетесь из прерывания вызывать шедулер.

Цитата(ZAA @ May 27 2008, 21:31) *
И ещё, имеет ли разницу, буду я использовать DBGU или же USART? Когда конфигурирую как DBGU, хотя бы посылается и принимается байт по RS232. USART же упорно не хочет работать... sad.gif 05.gif

Разницы нет практически никакой. Проверьте, разрешено ли тактирование.
ZAA
Цитата(aaarrr @ May 27 2008, 21:38) *
Можно так. Можно и просто оформить прерывание как
Код
void isr_handler( void ) __attribute__((interrupt("IRQ")))
{
    ...
}

если не собираетесь из прерывания вызывать шедулер.
Разницы нет практически никакой. Проверьте, разрешено ли тактирование.

Спасибо! Буду пробовать)))
ZAA
Цитата(aaarrr @ May 27 2008, 21:38) *
Разницы нет практически никакой. Проверьте, разрешено ли тактирование.


Очень неудобно беспокоить Вас снова, но снова столкнулась с проблемой, вернее, с проблемами. Все те же прерывания от уарта. Пересмотрела кучу постов на эту тему, вроде все прозрачно. Надо генерировать прерывания по приему байта. Тут и начинаются косяки. Если не затруднит, не могли бы Вы помочь мне еще раз help.gif
1) Можно ли одновременно использовать и USART0, и DBGU? То есть например, прерывание конфигурировать от USART0, а посылать байт из контроллера через DBGU?
2) Почему-то срабатывают прерывание (но опять же 1 раз - ещё одна проблема) по передаче байта, по флагу RXBUFF, но не по RXRDY? На какой вообще надо настраивать?
3) Снова та же проблема - прерывание выполняется 1 раз
4) программа переходит в обработчик без какого-либо опроса буфера приемника, т е как только что-то пришло в Rx, должно произойти прерывание?
5) Обязательно ли использовать PDC?

Вот мои тексты:
Код
void init_uart(void)
{
    AT91C_BASE_PIOA->PIO_PDR = AT91C_PIO_PA1 | AT91C_PIO_PA0;
    AT91C_BASE_SYS->AIC_SVR[AT91C_ID_US0] = (unsigned int) vUART_ISR_Wrapper;
    //растановка приоритета прерывания
    AT91C_BASE_SYS->AIC_SMR[AT91C_ID_US0] = 0x63; // SRCTYPE=1, PRIOR=3. USART 0 interrupt positive edge-triggered at prio 3 //0x02;
    AT91C_BASE_SYS->AIC_IECR = (1<<AT91C_ID_US0);
    AT91C_BASE_SYS->AIC_ICCR = (1<<AT91C_ID_US0);

    *AT91C_US0_BRGR = 625;
    *AT91C_US0_MR = 0x000808C0; // Normal mode, 1 stop bit, no parity, async mode, 8 bits, MCK.
    *AT91C_US0_IDR = 0xffffffff; // Disable all USART interrupts
    *AT91C_US0_IER = AT91C_US_ENDRX; //| AT91C_US_RXBUFF;//AT91C_US_TXRDY | AT91C_US_RXRDY;

    *AT91C_US0_CR = AT91C_US_RXDIS | AT91C_US_TXDIS;
    *AT91C_US0_CR = AT91C_US_RXEN | AT91C_US_TXEN;
    *AT91C_US0_CR = AT91C_US_RSTRX | AT91C_US_RSTTX |AT91C_US_RSTSTA;
    *AT91C_PMC_PCER = (1 << AT91C_ID_US0);
}

Здесь собственно говоря смущает AT91C_BASE_SYS. Может надо настраивать как AT91C_BASE_AIC (пример настройки кстати взят из одного из постов)?

Обработчик прерывания
Код
void vUART_ISR_Handler( void )
{
    int i;
    char Tmp = *AT91C_US0_CSR;
            char *Data;
            char buffer[5];
    unsigned int status;
    status = AT91C_BASE_US0->US_CSR;
    vParTestToggleLED(Data);
    count_uart_interrupt++;
    AT91C_BASE_DBGU->DBGU_CR = AT91C_US_RSTSTA;//US0->US_CR = AT91C_US_RSTSTA;
    AT91C_BASE_US0->US_CR = AT91C_US_RSTRX;//US0->US_CR = AT91C_US_RSTRX;
    AT91C_BASE_US0->US_CR = AT91C_US_RXEN;
    *AT91C_US0_IER = AT91C_US_ENDRX;
    AT91C_BASE_AIC->AIC_EOICR = 0;            // Signal end of interrupt
}

Вроде и регистр статуса считываю, и в EOICR пишу в конце. Уже и прерывание снова объявила..Ну ни в какую(((
Код
void vUART_ISR_Wrapper( void )
{
    /* Save the context of the interrupted task. */
    portSAVE_CONTEXT();

    /* Call the handler itself.  This must be a separate function as it uses
    the stack. */
    vParTestToggleLED(3);
    vUART_ISR_Handler();
    
    /* Restore the context of the task that is going to
    execute next. This might not be the same as the originally
    interrupted task.*/
    portRESTORE_CONTEXT();
}


Понимаю, что вопросы стандартные и глупые, но уже погрязла в куче информации и в доках, и в форуме, а времени остаётся все меньше и меньше crying.gif Помогите советом ещё раз, плз!!!
aaarrr
Цитата(ZAA @ May 28 2008, 21:40) *
1) Можно ли одновременно использовать и USART0, и DBGU? То есть например, прерывание конфигурировать от USART0, а посылать байт из контроллера через DBGU?

Если скорости совпадают, то в отладочных целях можно.

Цитата(ZAA @ May 28 2008, 21:40) *
2) Почему-то срабатывают прерывание (но опять же 1 раз - ещё одна проблема) по передаче байта, по флагу RXBUFF, но не по RXRDY? На какой вообще надо настраивать?

RXBUFF будет установлен, если используется PDC. Без PDC нужно настраивать на RXRDY.

Цитата(ZAA @ May 28 2008, 21:40) *
3) Снова та же проблема - прерывание выполняется 1 раз

Возможно, из-за того, что прерывание настроено как edge sensetive.

Цитата(ZAA @ May 28 2008, 21:40) *
4) программа переходит в обработчик без какого-либо опроса буфера приемника, т е как только что-то пришло в Rx, должно произойти прерывание?

Да.

Цитата(ZAA @ May 28 2008, 21:40) *
5) Обязательно ли использовать PDC?

Нет.

Цитата(ZAA @ May 28 2008, 21:40) *
Вот мои тексты:


Я бы немного переделал:
Код
void init_uart(void)
{
    //aaarrr сначала PIO и тактирование
    AT91C_BASE_PIOA->PIO_PDR = AT91C_PIO_PA1 | AT91C_PIO_PA0;
    AT91C_BASE_SYS->AIC_IDCR = (1<<AT91C_ID_US0);    // на всякий случай, если UART уже использовался
    *AT91C_PMC_PCER = (1 << AT91C_ID_US0);

    //aaarrr затем собственно периферийный модуль
    // а вот здесь иногда лучше использовать макросы для битов регистров
    *AT91C_US0_BRGR = 625; // (u_int)((MCK + (UART0_BAUDRATE * 0x08)) / (UART0_BAUDRATE * 0x10)); - так может быть удобнее
    *AT91C_US0_MR = AT91C_US_USMODE_NORMAL | AT91C_US_CHRL_8_BITS | AT91C_US_PAR_NONE; // Normal mode, 1 stop bit, no parity, async mode, 8 bits, MCK.
    *AT91C_US0_IDR = 0xffffffff; // Disable all USART interrupts
    *AT91C_US0_IER = AT91C_US_TXRDY | AT91C_US_RXRDY;

    *AT91C_US0_CR = AT91C_US_RXEN | AT91C_US_TXEN;
    *AT91C_US0_CR = AT91C_US_RSTRX | AT91C_US_RSTTX |AT91C_US_RSTSTA;

    //aaarrr и в самом конце - прерывания
    AT91C_BASE_SYS->AIC_SVR[AT91C_ID_US0] = (unsigned int) vUART_ISR_Wrapper;
    //растановка приоритета прерывания

//    AT91C_BASE_SYS->AIC_SMR[AT91C_ID_US0] = 0x63; // SRCTYPE=1, PRIOR=3. USART 0 interrupt positive edge-triggered at prio 3 //0x02;
    //aaarrr Для внутренних источников лучше использовать прерывание по уровню
    AT91C_BASE_SYS->AIC_SMR[AT91C_ID_US0] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 0x03; // SRCTYPE=0, PRIOR=3. USART 0 interrupt high level sensetive at prio 3

    AT91C_BASE_SYS->AIC_IECR = (1<<AT91C_ID_US0);
}


Продолжение следует...

Цитата(ZAA @ May 28 2008, 21:40) *
Здесь собственно говоря смущает AT91C_BASE_SYS. Может надо настраивать как AT91C_BASE_AIC (пример настройки кстати взят из одного из постов)?

Можно и так и так: если Вы посмотрите структуру _AT91S_SYS в файле AT91SAM7X256.h, то убедитесь, что регистры AIC на месте.
Для красоты можно, конечно, поменять.

Обработчик прерывания
Код
void vUART_ISR_Handler( void )
{
    unsigned int status;

    status = AT91C_BASE_US0->US_CSR & AT91C_BASE_US0->US_IMR; // Сразу отбросим маскированные прерывания

    vParTestToggleLED(Data);
    count_uart_interrupt++;

    if(status & AT91C_US_RXRDY)
    {
        // Делаем что нужно, но обязательно читаем US_RHR или запрещаем прерывание RXRDY
    }
    if(status & AT91C_US_TXRDY)
    {
        // Делаем что нужно, но обязательно пишем US_THR или запрещаем прерывание TXRDY
    }

    AT91C_BASE_AIC->AIC_EOICR = 0;            // Signal end of interrupt
}
ZAA
Цитата(aaarrr @ May 28 2008, 21:21) *

Спасибо, я в процессе...)))
ZAA
Цитата(aaarrr @ May 28 2008, 21:21) *
...

В общем, полнейшая ерунда...Если разрешать прерывания по Tx, то программа какое-то количество раз заходит в обработчик, а потом все останавливается. А по Rx прерывания так и не воспринимаются, хотя все делаю по Вашим советам, да и по логике-то должно работать((( Вообще для общения с контроллером я пользуюсь программой Terminal.exe. В обработчике я пишу, так как Вы советовали:
Код
if(status & AT91C_US_TXRDY)
    {
        // Делаем что нужно, но обязательно пишем US_THR или запрещаем прерывание TXRDY
        (pUS0->US_THR) = 0x1;//Data & 0x1FF;
        vParTestToggleLED(2);
        AT91F_DBGU_Printc(count_uart_interrupt);    //эта функция по DBGU байт передает
    }

crying.gif crying.gif crying.gif Мозг взрывается уже
aaarrr
Цитата(ZAA @ May 29 2008, 00:51) *
Если разрешать прерывания по Tx, то программа какое-то количество раз заходит в обработчик, а потом все останавливается.

Останавливается как - процессор виснет, или прерывания не прерываются?

Цитата(ZAA @ May 29 2008, 00:51) *
А по Rx прерывания так и не воспринимаются, хотя все делаю по Вашим советам, да и по логике-то должно работать(((

А вот это совсем странно, тем более, что инициализируется оно одновременно с TX. Проверьте все внимательно еще раз. PDC точно выключен?
ZAA
Цитата(aaarrr @ May 29 2008, 06:06) *
Останавливается как - процессор виснет, или прерывания не прерываются?

Похоже на то, что прерывания не прерываются. Потому что в условии обработчика, где про Tx, я посылаю через DBGU значение счётчика, к-рый инкрементируется каждое прерывание. ПОсылается примерно значений 1500, а дальше все. Да ещё и в прерывание заходит, даже если кабель RS232 не подключен.
aaarrr
Цитата(ZAA @ May 29 2008, 07:11) *
Да ещё и в прерывание заходит, даже если кабель RS232 не подключен.

Ну, это правильно - откуда ему знать, подключен кабель, или нет? Какая-нибудь светодиодная моргалка в проекте есть?
ZAA
Цитата(aaarrr @ May 29 2008, 07:56) *
Ну, это правильно - откуда ему знать, подключен кабель, или нет? Какая-нибудь светодиодная моргалка в проекте есть?

Да, есть. Это функция vParTestToggleLED ('номер светодиода')
Я её использую, чтобы определить. зашла программа в прерывание или нет. Отладчика-то не имеется. вот и приходится лампочками отлаживать 05.gif
А не может дело быть в структуре самой программы? То есть в ф-ии main вызывается PrvSetupHardware (ну как обычно), потом ф-ия ReadComPort(), потом vStartSheduler;
А ф-ия ReadComPort выглядит так:
void ReadComPort()
{
init_uart();
}

init_uart - это инициализация уарта. про которую обсуждалось выше.

А данные в порт с компа все равно какой программой отправлять? (либо terminal.exe, либо ComPUMP ну или еще какой-нить sad.gif )
aaarrr
Так добавьте какую-нибудь задачу, которая просто будет LED'ом моргать. А то не понятно, хвост-IRQ отваливается, или лапы-OS smile.gif
ZAA
Цитата(aaarrr @ May 29 2008, 10:50) *
Так добавьте какую-нибудь задачу, которая просто будет LED'ом моргать. А то не понятно, хвост-IRQ отваливается, или лапы-OS smile.gif

Спасибо за поддержку. Попробую...)
ZAA
Цитата(aaarrr @ May 29 2008, 10:50) *
Так добавьте какую-нибудь задачу, которая просто будет LED'ом моргать. А то не понятно, хвост-IRQ отваливается, или лапы-OS smile.gif

Уважаемый aaarrr! Не было возможности Вам ответить раньше. Хочется очень Вас поблагодарить. проблема с UARTом разрешилась. причиной всему была собственная глупость, тупость и т п. если бы в руках схема не оказалась, долго бы ещё голову ломали. В общем, USART0, который я так настойчиво пыталась конфигурировать ,выведен совсем на другие выводы. Припаяли разъём на PA0, PA1 (к-рые отвечают за TxD RxD) и все заработало. Наука мне на будущее. СПАСИБО ещё раз
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.