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

 
 
> Не могу переделать 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
 
Start new topic
Ответов
zltigo
сообщение Jan 12 2007, 13:53
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(OlegHmt @ Jan 12 2007, 12:18) *
2. В AT91SAM7_Startup.s изменил команду перехода на обработку прерывания FIQ
Код
ldr pc, [PC, #-0xF20]    /* irq */
  //ldr pc, [pc, #fiq_handler_address - . - 8]    /* fiq */
  ldr pc, [PC, #-0xF20]    /* fiq */

Не заменить! а просто НАПИСАТЬ свой обработчик FIQ и ПРЯМО подставить ЕГО адрес.
Сам обработчик FIQ и естественно он НЕ сможет "работать обработчиком IRQ" все обертки для переключения контекста из IRQ УБРАТЬ они нужны только для случая если Вы собрались переключить задачу при выходе из IRQ и уж по всякому не годяться для FIQ - просто чистый как слеза обработчик FIQ "как в книжке" напишите и ВСЕ!
При инициализации прерывание классифицировать как FIQ и больше никаких телодвижений.
Все будет работать.
Потом придется sad.gif доработать FreeRTOS с целью не запрещения FIQ в критических секциях, ибо
в оригинале сделано огульное запрещение и IRQ и FIQ разом.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
OlegHmt
сообщение Jan 12 2007, 15:45
Сообщение #3


Участник
*

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



Цитата(zltigo @ Jan 12 2007, 12:53) *
Не заменить! а просто НАПИСАТЬ свой обработчик FIQ и ПРЯМО подставить ЕГО адрес.
Сам обработчик FIQ и естественно он НЕ сможет "работать обработчиком IRQ" все обертки для переключения контекста из IRQ УБРАТЬ они нужны только для случая если Вы собрались переключить задачу при выходе из IRQ и уж по всякому не годяться для FIQ - просто чистый как слеза обработчик FIQ "как в книжке" напишите и ВСЕ!
При инициализации прерывание классифицировать как FIQ и больше никаких телодвижений.
Все будет работать.
Потом придется sad.gif доработать FreeRTOS с целью не запрещения FIQ в критических секциях, ибо
в оригинале сделано огульное запрещение и IRQ и FIQ разом.


Спасибо. Правда первый раз, когда я так попробовал сделать, у меня что-то на обработчик не переходило совсем, а через вектор заработало. Правда, тогда, я ещё очень слабо представлял что это такое, поэтому наверняка ошибся. Сегодня попробую.
А на счёт контекста - переключение убрать, а оставить сохранение?
portSAVE_CONTEXT()
portRESTORE_CONTEXT()

Немножко дурацкий вопрос :-), но всё же - у Вас FIQ вместе с FreeRTOS работал?
Так как вроде-бы то что у меня написано, оно тоже "по книжке". И само по себе работает, но не хочет уживаться с FreeRTOS. Может что-то забыл ещё записать?

А доработать отмену запрещения FIQ - это я уже нашёл, там в нескольких местах нужно запись в регистр поправить.

Сообщение отредактировал OlegHmt - Jan 12 2007, 15:46
Go to the top of the page
 
+Quote Post
zltigo
сообщение Jan 12 2007, 18:13
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата
Правда первый раз, когда я так попробовал сделать, у меня что-то на обработчик не переходило совсем, а через вектор заработало.

Это не принципиально, это просто лишнее при одном единственом обработчике FIQ.
Цитата(OlegHmt @ Jan 12 2007, 14:45) *
А на счёт контекста - переключение убрать, а оставить сохранение?
portSAVE_CONTEXT()
portRESTORE_CONTEXT()

У Вас НЕТ переключения задач. Посему и save/restore от FreeRTOS как минимум НЕ нужны даже для IRQ. Нужен просто (с учетом предыдущих постов уже притомился писать одно и тоже) обработчик FIQ. Причем обработчик FIQ самый обычный а не какой-то особеный для FreeRTOS, ему глубоко все равно кого прерывать!
Цитата
Немножко дурацкий вопрос :-), но всё же - у Вас FIQ вместе с FreeRTOS работал?

Естественно работал, работает и будет работать и с FreeRTOS и без нее. Естественно без переключения контекстов - прервал всех и вся сделал дело и все.
Цитата
Так как вроде-бы то что у меня написано, оно тоже "по книжке".

За каким-то чертом было проведено бездумное сваливание в одну кучу кусков обработчика IRQ и не простого а того из которого можно производить переключение задач FreeRTOS, и банального обработчика FIQ, причем на специфика FIQ была проигнорирована.

Вместо того, что-бы просто по, например, первой попавшейся "книжке" сваять абстрактный обработчик FIQ и все!.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post



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

 


RSS Текстовая версия Сейчас: 21st July 2025 - 15:03
Рейтинг@Mail.ru


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