임베디드 프로그램이 완료되면 어떻게됩니까?


29

실행이 최종 return명령문에 도달 할 때 임베디드 프로세서에서 발생하는 상황 모든 것이 그대로 중지됩니다. 하늘에 하나의 영원한 NOP가있는 전력 소비 등? 또는 NOP가 지속적으로 실행됩니까? 아니면 프로세서가 완전히 종료됩니까?

내가 묻는 이유 중 하나는 프로세서가 실행을 마치기 전에 전원을 꺼야하는지, 그리고 사전에 전원을 끈 경우 어떻게 실행을 끝내는지 궁금합니다.


22
그것은 당신의 신념에 달려 있습니다. 어떤 이들은 환생 할 것이라고 말합니다.
Telaclavo

9
미사일입니까?
Lee Kowalkowski

6
일부 시스템은 HCF (Halt and Catch Fire) 명령을 지원합니다 . :)
Stefan Paul Noack

1
그것은 자기 파괴 루틴으로 분기 될 것입니다

답변:


41

아빠가 늘 물어 보신 질문입니다. " 왜 모든 지시 사항을 실행하고 마지막에 멈추지 않는가? "

병리학 적 예를 살펴 보겠습니다. 다음 코드는 PIC18 용 Microchip의 C18 컴파일러에서 컴파일되었습니다.

void main(void)
{

}

다음과 같은 어셈블러 출력을 생성합니다.

addr    opco     instruction
----    ----     -----------
0000    EF63     GOTO 0xc6
0002    F000     NOP
0004    0012     RETURN 0
.
. some instructions removed for brevity
.
00C6    EE15     LFSR 0x1, 0x500
00C8    F000     NOP
00CA    EE25     LFSR 0x2, 0x500
00CC    F000     NOP
.
. some instructions removed for brevity
.
00D6    EC72     CALL 0xe4, 0            // Call the initialisation code
00D8    F000     NOP                     //  
00DA    EC71     CALL 0xe2, 0            // Here we call main()
00DC    F000     NOP                     // 
00DE    D7FB     BRA 0xd6                // Jump back to address 00D6
.
. some instructions removed for brevity
.

00E2    0012     RETURN 0                // This is main()

00E4    0012     RETURN 0                // This is the initialisation code

보시다시피 main ()이 호출되고 결국 명시 적으로 넣지 않았지만 return 문이 포함됩니다. 메인이 돌아 오면 CPU는 코드의 시작 부분으로 돌아 가기 위해 단순히 GOTO 인 다음 명령어를 실행합니다. main ()은 단순히 반복해서 호출됩니다.

자, 이것이 말했듯이, 이것은 사람들이 일반적으로 일하는 방식이 아닙니다. main ()이 그런 식으로 종료되도록 내장 코드를 작성한 적이 없습니다. 대부분 내 코드는 다음과 같습니다.

void main(void)
{
    while(1)
    {
        wait_timer();
        do_some_task();
    }    
}

그래서 나는 보통 main ()을 끝내지 않을 것입니다.

"좋아." 이 모든 것은 컴파일러가 마지막 return 문이 없다는 것을 확신한다는 점에서 매우 흥미 롭습니다. 그러나 우리가 문제를 강요하면 어떻게됩니까? 어셈블러를 직접 코딩하고 처음으로 돌아 가지 않으면 어떻게됩니까?

분명히 CPU는 다음 명령을 계속 실행합니다. 그것들은 다음과 같이 보일 것입니다 :

addr    opco     instruction
----    ----     -----------
00E6    FFFF     NOP
00E8    FFFF     NOP
00EA    FFFF     NOP
00EB    FFFF     NOP
.
. some instructions removed for brevity
.
7EE8    FFFF     NOP
7FFA    FFFF     NOP
7FFC    FFFF     NOP
7FFE    FFFF     NOP

main ()에서 마지막 명령어 이후의 다음 메모리 주소가 비어 있습니다. FLASH 메모리가있는 마이크로 컨트롤러에서 빈 명령어에는 값 0xFFFF가 포함됩니다. PIC에서 최소한 해당 op 코드는 'nop'또는 'no operation'으로 해석됩니다. 단순히 아무것도하지 않습니다. CPU는 메모리에서 끝까지 해당 nops를 계속 실행합니다.

그 후 뭐야?

마지막 명령어에서 CPU의 명령어 포인터는 0x7FFe입니다. CPU가 명령 포인터에 2를 추가하면 32k FLASH 만있는 PIC의 오버플로로 간주되는 0x8000을 얻으므로 0x0000으로 다시 감싸고 CPU는 코드 시작 부분에서 명령을 계속 실행합니다. 마치 마치 재설정 된 것처럼.


또한 전원을 꺼야하는지 물었습니다. 기본적으로 원하는대로 할 수 있으며 응용 프로그램에 따라 다릅니다.

전원을 켠 후 한 가지 작업 만하면되는 응용 프로그램이 있고 다른 작업을 수행하지 않으면 잠시만 기다릴 수 있습니다 (1); CPU가 눈에 띄는 것을 멈추도록 main ()의 끝에.

응용 프로그램에서 CPU의 전원을 꺼야하는 경우 CPU에 따라 사용 가능한 다양한 절전 모드가있을 수 있습니다. 그러나 CPU는 다시 깨우는 습관이 있으므로 잠자기 시간 제한이없고 워치 독 타이머가 활성화되어 있지 않은지 확인해야합니다.

CPU가 완료되면 자체 전원을 완전히 차단할 수있는 외부 회로를 구성 할 수도 있습니다. 이 질문을 참고하십시오 : 순간적인 푸시 버튼을 래칭 온-오프 토글 스위치로 사용 .


20

컴파일 된 코드의 경우 컴파일러에 따라 다릅니다. 내가 사용하는 Rowley CrossWorks gcc ARM 컴파일러는 무한 루프가있는 crt0.s 파일의 코드로 이동합니다. 16 비트 dsPIC 및 PIC24 장치 (gcc 기반) 용 Microchip C30 컴파일러는 프로세서를 재설정합니다.

물론 대부분의 임베디드 소프트웨어는 그런 식으로 종료되지 않으며 루프에서 지속적으로 코드를 실행합니다.


13

여기에는 두 가지 사항이 있습니다.

  • 엄밀히 말하면 내장 된 프로그램은 "종료"할 수 없습니다.
  • 임베디드 프로그램을 얼마 동안 실행 한 다음 "완료"할 필요는 거의 없습니다.

프로그램 종료 개념은 일반적으로 임베디드 환경에 존재하지 않습니다. 낮은 수준에서 CPU는 가능한 동안 명령을 실행합니다. "최종 반환 진술"과 같은 것은 없습니다. CPU는 복구 할 수없는 결함이 발생하거나 명시 적으로 정지 된 경우 (절전 모드, 저전력 모드 등) 실행을 중지 할 수 있지만, 절전 모드 나 복구 할 수없는 결함 일지라도 일반적으로 더 이상 코드가 작동하지 않는다고 보장하지는 않습니다. 처형된다. 휴면 모드에서 깨어날 수 있으며 (일반적으로 사용되는 방식 임) 잠긴 CPU에서도 여전히 NMI 핸들러를 실행할 수 있습니다 (Cortex-M의 경우). 워치 독도 여전히 실행되며 일부 마이크로 컨트롤러에서 활성화 된 후에는이를 비활성화하지 못할 수 있습니다. 세부 사항은 아키텍처마다 크게 다릅니다.

C 또는 C ++와 같은 언어로 작성된 펌웨어의 경우 main () 종료가 시작 코드에 의해 결정되면 어떻게됩니까? 예를 들어, 다음은 STM32 표준 주변 라이브러리의 시작 코드와 관련된 부분입니다 (GNU 툴체인의 경우 주석은 내 것입니다).

Reset_Handler:  
  /*  ...  */
  bl  main    ; call main(), lr points to next instruction
  bx  lr      ; infinite loop

이 코드는 main ()이 반환 될 때 무한 루프에 들어갑니다 (비 명확한 방식으로 ( 실제로 점프하는 다음 명령어의 주소로 bl main로드 lr)). CPU를 정지 시키거나 저전력 모드 등으로 들어 가려는 시도는 없습니다. 응용 프로그램에서 합법적 인 요구가있는 경우 직접 처리해야합니다.

ARMv7-M ARM A2.3.1에 지정된대로 재설정시 링크 레지스터는 0xFFFFFFFF로 설정되며 해당 주소로 분기하면 오류가 발생합니다. 그래서 Cortex-M의 설계자들은 리셋 핸들러로부터의 리턴을 비정상으로 취급하기로 결정했으며, 그것들과 논쟁하기가 어렵습니다.

펌웨어가 완료된 후 CPU를 중지해야하는 합법적 인 필요성에 대해 말하면 장치의 전원을 차단해도 더 이상 제공되지 않는 것은 상상하기 어렵습니다. (CPU를 "좋게"비활성화하면 장치에 수행 할 수있는 유일한 작업은 전원주기 또는 외부 하드웨어 재설정입니다.) DC / DC 변환기에 대한 ENABLE 신호를 비활성화하거나 전원 공급 장치를 끌 수 있습니다. ATX PC와 같은 다른 방법.


1
"잠자기 모드 (일반적으로 사용되는 방식)에서 깨울 수 있으며 잠긴 CPU조차도 여전히 NMI 핸들러를 실행할 수 있습니다 (이것은 Cortex-M의 경우입니다)."<- 책이나 영화 줄거리. :)
Mark Allen

"bl main"은 다음 명령어의 주소 ( "bx lr")와 함께 "lr"을로드합니까? "bx lr"이 실행될 때 "lr"에 다른 내용이 포함될 것으로 예상되는 이유가 있습니까?
supercat

@ supercat : 당신은 물론입니다. 오류를 제거하고 조금 확장하기 위해 답변을 편집했습니다. 이것에 대해 생각하면,이 루프를 구현하는 방식은 매우 이상합니다. 그들은 쉽게 할 수있었습니다 loop: b loop. 나는 그들이 실제로 반환을 의미하지만 저장하는 것을 잊었는지 궁금합니다 lr.
가시

궁금하다. 많은 ARM 코드가 진입시 보유 한 것과 동일한 값을 유지하면서 LR로 종료 될 것으로 기대하지만 보장되지는 않습니다. 이러한 보증은 종종 유용하지는 않지만 r14를 다른 레지스터에 복사 한 다음 다른 루틴을 호출하는 루틴에 명령을 추가해야합니다. lr이 반환시 "알 수 없음"으로 간주되면 저장된 사본을 보유한 레지스터를 "bx"할 수 있습니다. 그러나 표시된 코드에서는 매우 이상한 동작이 발생합니다.
supercat

실제로 리프가 아닌 함수가 lr을 절약 할 것으로 확신합니다. 이들은 일반적으로 프롤로그의 스택에 lr을 푸시하고 저장된 값을 pc에 팝하여 반환합니다. 예를 들어 C 또는 C ++ main ()이하는 일이지만 문제의 라이브러리 개발자는 Reset_Handler에서 이와 같은 작업을 수행하지 않았습니다.
가시

9

에 대해 질문 할 때 return너무 높은 수준으로 생각하고 있습니다. C 코드는 기계 코드로 변환됩니다. 따라서 프로세서가 맹목적으로 메모리에서 명령어를 가져 와서 실행하는 것에 대해 생각한다면 어떤 명령이 "최종"인지 알 수 없습니다 return. 따라서 프로세서에는 고유 한 목적이 없지만 대신 최종 사례를 처리하는 것은 프로그래머의 책임입니다. Leon이 그의 대답에서 지적한 것처럼 컴파일러는 기본 동작을 프로그래밍했지만 프로그래머가 종종 자체 종료 시퀀스를 원할 수도 있습니다 (저전력 모드로 들어가거나 정지하거나 USB 케이블이 연결되기를 기다리는 등의 다양한 작업을 수행했습니다) 다시 부팅).

많은 마이크로 프로세서에는 중지 명령이있어 주변 장치에 영향을주지 않고 프로세서를 중지합니다. 다른 프로세서는 단순히 같은 주소로 반복해서 점프하여 "정지"에 의존 할 수 있습니다. 옵션이있을 수 있지만 프로세서는 메모리가 명령이 아닌 경우에도 메모리에서 명령을 계속 읽게되므로 프로그래머에게 달려 있습니다.


7

이 문제는 임베디드 (임베디드 시스템에서 Linux 또는 Windows를 실행할 수 있음)가 아니라 독립형 또는 베어 메탈입니다. (컴파일 된) 응용 프로그램은 컴퓨터에서 실행되는 유일한 프로그램입니다. 마이크로 컨트롤러 또는 마이크로 프로세서).

대부분의 언어에서 언어는 'main'이 종료되고 리턴 할 OS가 없을 때 발생하는 상황을 정의하지 않습니다. C의 경우 시작 파일에있는 내용 (종종 crt0.s)에 따라 다릅니다. 대부분의 경우 사용자는 시작 코드를 제공 할 수 있거나 제공해야하므로 최종 답변은 사용자가 작성하는 것이 시작 코드이거나 지정한 시작 코드에있는 것입니다.

실제로 3 가지 접근 방식이 있습니다.

  • 특별한 조치를 취하지 마십시오. 주요 수익률이 정의되지 않은 경우 어떻게됩니까?

  • 0으로 이동하거나 다른 방법을 사용하여 응용 프로그램을 다시 시작하십시오.

  • 프로세서를 영구적으로 잠그는 단단한 루프 (또는 인터럽트 비활성화 및 중지 명령 실행)를 입력하십시오.

적절한 것은 응용 프로그램에 따라 다릅니다. fur-elise 인사 장과 브레이크 제어 시스템 (2 개의 내장형 시스템을 언급 할 것임)은 재시작해야합니다. 재시작의 단점은 문제가 눈에 띄지 않을 수 있다는 것입니다.


5

나는 다른 날에 ATtiny45 디스 어셈블 (avr-gcc로 컴파일 된 C ++) 코드를보고 있었고 코드 끝에서 수행하는 작업은 0x0000으로 이동합니다. 기본적으로 재설정 / 재시작

컴파일러 / 어셈블러에서 0x0000으로의 마지막 점프를 생략하면 프로그램 메모리의 모든 바이트가 '유효한'기계 코드로 해석되며 프로그램 카운터가 0x0000으로 롤오버 될 때까지 계속 실행됩니다.

AVR에서 00 바이트 (셀이 비어있는 경우 기본값)는 NOP = 작동 없음입니다. 따라서 시간이 걸리는 것 외에는 아무것도하지 않습니다.


1

일반적으로 컴파일 된 main코드는 나중에 시작 코드와 연결됩니다 (칩 공급 업체에서 제공 한 도구 체인에 통합되어 사용자가 작성하는 등).

그런 다음 링커는 모든 응용 프로그램 및 시작 코드를 메모리 세그먼트에 배치하므로 질문에 대한 답변은 다음에 따라 다릅니다. 1. 시작 코드 : 예를 들면 다음과 같습니다.

  • 빈 루프 ( bl lr또는 b .)로 끝납니다. "프로그램 끝"과 비슷하지만 이전에 활성화 된 인터럽트 및 주변 장치는 여전히 작동합니다.
  • 프로그램 시작으로 점프하여 종료하십시오 (시작을 완전히 다시 실행하거나 jsut to main).
  • main리턴 호출 후 "다음에 무엇이 될지"를 무시하십시오 .

    1. 세 번째 글 머리 기호에서, main동작 에서 복귀 한 후 프로그램 카운터가 단순히 증가 하면 링커 (및 / 또는 링크 중에 사용 된 링커 스크립트)에 따라 달라집니다.
  • 다른 함수 / 코드가 main유효하지 않은 / 정의되지 않은 인수 값으로 실행 된 후에 배치 되면,

  • 다음 메모리가 잘못된 명령 예외로 시작하면 migh가 생성되고 결국 MCU가 재설정됩니다 (예외가 재설정되는 경우).

워치 독이 활성화되면 모든 무한 루프에도 불구하고 결국 MCU를 재설정합니다 (물론 다시로드되지 않는 경우).


-1

임베디드 장치를 중지하는 가장 좋은 방법은 NOP 명령으로 영원히 기다리는 것입니다.

두 번째 방법은 장치 자체를 사용하여 장치를 닫는 것입니다. 당신이 당신의 지시에 릴레이를 제어 할 수있는 경우에, 당신은 당신의 임베디드 장치에 전원을 공급하고 스위치를 열 수 임베디드 장치없이 소비 전력 사라를.


그것은 실제로 질문에 대답하지 않습니다.
Matt Young

-4

설명서에 명확하게 설명되어 있습니다. 일반적으로 CPU는 스택 세그먼트 외부에있는 메모리 위치에 액세스하기 때문에 일반적인 예외가 발생합니다. [메모리 보호 예외].

임베디드 시스템의 의미는 무엇입니까? 마이크로 프로세서 또는 마이크로 컨트롤러 어느 쪽이든 설명서에 정의되어 있습니다.

x86 CPU에서는 ACIP 컨트롤러로 명령을 보내서 컴퓨터를 끕니다. 시스템 관리 모드로 들어갑니다. 따라서 컨트롤러는 I / O 칩이므로 수동으로 끌 필요가 없습니다.

자세한 내용은 ACPI 사양을 읽으십시오.


3
-1 : TS가 특정 CPU를 언급하지 않았으므로 너무 많이 가정하지 마십시오. 다른 시스템은이 사례를 매우 다른 방식으로 처리합니다.
Wouter van Ooijen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.