UC/OS III семафор внутри ISR иногда не работает
У меня проблема с семафором, кажется, что иногда SemPost, вызываемый внутри ISR, не эффективен.
Мое приложение основано на Micrimum UCOS III, а целевая платформа основана на Microsemi Smartfusion2 SoC (Cortex-M3). Мое приложение состоит из двух задач (A и B), но только одна активна, когда возникает проблема (другая прикреплена к семафору).
Проблема возникает, когда активная задача (назовем ее Задачей A) выполняет следующие действия:
- записать в какой-либо регистр, чтобы начать операцию после того, как будет запущено прерывание
- ожидает завершения операции, создавая OSSemPend в семафоре (назовем его Sem A), устанавливая время ожидания 100 мсек.
- проверяет, нормально ли завершился вызов 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 ответ
Вам не нужно отключать прерывания при вызове OSSemPost(). OSSemPost() считается атомарной операцией в вашем приложении.
ISR должен выглядеть следующим образом для ядра Cortex-M3, которое входит в состав Microsemi:
void MyISR (void) { CPU_SR_ALLOC(); CPU_CRITICAL_ENTER(); OSIntEnter(); CPU_CRITICAL_EXIT(); OSSemPost(...); OSIntExit(); }
Это позволяет вам сообщить uC/OS-III, что вы запускаете ISR. Это необходимо для того, чтобы ядро могло запланировать опубликованное задание, если оно готово к запуску с наивысшим приоритетом.