Что происходит во встроенном процессоре, когда выполнение достигает этого последнего return
оператора. Все ли просто замирает, как есть; энергопотребление и т.д., с одним длинным вечным NOP в небе? или постоянно выполняются NOP, или процессор вообще отключится?
Одна из причин, по которой я спрашиваю, заключается в том, что мне интересно, нужно ли отключать питание процессора перед завершением выполнения, и если да, то каким образом завершается выполнение, если оно было выключено раньше?
Ответы:
Это вопрос, который мой папа всегда задавал мне. « Почему он не проходит через все инструкции и не останавливается в конце? »
Давайте посмотрим на патологический пример. Следующий код был скомпилирован в компиляторе C18 Microchip для PIC18:
Он производит следующий вывод ассемблера:
Как вы можете видеть, main () вызывается и в конце содержит оператор return, хотя мы сами его явно не помещали туда. Когда main возвращается, CPU выполняет следующую инструкцию, которая является просто GOTO, чтобы вернуться к началу кода. main () просто вызывается снова и снова.
Сказав это, люди обычно так не поступают. Я никогда не писал ни одного встроенного кода, который позволял бы main () завершать работу таким образом. В основном мой код будет выглядеть примерно так:
Поэтому я бы никогда не позволил main () выйти.
«Хорошо, хорошо», - говорите вы. Все это очень интересно, что компилятор гарантирует, что никогда не будет последнего оператора return. Но что произойдет, если мы заставим проблему? Что, если я вручную закодирую свой ассемблер и не вернусь к началу?
Ну, очевидно, процессор просто продолжит выполнять следующие инструкции. Это будет выглядеть примерно так:
Следующий адрес памяти после последней инструкции в main () пуст. На микроконтроллере с флэш-памятью пустая инструкция содержит значение 0xFFFF. По крайней мере, на PIC этот код операции интерпретируется как 'nop' или 'no operation'. Это просто ничего не делает. Процессор продолжит выполнение этих nops до конца памяти.
Что после этого?
В последней инструкции указатель команды процессора равен 0x7FFe. Когда ЦП добавляет 2 к своему указателю инструкций, он получает 0x8000, что считается переполнением PIC только с 32k FLASH, и поэтому он возвращается обратно к 0x0000, и ЦП с радостью продолжает выполнять инструкции в начале кода так же, как если бы он был сброшен.
Вы также спросили о необходимости выключения. По сути, вы можете делать все, что захотите, и это зависит от вашего приложения.
Если у вас есть приложение, которое должно было выполнить только одно действие после включения, а затем ничего не делать, вы можете просто добавить время (1); в конце main (), так что процессор перестает делать что-либо заметное.
Если приложению требуется отключение ЦП, то, в зависимости от ЦП, возможно, будут доступны различные спящие режимы. Тем не менее, процессоры имеют привычку снова просыпаться, поэтому вам нужно убедиться, что для сна не было ограничений по времени, таймера сторожевого пса и т. Д.
Вы могли бы даже организовать некоторые внешние схемы, которые позволили бы процессору полностью отключить свою собственную мощность, когда он закончил. См. Этот вопрос: Использование кратковременной кнопки в качестве защелкивающегося выключателя .
источник
Для скомпилированного кода это зависит от компилятора. Компилятор Rowley CrossWorks gcc ARM, который я использую, переходит к коду в файле crt0.s с бесконечным циклом. Компилятор Microchip C30 для 16-разрядных устройств dsPIC и PIC24 (также основанный на gcc) сбрасывает процессор.
Конечно, большинство встроенных программ никогда не завершается таким образом и выполняет код непрерывно в цикле.
источник
Здесь нужно сделать два замечания:
Концепция выключения программы обычно не существует во встроенной среде. На низком уровне процессор будет выполнять инструкции, пока он может; не существует такого понятия, как «окончательное возвращение». Процессор может остановить выполнение, если он обнаружит неисправимую ошибку или если явно остановлен (переведен в режим ожидания, режим низкого энергопотребления и т. Д.), Но учтите, что даже режимы ожидания или неисправимые ошибки обычно не гарантируют, что больше кода не будет быть казненным. Вы можете выйти из спящих режимов (именно так они обычно используются), и даже заблокированный ЦП все еще может выполнять обработчик NMI (это имеет место в Cortex-M). Сторожевой таймер также будет работать, и вы не сможете отключить его на некоторых микроконтроллерах после его включения. Детали сильно различаются между архитектурами.
В случае прошивки, написанной на языке, таком как C или C ++, что произойдет, если main () завершится, определяется кодом запуска. Например, вот соответствующая часть кода запуска из стандартной периферийной библиотеки STM32 (для цепочки инструментов GNU комментарии мои):
Этот код войдет в бесконечный цикл, когда main () вернется, хотя и неочевидным способом (
bl main
загружаетсяlr
с адресом следующей инструкции, которая фактически является переходом к самой себе). Не делается никаких попыток остановить процессор или перевести его в режим пониженного энергопотребления и т. Д. Если у вас есть законные потребности в этом в вашем приложении, вам придется сделать это самостоятельно.Обратите внимание, что, как указано в ARMv7-M ARM A2.3.1, регистр связи при сбросе устанавливается в 0xFFFFFFFF, и переход по этому адресу вызовет ошибку. Поэтому разработчики Cortex-M решили рассматривать возврат из обработчика сброса как ненормальный, и с ними трудно спорить.
Говоря о законной необходимости останавливать процессор после завершения прошивки, трудно представить себе что-либо, что не будет лучше обслуживаться при отключении питания вашего устройства. (Если вы отключите свой процессор «насовсем», единственное, что можно сделать с вашим устройством, - это выключить и снова включить или выключить внешнее оборудование.) Вы можете деактивировать сигнал ENABLE для преобразователя постоянного тока или отключить питание в каким-то другим способом, как это делает ПК ATX.
источник
loop: b loop
. Интересно, они действительно хотели вернуть, но забыли сохранитьlr
?Когда спрашиваешь
return
, ты думаешь о слишком высоком уровне. Код C переводится в машинный код. Таким образом, если вы вместо этого думаете о том, как процессор вслепую извлекает инструкции из памяти и выполняет их, он не знает, какая из них является «последней»return
. Таким образом, процессоры не имеют собственного конца, но вместо этого дело программиста обрабатывать конечный случай. Как указывает Леон в своем ответе, компиляторы запрограммировали поведение по умолчанию, но часто программисту может потребоваться собственная последовательность выключения (я делал разные вещи, например, переход в режим низкого энергопотребления и останов или ожидание подключения кабеля USB. в и затем перезагрузка).Многие микропроцессоры имеют инструкции остановки, которые останавливают процессор, не затрагивая периферийные устройства. Другие процессоры могут рассчитывать на «остановку», просто просто многократно переходя на один и тот же адрес. Возможны варианты, но дело за программистом, потому что процессор просто продолжит чтение инструкций из памяти, даже если эта память не предназначена для инструкций.
источник
Проблема не встроенная (встроенная система может работать под управлением Linux или даже Windows), а автономная или «голая железо»: (скомпилированная) прикладная программа - единственное, что запускается на компьютере (не имеет значения, является ли она микроконтроллер или микропроцессор).
Для большинства языков язык не определяет, что происходит, когда завершается «main» и нет ОС, к которой можно вернуться. Для C это зависит от того, что находится в файле запуска (часто crt0.s). В большинстве случаев пользователь может (или даже должен) предоставить код запуска, поэтому окончательный ответ таков: что вы пишете, это код запуска или то, что происходит в указанном вами коде запуска.
На практике существует 3 подхода:
не принимать никаких специальных мер. что происходит, когда основной возврат не определен.
перейти к 0 или использовать любые другие средства для перезапуска приложения.
войти в жесткий цикл (или отключить прерывания и выполнить команду остановки), навсегда заблокировав процессор.
Что подходит, зависит от приложения. Вероятно, следует перезагрузить поздравительную открытку с мехом и систему управления тормозами (просто чтобы упомянуть две встроенные системы). Недостатком перезапуска является то, что проблема может остаться незамеченной.
источник
На днях я смотрел на какой-то дизассемблированный код ATtiny45 (C ++, скомпилированный avr-gcc), и в конце кода он переходит к 0x0000. В основном делаю сброс / перезапуск.
Если этот последний переход к 0x0000 пропущен компилятором / ассемблером, все байты в памяти программы интерпретируются как «допустимый» машинный код, и он выполняется до тех пор, пока счетчик программ не переходит на 0x0000.
На AVR байт 00 (значение по умолчанию, когда ячейка пуста) - это NOP = Нет операции. Так что он работает очень быстро, ничего не делая, а просто занимает некоторое время.
источник
Обычно скомпилированный
main
код впоследствии связывается с кодом запуска (он может быть интегрирован в набор инструментов, предоставленный производителем чипа, написанный вами и т. Д.).Затем компоновщик помещает весь код приложения и запуска в сегменты памяти, поэтому ответы на ваши вопросы зависят от: 1. кода при запуске, поскольку он может, например:
bl lr
илиb .
), который будет аналогичен «концу программы», но ранее включенные прерывания и периферийные устройства будут работать,main
).просто игнорируйте «что будет дальше» после вызова
main
return.main
поведения, будет зависеть от вашего компоновщика (и / или сценария компоновщика, используемого при компоновке).Если другая функция / код ставится после вашей,
main
она будет выполняться с недопустимыми / неопределенными значениями аргументов,Если сторожевой таймер включен, он в конечном итоге сбросит MCU, несмотря на все бесконечные циклы, в которых вы находитесь (конечно, если он не будет перезагружен).
источник
Лучший способ остановить встроенное устройство - это ждать вечно с инструкциями NOP.
Второй способ - закрыть устройство, используя само устройство. Если вы можете управлять реле с вашими указаниями, вы можете просто открыть выключатель , который приводит в движении вашего встроенного устройства и да ваш встроенный прибор Унесенный не энергопотребления.
источник
Это было четко объяснено в руководстве. Обычно общее исключение выдается процессором, потому что оно будет обращаться к области памяти, которая находится за пределами сегмента стека. исключение защиты памяти.
Что вы имели в виду под встроенной системой? Микропроцессор или микроконтроллер? В любом случае, это определено в руководстве.
В x86 CPU мы выключаем компьютер, отправляя команду на контроллер ACIP. Вход в режим управления системой. Таким образом, этот контроллер является микросхемой ввода-вывода, и вам не нужно вручную его выключать.
Прочитайте спецификацию ACPI для получения дополнительной информации.
источник