티스토리 뷰

반응형

오늘은 굉장히 저가 이면서 아주 간단한 제어를 위해 사용하는 칩은 STM32F030의 파워 세이브 기능 구현에 대해서 이야기해보도록 하겠습니다. 사실 칩의 스펙은 날로 좋아지고 가격은 떨어지기 때문에 이 글을 쓸까 말까 고민을 했었지만 실제로 이 칩을 포함해서 양산하기도 했고 양산 문제가 나와서 중간에 펌웨어를 수정하면서 비용도 발생했기 때문에 큰 인사이트를 남긴 칩이기도 하기에 아주 많은 분들이 이 내용을 알 필요는 없겠지만 그래도 분명 검색했을 때 쉽게 나오는 내용은 아니어서 도움이 되실 수 있으면 좋겠습니다.

스펙

데이터 시트 : https://octopart.com/stm32f030f4p6-stmicroelectronics-30038871?gclid=Cj0KCQiApKagBhC1ARIsAFc7Mc5ZQIM74yUZkUK-K8mJTt_Dtx2xyiRSP1gxM6rnDBPpn3iyLmz02X0aAu7qEALw_wcB 

  • Core : ARM32 M0 CPU 48MHz
  • Memoery : 16 to 256 kb of Flash / 4 to 32 kb SRAM
  • Interfaces : 2 I2C, UART, 2 SPI, 16channel ADC, 6channel PWM

칩의 스펙은 대략 이정도인데요, 저는 STM32F030 에서도 가장 저렴한 STM32F030F4P6 을 사용했습니다.

따라서 16KB Flash에 4KB Ram을 가지고 있는데 과연 여기어 어떤 코딩을 얼마나 넣을 수 있을까 생각 했지만 홀센서에 의해서 전원이 인가되면 타이머가 돌고 타이머가 도는 동안에는 PWM으로 라이팅이 켜지고, 타이머 후에는 꺼지는 이정도 기능은 충분히 구현할 수 있었습니다. 절차지향 프로그램으로 쓰레드도 별도 필요없었는데요. 한가지 문제가 있었습니다.

대기전류

제가 만들었던 제품은 배터리가 있는 제품이라, 배터리에 대한 관리가 필요합니다. 다만 이 칩에서 성능을 봤을때 그렇게 현란한 테크닉의 배터리 관리 시스템을 만들 수 없었는데요. 문제는 어떠한 물리적인 방법으로 전원이 인가되었다가 다시 해제되었다가 하게 되면 전원을 켰을때만 사용하기 때문에 또 그닥 배터리 관리가 필요없을 수 없다고 생각 했었는데요. 위에서 말씀드린 시나리오를 보면 켰을때 일정시간 타이머 만큼 라이팅이 켜지고 꺼진다라고 말씀드렸죠? 라이팅은 꺼져있지만 사실 전원은 인가된 상태이기 때문에 대기전류가 발생하게 됩니다. 만약 전원을 아에 빼버리는 물리적인 방법을 쓰면 대기전류자체가 발생하지 않겠지만 이렇게 되면서 타이머 종료 후 꺼졌을 때 대기전류를 최소화 해야하는 문제가 생긴 것이죠.

문제에 대한 분석

실제 고객들의 컴플레인이 발생하고야 말았습니다, 대기전류가 20mA/5V 있다보니 타이머가 종료되어 라이팅이 꺼진 상태에서 그대로 방치하면 배터리가 하루안에 방전되고 말아서, 자꾸 충전해야한다는 컴플레인이 나왔는데요. 사실 테스트하는 과정에서 내부에서 사용하고 전원을 빼는 작업을 하기 때문에 사용자가 사용하는 패턴과 다르게 사용했기애 발견을 못했것이었습니다. 충분한 동작의 테스트는 되었지만 다양한 시나리오에 따라서 고객관점에 의해 테스트는 미진했던 부분이 결국 나오게 되었는데, 이렇게 단순한 기능일지라도 상품화 했을때 놓칠수 있음을 다시한번 깨닫게 되었습니다. 

문제 해결

이렇게 굉장히 기능이 적은 칩이라 할지라도 파워세이브를 할 수 있는 슬립모드 기능이 존재합니다. 데이터 시트를 보면 알수 있는데요. 아래와 같이 3가지 모드가 존재합니다.

  • Sleep Mode
    • Peripheral은 모두 깨어있고, CPU만 자고 있으므로 모든 인터럽트/이벤트에 일어날 수 있다.
  • Stop Mode
    • EXTI 라인으로 일어날 수 있다. (16개의 외부 라인 & RTC)
  • Standby Mode
    • NRST핀, IWDG 리셋, WKUP핀의 rise clock, RTC 이벤트에 일어날 수 있다.
  • 전력 소모량은 Sleep Mode > Stop Mode > Standby Mode 이며, 전력 소모량이 제일 낮은 Standby Mode는 NRST를 통한 깨우기밖에 불가능하다.

구현

Sleep Mode

assert_param(IS_PWR_REGULATOR(Regulator));
assert_param(IS_PWR_SLEEP_ENTRY(SLEEPEntry));
SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);
if(SLEEPEntry == PWR_SLEEPENTRY_WFI)
{
  /* Request Wait For Interrupt */
  __WFI();
}
else
{
  /* Request Wait For Event */
  __SEV();
  __WFE();
  __WFE();
}

Stop Mode

uint32_t tmpreg = 0;

assert_param(IS_PWR_REGULATOR(Regulator));
assert_param(IS_PWR_STOP_ENTRY(STOPEntry));
tmpreg = PWR->CR;
tmpreg &= (uint32_t)~(PWR_CR_PDDS | PWR_CR_LPDS);
tmpreg |= Regulator;

PWR->CR = tmpreg;
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;

if(STOPEntry == PWR_STOPENTRY_WFI)
{
  /* Request Wait For Interrupt */
  __WFI();
}
else
{
  /* Request Wait For Event */
  __SEV();
  __WFE();
  __WFE();
}

SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);

StandBy Mode

PWR->CR |= (uint32_t)PWR_CR_PDDS;
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
#if defined ( __CC_ARM)
  __force_stores();
#endif
/* Request Wait For Interrupt */
__WFI();

 

위 방법 중 가장 초절전하는 방법은 StandBy Mode 이기에 이 모드를 타이머가 종료되었을때 실행되도록 하고 대기전류를 다시 측정해보니 적용 전 20mA에서 5.5mA로 줄어들었습니다.

4배의 전류를 세이브하게 된 것인데요. 이렇다 보니 조금은 고객들의 불만을 잠재울 수 있을 거 같지만 배터리는 항상 부족하기에 그러함에도 배터리 문제에 대한 이슈는 계속 나올 수 있을 것 같습니다. 사실 해결하는 방법은 개발적인 방법도 있지만 마켓팅이나, 브랜딩의 방법적으로 풀 수도 있을 것 같은데요. 어떻게 보면 이 칩에서 할 수 있는 최대의 방법을 써도 5mA를 대기전류로 사용하기에 더 낮게 하기 위핸 칩을 바꿔야하는 상황이고 그러려면 소프트웨어, 하드웨어 모드 다시 개발해야하는 큰 공수이기 때문에 기술 측면이외에 다른 방법으로 해결할 수 있는지 항상 생각해보는 것이 좋습니다. 오늘의 교훈은 기술에 너무 몰입되지 말자! 다른 글에서 실제 배터리의 문제를 UX적으로 풀어낸 경험이 있기에 기회가 되면 공유하도록 하겠습니다.

반응형
댓글