O que acontece em um processador incorporado quando a execução atinge essa return
afirmação final Tudo fica congelado como está; consumo de energia etc, com um NOP eterno longo no céu? ou os NOPs são executados continuamente ou o processador será desligado completamente?
Parte do motivo pelo qual pergunto é: estou me perguntando se um processador precisa desligar antes de concluir a execução e se o faz, como termina a execução se já desligou antes?
Respostas:
Essa é uma pergunta que meu pai sempre me perguntava. " Por que simplesmente não percorre todas as instruções e pára no final? "
Vamos dar uma olhada em um exemplo patológico. O código a seguir foi compilado no compilador C18 da Microchip para o PIC18:
Produz a seguinte saída do assembler:
Como você pode ver, main () é chamado e, no final, contém uma declaração de retorno, embora não tenhamos explicitamente colocado lá. Quando main retorna, a CPU executa a próxima instrução, que é simplesmente um GOTO para voltar ao início do código. main () é simplesmente chamado repetidamente.
Agora, tendo dito isso, não é assim que as pessoas costumam fazer as coisas. Eu nunca escrevi nenhum código incorporado que permita que o main () saia assim. Principalmente, meu código seria algo como isto:
Então, eu normalmente nunca deixaria main () sair.
"OK ok" você está dizendo. Tudo isso é muito interessante que o compilador garante que nunca haja uma última declaração de retorno. Mas o que acontece se forçarmos o problema? E se eu codificasse manualmente meu montador e não voltasse ao começo?
Bem, obviamente, a CPU continuaria executando as próximas instruções. Aqueles seriam algo como isto:
O próximo endereço de memória após a última instrução em main () está vazio. Em um microcontrolador com memória FLASH, uma instrução vazia contém o valor 0xFFFF. Em um PIC, pelo menos, esse código operacional é interpretado como um 'nop' ou 'nenhuma operação'. Simplesmente não faz nada. A CPU continuaria executando esses nops por toda a memória até o fim.
O que é depois disso?
Na última instrução, o ponteiro de instrução da CPU é 0x7FFe. Quando a CPU adiciona 2 ao ponteiro de instruções, obtém 0x8000, que é considerado um estouro em uma PIC com apenas 32k FLASH, e volta para 0x0000, e a CPU continua felizmente executando as instruções no início do código , como se tivesse sido redefinido.
Você também perguntou sobre a necessidade de desligar. Basicamente, você pode fazer o que quiser, e isso depende da sua aplicação.
Se você tinha um aplicativo que só precisava fazer uma coisa depois de ligar, e não fazer mais nada, você poderia esperar um pouco (1); no final de main () para que a CPU pare de fazer qualquer coisa perceptível.
Se o aplicativo exigir que a CPU seja desligada, dependendo da CPU, provavelmente haverá vários modos de suspensão disponíveis. No entanto, as CPUs têm o hábito de acordar novamente, portanto, você deve garantir que não haja limite de tempo para dormir e que o Watch Dog Timer esteja ativo etc.
Você pode até organizar alguns circuitos externos que permitiriam à CPU cortar completamente sua própria energia quando ela terminasse. Veja esta pergunta: Usando um botão momentâneo como uma chave seletora liga / desliga .
fonte
Para código compilado, isso depende do compilador. O compilador Rowley CrossWorks gcc ARM que eu uso salta para codificar no arquivo crt0.s que possui um loop infinito. O compilador Microchip C30 para os dispositivos dsPIC e PIC24 de 16 bits (também baseados em gcc) redefine o processador.
Obviamente, a maioria dos softwares incorporados nunca termina assim e executa o código continuamente em um loop.
fonte
Há dois pontos a serem feitos aqui:
O conceito de desligamento de um programa normalmente não existe em um ambiente incorporado. Em um nível baixo, uma CPU executa instruções enquanto pode; não existe uma "declaração final de retorno". Uma CPU pode interromper a execução se encontrar uma falha irrecuperável ou se for interrompida explicitamente (coloque no modo de suspensão, modo de baixa energia etc.), mas observe que mesmo os modos de suspensão ou falhas irrecuperáveis geralmente não garantem que não haja mais código. ser executado. Você pode ativar a partir dos modos de suspensão (é assim que normalmente são usados) e até mesmo uma CPU bloqueada ainda pode executar um manipulador de NMI (este é o caso do Cortex-M). Um watchdog ainda será executado também, e talvez você não consiga desabilitá-lo em alguns microcontroladores depois de habilitado. Os detalhes variam muito entre as arquiteturas.
No caso de firmware escrito em um idioma como C ou C ++, o que acontece se a saída main () for determinada pelo código de inicialização. Por exemplo, aqui está a parte relevante do código de inicialização da STM32 Standard Peripheral Library (para uma cadeia de ferramentas GNU, os comentários são meus):
Este código entrará em um loop infinito quando main () retornar, embora de uma maneira não óbvia (
bl main
carreguelr
com o endereço da próxima instrução que é efetivamente um salto para si mesmo). Não são feitas tentativas para interromper a CPU ou fazê-la entrar no modo de baixo consumo de energia, etc. Se você tiver uma necessidade legítima de algo disso em seu aplicativo, precisará fazer isso sozinho.Observe que, conforme especificado no ARMv7-M ARM A2.3.1, o registro do link é definido como 0xFFFFFFFF na redefinição e uma ramificação para esse endereço acionará uma falha. Portanto, os designers do Cortex-M decidiram tratar um retorno do manipulador de redefinição como anormal, e é difícil argumentar com eles.
Falando de uma necessidade legítima de interromper a CPU após a conclusão do firmware, é difícil imaginar um que não seria melhor atendido pelo desligamento do seu dispositivo. (Se você desativar a CPU "para sempre", a única coisa que pode ser feita ao seu dispositivo é um ciclo de energia ou redefinição de hardware externo.) Você pode desativar o sinal ENABLE para o seu conversor DC / DC ou desligar a fonte de alimentação. de alguma outra maneira, como um PC ATX faz.
fonte
loop: b loop
. Gostaria de saber se eles realmente pretendiam retornar, mas se esqueceram de economizarlr
.When asking about
return
, you're thinking too high level. The C code is translated into machine code. So, if you instead think about the processor blindly pulling instructions out of memory and executing them, it has no idea which one is the "final"return
. So, processors have no inherent end, but instead it's up to the programmer to handle the end case. As Leon points out in his answer, compilers have programmed a default behavior, but often times the programmer may want their own shutdown sequence (I have done various things like entering a low power mode and halting, or waiting for a USB cable to get plugged in and then rebooting).Many microprocessors have halt instructions, which stops the processor without affecting perhiperals. Other processors may rely on "halting" by simply just jumping to the same address repeatedly. There are may options, but it's up to the programmer because the processor will simply keep reading instructions from meory, even if that memory wasn't intented to be instructions.
fonte
The issue is not embedded (an embedded system can run Linux or even Windows) but stand-alone or bare-metal: the (compiled) application program is the only thing that is running on the computer (It does not matter if it is a microcontroller or microprocessor).
For most languages the language does not define what happens when the 'main' terminates and there is no OS to return to. For C it depends on what is in the startupfile (often crt0.s). In most cases the user can (or even must) supply the startup code, so the final answer is: whatever you write is the startup code, or what happens to be in the startup code you specify.
In practice there are 3 approaches:
take no special measures. what happens when the main returns is undefined.
jump to 0, or use any other means to restart the application.
enter a tight loop (or disabling interrupts and executing a halt instruction), locking up the processor forever.
What is appropriate depends on the application. A fur-elise greeting card and a brake-control-system (just to mention two embedded systems) should probably restart. The downside of restarting is that the problem might go unnoticed.
fonte
I was looking at some ATtiny45 disassembled (C++ compiled by avr-gcc) code the other day and what it does at the end of the code is jump to 0x0000. Basically doing a reset/restart.
If that last jump to 0x0000 is being left out by the compiler/assembler, all bytes in program memory are interpreted as 'valid' machine code and it runs all the way until the program counter rolls over to 0x0000.
On AVR a 00 byte (de default value when a cell is empty) is a NOP = No Operation. So it runs really quickly, doing nothing but just taking some time.
fonte
Generally compiled
main
code is afterwards linked with startup code (it might be integrated into toolchain, provided by chip vendor, written by you etc.).Linker then places all application and startup code in memory segments, so answer to you questions depends on: 1. code from startup, because it can for example:
bl lr
orb .
), which will be similar to "program end", but interrupts and peripherals enabled previously will still operate,main
).simply ignore "what will be next" after call to
main
returns.main
behavior will depend on you linker (and/or linker script used during linking).If other function/code is placed after your
main
it will be executed with invalid/undefined argument values,If watchdog is enabled, it will eventually reset MCU despite all endless loops you are in (of course if it will be not reloaded).
fonte
The best way to stop an embedded device is to wait forever with NOP instructions.
The second way is to closing the device by using device itself. If you can control a relay with your instructions, you can just open the switch which is powering your embedded device and huh your embedded device is gone with no power consumption.
fonte
It was clearly explained in the manual. Typically an general exception will be thrown by the CPU because it will access a memory location which is outside the stack segment. [ memory protection exception ].
What did you meant by the embedded system? Microprocessor or microcontroller ?Either ways , it's defined on the manual.
In x86 CPU we turn off the computer by sending the command to the ACIP controller. Entering the System Management Mode. So that controller is a I/O chip and you don't need to manually turn it off.
Read the ACPI specification for more information.
fonte