Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: stm32 NVIC: сброс маскировки прерываний внутри обработчика
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Страницы: 1, 2
jeka
Назрела необходимость (уже давно), разрешить прерывания более низкого приоритета в обработчике высокого приоритета. Способ в лоб - подкорректировав стек и сделать фиктивный возврат из прерывания.
С помощью MRS/MSR как я понял этого не сделать - в документации написано что запись в IPSR игнорируется.
Есть ли какое-то более человеческое решение чем через формирование стека возврата и возврат из прерывания?

Собственно, зачем это нужно - в случае аварии вызывается определенный irq. В обработчике нужно сделать некую аварийную последовательность действий, но для этого нужны рабочие обработчики другиз, в т.ч. низкоприоритетных прерываний. Можно конечно приоритеты нужных irq повысить.
Но есть вторая задача - сделать софтовый ресет (разумеется с обнулением стека), в нужную функцию и с разблокированными прерываниями. Например, в bootolader для перепрошивки.
Forger
Цитата(jeka @ Jul 12 2017, 19:58) *
Назрела необходимость (уже давно), разрешить прерывания более низкого приоритета в обработчике высокого приоритета.

Это противоречит самому принципу приоритетов прерываний. Странная необходимость ...

Цитата
Способ в лоб - подкорректировав стек и сделать фиктивный возврат из прерывания.
С помощью MRS/MSR как я понял этого не сделать - в документации написано что запись в IPSR игнорируется.

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

Цитата
Есть ли какое-то более человеческое решение чем через формирование стека возврата и возврат из прерывания?

Можно форсить более высокоприоритетное прерывание прямо из текущего обработчика.
В зависимости от его приоритета оно будет вызвано сразу или лишь после выхода из текущего обработчика.
Для этой цели хорошо подойдет NMI, у него самый высокий приоритет (после Reset).
Можно даже извратиться - вызывать hardfault, например, обращаясь к несуществующей памяти smile3046.gif

Цитата
Собственно, зачем это нужно - в случае аварии вызывается определенный irq.

А в чем проблема вызывать некую функцию? К чему городить огород с отдельным прерыванием?

Цитата
Например, в bootolader для перепрошивки.

А вот эта задача реализуется уже несколько иначе. Тут неоднократно поднималась эта тема. Пройдитесь поиском ))


зы. Подобную задачу я реализую просто: вызываю в случае аварии System Reset (нужно смотреть на его реализацию в каждом семействе МК).
Однако, не во всех задачах полный сброс допустим.
Аппаратно само устройство делаю так, что в сброшенном состоянии все силовые цепи отключаются, автоматом снимаются все сигналы готовности (если используются внешние силовые модули).
Это реализована подтяжками соотв. портов МК внешними резисторами.
Остальные обработчики типа HardFault у меня тоже в итоге вызывают System Reset (после анализа и фиксации в журнале событий причины сбоя).
Т.е. любое зависание, срабатывание вотчдога и т. д. всегда сбрасывают проц, что автоматом вырубает все силовые цепи.
Это удобно при отладке и прошивке - пока шьется проц, вырубается всякая опасная "сила", скажем силовые ключи привода мощного мотора, гасится мощной источник для "силы".
В таком решении гарантировано, что ничего никуда не поедет и не сожжет никакие "пробки" )))
jeka
Собственно в мягком ресете есть необходимость именно из-за сброса gpio - например, обрывается питание и bluetooth подвисает перед прошивкой. Плюс, все переменные переинициализируются и нельзя точку входа выбрать, неудобно.

То что колхоз это понятно, но без него не вижу простых решений. Хотя не сильный колхоз. Единственное неудобство - повторный вход в оборванные обработчики прерываний, но это не сильно пугает. Сброс состояний - дело несложное.
Forger
Цитата(jeka @ Jul 12 2017, 20:55) *
Единственное неудобство - повторный вход в оборванные обработчики прерываний, но это не сильно пугает. Сброс состояний - дело несложное.

Все-таки не пойму, чем не годится обычная функция, которая делает всю эту инициализацию?

Цитата
например, обрывается питание и bluetooth подвисает перед прошивкой
Я бы в таком случае поставил ключ на питание блютуса - какой нить подходящий p-mosfet.
Управление им от соотв. gpio. Так и питание батарейки проще экономить (если девайс батарейный).
jeka
п.с. irq вызывается, поскольку авария может прилететь извне в любой момент и независимо от режима работы нужно немедленно выполнить аварийные процедуры. Проще всего это сделать с чистого листа - заново принудительно с нуля переинициализировать нужную периферию (чтоб наверняка) в нужный режим, отключить все лишнее и сделать несколько действий.
Forger
Цитата(jeka @ Jul 12 2017, 21:06) *
п.с. irq вызывается, поскольку авария может прилететь извне в любой момент и независимо от режима работы нужно немедленно выполнить аварийные процедуры. Проще всего это сделать с чистого листа - заново принудительно с нуля переинициализировать нужную периферию (чтоб наверняка) в нужный режим, отключить все лишнее и сделать несколько действий.

Так все-таки, чем не годится вызов некой функции, где все это делается?
Она же вызывается при запуске проца однократно.
jeka
Цитата(Forger @ Jul 12 2017, 21:02) *
Я бы в таком случае поставил ключ на питание блютуса - какой нить подходящий p-mosfet.

как вариант, только с RC цепочкой. Чтоб вырубался, но не сразу. Но честно не думал что проблемы такого характера могут возникнуть, думаю все-таки правильнее программно решить.
Forger
Цитата(jeka @ Jul 12 2017, 21:14) *
как вариант, только с RC цепочкой. Чтоб вырубался, но не сразу. Но честно не думал что проблемы такого характера могут возникнуть, думаю все-таки правильнее программно решить.

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

В одном моем проекте стояла ESP-ка, которая любила иногда подвисать по usart-у. Зная это, я сразу поставил для нее отдельный стабилизатор 3.3В со входом EN.
Это позволило включать ESP-ку только тогда, когда это было нужно, чисто программно. Зависла - передергиваем питание стабилизаатора и начинаем все по-новой.
Фактически производился сброс только модуля, отвечающего за обмен под wifi, а все остальные модули (программные модули) работали в штатном режиме.
jeka
Цитата(Forger @ Jul 12 2017, 21:14) *
Так все-таки, чем не годится вызов некой функции, где все это делается?
Она же вызывается при запуске проца однократно.

Ей нужно по хорошему передать несколько параметров. Плюс как определить что на ребут для определенной цели ушел? В память записать определенную сигнатуру? Но это то же колхоз.
Forger
Цитата(jeka @ Jul 12 2017, 21:25) *
Ей нужно по хорошему передать несколько параметров.
Зачем?
Сделайте разные функции для разных задач. Дайте им соотв. имена.

Цитата
Плюс как определить что на ребут для определенной цели ушел?

Я использую модульную структура проекта, каждый модуль нужно инициализировать индивидуально при старте.
Но ничто не мешает принудительно его переинициализировать (скажем, вызвав соотв. SWI).
Каждый модуль у меня "владеет" своими пинами и своими аппаратными узлами (таймеры, цапы и т.п.).
Никто не обращается к одному и тому же аппаратному узлу из разных модулей. Т. е. у всех аппаратных сущностей есть владелец в единственном числе.
Так я точно могу управлять всей системой. Т. е. на этапе проектировки закладывается строгая и очень жесткая иерархия.
Она неизменна в процессе работы всей железки.
Каждый модуль обязан самостоятельно инициализировать "свое" железо (в т.п. числе и пины!).
Общая пока что только инициализация системного таймера и тактовой частоты, но и она скоро "уйдет" в свой модуль (SystemController).

Цитата
В память записать определенную сигнатуру? Но это то же колхоз.

Я совсем запутался ... Какую еще сигнатуру?
Что же на самом деле вы хотите реализовать?
Распишите конкретный пример, а то, может оказаться, что мы толкуем о разных вещах )))
jeka
Сейчас я в одном из девайсов делаю примерно так. Т.е. делаю софт-ресет из основного цикла (где контроллер irq не замаскирован), а в AHBENR ставлю флаг, который в загрузчике анализируется и после железного ресета гарантированно сброшен.

Код
        RCC->AHBENR=1;// marker for software reset
  
        SysTick->CTRL=0;
        uint32_t* ptr=(uint32_t*)(0x08000000);
        SCB->VTOR=(uint32_t)ptr;
        __set_MSP(*(ptr++));
        __set_BASEPRI(0);
        __set_CONTROL(0);
        NVIC->ICER[0]=0xFFFFFFFF;
        NVIC->ICER[1]=0xFFFFFFFF;
        NVIC->ICER[2]=0xFFFFFFFF;
        NVIC->ICER[3]=0xFFFFFFFF;
        NVIC->ICER[4]=0xFFFFFFFF;
        NVIC->ICER[5]=0xFFFFFFFF;
        NVIC->ICER[6]=0xFFFFFFFF;
        NVIC->ICER[7]=0xFFFFFFFF;
        NVIC->ICPR[0]=0xFFFFFFFF;
        NVIC->ICPR[1]=0xFFFFFFFF;
        NVIC->ICPR[2]=0xFFFFFFFF;
        NVIC->ICPR[3]=0xFFFFFFFF;
        NVIC->ICPR[4]=0xFFFFFFFF;
        NVIC->ICPR[5]=0xFFFFFFFF;
        NVIC->ICPR[6]=0xFFFFFFFF;
        NVIC->ICPR[7]=0xFFFFFFFF;
        void (*start)()=(void(*)())(*ptr);
        start();


Вполне доволен таким софтовым ресетом без сброса железа.
Forger
Цитата(jeka @ Jul 12 2017, 21:34) *
Вполне доволен таким софтовым ресетом без сброса железа.

А приведите пример, когда действительно нужен такой "софтовый ресет"?
jeka
Цитата(Forger @ Jul 12 2017, 21:32) *
Я совсем запутался ... Какую еще сигнатуру?
Что же на самом деле вы хотите реализовать?
Распишите конкретный пример, а то, может оказаться, что мы толкуем о разных вещах )))

Мы видимо по разному думаем.

Я про то, как передать загрузчику после железного ресета параметры. Это некий квест и тоже с колхозом.

Работает примерно так: работает девайс в обычном режиме. Приходит кодограмма на перепрошивку, с дополнительными данными. Независимо от режима он должен ребутнуться, продолжить обмен по этому протоколу (без обрыва и без переинициализации протокола обмена) и прошиться. При этом в этой кодограмме содержатся данные, которые надо передать загрузчику.
То есть загрузчик должен получить содержимое кодограммы и все состояния протокола обмена.
После перепрошивки также без переинициализации протокола обмена запустить основную программу.
Forger
Цитата(jeka @ Jul 12 2017, 21:45) *
После перепрошивки также без переинициализации протокола обмена запустить основную программу.

Имхо, очень сомнительная и где-то даже опасная необходимость ...
Обычно, всякая смена прошивки софта предполагает сброс всего проца. Мне никогда не попадалось обратное.

Но, может быть, вы имеете ввиду некие настройки конкретного экземпляра девайса?
У меня такие настройки храняться в внешней EEPROM/FRAM или во внутреннем EEPROM (или FLASH, если нету EEPROM).
При перезапуске приложения все настройки загружаются в ОЗУ и оттуда все работает до очередного сброса.
Также предусмотрены настройки по дефолту, позволяет вернуть девайс соотв. командами к заводским настройкам.
За все это отвечает отдельный модуль Settings, он хранит все изменяемые параметры системы, которые могут быть разные для разных девайсов (в т. ч. серийны номер).

Цитата
Мы видимо по разному думаем.
Это вообще-то справедливо для всех, иначе вообще не были бы нужны форумы sm.gif
jeka
Специфика такая. Не хочется протокол обмена обрывать, т.к. это вызывает проблемы на главном устройстве, а их решить сложнее чем протокол поддерживать.
Forger
Цитата(jeka @ Jul 12 2017, 22:17) *
Специфика такая. Не хочется протокол обмена обрывать, т.к. это вызывает проблемы на главном устройстве, а их решить сложнее чем протокол поддерживать.

А если сохранить параметры протокола в энергонезависимой памяти, а после сброса (даже аппаратного) восстановить их и продолжить с прерванного места?
Годится такое решение?
jeka
годится, но больно сложно получается. Плюс дополнительная блокировка обмена на этапе рукопожатия (пока трём и пишем страницу во flash) перед прошивкой может проблем добавить.
Forger
Цитата(jeka @ Jul 12 2017, 22:29) *
годится, но больно сложно получается.
Да неужели? Вот тут я бы поспорил, что сложнее ... sm.gif

Цитата
Плюс дополнительная блокировка обмена на этапе рукопожатия (пока трём и пишем страницу во flash) перед прошивкой может проблем добавить.

Обмен все равно придется прекратить на всё время обновления прошивки. Так в чем проблема приостановить обмен перед сохранение его параметров?
jeka
Ну не хочется городить огород с записью во флеш, правкой дисциплины обмена когда есть простое и работающее без нареканий на других процессорах решение. Решение меня не устраивало только тем что не хотел вставлять ассемблерную функцию. Пока варианта лучше нет, будет так.
Forger
Цитата(jeka @ Jul 12 2017, 23:01) *
... когда есть простое и работающее без нареканий на других процессорах решение.

Но тогда с какой целью затевалась эта тема? wink.gif
jeka
Цель - понять, можно ли на arm сбросить маскировку прерываний кроме как командой возврата из прерывания. Хочется без костыля в виде функции на ассемблере обойтись.
KSN
По поводу непрерывного протокола обмена.
Делаю так: в RAM есть структура, которая не инициализируется средствами компилятора при старте программы. Через эту структуру bootloader и application обмениваются информацией( вызов bootloadera из application, возврат из bootloader в application). Использую какие-нибудь хитрые значения для этих переменных, а не простые 0x00000000, 0xFFFFFFFF, наподобие значение переменных для снятие блокировки с watch-dog, flash memory в stm32f.
Работает так: прилетает команда по интерфейсу "перейти в bootloder". Application отвечает, что команда принята, выполняет необходимы действия, устанавливает переменную и вызов bootloader. Bootloader "понимает" что был переход по команде, шлет по интерфейсу подтверждение исполнения команды и далее обрабатываются команды для bootloadera. После завершения обновления прошивки, приходит команда "выйти из bootloader" - посылается ответ, что команда принята, устанавливается переменная, выполняются необходимые действия и переход в Application. Application "понимает", что был выход из bootloadera по команде, шлет "подтверждение исполнения" команды и продолжает исполняться код приложения.
jcxz
Цитата(jeka @ Jul 12 2017, 19:58) *
Назрела необходимость (уже давно), разрешить прерывания более низкого приоритета в обработчике высокого приоритета.

А в чём проблема? Разрешаете через соотв. регистр NVIC и всё. У меня много где внутри одних ISR разрешаются/запрещаются другие.

Цитата(jeka @ Jul 12 2017, 19:58) *
Способ в лоб - подкорректировав стек и сделать фиктивный возврат из прерывания.

Не понял... %-\ Зачем???
Вам же надо вроде только разрешить некое другое прерывание, причём тут возврат из текущего?
Forger
Цитата(KSN @ Jul 13 2017, 05:24) *
По поводу непрерывного протокола обмена.
Делаю так: в RAM есть структура, которая не инициализируется средствами компилятора при старте программы.

Скажем, питание было выдернуто (передернуто) в процессе обмена данными через эту область ОЗУ и тем более в процессе заливки новой прошивки.
Есть защита от подобных сбоев?
jcxz
Цитата(jeka @ Jul 12 2017, 19:58) *
в документации написано что запись в IPSR игнорируется.

Если с умом подходить, то и в IPSR можно записать. Только - зачем?

Цитата(jeka @ Jul 12 2017, 21:25) *
Ей нужно по хорошему передать несколько параметров. Плюс как определить что на ребут для определенной цели ушел? В память записать определенную сигнатуру? Но это то же колхоз.

Почему "колхоз"?
Такой "колхоз" даже производители некоторых МК делают biggrin.gif Например в Infineon, после передачи управления пользовательскому ПО из ROM-загрузчика, в начале ОЗУ гарантируется наличие некоторых данных (например - серийный номер чипа).
И в Вашем случае, для передачи неких команд управления вашему бутлоадеру вполне можно также делать. Но опять-же - с умом.
Например:
Обычно в МК есть флажки, позволяющие определить причину сброса (внешний reset, POR, WDT, etc.). Так вот: после старта бутлоадер может посмотреть на флажки и, если там указан WDT, проверить некую область ОЗУ на наличие ключа. Если причина сброса - не WDT, то не читать ключ. Соответственно в рабочей прошивке, сразу после получения управления, в область ключа записывается НЕ_ключ и спокойно работаем. Если пришла необходимость сделать переход в бутлоадер: формируем WDI, пишем в область ключа собственно ключ и делаем сброс по WDT.
KSN
Цитата(Forger @ Jul 13 2017, 13:04) *
Скажем, питание было выдернуто (передернуто) в процессе обмена данными через эту область ОЗУ и тем более в процессе заливки новой прошивки.
Есть защита от подобных сбоев?

Да, конечно. Проверка CRC прошивки, область bootloaderа защищена. При возникновение такой ситуации устройство перезагрузится, останется в bootloader, при этом по интерфейсу будет послано сообщение в систему.
Obam
Цитата
Назрела необходимость (уже давно), разрешить прерывания более низкого приоритета в обработчике высокого приоритета…
Есть ли какое-то более человеческое решение чем через формирование стека возврата и возврат из прерывания?


Как возможность, вызов прерывания с достаточным приоритетом записью его номера в STIR: ваш обработчик высокого приоритета отработает, и будет исполняться тот, что из STIR.
jeka
Прошу прощения, не указал один важный момент, из-за которого путаница возникла: из обработчика прерывания высокого приоритета возврат не предполагается. Совсем. Предполагается не выходя из обработчика этого irq сделать фактически рестарт процессора и передачу управления нужному модулю с переинициализацией стека, контроллера прерываний и остальной периферии.
Obam
Тогда вообще ни о чём: сброс и всё.
jeka
Сброс не желателен, т.к. состояние части периферии нужно сохранить.

Вообще топик не про поиск обходных путей решения (это мне не нужно - придумать с десяток вариантов и сделать один из вариантов проблем не составляет), а про конкретную аппаратную особенность процессора, а именно сброс текущего приоритета прерываний без шаманства со стеком.
Forger
Цитата(jeka @ Jul 13 2017, 15:27) *
сброс не желателен, т.к. состояние части периферии нужно сохранить.

Так что мешает вызывать соотв. функцию, которая переинициализирует нужную периферию и в т.ч. NVIC.
Эта же функция должна вызывается при сбросе.
Вот тут я подробно описал как делаю нечто подобное, никакого колхоза, все прозрачно:
https://electronix.ru/forum/index.php?s=&am...t&p=1508140
jeka
Мешает то что если из обработчика прерывания просто передать управление стартовому коду (без system reset), то ненулевой IPSR не сбросится и часть прерываний будет перманентно заблокировано.
Forger
Цитата(jeka @ Jul 13 2017, 15:48) *
Мешает то что если из обработчика прерывания просто передать управление стартовому коду (без system reset), то ненулевой IPSR не сбросится и часть прерываний будет перманентно заблокировано.

А почему реально не сделать программный сброс (system reset)? Ведь содержимое внутреннего ОЗУ при этом вроде бы не теряется.
Obam
"сброс текущего приоритета прерываний без шаманства со стеком."
Рафинированное шаманство wink.gif
jcxz
Цитата(jeka @ Jul 13 2017, 15:48) *
Мешает то что если из обработчика прерывания просто передать управление стартовому коду (без system reset), то ненулевой IPSR не сбросится и часть прерываний будет перманентно заблокировано.

Без формирования необходимого стекового фрейма тут не обойтись. Собственно именно такую операцию и выполняет таск-шедулер любой ОС, висящий на PendSV.
Вы можете сделать по образу и подобию:
Задействовать некий вектор прерывания (не используемого). Назначить ему приоритет заведомо ниже любого другого прерывания (самый низкий из всех).
Далее - в Вашем ISR возбуждаете это прерывание программно (через соотв. регистры NVIC) и штатно выходите из ISR.
Соответственно - сразу попадаете в тот низкий ISR, в нём корректируете стековый фрейм (кроме адреса возврата собственно больше ничего менять и не надо) и штатно выходите из этого ISR в нужную точку с корректным IPSR.
Никаких запретов прерываний, никакого шаманства - всё штатными средствами.

PS: Хотя лучше всё-таки подумать - зачем именно нужно так переходить, без сброса периферии. Это, имхо, идеологически неправильный подход wink.gif
AVI-crak
Цитата(jeka @ Jul 12 2017, 22:58) *
Собственно, зачем это нужно - в случае аварии вызывается определенный irq.

На случай аварий - системой уже предусмотрено несколько стандартных аппаратных прерываний разного уровня. От мягких программных, до жёстких системных.

Собаку можно обработать программно, и успеть перевести внешнюю периферию в необходимое для выключение состояние. Например полностью блокировать внешний силовой драйвер мощных транзисторов, да и вообще отрубить всё питание.

Чтение мимо адресного пространства BusFault - можно поймать отладчиком, вернуться в точку остановки кода, и найти сбойное место. Часто причиной сбоя является неисправность указателей, тогда приходится искать намного дольше.

Модуль защиты MPU - на самом деле замечательная вещь, на M4-M7 без него никак. Дело в том что ядро обрабатывает программный код на конвейере, дополнительно - сам код собирается для внеочередного исполнения. GCC знает про MPU, и умеет использовать его настройки. Например для линейной области памяти управления почти всей периферией (0x40000000 - (0.5G)) - запрет кеша, сквозная запись, запрет обратной записи, запрет исполнения кода, ожидать выполнения физической записи. В этом случае состояние периферии будет меняться программой - как задумал пользователь, но не как удобно GCC. Дополнительно - конвейер команд будет сбрасываться при обнаружении обращения к области периферии - чтоб ни одна сволочь вперёд очереди не проскочила (типа я только спросить).
Если при таких настройках выполнить переход на адреса периферии (исполнение программного кода) - то сработает прерывание MemManage_Handler. Оно является мягким, и его можно обработать возвратом в программный код с поиском ошибки.

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

Ну и всё скопом по порядку:
Reset_Handler - стартовый адрес прошивки
NMI_Handler - неизвестное прерывание Default_Handler, любое из неопределённых
HardFault_Handler - отказы: шины, арбитра памяти, сбой чтения вектора прерываний.
MemManage_Handler - ошибка доступа к памяти, срабатывание правил MPU
BusFault_Handler - чтение/запись по недопустимому адресу
UsageFault_Handler - прерывание специально для пользователя, можно оформить как критическую секцию
часть прерываний от старших ARM процессоров вырезана тупым ржавым скальпелем, ещё не успело зарубцеваться
SVC_Handler - крутое прерывание пользователя из разряда - пусть весь мир подождёт
DebugMon_Handler - запуск кода отладчика на ядре мк в момент контрольной точки, остановка ядра после кода - для считывания данных отладчиком
пусто
PendSV_Handler - типа удобная функция для переключения контекста, я так не думаю
SysTick_Handler - самый примитивный таймер во всей системе, он даже не полностью 32 бита.

/* External Interrupts */
WWDG_IRQHandler - сторожевая собака, гавкает когда перестают ходить строем
jeka
jcxz, спасибо за ответ. В целом как и предполагал. И понизить приоритет чтоб завершить все подвисшие обработчики прерываний тоже полезная штука, о ней как раз думал.

Итог - кроме как через стек возврата не сделать. Вопрос решен.

AVI-crak, Да, MPU хорошо сделали. Главное просто и все что надо есть. Хотя еще не пробовал с ним работать.
jcxz
Цитата(jeka @ Jul 13 2017, 19:11) *
jcxz, спасибо за ответ. В целом как и предполагал. И понизить приоритет чтоб завершить все подвисшие обработчики прерываний тоже полезная штука, о ней как раз думал.

Да, забыл указать, что для описанного метода желательно править Process stack и возврат из этого ISR тогда будет идти в Thread mode.
Можно конечно и Main stack править, но тогда нужно перед возвратом из этого ISR сделать запрет прерываний и fault-ов.
Forger
Вот читаю, вижу интересные мудрёные решения, но вопрос остается прежний - чем не угодил традиционный System Reset с предварительным сохранением нужных данных в ОЗУ/FLASH/EEPROM?
Ведь рано или поздно излишняя самодеятельность с ручной правкой стека приведет к самым неожиданным последствиям в самый неожиданный момент ...
А если девайс еще и напрямую управляет опасной "силой", то я бы стопитсот раз подумал.
Имхо, лучше лишний раз "передернуть" все железо, чем так нагло влезать в стек подобного девайса wink.gif
AVI-crak
Цитата(Forger @ Jul 13 2017, 23:14) *
Имхо, лучше лишний раз "передернуть" все железо, чем так нагло влезать в стек подобного девайса wink.gif

Чтобы не ресетить девайс - нужно изначально закладывать архитектуру здоровой OS, с отдельным стеком прерываний и куче стеков задач. В этом случае запуск/отключение и управление уровнем прерывания - осуществляется через активную задачу, которая вызывает системное прерывание с заведомо максимальным уровнем.
Без блокировки!!!

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

Уход в глубокий сон выполняется по команде OS, после чего все активные задачи должны свернуть свою деятельность и уйти в зависимость, вот после этого можно сохранять на флеш - активную память задач и их стеки, с последующим отключением питания. Предусмотреть все ньюансы работы периферии - просто невозможно. Однако в самой активной задаче - вполне реально. Просто блок инициализации будет выполняться повторно при перезапуске в каждой задаче отдельно.

Глубокий сон - весьма специфическое требование, его трудно выполнить качественно, всегда придётся идти на компромисс. Гораздо чаще делают более простой вариант - сохраняют только данные объявленные как статические - в энергонезависимой памяти. С копированием их в память при запуске и сохранением перед отключением.
Forger
Цитата(AVI-crak @ Jul 14 2017, 02:05) *
нужно изначально закладывать архитектуру здоровой OS, с отдельным стеком прерываний и куче стеков задач.

Ну, обычно существующие ОS под cortex именно так и реализованы sm.gif
Но что-то мне подсказывает, что в данном случае OS вообще не используется ...

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

Вы прям озвучили мои мысли sm.gif
jeka
Цитата(AVI-crak @ Jul 14 2017, 02:05) *
Править уровни прерываний и их очереди в теле пользовательских прерываний - это есть громадный костыль, означающий что программист накосячил в нескольких местах и не смог исправить.

Никто уровни и очереди не правит. Еще раз - задача выполнить reset, но не всего и сразу, а выборочный. Включая сброс NVIC. Чтобы часть периферии и данных в RAM остались нетронутыми.

Цитата
Чтобы не ресетить девайс - нужно изначально закладывать архитектуру здоровой OS

Вы эту ОС будете переустанавливать/обновлять без ресета?
Действия при аварии электропитания тоже предполагаются без ресета?
Forger
Цитата(jeka @ Jul 14 2017, 18:37) *
Включая сброс NVIC.

NVIC является частью ядра, поэтому сбросить NVIC без сброса всего ядра никак не получится (оно и к лучшему).
Сбросить ядро (или весь МК) можно программно, но все МК делают это по-разному.
В частности, ST умеет делать полноценный аппаратный сброс (как будто дернули внешний NRST) программно через system reset .

LightElf
QUOTE (jeka @ Jul 14 2017, 18:37) *
Чтобы часть периферии и данных в RAM остались нетронутыми.

Дык не трогайте данные в RAM - они и останутся нетронутыми. Ресет содержимое SRAM не затрагивает. Для пущей безопасности нужный кусок SRAM защитите CRC или еще каким образом.
Forger
Цитата(LightElf @ Jul 24 2017, 12:50) *
Дык не трогайте данные в RAM - они и останутся нетронутыми. Ресет содержимое SRAM не затрагивает. Для пущей безопасности нужный кусок SRAM защитите CRC или еще каким образом.

Не прокатит - ТС не желает сбрасывать всю периферию laughing.gif
Я уже предлагал решить эту задачу, разбиением программы на т. н. "модули", тогда несложно сделать возможность выполнять полную переинициализацию каждого модуля индивидуально.
Практически всю периферию можно переинициализировать заново, нельзя тока нормально сбросить NVIC, т. к. NVIC является частью ядра.
Но NVIC тоже можно переинициализировать, пусть это и будет неким колхозом.

Я бы в данной задаче реализовал отложенный сброс каждого модуля индивидуально: модуль (задача/задачи), который нужно перезапустить, получает соотв. уведомление и решает сам, когда и как нужно делать сброс.
После чего модуль "сообщает", что это сброс был выполнен или это невозможно выполнить в данный момент.

Но все же лучше по-искать другое решение, которое в случае тотального алярма без проблем позволит сделать полноценный сброс всего проца )))
jcxz
Цитата(LightElf @ Jul 24 2017, 12:50) *
Ресет содержимое SRAM не затрагивает.

Да ладно??! А код boot-ROM, выполняемый после сброса, где стек и рабочие переменные размещает? laughing.gif
Forger
Цитата(jcxz @ Jul 25 2017, 13:45) *
Да ладно??! А код boot-ROM, выполняемый после сброса, где стек и рабочие переменные размещает? laughing.gif

В STM32 SRAM не страдает от сброса (кроме, разумеется, сброса от передергивания питания, после которого там всегда будет "мусор").
STM32 RAM behavior after soft-reset


зы Помню, что как-то давно я все недоумевал, зачем в STM32 есть boot-режим старта прямо из ОЗУ (соотв. ремап вектора сброса на начало ОЗУ)? ...
jcxz
Цитата(Forger @ Jul 25 2017, 14:14) *
В STM32 SRAM не страдает от сброса (кроме, разумеется, сброса от передергивания питания, после которого там всегда будет "мусор").

Да ладно?!! Они умудрились написать код чисто на регистрах и без использования стека??? Прямо чудеса чудесатые какие-то рассказываете..... biggrin.gif
Или они стек boot-ROM-а научились размещать в облаке? santa2.gif
Forger
Цитата(jcxz @ Jul 25 2017, 15:02) *
Да ладно?!! Они умудрились написать код чисто на регистрах и без использования стека??? Прямо чудеса чудесатые какие-то рассказываете..... biggrin.gif

Вы ничего не путаете? sm.gif

В STM32 есть два спец пина BOOT0 и BOOT1, оменно они определяют кто будет запускаться при старте проца:
user-код (User Flash memory), boot-загручик (System memory), ОЗУ или еще что-то (например, в "толстых" камнях).
Опрос этих пинов производится ядром (или узлом, который отвечает за выбор области загрузки) в течение нескольких тактов после сброса.
Но даже в случае безусловного использования бут-загручика можно выяснить области ОЗУ, которые он использует. А используют они совсем небольшую часть ОЗУ.
Это не секретная информация sm.gif Все есть в соотв. мануалах ))

Еще раз: BOOT-загрузчик в STM32 НЕ стартует безусловно.
Более того, в тотально залоченном состоянии бут вообще невозможно запустить (разве что прочитать его версию):
When readout protection Level2 is activated, STM32 does not boot on system memory in
any case and Bootloader can't be executed
(unless jumping to it from Flash user code, all
commands are not accessible except Get, GetID, and GetVersion).



Может, вы путаете STM32 с другими камнями (которые без своей FLASH), где BOOT стартует ВСЕГДА после сброса? wink.gif
jcxz
Цитата(Forger @ Jul 25 2017, 15:30) *
Вы ничего не путаете? sm.gif

В AN2606 в Table 66. STM32F42xxx/43xxx configuration in system memory boot mode указано, что 8 Kbyte starting from address 0x20000000 are used by the bootloader firmware.
И эта область указана как Common to all bootloaders.
Также видно, что указатель стека из вектора сброса из таблицы векторов прерываний в ROM по адресу 0x1FFF0000 (из STM32F429 который у меня сейчас на столе) указывает на адрес 0x20002318 опять-же - внутри этих 8КБ.
Вот именно этот код, который считывает BOOT-пины и определяет куда передать управление (и возможно что-то ещё делает), видимо и находится по адресу, на который указывает вектор сброса из 0x1FFF0000.

PS: Не посчитал однако... 0x20002318 - это ведь уже за пределами 8КБ. Странно.... wacko.gif
Опять-же - в AN2606 говорится про Bootloader V7.x. А какая у моего версия - не знаю.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.