Jump to content

    
Sign in to follow this  
3.14

FreeRTOS + LPC2378

Recommended Posts

Решил подправить пример freertos на lpc2129 под кейл-ом на сабжевый чип.

Втставил в родной startup.s часть касаюшуюся настроек тактирования, успешно пересобрал.

Запускаю дебагер, дебагер впадает в вечный цикл с ошибкой выбора инструкции по адресу 0xC ?!

Причем в оригинале, как полагается, после сброса в PC грузится 0х40.

Share this post


Link to post
Share on other sites

Вобщем, не понял почему в данном случае у симулятора крыша едет ... если переключить чип (на 2129) при тех же исходниках то стартап оживает ...

Далее, главное в железе запускается.

Ну как и следовало ожидать, ничего сходу не вышло, стал выяснять на каком месте встает.

Успешно проходят функции:

prvSetupHardware();

vStartIntegerMathTasks( tskIDLE_PRIORITY );

vAltStartComTestTasks( mainCOM_TEST_PRIORITY, mainCOM_TEST_BAUD_RATE, mainCOM_TEST_LED );

vStartLEDFlashTasks( mainLED_TASK_PRIORITY );

vStartPolledQueueTasks( mainQUEUE_POLL_PRIORITY );

vStartBlockingQueueTasks( mainBLOCK_Q_PRIORITY );

vStartSemaphoreTasks( mainSEM_TEST_PRIORITY );

vStartDynamicPriorityTasks();

xTaskCreate( vErrorChecks, "Check", configMINIMAL_STACK_SIZE, NULL, mainCHECK_TASK_PRIORITY, NULL );

 

Далее входит в vTaskStartScheduler() в которой выполняется настройка таймера а после выполняется vPortISRStartFirstTask().

Так вот в это самой vPortISRStartFirstTask выполняется только один макрос (portRESTORE_CONTEXT()):

#define portRESTORE_CONTEXT() \

{ \

extern volatile unsigned portLONG ulCriticalNesting; \

extern volatile void * volatile pxCurrentTCB; \

\

__asm{ LDR R1, =pxCurrentTCB };/* Set the LR to the task stack. The location was ... */ \

__asm{ LDR R0, [R1] }; /* ... stored in pxCurrentTCB. */ \

__asm{ LDR LR, [R0] }; \

\

__asm{ LDR R0, =ulCriticalNesting }; /* The critical nesting depth is the first item on ... */ \

__asm{ LDMFD LR!, {R1 } } /* ... the stack. Load it into the ulCriticalNesting var. */ \

__asm{ STR R1, [R0] } \

\

__asm{ LDMFD LR!, {R0} }; /* Get the SPSR from the stack. */ \

__asm{ MSR SPSR_CXSF, R0 }; \

\

__asm{ LDMFD LR, {R0-R14}^ }; /* Restore all system mode registers for the task. */ \

__asm{ NOP }; \

\

__asm{ LDR LR, [LR, #+60] }; /* Restore the return address. */ \

\

/* And return - correcting the offset in the LR to obtain ... */ \

__asm{ SUBS PC, LR, #4 }; /* ... the correct address. */ \

}

Где то здесь все и встает :(

Share this post


Link to post
Share on other sites
Решил подправить пример freertos на lpc2129 под кейл-ом на сабжевый чип.

Втставил в родной startup.s часть касаюшуюся настроек тактирования, успешно пересобрал.

Запускаю дебагер, дебагер впадает в вечный цикл с ошибкой выбора инструкции по адресу 0xC ?!

Причем в оригинале, как полагается, после сброса в PC грузится 0х40.

Так поди ж, в том же дебагере при этом можно поглядеть регистры.

Например r14_abt, и локализовать место.

Можно тут почитать.

Share this post


Link to post
Share on other sites

Похоже что то с вычислением адреса возврата в portRESTORE_CONTEXT() макросе, если закоментарить последнюю строчку (__asm{ SUBS PC, LR, #4 }), то он завершается без зависонов.

Share this post


Link to post
Share on other sites

Похоже что собака зарылась в настройках контроллера прерываний.

Для начала я во freertos-ном обработчике прерывания вставил дрыгание IO пина, увидеть который так и не смог.

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

Дальше пошли варианты ... екперименты ... безрезультатно, обрабочики прерываний не вызываются (пробовал еще I2C).

Функции инициализации VIC и инсталляции обработчиков перетащил из своих рабочих примеров.

Странно, но в самой rtos я не нашел инициализации VIC.

Share this post


Link to post
Share on other sites

Блин, уперся обеими рогами.

Никак немогу заставить работать прерывания.

Все облазил, даже доку прочитал :), не помогло.

Гляньте плиз на стартап, может что заметите.

В main-е после инициализации железа ставлю вечный цикл.

// *** Startup Code (executed after Reset) ***
// Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
        Mode_USR  EQU      0x10
        Mode_FIQ  EQU      0x11
        Mode_IRQ  EQU      0x12
        Mode_SVC  EQU      0x13
        Mode_ABT  EQU      0x17
        Mode_UND  EQU      0x1B
        Mode_SYS  EQU      0x1F
        I_Bit     EQU      0x80    /* when I bit is set, IRQ is disabled */
        F_Bit     EQU      0x40    /* when F bit is set, FIQ is disabled */
/*
// <h> Stack Configuration (Stack Sizes in Bytes)
//   <o0> Undefined Mode      <0x0-0xFFFFFFFF>
//   <o1> Supervisor Mode     <0x0-0xFFFFFFFF>
//   <o2> Abort Mode          <0x0-0xFFFFFFFF>
//   <o3> Fast Interrupt Mode <0x0-0xFFFFFFFF>
//   <o4> Interrupt Mode      <0x0-0xFFFFFFFF>
//   <o5> User/System Mode    <0x0-0xFFFFFFFF>
// </h>
*/
        UND_Stack_Size  EQU     0x00000008
        SVC_Stack_Size  EQU     0x00000100;
        ABT_Stack_Size  EQU     0x00000008
        FIQ_Stack_Size  EQU     0x00000100
        IRQ_Stack_Size  EQU     0x00000300
        USR_Stack_Size  EQU     0x00000200
AREA   STACK, DATA, READWRITE, ALIGN=2
        DS   (USR_Stack_Size+3)&~3 ; Stack for User/System Mode 
        DS   (IRQ_Stack_Size+3)&~3 ; Stack for Interrupt Mode
        DS   (FIQ_Stack_Size+3)&~3 ; Stack for Fast Interrupt Mode 
        DS   (ABT_Stack_Size+3)&~3 ; Stack for Abort Mode
        DS   (SVC_Stack_Size+3)&~3 ; Stack for Supervisor Mode
        DS   (UND_Stack_Size+3)&~3 ; Stack for Undefined Mode
Top_Stack:
// Starupt Code must be linked first at Address at which it expects to run.
AREA   STARTUPCODE, CODE, AT CODE_BASE   // READONLY, ALIGN=4
       PUBLIC  __startup
       EXTERN  CODE32 (?C?INIT)
__startup       PROC    CODE32
// Pre-defined interrupt handlers that may be directly 
// overwritten by C interrupt functions
EXTERN CODE32 (Undef_Handler?A)
EXTERN CODE32 (vPortYieldProcessor?A)
EXTERN CODE32 (PAbt_Handler?A)
EXTERN CODE32 (DAbt_Handler?A)
EXTERN CODE32 (IRQ_Handler?A)
EXTERN CODE32 (FIQ_Handler?A)
// Exception Vectors
// Mapped to Address 0.
// Absolute addressing mode must be used.
Vectors:        LDR     PC,Reset_Addr         
                LDR     PC,Undef_Addr
                LDR     PC,SWI_Addr
                LDR     PC,PAbt_Addr
                LDR     PC,DAbt_Addr
;                NOP                            /* Reserved Vector */
                DD      0xB9205F80
;               LDR     PC,IRQ_Addr
;                LDR     PC,[PC, #-0x0FF0]      /* Vector from VicVectAddr */
                LDR     PC,[PC, #-0x0120]      /* Vector from VicVectAddr */
                LDR     PC,FIQ_Addr
Reset_Addr:     DD      Reset_Handler
Undef_Addr:     DD      Undef_Handler?A
SWI_Addr:       DD      vPortYieldProcessor?A
PAbt_Addr:      DD      PAbt_Handler?A
DAbt_Addr:      DD      DAbt_Handler?A
                DD      0xB9205F80                      /* Reserved Address */
IRQ_Addr:       DD      IRQ_Handler?A
FIQ_Addr:       DD      FIQ_Handler?A

Reset_Handler:  
// Setup Stack for each mode
                LDR     R0, =Top_Stack
// Enter Undefined Instruction Mode and set its Stack Pointer
                MSR     CPSR_c, #Mode_UND|I_Bit|F_Bit
                MOV     SP, R0
                SUB     R0, R0, #UND_Stack_Size
// Enter Abort Mode and set its Stack Pointer
                MSR     CPSR_c, #Mode_ABT|I_Bit|F_Bit
                MOV     SP, R0
                SUB     R0, R0, #ABT_Stack_Size
// Enter FIQ Mode and set its Stack Pointer
                MSR     CPSR_c, #Mode_FIQ|I_Bit|F_Bit
                MOV     SP, R0
                SUB     R0, R0, #FIQ_Stack_Size
// Enter IRQ Mode and set its Stack Pointer
                MSR     CPSR_c, #Mode_IRQ|I_Bit|F_Bit
                MOV     SP, R0
                SUB     R0, R0, #IRQ_Stack_Size
// Enter Supervisor Mode and set its Stack Pointer
                MSR     CPSR_c, #Mode_SVC|I_Bit|F_Bit
                MOV     SP, R0
                SUB     R0, R0, #SVC_Stack_Size
// Enter S Mode and set its Stack Pointer
                MSR     CPSR_c, #Mode_SYS
                MOV     SP, R0
// Start in supervisor mode
                MSR     CPSR_c, #Mode_SVC|I_Bit|F_Bit
// Enter the C code
                LDR     R0,=?C?INIT
                TST     R0,#1      ; Bit-0 set: INIT is Thumb
                LDREQ   LR,=exit?A ; ARM Mode
                LDRNE   LR,=exit?T ; Thumb Mode
                BX      R0
                ENDP
PUBLIC exit?A
exit?A          PROC    CODE32
                B       exit?A
                ENDP
PUBLIC exit?T
exit?T          PROC    CODE16
exit:           B       exit?T
                ENDP
                END

 

А-а-а вот она зараза-а ...

Пока стартап форматировал обратил внимание на I_Bit, и то что он устанавливается во всех режимах, как думаете насколько корректно убрать его из юзерского режима?

Share this post


Link to post
Share on other sites
Пока стартап форматировал обратил внимание на I_Bit, и то что он устанавливается во всех режимах, как думаете насколько корректно убрать его из юзерского режима?
Подумайте сами логично - Reset_Handler выполняется при старте процессора. Если вы уберете I_Bit, вы тем самым разрешите прерывания IRQ. То, что разрешение прерываний происходит до настройки VIC может и не приведет ни к чему плохому, но я бы не рискнул. Но кроме этого в обработчиках прерываний могут вызываться сервисы ОС, а в этот момент ОС еще не проинициализирована. Вот тут точно ничего хорошего не получится.

если закоментарить последнюю строчку (__asm{ SUBS PC, LR, #4 }), то он завершается без зависонов.
Вообще-то это ARMовский аналог reti. Интересно, если оно не висло, то куда же его уносило?

Share this post


Link to post
Share on other sites

Пока стартап форматировал обратил внимание на I_Bit, и то что он устанавливается во всех режимах, как думаете насколько корректно убрать его из юзерского режима?

Подумайте сами логично - Reset_Handler выполняется при старте процессора. Если вы уберете I_Bit, вы тем самым разрешите прерывания IRQ. То, что разрешение прерываний происходит до настройки VIC может и не приведет ни к чему плохому, но я бы не рискнул. Но кроме этого в обработчиках прерываний могут вызываться сервисы ОС, а в этот момент ОС еще не проинициализирована. Вот тут точно ничего хорошего не получится.

если закоментарить последнюю строчку (__asm{ SUBS PC, LR, #4 }), то он завершается без зависонов.
Вообще-то это ARMовский аналог reti. Интересно, если оно не висло, то куда же его уносило?

позволю себе поделиться опытом, не уверен, правда, что это тот случай, к тому же, по причине не очень хорошего владения армовским ассемблером, в деталях ситуации мне разобраться не удалось. и тем не менее - когда я занимался запуском FreeRTOS на STR710, параллельно начиная изучать АРМы, у меня возникала ситуация, подобная описанной. правда, зависание происходило во время засгрузки стартапа, до входа в main() - во всяком случае, в отладчике я туда не попадал. поскльку я на тот момент вообще никак не разбирался в процессоре, пошел наиболее легким путем, а именно, попытался адаптировать готовый проект (из примеров к FreeRTOS). как выяснилось, если заменить 71x_init.s и 71x_vect.s из комплекта ИАР на cstartup.s79 и vect.s79 из примера, после некоторой адаптации система начинает стартовать нормально. собственно, на тот момент я этим и ограничился. а недавно, когда взялся делать bootload для своего проекта, попутно пришлось более детально разбираться в алгоритме запуска АРМ. в частности, мне пришлось снова вернуться к упомянутым ассемблерным файлам - ибо после пуска процесора бутлоадер работал нормально, но после перехода на точку запуска программы снова возникла упомянутая ситуация. я поступил просто - перекинул в проект бутлоадера проверенные стартап-файлы. и все опять стало нормально. ну естественно, разобрало меня любопытство - и вот что я обнаружил при сравнении кода: в 71x_init.s по окончании инициализации проект переводится в режим пользователя

      MSR     CPSR_c, #Mode_USR ; Change to User mode, Enable IRQ and FIQ
       LDR     SP, =SFE(CSTACK) & 0xFFFFFFF8    ; Initialize USR stack pointer

в то время, как в моем cstartup.s79 - в режим супервизора

      /* We want to start in supervisor mode.  Operation will switch to system
      mode when the first task starts. */
     msr   CPSR_c, #Mode_SVC|I_Bit|F_Bit

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

Share this post


Link to post
Share on other sites

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

Все кастрации инициализации VIC я вернул на место, всвязи с чем возникает вопрос, а где тогда правильнее инициализировать железо работающее на прерываниях?

Share this post


Link to post
Share on other sites
Вроде сдвинулся с мертвой точки, оказалось все дело в объявлении вектора обработчика прерывания для таймера, сейчас вроде работает.

Все кастрации инициализации VIC я вернул на место, всвязи с чем возникает вопрос, а где тогда правильнее инициализировать железо работающее на прерываниях?

на мой вкус, по-хорошему, все надо делать после входа в main(). и инициализировать железо, и разрешать прерывания. дело стартапа - инициализация памяти

Share this post


Link to post
Share on other sites

а вот у freertos другие вкусы ...

да ладно ... думаю после старта какой-нибудь из задач наверное точно можно VIC-жаждущее железо инить.

Share this post


Link to post
Share on other sites
а вот у freertos другие вкусы ...

да ладно ... думаю после старта какой-нибудь из задач наверное точно можно VIC-жаждущее железо инить.

ну я ваще-то все иничу перед стартом многозадачности, после входа в main(). вроде никаких проблем. так что насчет вкусов FreeRTOS я немного недопонял. а вот зависание, по-моему, происходит из-за разрешения прерывания до инициализации системы - у меня это было так, во всяком случае

Edited by sergik_vrn

Share this post


Link to post
Share on other sites

Прерывания разрешаются, насколько я проникся, после инита всей системы. Например, имею I2C LCD, обмен которого осуществляется через прерывания, соответсвенно на ините этого LCD (если его вначале main включать) все и встанет.

Share this post


Link to post
Share on other sites
Прерывания разрешаются, насколько я проникся, после инита всей системы. Например, имею I2C LCD, обмен которого осуществляется через прерывания, соответсвенно на ините этого LCD (если его вначале main включать) все и встанет.

а, ну это разумеется, да. что, кстати, неудобно - приходится инициализацию делать уже в многозадачном режиме, то есть через задницу

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this