UC/OS III семафор внутри ISR иногда не работает

У меня проблема с семафором, кажется, что иногда SemPost, вызываемый внутри ISR, не эффективен.

Мое приложение основано на Micrimum UCOS III, а целевая платформа основана на Microsemi Smartfusion2 SoC (Cortex-M3). Мое приложение состоит из двух задач (A и B), но только одна активна, когда возникает проблема (другая прикреплена к семафору).

Проблема возникает, когда активная задача (назовем ее Задачей A) выполняет следующие действия:

  1. записать в какой-либо регистр, чтобы начать операцию после того, как будет запущено прерывание
  2. ожидает завершения операции, создавая OSSemPend в семафоре (назовем его Sem A), устанавливая время ожидания 100 мсек.
  3. проверяет, нормально ли завершился вызов OSSemPend или произошел тайм-аут

Когда прерывание инициируется, соответствующий ISR создает SemPost для Sem A, чтобы разблокировать семафор до истечения времени ожидания.

Когда возникает проблема, OSSemPend возвращает OS_ERR_TIMEOUT. Я вижу эту проблему очень, очень, очень редко.

Я уверен в том что:

  • операция запуска (см. пункт 1) дается, и операция начинается.
  • прерывание срабатывает, и выполняется OSSemPost в Sem A.
  • прерывание срабатывает менее чем через 500 мкс (т. е. < 1 мс) с начала

Правильно ли написан код? Есть ли какие-либо ограничения в использовании семафоров внутри ISR? Кто-нибудь может мне помочь? Спасибо

Я прилагаю упрощенную версию кода

/*
 * the interrupt handler, triggered at the end of the operation
 */
void FabricIrq2_IRQHandler(void)
{
    OS_ERR os_err;
    CPU_SR_ALLOC();
    CPU_CRITICAL_ENTER();
    /*
     * write in a register of the ip core generating the interrupt in order 
     * to reset the interrupt
     */
    OSSemPost(&Sem_A, OS_OPT_POST_ALL, &os_err); 
    OSSemSet(&Sem_Tx, 0, &os_err); /* not relevant for this problem */
    CPU_CRITICAL_EXIT();
}

void startOp()
{
    CPU_SR_ALLOC();
    CPU_CRITICAL_ENTER();
    /*
     * write in an ip core register in order to start operation
     */
    CPU_CRITICAL_EXIT();
}


/*
 * task a **partial**
 */
uint8_t task_a(void)
{
    uint8_t ret;
    OS_ERR   os_err;
    startOp();
    OSSemPend(&Sem_A, (OS_TICK)10, OS_OPT_PEND_BLOCKING, NULL, &os_err);
    switch (os_err){
    /* manage errors*/
    }
    return ret;
}

1 ответ

  1. Вам не нужно отключать прерывания при вызове OSSemPost(). OSSemPost() считается атомарной операцией в вашем приложении.

  2. ISR должен выглядеть следующим образом для ядра Cortex-M3, которое входит в состав Microsemi:

    void MyISR (void)
    {
       CPU_SR_ALLOC();
    
       CPU_CRITICAL_ENTER();
       OSIntEnter();
       CPU_CRITICAL_EXIT();
       OSSemPost(...);
       OSIntExit();
    }
    

Это позволяет вам сообщить uC/OS-III, что вы запускаете ISR. Это необходимо для того, чтобы ядро ​​могло запланировать опубликованное задание, если оно готово к запуску с наивысшим приоритетом.

Другие вопросы по тегам