Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Прерывания USART
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Daermon
AT91rm9200 AS-9200
IAR4.42


Разрешил прерывания RXBUFF и ENDRX.
На шине тишина, а прерывания эти срабатывают! В чем может быть дело?


//== Обработчик прерываний
static __arm __irq void IRQ1_RS232()
{
unsigned int status;
unsigned int status1;
//----------------------------------
AT91C_BASE_AIC->AIC_IVR = 0 ; /* enter interrupt in protected mode */
DBGU.PrintString("\n\rINTERUPT_USART1\n\r");

status = (AT91C_BASE_US1->US_CSR) ;
status1 = (AT91C_BASE_US1->US_IMR);
status &=status1;
//
//* Disable all interrupts
// AT91C_BASE_US1->US_IDR = (0xFFFFFFFF);

if( status & AT91C_US_TXEMPTY ){DBGU.PrintString("\n\rAT91C_US_TXEMPTY\n\r");}
if( status & AT91C_US_RXBUFF )
{
RxBuffer[count++] = AT91F_US_GetChar(AT91C_BASE_US1);
if(count==5)
{
count=0;
for(int i=0;i<10;i++)
RxBuffer[i]=0;
}
DBGU.PrintString("\n\rAT91C_US_RXBUFF\n\r");
}
if( status & AT91C_US_TXBUFE ){DBGU.PrintString("\n\rAT91C_US_TXBUFE\n\r");}
if( status & AT91C_US_TIMEOUT ){DBGU.PrintString("\n\rAT91C_US_TIMEOUT\n\r");}
if( status & AT91C_US_ENDTX ){DBGU.PrintString("\n\rAT91C_US_ENDTX\n\r");}
if( status & AT91C_US_ENDRX )
{
RxBuffer[count++] = AT91F_US_GetChar(AT91C_BASE_US1);
if(count==5)
{
count=0;
for(int i=0;i<10;i++)
RxBuffer[i]=0;
}
}
if( status & AT91C_US_ITERATION ){;}
if( status & AT91C_US_NACK ){;}
if( status & AT91C_US_RIIC ){;}
if( status & AT91C_US_DSRIC ){;}
if( status & AT91C_US_DCDIC ){;}
if( status & AT91C_US_CTSIC ){;}
AT91C_BASE_US1->US_CR = AT91C_US_RSTSTA;
AT91C_BASE_AIC->AIC_EOICR = 0 ; /* unstack one level */
}

status = (AT91C_BASE_US1->US_CSR) ;
Эта операция не чистит статус рег.
можно опять вызвать
status = (AT91C_BASE_US1->US_CSR) ;
и статус снова будет тем же
VSt&
прерывания срабатывают, потому что счетчики PDC пустые
RXBUFF и ENDRX встают при обнулении RXNCR и RXCTR соответственно

работа с PDC ведется следующим образом:
в регистры RXPTR, TXPTR записываются указатели куда писать и откуда читать
в регистры RXCTR, TXCTR записывается, сколько писать и сколько читать
далее инициализируется трансфер

прерывания ENDRX, ENDTX, RXBUFF, TXBUFE встают при обнулении счетчиков DMA
Daermon
Вроде все заработало...но появилась другая проблема.

В обработчике прерывания вызываю функцию
AT91F_US_ReceiveFrame (AT91C_BASE_US1,RxBuffer, 5, 0,0 );

Если посылаю посылку (0x01 0x02 0x03 0x04 0x05), то приемный буфер заполняется с 0го элемента до 4го:
RxBuffer[0] = 1;
RxBuffer[1] = 2;
RxBuffer[2] = 3;
RxBuffer[3] = 4;
RxBuffer[4] = 5;

если вдруг в результате сбоя или еще чего посылка становится другой, например
(0x01 0x02 0x03 0x04 0x05 0x06) - в этом случае принимаем следующее:
RxBuffer[0] = 6;
RxBuffer[1] = 1; // интересно куда пропала 5 ка???
RxBuffer[2] = 2;
RxBuffer[3] = 3;
RxBuffer[4] = 4;




а потом востанавливается до 5 байт (0x01 0x02 0x03 0x04 0x05), и начинаем принимать:
RxBuffer[0] = 5;
RxBuffer[1] = 1;
RxBuffer[2] = 2;
RxBuffer[3] = 3;
RxBuffer[4] = 4;

Необходимо вернуть прием в след вид
RxBuffer[0] = 1;
RxBuffer[1] = 2;
RxBuffer[2] = 3;
RxBuffer[3] = 4;
RxBuffer[4] = 5;

Что можно сделать?

Преинициализацию PDP делал - непомагает.
//* Disable the RX and TX PDC transfer requests
AT91F_PDC_DisableRx(pPDC);
AT91F_PDC_DisableTx(pPDC);

//* Reset all Counter register Next buffer first
AT91F_PDC_SetNextTx(pPDC, (char *) 0, 0);
AT91F_PDC_SetNextRx(pPDC, (char *) 0, 0);
AT91F_PDC_SetTx(pPDC, (char *) 0, 0);
AT91F_PDC_SetRx(pPDC, (char *) 0, 0);

//* Enable the RX and TX PDC transfer requests
AT91F_PDC_EnableRx(pPDC);
AT91F_PDC_EnableTx(pPDC);

//*----------------------------------------------------------------------------
//* \fn AT91F_US_ReceiveFrame
//* \brief Return 2 if PDC has been initialized with Buffer and Next Buffer, 1 if PDC has been initializaed with Next Buffer, 0 if PDC is busy
//*----------------------------------------------------------------------------
inline unsigned int AT91F_US_ReceiveFrame (
AT91PS_USART pUSART,
char *pBuffer,
unsigned int szBuffer,
char *pNextBuffer,
unsigned int szNextBuffer )
{
return AT91F_PDC_ReceiveFrame(
(AT91PS_PDC) &(pUSART->US_RPR),
pBuffer,
szBuffer,
pNextBuffer,
szNextBuffer);
}
VSt&
мне почему-то кажется, что дело в размерности элементов Вашего RxBuffer и выравнивании, т.к. я не вижу механизмов, сдвигающих массив поиндексно (а у Вас так и происходит, 0х06 встает спереди, сдвигая все на один индекс вверх)
предлагаю попробовать USART c DMA без прерываний, возможно на "пустом" проекте, сделать "ровные" массивы для dma

в момент окончания приема, определяемый обнулением значения счетчика dma, регистр RXPTR указывает на адрес последнего принятого элемента
Daermon
Не индексирую массив потому что просто хочу перезаписать старые значения новыми. масив char RxBuffer [250];

я так понимаю что вызовом AT91F_US_ReceiveFrame (AT91C_BASE_US1,RxBuffer,5, 0,0 );
я инизиализирую прием в адрес RxBuffer пяти байт. Но почему то этого не происходит...

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


А как без прерываний сделать чтение через PDC ?

inline void AT91F_US_ResetRx (
AT91PS_USART pUSART) // \arg pointer to a USART controller
{
//* Reset receiver
pUSART->US_CR = AT91C_US_RSTRX;
//* Re-Enable receiver
pUSART->US_CR = AT91C_US_RXEN;
}


делаю резет перед AT91F_US_ReceiveFrame (AT91C_BASE_US1,RxBuffer,5, 0,0 );

И все работает smile.gif))
VSt&
алгоритм работы с последовательной периферией посредством DMA:
1) при инициализации периферии обнуляем все указатели и счетчики PDC, выключаем обмен TXTDIS, RXTDIS
2) в приложении, для того, чтобы принять блок данных, выполняем следующую последовательность действий:
2.1) устанавливаем указатель(и) и счетчик(и) PDC на некоторую заранее определенную область памяти, память должна быть некешируемой
2.2) включаем нужные прерывания - ENDRX, ENDTX, RXBUFF, TXBUFE и др. - в IMR (AIC сконфигурирован заранее)
2.3) разрешаем обмен TXTEN, RXTEN
2.4) занимаемся далее своими делами, ожидая прерывания
3) хендлер прерывания выключает обмен, при необходимости устанавливает новые указатели и счетчики, и снова разрешает обмен - либо играет глобальными флагами( sad.gif )


вроде ничего не напутал
p.s. не увлекайтесь иаровскими макросами - в первый раз лучше написать лично с указанием регистров и битов
Daermon
Спасибо! Разобрался. Все работает.
Daermon
Опа..шаманство какоето. вчера весь день все нормально запускалось. сегодня добавил пару строчек и все заткнулось..удаление этих строк ни к чему хорошему не привело... может в ИАРе глюк какой есть..файлы не не подтягивает или еще что???

Запускаю USART1
void Usart1::Init()
{
for(int i=0;i<100;i++) Usart1::OutBuf[i] = i+100;
PIO_Init();
AIC_Init();

AT91F_US1_CfgPMC();

AT91F_US_Configure (
AT91C_BASE_US1, // \arg pointer to a USART controller
60000000, // \arg peripheral clock - 60 ÌÃö
AT91C_US_USMODE_NORMAL | // normal mode
AT91C_US_CLKS_CLOCK | // clock is MCK
AT91C_US_CHRL_8_BITS | // 8 databits
AT91C_US_PAR_NONE | // no parity
AT91C_US_NBSTOP_1_BIT | // 1 stopbit
AT91C_US_CHMODE_NORMAL // channel mode - normal
// AT91C_US_CHMODE_LOCAL // channel mode - local
, // \arg mode Register to be programmed
9600 , // \arg baudrate to be programmed
0 ); // \arg timeguard to be programmed


AT91F_US_ResetTx(AT91C_BASE_US1);
AT91F_US_ResetRx(AT91C_BASE_US1);

AT91F_AIC_ConfigureIt(AT91C_BASE_AIC, AT91C_ID_US1,AT91C_AIC_PRIOR_HIGHEST, AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE, (void (*)(void))IRQ1_USART);
AT91C_BASE_AIC->AIC_EOICR = 0 ; /* unstack one level */
AT91C_BASE_AIC->AIC_ICCR = ( 1<<AT91C_ID_US1 );
AT91F_AIC_EnableIt(AT91C_BASE_AIC, AT91C_ID_US1);
__enable_interrupt();
AT91F_US_EnableIt(AT91C_BASE_US1,AT91C_US_ENDRX);

}

а в обработчике инициализирую прием через PDC

static __arm __irq void IRQ1_USART()
{
unsigned int status;
unsigned int status1;

AT91C_BASE_AIC->AIC_IVR = 0 ; /* enter interrupt in protected mode */
//* get Usart status register and active interrupt

status = (AT91C_BASE_US1->US_CSR) ;status &= (AT91C_BASE_US1->US_IMR);
status = (AT91C_BASE_US1->US_CSR) ;
status1 = (AT91C_BASE_US1->US_IMR);
status &=status1;

//* Disable all interrupts
AT91C_BASE_US1->US_IDR = (0xFFFFFFFF);
if( status & AT91C_US_ENDTX )
{

}

if(status & AT91C_US_ENDRX )
{

AT91F_US_ResetRx(AT91C_BASE_US1);
AT91F_US_ReceiveFrame (AT91C_BASE_US1,RxBuffer,Rx_Len,RxBuffer+10,Rx_Len );
AT91F_US_EnableIt(AT91C_BASE_US1,AT91C_US_ENDRX); //AT91C_US_RXRDY);

}

AT91C_BASE_US1->US_CR = AT91C_US_RSTSTA;
AT91C_BASE_AIC->AIC_EOICR = 0 ;

}

Все в теории должно пахать...а на практике работало только вчера smile.gif)) Может сегодня магнитные бури???
sergeeff
Коллега!

Как ты думаешь, когда вырабатывается прерывание ENDRX? Когда заполнится приемный буффер через DMA. Если ты его в Init'e никак не определяешь, то чего же ты хочешь?
Daermon
Очепятка
AT91F_US_ReceiveFrame (AT91C_BASE_US1,RxBuffer, Rx_Len, 0,0 );
Вот что стоит перед разрешением прерывания.

Хотя... практика показывает что и без ЭТОГО работает, так как прерывания начинают сразу генериться как только счетчик PDC становится равным 0.


Я плакаю crying.gif не могу отладить этот код через SAM-ICE...почемуто в прерывания не заходит...вижу что в AIC_IPR регистре выставляется флаг....а в прерывание не заходит.
Если заливаю код через DBGU то отлично все работает...

Из за чего может не работать SAM-ICE???
Прибор исправный. Есть 3 новых штуки - проверял.

А вот вчера и через SAM-ICE все нормально работало.
Сергей Борщ
Цитата(Daermon @ Nov 20 2007, 14:09) *
Я плакаю crying.gif не могу отладить этот код через SAM-ICE...почемуто в прерывания не заходит...вижу что в AIC_IPR регистре выставляется флаг....а в прерывание не заходит.
Если заливаю код через DBGU то отлично все работает...
Закройте окно просмотра AIC. Или отредактируйте .ddf и удалите из этого окна AIC_IVR. Чтение этого регистра, даже отладчиком, говорит процессору, что началась обработка прерывания и все прерывания с этим и более низким приоритетом блокируются. То же и с другой периферией - если чтение какого-то регистра приводит к каким-то действиям, то смотреть этот регистр в отладчике не надо.
Daermon
a14.gif

Вотэто да....
И точно...ни за что бы не додумался

Борщу a14.gif a14.gif a14.gif a14.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.