Перейти к содержанию
    

Сбой системы при использовании вложенных прерываний

Есть довольно увесистый проект stm32f207+freertos 8.0.1+Keil 4.6

Вылетает в bus fault. Причем только после того как начинаю включать вложенные прерывания. Пока все прерывания сидят в

приоритете 15(Тик ртоса и мои таймера/уарты) работает нормально. Как только любому из моих прерываний даю приоритет 14(вывел на джампер GPIOE->IDR & Key_K1) либо всем, сразу валится в эксепшин, причем не сразу а через 5-10 мин как "звезды станут в ряд"

 

Дошел до следующего, в процедуре xPortPendSVHandler в pxCurrentTCB после переключения контекста попадает NULL,

далее подтягивается с нулевого адреса начальное значение стека MSP вместо стека задачи, и при попытке восстановить стек задачи

с адреса 0x20020000 валится в BUS FAULT (это я спецом под стек выделил все оставшееся ОЗУ, до этого валилось в USAGE FAULT

когда восстанавливало стек из неиспользуемого места ОЗУ)

 

__asm void xPortPendSVHandler( void )
{
    extern uxCriticalNesting;
    extern pxCurrentTCB;
    extern vTaskSwitchContext;

    PRESERVE8

    mrs r0, psp
    isb

    ldr    r3, =pxCurrentTCB        /* Get the location of the current TCB. */
    ldr    r2, [r3]

    stmdb r0!, {r4-r11}            /* Save the remaining registers. */
    str r0, [r2]                /* Save the new top of stack into the first member of the TCB. */

    stmdb sp!, {r3, r14}
    mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITY
    msr basepri, r0
    bl vTaskSwitchContext
    mov r0, #0
    msr basepri, r0
    ldmia sp!, {r3, r14}

    ldr r1, [r3]
; ***************my start
    cmp R1,#0
    bne l22
    nop;-------------------------------------------------------- Здесь поставил бреакпоинт
    nop
l22    

; ***************my finish
    
    ldr r0, [r1]                /* The first item in pxCurrentTCB is the task top of stack. */
;----------------Вылетает при  следующей команде
; R0=0x20020000  - следующий адрес за  внутренним ОЗУ
    ldmia r0!, {r4-r11}            /* Pop the registers and the critical nesting count. */
    msr psp, r0
    isb
    bx r14
    nop
}

 

 

Настройка прерываний

 

 

При старте до старта ртоса

   RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); // 4 preeptive  4 subpriority

 

#define configKERNEL_INTERRUPT_PRIORITY         255
#define configMAX_SYSCALL_INTERRUPT_PRIORITY     191 /* equivalent to 0xb0, or priority 11. */
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY    15

 

Конфигурация таймера(ов) Используются как внешние прерывания по уровню.

void Tim9_IT_init (void)
{
    
    TIM_TimeBaseInitTypeDef timStruct;
    TIM_ICInitTypeDef timicStruct;
    NVIC_InitTypeDef nvicStructure;
    
    // Alternative function
    GPIOE->AFR[0] &= ~(GPIO_AFRL_AFRL6  );
    GPIOE->AFR[0] |= ((GPIO_AFRL_AFRL6 & 0x33333333) ); // PE6 - AF3
    
    GPIOE->MODER&=~GPIO_MODER_MODER6;
    GPIOE->MODER|=GPIO_MODER_MODER6_1;
    
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM9, ENABLE);
    timStruct.TIM_Prescaler=0;
    timStruct.TIM_CounterMode=TIM_CounterMode_Up;
    timStruct.TIM_Period=10;
    timStruct.TIM_ClockDivision=TIM_CKD_DIV1;
    timStruct.TIM_RepetitionCounter=0; // doesn't matter
    TIM_TimeBaseInit(TIM9, &timStruct);
    
    
        // Gated mode
    //timicStruct.TIM_Channel=TIM_Channel_1;
    timicStruct.TIM_Channel=TIM_Channel_2;
    timicStruct.TIM_ICPolarity=TIM_ICPolarity_Falling;
    timicStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;
    timicStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;
    timicStruct.TIM_ICFilter=0;
    TIM_ICInit(TIM9,&timicStruct);
    
    
    //TIM_SelectInputTrigger(TIM9,TIM_TS_TI1FP1);
    TIM_SelectInputTrigger(TIM9,TIM_TS_TI2FP2);
    TIM_SelectSlaveMode(TIM9,TIM_SlaveMode_Gated);
    
       //5. Enable the corresponding interrupt using the function TIM_ITConfig(TIMx, TIM_IT_Update) 
    
//    TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
//    TIM_ITConfig(TIM4, TIM_IT_Update,ENABLE);
    
    // interrupt
    
       //4. Enable the NVIC if you need to generate the update interrupt. 
             
    nvicStructure.NVIC_IRQChannel = TIM1_BRK_TIM9_IRQn;
        if (GPIOE->IDR & Key_K1)    
        {
            nvicStructure.NVIC_IRQChannelPreemptionPriority = 15;
        }
        else
        {
            nvicStructure.NVIC_IRQChannelPreemptionPriority = 14;
        }
    nvicStructure.NVIC_IRQChannelSubPriority = 0;
    nvicStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvicStructure);
             
       //6. Call the TIM_Cmd(ENABLE) function to enable the TIM counter.
             
  TIM_Cmd(TIM9,ENABLE);
    
}

 

Стеки задач с запасом где то минимум на 50 байт (видно по статистике когда нет вложенных прерываний, проект живет сутками)

Стек MSP вообще сейчас вся оставшаяся память - 7кб

Куча стартапа - 1кб, но я так понимаю она используется только при либовских Malloc которую я не использую. Вместо них я

использую ртосовскую, там где то свободных 10кб.

 

 

Собственно вопрос , что теперь с этим делать и куда рыть ? Каким образом в pxCurrentTCB может попасть 0 ? В моем понимании

если даже все мои задачи в ожидании , должна крутиться Idle ?

Изменено пользователем grv

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я думаю, что с этим у вас все правильно, но все же на всякий случай: все обработчики прерываний, вызывающие API-шные функции операционки, используют специализированные функции с окончанием FromISR()? Все такие функции имеют приоритет 11 и выше (численно)?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Я думаю, что с этим у вас все правильно, но все же на всякий случай: все обработчики прерываний, вызывающие API-шные функции операционки, используют специализированные функции с окончанием FromISR()? Все такие функции имеют приоритет 11 и выше (численно)?

 

 

Вроде разобрался.

Ситуация конечно плачевная, суть в следующем:

Грабли таятся в Trace. При определении в настойках USE_PRIMASK_CS 0 в прерываниях в теле функций типа xSemaphoreGiveFromISR() используются макросы portENTER_CRITICAL/ portEXIT_CRITICAL чего делать категорически нельзя. Этими макросами трейс защищает свою критическую секцию. Но при выходе из portEXIT_CRITICAL мы гарантированно имеем BASEPRI=0, и в далее идущую часть критического кода xSemaphoreGiveFromISR врезается высокоприоритетное прерывание что у меня приводило к повреждениям списков задач и далее вылетало в BUSFAULT.

Когда не было вложенных прерываний естественно все классно работало.

 

#if ((SELECTED_PORT == PORT_ARM_CortexM) && (USE_PRIMASK_CS == 1))

#define TRACE_SR_ALLOC_CRITICAL_SECTION() int __irq_status;

#define TRACE_ENTER_CRITICAL_SECTION() { __irq_status = prvTraceGetIRQMask(); prvTraceDisableIRQ(); }

#define TRACE_EXIT_CRITICAL_SECTION() { prvTraceSetIRQMask(__irq_status); }

#define trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY trcCRITICAL_SECTION_BEGIN
#define trcCRITICAL_SECTION_END_ON_CORTEX_M_ONLY trcCRITICAL_SECTION_END

#else

#define TRACE_ENTER_CRITICAL_SECTION() portENTER_CRITICAL()
#define TRACE_EXIT_CRITICAL_SECTION() portEXIT_CRITICAL()

#define trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY() recorder_busy++;
#define trcCRITICAL_SECTION_END_ON_CORTEX_M_ONLY() recorder_busy--;

#endif

 

 

Ставить USE_PRIMASK_CS 1 это с пушки по воробьям, теряется тогда идея "всегда разрешенных прерываний" приоритетом выше MAXSYSCALL

Пока поставил так (изменил вариант для USE_PRIMASK_CS 1), грабли ушли:

#if ((SELECTED_PORT == PORT_ARM_CortexM) && (USE_PRIMASK_CS == 1))

#define TRACE_SR_ALLOC_CRITICAL_SECTION() int __irq_status;

//#define TRACE_ENTER_CRITICAL_SECTION() { __irq_status = prvTraceGetIRQMask(); prvTraceDisableIRQ(); }
#define TRACE_ENTER_CRITICAL_SECTION() { __irq_status = portSET_INTERRUPT_MASK_FROM_ISR(); }


//#define TRACE_EXIT_CRITICAL_SECTION() { prvTraceSetIRQMask(__irq_status); }
#define TRACE_EXIT_CRITICAL_SECTION() { portCLEAR_INTERRUPT_MASK_FROM_ISR(__irq_status); }

#define trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY trcCRITICAL_SECTION_BEGIN
#define trcCRITICAL_SECTION_END_ON_CORTEX_M_ONLY trcCRITICAL_SECTION_END

#else

#define TRACE_ENTER_CRITICAL_SECTION() portENTER_CRITICAL()
#define TRACE_EXIT_CRITICAL_SECTION() portEXIT_CRITICAL()

#define trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY() recorder_busy++;
#define trcCRITICAL_SECTION_END_ON_CORTEX_M_ONLY() recorder_busy--;

#endif

 

Одно хорошо, за неделю ковыряний нашел у себя небольшую тележку багов по-меньше и перешел на advanced level в части понимания как FREERTOS все-таки работает :biggrin:

Изменено пользователем grv

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Здравствуйте

 

У меня похоже такая же проблема. FreeRTOS 9.0. Если прерывания идут друг за другом, то всё работает. Как только появляется вложенное прерывание то происходит вылет. Иногда не вылет но теряются семафоры. В общем не предсказуемое поведение программы. Только R0 у меня если я правлиьно понял был равен 0x1. Пробовал назначать всем прерываниям один уровень, чтобы небыло вложенных . Но на отложенных прерываниях тоже самое. Включал отключал трассировку - не влияет.

Хотел спросить. В каих файлах эти строки? Или они в 9 вресии этот участок кода изменили?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Прошу прощения. У меня оказалась совсем другая и банальная ошибка.

Каким то чудом закоментировал NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...