jcxz 350 March 4, 2025 Posted March 4, 2025 · Report post Перенося свою РТОС на Cortex-M7, столкнулся с неожиданным эффектом: Когда из функции ОС требуется активировать PendSV, то для этого выполняется запись лог."1" в ICSR.PENDSVSET. Почти сразу после этого в одном участке кода (одна из функций РТОС) делается запрет прерывания. Выглядит участок кода так: MOV R0, #1 << 28 STR R0, [R1, ICSR] DSB ISB BX LR CPSID I точнее - это не участок кода, а последовательность команд выполняемая после STR в ICSR и до запрета прерываний. (исходно прерывания разрешены; CPU - в Thread Mode; активен PSP; активен MPU и кеши данных/кода, но регион регистров периферии CPU (адреса 0xE0000000) - выключена из кеширования; код выполняется из ОЗУ - из DTCM RAM). Важно, чтобы ISR PendSV успел активироваться до CPSID I. По условию алгоритма. Иначе нарушается работа кода. До Cortex-M7 в этом коде не было команд DSB, ISB и тем не менее - проблем на Cortex-M3/M4 не наблюдал. На разных МК на разных частотах и при выполнении из памяти разного рода со включёнными кешами. Эти 2 команды я добавил только сейчас. Причём насколько помню - в uCOS-II точно также активировалось раньше PendSV - без DSB,ISB. Получается - на Cortex-M7 уже PendSV не активирует мгновенно PendSV при записи лог."1" в ICSR.PENDSVSET? И достаточно ли такой последовательности (DSB, ISB) чтобы PendSV гарантированно успело активироваться до CPSID I? Или нужно что-то ещё? В errata на ядро Cortex-M7 ничего не нашёл по этому поводу. Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 320 March 4, 2025 Posted March 4, 2025 · Report post ICSR это же SCS-область? Интереса ради: а Вы проверили, что без этих инструкций прерывание активируется позже? И кстати, не понял, как там затесалась BX LR? Quote Share this post Link to post Share on other sites More sharing options...
jcxz 350 March 4, 2025 Posted March 4, 2025 · Report post 31 минуту назад, Arlleex сказал: ICSR это же SCS-область? да 31 минуту назад, Arlleex сказал: Интереса ради: а Вы проверили, что без этих инструкций прерывание активируется позже? Оно аквтивируется после уже последующего разрешения прерываний. Что слишком поздно. Должно - ДО запрета прерываний. 31 минуту назад, Arlleex сказал: И кстати, не понял, как там затесалась BX LR? Инструкция записи в ICSR - внутри функции. Сразу после неё - выход из функции (BX LR), и сразу после выхода - CPSID I. PS: До сих пор воспринимал запись в ICSR.PENDSVSET как аналог синхронной инструкции вызова прерывания сразу после STR. При условии разрешённости прерываний и достаточном уровне приоритета. Типа - как будто там вставляется SVC, только активирующая PendSV. Получается - для Cortex-M7 это не так. Интересно - может на каких-то других Cortex-M (M3/M4) тоже возможна задержка активации PendSV? Хотя я никогда не сталкивался с таким ранее. Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 320 March 5, 2025 Posted March 5, 2025 · Report post Для семейства Cortex-M (всего) на момент, когда Cortex-M7 еще не изобрели, достаточно было DSB + ISB. Когда появился Cortex-M7, редакцию документа по барьерам памяти не изменяли и новых не выпускали, соответственно, все осталось как есть. P.S. В общем-то, и для Cortex-M3/4 в описанном случае DSB + ISB должны быть. 8 часов назад, jcxz сказал: PS: До сих пор воспринимал запись в ICSR.PENDSVSET как аналог синхронной инструкции вызова прерывания сразу после STR. Нет, PendSV никогда как аналог синхронного исключения не позиционировалась. Для синхронного только SVC. Quote Share this post Link to post Share on other sites More sharing options...
jcxz 350 March 5, 2025 Posted March 5, 2025 · Report post 31 минуту назад, Arlleex сказал: Для семейства Cortex-M (всего) на момент, когда Cortex-M7 еще не изобрели, достаточно было DSB + ISB. Откуда тапки данные? Открыл исходники uC/OS-II V2.92.13 порт ARMv7-M от 2017г (это последняя которую я когда то пользовал). В шапке указано: Цитата For : ARMv7M Cortex-M Mode : Thumb-2 ISA Toolchain : IAR EWARM То же самое в uC/OS-III v3.06.02 от 2017г. Смотрю реализацию активации переключателя контекста (PendSV): ;******************************************************************************************************** ; PERFORM A CONTEXT SWITCH (From task level) - OSCtxSw() ; ; Note(s) : 1) OSCtxSw() is called when OS wants to perform a task context switch. This function ; triggers the PendSV exception which is where the real work is done. ;******************************************************************************************************** OSCtxSw LDR R0, =NVIC_INT_CTRL ; Trigger the PendSV exception (causes context switch) LDR R1, =NVIC_PENDSVSET STR R1, [R0] BX LR Никаких DSB, ISB вообще не наблюдаю! О чём выше и писал. Код точно такой же, как был у меня до вчерашнего дня (до добавления вчера DSB, ISB). Единственное отличие от моего кода, которое я нахожу у uCOS - это то, что OSCtxSw() всегда вызывается при запрещённых прерываниях. Но всегда - непосредственно перед их разрешением. Т.е. - последовательность команд при активации ICSR.PENDSVSET там получается чуть длиннее: ... STR Rx, [Ry] ;запись лог."1" в ICSR.PENDSVSET BX LR ;конец ассемблерной OSCtxSw() MSR PRIMASK, Rz ;это OS_EXIT_CRITICAL() в конце си-шной OS_Sched(void) BX LR ;это выход из OS_Sched(void); но этой команды может и не быть, если OS_Sched() заинлайнится MRS Rz, PRIMASK ;OS_ENTER_CRITICAL(); CPSID I ;OS_ENTER_CRITICAL(); ... Но ни одной барьерной инструкции нет! И это последовательность команд, выполняемая для запуска любого переключения контекста ОС. Она активируется при любом вытеснении задачи: мэйлбоксом, семафором, мьютексом или даже обычным вызовом функции паузы OSTimeDly(INT32U ticks). Но это раньше нормально работало на Cortex-M3/M4! И перестало только на Cortex-M7. Единственный барьер, который нахожу в недрах uCOS - это внутри функции принудительного вызова шедулера OSSched(). В её конце: #define OS_TASK_SW_SYNC() __ISB() void OSSched(void) { ... #ifdef OS_TASK_SW_SYNC OS_TASK_SW_SYNC(); #endif } Причём OS_TASK_SW_SYNC - undefined и никаких комментариев о ней. 31 минуту назад, Arlleex сказал: Когда появился Cortex-M7, редакцию документа по барьерам памяти не изменяли и новых не выпускали, соответственно, все осталось как есть. Получается - во всех uCOS ошибка? И все они могут не работать корректно на Cortex-M7? Если только те 3-4 команды до CPSID I: ... STR Rx, [Ry] ;запись лог."1" в ICSR.PENDSVSET BX LR ;конец ассемблерной OSCtxSw() MSR PRIMASK, Rz ;это OS_EXIT_CRITICAL() в конце си-шной OS_Sched(void) BX LR ;это выход из OS_Sched(void); но этой команды может и не быть, если OS_Sched() заинлайнится MRS Rz, PRIMASK ;OS_ENTER_CRITICAL(); CPSID I ;OS_ENTER_CRITICAL(); ... не являются эквивалентом DSB, ISB. 31 минуту назад, Arlleex сказал: P.S. В общем-то, и для Cortex-M3/4 в описанном случае DSB + ISB должны быть. В uCOS-II v2.92.13 и в uCOS-III v3.06.02 - нет. Вообще на весь код там имеется одна единственная команда ISB в одном месте (указанном выше). И ни одной DSB по всему коду вообще нет. Может в других РТОС есть? Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 320 March 5, 2025 Posted March 5, 2025 · Report post 51 минуту назад, jcxz сказал: То же самое в uC/OS-III v3.06.02 от 2017г. Смотрю реализацию активации переключателя контекста (PendSV): Никаких DSB, ISB вообще не наблюдаю! О чём выше и писал. Код точно такой же, как был у меня до вчерашнего дня (до добавления вчера DSB, ISB). Значит разработчики uC/OS не читают мануалов. У ARM есть документ: ARM Cortex-M AN321. Там как раз описываются эффекты барьерных инструкций с точки зрения архитектуры и реализации конкретных ядер (M0, M0+, M3, M4). И там написано, что если после включения (по сути и активации) прерывания юзер ожидает, что первые несколько инструкций увидят эффект прерывания (т.е. нужно, чтобы возникло прерывание, а лишь затем исполнялись дальнейшие инструкции), то нужно вставить намеренно DSB + ISB. DSB гарантируется реализацией, поэтому достаточно лишь одной ISB. Загляните, например, в реализацию __NVIC_DisableIRQ() для Cortex-M3/4, и для Cortex-M7, они одинаковы и следуют требованиям мануала: __STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) { if ((int32_t)(IRQn) >= 0) { NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); __DSB(); __ISB(); } } Цитата Получается - во всех uCOS ошибка? Да. Но только в том случае, если они тоже завязываются на логику, что прерывание должно возникнуть до определенного потока инструкций. Приведу кусок кода, используемый для формирования PendSV во FreeRTOS #define portYIELD() \ { \ /* Set a PendSV to request a context switch. */ \ portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \ \ /* Barriers are normally not required but do ensure the code is completely \ * within the specified behaviour for the architecture. */ \ __dsb( portSY_FULL_READ_WRITE ); \ __isb( portSY_FULL_READ_WRITE ); \ } ISB можно не использовать, если предполагается, что установка PendSV будет осуществляться из прерывания, т.к. прерывание неявно имеет эффект инструкции ISB. Quote Share this post Link to post Share on other sites More sharing options...
jcxz 350 March 5, 2025 Posted March 5, 2025 · Report post 3 часа назад, Arlleex сказал: Да. Но только в том случае, если они тоже завязываются на логику, что прерывание должно возникнуть до определенного потока инструкций. Там так и есть. Вызовы OSCtxSw() выполняются в тех случаях, когда необходимо вытеснение задачи. Например: Вызов функции захвата семафора SEM. Семафор оказался занят. В первой части функции захвата будет критическая секция, которая внутренние переменные задачи и некоторые переменные ядра РТОС подготавливает к вытеснению задачи (удаляет её из карты активных задач РТОС, переменные TCB (task control block) устаналивает в состояние "ожидание семафора SEM"). Затем - выходит из критической секции и вызывает OSCtxSw() (активирует PendSV). Внутри ISR PendSV должно выполниться собственно само переключение задач (сохранение/восстановление стеков, установка ID активной задачи и указателя на её TCB, и т.д.). Если же двигаться далее по коду функции захвата семафора (как если бы PendSV не случилось), то далее идёт следующая критическая секция. Внутри коей выполняются действия для обратной активации задачи (внесение её в бит-карту активных задач, установка внутренних переменных TCB для активного состояния задачи и т.д.). При штатном выполнении, сюда управление должно попадать уже после новой активации задачи каким-либо сервисом РТОС и нового ISR PendSV. А если первого PendSV не случается, то это место выполняется как будто задача вновь активна (захватила семафор). Что естественно приводит к нарушению логики работы программы. Это описано на примере захвата семафора. Но остальные функции, которые могут перевести задачу в пассивное состояние, построены по тому же принципу. Поэтому - там тоже будет аналогичная проблема. 3 часа назад, Arlleex сказал: Приведу кусок кода, используемый для формирования PendSV во FreeRTOS #define portYIELD() \ { \ /* Set a PendSV to request a context switch. */ \ portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; \ \ /* Barriers are normally not required but do ensure the code is completely \ * within the specified behaviour for the architecture. */ \ __dsb( portSY_FULL_READ_WRITE ); \ __isb( portSY_FULL_READ_WRITE ); \ } Спасибо. Значит во FreeRTOS это предусмотрено. И никаких ключей условной компиляции (для разных ядер Cortex-M) тут нет? DSB, ISB - для всех ядер? 3 часа назад, Arlleex сказал: ISB можно не использовать, если предполагается, что установка PendSV будет осуществляться из прерывания, т.к. прерывание неявно имеет эффект инструкции ISB. В данном случае: функции старта вытеснения задачи - все вызываются с уровня задачи, а не ISR. Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 320 March 5, 2025 Posted March 5, 2025 · Report post 2 минуты назад, jcxz сказал: Спасибо. Значит во FreeRTOS это предусмотрено. И никаких ключей условной компиляции (для разных ядер Cortex-M) тут нет? DSB, ISB - для всех ядер? Это я открыл порт для Cortex-M7. В файле портирования для M3/M4 то же самое. Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 320 March 5, 2025 Posted March 5, 2025 · Report post https://github.com/mojinpan/UOS/blob/master/uos.c Это uCOS? По названию всяких функций выглядит как стыренный и допиленный uCOS. Но самое главное, китайцы в курсе: #define OSCtxSw() \ { \ ( *( ( volatile uint32_t * ) NVIC_INT_CTRL ) ) = NVIC_PENDSVSET; \ __asm volatile ( "dsb" ::: "memory" ); \ __asm volatile ( "isb" ); \ } Quote Share this post Link to post Share on other sites More sharing options...
mantech 128 March 5, 2025 Posted March 5, 2025 (edited) · Report post 7 минут назад, Arlleex сказал: Это uCOS? По названию всяких функций выглядит как стыренный и допиленный uCOS. Так там же даже не парятся)))))) /** **************************************************************************** * @file uos.c * @author mojinpan * @copyright (c) 2018 - 2019 BRC Tech. Co., Ltd. * @brief 微型嵌入式操作系统 * * @version V0.1 * @date 2019-05-18 * @details * 1.开始对UCOSII进行精简 * 2.将汇编整合到C文件中 Edited March 5, 2025 by mantech Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 320 March 5, 2025 Posted March 5, 2025 · Report post А ну все)) Тогда точно импортозаместили😄 Quote Share this post Link to post Share on other sites More sharing options...
jcxz 350 March 5, 2025 Posted March 5, 2025 · Report post 40 минут назад, Arlleex сказал: Это uCOS? По названию всяких функций выглядит как стыренный и допиленный uCOS. Да, судя по коду ISR PendSV - полностью стырили адаптировали. И метод старта многозадачности используют тот же самый. И переменные все uCOS-овские. В моей ОС эти функции выглядят совершенно по другому. И способы старта многозадачности у меня другие и их 2 разных. 40 минут назад, Arlleex сказал: Но самое главное, китайцы в курсе: Я смотрел по версии uCOS от 2017г. Это последняя, которую я использовал, потом перешёл на свою. Может позже поправили. Сомневаюсь, что китайцы сами додумались. Тем более в списке изменений ничего про это нет. Но получается, что похоже на предыдущих ядрах проблема отсутствия DSB,ISB не проявлялась. Раз её так поздно обнаружили. Видимо она в полный рост вылезла, как появились CM7. PS: Интересно - во FreeRTOS когда ICSR.PENDSVSET=1 дополнили DSB, ISB? С какого года? Quote Share this post Link to post Share on other sites More sharing options...
Arlleex 320 March 5, 2025 Posted March 5, 2025 · Report post 25 минут назад, jcxz сказал: PS: Интересно - во FreeRTOS когда ICSR.PENDSVSET=1 дополнили DSB, ISB? С какого года? Цитата Changes between V7.4.0 and V7.4.1 released April 18 2013 To ensure strict conformance with the spec and ensure compatibility with future chips data and instruction barrier instructions have been added to the yield macros of Cortex-M and Cortex-R port layers. For efficiency the Cortex-M port layer "yield" and "yield" from ISR are now implemented separately as the barrier instructions are not required in the ISR case. 12 лет назад. Quote Share this post Link to post Share on other sites More sharing options...