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

Понятно. Свой порт под IAR для M0+?

 

Давайте теперь по ходу процесса. Скриншот 1. - Это же выход из прерывания RTC_Second_Handler()? Если так, то перепланировка ещё не произошла, а только запланирована (взведён флаг прерывания PendSV). Так что никакой порчи регистров в этом месте ещё нет.

После выхода из прерывания вы попадаете в sched(), который как раз и должен дождаться срабатывания прерывания PendSV и собственно перепланировки.

А этого как раз в вашем расследовании и не видно.

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


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

Да, не видно. То, что удалось словить, - это уже следствие. Ближе я пока что не подобрался. Поэтому и спрашиваю многоуважаемое сообщество, как можно заглянуть поглубже.

Банальная точка останова на коде, который вызывается из множества мест, не поможет.

Городить средства профилировки? Сложно и можно испортить что-то ещё, появятся артефакты, с которыми тоже придётся повоевать.

 

Может, у кого есть уже опробованное средство, а?

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


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

Простите, не понял сразу.

 

PendSV_Handler

#if defined __ARM_ARCH_6M__   // Cortex-M0(+)/Cortex-M1
       CPSID   I                   // Prevent interruption during context switch
       MRS     R0, PSP             // Load process stack pointer to R0
       SUBS    R0, R0, #32         // Adjust R0 to point to top of saved context in stack
       MOV     R1, R0              // Preserve R0 (needed for os_context_switch_hook() call)
       STMIA   R1!, {R4-R7}        // Save low portion of remaining registers (r4-7) on process stack
       MOV     R4, R8              // Move high portion of remaining registers (r8-11) to low registers
       MOV     R5, R9
       MOV     R6, R10
       MOV     R7, R11
       STMIA   R1!, {R4-R7}        // Save high portion of remaining registers (r8-11) on process stack

       // At this point, entire context of process has been saved
       PUSH    {LR}               // we must save LR (exc_return value) until exception return
       LDR     R1, =os_context_switch_hook    // call os_context_switch_hook();
       BLX     R1

       // R0 is new process SP;
       ADDS     R0, R0, #16        // Adjust R0 to point to high registers (r8-11)
       LDMIA   R0!, {R4-R7}       // Restore r8-11 from new process stack
       MOV     R8, R4             // Move restored values to high registers (r8-11)
       MOV     R9, R5
       MOV     R10, R6
       MOV     R11, R7
       MSR     PSP, R0            // R0 at this point is new process SP
       SUBS     R0, R0, #32        // Adjust R0 to point to low registers
       LDMIA   R0!, {R4-R7}       // Restore r4-7
       CPSIE   I
       POP     {PC}               // Return to saved exc_return. Exception return will restore remaining context

#else

 

Если есть необходимость, могу загрузить проект. Но Вы под IAR-ом не работаете.

 

Для визуального контроля границ стеков процессов добавил в функцию TBaseProcess::init_stack_frame возможность записи заголовков в формате "ProcXX".

Хорошо видно тогда в дампе памяти дно стека. Если затёрт заголовок полностью - хана, стек закончился!

 

А выглядит это так:

Dump1.jpg

 

или вот так:

Dump2.jpg

 

Код функции:

//------------------------------------------------------------------------------
void TBaseProcess::init_stack_frame( stack_item_t * Stack
                                  , void (*exec)()
                                  #if scmRTOS_DEBUG_ENABLE == 1
                                  , stack_item_t * StackBegin
                                  #endif
                                  )
{
   // ARM Architecture Procedure Call Standard [AAPCS] requires 8-byte stack alignment:
   StackPointer = (stack_item_t*)((uintptr_t)Stack & 0xFFFFFFF8);
   // Prepare Process Stack Frame.
   *(--StackPointer)  = 0x01000000UL;             // xPSR
   *(--StackPointer)  = reinterpret_cast<uint32_t>(exec); // Entry Point
   StackPointer -= 14;                           // emulate "push R14,R12,R3,R2,R1,R0,R11-R4"

#if scmRTOS_DEBUG_ENABLE == 1
   for (stack_item_t* pDst = StackBegin; pDst < StackPointer; ++pDst)
       *pDst = STACK_DEFAULT_PATTERN;
stack_item_t* pDst = StackBegin;
*pDst++ = 0x636f7250;
int a = this->priority()& 0x0000003F;
if (a == prIDLE)
{
  *pDst = 0x454c4449;
  return;
}
#if scmRTOS_PRIORITY_ORDER > 0
a = scmRTOS_PROCESS_COUNT - a;
#endif
int b = 48;
while (a>10)
{
  b++;
  a -= 10;
}
b += (a+48)<<8;
*pDst = b;
#endif // scmRTOS_DEBUG_ENABLE
}

 

Эту фичу можно включить с помощью макроса scmRTOS_DEBUG_ENABLE

 

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


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

С обработчиком порядок, он один-в-один как в порте GCC. Ещё посмотрите приоритеты прерываний. Прерывание PendSV должно иметь минимальный приоритет.

На всякий случай, если есть возможность, попробуйте собрать проект другой версией IAR, или поменять уровень оптимизации.

Больше пока ничего в голову не приходит.

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


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

Вот приоритеты:

//-----------------------------------------------------------------------------
//  EQUATES
//
NVIC_SYSPRI14        EQU     0xE000ED22  // System priority register (priority 14).
NVIC_PENDSV_PRI      EQU           0xFF  // PendSV priority value (lowest).
NVIC_SYSPRI15        EQU     0xE000ED23  // System priority register (priority 15).
NVIC_ST_PRI          EQU           0xFF  // SysTick priority value (lowest).

NVIC_ST_CTRL         EQU    0xE000E010   // SysTick Ctrl & Status Reg.
NVIC_ST_RELOAD       EQU    0xE000E014   // SysTick Reload  Value Reg.
NVIC_ST_CTRL_CLK_SRC EQU    0x00000004   // Clock Source.
NVIC_ST_CTRL_INTEN   EQU    0x00000002   // Interrupt enable.
NVIC_ST_CTRL_ENABLE  EQU    0x00000001   // Counter mode.

 

Присваивание приоритетов:

//-----------------------------------------------------------------------------
// Perform systick timer initialization.
//
init_system_timer
   LDR     R1, =NVIC_SYSPRI15      // Set the SysTick exception priority (lowest)
   LDR     R2, =NVIC_ST_PRI
   STRB    R2, [R1]

   LDR     R1, =NVIC_ST_RELOAD     // Setup SysTick
   LDR     R2, =(SYSTICKFREQ/SYSTICKINTRATE-1)
   STR     R2, [R1]
   LDR     R1, =NVIC_ST_CTRL       // Enable and run SysTick
   LDR     R2, =(NVIC_ST_CTRL_CLK_SRC | NVIC_ST_CTRL_INTEN | NVIC_ST_CTRL_ENABLE)
   STR     R2, [R1]
   BX      LR

//-----------------------------------------------------------------------------
//      START MULTITASKING
//      void os_start(stack_item_t* sp)
//
// Note(s) : 1) os_start() MUST:
//              a) Setup PendSVexception priority to lowest;
//              B) Setup system timer (exception priority and reload value);
//              c) Enable interrupts (tasks will run with interrupts enabled).
//              d) Jump to exec() function of the highest priority process.
//
os_start
   LDR     R1, =NVIC_SYSPRI14      // Set the PendSV exception priority (lowest)
   LDR     R2, =NVIC_PENDSV_PRI
   STRB    R2, [R1]

#ifdef __SOFTFP__
   LDR     R4, [R0, #(4 * 14)]		// Load process entry point into R3
   ADDS     R0, R0, #(4 * 16)       // emulate context restore
#else
   LDR     R4, [R0, #(4 * 15)]
   ADDS     R0, R0, #(4 * 16)
#endif

   MSR     PSP, R0                 // store process SP to PSP
   MOVS     R0, #2                  // Switch thread mode stack to PSP
   MSR     CONTROL, R0
   ISB                             // Insert a barrier

#if USE_SYSTICK_TIMER != 0
   LDR R1, =init_system_timer      // Init and run system timer
   BLX R1
#endif

   CPSIE   I                       // Enable interrupts at processor level

   BX      R4                      // Jump to process exec() function

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


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

Ага, вот оно! В M0 нет побайтового доступа к регистру приоритета SHPR3. Нужно назначать приоритет при помощи операций со словом.

Например, вот так.

Поправьте назначения приоритетов для PendSV и для SysTick, и всё должно заработать.

 

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


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

Только сегодня добрался до проекта. Работа, однако!

 

Итак, дело действительно было в приоритетах и только в приоритетах.

Я их поправил и всё заиграло!

И вот что я сделал по-быстрому:

1. Назначил константы регистров и констант приоритетов:

#if defined __ARM_ARCH_6M__   // Cortex-M0(+)/Cortex-M1
NVIC_SYSPRI14        EQU     0xE000ED20  // System priority register (priority 12..15).
NVIC_PENDSV_PRI      EQU     0x00C00000  // PendSV priority value (lowest)
NVIC_SYSPRI15        EQU     0xE000ED20  // System priority register (priority 12..15).
NVIC_ST_PRI          EQU     0xC0000000  // SysTick priority value (lowest)
#else
NVIC_SYSPRI14        EQU     0xE000ED22  // System priority register (priority 14).
NVIC_PENDSV_PRI      EQU           0xFF  // PendSV priority value (lowest).
NVIC_SYSPRI15        EQU     0xE000ED23  // System priority register (priority 15).
NVIC_ST_PRI          EQU           0xFF  // SysTick priority value (lowest).
#endif

NVIC_ST_CTRL         EQU    0xE000E010   // SysTick Ctrl & Status Reg.
NVIC_ST_RELOAD       EQU    0xE000E014   // SysTick Reload  Value Reg.
NVIC_ST_CTRL_CLK_SRC EQU    0x00000004   // Clock Source.
NVIC_ST_CTRL_INTEN   EQU    0x00000002   // Interrupt enable.
NVIC_ST_CTRL_ENABLE  EQU    0x00000001   // Counter mode.

 

2. Поправил загрузку приоритета PendSV в os_start:

os_start
#if defined __ARM_ARCH_6M__   // Cortex-M0(+)/Cortex-M1
   LDR     R1, =NVIC_SYSPRI14      // Set the SysTick exception priority (lowest)
   LDR     R2, =NVIC_PENDSV_PRI
   LDR     R3, [R1]
ADD     R2, R3
   STR     R2, [R1]
#else
   LDR     R1, =NVIC_SYSPRI14      // Set the PendSV exception priority (lowest)
   LDR     R2, =NVIC_PENDSV_PRI
   STRB    R2, [R1]
#endif

 

3. Поправил загрузку приоритета SysTick в init_system_timer:

init_system_timer
#if defined __ARM_ARCH_6M__   // Cortex-M0(+)/Cortex-M1
   LDR     R1, =NVIC_SYSPRI15      // Set the SysTick exception priority (lowest)
   LDR     R2, =NVIC_ST_PRI
   LDR     R3, [R1]
ADD     R2, R3
   STR    R2, [R1]
#else
   LDR     R1, =NVIC_SYSPRI15      // Set the SysTick exception priority (lowest)
   LDR     R2, =NVIC_ST_PRI
   STRB    R2, [R1]
#endif

 

Всем спасибо!

 

PS Хотел сделать по-красивому, как для mx-gcc, но не пошла строчка:

 

        "    LDR     R1, =os_context_switch_hook  \n"   // call os_context_switch_hook();

 

Как сделать видимой для IAR-овского встроенного ассемблера адрес функции из другого модуля?

 

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


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

Как сделать видимой для IAR-овского встроенного ассемблера адрес функции из другого модуля?

 

    EXTERN  os_context_switch_hook

По крайней мере, в порте для M3 так.

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


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

    EXTERN  os_context_switch_hook

По крайней мере, в порте для M3 так.

Это определение для файла "*.s", т.е. чисто ассемблерное.

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


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

Как сделать видимой для IAR-овского встроенного ассемблера адрес функции из другого модуля?

Или я не понял вопрос, или Вам нужен EXTERN.

Как оно работает, можно подсмотреть в любом другом ассемблерном модуле (например, в штатном стартапе).

 

UPD. Перечитал ещё раз. Да, вопрос я не понял. Тут инлайн ассемблер (с какими-то своими правилами). Извиняюсь...

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


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

Удалось-таки победить. Вот что вышло:

 

Это обработчик прерывания для среды IAR:

extern "C" void PendSV_Handler()
{
#if (defined __ARM_ARCH_6M__)   // Cortex-M0(+)/Cortex-M1
   asm volatile (
       "    CPSID   I                 \n"  // Prevent interruption during context switch
       "    MRS     R0, PSP           \n"  // Load process stack pointer to R0
       "    SUBS    R0, R0, #32       \n"  // Adjust R0 to point to top of saved context in stack
       "    MOV     R1, R0            \n"  // Preserve R0 
       "    MOV     R2, R0            \n"  // Preserve R0 (needed for os_context_switch_hook() call)
       "    STMIA   R1!, {R4-R7}      \n"  // Save low portion of remaining registers (r4-7) on process stack
       "    MOV     R4, R8            \n"  // Move high portion of remaining registers (r8-11) to low registers
       "    MOV     R5, R9            \n"
       "    MOV     R6, R10           \n"
       "    MOV     R7, R11           \n"
       "    STMIA   R1!, {R4-R7}      \n"  // Save high portion of remaining registers (r8-11) on process stack
	: :
	);
   asm volatile (
       // At this point, entire context of process has been saved
       "    PUSH    {LR}              \n" // we must save LR (exc_return value) until exception return
       "    MOV     R1, %0  \n"   // load os_context_switch_hook() address;
       "    MOV     R0, R2            \n"  // Restore R0 (needed for os_context_switch_hook() call)
       "    BLX     R1                \n"  // call os_context_switch_hook();
       // R0 is new process SP;
       "    ADDS    R0, R0, #16       \n" // Adjust R0 to point to high registers (r8-11)
       "    LDMIA   R0!, {R4-R7}      \n" // Restore r8-11 from new process stack
       "    MOV     R8, R4            \n" // Move restored values to high registers (r8-11)
       "    MOV     R9, R5            \n"
       "    MOV     R10, R6           \n"
       "    MOV     R11, R7           \n"
       "    MSR     PSP, R0           \n" // R0 at this point is new process SP
       "    SUBs    R0, R0, #32       \n" // Adjust R0 to point to low registers
       "    LDMIA   R0!, {R4-R7}      \n" // Restore r4-7
       "    CPSIE   I                 \n"
       "    POP     {PC}              \n" // Return to saved exc_return. Exception return will restore remaining context
		: : "r" (os_context_switch_hook)
   );
#else  // #if (defined __ARM_ARCH_6M__)

#if (defined __SOFTFP__)
   // M3/M4 cores without FPU
   asm volatile (
       "    CPSID   I                 \n" // Prevent interruption during context switch
       "    MRS     R0, PSP           \n" // PSP is process stack pointer
       "    STMDB   R0!, {R4-R11}     \n" // Save remaining regs r4-11 on process stack

       // At this point, entire context of process has been saved
       "    PUSH    {LR}              \n" // we must save LR (exc_return value) until exception return
       "    LDR     R1, =os_context_switch_hook  \n"   // call os_context_switch_hook();
       "    BLX     R1                \n"

       // R0 is new process SP;
       "    LDMIA   R0!, {R4-R11}     \n" // Restore r4-11 from new process stack
       "    MSR     PSP, R0           \n" // Load PSP with new process SP
       "    CPSIE   I                 \n"
       "    POP     {PC}              \n" // Return to saved exc_return. Exception return will restore remaining context
       : :
   );

#else // #if (defined __SOFTFP__)
   // Core with FPU (cortex-M4F)
   asm volatile (
       "    CPSID     I                 \n" // Prevent interruption during context switch
       "    MRS       R0, PSP           \n" // PSP is process stack pointer
       "    TST       LR, #0x10         \n" // exc_return[4]=0? (it means that current process
       "    IT        EQ                \n" // has active floating point context)
       "    VSTMDBEQ  R0!, {S16-S31}    \n" // if so - save it.
       "    STMDB     R0!, {R4-R11, LR} \n" // save remaining regs r4-11 and LR on process stack

       // At this point, entire context of process has been saved
       "    LDR     R1, =os_context_switch_hook  \n"   // call os_context_switch_hook();
       "    BLX     R1                \n"

       // R0 is new process SP;
       "    LDMIA     R0!, {R4-R11, LR} \n" // Restore r4-11 and LR from new process stack
       "    TST       LR, #0x10         \n" // exc_return[4]=0? (it means that new process
       "    IT        EQ                \n" // has active floating point context)
       "    VLDMIAEQ  R0!, {S16-S31}    \n" // if so - restore it.
       "    MSR       PSP, R0           \n" // Load PSP with new process SP
       "    CPSIE     I                 \n"
       "    BX        LR                \n" // Return to saved exc_return. Exception return will restore remaining context
       : :
   );
#endif  // #if (defined __SOFTFP__)
#endif  // #if (defined __ARM_ARCH_6M__)
}

 

А это функция старта оси, также для среды IAR:

extern "C" NORETURN void os_start(stack_item_t *sp)
{
   // Set PendSV lowest priority value
#if (defined SHP3_WORD_ACCESS)
   SHPR3 |= (0xFF << 16);
#else
   PendSvPriority = 0xFF;
#endif

#if (!defined __SOFTFP__)
   FPCCR |= ASPEN | LSPEN;
#endif

   asm volatile (
#if (defined __SOFTFP__)  // code without FPU
       "    LDR     R4, [%[stack], #(4 * 14)] \n" // Load process entry point into R4
       "    ADDS    %[stack], #(4 * 16)       \n" // emulate context restore
#else
       "    LDR     R4, [%[stack], #(4 * 15)] \n" // Load process entry point into R4
       "    ADD     %[stack], #(4 * 17)       \n" // emulate context restore
#endif
       "    MSR     PSP, %[stack]             \n" // store process SP to PSP
       "    MOVS    R0, #2                    \n" // set up the current (thread) mode: use PSP as stack pointer, privileged level
       "    MSR     CONTROL, R0               \n"
       "    ISB                               \n" // Insert a barrier
       : [stack]"+r" (sp)  // output
   );
   asm volatile (
       "    MOV     R1, %0                \n" // Init and run system timer
       "    BLX     R1                        \n" //
       "    CPSIE   I                         \n" // Enable interrupts at processor level
       "    BX      R4                        \n" // Jump to process exec() function
		: :"r" (__init_system_timer)  // output
   );
}

 

В результате я перенёс некоторые функции, приведя в соответствие с версией для GCC и избавился от файла os_target_asm.s

 

 

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


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

Удалось-таки победить. Вот что вышло:

 

<...>

 

В результате я перенёс некоторые функции, приведя в соответствие с версией для GCC и избавился от файла os_target_asm.s

Я правильно понимаю, что вы сделали универсальный порт Cortex-M под IAR? Если так, то не желаете ли эту наработку включить в основной репозиторий?

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


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

Можно. Я отладил код под Freescale M0+. Подчистить исходники по комментариям и отступам - и вперёд! Куда сбрасывать и как?

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


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

Можно. Я отладил код под Freescale M0+. Подчистить исходники по комментариям и отступам - и вперёд! Куда сбрасывать и как?

Два варианта.

 

Первый (предпочтительный). Пререквизиты (что требуется от вас):

 

1. Какое-то умение работать с git.

2. Аккаунт на гитхабе.

3. Желание/готовность участвовать в проекте - сопровождать этот порт и не только. :)

 

В этом случае получаете доступ к репозиторию на гитхабе (включаем вас в команду), далее в соответствии с этим документом вносите свои правки и фиксируете. Я не знаю, насколько вам близок git, но если будут возникать затруднения, мы (с Антоном) всегда готовы помочь.

 

Второй (простой). Если по какой-то причине первый вариант не подходит, то можете выложить архив с портом (и желательно примерами) где вам удобно (например, яндекс диск или любой другой файлообменник). Дальше мы сами добавим порт в репозиторий.

 

Ваш выбор. :)

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


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

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

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

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

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

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

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

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

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

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