모든 포스트

EV 충전기 개발: 하드웨어 플랫폼과 개발 언어 선정

·권경환
기술
EV 충전기 개발: 하드웨어 플랫폼과 개발 언어 선정

들어가는 말

우리는 오래 가는 제품을 만들고 싶습니다. 오래 쓴다는 건 단지 물리적으로 튼튼하다는 의미만은 아닙니다. 우리에게 제품이란 적재적소의 기능과 배치로 사용자에게 편의를 제공하는 한편, 기술부채를 최소화해 안정적으로 유지보수할 수 있는 것, 불필요한 에너지 낭비 없이 효율적으로 작동해 지속성과 함께 신뢰감을 주는 것입니다.

이번 글에서는 우리가 전기차 충전기를 설계하며 왜 AP(Application Processor)가 아닌 MCU(Microcontroller Unit)를 선택했고, 개발 언어로 왜 C 언어를 선택했는지 얘기해보려 합니다.

이 글은 정량적 데이터를 제시하기보다 경험 기반의 주관적인 설명 위주로 전개될 것입니다. 기술적으로 구체적인 내용을 다루기보다는 결정 과정과 그에 대한 고민을 서술하는 식으로 정리해보려 합니다.

비판적 시각을 포함한 다양한 의견을 환영합니다. 관련 오픈소스 펌웨어는 GitHub 저장소에서 확인하실 수 있습니다: https://github.com/pazzk-labs/evse

충전기란 - 무엇을 개발하나

전기차 시장의 급성장과 함께 충전 인프라의 중요성이 높아지고 있습니다. 전기차 충전기는 차량과 전력망을 연결하는 핵심 장치로서, 신뢰성, 안전성, 유지보수 용이성 등 다양한 요구사항을 충족해야 합니다.

우리가 첫번째로 개발하는 제품은 ISO15118 표준의 Plug & Charge 기능을 지원하며, IEC61851과의 호환성을 갖춘 11kW급 완속 충전기입니다.

충전기는 단순한 전력 공급 장치가 아니라, 국제 표준과 보안 및 안전 인증 요건을 충족해야하는 통신/제어 시스템이기도 합니다. ISO 15118과 IEC 61851 외에도 OCPP, 전력선 통신(PLC) 등을 지원해야 하며, V2G(Vehicle-to-Grid), 스마트그리드 연동과 같은 차세대 전력 인프라 기술들과의 호환성도 염두에 두어야 합니다.

결국 EV 충전기는 차량과 전력망을 연결하는 다중 표준 및 프로토콜을 수용하는 제어 중심 시스템이며, 전기적 안정성과 사이버 보안, 유지보수성까지 모두 균형 있게 설계되어야 합니다.

하드웨어 플랫폼 - 왜 AP가 아닌 MCU를 선택했나

Note: 프로세서 아키텍처 뿐만 아니라 주변 회로 및 개발 도구를 포함한 하드웨어 생태계 전반을 가리키기 위해 하드웨어 플랫폼이라는 단어를 사용했습니다. 응용 제품 개발의 용이성은 프로세서 아키텍처보다 관련 개발 도구 제공 여부와 각종 정보를 취득할 수 있는 생태계에 의존하기 때문입니다.

주요 고려사항

프로세서 아키텍처는 논의의 대상이 아니었습니다. ARM 아키텍처가 모바일과 임베디드 시장에서 사실상 표준으로 자리잡고 있기 때문입니다. 전력 효율, 안정성, 성숙도뿐 아니라 개발 도구, 라이브러리, 커뮤니티 등 생태계 전반에서도 ARM은 다른 아키텍처에 비해 우위를 보이고 있습니다.

하드웨어 플랫폼 선정에 유일한 고민은 AP(Application Processor)와 MCU(Microcontroller Unit) 중 어떤 것을 선택할 것인가였습니다. 이 고민은 Linux 기반의 범용 운영체제를 사용할 것인지, 아니면 Zephyr나 FreeRTOS와 같은 RTOS (Real-Time Operating System)를 사용할 것인지에 대한 고민이기도 했습니다.

AP는 고성능 프로세서로, 복잡한 연산과 대량의 데이터를 처리할 수 있습니다. 반면, MCU는 저전력, 저비용의 마이크로컨트롤러로 특정한 작업을 수행하는 데 최적화되어 있습니다.

AP는 Raspberry Pi나 NXP i.MX와 같은 Linux 기반 시스템을 운영할 수 있는 Application Processor로, 범용으로 설계된 만큼 풍부한 메모리와 고성능의 프로세싱 파워를 제공합니다. 그러나 상대적으로 높은 비용과 전력 소비, 긴 부팅 시간, 그리고 리얼타임 성능 부족 등의 단점을 갖고 있습니다.

항목 AP (예: Raspberry Pi, i.MX 8M) MCU (예: ESP32-S3, STM32H7)
CPU 아키텍처 Cortex-A53, Cortex-A7 등 Xtensa LX7, Cortex-M7 등
클럭 속도 1.2GHz ~ 2.0GHz 160MHz ~ 480MHz
RAM 512MB ~ 8GB 512KB ~ 2MB (내장 SRAM)
부팅 시간 4 ~ 15초 100 ~ 500ms
소비 전력 3 ~ 7W 0.3 ~ 1W
운영체제 Linux 기반 Baremetal / RTOS (FreeRTOS, Zephyr)
단가 (모듈 기준) $15 ~ 30 $2 ~ 5

세부 고려사항

메모리 최소 사양을 결정하는 것이 가장 첫번째 작업이었습니다. 네트워크를 포함한 각종 스택과 국내 화재예방형 충전기 인증과 같은 응용계층에서 소비할 여러 메모리 요구사항, 그리고 앞으로 확장 가능성을 염두할 때 권장 1MiB, 최소 512KiB의 RAM을 확보하고자 했습니다.

플래시 메모리는 8MiB를 최소사양으로 하되, 저장할 데이터와 Wear-leveling을 고려했을 때 16MiB 이상이 적당하다고 판단했습니다.

AP나 MCU 어느쪽을 사용하게 되든 외장 플래시 사용은 불가피했기 때문에 보안 리스크를 어떻게 최소화하며 성능을 유지할 수 있는지도 고려 대상이었습니다.

RoT를 위한 HSM 사용과 TEE 환경도 염두했습니다. 적어도 SoC에 내장된 tamper 탐지나 protection 기능으로 충전기라는 제품에 필요한 보안 수준을 확보하고자 했습니다.

Note: 미디어에서 말하는 IoT 제품의 보안 취약성은 TLS와 같은 기본적인 암호화 계층을 사용하지 않기 때문에 발생한 경우가 대부분입니다. 이는 mTLS 적용만으로 대폭 완화될 수 있습니다. 위에 언급된 기능들은 사이드채널 공격과 같은 물리적 접근으로 인한 보안키 탈취를 방어하기 위한 것입니다.

관련 표준들을 검토한 결과, CP 측정 및 릴레이 제어를 위한 100ms 주기가 애플리케이션 수준에서 요구되는 최소 실시간 조건이었습니다. 대부분의 주변장치는 DMA 또는 인터럽트 기반으로 처리하여 CPU 점유를 최소화할 수 있었고, 후보 프로세서들의 최소 동작 주파수가 160MHz 이상이었기 때문에 CPU 점유율은 30% 이하로 유지될 수 있다고 계산했습니다. 따라서 프로세서의 클럭 주파수는 설계에서 주요 고려사항이 아니었습니다.

빠른 부팅 시간은 시스템 장애에 대한 MTTR (Mean Time To Recovery) 관점에서 중요한 지표였습니다. 물론 의도하지 않은 시스템 재부팅은 발생하지 않는 것이 최선이겠습니다만, 현실에서 그런 이상을 달성하기는 불가능에 가깝고 그렇기 때문에 설계는 최악을 고려해야하는 것 같습니다. 어떤 오류나 버그로 시스템이 기대한 동작을 하지 않게되더라도 빠르게 탐지하고 복구될 수 있는 것이 중요했습니다.

상시 전원으로 기획한 제품이지만, 나중에 배터리 기반 제품도 염두하고 있기 때문에 우선순위는 낮지만 저전력도 요구사항 중 하나였습니다. 소프트웨어를 이벤트-드리븐으로 설계해야만 하는 주요 이유 중 하나이기도 했습니다.

결과적으로 비용 및 전력 효율성, 안정성과 robustness 그리고 실시간성을 고려했을 때 우리는 MCU가 AP보다 충전기 개발에 더 적합하다는 결론을 내리게 됐습니다. 한정된 자원을 다루어야 한다는 점과 시스템 레벨까지 제어할 수 있다는 점은 기술적으로도 도전적이고 매력적이었습니다.

Note: MCU 사용으로 무게가 실리면서, Cotex-M33, M4, M7 코어 순서로 SoC를 검토하기 시작했습니다만, 결과적으로 앞서 언급한 ARM 아키텍처가 아닌 Xtensa 아키텍처를 사용하게 됐습니다. Xtensa 아키텍처를 채용한 ESP32 모듈을 추가로 검토하면서, 기능이나 비용 측면에서 이 프로젝트에 사용할 MCU로 이만한 후보는 없어 보였기 때문입니다.

ESP32는 저전력, 저비용의 MCU로, WiFi와 BLE를 지원하며, 다양한 주변 장치와 통신 프로토콜을 지원합니다. PSRAM이 내장된 모듈을 사용할 수 있었고 이더넷과 더불어 WiFi+BLE 무선 통신도 지원한다는 점이 매력적이었습니다. 매우 활발한 생태계를 갖고 있고, 치명적인 CVE도 없었습니다. SoC 선택 기준과 검토한 세부사항은 AP vs MCU 에 대한 주제에서 벗어나므로 기회가 되는대로 다른 글에서 다루어보도록 하겠습니다.

개발 언어 - 왜 C 언어인가

선택한 MCU 하드웨어 플랫폼 위에서 사용할 수 있는 언어로는 C, C++, Rust 를 고려할 수 있었습니다.

개발 언어 선택에서 고려할 점은 개발자의 생산성 뿐이었습니다. 객체지향은 패러다임이지 문법이 아닌 것 처럼, 제품의 품질이나 보안은 언어보다 아키텍처와 구현 방식에 크게 좌우되며, 언어는 그 기반을 지원하는 수단으로 작용한다고 생각하기 때문입니다.

물론, 현대적 언어에서 지원하는 각종 기능은 강력하고 생산성을 향상시키는 한편, 개발자의 실수를 방지하기도 합니다. 하지만, C 언어가 현재 업계에서 차지하는 비중과 Rust나 C++을 도입하는 비용을 고려했을 때 개발 언어 선택은 상대적으로 간단했습니다. 우리가 가진 각 언어들에 대한 이해 정도나 숙련도 역시 결정을 쉽게 만들었습니다.

C++는 객체 지향과 풍부한 추상화를 지원하지만 몸집이 크고 복잡했습니다. Rust는 메모리 안전성이라는 강력한 장점이 있지만 아직 MCU 생태계에서 충분히 성숙하지 않아 제한적이기도 했고, 진입 장벽이 높았습니다. 자연스럽게 가장 단순하고 팀이 이미 여러차례 경험한 C 언어에 무게가 실렸습니다.

다만, C 언어의 취약성(메모리 관리, UB, 추상화)을 어떻게 보완하고 버그 밀도를 낮출 것인지에 대한 고민이 필요했습니다.

C 언어에서 빈번히 문제로 지적되는 메모리 관리의 취약성은 동적 할당을 최소화하고 메모리의 생애 주기를 명확히 관리하는 것으로 리스크를 줄이고자 했습니다. 특히 네트워크 스택과 같이 동적 할당이 필수적인 경우에는 할당 해제 시점을 명확히 통제하고, 응용 계층에서는 초기 할당 후 종료까지 유지되는 정적 할당을 적극 활용했습니다.

C 언어는 언어 자체로서 추상화를 제공하지 않지만, 그 단순성 덕분에 오히려 직관적인 추상화 및 객체지향 설계를 달성할 수 있다고 판단했습니다. 예컨대, opaque pointer와 전방 참조를 활용해 제법 훌륭한 캡슐화를 구현할 수 있습니다. 이는 코드 복잡도를 낮추고 유지보수성을 높이는 데 효과적인 방법이 될 수 있습니다.

Undefined Behavior(UB)는 코드 리뷰와 더불어 컴파일러 경고 옵션(-Wall, -Wextra, -Wconversion, -Wsign-conversion, -Wshadow) 및 분석 도구를 사용하여 적극 관리하기로 했습니다. 또한, MISRA C와 같은 표준 코딩 가이드를 준수하여 UB 발생 가능성을 근본적으로 낮추고자 했습니다.

이러한 접근과 함께 정적 분석 도구(cppcheck, Coverity, CodeQL 등)를 개발 프로세스에 통합하여, 언어적 한계를 보완하고 코드의 신뢰성을 높이는 방안을 수립했습니다.

나가는 말

이번 글에서는 전기차 충전기라는 제품 개발에 MCU와 C 언어를 선택하게 된 배경과 그에 따르는 기술적 고려사항을 정리했습니다.

이 선택은 주어진 조건과 시간 내 최적화된 결정일 뿐, 특정 기술이나 언어의 우월성을 주장하는 것이 아닙니다. 각 기술은 특정한 요구사항과 환경에 따라 장단점이 다르며, 그에 따라 선택이 달라질 수 있습니다. 따라서 우리는 기술과 업계의 동향을 관찰하며 지속적으로 보완 및 개선할 것입니다.

혹시 MCU나 C 언어를 기반으로 한 제품 개발에서 어떤 고민과 경험이 있으셨나요? 유사한 선택을 하신 분들 또는 전혀 다른 접근을 하신 분들의 의견도 궁금합니다. 댓글이나 이슈, 블로그 링크 등으로 자유롭게 공유해 주세요.

같이 만들어갈 분을 찾고 있습니다.

파직은 지금, 이 방향에 공감하고 함께할 수 있는 파트너를 찾고 있습니다. 충전기 제조사, 운영 사업자는 물론, 전기차 충전 생태계의 새로운 기회를 함께 모색할 투자자, 전략 파트너, 기술 협력자 모두 환영합니다. 관심 있으시다면 편하게 연락 주세요.

문의하기

댓글