제가 stm32f411로 테트트하다 보니, 가끔 인터럽트를 사용하면 이상동작을 하는 경우가 있어서,

이전에 만든 DWT Delay 함수를 사용하지 못해서 Polling 으로 micro second Delay 함수를 또 찾아봤습니다.

정말 간단하게 만들 수 있었습니다. 아주 정확하지는 않겠지만, 
system 클럭의 정보를 바탕으로 1clk 당 실행시간을 계산해서 us Delay를 만들어 내는 것으로 보입니다.
따라서 system clk 이 바뀌더라도 대충 맞는 그런그런 정도(아주 정밀하지는 않음)의 딜레이 함수입니다.

제가 구글링에서 참고한 사이트는 다음과 같습니다.

그리고 제가 사용자 함수를 모아 놓는 파일인 user_def.c 와 user_def.h 가 있는데,
user_def.h 파일에만 다음과 같은 함수를 정의해 놓습니다.
1
2
3
4
5
6
7
8
__STATIC_INLINE void Pol_Delay_us(volatile uint32_t microseconds)
{
  /* Go to number of cycles for system */
  microseconds *= (SystemCoreClock / 1000000);
 
  /* Delay till end */
  while (microseconds--);
}
cs


그리고 이 user_def.h 를 인클루드한 소스파일에서 다음과 같이 사용하면 됩니다.
1
2
3
    Pol_Delay_us(50);        // Polling 50us
    //DWT_Delay_us(100);    // DWT 100us
    //HAL_Delay(1);            // HAL Library 1ms
cs


라이브러리로 제공되는 함수가 milisec 함수(HAL_Delay()) 는 있는데,

가끔 가다가 필요한 us 함수를 구글링해서 찾았고, 잘 동작합니다.

링크는 다음과 같습니다. 
https://community.st.com/thread/13838 에서 Knut Knusper 가 쓴 글을 참조하시면 됩니다.

cubemx 로 여러가지 테스트해보다 보면 실수로 User code 부분이 싹~ 날아가는 경우가 많아서,
이곳에 코드를 다시 정리해 봅니다.

저는 user_def.c 라는 파일을 하나 만들어서 cubemx 에서 갑자기 지워지는 것을 막기 위해 필요한 함수를 정의해 놓아서,
새로 추가된 DWT_Delay_Init() 함수는 이곳에 정의해 놓았습니다.

1. user_def.c 에 다음의 코드를 추가
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
uint32_t DWT_Delay_Init(void) {
  /* Disable TRC */
  CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk; // ~0x01000000;
  /* Enable TRC */
  CoreDebug->DEMCR |=  CoreDebug_DEMCR_TRCENA_Msk; // 0x01000000;
     
  /* Disable clock cycle counter */
  DWT->CTRL &= ~DWT_CTRL_CYCCNTENA_Msk; //~0x00000001;
  /* Enable  clock cycle counter */
  DWT->CTRL |=  DWT_CTRL_CYCCNTENA_Msk; //0x00000001;
     
  /* Reset the clock cycle counter value */
  DWT->CYCCNT = 0;
     
     /* 3 NO OPERATION instructions */
     __ASM volatile ("NOP");
     __ASM volatile ("NOP");
  __ASM volatile ("NOP");
 
  /* Check if clock cycle counter has started */
     if(DWT->CYCCNT)
     {
       return 0/*clock cycle counter started*/
     }
     else
  {
    return 1/*clock cycle counter not started*/
  }
}
cs

2. user_def.h 에 다음의 코드 추가
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
uint32_t DWT_Delay_Init(void);
 
 
 
/**
 * @brief  This function provides a delay (in microseconds)
 * @param  microseconds: delay in microseconds
 */
__STATIC_INLINE void DWT_Delay_us(volatile uint32_t microseconds)
{
  uint32_t clk_cycle_start = DWT->CYCCNT;
 
  /* Go to number of cycles for system */
  microseconds *= (HAL_RCC_GetHCLKFreq() / 1000000);
 
  /* Delay till end */
  while ((DWT->CYCCNT - clk_cycle_start) < microseconds);
}
cs


3. main.c 의 main() 함수에서 us Delay 함수(DWT_Delay_us()) 사용.
1
2
3
4
5
6
    while(1)
    {
        HAL_GPIO_TogglePin(IND_LED_FL_GPIO_Port,IND_LED_FL_Pin);
        DWT_Delay_us(1000000);    // 1sec
    }
 
cs


1000,000 us (1 sec) 마다 GPIO 가 토글되는 것을 확인했으니, 동작이 잘 되네요. ^^


+ Recent posts