NUCLEO-STM32F429ZI 보드를 사용했습니다.
(STM32F429 discovery 보드는 핀 번호가 달라서 핀 번호 설정만 바꿔서 하면 된다.)



IWDG 이해


iwdg은 카운트 다운을 하며, 일정신호를 주기적으로 보내는 정상 작동이 아닌 경우, 카운트 값을 갱신하지 않고 카운팅을 계속하여 0이 되면 시스템을 리셋한다.

iwdg은 내부의 LSI클럭을 이용하는 독립된 구조이다. RCC와 연결된 CSR이라는 레지스터로 LSI클럭을 onoff하는 비트가 있는데, 이걸로 IWDG의 실행에 영향을 주지 않는다.
iwdg는 한 번 CCCC로 enable되면, 끌 수 없다.
ST의 다른 칩들에서는 desable할 수도 있는데 이 보드는 끌 수없도록 설계되었다고 볼 수 있다.

WWDG와 다른점은 메인 클럭이 고장나도 독립적으로 작동을 유지한다는 것이다.

iwdg 레지스터제어로 구현해보기


다이어그램에 있는 iwdg의 작동을 제어하는 레지스터를 레퍼런스에서 찾아본다.

1. IWDG->KR(key register)


IWDR->KR에 5555값을 주면 PR(prescale),RLR(reload)레지스터에 접근할 수 있다.
왜 이런 방식으로 접근하는 이유는 실수로 watchdog 제어에 관련된 레지스터에 접근하는 것을 방지하는 것이다.
CCCC : iwdg 카운트 다운 시작.
AAAA : iwdg의 reload(카운트값)을 갱신. (정상작동 시 리셋되지않도록 계속 갱신해준다)





2. IWDG->PR(Prescaler register)


LSI클럭을 사용하는 iwdg의 클럭 값을 prescale로 divide해줄 수 있다. 표에 맞게 설정하면 된다.



3. IWDG->RLR(Reload register)


카운트 값을 12비트, 즉 4095내로 넣어준다.
그럼 0까지 down count한다.



4. RCC->CSR(clock control, status register)

 


iwdg reset에 의해 flag되는 29번 비트를 24번 remove비트로 지워줄 수 있다. 이 두 개를 사용해서 코드를 구현해본다.


근데 LSI osc와 관련된 비트가 있는데 이걸 해봤더니, 소용이 없다. 왜냐면 앞에서 레퍼런스에 나와있듯, iwdg이 한 번 실행되면 LSI클럭을 끌 수 없다. 그리고 이 레지스터에서의 0번 비트의 reset value도 0인데, 1로 on해주지 않고도 iwdg카운트를 시작해도 된다.
처음에 레지스터에 이 비트때문에 클럭 on해줘야하는건지 헷갈렸다. iwdg은 RCC의 경로와 다른 내부의 LSI클럭을 가지는 독립된 구조이다.

RCC→ CSR에 LSI클럭을 onoff하는 비트가 있지만, iwdg의 경우, 클럭 on off에 영향 받지 않고 동작한다. Iwdg은 시스템의 안전을 위한 장치이기 때문에, 소프트웨어 설정으로 멈출 수 없고, 한 번 시작되면 오직 reset에 의해서만 멈춘다.

코드 구현

iwdg에 의한 리셋을 확인해보는 코드이다.
uart3으로 Tera Term으로 메세지 출력해서 확인해보았다.

//처음엔 first try 출력, 두번째부터 reset by IWDG2 출력
void uart3_init(void){
    RCC->AHB1ENR |= 1<<3;//GPIOD
    RCC->APB1ENR |= 1<<18;//USART3

    //PD8,9 AF모드
    GPIOD->MODER &= ~((0x3<< (2*8))| (0x3<<(2*9)));
    GPIOD->MODER |=((0x2<<(2*8)) | (0x2<<(2*9)));

    GPIOD->AFR[1]&= ~(0xf<<4 | 0xf<<0);//MUX PD8,9(AFRH 8~15)
    GPIOD->AFR[1] |= (0x7<<4 | 0x7<<0);//uart3

    USART3->CR1 =(0<<15 |1<<13 | 0<<12 |0<<10 | 1<<3 | 1<<2);
    USART3->BRR=(22 << 4) | 13;//115200bps,42MHZ =356

}

void uart3_send(char c){
    while(!(USART3->SR>>7 &0x1));
    USART3->DR=c;
}

void uart3_printf(const char* str){
    while(*str){
        uart3_send(*str++);
    }
}

char msg[100];

void iwdg_init(void){
    IWDG->KR=0x5555;//enable access to PR,RLR
    IWDG->PR |=0x3; //divided by 32
    IWDG->RLR= 4096-1; //count load
    IWDG->KR=0xAAAA;//update
    IWDG->KR=0xCCCC;//start watchdog
    //Timeout = (4095 + 1) * 32 / 32000 = 4.096 sec
}

int main(void)
{
 HAL_Init();
  SystemClock_Config();
  uart3_init();

  if((RCC->CSR)&(0x1<<29)){
                  sprintf(msg,"%s","reset by IWDG2 ");
                  uart3_printf(msg);
                  RCC->CSR |= (0x1<<24);//리셋 Flag clear
                   while(1);
              }else{
                  sprintf(msg,"%s","first try");//IWDG 실행 전 리셋이 아직 되지않았을 때를 출력해서 확인.
                  uart3_printf(msg);
              }


  iwdg_init();
  while (1);//기다리다 타임 아웃 후 리셋되면 main다시 실행



}

보드에 있는 두 버튼 중 리셋 버튼을 누르면서 테스트 해본다. 보드 전원 연결(usb)을 해제했다가 다시 로드하고 해도된다.

+ Recent posts