Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вывод символов в UART по прерванию
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
igorenja
Доброе время суток!

Случилась у меня следующая проблемка:
Как известно существует несколько вариантов настройки AIC, среди которых есть режим чувствительности к уровню входного сигнала и режим чувствительности к фронту. При использовании первого случая в обработчике прерывания должен присутствовать код, который сбросит источник прерывания, во втором случае это делать не обязательно.

Ниже приведен код, задачей которого является выводить в УАРТ (в данном случае ДБГУ, но и с обычным проблема не исчезает) символы по прерыванию:

CODE
void USART_DBGU_irq_handler(void)
{
unsigned int status;
status = USART_pt_d->US_CSR;
if ( status & AT91C_US_RXRDY)
{
rx_buffer[ptr_rx_wr]=(char)AT91F_US_GetChar(USART_pt_d);
if(++ptr_rx_wr>=TX_BUFFER_SIZE) ptr_rx_wr=0;
bUART_DBGU_RX=1;
}
if ( status & AT91C_US_TXRDY)
{
if(ptr_tx_rd!=ptr_tx_wr)
{
AT91F_US_PutChar(USART_pt_d, tx_buffer[ptr_tx_rd]);
if(++ptr_tx_rd>=TX_BUFFER_SIZE) ptr_tx_rd=0;
}
else
{
AT91F_US_DisableIt (USART_pt_d,AT91C_US_TXRDY);
}
}
}



CODE
int putchar(int out)
{
AT91F_US_DisableIt(USART_pt_d,AT91C_US_RXRDY|AT91C_US_TXRDY);
tx_buffer[ptr_tx_wr++]=(char)out;
if(ptr_tx_wr>=TX_BUFFER_SIZE) ptr_tx_wr=0;
AT91F_US_EnableIt(USART_pt_d,AT91C_US_RXRDY|AT91C_US_TXRDY);
return out;
}


В общем этот код работает только при настройке AIC в режиме чувствительности к фронту. А мне край дела нужно чтобы он работал в режиме чувствительности к уровню. "Неработа" проявляется тогда кода выводится большое колличество символов подряд и процессор зависает.
aaarrr
Код
status = USART_pt_d->US_CSR;
...
if ( status & AT91C_US_TXRDY)


Так Вы будете обрабатывать и запрещенные прерывания TXRDY в момент прихода символа на RX. Добавьте маску:
status = USART_pt_d->US_CSR & USART_pt_d->US_IMR;
igorenja
Цитата(aaarrr @ Aug 26 2009, 04:28) *
Код
status = USART_pt_d->US_CSR;
...
if ( status & AT91C_US_TXRDY)


Так Вы будете обрабатывать и запрещенные прерывания TXRDY в момент прихода символа на RX. Добавьте маску:
status = USART_pt_d->US_CSR & USART_pt_d->US_IMR;


Да вы правы, но корень зла не в этом...
aaarrr
Цитата(igorenja @ Aug 26 2009, 13:05) *
Да вы правы, но корень зла не в этом...

Он вообще не в прерывании - очевидно, что источники USART'а в нем будут сняты. В случае DBGU возможно, что кто-то еще тянет линию SYS.

Еще у Вас нет никакой проверки переполнения буфера передачи. Вызывая последовательно putchar можно добиться ситуации, когда ptr_tx_rd == ptr_tx_wr при полном буфере.

И еще один косяк:
Код
if(++ptr_rx_wr>=TX_BUFFER_SIZE)


Ну и традиционно не понятно, правильно ли оформлено прерывание.
igorenja
Цитата(aaarrr @ Aug 26 2009, 17:27) *
Он вообще не в прерывании - очевидно, что источники USART'а в нем будут сняты. В случае DBGU возможно, что кто-то еще тянет линию SYS.
Еще у Вас нет никакой проверки переполнения буфера передачи. Вызывая последовательно putchar можно добиться ситуации, когда ptr_tx_rd == ptr_tx_wr при полном буфере.
И еще один косяк:
Код
if(++ptr_rx_wr>=TX_BUFFER_SIZE)

Ну и традиционно не понятно, правильно ли оформлено прерывание.

Код
tx_buffer[ptr_tx_wr++]=(char)out;
if(ptr_tx_wr>=TX_BUFFER_SIZE) ptr_tx_wr=0;

Нет тут косяка!
Про переполнение буфера, да проверки нет, но выводится относительно мало символов, при размере буфера 2000байт
вот код обработчика прерывания:
CODE
if((((AT91PS_USART)AT91C_BASE_DBGU)->US_CSR)&(((AT91PS_USART)AT91C_BASE_DBGU)->US_IMR))
{
USART_DBGU_irq_handler();
}
else if((AT91C_BASE_PITC->PITC_PISR & AT91C_PITC_PITS))//(AT91C_BASE_PITC->PITC_PIMR & AT91C_PITC_PITIEN)&&
{
PIT_irq_handler();
}
else printf("anower sys int");

я тестировал этот код не только на DBGU но и на простом UARTe эффект тотже
aaarrr
Цитата(igorenja @ Aug 26 2009, 14:47) *
Нет тут косяка!

ptr_rx_wr>=TX_BUFFER_SIZE
igorenja
Цитата(aaarrr @ Aug 26 2009, 17:50) *
ptr_rx_wr>=TX_BUFFER_SIZE


согласен...
igorenja
новые подробности:
вставил в начало обработчика прерывания
Код
__disable_interrupt();

а в конец:
Код
__enable_interrupt();

ту же процедуру повторил и для putchar(); ... Всё работает как часы...
aaarrr
Возможно, стека не хватает. Прерывания, как я понимаю, по умолчанию вложенные?
И покажите общую часть, что после вектора непосредственно.
igorenja
Цитата(aaarrr @ Sep 7 2009, 21:53) *
Возможно, стека не хватает. Прерывания, как я понимаю, по умолчанию вложенные?

На сколько я понимаю, да.

Цитата(aaarrr @ Sep 7 2009, 21:53) *
И покажите общую часть, что после вектора непосредственно.

Cstartup во вложении

Нашел еще в файле конфигурации линкера строчку:

-D_IRQ_STACK_SIZE=(50*8*4) //FVA code


Вот теперь и не знаю каков он всётаки этот irq_stack 50*8*4 или 3*8*4 laughing.gif
aaarrr
Цитата(igorenja @ Sep 8 2009, 10:31) *
Вот теперь и не знаю каков он всётаки этот irq_stack 50*8*4 или 3*8*4 laughing.gif

3*8*4. И для IRQ стека больше не надо по причине вложенности. Не хватать может обычного.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.