Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: проблема - uCos и USART IRQ handler
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
_dem
Добрый день, уважаемый ALL

Разбираюсь с micrium OS - пожалуйста, ткните носом в страницу мануала.
мозги уже кипят - видимо, чего-то упорно не хотят замечать sad.gif

Проблема в следующем - при попытке навесить свой обработчик прерывания на ком-порт под uCos-ом задача работает до первого вызова OSTimeDlyHMSM(), потом все зависает в цикле OS_TaskIdle().

вот код, запускающий обработчик

Код
    AT91F_AIC_ConfigureIt( AT91C_BASE_AIC,   AT91C_ID_US0, 7 , AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL  | AT91C_AIC_PRIOR_LOWEST, usart0_irq_handler);  
    AT91F_AIC_EnableIt (AT91C_BASE_AIC, AT91C_ID_US0);


вот сам обработчик

Код
void usart0_irq_handler(void)
{
        // calling irq processor
        if (_comports [ 0 ])
                {
                 _comports [ 0 ] -> __irq_processor();
                }
/////////////////////
    unsigned long rx_data                     = AT91C_BASE_PITC->PITC_PIVR;   /* Read the interrupt source, ignore the value*/

    AT91C_BASE_AIC->AIC_IVR     = 0;                            /* Debug variant of IVR (protect mode is used)*/
    AT91C_BASE_AIC->AIC_ICCR    = AT91C_ID_US0;                 /* Clear  USART0 interrupt                    */
    AT91C_BASE_AIC->AIC_EOICR   = 0;                            /* Signal end of interrupt                    */

       //* Reset the satus bit
AT91C_BASE_US0->US_CR = AT91C_US_RSTSTA;  

}


Если убрать вызов
Код
AT91F_AIC_EnableIt (AT91C_BASE_AIC, AT91C_ID_US0);

т.е. не включать прерывание в AIC, то все работает - понятно, кроме собственно обработчика.

видимо, ошибся в обработчике, но не могу понять - где ?

----
добавил в обработчик вызовы OSIntEnter() / OSIntExit() - не помогло sad.gif
AlexBoy
Там цепочка вызовов такая: с вектора 0x18 вызввается общий асмовский обработчик OS_CPU_IRQ_ISR_Handler в файле os_cpu_a.s, затем из него общий сишный обработчик, у меня он такой:
Код
void OS_CPU_IRQ_ISR_Handler(void)
  {
    pFNCT pfnct;
  
    pfnct = (pFNCT)*AT91C_AIC_IVR;   // Чтение адреса обработчика с максимальным приоритетом

    AT91C_BASE_AIC->AIC_IVR = 0;                // Debug variant of vector read (protect mode is used)
    if (pfnct) pfnct();                         // Вызвать обработчик
    AT91C_BASE_AIC->AIC_EOICR = 0;              // Признак завершения обработчика
  }


а из него уже обработчик конкретного устройства
Код
void UART0_IRQ_Handler(void)
  {
    BYTE data;
    AT91PS_USART pCOM;
    DWORD status;

    // читаем регистр состояния в соотв. с текущим прерыванием
    status = pCOM->US_CSR;
    
    // Есть принятый байт
    if (status & AT91C_US_RXRDY)
      {
        data = pCOM->US_RHR;
        if (!(status & AT91C_US_FRAME))
          {
            QueueAdd(RxQueue, data);
          }
      }
    ....  

    // timeout приема
    if (status & AT91C_US_TIMEOUT)
      {
       // начать новый отсчет
        pCOM->US_CR = AT91C_US_RETTO;
      }  
      
    // очистить признаки ошибок
    pCOM->US_CR = AT91C_US_RSTSTA;
    // Разбудить задачу
    OSMboxPost(TabloMsg, (void*)1);
  }
_dem
с этим я разобрался, спасибо

но все равно не работает sad.gif где может быть собака зарыта ?
AlexBoy
Цитата(_dem @ Mar 5 2007, 10:48) *
с этим я разобрался, спасибо

но все равно не работает sad.gif где может быть собака зарыта ?


ну вообще похоже, что прерывания были выключены и не включились обратно
_dem
Цитата(AlexBoy @ Mar 5 2007, 14:06) *
Цитата(_dem @ Mar 5 2007, 10:48) *

с этим я разобрался, спасибо

но все равно не работает sad.gif где может быть собака зарыта ?


ну вообще похоже, что прерывания были выключены и не включились обратно


ситуация такая, что мой таск работает до тех пор, пока я не передам каким-либо образом управление другому таску - например, задаче IdleTask при вызове функции OSTimeDly()...

обратно управление не передается sad.gif
AlexBoy
Цитата(_dem @ Mar 5 2007, 12:13) *
ситуация такая, что мой таск работает до тех пор, пока я не передам каким-либо образом управление другому таску - например, задаче IdleTask при вызове функции OSTimeDly()...

обратно управление не передается sad.gif


Из IdleTask вызов шедулера происходит по прерыванию таймера. Нету прерывания, соответственно остается вечно в IdleTask. Возможно OS_EXIT_CRITICAL где-то забыл.
_dem
пока ничего нового sad.gif роюсь в документации и сырцах

сделал 2 своих обработчика прерывания - таймера и usart.
естественно, из обработчика PIT вызываю старый обработчик - чтобы оська работала

включаем свой обработчик таймера - все работает нормально, все переключается
включаем свой обработчик USART - все валится, конкретно - не работает таймер, и, видимо, остальные прерывание тоже не обрабатываются... код одинаковый, за исключением, понятно, констант идентификации периферии ID_US0.

help.gif ! cranky.gif

включаем ISR USART :
Код
void InitUSART (void) {

  // Enable interrupts
  // Disable the interrupt on the interrupt controller
  AT91C_BASE_AIC->AIC_IDCR = (1 << AT91C_ID_US0);
  // Save the interrupt handler routine pointer and the interrupt priority
  void * ptr  = 0;
  ptr = (void *)(unsigned long)AT91C_BASE_AIC->AIC_SVR[AT91C_ID_US0];
  *(unsigned long *)&old_usart_handlers[0] = (unsigned long)ptr;
  AT91C_BASE_AIC->AIC_SVR[AT91C_ID_US0] = (unsigned long) USART0_ISR_Handler;
  // Store the Source Mode Register
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_US0] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | AT91C_AIC_PRIOR_LOWEST;
  // Clear the interrupt on the interrupt controller
  AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_US0);
  // disable all interrupts on USART
  AT91C_BASE_US0->US_IDR = 0xFFFFFFFF;
  // Enable the interrupt on the interrupt controller

  AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_US0);
  // Enable the interrupt on the USART
      return;



}


USART ISR :
Код
static  void  USART0_ISR_Handler (void)
{
    CPU_INT32U      status;

    if (blink) {
        AT91C_BASE_PIOA->PIO_SODR = (1<<13);
        AT91C_BASE_PIOB->PIO_SODR = (1<<26);
    blink = 0;
    }
    else
    {
        AT91C_BASE_PIOA->PIO_CODR = (1<<13);
        AT91C_BASE_PIOB->PIO_CODR = (1<<26);
    blink = 1;
    }
    /*
    status = AT91C_BASE_AIC->AIC_IVR;
    if (status!=0x1124)
        AT91C_BASE_AIC->AIC_IVR = 0;
    
    status = AT91C_BASE_US0->US_CSR;
    if (status==0x1124)
        AT91C_BASE_AIC->AIC_IVR = 0;
*/
    AT91C_BASE_AIC->AIC_ICCR  = 1 << AT91C_ID_US0;                     /* Clear the  interrupts                            */
    AT91C_BASE_AIC->AIC_EOICR = 0;                                      /* Signal end of interrupt                              */
    
    return;    
}

Enable PIT ISR :
Код
AT91C_BASE_PITC->PITC_PIMR =  ((BSP_CPU_ClkFreq() * 1000) / 16 / OS_TICKS_PER_SEC) - 1;


  // Enable interrupts
  // Disable the interrupt on the interrupt controller
  AT91C_BASE_AIC->AIC_IDCR = (1 << AT91C_ID_SYS);

  // Save the interrupt handler routine pointer and the interrupt priority
  void * ptr  = 0;
  ptr = (void *)(unsigned long)AT91C_BASE_AIC->AIC_SVR[AT91C_ID_SYS];
  *(unsigned long *)&old_handler = (unsigned long)ptr;
  AT91C_BASE_AIC->AIC_SVR[AT91C_ID_SYS] = (unsigned long) pitc_handler;
  // Store the Source Mode Register
  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SYS] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | AT91C_AIC_PRIOR_LOWEST;
  // Clear the interrupt on the interrupt controller
  AT91C_BASE_AIC->AIC_ICCR = (1 << AT91C_ID_SYS);

  // Enable the interrupt on the interrupt controller
  AT91C_BASE_AIC->AIC_IECR = (1 << AT91C_ID_SYS);

  // Enable the interrupt on the pit
  pimr = AT91C_BASE_PITC->PITC_PIMR;
  AT91C_BASE_PITC->PITC_PIMR = pimr | AT91C_PITC_PITIEN;

  // Enable the pit
  pimr = AT91C_BASE_PITC->PITC_PIMR;
  AT91C_BASE_PITC->PITC_PIMR = pimr | AT91C_PITC_PITEN;


}


PIT ISR :

Код
void pitc_handler(void)
{

for(unsigned short i=0; i<MAX_TIME_COUNTERS; i++)
    {
        if(gMeters[i].connected)
            {
             gMeters[i].counter += OS_TIMER_PERIOD * 2;
            
            // here some like "garbage collector"
            // if no reset within 5 minutes, disconnect that
            if (gMeters[i].counter > 300000)
                gMeters[i].connected = 0;
            }// ?connected
    }// loop

    old_handler();

}



sad.gif хоть не код, ткните хотя бы в страницу мануала ! мозги кипятЪ ! cranky.gif
AlexBoy
По функциям, то что нужно добавить:
InitUSART:
1. Уарт должен быть настроен (тактовая, pio, скорость)
2. Разрешить прием/передачу AT91C_BASE_US0->US_CR = AT91C_US_RXEN | AT91C_US_TXEN;
3. Включить прерывания в usart AT91C_BASE_US0->US_IER = AT91C_US_RXRDY | AT91C_US_TXRDY | AT91C_US_OVRE | AT91C_US_FRAME;

USART0_ISR_Handler:
1. Статус должен быть прочитан обязательно. status = AT91C_BASE_US0->US_CSR;
2. Это убрать. AT91C_BASE_AIC->AIC_ICCR = 1 << AT91C_ID_US0;
3. Сбросить флаги. AT91C_BASE_US0->US_CR = AT91C_US_RSTSTA;

Enable PIT ISR: все нормально

pitc_handler: что-то сильно наворочено, у меня попроще и обязательно нужно прочитать статус иначе не сбросятся прерывания
// ------------------------------------------------------------------------------
// Обработчик системного прерывания (ID_SYS=1)
void SYSIRQ_Handler(void)
{
DWORD status;

status = *AT91C_PITC_PIVR;
if (status & AT91C_PITC_PICNT) // Если системное прерывание от PIT таймера то вызвать OSTimeTick
{
OSTimeTick();
}
}
_dem
оно все так и сделано, а OSTick() вызывается в старом обработчике таймера.
мой таймер работает беспроблемно, и переключения тасков происходят, все гуд

а обработчик уарта - нет, хотя тот же код без оськи работает отлично
_dem
проблема решена радикально - переходом на FreeRTOS.

Спасибо за помощь cheers.gif
Tahoe
Такой вопрос назрел. А кто как "дебажится" в прерываниях?

Есть связка, EWARM 4.41a -> plugins ( C-Spy + uCOS ) -> AT91SAM7Sxxx. Вертится под Мюкосом, разумеется. Если открыть в дебаге окно "Registers" и выбрать AIC, то для отображения состояния регистров AIC их, очевидно, надо прочитать. А проблема в том, что однократное чтение того же AIC_IVR изменяет состояние AIC.

Я вообще-то вслепую отлаживаюсь, но осадочек имеется. (с) Хочется "поцивильнее". :)

Теоретически, uCOS работает в SVC-mode, в который переключается и при обработке преррываний тоже. А при чтении AIC_IVR в SVC-mode, Атмел говорит что всё произойдёт "without performing the associated automatic operations". У меня же отладчик постоянно показывает хрень, в виде указателя на "spurios vector". :(
_dem
Цитата(Tahoe @ Apr 3 2007, 08:55) *
Такой вопрос назрел. А кто как "дебажится" в прерываниях?

....


Да вроде бы все нормально дебажится...

Хотя сам тоже еще с AVR-а и MSP привык отлаживаться вслепую, но никаких проблем при отладке в прерываниях не было. (sam7 + IAR + SEGGER j-link). Дебаггер читает регистры AIC через логику JTAG-машины, и, как и пишет Атмел, при этом биты не обнуляются. Ни для AIC, ни для того же таймера (PITC) - биты обнуляются только кодом, а дебаггер все исправно показывает.
Dron_Gus
Можно еще protected mode использовать для AIC... smile.gif
Сергей Борщ
Цитата(Tahoe @ Apr 3 2007, 06:55) *
А проблема в том, что однократное чтение того же AIC_IVR изменяет состояние AIC.
Залезть в .ddf и исключить IVR из списка отображаемых регистров.
Tahoe
Цитата
Можно еще protected mode использовать для AIC...

Ну дык uCOS из SVC и не вылезает. wink.gif За исключением собсно прерывания, но сам хендлер всё равно запускается в SVC. Вот потому-то мне и непонятно. Вроде всё по науке, запись в AIC_IVR производится...


Насчёт залезть в ddf была мысля. Под uCOS в принципе прокатит, потому как значение AIC_IVR там сначала переменной присваивается. Её и можно будет смотреть ( что сечйчас и делаю smile.gif ). Но как быть, если проект без ОСи? Если значение AIC_IVR используется непосредственно, как указатель на хендлер? Хотя, наверное, можно и пережить. smile.gif

2 _dem
А с чем связан прыжок обратно, с FreeRTOS на uCOS? Если не секрет? wink.gif
_dem
Цитата(Tahoe @ Apr 3 2007, 14:27) *
2 _dem
А с чем связан прыжок обратно, с FreeRTOS на uCOS? Если не секрет? wink.gif


Не секрет smile.gif

Под FreeRTOS для IAR не удалось в разумный срок портировать LwIP, а uIP дал скорость потока TCP/UDP порядка 3-5 кбайт в секунду, что не достаточно.

Порт LwIP + FreeRTOS для Rowley устроил всем, кроме одного - под нашим J-Link он (Rowley) зашивает MCU порядка минуты. Опять таки, ни скудные мануалы Rowley, ни форумы не помогли решить проблему (в т.ч. пробовались разные версии драйвера J-Link).

Огорчились, выпили чего-то там... Пересоздали с нуля проект uCOS для IAR, прерывания USART запустились и в данный момент работает все отлично (тьфу-тьфу-тьфу).

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

TCP/IP стек uC/OS-ii дал с ходу в простейшем тесте поток порядка 3.5 мбайта в секунду (только одна задача - отправка данных в цикле).

smile.gif
Tahoe
dem
Понятно. Я пока тоже до конца не разобрался с прерываниями. На данный момент вроде работает. Но некоторые траблы остались. Например сейчас из ddf выкинул AIC_IVR, вроде как работает. Но вылезла другая бяка. Если включен в IAR-е uCOS-плугин, то всё работает до первой остановки дебага. Потом уже не запускается. Но теперь я хоть регистры AIC вижу, так что разберусь попозже. smile.gif


Кстати, интересно, это только у меня такая бяка: если дебаг остановлен в хендлере прерывания, то при попытке посмотреть в "хинте" значение локальной переменной IAR 4.41a просто падает. Попробовал, снёс папку settings в проекте, но не помогло. Сама пременная static int16u.
SpiritDance
Цитата(_dem @ Apr 5 2007, 19:23) *
Порт LwIP + FreeRTOS для Rowley устроил всем, кроме одного - под нашим J-Link он (Rowley) зашивает MCU порядка минуты. Опять таки, ни скудные мануалы Rowley, ни форумы не помогли решить проблему (в т.ч. пробовались разные версии драйвера J-Link).

Надо было виглер пользовать, кроссворкс с ним на порядок быстрее работает.
_dem
Цитата
при попытке посмотреть в "хинте" значение локальной переменной IAR 4.41a просто падает


именно в "хинте", не в Watch/Quick Watch ?


Цитата
Надо было виглер пользовать, кроссворкс с ним на порядок быстрее работает.


С вигглером мучались ранее - так и не смогли заставить его работать под IAR... хотя, может, плохо старались smile.gif т.к. к тому времени уже приехала eval board и 2 J-link-а

А съезжать с привычного всем IAR-а на CrossWorkx из-за TCP/IP стека было не совсем хорошо. Хотя лично мне Rowley понравился больше, чем иар...
Tahoe
Цитата(_dem @ Apr 6 2007, 11:09) *
именно в "хинте", не в Watch/Quick Watch ?

Да, именно в "хинте". Что неприятно, можно случайно остановить мышь "не в том месте" и вуаля. ИАР закроется. Причём без всяких GPF, просто тихо вываливается в винду и всё.
Пока думаю, что эта проблемка моя, локальная, а не глюк ИАРа. Просто на всякий случай решил спросить, может кто откликнется, это же недолго проверить. smile.gif

Цитата(_dem @ Apr 6 2007, 11:09) *
С вигглером мучались ранее - так и не смогли заставить его работать под IAR... хотя, может, плохо старались smile.gif

Именно плохо старались. wink.gif IAR нормально работает с Wiggler через RDI->HJTAG. И имхо гораздо стабильнее, чем напрямую. Причём у меня прямо сейчас висит на плате цепочка из SAM7S и MAX-II. Видится и шьётся без проблем, что проц, что ПЛИС.

Цитата(_dem @ Apr 6 2007, 11:09) *
Хотя лично мне Rowley понравился больше, чем иар...

Да ну... Ёлочка новогодняя, а не среда разработки.
Velund
Цитата(Tahoe @ Apr 6 2007, 06:59) *
Если включен в IAR-е uCOS-плугин, то всё работает до первой остановки дебага. Потом уже не запускается. Но теперь я хоть регистры AIC вижу, так что разберусь попозже. smile.gif


Я наступал на подобные грабли (на LPC2129) - вылечилось небольшой модификацией тикера (переходом с free-running timer на сброс при досчете). Не самое лучшее что можно придумать, таймер для другого не попользуешь, но по крайней мере он быстро "подхватывает" инты после останова.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.