реклама на сайте
подробности

 
 
> Не могу переделать IRQ на FIQ (fast forcing) для FreeRTOS, AT91SAM7X256
OlegHmt
сообщение Jan 12 2007, 13:18
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 70
Регистрация: 5-12-06
Пользователь №: 23 146



Помогите, пожалуйста, найти ошибку.

Собственно система работает под управлением FreeRTOS - это модифицированный вариант примера IwIp для Rowley только вместо стека lwIP я прикрутил uIP. В системе запущены три задачи: первая обслуживает сеть, вторая USB (виртуальный COM), третья мониторит и перерабатывает данные полученные через USB. Кроме этого в системе добавлено прерывание по таймеру (сравнение с регистром RC) по которому с заданым периодом из полученных даных фомируется короткая посылка, которая скармливается DMA для SPI. Приоритет этого прерывания я поставил наивысший (7), понизив приоритет таймера ОС до 6. Система работает, но (как я понимаю) в связи с наличием критических секций, период вывода в SPI плавает. Мне порекомендовали перейти на FIQ, что я и попробовал сделать. Но возникли проблемы - в таком варианте система отказывается работать. Если период вывода большой, то вывод на SPI работает, а всё остальное не откликается, если маленький, то даже вывод в SPI молчит. Стоит забрать опцию FastForcing, то-есть перевести тот-же код на IRQ - всё нормально работает. Само FIQ прерывание, похоже работает нормально, так-как если после инициализиции запустить систему по пустому циклу, то вывод на SPI работает:
Код
InitTimerInt();
  portENABLE_INTERRUPTS();
  for(;;)
  {
  }  
  /* Finally, start the scheduler.     
  vTaskStartScheduler();

А при старте в нормальном режиме с выполнением задач в какой-то момент система останавливается, что-ли.
Ума уже не приложу что ещё нужно сделать. Похоже на какой-то конфликт ядра FreeRTOS с FIQ, но где именно копать понять не могу. Часть кода относящаяся к этой проблеме ниже. По сравнению с вариантом реализованым на IRQ изменения следующие:
1. В flash_placement.xml изменил размер стека для FIQ с нуля до 0х190
2. В AT91SAM7_Startup.s изменил команду перехода на обработку прерывания FIQ
Код
ldr pc, [PC, #-0xF20]    /* irq */
  //ldr pc, [pc, #fiq_handler_address - . - 8]    /* fiq */
  ldr pc, [PC, #-0xF20]    /* fiq */


3. У функцию инициализации прерывания добавлено установку адреса обработчика для FIQ и включение FastForcing:
Код
void InitTimerInt(void)
{
//  AT91F_AIC_ConfigureIt( AT91C_ID_TC0, DACsTIMER_PRIORITY, AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL, ( void (*)( void ) ) vTimer_ISR );
  //Disable the interrupt on the interrupt controller
  AT91C_BASE_AIC->AIC_IDCR=(0x1<<AT91C_ID_TC0);
  AT91C_BASE_AIC->AIC_IDCR=(0x1<<AT91C_ID_FIQ); //Добавлено это
  //Save the interrupt handler routine pointer and the interrupt priority
  AT91C_BASE_AIC->AIC_SVR[AT91C_ID_FIQ] = (unsigned int) vTimer_ISR;  //Добавлено это
  AT91C_BASE_AIC->AIC_SVR[AT91C_ID_TC0] = (unsigned int) vTimer_ISR;
  //Store the Source Mode Register  AT91C_BASE_AIC->AIC_SMR[AT91C_ID_TC0]=AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL|DACsTIMER_PRIORITY;
  //Clear the interrupt on the interrupt controller
  AT91C_BASE_AIC->AIC_ICCR=(0x1<<AT91C_ID_TC0); //Добавлено это
  AT91C_BASE_AIC->AIC_ICCR=(0x1<<AT91C_ID_FIQ); //Добавлено это
  AT91C_BASE_AIC->AIC_FFER=(1<<AT91C_ID_TC0); //Добавлено это
AT91C_BASE_TC0->TC_CMR=AT91C_TC_CLKS_TIMER_DIV1_CLOCK|AT91C_TC_EEVT_XC0|AT91C_TC_WAVESEL_UP_
AUTO|AT91C_TC_WAVE|AT91C_TC_ACPA_SET|AT91C_TC_ACPC_CLEAR;
  AT91C_BASE_TC0->TC_IER=AT91C_TC_CPCS;
  AT91C_BASE_AIC->AIC_IECR = 0x1 << AT91C_ID_TC0;
  AT91C_BASE_TC0->TC_CCR=AT91C_TC_CLKEN | AT91C_TC_SWTRG;
}


4. Изменённый обработчик выглядит следующим образом:
Код
void vTimer_ISR( void ) __attribute__ ((section(".fast"))) __attribute__ ((naked));
void vTimer_ISR( void )
{
  portENTER_SWITCHING_ISR();
  AT91C_BASE_PIOB->PIO_OER = BIT27;
  AT91C_BASE_PIOB->PIO_PER = BIT27;
  AT91C_BASE_PIOB->PIO_CODR = BIT27;//Вывод на светодиод чтобы проверить что обработчик работает
  AT91C_BASE_TC0->TC_SR;
  AT91C_BASE_PIOA->PIO_CODR = BIT3;
  AT91C_BASE_PIOA->PIO_SODR = BIT3;
  if (OutFlags & NotFlag){
    tempBuff[0]=AnPDCS3;
    tempBuff[1]=XCS0;
    tempBuff[2]=BnPDCS3;
    tempBuff[3]=XCS0;
    tempBuff[4]=CnPDCS3;
    tempBuff[5]=YCS0;
    tempBuff[6]=DnPDnCCS3;
    Current++;
    if (Current>=Numb)
    {
      Current=0;
    }
  } else {
    tempBuff[0]=(A1[Current]<<4)|AnPDCS3;
    tempBuff[1]=XCS0;
    tempBuff[2]=(A2[Current]<<4)|BnPDCS3;
    tempBuff[3]=A3[Current]|XCS0;
    tempBuff[4]=(A4[Current]<<4)|CnPDCS3;
    tempBuff[5]=A5[Current]|YCS0;
    tempBuff[6]=(A6[Current]<<4)|DnPDnCCS3;
    Current++;
    if (Current>=Numb)
    {
      Current=0;
    }
  }
  AT91C_BASE_SPI1->SPI_TPR=(unsigned int)tempBuff;
  AT91C_BASE_SPI1->SPI_TCR=7;
  //AT91C_BASE_AIC->AIC_EOICR = 0; \\Это включается для IRQ
  AT91C_BASE_AIC->AIC_ICCR = (0x1 << AT91C_ID_TC0)|(0x1 << AT91C_ID_FIQ);
  if (Current==300) {
    AT91C_BASE_AIC->AIC_IDCR = 0x1 << AT91C_ID_TC0;
  } //Вот этой конструкцией я проверял начинает ли работать FIQ. Если где-то после 300 (или меньше) прерываний их запретить, то дальше вся система работает нормально (конечно кроме вывода в SPI)
  portEXIT_SWITCHING_ISR(pdFALSE);
}


На всякий случай ещё привожу расшифровку макросов обёртки прерывания, может там что нужно поменять:

Код
#define portRESTORE_CONTEXT()                                            \
{                                                                        \
extern volatile void * volatile pxCurrentTCB;                            \
extern volatile unsigned portLONG ulCriticalNesting;                    \
    /* Set the LR to the task stack. */                                    \
    asm volatile (                                                        \
    "LDR        R0, =pxCurrentTCB                                \n\t"    \
    "LDR        R0, [R0]                                        \n\t"    \
    "LDR        LR, [R0]                                        \n\t"    \
    /* The critical nesting depth is the first item on the stack. */    \
    /* Load it into the ulCriticalNesting variable. */                    \
    "LDR        R0, =ulCriticalNesting                            \n\t"    \
    "LDMFD    LR!, {R1}                                            \n\t"    \
    "STR        R1, [R0]                                        \n\t"    \
    /* Get the SPSR from the stack. */                                    \
    "LDMFD    LR!, {R0}                                            \n\t"    \
    "MSR        SPSR, R0                                        \n\t"    \
    /* Restore all system mode registers for the task. */                \
    "LDMFD    LR, {R0-R14}^                                        \n\t"    \
    "NOP                                                        \n\t"    \
    /* Restore the return address. */                                    \
    "LDR        LR, [LR, #+60]                                    \n\t"    \
    /* And return - correcting the offset in the LR to obtain the */    \
    /* correct address. */                                                \
    "SUBS    PC, LR, #4                                            \n\t"    \
    );                                                                    \
    ( void ) ulCriticalNesting;                                            \
    ( void ) pxCurrentTCB;                                                \
}
/*-----------------------------------------------------------*/

#define portSAVE_CONTEXT()                                                \
{                                                                        \
extern volatile void * volatile pxCurrentTCB;                            \
extern volatile unsigned portLONG ulCriticalNesting;                    \
    /* Push R0 as we are going to use the register. */                    \
    asm volatile (                                                        \
    "STMDB    SP!, {R0}                                            \n\t"    \
    /* Set R0 to point to the task stack pointer. */                    \
    "STMDB    SP,{SP}^                                            \n\t"    \
    "NOP                                                        \n\t"    \
    "SUB    SP, SP, #4                                            \n\t"    \
    "LDMIA    SP!,{R0}                                            \n\t"    \
    /* Push the return address onto the stack. */                        \
    "STMDB    R0!, {LR}                                            \n\t"    \
    /* Now we have saved LR we can use it instead of R0. */                \
    "MOV    LR, R0                                                \n\t"    \
    /* Pop R0 so we can save it onto the system mode stack. */            \
    "LDMIA    SP!, {R0}                                            \n\t"    \
    /* Push all the system mode registers onto the task stack. */        \
    "STMDB    LR,{R0-LR}^                                            \n\t"    \
    "NOP                                                        \n\t"    \
    "SUB    LR, LR, #60                                            \n\t"    \
    /* Push the SPSR onto the task stack. */                            \
    "MRS    R0, SPSR                                            \n\t"    \
    "STMDB    LR!, {R0}                                            \n\t"    \
    "LDR    R0, =ulCriticalNesting                                \n\t"    \
    "LDR    R0, [R0]                                            \n\t"    \
    "STMDB    LR!, {R0}                                            \n\t"    \
    /* Store the new top of stack for the task. */                        \
    "LDR    R0, =pxCurrentTCB                                    \n\t"    \
    "LDR    R0, [R0]                                            \n\t"    \
    "STR    LR, [R0]                                            \n\t"    \
    );                                                                    \
    ( void ) ulCriticalNesting;                                            \
    ( void ) pxCurrentTCB;                                                \
}


/*-----------------------------------------------------------
* ISR entry and exit macros.  These are only required if a task switch
* is required from the ISR.
*----------------------------------------------------------*/
#define portENTER_SWITCHING_ISR()                                        \
    /* Save the context of the interrupted task. */                        \
    portSAVE_CONTEXT();                                                    \
    /* We don't know the stack requirements for the ISR, so the frame */\
    /* pointer will be set to the top of the task stack, and the stack*/\
    /* pointer left where it is.  The IRQ stack will get used for any */\
    /* functions calls made by this ISR. */                                \
    asm volatile ( "SUB        R11, LR, #4" );                            \
    {

#define portEXIT_SWITCHING_ISR( SwitchRequired )                        \
        /* If a switch is required then we just need to call */            \
        /* vTaskSwitchContext() as the context has already been */        \
        /* saved. */                                                    \
        if( SwitchRequired )                                            \
        {                                                                \
            vTaskSwitchContext();                                        \
        }                                                                \
    }                                                                    \
    /* Restore the context of which ever task is now the highest */        \
    /* priority that is ready to run. */                                \
    portRESTORE_CONTEXT();


Сообщение отредактировал OlegHmt - Jan 12 2007, 13:22
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 01:01
Рейтинг@Mail.ru


Страница сгенерированна за 0.01411 секунд с 7
ELECTRONIX ©2004-2016