티스토리 뷰

embedded

Atmega 328p - Software reset

주먹불끈 2019. 1. 16. 16:10

개요

 

원문 참고링크: https://www.codeproject.com/Articles/1012319/Arduino-Software-Reset

 

임베디드 시스템에도 오동작등 다양한 이유로 재부팅을 해야할 경우가 있다.

(Arduino 이지만) 참고 링크에서는 가지 방법을 소개하고 있으며,

중에서 추천하고 있는 Watchdog Reset 소개해본다.

 

TL;DR

 

아래 코드를 쓰시오.

 

#include <avr/wdt.h>

void softwareReset( uint8_t prescaller) {
 
// start watchdog with the provided prescaller
  wdt_enable( prescaller);
 
// wait for the prescaller time to expire
 
// without sending the reset signal by using
 
// the wdt_reset() method
 
while(1) {}
}

void setup() { // add setup code here...}

void loop() {
 
// ... various code...

// restart in 60 milliseconds
  softwareReset( WDTO_60MS);
}

 

Watchdog 프로세스

 

1) Watchdog Enable 한다.

2) 이때 설정한 시간내에 Watchdog reset (혹은 clear)  하지 않으면 Watchdog reset 걸린다.

 

이를 활용하여

1) Watchdog Enable 다음

2) 무한루프를 돌려서 Watchdog reset 걸리게 강제하여 Software reset 하게 만든다.

 

 

TroubleShooting

 

Q. 이상하게 이렇게 reset 되고 나면 계속 reset

- main() 에서 시작하자 마자 wdt_disable() 먹여도 안됨

 

A. 아래 공식 언급을 참고할

- WDT reset 되고 나서도 살아있음. (except power on reset)

- 심지어는 15ms 내에 wdt_reset() 먹여주지 않으면 리셋이

- 그래서 아예 main() 함수를 타기 전에 MCUSR 레지스터를 리셋해주고, wdt_disable() 해주어야 한다.

 

- 공식언급: https://www.microchip.com/webdoc/AVRLibcReferenceManual/group__avr__watchdog.html

 

Note that for newer devices (ATmega88 and newer, effectively any AVR that has the option to also generate interrupts), the watchdog timer remains active even after a system reset (except a power-on condition), using the fastest prescaler value (approximately 15 ms). It is therefore required to turn off the watchdog early during program startup, the datasheet recommends a sequence like the following:

 

 

main() 함수보다 빠른 실행

 

어떻게 main() 함수의 실행 이전에 코드를 먹일 있는가?

디테일한 설명을 생략하면, 함수를 main() 함수 이전에 실행되는 영역에 두면 된다.

 

공식 링크: https://goo.gl/9ZG2xc

 

#include <stdint.h>

#include <avr/wdt.h>

 

uint8_t mcusr_mirror __attribute__ ((section (".noinit")));

void get_mcusr(void) \

  __attribute__((naked)) \

  __attribute__((section(".init3")));

void get_mcusr(void)

{

  mcusr_mirror = MCUSR;

  MCUSR = 0;

  wdt_disable();

}

int main(void

{

  //get_mcusr();

  wdt_enable(WDTO_2S);

  ...

  while(1) {

    ...

    wdt_reset();

    ...

  }

}

1) mcuser_mirror 변수는 .noinit 영역에 메모리를 할당한다.

- 초기 부팅시 등등 다양한 상황에서도 지워지지 않게 해줌

 

2) get_mcusr() 함수는 .init3 영역에 써준다.

- 영역에 써두면 부팅시에 자동으로

- main() 함수 이전에 실행이 되는 것이다.

1) reset 원인을 MCUSR 레지스터에서 복사해두고

2) MCUSR 레지스터는 0으로 초기화 해준다.

3) 그리고 (15ms 이전에) wdt_disable() 해준다.

이제 언제든 mcusr_mirror 변수를 보면 리셋의 원인을 있다.

 

(주의) get_mcusr() 함수는 자동으로 실행된다.

- main() 함수내에서 실행시키면 오동작한다.

* 왼쪽 코드에서는 참고삼아 코멘트 처리 해두었다.

* 참고링크: https://www.avrfreaks.net/forum/watch-dog-question

You're not suppose to call get_mcusr() in main().

the attribute section(".init3") puts the code in before main() so it runs automatically before entering main().

 


반응형
반응형
잡학툰 뱃지
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/03   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함