<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>소프트웨어 공장</title>
    <link>https://coding-by-head.tistory.com/</link>
    <description>소프트웨어 공장 (Software Factory) &amp;mdash; System &amp;amp; Embedded Software Engineering
시스템의 가장 낮은 곳(Low-level)에서부터 사용자에게 닿는 플랫폼 레이어까지, 핵심 엔지니어링 기술을 기록하고 공유하는 공간입니다.
주로 다루는 기술 영역:
Embedded &amp;amp; Firmware: Bootloader(U-Boot, Fastboot), Linux Kernel &amp;amp; Device Driver, FreeRTOS, STM</description>
    <language>ko</language>
    <pubDate>Wed, 10 Jun 2026 00:16:33 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>임베디드 친구</managingEditor>
    <image>
      <title>소프트웨어 공장</title>
      <url>https://tistory1.daumcdn.net/tistory/7292754/attach/4620b993d9834900a40a28903fa2c948</url>
      <link>https://coding-by-head.tistory.com</link>
    </image>
    <item>
      <title>[MCU] 워치독 타이머(Watchdog) 무한 리셋 버그 원인과 메인 루프 구조 개선 방법</title>
      <link>https://coding-by-head.tistory.com/entry/watchdog-timer</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;[Quick Summary (TL;DR) - For Global Developers]&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Symptom: 시스템이 정상 주기를 무시하고 무한히 재부팅(Infinite Reset Loop)되거나 특정 주변장치 응답 대기 시 MCU가 완전히 먹통(System Freeze)이 됨.&lt;/li&gt;
&lt;li&gt;Cause: 메인 루프 내부에 &lt;b&gt;HAL_Delay()&lt;/b&gt; 같은 차단형(Blocking) 지연 함수를 사용하거나 외부 하드웨어의 응답을 무한 대기(Infinite polling)하여 독립형 워치독 타이머(IWDG) 레지스터를 제때 리프레시(Kicking)하지 못함.&lt;/li&gt;
&lt;li&gt;Solution: 차단형 대기 코드를 &lt;b&gt;HAL_GetTick()&lt;/b&gt; 기반의 비차단(Non-blocking) 시간 비교 구조 및 상태 머신(State Machine) 아키텍처로 전면 수정하여 어떤 분기에서도 주기적으로 HAL_IWDG_Refresh()가 호출되도록 개선함.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;독립형 워치독 타이머(IWDG) 무한 리셋 현상과 시스템 다운 증상 (Introduction)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임베디드 시스템 펌웨어 개발 및 필드 테스트 과정에서 하드웨어가 멈추거나 예기치 않게 무한 재부팅되는 무한 리셋 루프(&lt;b&gt;Infinite Reset Loop&lt;/b&gt;) 버그는 자주 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템 안정성을 위해 탑재한 &lt;b&gt;독립형 워치독 타이머(IWDG, Independent Watchdog)&lt;/b&gt;가 도리어 하드웨어를 지속적인 리셋 상태로 몰고 가는 현상입니다. 디버거 가동 중에는 정상 동작하다가도 단독 구동(Standalone) 상태만 되면 수 초 이내에 시스템이 셧다운되거나, 외부 센서 및 통신 칩의 응답이 지연될 때 &lt;b&gt;HardFault_Handler&lt;/b&gt; 예외 벡터로 진입하지 않고 시스템이 초기화되어 버리는 증상을 동반합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해외 포럼이나 Stack Overflow 등에서 주로 &lt;b&gt;&quot;MCU infinite reboot loop with IWDG&quot;, &quot;Watchdog reset during blocking function&quot;&lt;/b&gt;, 혹은 &lt;b&gt;&quot;System freeze due to missed watchdog refresh&quot;&lt;/b&gt; 같은 키워드로 검색되는 대표적인 메인 루프 설계 결함 구조입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;워치독 카운터 다운카운팅 인터벌 및 카운터 리프레시 누락의 근본 원인 (Why it happens)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;독립형 워치독(IWDG)은 메인 CPU의 시스템 클럭(HCLK)과 분리된 내부 저속 RC 오실레이터(LSI)를 클럭 소스로 사용합니다. 따라서 메인 코어가 하드웨어 오류나 소프트웨어 데드락(Deadlock)으로 정지하더라도 다운카운터는 독립적으로 연산을 지속합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 펌웨어 아키텍처 내부에서 워치독 카운터를 리프레시하는 HAL_IWDG_Refresh() (Kicking the watchdog) 함수의 호출 주기가 하드웨어 카운터의 오버플로우 임계값보다 길어질 때 발생합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;차단형 지연 함수(Blocking Delay Execution)&lt;/b&gt;: HAL_Delay()는 내부적으로 시스템 틱이 내부 카운터 값에 도달할 때까지 while 루프를 돌며 CPU 자원을 완전히 점유하는 구조입니다. 이 지연 시간이 워치독 타임아웃 설정값(예: 1초)을 초과하면 타임아웃 예외가 트리거되어 하드웨어 리셋 신호가 발생합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;주변장치 폴링 대기(Infinite Hardware Polling)&lt;/b&gt;: I2C, SPI, UART 통신이나 외부 플래시 메모리 응답을 동기식 폴링 구조(Polling mode)로 대기할 때, 물리적 단선이나 슬레이브 장치의 전원 불량으로 인해 상태 레지스터의 비트 변화를 무한 대기하게 되면 메인 루프 하단에 배치된 워치독 리프레시 함수에 절대 도달할 수 없습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;무한 리셋을 유발하는 잘못된 IWDG 리프레시 C 코드 예시 (Bad Case)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 소스코드는 메인 루프 내부에서 하드웨어 폴링 및 차단형 지연 함수를 무분별하게 사용하여 워치독 리셋 루프를 유발하는 전형적인 오동작 코드입니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;#include &quot;stm32f4xx_hal.h&quot;

IWDG_HandleTypeDef hiwdg;

/* Bad implementation causing watchdog timeout reset */
int main(void) {
    HAL_Init();
    MX_IWDG_Init(); // Watchdog timeout is set to 1000ms (1 second)
    MX_I2C1_Init();

    while (1) {
        uint8_t rx_buf[2];

        /* CRITICAL BUG: Infinite polling without timeout if hardware fails.
           If I2C slave disconnects, execution traps here and watchdog resets MCU. */
        while(__HAL_I2C_GET_FLAG(&amp;amp;hi2c1, I2C_FLAG_RXNE) == RESET) {
            // Wait indefinitely for hardware response
        }
        HAL_I2C_Master_Receive(&amp;amp;hi2c1, 0xA0, rx_buf, 2, HAL_MAX_DELAY);

        /* CRITICAL BUG: 1500ms blocking delay exceeds 1000ms watchdog threshold.
           This statement guarantees a hardware watchdog reset every loop cycle. */
        HAL_Delay(1500); 

        /* This refresh function is never reached due to the issues above */
        HAL_IWDG_Refresh(&amp;amp;hiwdg); 
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;비차단 시간 비교문 및 상태 머신을 적용한 방어적 C 코드 구조 (Good Case)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 해결하기 위해서는 시스템을 완전히 정지시키는 차단형 구조를 타임스탬프 비교문(&lt;b&gt;HAL_GetTick()&lt;/b&gt;) 체계로 변경하고, 하드웨어 응답 대기 로직을 상태 머신(&lt;b&gt;State Machine&lt;/b&gt;) 아키텍처로 분리하여 어떤 상황에서도 메인 루프가 초당 수천 번 이상 공회전하며 워치독을 리프레시하도록 재설계해야 합니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;#include &quot;stm32f4xx_hal.h&quot;

typedef enum {
    SYS_STATE_IDLE,
    SYS_STATE_WAIT_SENSOR,
    SYS_STATE_PROCESS,
    SYS_STATE_ERROR
} SystemState;

IWDG_HandleTypeDef hiwdg;
I2C_HandleTypeDef hi2c1;

int main(void) {
    HAL_Init();
    MX_IWDG_Init(); // Watchdog timeout set to 1000ms
    MX_I2C1_Init();

    SystemState current_state = SYS_STATE_IDLE;
    uint32_t prev_tick = HAL_GetTick();
    uint32_t sensor_timeout_cnt = 0;

    while (1) {
        /* Always refresh watchdog at the top of non-blocking main loop */
        HAL_IWDG_Refresh(&amp;amp;hiwdg);

        /* Task 1: Non-blocking LED toggle or interval function instead of HAL_Delay() */
        if (HAL_GetTick() - prev_tick &amp;gt;= 1500) {
            HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
            prev_tick = HAL_GetTick();
        }

        /* Task 2: Robust State Machine architecture for hardware I/O */
        switch (current_state) {
            case SYS_STATE_IDLE:
                if (__HAL_I2C_GET_FLAG(&amp;amp;hi2c1, I2C_FLAG_RXNE) == RESET) {
                    sensor_timeout_cnt = HAL_GetTick();
                    current_state = SYS_STATE_WAIT_SENSOR;
                } else {
                    current_state = SYS_STATE_PROCESS;
                }
                break;

            case SYS_STATE_WAIT_SENSOR:
                /* Software-level timeout handling before hardware watchdog threshold (800ms) */
                if (HAL_GetTick() - sensor_timeout_cnt &amp;gt; 800) {
                    current_state = SYS_STATE_ERROR; // Handle hardware exception safely
                } else if (__HAL_I2C_GET_FLAG(&amp;amp;hi2c1, I2C_FLAG_RXNE) != RESET) {
                    current_state = SYS_STATE_PROCESS;
                }
                break;

            case SYS_STATE_PROCESS:
                // Execute secure data processing here
                current_state = SYS_STATE_IDLE;
                break;

            case SYS_STATE_ERROR:
                /* Safe state execution: Disable components or run safe reboot sequence */
                break;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;핵심 개선 포인트&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;차단형 지연 함수 제거&lt;/b&gt;: 메인 루프를 멈추게 만들었던 HAL_Delay()를 제거하고, &lt;b&gt;HAL_GetTick()&lt;/b&gt; 기반의 무차단 시간 비교문 구조로 수정하여 루프의 연속성을 확보했습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상태 머신 아키텍처 도입&lt;/b&gt;: 외부 하드웨어 응답 대기 로직을 비차단 주기 점검 상태 머신 구조로 변경하여, 임의의 시점에서도 주기적으로 &lt;b&gt;HAL_IWDG_Refresh()&lt;/b&gt; 함수가 무조건 실행될 수 있도록 구조적 안전성을 확보했습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;소프트웨어 레벨 타임아웃 처리&lt;/b&gt;: 하드웨어 워치독 타이머 한계 임계값인 1초가 도달하기 전인 800ms 시점에 소프트웨어 카운터 기반의 예외 분기 구조를 추가하여, 예기치 못한 하드웨어 오동작 시에도 먹통 현상 없이 안전 상태(&lt;b&gt;SYS_STATE_ERROR&lt;/b&gt;)로 진입하도록 유도했습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시니어 엔지니어의 레지스터 기반 워치독 디버깅 팁 (Debugging Tips)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시스템 리셋이 워치독에 의한 것인지 다른 비정상 코드로 인한 하드폴트(HardFault) 때문인지 디버거 프로브(J-Link, ST-LINK) 및 통합 개발 환경(IDE)을 활용해 정밀하게 추적하는 실무 트러블슈팅 가이드입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;리셋 소스 제어 레지스터(Reset Status Register) 검증&lt;/b&gt;: MCU가 부팅될 때 가장 먼저 제어 레지스터(STM32의 경우 RCC_CSR)의 플래그 비트를 확인해야 합니다. 독립형 워치독 리셋 플래그인 IWDGRSTF 비트가 1로 셋되어 있다면 시스템 전원 노이즈나 하드폴트가 아닌, 메인 루프 지연으로 인한 워치독 타임아웃 리셋임이 100% 입증됩니다. 이 플래그는 확인 후 소프트웨어적으로 RCC_CSR_RMVF를 호출해 클리어해야 다음 리셋 원인을 식별할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디버그 모드 시 워치독 카운터 동결(Freeze Watchdog Counter in Debug Mode)&lt;/b&gt;: 디버거를 연결하고 브레이크포인트(Breakpoint)를 잡아 코드를 멈추었을 때 워치독 카운터가 계속 다운카운팅되면 즉시 리셋이 걸려 디버깅이 불가능해집니다. 이를 방지하기 위해 MCU 내부의 디버그 컴포넌트 레지스터를 제어하여 CPU가 멈췄을 때 워치독 타이머도 일시 정지하도록 설정해야 합니다. STM32 기준 하단 코드를 초기화 영역에 삽입하십시오.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;__HAL_DBGMCU_FREEZE_IWDG(); // Stops IWDG counter when core is halted via JTAG/SWD&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;워치독 인터럽트(Early Wakeup Interrupt, EWI)의 활용&lt;/b&gt;: 물리적 리셋이 걸리기 직전 단계에서 시스템 상태와 스택 프레임을 덤프하기 위해, 하드웨어 스펙이 허용한다면 창 방식 워치독(WWDG) 또는 EWI 인터럽트 기능을 활성화하는 것이 좋습니다. 카운터가 제로가 되기 직전 예외 인터럽트 벡터가 실행되므로, 해당 핸들러 내부에서 현재 중단된 함수 주소(PC, Program Counter)를 로그로 남겨 메인 루프 내 어떤 차단형 기능이 병목을 유발했는지 추적할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Troubleshooting</category>
      <category>embeddedsystems</category>
      <category>IWDG</category>
      <category>mainloop</category>
      <category>STM32Debugging</category>
      <category>WatchdogTimer</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1179</guid>
      <comments>https://coding-by-head.tistory.com/entry/watchdog-timer#entry1179comment</comments>
      <pubDate>Tue, 9 Jun 2026 21:34:20 +0900</pubDate>
    </item>
    <item>
      <title>ARM Cortex-M 하드폴트(Hard Fault) 디버깅: 레지스터 추적으로 원인 코드 찾는 법</title>
      <link>https://coding-by-head.tistory.com/entry/arm-coretex-m-hard-fault</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;Quick Summary (TL;DR) - For Global Developers&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Symptom: The MCU suddenly stops executing normal code and jumps to an infinite loop inside the HardFault_Handler(), often causing the watchdog timer to reset the system.&lt;/li&gt;
&lt;li&gt;Cause: Execution of illegal instructions, memory access violations (such as null pointer dereferencing or unaligned memory access), or stacking failures during exception entry.&lt;/li&gt;
&lt;li&gt;Solution: Trace the &lt;b&gt;Link Register (LR)&lt;/b&gt; to identify the active stack pointer (&lt;b&gt;MSP&lt;/b&gt; or &lt;b&gt;PSP&lt;/b&gt;), read the stacked CPU registers (&lt;b&gt;R0-R3, R12, LR, PC, xPSR&lt;/b&gt;), and locate the exact crash address using the &lt;b&gt;Program Counter (PC)&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ARM Cortex-M HardFault_Handler 발생 증상 및 디버깅의 어려움&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ARM Cortex-M 기반 MCU(Cortex-M0, M3, M4, M7 등)를 타깃으로 펌웨어를 개발하다 보면, 시스템이 아무런 동작을 하지 않고 멈추는 현상을 보게 됩니다. 디버거(J-Link, ST-Link 등)를 연결해 보면 예외 처리 벡터인 &lt;b&gt;HardFault_Handler&lt;/b&gt;에서 무한 루프에 빠져 있는것을 보게 되지요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 문맥이나 키워드를 검색하면 다음과 같은 내용이 검색됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Cortex-M Hard Fault debugging raw registers&lt;/li&gt;
&lt;li&gt;How to find PC from HardFault_Handler&lt;/li&gt;
&lt;li&gt;BusFault, UsageFault escalated to HardFault&lt;/li&gt;
&lt;li&gt;Unaligned memory access crash on Cortex-M0&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 HardFault_Handler 내부에서는 이미 크래시가 발생한 시점의 컨텍스트(Context)가 덮어써졌거나 사라진 것처럼 보인다는 것입니다. Call Stack을 상위로 추적해도 인터럽트 진입점만 표시되고, 어떤 Task의 어떤 코드에서 예외가 발생했는지 찾기 어렵습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;하드폴트(Hard Fault)의 근본 원인과 MCU 내부 동작 메커니즘&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ARM Cortex-M 아키텍처에서 하드폴트가 발생하는 근본 원인은 크게 세 가지가 있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Usage Fault (사용 오류)&lt;/b&gt;: 정의되지 않은 인스트럭션(&lt;b&gt;Undefined Instruction&lt;/b&gt;)을 실행하려고 하거나, &lt;b&gt;Cortex-M0/M3&lt;/b&gt; 등 하드웨어적으로 미지원하는 환경에서 정렬되지 않은 메모리(&lt;b&gt;Unaligned Access&lt;/b&gt;)에 접근 할 때 발생합니다. 0으로 나누기(&lt;b&gt;Divide by Zero&lt;/b&gt;) 설정을 켠 상태에서 나눗셈 오류가 나도 해당합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Bus Fault / MemManage Fault (메모리 접근 오류)&lt;/b&gt;: 유효하지 않은 메모리 주소(예: 0x00000000 널 포인터, 혹은 주변장치 클럭이 꺼진 상태의 레지스터 주소)에 읽기/쓰기를 시도할 때 발생합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Fault Escalation (폴트 하이재킹)&lt;/b&gt;: BusFault, UsageFault, MemManageFault 가 각각의 제어 레지스터(&lt;b&gt;SHCSR&lt;/b&gt;)에서 비활성화되어 있거나, 해당 인터럽트 서비스 루틴을 처리하는 도중 또 다른 폴트가 발생하면 모두 &lt;b&gt;Hard Fault&lt;/b&gt;로 격상(Escalation)됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ARM Core 로직은 예외가 발생한 순간 고유의 하드웨어 스태킹(Hardware Stacking) 메커니즘을 가동합니다. 현재 가동 중이던 핵심 레지스터 8개(&lt;b&gt;R0-R3, R12, LR, PC, xPSR&lt;/b&gt;)를 메인 스택 포인터(&lt;b&gt;MSP&lt;/b&gt;) 또는 프로세스 스택 포인터(&lt;b&gt;PSP&lt;/b&gt;)에 자동으로 push합니다. 따라서 하드폴트 직후 스택에 저장된 이 &lt;b&gt;Context Frame&lt;/b&gt;을 역추적하면 정확히 어떤 주소(&lt;b&gt;PC&lt;/b&gt;)에서 크래시가 났는지 찾아낼 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제를 유발하는 잘못된 포인터 및 데이터 정렬 C 코드 (Bad Case)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드는 임베디드 환경에서 하드폴트를 유발하는 가장 대표적인 두 가지 패턴(Null Pointer Dereference, Unaligned Memory Access)을 보여줍니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;#include &amp;lt;stdint.h&amp;gt;

typedef struct {
    uint8_t  status;
    uint32_t payload; /* Might be unaligned if the struct is packed or cast raw */
} __attribute__((packed)) Packet_t;

void trigger_hardfault_example(void) {
    /* Case 1: Null Pointer Dereferencing (Causes BusFault / HardFault) */
    volatile uint32_t *invalid_ptr = (volatile uint32_t *)0x00000000;
    *invalid_ptr = 0xDEADBEEF; 

    /* Case 2: Unaligned Access on strict hardware (e.g., Cortex-M0) */
    uint8_t buffer[8] = {0, 1, 2, 3, 4, 5, 6, 7};

    /* Forcing an unaligned 32-bit read from an odd byte address */
    volatile uint32_t *unaligned_ptr = (volatile uint32_t *)&amp;amp;buffer[1]; 
    volatile uint32_t value = *unaligned_ptr; 

    (void)value;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;구조체 패딩 보존 및 방어적 코딩을 적용한 C 코드 (Good Case)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드폴트를 방지하기 위해서는 원시 포인터 캐스팅을 지양하고, 하드웨어 특성에 맞춰 메모리 정렬(Alignment)을 유지하거나 널 체크를 선행해야 합니다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;#include &amp;lt;stdint.h&amp;gt;
#include &amp;lt;string.h&amp;gt;

typedef struct {
    uint8_t  status;
    uint32_t payload; 
} SafePacket_t; /* Compiler aligns 'payload' to a 4-byte boundary by default */

void safe_execution_example(void) {
    /* Mitigation 1: Defensive Null Pointer Check */
    volatile uint32_t *ptr = (volatile uint32_t *)0x00000000;
    if (ptr != NULL) {
        *ptr = 0xDEADBEEF;
    }

    /* Mitigation 2: Handling Unaligned Data safely using memcpy */
    uint8_t buffer[8] = {0, 1, 2, 3, 4, 5, 6, 7};
    uint32_t safe_value = 0;

    /* memcpy safely handles unaligned byte-to-word copy on any architecture */
    memcpy((void *)&amp;amp;safe_value, &amp;amp;buffer[1], sizeof(uint32_t));

    (void)safe_value;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;핵심 수정 포인트&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;b&gt;attribute&lt;/b&gt;((packed)) 제거 및 memcpy 활용&lt;/b&gt;: Cortex-M0 아키텍처나 특정 버스 환경에서는 패킹된 구조체의 32비트 멤버에 직접 접근할 때 하드폴트가 발생합니다. 바이트 단위로 복사하는 memcpy를 사용하면 컴파일러가 정렬 오류가 나지 않도록 인스트럭션을 안전하게 쪼개서 생성합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;명시적 포인터 유효성 검증&lt;/b&gt;: 하드코딩된 주소나 가리키는 대상이 모호한 포인터는 반드시 NULL 또는 가용 RAM 범위 내에 있는지 검증 로직을 거칩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Cortex-M 하드폴트 디버깅 및 트러블슈팅 가이드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;디버거 툴(IAR EWARM, Keil MDK, STM32CubeIDE 등) 상에서 HardFault_Handler에 걸렸을 때, 레지스터 분석을 통해 PC(Program Counter)를 뽑아내는 실무 트러블슈팅 절차입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Step 1. EXC_RETURN (Link Register) 값 확인을 통한 스택 판별&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드폴트 핸들러 내에 브레이크포인트가 걸렸을 때 제일 먼저 Core Register 윈도우에서 LR(Link Register) 값을 확인합니다. 인터럽트 진입 시 LR은 일반 주소가 아닌 예외 복귀 플래그인 EXC_RETURN 값으로 채워집니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;0xFFFFFFF9: 예외 발생 전 시스템이 Main Stack(MSP)을 사용 중이었음.&lt;/li&gt;
&lt;li&gt;0xFFFFFFFD: 예외 발생 전 시스템이 Process Stack(PSP)을 사용 중이었음(RTOS 환경의 Task 내부에서 터졌을 때 주로 발생).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Step 2. 해당 스택 포인터 주소로 이동하여 Context Frame 추출&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 LR이 0xFFFFFFFD라면 디버거의 레지스터 창에서 PSP 값을 확인하고, Memory View 창에 해당 PSP 주소를 입력합니다. 하드웨어 스태킹 규칙에 따라 메모리에 다음과 같은 순서(Low Address에서 High Address 방향)로 레지스터가 저장되어 있습니다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Offset&lt;/th&gt;
&lt;th&gt;Stacked Register&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SP + 0x00&lt;/td&gt;
&lt;td&gt;R0&lt;/td&gt;
&lt;td&gt;Argument / Result&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SP + 0x04&lt;/td&gt;
&lt;td&gt;R1&lt;/td&gt;
&lt;td&gt;Argument / Result&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SP + 0x08&lt;/td&gt;
&lt;td&gt;R2&lt;/td&gt;
&lt;td&gt;Argument / Parameter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SP + 0x0C&lt;/td&gt;
&lt;td&gt;R3&lt;/td&gt;
&lt;td&gt;Argument / Parameter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SP + 0x10&lt;/td&gt;
&lt;td&gt;R12&lt;/td&gt;
&lt;td&gt;Intra-Procedure-call scratch register&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SP + 0x14&lt;/td&gt;
&lt;td&gt;LR&lt;/td&gt;
&lt;td&gt;Link Register (Crash를 유발한 함수를 호출한 곳)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SP + 0x18&lt;/td&gt;
&lt;td&gt;PC&lt;/td&gt;
&lt;td&gt;&lt;b&gt;Program Counter (실제 에러를 유발한 정확한 코드 주소)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SP + 0x1C&lt;/td&gt;
&lt;td&gt;xPSR&lt;/td&gt;
&lt;td&gt;Execution Program Status Register&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Step 3. PC 주소 추적 및 MAP 파일 비교&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SP + 0x18 위치에 기록된 32비트 헥사 주소(예: 0x08002A34)를 확보합니다. 이 주소가 바로 크래시를 일으킨 인스트럭션 위치입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;디버거의 Disassembly Window 창에 해당 주소를 입력하면 문제가 된 C 코드 라인과 어셈블리 명령어를 즉시 확인할 수 있습니다.&lt;/li&gt;
&lt;li&gt;디버거를 연결할 수 없는 양산 제품 검증 환경이라면, 빌드 결과물로 나온 &lt;i&gt;.map 파일 또는 디스어셈블리 파일(&lt;/i&gt;.list, *.asm)을 열어 해당 주소가 어떤 함수 영역에 포함되어 있는지 맵핑하여 원인을 검거합니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Troubleshooting</category>
      <category>BareMetal</category>
      <category>cortexm</category>
      <category>debugging</category>
      <category>Embedded</category>
      <category>HardFault</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1178</guid>
      <comments>https://coding-by-head.tistory.com/entry/arm-coretex-m-hard-fault#entry1178comment</comments>
      <pubDate>Mon, 8 Jun 2026 21:01:25 +0900</pubDate>
    </item>
    <item>
      <title>[C언어 임베디드] 버퍼 오버플로우(Buffer Overflow) 에러 예방과 안전한 메모리 복사</title>
      <link>https://coding-by-head.tistory.com/entry/prevention-buffer-overflow</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;[Quick Summary (TL;DR) - For Global Developers]&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Symptom: Unexpected modification of adjacent variables, sudden system resets, or immediate jumps to HardFault_Handler during data parsing.&lt;/li&gt;
&lt;li&gt;Cause: Writing data beyond the allocated array boundary, which overwrites the Stack Frame (return address) or adjacent global variables in RAM.&lt;/li&gt;
&lt;li&gt;Solution: Implement strict input validation (Bounds Checking) before any memory write operation, and replace unsafe memory functions with size-limited alternatives.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;임베디드 C언어 버퍼 오버플로우(Buffer Overflow) 발생 증상과 HardFault 하드웨어 오작동&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임베디드 시스템에서 배열 인덱스 초과(Array Index Out of Bounds)로 인한 메모리 오염은 OS가 존재하는 PC 환경과 달리 &lt;b&gt;Segmentation Fault&lt;/b&gt;를 발생시키지 않고 침묵 속에 동작하는 경우가 많습니다. 대개 다음과 같은 하드웨어 및 소프트웨어적 징후로 나타납니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;인접 변수 값의 이유 없는 변경&lt;/b&gt;: 특정 배열에 데이터를 채운 직후, 코드상에서 수정하지 않은 다른 전역 변수나 로컬 변수의 값이 무작위로 변경됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비정상적인 분기 및 시스템 리셋&lt;/b&gt;: 함수가 종료되는 시점(return)에 시스템이 얼어버리거나 예기치 못한 번지로 점프하여 &lt;b&gt;Watchdog Timer&lt;/b&gt; 리셋을 유발합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;코어 예외(Core Exception) 발생&lt;/b&gt;: ARM Cortex-M 코어 기준으로, 오염된 메모리 주소에 접근하거나 잘못된 명령어 번지로 진입하면서 &lt;b&gt;HardFault_Handler, MemManage_Handler,&lt;/b&gt; 또는 &lt;b&gt;Alignment Fault&lt;/b&gt;가 즉각적으로 트리거됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;배열 인덱스 초과(Array Index Out of Bounds)가 유발하는 메모리 오염의 컴파일러 레벨 원인 분석&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임베디드 C 환경에서 컴파일된 바이너리는 메모리(RAM) 구조상 고정된 배치를 가집니다. 컴파일러와 MCU 레지스터 관점에서 원인은 두 가지 레이어로 나뉩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;스택 프레임(Stack Frame) 파괴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 내부의 로컬 버퍼(Local Buffer)는 스택(Stack) 영역에 할당됩니다. 이 버퍼의 인덱스를 초과하여 데이터를 쓰면, 스택 프레임 상위에 저장된 함수의 반환 주소(Return Address)인 &lt;b&gt;Link Register (LR)&lt;/b&gt; 값이 오염됩니다. 함수 실행이 끝나고 &lt;b&gt;Program Counter (PC)&lt;/b&gt; 레지스터가 오염된 LR 값을 복원하는 순간, CPU는 무효한 메모리 주소의 코드를 실행하려 시도하므로 HardFault가 발생합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;데이터 세그먼트(Data/BSS Segment) 오염&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전역(Global) 또는 정적(Static) 배열의 경우 링커 스크립트(.ld)에 정의된 순서 및 컴파일러 최적화 정렬(Data Alignment) 규칙에 따라 RAM에 차례대로 배치됩니다.&lt;/p&gt;
&lt;pre class=&quot;inform7&quot;&gt;&lt;code&gt;[ 낮은 주소 ] ---&amp;gt; [ 높은 주소 ]
[    rx_buffer[64]    ] [ critical_flag (4-byte) ] [ target_address (4-byte) ]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 구조에서 rx_buffer에 64바이트를 초과하는 데이터를 쓰면 내부 제어 플래그인 critical_flag나 포인터 변수인 target_address가 그대로 덮어써집니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;임베디드 통신 패킷 수신 시 버퍼 오버플로우를 유발하는 잘못된 C 코드 예시 (Bad Case)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 인터페이스(UART, SPI, CAN 등)로부터 전달받은 패킷 내부의 길이 필드(Length Field)를 검증 없이 바이트 복사에 그대로 사용할 때 가장 흔하게 발생합니다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &amp;lt;stdint.h&amp;gt;
#include &amp;lt;string.h&amp;gt;

#define MAX_BUFFER_SIZE 64

typedef struct {
    uint8_t payload_len;
    uint8_t payload_data[128]; 
} Packet_t;

uint8_t g_system_buffer[MAX_BUFFER_SIZE]; // Destination buffer allocated in RAM
uint32_t g_critical_system_state = 0x11223344; // Target variable susceptible to corruption

void process_received_packet(const Packet_t* packet) {
    /* 
     * BAD: No bounds checking performed on packet-&amp;gt;payload_len.
     * If payload_len is greater than 64, g_critical_system_state will be overwritten.
     */
    memcpy(g_system_buffer, packet-&amp;gt;payload_data, packet-&amp;gt;payload_len);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;경계 검증(Bounds Checking)을 적용한 안전한 메모리 복사 및 방어적 C 코드 (Good Case)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;런타임 환경에서 입력 데이터의 크기를 타깃 버퍼의 물리적 크기와 비교하는 예외 처리 코드를 반드시 포함해야 합니다&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &amp;lt;stdint.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;stdbool.h&amp;gt;

#define MAX_BUFFER_SIZE 64

typedef struct {
    uint8_t payload_len;
    uint8_t payload_data[128]; 
} Packet_t;

uint8_t g_system_buffer[MAX_BUFFER_SIZE];
uint32_t g_critical_system_state = 0x11223344;

bool safe_process_received_packet(const Packet_t* packet) {
    /* 
     * GOOD: Strict bounds checking against the destination buffer size.
     * Prevent memory corruption before execution.
     */
    if (packet-&amp;gt;payload_len &amp;gt; MAX_BUFFER_SIZE) {
        // Log error or update communication status register here
        return false; 
    }

    /* 
     * Alternatively, use size-bounded copy functions, ensuring length validation.
     */
    memcpy(g_system_buffer, packet-&amp;gt;payload_data, packet-&amp;gt;payload_len);
    return true;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;핵심 수정 포인트&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;조건문 기반 크기 검증&lt;/b&gt;: 복사 연산을 수행하기 전, 소스(Source) 데이터의 크기(packet-&amp;gt;payload_len)가 목적지(Destination) 버퍼의 최대 크기(MAX_BUFFER_SIZE)보다 작은지 비교하는 방어적 구문을 명시했습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;에러 핸들링 리턴 플래그 추가&lt;/b&gt;: 유효하지 않은 패킷이 인입되었을 때 복사를 차단하고 상위 모듈로 에러 상태(false)를 즉시 반환하여 후속 예외 처리가 가능하도록 설계했습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;버퍼 오버플로우 디버깅 및 MAP 파일 활용 트러블슈팅 가이드&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;링커 맵 파일(MAP File) 주소 분석&lt;/b&gt;: 빌드 결과물로 생성되는 .map 파일을 열어 오염된 전역 변수의 메모리 주소를 확인하십시오. 해당 변수 바로 앞에 배치된 배열이나 구조체가 버퍼 오버플로우를 일으킨 유력한 원인(Originator)입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 와치포인트(Data Watchpoint) 설정&lt;/b&gt;: J-Link 또는 ST-Link 환경에서 값이 원치 않게 바뀌는 인접 변수에 GDB 명령어나 IDE 기능을 통해 Watchpoint를 등록하십시오. 해당 메모리 주소에 쓰기(Write) 작업이 발생하는 즉시 CPU 코어가 멈추므로 오버플로우를 유발한 원인 코드를 실시간으로 추적할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스택 포인터(SP) 및 링크 레지스터(LR) 역추적&lt;/b&gt;: 함수 리턴 시점에 HardFault가 발생했다면, 예외 스택 프레임(Exception Stack Frame)에 저장된 PC와 LR 값을 확인하십시오. 스택 포인터(SP) 주변 메모리를 덤프하여 어떤 로컬 버퍼가 상위 레지스터 영역을 침범했는지 크기를 역산할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Troubleshooting</category>
      <category>bufferoverflow</category>
      <category>DefensiveProgramming</category>
      <category>EmbeddedC</category>
      <category>HardFault</category>
      <category>MemoryCorruption</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1177</guid>
      <comments>https://coding-by-head.tistory.com/entry/prevention-buffer-overflow#entry1177comment</comments>
      <pubDate>Sun, 7 Jun 2026 20:15:11 +0900</pubDate>
    </item>
    <item>
      <title>[MCU 디버깅] Wild Pointer 및 Dangling Pointer로 인한 시스템 다운 방지 대책</title>
      <link>https://coding-by-head.tistory.com/entry/mcu-wild-dangling-pointer-debugging-hardfault</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;[Quick Summary (TL;DR) - For Global Developers]&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Symptom: Random system resets, infinite loops in HardFault_Handler, unexpected peripheral behaviors, or silent data corruption that alters operation based on Compiler Optimization levels.&lt;/li&gt;
&lt;li&gt;Cause: Dereferencing uninitialized pointer variables (Wild Pointer) or accessing memory addresses that have already been deallocated from the heap or stack frame (Dangling Pointer).&lt;/li&gt;
&lt;li&gt;Solution: Initialize all pointers to NULL, explicitly nullify pointers immediately after deallocation, validate pointers before dereferencing, and leverage hardware MPU (Memory Protection Unit) boundaries.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MCU Memory Corruption: Wild Pointer &amp;amp; Dangling Pointer Symptoms (포인터 오동작 발생 증상)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드웨어 제어권이 완전히 열려 있는 베어메탈(Bare-metal) 환경이나 RTOS 기반의 MCU 커널 환경에서는 OS 수준의 메모리 격리(Memory Isolation)가 불가능합니다. 이로 인해 잘못된 포인터 참조는 단순 애플리케이션 종료가 아닌, 치명적인 하드웨어 예외 상황으로 직결됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;런타임 중 마주치는 주요 하드웨어적/소프트웨어적 증상은 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;HardFault_Handler 진입&lt;/b&gt;: 시스템이 하드웨어 예외를 처리하는 루프에 갇힙니다. 주로 메모리 정렬 불량으로 인한 Alignment Fault, 존재하지 않거나 쓰기가 제한된 영역에 접근할 때 발생하는 BusFault 혹은 UsageFault가 CPU 코어 레벨에서 트리거됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;재현 불가능한 무작위 크래시 (Random Reset)&lt;/b&gt;: 컴파일러 최적화 옵션(-O1, -O2, -O3) 레벨에 따라 증상이 완전히 바뀝니다. 디버그 빌드에서는 정상 동작하던 코드가 양산용 배포 빌드에서 무한 루프에 빠지거나 오작동합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 자동 오염 (Silent Data Overwrite)&lt;/b&gt;: 포인터가 의도치 않은 RAM 주소를 가리킨 상태에서 데이터를 쓰면, 인접한 전역 변수나 주변장치 제어용 SFR (Special Function Register)을 임의로 덮어써 시스템 전반의 무결성을 깨뜨립니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MCU 레지스터 및 메모리 구조 관점의 포인터 오동작 원인 (Root Cause Analysis)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU 코어가 메모리 액세스 명령어(LDR, STR)를 처리하는 하드웨어적 메커니즘과 메모리 맵 배치 구조에서 원인을 찾을 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 와일드 포인터(Wild Pointer)의 메커니즘&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지역 변수로 선언된 포인터가 스택(Stack) 프레임에 할당될 때, 명시적인 초기화가 없으면 해당 스택 메모리 슬롯에 남아있던 이전 작업의 쓰레기 값(Garbage Value)을 주소로 가집니다. 이 상태에서 CPU가 STR 명령을 실행하면 엉뚱한 메모리 번지에 쓰기를 시도합니다. 이 주소가 물리적 SRAM이나 내부 플래시(Internal Flash)의 유효 범위를 벗어날 경우 메모리 관리 유닛이 이를 감지하여 즉시 BusFault를 발생시킵니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 댕글링 포인터(Dangling Pointer)의 메커니즘&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;malloc() 등으로 동적 할당한 힙(Heap) 메모리를 free()로 해제하면, 힙 메모리 관리자(Allocator)는 해당 블록을 '사용 가능' 상태로만 변경할 뿐입니다. 포인터 변수 자체는 여전히 해제된 물리 주소를 그대로 가리키고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 이 포인터를 지우지 않고 다시 역참조(Dereference)하여 데이터를 읽거나 쓰면 문제가 발생합니다. 이미 해당 메모리 블록이 ISR (Interrupt Service Routine)이나 다른 태스크에 의해 재할당되어 다른 용도로 사용 중일 수 있기 때문입니다. 이는 시스템 내부 제어 구조체를 파괴하는 결과를 낳습니다. 함수 내부의 지역 변수 주소를 반환하여 함수 종료 후 파괴된 스택 영역을 가리키게 만드는 경우도 동일한 원리입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;시스템 다운을 유발하는 잘못된 C 소스 코드 예시 (Bad Pointer Examples)&lt;/h2&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;stdint.h&amp;gt;

typedef struct {
    uint32_t data[4];
} Packet_t;

/* Case 1: Wild Pointer (Uninitialized Local Pointer) */
void Process_RawData(void) {
    Packet_t *p_packet; // Bug: Contains garbage stack value. Not initialized to NULL.

    // System crashes into HardFault here depending on the garbage address value
    p_packet-&amp;gt;data[0] = 0xDEADBEEF; 
}

/* Case 2: Dangling Pointer (Returning Stack Address) */
uint32_t* Get_SystemStatus(void) {
    uint32_t status_flag = 0x01;
    return &amp;amp;status_flag; // Bug: Returns address of a local variable that will be destroyed post-return
}

/* Case 3: Dangling Pointer (Missing Nullification after free) */
void Manage_HeapMemory(void) {
    Packet_t *p_dynamic = (Packet_t*)malloc(sizeof(Packet_t));
    if (p_dynamic == NULL) return;

    free(p_dynamic); // Memory freed, but p_dynamic still holds the old address

    // Bug: Dangling pointer dereference. Corrupts current heap state or metadata.
    p_dynamic-&amp;gt;data[0] = 0xAAAA5555; 
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;MCU 시스템 안정성을 확보하는 방어적 C 소스 코드 (Defensive Pointer Patterns)&lt;/h2&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &amp;lt;stdlib.h&amp;gt;
#include &amp;lt;stdint.h&amp;gt;

typedef struct {
    uint32_t data[4];
} Packet_t;

/* Safe Free Macro to eliminate Dangling Pointers */
#define SAFE_FREE(ptr) do { free(ptr); (ptr) = NULL; } while(0)

/* Solution 1: Always Initialize and Validate Pointers */
void Safe_Process_RawData(void) {
    Packet_t *p_packet = NULL; // Initialized to NULL explicitly

    /* Code block allocating or assigning valid reference to p_packet */

    if (p_packet != NULL) {
        p_packet-&amp;gt;data[0] = 0xDEADBEEF;
    }
}

/* Solution 2: Prevent Stack Address Leakage via Static Storage */
uint32_t* Safe_Get_SystemStatus(void) {
    static uint32_t status_flag = 0x01; // Persistent allocation in .data/.bss segment
    return &amp;amp;status_flag;
}

/* Solution 3: Enforce Safe Free Pattern */
void Safe_Manage_HeapMemory(void) {
    Packet_t *p_dynamic = (Packet_t*)malloc(sizeof(Packet_t));
    if (p_dynamic == NULL) return;

    // Frees memory and immediately updates pointer to NULL
    SAFE_FREE(p_dynamic); 

    // Guard condition prevents invalid memory operations
    if (p_dynamic != NULL) {
        p_dynamic-&amp;gt;data[0] = 0xAAAA5555;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;핵심 수정 포인트 (Key Modifications)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;포인터 선언과 동시에 NULL 초기화&lt;/b&gt;: 스택 내 잔여 쓰레기 값으로 인한 오동작을 원천 차단하기 위해 모든 포인터는 선언 시점에 NULL로 명시적 초기화를 수행합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SAFE_FREE 매크로 활용&lt;/b&gt;: 메모리 해제와 동시에 해당 포인터 변수에 자동으로 NULL을 주입하는 매크로 함수를 정의하여 사용함으로써 인간의 실수(Human Error)로 인한 댕글링 포인터 발생을 막습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;역참조 전 조건문 검증&lt;/b&gt;: 포인터를 통해 실제 가치에 접근하기 전 항상 if (ptr != NULL) 패턴을 적용하여, 유효성이 검증된 포인터만 메모리에 접근하도록 제한합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;하드폴트 예외 발생 시 포인터 추적 디버깅 가이드 (HardFault Debugging Tips)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;하드웨어 에러 예외 스택 프레임 (Stack Frame) 역추적&lt;/b&gt;: HardFault가 트리거되는 순간 ARM Cortex-M 코어는 SP (Stack Pointer)가 가리키는 스택 영역에 &lt;b&gt;R0-R3, R12, LR, PC, xPSR&lt;/b&gt; 레지스터 정보를 자동으로 백업(Stacking)합니다. 디버거(J-Link 또는 ST-Link) 인터페이스의 레지스터 뷰어 창에서 SP 주소를 찾아 해당 메모리 덤프의 &lt;b&gt;PC (Program Counter)&lt;/b&gt; 값을 식별하면, 부적절한 포인터 접근을 명령한 소스 코드의 정확한 물리 행 위치를 찾을 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MAP 파일(Build Map File)을 활용한 주소 바운더리 체크&lt;/b&gt;: 디버깅 화면에서 오동작이 의심되는 포인터 변수의 16진수 주소 값을 복사한 뒤, 링커가 생성한 &lt;b&gt;MAP 파일&lt;/b&gt;과 대조하십시오. 해당 주소가 하드웨어 데이터시트에 명시된 내부 SRAM, Flash 영역, Peripheral SFR 메모리 맵 경계선 바깥 영역을 가리키고 있다면 이는 포인터 초기화가 누락된 &lt;b&gt;Wild Pointer&lt;/b&gt; 에러입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 워치포인트 (Data Watchpoint - DWT) 실시간 모니터링&lt;/b&gt;: 특정 전역 변수나 메모리 구조체 내부 값이 임의의 타이밍에 오염되고 있다면, 메모리 주소 자체에 IDE(Keil, IAR, STM32CubeIDE 등)의 &lt;b&gt;Data Watchpoint&lt;/b&gt; 기능을 설정하십시오. 해당 번지에 &lt;b&gt;쓰기(Write)&lt;/b&gt;가 시도되는 즉시 CPU 파이프라인이 멈추므로, 메모리를 오염시킨 주범(Dangling Pointer)이 속한 함수 컨텍스트를 런타임 상에서 실시간으로 색출할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Troubleshooting</category>
      <category>DanglingPointer</category>
      <category>EmbeddedC</category>
      <category>HardFault</category>
      <category>MCUDebugging</category>
      <category>WildPointer</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1176</guid>
      <comments>https://coding-by-head.tistory.com/entry/mcu-wild-dangling-pointer-debugging-hardfault#entry1176comment</comments>
      <pubDate>Sat, 6 Jun 2026 21:25:21 +0900</pubDate>
    </item>
    <item>
      <title>[임베디드 C] 스택 오버플로우(Stack Overflow) 원인 분석과 MAP 파일 활용한 해결 방법</title>
      <link>https://coding-by-head.tistory.com/entry/stack-overflow</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;[Quick Summary (TL;DR) - For Global Developers]&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Symptom: MCU enters HardFault_Handler or suddenly resets, causing memory corruption and unpredictable runtime behavior.&lt;/li&gt;
&lt;li&gt;Cause: A thread or function exceeds its allocated stack space due to large local variables, deep recursion, or high interrupt nesting.&lt;/li&gt;
&lt;li&gt;Solution: Optimize local memory allocation using static or dynamic memory, increase stack size in the linker script, and analyze the MAP file to audit stack usage.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스택 오버플로우(Stack Overflow) 무작위 시스템 크래시 증상 (Introduction)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임베디드 시스템 개발 중 멀쩡히 동작하던 펌웨어가 특정 함수를 호출하는 순간 먹통이 되거나, 디버거가 &lt;b&gt;HardFault_Handler&lt;/b&gt; 또는 &lt;b&gt;UsageFault_Handler&lt;/b&gt; 가리키며 멈추는 현상을 겪어보셨을 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 무작위적 시스템 크래시(Random System Crash)의 주범 중 하나가 바로 &lt;b&gt;Stack Overflow&lt;/b&gt;입니다. 특히 실시간 운영체제(RTOS) 환경에서는 특정 태스크(Task)가 할당받은 스택 크기를 넘어서는 순간, 인접한 다른 태스크의 TCB(Task Control Block)나 시스템 힙(Heap) 영역을 훼손시켜 원인 추적이 아주 어려워집니다. 해외 포럼에서도 MCU random reset after function call, ARM Cortex-M HardFault stack pointer와 같은 키워드로 자주 검색되는 대표적인 런타임 에러입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;메모리 하강 구조와 스택 오버플로우(Stack Overflow)의 근본적인 원인 분석 (Why it happens)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임베디드 c에서 스택(Stack)은 함수 호출 시 &lt;b&gt;Local Variables(지역 변수), Function Parameters(매개변수)&lt;/b&gt;, 그리고 함수 종료 후 돌아갈 &lt;b&gt;Return Address(복귀 주소)&lt;/b&gt;를 저장하는 메모리 공간입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ARM Cortex-M Core를 기준으로 설명하면, 스택은 상위 주소에서 하위 주소로 자라나는 &lt;b&gt;Descending Stack&lt;/b&gt; 방식을 사용합니다. 함수가 호출될 때마다 &lt;b&gt;SP(Stack Pointer)&lt;/b&gt; 레지스터 값이 감소하며 메모리가 할당됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;images.png&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/degdEW/dJMcaar25km/VP8NIjBcQR4RmXKGz4Kyik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/degdEW/dJMcaar25km/VP8NIjBcQR4RmXKGz4Kyik/img.png&quot; data-alt=&quot;Generated by Gemini AI.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/degdEW/dJMcaar25km/VP8NIjBcQR4RmXKGz4Kyik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdegdEW%2FdJMcaar25km%2FVP8NIjBcQR4RmXKGz4Kyik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;747&quot; height=&quot;349&quot; data-filename=&quot;images.png&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Generated by Gemini AI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 다이어그램처럼 PUSH 동작이 수행되면 SP가 하위 주소 방향으로 이동합니다. 스택 오버플로우는 이 &lt;b&gt;Current SP&lt;/b&gt;가 링커 스크립트(Linker Script, .ld/.sct)에서 정의한 &lt;b&gt;Stack Limit&lt;/b&gt; 경계를 넘어설 때 발생합니다.&lt;/p&gt;
&lt;pre class=&quot;coq&quot;&gt;&lt;code&gt;[High Address]
  +-----------------------+ &amp;lt;--- Stack Top (Initial SP)
  | Function A Frame      |
  +-----------------------+
  | Function B Frame      |
  +-----------------------+
  |                       | |
  |     Valid Stack       | | Stack Grows Downward
  |                       | v
  +-----------------------+ &amp;lt;--- Current SP
  |     Unallocated       |
  +=======================+ &amp;lt;--- Stack Limit (Boundary)
  |  Overflown / Corrupt  | 
  +-----------------------+
  | Heap / Global Variables
[Low Address]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;경계를 넘어선 상태에서 데이터 쓰기(&lt;b&gt;Write operation&lt;/b&gt;)가 실행되면 인접한 메모리 영역의 변수나 &lt;b&gt;LR(Link Register)&lt;/b&gt; 값이 덮어씌워져 시스템이 통제 불능 상태에 빠지게 됩니다. 주요 발생 원인은 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;과도한 크기의 지역 변수(Large Local Arrays)&lt;/b&gt;: 버퍼 메모리를 함수 내부 변수로 크게 선언하는 경우.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;깊은 재귀 호출(Deep Recursion)&lt;/b&gt;: 종료 조건이 모호하거나 depth가 깊은 재귀 함수를 호출하는 경우.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터럽트 중첩(Interrupt Nesting)&lt;/b&gt;: ISR(Interrupt Service Routine)이 실행되는 와중에 우선순위가 더 높은 인터럽트가 지속적으로 중첩되어 스택에 콘텍스트(Context)를 누적하는 경우.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제를 유발하는 잘못된 지역 버퍼 스택(Stack) 할당 C 코드 예시 (Bad Case)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 흔하게 발생하는 실수는 네트워크 패킷이나 센서 데이터를 처리하기 위해 함수 내부에서 대용량 버퍼를 지역 변수로 선언하는 경우입니다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#define BUFFER_SIZE 2048 // 2KB Buffer

void Process_Network_Data(void) {
    /* BAD: Allocating a 2KB array on the stack.
     * If the total allocated stack for this task/system is only 1KB or 2KB,
     * this single declaration will immediately cause a Stack Overflow. */
    uint8_t local_buffer[BUFFER_SIZE]; 

    /* Simulate data processing */
    for(int i = 0; i &amp;lt; BUFFER_SIZE; i++) {
        local_buffer[i] = Read_Hardware_Register();
    }

    Parse_Payload(local_buffer);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;스택 오버플로우(Stack Overflow) 해결을 위한 올바른 정적 메모리 할당 C 코드 (Good Case)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스택 공간을 절약하기 위해 대용량 버퍼는 &lt;b&gt;static&lt;/b&gt; 키워드를 사용하여 &lt;b&gt;.bss/.data&lt;/b&gt; (&lt;b&gt;정적 메모리 영역&lt;/b&gt;)로 빼거나, 필요한 경우에만 힙(Heap) 메모리를 활용해야 합니다. 다음은 정적 할당으로 스택 부하를 제거한 코드입니다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#define BUFFER_SIZE 2048

/* GOOD: Allocated in the .bss section (RAM), not on the stack.
 * Thread-safe caution: If this function is called concurrently by multiple 
 * RTOS tasks, use mutex/semaphores or consider dynamic allocation (malloc). */
static uint8_t global_static_buffer[BUFFER_SIZE];

void Process_Network_Data(void) {
    /* No large allocation on the stack; only pointer/index variables are used */

    for(int i = 0; i &amp;lt; BUFFER_SIZE; i++) {
        global_static_buffer[i] = Read_Hardware_Register();
    }

    Parse_Payload(global_static_buffer);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;핵심 수정 포인트&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;static 키워드를 추가하여 변수의 저장 위치를 스택 프레임 외부의 정적 데이터 영역인 .bss 섹션으로 변경했습니다. 이를 통해 함수가 호출되어도 SP(Stack Pointer)가 급격하게 감소하지 않아 오버플로우 위험을 원천 차단합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;런타임 하드폴트 및 스택 디버깅 가이드 (Debugging Tips)&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;빌드 결과물인 MAP 파일 (.map) 분석&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴파일 후 생성되는 MAP 파일을 열어 전체 시스템의 스택 크기와 전역 변수 배치를 수시로 확인해야 합니다.툴체인(Keil, IAR, GCC)에서 제공하는 MAP 파일에서 STACK 또는 __stack_limit 키워드를 검색하여, 설계한 스택 사이즈가 메모리 맵 상에 안전하게 정렬되어 있는지 확인합니다. GCC 기준 -fstack-usage 플래그를 컴파일러 옵션에 추가하면, 각 함수가 소비하는 정확한 스택 크기가 .su 파일로 출력되므로 어떤 함수가 범인인지 정량적으로 추적할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;스택 가드 패턴 (Stack Canary / Guard Pattern) 활용&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스택의 최하단(종료 경계면) 메모리에 특정 매직 넘버(예: 0xDEADBEEF)를 써두고, 시스템 소프트웨어나 타이머 ISR에서 이 값이 유지되고 있는지 주기적으로 감킹(Monitoring)하는 기법입니다. RTOS 환경이라면 &lt;b&gt;Stack Overflow Hook&lt;/b&gt; 기능(configCHECK_FOR_STACK_OVERFLOW)을 활성화하여 런타임에 경계를 넘는 순간 즉시 트랩(Trap)을 걸 수 있도록 설정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;디버거 레지스터 윈도우 (SP 레지스터 추적)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;J-Link 또는 ST-Link를 연결한 상태에서 HardFault가 발생했다면, IDE의 Register View를 열어 SP(R13) 값을 확인합니다. 링크 스크립트에서 정의한 스택 범위를 벗어난 주소값이 SP에 찍혀있다면 100% 스택 오버플로우입니다. 복귀 주소가 저장되는 LR(Link Register, R14) 값을 역추적하여 하드폴트 직전에 실행 중이던 함수를 찾아내야 합니다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Troubleshooting</category>
      <category>BareMetal</category>
      <category>EmbeddedC</category>
      <category>HardFault</category>
      <category>MapFile</category>
      <category>stackoverflow</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1175</guid>
      <comments>https://coding-by-head.tistory.com/entry/stack-overflow#entry1175comment</comments>
      <pubDate>Fri, 5 Jun 2026 21:31:15 +0900</pubDate>
    </item>
    <item>
      <title>임베디드 개발자를 위한 패스트부트(Fastboot) 활용 완벽 가이드</title>
      <link>https://coding-by-head.tistory.com/entry/%EC%9E%84%EB%B2%A0%EB%94%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%8C%A8%EC%8A%A4%ED%8A%B8%EB%B6%80%ED%8A%B8Fastboot-%ED%99%9C%EC%9A%A9-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C</link>
      <description>&lt;p data-path-to-node=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 시스템 개발과 안드로이드 기기 유지보수 과정에서 하드웨어와 PC 사이의 통신은 매우 중요한 단계입니다. 특히 운영체제가 정상적으로 동작하지 않거나, 펌웨어 레벨에서 직접 파티션 데이터를 제어해야 할 때 가장 먼저 떠올리는 도구가 바로 패스트부트(Fastboot)입니다. 이번 글에서는 패스트부트의 정의와 동작 원리, ADB를 활용한 진입 방법, 그리고 실무에서 활용하는 핵심 명령어와 주의사항을 정리해 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_c9vrrhc9vrrhc9vr.png&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;848&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ozQdc/dJMcahR1KVq/DvtFCYbuZ3TZYsSbhOMEVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ozQdc/dJMcahR1KVq/DvtFCYbuZ3TZYsSbhOMEVk/img.png&quot; data-alt=&quot;Generated by Gemini AI.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ozQdc/dJMcahR1KVq/DvtFCYbuZ3TZYsSbhOMEVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FozQdc%2FdJMcahR1KVq%2FDvtFCYbuZ3TZYsSbhOMEVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1264&quot; height=&quot;848&quot; data-filename=&quot;Gemini_Generated_Image_c9vrrhc9vrrhc9vr.png&quot; data-origin-width=&quot;1264&quot; data-origin-height=&quot;848&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Generated by Gemini AI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;1&quot; data-ke-size=&quot;size23&quot;&gt;핵심 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;패스트부트는 부트로더 모드에서 PC와 기기 간 통신을 가능하게 하여, 운영체제 부팅 없이 파티션 쓰기 및 데이터 전송을 수행하는 프로토콜입니다.&lt;/li&gt;
&lt;li&gt;사용자는 fastboot flash, fastboot erase 등의 명령어로 커널, 루트 파일시스템, 리커버리 이미지 등을 기기에 직접 기록할 수 있습니다.&lt;/li&gt;
&lt;li&gt;안정적인 패스트부트 활용을 위해서는 대상 기기의 USB 드라이버 설치와 적절한 파티션 정보 확인이 필수적으로 선행되어야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;1. 패스트부트(Fastboot)의 개념과 역할&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;패스트부트는 부트로더(Bootloader)에 내장된 작은 서버 프로그램입니다. 시스템이 부팅되기 전 단계인 부트로더 모드에서 작동하며, USB를 통해 PC로부터 명령을 받아 기기 내부의 저장 장치(eMMC, UFS 등)에 접근합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;6&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;분류&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0,0&quot;&gt;작동 환경&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,1,0&quot;&gt;부트로더(Bootloader) 모드&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,2,0,0&quot;&gt;주요 목적&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,1,0&quot;&gt;펌웨어 이미지 플래싱, 파티션 삭제, 기기 잠금 해제&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,3,0,0&quot;&gt;통신 방식&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,1,0&quot;&gt;USB 기반의 커맨드 라인 인터페이스(CLI)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;2. ADB를 활용한 fastboot 진입 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기기의 물리 버튼(볼륨/전원 키)을 사용하지 않고도, 안드로이드 운영체제가 부팅된 상태라면 ADB 명령어를 통해 손쉽게 부트로더 모드로 전환할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-path-to-node=&quot;2&quot;&gt;
&lt;li&gt;ADB 연결 확인: adb devices 명령어를 입력하여 기기가 정상적으로 인식되는지 확인합니다.&lt;/li&gt;
&lt;li&gt;부트로더 진입 명령어: 아래 명령어를 터미널에 입력하십시오.
&lt;pre id=&quot;code_1779457137314&quot; class=&quot;ebnf&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;adb reboot bootloader&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;결과: 기기가 자동으로 재부팅되며 즉시 패스트부트 모드로 진입합니다. 이후 PC에서 fastboot devices 명령어를 통해 연결 상태를 확인하면 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;3. 필수 패스트부트 명령어 가이드&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;실무에서 가장 빈번하게 사용되는 명령어들을 정리한 표입니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;9&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;명령어&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,1,0,0&quot;&gt;fastboot devices&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,1,1,0&quot;&gt;연결된 기기의 시리얼 번호 확인&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,2,0,0&quot;&gt;fastboot flash [part] [file]&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,2,1,0&quot;&gt;지정된 파티션에 이미지 파일 기록&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,3,0,0&quot;&gt;fastboot erase [part]&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,3,1,0&quot;&gt;특정 파티션의 데이터 삭제&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,4,0,0&quot;&gt;fastboot reboot&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,4,1,0&quot;&gt;기기 재부팅&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,5,0,0&quot;&gt;fastboot boot [kernel]&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,5,1,0&quot;&gt;플래싱 없이 커널 이미지만 일시적으로 실행&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;4. 패스트부트 사용 순서&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,0,0&quot;&gt;기기 모드 진입&lt;/b&gt;: 기기를 부트로더 모드로 부팅합니다(일반적으로 볼륨 키와 전원 키 조합).&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,1,0&quot;&gt;연결 확인&lt;/b&gt;: PC와 기기를 USB 케이블로 연결한 후 fastboot devices로 연결 상태를 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,2,0&quot;&gt;작업 수행&lt;/b&gt;: 필요한 이미지를 플래싱하거나 파티션을 조작합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,3,0&quot;&gt;종료&lt;/b&gt;: fastboot reboot를 입력하여 정상 운영체제로 복귀합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size23&quot;&gt;5. 개발을 위한 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;13&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,0,0&quot;&gt;전용 케이블 사용&lt;/b&gt;: 패스트부트는 USB 데이터 전송 안정성에 민감합니다. 충전 전용 케이블이 아닌, 데이터 통신이 보장된 품질 좋은 USB 케이블을 사용하는 것만으로도 플래싱 실패 확률을 크게 줄일 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,1,0&quot;&gt;이미지 백업&lt;/b&gt;: 플래싱 작업을 수행하기 전, fastboot readback 기능(기기 지원 시)이나 별도의 백업 수단을 통해 기존 데이터를 반드시 보관해 두어야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size23&quot;&gt;6. 흔히 하는 실수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;15&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15,0,0&quot;&gt;드라이버 미설치&lt;/b&gt;: PC에서 fastboot devices를 입력했는데 응답이 없다면 기기 문제가 아니라 PC 측 USB 드라이버 문제일 확률이 매우 높습니다. OS에 맞는 정식 USB 드라이버를 설치하세요.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15,1,0&quot;&gt;이미지 파티션 오기입&lt;/b&gt;: fastboot flash boot [이미지 파일]을 수행해야 할 곳에 system 파티션을 지정하는 등 대상 파티션을 잘못 선택하면 시스템이 부팅되지 않는 치명적인 오류가 발생합니다. 명령 실행 전 항상 파티션 명칭을 확인하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;패스트부트는 임베디드 및 모바일 개발자에게는 없어서는 안 될 가장 기초적이면서도 강력한 도구입니다. 하드웨어의 부팅 흐름을 이해하고 패스트부트를 능숙하게 다룰 수 있게 된다면, 펌웨어 업데이트부터 시스템 복구까지 다양한 상황에 유연하게 대응할 수 있을 것입니다. 오늘 소개한 명령어와 주의사항을 잘 숙지하여 보다 효율적인 개발 환경을 만들어 보시기 바랍니다.&lt;/p&gt;</description>
      <category>Embedded System/Bootloader &amp;amp; System Startup</category>
      <category>fastboot</category>
      <category>u-boot</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1163</guid>
      <comments>https://coding-by-head.tistory.com/entry/%EC%9E%84%EB%B2%A0%EB%94%94%EB%93%9C-%EA%B0%9C%EB%B0%9C%EC%9E%90%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%8C%A8%EC%8A%A4%ED%8A%B8%EB%B6%80%ED%8A%B8Fastboot-%ED%99%9C%EC%9A%A9-%EC%99%84%EB%B2%BD-%EA%B0%80%EC%9D%B4%EB%93%9C#entry1163comment</comments>
      <pubDate>Fri, 22 May 2026 22:41:07 +0900</pubDate>
    </item>
    <item>
      <title>임베디드 리눅스 U-Boot 드라이버 모델(DM): I2C 드라이버 구현 가이드</title>
      <link>https://coding-by-head.tistory.com/entry/u-boot-i2c</link>
      <description>&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 시스템이 고도화되면서 하드웨어 제어 방식에도 변화가 필요해졌습니다. 과거의 임베디드 드라이버는 특정 하드웨어 레지스터에 직접 접근하거나 전역 함수를 호출하는 방식이 주를 이루었지만, 이는 코드의 의존성을 높이고 유지보수를 어렵게 만드는 원인이 되었습니다. 이러한 문제를 해결하기 위해 도입된 것이 바로 드라이버 모델(Driver Model, DM)입니다. 이번 글에서는 U-Boot의 표준으로 자리 잡은 DM 기반 I2C 드라이버의 구조와 실제 구현 방법을 실무적인 관점에서 정리해 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_1vn8il1vn8il1vn8.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pxuGV/dJMcaicewXM/TA0SRtgfxp3n5p33sQIki1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pxuGV/dJMcaicewXM/TA0SRtgfxp3n5p33sQIki1/img.png&quot; data-alt=&quot;Generated by Gemini AI.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pxuGV/dJMcaicewXM/TA0SRtgfxp3n5p33sQIki1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpxuGV%2FdJMcaicewXM%2FTA0SRtgfxp3n5p33sQIki1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;470&quot; height=&quot;470&quot; data-filename=&quot;Gemini_Generated_Image_1vn8il1vn8il1vn8.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Generated by Gemini AI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;1&quot; data-ke-size=&quot;size23&quot;&gt;핵심 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;드라이버 모델(DM)은 드라이버와 하드웨어를 분리하여 유지보수성과 확장성을 높이며, 디바이스 트리(Device Tree)를 통해 하드웨어 구성을 유연하게 관리합니다.&lt;/li&gt;
&lt;li&gt;DM I2C 드라이버는 struct dm_i2c_ops를 통해 통신 로직을 구현하고 U_BOOT_DRIVER 매크로를 통해 시스템에 등록하는 구조를 가집니다.&lt;/li&gt;
&lt;li&gt;dm tree 명령어와 디바이스 트리 설정을 활용하면 드라이버 바인딩 상태를 쉽게 점검하고 시스템 변경에 대응할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;1. DM I2C 드라이버의 핵심 구성 요소&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;DM 체계에서 I2C 드라이버를 작성하려면 드라이버의 동작을 정의하는 인터페이스와 시스템 등록을 위한 메타데이터가 필요합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;6&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구성 요소&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0,0&quot;&gt;struct dm_i2c_ops&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,1,0&quot;&gt;데이터 전송(xfer), 속도 설정(set_speed) 등 하드웨어 제어 로직 정의&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,2,0,0&quot;&gt;U_BOOT_DRIVER&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,1,0&quot;&gt;드라이버 이름, ID, ops 등을 시스템에 등록하는 매크로&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,3,0,0&quot;&gt;Device Tree&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,1,0&quot;&gt;하드웨어 사양과 드라이버를 매칭하는 연결 고리&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;2. 구현 코드: I2C Operations 정의&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;하드웨어가 실제 데이터를 주고받는 로직을 dm_i2c_ops 구조체에 구현해야 합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwijyMu4-8yUAxUAAAAAHQAAAAAQ4AM&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;C&lt;/span&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;/* I2C 통신을 위한 실제 동작 정의 */
static int my_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) {
    /* 하드웨어 레지스터 제어 로직 구현 */
    return 0;
}

static int my_i2c_set_bus_speed(struct udevice *bus, unsigned int speed) {
    /* 클럭 제어 로직 구현 */
    return 0;
}

/* Operations 구조체 연결 */
static const struct dm_i2c_ops my_i2c_ops = {
    .xfer           = my_i2c_xfer,
    .set_bus_speed  = my_i2c_set_bus_speed,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;3. 드라이버 등록 및 매칭&lt;/h3&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;작성한 드라이버가 디바이스 트리의 compatible 문자열과 매칭되도록 설정합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwijyMu4-8yUAxUAAAAAHQAAAAAQ4QM&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;C&lt;/span&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;static const struct udevice_id my_i2c_ids[] = {
    { .compatible = &quot;myvendor,my-i2c-controller&quot; },
    { }
};

U_BOOT_DRIVER(my_i2c_drv) = {
    .name   = &quot;my_i2c_drv&quot;,
    .id     = UCLASS_I2C,        /* I2C 클래스로 등록 */
    .of_match = my_i2c_ids,
    .ops    = &amp;amp;my_i2c_ops,
    .priv_auto = sizeof(struct my_i2c_priv),
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;4. 디바이스 트리(DTS) 설정 예시&lt;/h3&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;보드 설정 파일(.dts)에서 해당 컨트롤러를 활성화하고, 하위 장치를 명시합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwijyMu4-8yUAxUAAAAAHQAAAAAQ4gM&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;DTS&lt;/span&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;&amp;amp;i2c0 {
    compatible = &quot;myvendor,my-i2c-controller&quot;;
    reg = &amp;lt;0x12340000 0x1000&amp;gt;;
    status = &quot;okay&quot;;
    clock-frequency = &amp;lt;400000&amp;gt;;

    eeprom@50 {
        compatible = &quot;atmel,24c02&quot;;
        reg = &amp;lt;0x50&amp;gt;;
    };
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size23&quot;&gt;5. 개발을 위한 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,0,0&quot;&gt;명령어 활용&lt;/b&gt;: 디버깅 시 U-Boot 콘솔에서 dm tree 명령어를 사용하세요. 작성한 I2C 컨트롤러가 UCLASS_I2C 아래에 바인딩되었는지, 혹시 prob 단계에서 에러가 발생했는지 즉시 확인할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,1,0&quot;&gt;에러 코드 준수&lt;/b&gt;: 통신 실패 시 단순히 0을 반환하지 말고 -ETIMEDOUT, -EIO 등 표준 에러 코드를 반환하세요. 그래야 상위 계층에서 어떤 이유로 통신이 실패했는지 인지하고 재시도 로직을 가동할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size23&quot;&gt;6. 흔히 하는 실수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;19&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,0,0&quot;&gt;Probe 순서 누락&lt;/b&gt;: probe 함수를 구현할 때 클럭 초기화와 핀 매핑(Pinmux)이 선행되지 않으면 하드웨어 동작이 보장되지 않습니다. 초기화 순서를 항상 확인하세요.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,1,0&quot;&gt;메모리 할당 오류&lt;/b&gt;: priv_auto를 사용하여 드라이버 내부 데이터를 관리할 때, 데이터 크기 계산을 잘못하여 메모리 오버런이 발생하는 경우가 잦습니다. 구조체 크기를 항상 정확히 지정하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;21&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;DM 기반 드라이버는 구현 초기에는 구조가 낯설고 복잡해 보일 수 있습니다. 하지만 드라이버와 하드웨어를 분리해 설계하는 방식은 시스템 규모가 커질수록 압도적인 유지보수 효율을 제공합니다. 오늘 다룬 구조를 바탕으로 디바이스 트리를 활용한 드라이버 개발에 익숙해진다면, 다양한 하드웨어 변경에도 유연하게 대처하는 역량 있는 임베디드 개발자가 될 것입니다.&lt;/p&gt;</description>
      <category>Embedded System/Bootloader &amp;amp; System Startup</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1150</guid>
      <comments>https://coding-by-head.tistory.com/entry/u-boot-i2c#entry1150comment</comments>
      <pubDate>Sun, 10 May 2026 15:09:14 +0900</pubDate>
    </item>
    <item>
      <title>2026년 무료 코드 편집기 종결자: Rust 기반 'Zed'가 VS Code보다 빠른 이유</title>
      <link>https://coding-by-head.tistory.com/entry/trend-zed</link>
      <description>&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;개발자에게 편집기는 단순한 도구를 넘어 '손'과 같습니다. 하지만 최근 AI 기능이 비대해지면서 우리가 사랑했던 VS Code마저 무겁게 느껴질 때가 많죠.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;오늘은 2026년 현재, 미친듯한 퍼포먼스로 개발 생태계를 뒤흔들고 있는 초고속 오픈소스 에디터, Zed(제드)를 심층 분석합니다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;5&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_k05qlhk05qlhk05q.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/opTTa/dJMcaaE8wEo/J5ACvxFLCDtquMp675kOBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/opTTa/dJMcaaE8wEo/J5ACvxFLCDtquMp675kOBk/img.png&quot; data-alt=&quot;Generated by Gemini AI.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/opTTa/dJMcaaE8wEo/J5ACvxFLCDtquMp675kOBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FopTTa%2FdJMcaaE8wEo%2FJ5ACvxFLCDtquMp675kOBk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;354&quot; height=&quot;354&quot; data-filename=&quot;Gemini_Generated_Image_k05qlhk05qlhk05q.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Generated by Gemini AI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6&quot;&gt;핵심 요약 (TL;DR)&lt;/b&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;7&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,0,0&quot;&gt;압도적 성능:&lt;/b&gt; Rust 언어와 GPU 가속을 활용해 응답 지연(Latency)이 거의 '0'에 수렴합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,1,0&quot;&gt;협업의 진화:&lt;/b&gt; 별도의 설정 없이도 팀원과 실시간으로 코드를 짜는 강력한 멀티플레이어 편집 기능을 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,2,0&quot;&gt;가벼운 AI:&lt;/b&gt; VS Code보다 훨씬 적은 자원을 소모하면서도 최신 AI 모델과 유연하게 통합됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-path-to-node=&quot;8&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9&quot;&gt;1. 왜 다시 '속도'인가? Rust가 만든 기적&lt;/b&gt;&lt;/h3&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;최근 몇 년간 개발 툴들은 일렉트론(Electron) 기반의 무거운 환경이 주를 이뤘습니다. 하지만 Zed는 다릅니다. &lt;b data-index-in-node=&quot;67&quot; data-path-to-node=&quot;10&quot;&gt;Rust&lt;/b&gt;로 바닥부터 설계되었으며, 렌더링에 &lt;b data-index-in-node=&quot;91&quot; data-path-to-node=&quot;10&quot;&gt;GPU 가속&lt;/b&gt;을 직접 사용합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,0,0&quot;&gt;Zero Latency:&lt;/b&gt; 타이핑을 하는 즉시 화면에 반영되는 속도는 임베디드 개발자나 시스템 프로그래머들이 추구하는 '즉각성'을 완벽히 만족시킵니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,1,0&quot;&gt;VS Code와의 비교:&lt;/b&gt; 수십 개의 익스텐션을 설치한 VS Code가 실행되는 동안, Zed는 이미 빌드를 마칠 준비가 되어 있을 정도로 가볍습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12&quot;&gt;2. 2026년 개발의 핵심: AI와 실시간 협업&lt;/b&gt;&lt;/h3&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;단순히 빠르기만 해서는 대세가 될 수 없죠. Zed는 현대 개발 트렌드인 'AI'와 '협업'을 핵심 기능으로 내장했습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;14&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;기능&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;기대 효과&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;14,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,1,0,0&quot;&gt;Native AI Integration&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;14,1,1,0&quot;&gt;모델을 직접 연결해 코드 자동 완성 및 리팩토링 지원&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;14,1,2,0&quot;&gt;무거운 플러그인 없이도 지능형 코딩 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;14,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,2,0,0&quot;&gt;Multiplayer Editing&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;14,2,1,0&quot;&gt;링크 하나로 즉시 동료와 같은 화면에서 코드 수정&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;14,2,2,0&quot;&gt;페어 프로그래밍(Pair Programming) 효율 극대화&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;14,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,3,0,0&quot;&gt;GPU Rasterization&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;14,3,1,0&quot;&gt;모든 텍스트 렌더링을 GPU가 처리&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;14,3,2,0&quot;&gt;대용량 소스 파일 로딩 시 버벅임 제로&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15&quot;&gt;3. 미니멀리즘 개발자를 위한 Zed 세팅 가이드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;Zed의 철학은 &quot;불필요한 것은 걷어내고 본질에 집중한다&quot;입니다. 리눅스나 macOS 환경에서 개발하신다면 아래의 포인트만 기억하세요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,0,0&quot;&gt;Vim Mode 지원:&lt;/b&gt; 기존 Vim 유저라면 별도 학습 없이 바로 적응할 수 있는 완성도 높은 Vim 모드를 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,1,0&quot;&gt;LSP(Language Server Protocol) 내장:&lt;/b&gt; C, Rust, Python, Go 등 주요 언어의 자동 완성 및 정의 이동이 설정 없이도 매끄럽게 작동합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,2,0&quot;&gt;오픈소스 &amp;amp; 무료:&lt;/b&gt; 이 모든 강력한 기능이 완전히 무료이며, 커뮤니티의 힘으로 빠르게 진화하고 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;18&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19&quot;&gt;마치며: VS Code를 지울 때가 되었을까?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-path-to-node=&quot;20&quot; data-ke-size=&quot;size16&quot;&gt;물론 풍부한 에코시스템을 가진 VS Code를 당장 완전히 대체하기는 어려울 수 있습니다. 하지만 &quot;빠른 프로토타이핑&quot;과 &quot;집중력 있는 코딩 환경&quot;을 원하는 개발자들에게 Zed는 2026년 최고의 선택지입니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;특히 저사양 환경에서도 최상의 퍼포먼스를 내야 하는 시스템 개발자나, 복잡한 설정 없이 깔끔한 툴을 선호하는 주니어 개발자 모두에게 강력히 추천합니다.&lt;/p&gt;</description>
      <category>Edge AI &amp;amp; Cloud</category>
      <category>Rust</category>
      <category>zed</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1134</guid>
      <comments>https://coding-by-head.tistory.com/entry/trend-zed#entry1134comment</comments>
      <pubDate>Tue, 28 Apr 2026 21:34:31 +0900</pubDate>
    </item>
    <item>
      <title>2026년 필수 개발 툴: Cursor(커서) 사용기 - VS Code를 넘어선 AI 네이티브 에디터의 시대</title>
      <link>https://coding-by-head.tistory.com/entry/trend-ai-coding</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt; 코딩은 AI가, 검토는 내가: Cursor로 개발 속도 3배 높이는 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_lt3fiqlt3fiqlt3f.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pF8kc/dJMcacwakGg/kJqtmRO46koZk2dK1a3vSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pF8kc/dJMcacwakGg/kJqtmRO46koZk2dK1a3vSk/img.png&quot; data-alt=&quot;Gemini AI 생성 이미지입니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pF8kc/dJMcacwakGg/kJqtmRO46koZk2dK1a3vSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpF8kc%2FdJMcacwakGg%2FkJqtmRO46koZk2dK1a3vSk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;417&quot; height=&quot;417&quot; data-filename=&quot;Gemini_Generated_Image_lt3fiqlt3fiqlt3f.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Gemini AI 생성 이미지입니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6&quot;&gt;1. 개요: 텍스트 편집기에서 AI 개발 환경(IDE)으로&lt;/b&gt;&lt;/h3&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;불과 몇 년 전까지만 해도 개발자의 기본 소양은 VS Code의 다양한 확장을 얼마나 잘 활용하느냐에 달려 있었습니다. 하지만 &lt;b data-index-in-node=&quot;71&quot; data-path-to-node=&quot;7&quot;&gt;2026년 현재, 개발 환경의 패러다임은 완전히 바뀌었습니다.&lt;/b&gt; 단순한 코드 완성(Autocomplete)을 넘어, 프로젝트 전체의 맥락을 이해하고 로직을 설계하는 **'AI 네이티브 에디터'**가 표준이 되었습니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;오늘 소개할 **Cursor(커서)**는 &quot;더 이상 VS Code로 돌아갈 수 없다&quot;는 찬사를 받으며 AI 시대의 새로운 강자로 떠오른 도구입니다. 왜 수많은 임베디드 및 SW 개발자들이 기존 환경을 버리고 Cursor로 이주하고 있는지, 그 핵심 이유와 활용 팁을 정리해 보겠습니다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;9&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10&quot;&gt;2. Cursor(커서): 왜 2026년 최고의 에디터인가?&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11&quot;&gt;2.1 VS Code의 완벽한 계승과 진화&lt;/b&gt;&lt;/h4&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;Cursor는 VS Code를 포크(Fork)하여 제작되었습니다. 이는 기존에 사용하던 &lt;b data-index-in-node=&quot;49&quot; data-path-to-node=&quot;12&quot;&gt;VS Code의 테마, 단축키, 확장 프로그램(Extensions)을 클릭 한 번으로 그대로 가져올 수 있음&lt;/b&gt;을 의미합니다. 학습 비용 제로(0) 상태에서 AI 기능만 강력하게 업그레이드된 환경을 경험할 수 있습니다.&lt;/p&gt;
&lt;h4 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13&quot;&gt;2.2 코드 전체 맥락(Context)을 이해하는 AI&lt;/b&gt;&lt;/h4&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;기존의 코파일럿(Copilot)이 현재 열려 있는 파일 위주로 코드를 제안했다면, Cursor는 &lt;b data-index-in-node=&quot;54&quot; data-path-to-node=&quot;14&quot;&gt;프로젝트 전체 구조를 스캔&lt;/b&gt;합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;15&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;이 프로젝트의 인증 로직은 어디에 있어?&quot;&lt;/li&gt;
&lt;li&gt;&quot;새로운 API 엔드포인트를 기존 컨벤션에 맞춰 추가해 줘.&quot; 위와 같은 질문에 대해 프로젝트 내의 관련 파일을 스스로 찾아내어 정확한 코드를 생성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;16&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17&quot;&gt;3. 핵심 기능: 개발 속도를 3배 높이는 '치트키'&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18&quot;&gt;3.1 AI Chat &amp;amp; Composer (Cmd + K / Cmd + L)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;19&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,0,0&quot;&gt;Cmd + K (Edit):&lt;/b&gt; 코드의 특정 범위를 지정하고 명령을 내리면 실시간으로 코드를 수정합니다. 주석을 코드로 바꾸거나, 복잡한 정규식을 만드는 데 탁월합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,1,0&quot;&gt;Cmd + L (Chat):&lt;/b&gt; 코드에 대해 궁금한 점을 묻거나, 전체적인 아키텍처 설계를 상담할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20&quot;&gt;3.2 무료 플랜의 혜택&lt;/b&gt;&lt;/h4&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;Cursor는 유료 플랜(Pro)이 매우 강력하지만, &lt;b data-index-in-node=&quot;30&quot; data-path-to-node=&quot;21&quot;&gt;무료 사용자에게도 관대합니다.&lt;/b&gt; 기본 모델(Claude 3.5 Sonnet 혹은 GPT-4o 기반의 경량 모델)을 활용한 AI 제안 기능은 무료로도 충분히 매력적이며, 소규모 프로젝트나 학습용으로는 부족함이 없습니다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;22&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;23&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;23&quot;&gt;4. '소프트웨어 공장' 독자를 위한 실무 포스팅 포인트&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-path-to-node=&quot;24&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;24,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;24,0&quot;&gt;  &quot;더 이상 VS Code로 돌아갈 수 없다? 직접 써본 후기&quot;&lt;/b&gt; 처음에는 단순히 '조금 편해진 VS Code'라고 생각했습니다. 하지만 AI가 내 프로젝트의 레거시 코드를 분석해 버그를 찾아내고, 리팩토링 제안을 하는 순간 깨달았습니다. 이제 개발자의 역할은 '타이핑'이 아니라 AI가 짠 코드를 **'검토(Review)하고 승인'**하는 방향으로 진화하고 있다는 것을요.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;25&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,0,0&quot;&gt;임베디드 개발자라면?&lt;/b&gt; 복잡한 레지스터 설정이나 HAL 라이브러리 활용 예제를 Cursor에게 물어보세요. 데이터시트의 내용을 기반으로 초기화 코드를 짜는 속도가 비약적으로 상승합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,1,0&quot;&gt;웹/앱 개발자라면?&lt;/b&gt; 보일러플레이트 코드 생성을 AI에게 맡기고, 여러분은 핵심 비즈니스 로직 설계에 집중하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;26&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;27&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;27&quot;&gt;5. 결론: 도구를 바꾸는 것이 실력의 시작입니다&lt;/b&gt;&lt;/h3&gt;
&lt;p data-path-to-node=&quot;28&quot; data-ke-size=&quot;size16&quot;&gt;장인은 도구를 가리지 않는다고 하지만, 뛰어난 도구는 장인의 시간을 벌어줍니다. AI 네이티브 시대에 Cursor는 선택이 아닌 필수입니다. 아직 VS Code에 머물러 계신다면, 지금 바로 Cursor를 설치하고 **'AI와 협업하는 개발'**의 즐거움을 느껴보시기 바랍니다.&lt;/p&gt;</description>
      <category>Edge AI &amp;amp; Cloud</category>
      <category>ai에디터</category>
      <category>ai코딩</category>
      <category>cursor</category>
      <category>vsCode</category>
      <category>코드편집기추천</category>
      <category>프로그래밍도구</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1133</guid>
      <comments>https://coding-by-head.tistory.com/entry/trend-ai-coding#entry1133comment</comments>
      <pubDate>Mon, 27 Apr 2026 22:03:45 +0900</pubDate>
    </item>
    <item>
      <title>내 대화가 서버로? 인터넷 없는 AI, 온디바이스 LLM이 보안의 정답인 이유</title>
      <link>https://coding-by-head.tistory.com/entry/trend-ai-security</link>
      <description>&lt;h3 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6&quot;&gt;클라우드 AI의 편리함 뒤에 숨은 '데이터 유출' 공포&lt;/b&gt;&lt;/h3&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;ChatGPT, 클라우드 기반 AI 모델은 강력하지만 치명적인 약점이 있습니다. 바로 모든 데이터가 '외부 서버'로 전송되어야 한다는 점입니다. 기업의 기밀 소스 코드가 유출되거나 개인적인 의료 정보가 서버에 남는 것에 대한 불안감은 커지고 있습니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;이러한 문제를 원천적으로 해결하는 기술이 바로 **온디바이스 AI(On-Device AI)**입니다. 인터넷 연결 없이 기기 내부에서 돌아가는 이 기술이 어떻게 우리의 프라이버시를 지키는지, 기술적 깊이와 함께 살펴보겠습니다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;9&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_ebtgzkebtgzkebtg.png&quot; data-origin-width=&quot;1408&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l8e9X/dJMcagL2C4w/kuCuoW9FUqcRBd9cHZRmS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l8e9X/dJMcagL2C4w/kuCuoW9FUqcRBd9cHZRmS1/img.png&quot; data-alt=&quot;AI 보안과 관련한 Gemini AI 생성 이미지 입니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l8e9X/dJMcagL2C4w/kuCuoW9FUqcRBd9cHZRmS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl8e9X%2FdJMcagL2C4w%2FkuCuoW9FUqcRBd9cHZRmS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;594&quot; height=&quot;324&quot; data-filename=&quot;Gemini_Generated_Image_ebtgzkebtgzkebtg.png&quot; data-origin-width=&quot;1408&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;AI 보안과 관련한 Gemini AI 생성 이미지 입니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10&quot;&gt;1. 데이터 유출의 원천 봉쇄: 로컬 환경의 물리적 격리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;온디바이스 AI의 핵심은 데이터가 기기를 떠나지 않는다는 것입니다. 이는 단순히 '비행기 모드'에서 작동하는 수준을 넘어, OS 레벨에서의 강력한 보안 아키텍처를 기반으로 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;12&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,0,0&quot;&gt;안드로이드 프레임워크 수준의 격리:&lt;/b&gt; 안드로이드 OS는 AI 모델이 사용하는 데이터를 &lt;b data-index-in-node=&quot;47&quot; data-path-to-node=&quot;12,0,0&quot;&gt;AICore&lt;/b&gt;와 같은 전용 프레임워크 내에서 처리합니다. 앱 간 데이터 공유를 엄격히 제한하는 샌드박스 구조 덕분에, 특정 앱의 AI 활동이 다른 앱이나 외부 공격자에게 노출되지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,1,0&quot;&gt;리눅스 커널 커스텀 및 하드웨어 보안:&lt;/b&gt; 리눅스 커널 수준에서는 **TEE(Trusted Execution Environment)**를 활용합니다. 지문 인식 정보처럼 민감한 AI 연산 데이터를 일반 연산 구역과 물리적으로 분리된 '안전 구역'에서만 처리하도록 설계하여, OS가 해킹당하더라도 데이터 자체는 암호화된 상태로 보호됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;13&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14&quot;&gt;2. '로컬 LLM'이 바꿀 산업의 지형도&lt;/b&gt;&lt;/h3&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;인터넷 없이 돌아가는 **로컬 LLM(Large Language Model)**은 특히 보안이 생명인 분야에서 파괴적인 혁신을 일으키고 있습니다.&lt;/p&gt;
&lt;h4 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16&quot;&gt;① 의료 기기: 환자 정보의 완벽한 비식별화&lt;/b&gt;&lt;/h4&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;병원의 진단 데이터는 가장 민감한 정보입니다. 로컬 LLM이 탑재된 의료 기기는 환자의 데이터를 외부 클라우드로 보낼 필요 없이 현장에서 즉시 분석합니다. 이는 환자의 프라이버시를 보호하는 동시에, 네트워크 지연 없는 실시간 진단을 가능하게 합니다.&lt;/p&gt;
&lt;h4 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18&quot;&gt;② 스마트 가전: 우리 집 거실의 대화가 서버로 가지 않도록&lt;/b&gt;&lt;/h4&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;AI 스피커나 스마트 TV가 24시간 도청되고 있다는 불안감을 느껴본 적 있으신가요? 온디바이스 AI 기반 스마트 홈은 모든 음성 명령을 로컬에서 처리합니다. 가전제품이 내 습관을 학습하되, 그 데이터는 우리 집 거실 밖을 한 발짝도 나가지 않는 '프라이빗 AI 하우스'가 완성되는 것입니다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;20&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;21&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21&quot;&gt;3. 온디바이스 AI의 미래: 보안이 곧 경쟁력이다&lt;/b&gt;&lt;/h3&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;이제 사용자들은 성능만큼이나 '내 데이터를 얼마나 안전하게 다루는가'를 중요하게 생각합니다. NPU(신경망 처리 장치)의 발전으로 과거에는 불가능했던 대규모 연산이 스마트폰과 임베디드 기기 내에서 가능해졌습니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;결국 **'인터넷 없는 AI'**는 기술적 제약이 아니라, 사용자 신뢰를 얻기 위한 최선의 선택이 될 것입니다. 보안 사고로부터 자유로운 AI 환경, 온디바이스 AI가 그 미래를 앞당기고 있습니다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;24&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;25&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25&quot;&gt;결론: 보안 전문가가 온디바이스 AI를 주목하는 이유&lt;/b&gt;&lt;/h3&gt;
&lt;p data-path-to-node=&quot;26&quot; data-ke-size=&quot;size16&quot;&gt;데이터가 흐르는 통로 자체를 없애버리는 것보다 확실한 보안은 없습니다. 클라우드 AI의 효율성과 온디바이스 AI의 보안성이 결합된 하이브리드 모델이 대세가 되겠지만, **'개인정보의 마지노선'**은 언제나 온디바이스가 지키게 될 것입니다.&lt;/p&gt;</description>
      <category>Edge AI &amp;amp; Cloud</category>
      <category>AI보안</category>
      <category>ondeviceai</category>
      <category>개인정보보호</category>
      <category>데이터격리</category>
      <category>로컬llm</category>
      <category>리눅스커널</category>
      <category>스마트가전</category>
      <category>안드로이드보안</category>
      <category>온디바이스AI</category>
      <category>의료AI</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1126</guid>
      <comments>https://coding-by-head.tistory.com/entry/trend-ai-security#entry1126comment</comments>
      <pubDate>Wed, 22 Apr 2026 20:48:34 +0900</pubDate>
    </item>
    <item>
      <title>2026년 임베디드 개발자 로드맵: C++에서 'AI 프롬프트 엔지니어링'까지</title>
      <link>https://coding-by-head.tistory.com/entry/trend-embedded</link>
      <description>&lt;p data-path-to-node=&quot;3&quot; data-ke-size=&quot;size16&quot;&gt;2026년 현재, 임베디드 SW 개발 시장은 거대한 변곡점을 맞이했습니다. 단순히 회로도를 읽고 C/C++ 코드를 짜는 수준에 머문다면 시장에서의 가치는 정체될 수밖에 없습니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;이제 채용 시장이 원하는 인재는 **'AI가 짠 코드의 결함을 찾아내고, 무거운 AI 모델을 손바닥만 한 NPU에 구겨 넣을 수 있는 개발자'**입니다. 오늘은 연봉의 앞자리를 바꿀 수 있는 &lt;b data-index-in-node=&quot;107&quot; data-path-to-node=&quot;4&quot;&gt;2026년판 임베디드 로드맵&lt;/b&gt;을 핵심 기술 위주로 정리해 드립니다.&lt;/p&gt;
&lt;hr data-path-to-node=&quot;5&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_63o2be63o2be63o2.png&quot; data-origin-width=&quot;1408&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0EAcf/dJMb99MQCGN/QKnyUSxhkWgKeWC6yn8lh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0EAcf/dJMb99MQCGN/QKnyUSxhkWgKeWC6yn8lh0/img.png&quot; data-alt=&quot;Gemini AI가 작성한 임베디드 개발자 로드맵 이미지 입니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0EAcf/dJMb99MQCGN/QKnyUSxhkWgKeWC6yn8lh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0EAcf%2FdJMb99MQCGN%2FQKnyUSxhkWgKeWC6yn8lh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;634&quot; height=&quot;346&quot; data-filename=&quot;Gemini_Generated_Image_63o2be63o2be63o2.png&quot; data-origin-width=&quot;1408&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Gemini AI가 작성한 임베디드 개발자 로드맵 이미지 입니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size26&quot;&gt;1. 2026년, 왜 '전통적 임베디드'만으로는 부족한가?&lt;/h2&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;과거의 임베디드 개발이 하드웨어 제어와 리소스 최적화에 집중했다면, 지금은 **On-Device AI(온디바이스 AI)**의 시대입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;8&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,0,0&quot;&gt;AI 생성 코드의 범람:&lt;/b&gt; AI가 기본적인 펌웨어 코드를 작성하면서, 개발자의 역할은 '작성'에서 **'취약점 분석 및 검증'**으로 이동했습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,1,0&quot;&gt;NPU 하드웨어의 보편화:&lt;/b&gt; 저전력 MCU에도 NPU(Neural Processing Unit)가 탑재되면서, 이를 다루는 SW 역량이 필수 스택이 되었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;9&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size26&quot;&gt;2. 몸값을 결정짓는 핵심 키워드: '모델 압축'과 '런타임'&lt;/h2&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;전통적인 C/C++ 역량 위에 다음 두 가지 무기를 장착했을 때 개발자의 몸값은 폭등합니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size23&quot;&gt;① 모델 압축 (Model Compression) &amp;amp; 양자화 (Quantization)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;AI 모델은 본래 무겁습니다. 이를 엣지(Edge) 환경에 올리기 위해서는 &lt;b data-index-in-node=&quot;42&quot; data-path-to-node=&quot;13&quot;&gt;양자화(Quantization)&lt;/b&gt; 기술이 핵심입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;14&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,0,0&quot;&gt;INT8 / INT4 양자화:&lt;/b&gt; FP32 정밀도를 유지하면서 데이터 크기를 1/4로 줄여 NPU 효율을 극대화하는 능력.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,1,0&quot;&gt;Pruning(가지치기):&lt;/b&gt; 성능 저하 없이 불필요한 연산을 제거하여 메모리 점유율을 낮추는 기술.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size23&quot;&gt;② ONNX 및 TensorFlow Lite 숙련도&lt;/h3&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;학습된 모델을 실제 타겟 하드웨어에 이식하기 위한 가교 역할을 이해해야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,0,0&quot;&gt;ONNX(Open Neural Network Exchange):&lt;/b&gt; 다양한 프레임워크 간의 모델 호환성 해결.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,1,0&quot;&gt;TFLite Micro:&lt;/b&gt; 극도로 제한된 환경(Cortex-M 등)에서 AI 추론 엔진을 최적화하여 구동하는 역량.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;18&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size26&quot;&gt;3. 2026 임베디드 개발자 필승 로드맵 (Step-by-Step)&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;20&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;단계&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;목표&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;필수 스택&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;20,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,1,0,0&quot;&gt;Step 1&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;20,1,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,1,1,0&quot;&gt;심화 C++ &amp;amp; Rust&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;20,1,2,0&quot;&gt;Modern C++, Rust(메모리 안전성), 실시간 시스템 보안&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;20,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,2,0,0&quot;&gt;Step 2&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;20,2,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,2,1,0&quot;&gt;AI 프롬프트 엔지니어링&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;20,2,2,0&quot;&gt;LLM 기반 코드 리뷰, 취약점(Vulnerability) 자동 탐지 기법&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;20,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,3,0,0&quot;&gt;Step 3&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;20,3,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,3,1,0&quot;&gt;엣지 AI 프레임워크&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;20,3,2,0&quot;&gt;ONNX Runtime, TVM, TensorFlow Lite 활용 능력&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;20,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,4,0,0&quot;&gt;Step 4&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;20,4,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,4,1,0&quot;&gt;NPU 최적화 전문가&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;20,4,2,0&quot;&gt;하드웨어 가속기 구조 이해, 가중치 양자화(QAT, PTQ)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-path-to-node=&quot;21&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size26&quot;&gt;4. 커리어 전환을 위한 실무 팁&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;23&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;23,0,0&quot;&gt;Github 포트폴리오를 업데이트하세요:&lt;/b&gt; 단순한 드라이버 구현보다는, &quot;Pre-trained 모델을 특정 NPU 보드에 양자화하여 이식한 프로젝트&quot;가 2026년에는 훨씬 강력한 힘을 발휘합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;23,1,0&quot;&gt;AI 코드를 의심하세요:&lt;/b&gt; AI가 생성한 코드에서 발생할 수 있는 Race Condition이나 메모리 누수를 정적/동적 분석 도구로 잡아내는 과정을 블로그에 기록하세요. 그것이 곧 여러분의 전문성입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-path-to-node=&quot;24&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-path-to-node=&quot;25&quot; data-ke-size=&quot;size26&quot;&gt;  함께 읽으면 좋은 글 (블로그 내부 링크 추천)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;26&quot; data-ke-size=&quot;size16&quot;&gt;글의 전문성을 높이고 체류 시간을 늘리기 위해 아래 주제의 글들을 연계해 보세요.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;27&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;i data-index-in-node=&quot;0&quot; data-path-to-node=&quot;27,0,0&quot;&gt;기존 포스팅: [기술 심층] NPU TOPS 수치에 속지 마라: 진짜 성능 지표 분석&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i data-index-in-node=&quot;0&quot; data-path-to-node=&quot;27,1,0&quot;&gt;기존 포스팅: 딥엑스(DeepX) vs 래블업: 대한민국 엣지 AI 생태계 비교&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-path-to-node=&quot;28&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 data-path-to-node=&quot;29&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29&quot;&gt;마치며&lt;/b&gt;&lt;/h3&gt;
&lt;p data-path-to-node=&quot;30&quot; data-ke-size=&quot;size16&quot;&gt;2026년의 임베디드 개발자는 더 이상 하드웨어에 종속된 코더가 아닙니다. 하드웨어의 한계를 소프트웨어와 AI 최적화 기술로 극복하는 **'시스템 아키텍트'**입니다. 이 로드맵을 따라 기술 스택을 확장한다면, 채용 시장에서 대체 불가능한 존재가 될 것입니다.&lt;/p&gt;</description>
      <category>Edge AI &amp;amp; Cloud</category>
      <category>2026로드맵</category>
      <category>c++</category>
      <category>EdgeAI</category>
      <category>NPU최적화</category>
      <category>양자화</category>
      <category>온디바이스AI</category>
      <category>임베디드개발자</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1124</guid>
      <comments>https://coding-by-head.tistory.com/entry/trend-embedded#entry1124comment</comments>
      <pubDate>Tue, 21 Apr 2026 21:02:58 +0900</pubDate>
    </item>
    <item>
      <title>딥엑스(DeepX) vs 래블업(Lablup): 대한민국 엣지 AI 생태계를 이끄는 두 거인</title>
      <link>https://coding-by-head.tistory.com/entry/trend-deepx</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근 인공지능 시장의 무게중심이 거대한 클라우드 서버에서 우리 손안의 기기, 즉 &lt;b&gt;'엣지(Edge)'&lt;/b&gt;로 이동하고 있습니다. 대한민국 역시 이 분야에서 글로벌 수준의 경쟁력을 갖춘 기업들이 두각을 나타내고 있는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 엣지 AI 하드웨어의 혁신을 이끄는 &lt;b&gt;'딥엑스(DeepX)'&lt;/b&gt;와 AI 인프라 소프트웨어의 강자 &lt;b&gt;'래블업(Lablup)'&lt;/b&gt;을 비교 분석해 보겠습니다. 이 두 기업이 어떻게 대한민국 엣지 AI 생태계를 구축하고 있는지, 임베디드 개발자의 시각에서 살펴보겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_9pz2w09pz2w09pz2.png&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDfUO5/dJMcaiwfdu4/pNLLF81CUmkNhxO8UrYlY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDfUO5/dJMcaiwfdu4/pNLLF81CUmkNhxO8UrYlY0/img.png&quot; data-alt=&quot;Gemini AI로 생성한 DeepX 이미지 입니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDfUO5/dJMcaiwfdu4/pNLLF81CUmkNhxO8UrYlY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDfUO5%2FdJMcaiwfdu4%2FpNLLF81CUmkNhxO8UrYlY0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;555&quot; height=&quot;310&quot; data-filename=&quot;Gemini_Generated_Image_9pz2w09pz2w09pz2.png&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Gemini AI로 생성한 DeepX 이미지 입니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 하드웨어의 혁신: 딥엑스(DeepX)와 고성능 NPU&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딥엑스는 자체 설계한 NPU(Neural Processing Unit)를 통해 온디바이스 AI의 한계를 돌파하고 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;핵심 강점: 극강의 전력 효율(Efficiency)&lt;/b&gt;&lt;br /&gt;딥엑스의 칩셋(DX-V1, DX-M1 등)은 경쟁사 대비 훨씬 적은 전력을 소모하면서도 높은 연산 성능을 제공합니다. 이는 배터리 수명이 중요한 드론, 로봇, 스마트 가전 설계 시 결정적인 차이를 만듭니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;임베디드 설계 포인트:&lt;/b&gt;&lt;br /&gt;개발자는 딥엑스의 컴파일러를 통해 복잡한 AI 모델을 가볍게 최적화(Quantization)하여 하드웨어에 직접 올릴 수 있습니다. 특히 가상 환경이 아닌 '실제 물리 계층'에서의 실시간 제어에 최적화되어 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 소프트웨어의 지휘자: 래블업(Lablup)과 Backend.AI&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무리 좋은 하드웨어가 있어도 이를 효율적으로 관리할 소프트웨어가 없다면 자원은 낭비됩니다. 래블업은 이를 해결하는 &lt;b&gt;Backend.AI&lt;/b&gt; 솔루션을 제공합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;핵심 강점: 리소스 가상화 및 오케스트레이션&lt;/b&gt;&lt;br /&gt;래블업은 분산된 엣지 디바이스의 GPU나 NPU 자원을 마치 하나의 거대한 자원처럼 관리합니다. 필요한 만큼만 자원을 할당하고 회수하는 기술은 운영 비용 절감에 핵심적입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;임베디드 설계 포인트:&lt;/b&gt;&lt;br /&gt;엣지 디바이스가 수백 대에 달하는 스마트 팩토리나 도시 관제 시스템에서 래블업의 솔루션은 빛을 발합니다. 컨테이너 기반으로 AI 모델을 배포하고 모니터링하는 과정을 자동화하여 개발자의 운영 부담을 획기적으로 줄여줍니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 딥엑스 vs 래블업: 협력인가, 경쟁인가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이 두 기업은 경쟁 관계라기보다 &lt;b&gt;상호 보완적인 파트너&lt;/b&gt;에 가깝습니다.&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th align=&quot;left&quot;&gt;구분&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;딥엑스 (DeepX)&lt;/th&gt;
&lt;th align=&quot;left&quot;&gt;래블업 (Lablup)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;b&gt;주력 분야&lt;/b&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;AI 가속기 하드웨어 (NPU)&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;AI 인프라 관리 소프트웨어 (SaaS/PaaS)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;b&gt;핵심 역할&lt;/b&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;엣지 디바이스의 '뇌' 역할 수행&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;수많은 '뇌'를 연결하고 관리하는 '신경계'&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=&quot;left&quot;&gt;&lt;b&gt;주요 고객&lt;/b&gt;&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;로봇, 자율주행, 가전 제조사&lt;/td&gt;
&lt;td align=&quot;left&quot;&gt;연구소, 대학교, 대규모 AI 서비스 기업&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 &lt;b&gt;딥엑스의 고효율 하드웨어&lt;/b&gt; 위에 &lt;b&gt;래블업의 지능적인 인프라 관리&lt;/b&gt;가 더해질 때, 진정한 의미의 '지능형 엣지 생태계'가 완성된다고 볼 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 임베디드 개발자가 준비해야 할 것&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대한민국 엣지 AI 시장이 커질수록 우리 개발자들에게 요구되는 역량도 변하고 있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;하드웨어 가속기 최적화:&lt;/b&gt; 딥엑스와 같은 전용 NPU의 구조를 이해하고 모델을 이식하는 경험.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;클라우드-엣지 연동:&lt;/b&gt; 래블업과 같은 플랫폼을 통해 모델을 배포하고 버전 관리(MLOps)를 수행하는 프로세스 이해.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;리소스 관리:&lt;/b&gt; 한정된 엣지 자원을 어떻게 분배하여 서비스 가동률을 높일 것인가에 대한 고민.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마치며: 대한민국 AI의 미래는 엣지에 있다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라우드 AI 경쟁이 거대 자본의 싸움이라면, 엣지 AI는 &lt;b&gt;'효율과 최적화'&lt;/b&gt;의 싸움입니다. 딥엑스와 래블업 같은 기업들이 보여주는 혁신은 대한민국 임베디드 개발자들에게 새로운 기회의 장을 열어주고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여러분은 하드웨어 최적화와 인프라 관리 중 어느 분야에 더 관심이 있으신가요?&lt;/b&gt; 대한민국 엣지 AI 생태계에 대해 궁금한 점이 있다면 댓글로 남겨주세요!&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;함께 읽으면 좋은 글&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://coding-by-head.tistory.com/entry/trend-phygical-ai&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://coding-by-head.tistory.com/entry/trend-phygical-ai&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776687452388&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[CES 2026] '피지컬 AI' 시대의 개막: 왜 지금 임베디드 개발자의 몸값이 폭등하는가?&quot; data-og-description=&quot;[CES 2026] '피지컬 AI' 시대의 개막: 왜 지금 임베디드 개발자의 몸값이 폭등하는가?안녕하세요! 소프트웨어 공장입니다.지난 CES 2026의 핵심 키워드는 단연 '피지컬 AI(Physical AI)'였습니다. 이제 AI는 &quot; data-og-host=&quot;coding-by-head.tistory.com&quot; data-og-source-url=&quot;https://coding-by-head.tistory.com/entry/trend-phygical-ai&quot; data-og-url=&quot;https://coding-by-head.tistory.com/entry/trend-phygical-ai&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/zpi5e/dJMb9eff2K4/W9LmBAJsWK1gmzhgIl3Ft0/img.png?width=800&amp;amp;height=436&amp;amp;face=523_60_553_92,https://scrap.kakaocdn.net/dn/bjzv2h/dJMb9cBKavB/w2eTuGJobmQMkinC53tH71/img.png?width=800&amp;amp;height=436&amp;amp;face=523_60_553_92,https://scrap.kakaocdn.net/dn/eBEFh/dJMb9jOo0p3/lNQLEid9OHk9BegVniUmg1/img.png?width=1408&amp;amp;height=768&amp;amp;face=924_105_972_157&quot;&gt;&lt;a href=&quot;https://coding-by-head.tistory.com/entry/trend-phygical-ai&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://coding-by-head.tistory.com/entry/trend-phygical-ai&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/zpi5e/dJMb9eff2K4/W9LmBAJsWK1gmzhgIl3Ft0/img.png?width=800&amp;amp;height=436&amp;amp;face=523_60_553_92,https://scrap.kakaocdn.net/dn/bjzv2h/dJMb9cBKavB/w2eTuGJobmQMkinC53tH71/img.png?width=800&amp;amp;height=436&amp;amp;face=523_60_553_92,https://scrap.kakaocdn.net/dn/eBEFh/dJMb9jOo0p3/lNQLEid9OHk9BegVniUmg1/img.png?width=1408&amp;amp;height=768&amp;amp;face=924_105_972_157');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[CES 2026] '피지컬 AI' 시대의 개막: 왜 지금 임베디드 개발자의 몸값이 폭등하는가?&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;[CES 2026] '피지컬 AI' 시대의 개막: 왜 지금 임베디드 개발자의 몸값이 폭등하는가?안녕하세요! 소프트웨어 공장입니다.지난 CES 2026의 핵심 키워드는 단연 '피지컬 AI(Physical AI)'였습니다. 이제 AI는&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;coding-by-head.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://coding-by-head.tistory.com/entry/trend-npu-tops&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://coding-by-head.tistory.com/entry/trend-npu-tops&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776687483387&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;NPU TOPS 수치에 속지 마라: 임베디드 SW 개발자가 봐야 할 '진짜' AI 성능 지표&quot; data-og-description=&quot;NPU TOPS 수치에 속지 마라: 임베디드 SW 개발자가 봐야 할 '진짜' AI 성능 지표안녕하세요! 임베디드 개발 전문 블로그 소프트웨어 공장입니다.최근 애플, 퀄컴, 삼성 등 빅테크 기업들이 새로운 프&quot; data-og-host=&quot;coding-by-head.tistory.com&quot; data-og-source-url=&quot;https://coding-by-head.tistory.com/entry/trend-npu-tops&quot; data-og-url=&quot;https://coding-by-head.tistory.com/entry/trend-npu-tops&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dKasGX/dJMb8SXzP8n/5ljVhMjwHwDWOxXRKn61VK/img.png?width=800&amp;amp;height=446&amp;amp;face=0_0_800_446,https://scrap.kakaocdn.net/dn/r31dL/dJMb8Z3tmKV/Oi00nu5PjSHxHWVweN3u60/img.png?width=800&amp;amp;height=446&amp;amp;face=0_0_800_446,https://scrap.kakaocdn.net/dn/EbFqW/dJMb9jOo0qg/tEkEQh5Yzurag98jJoRupK/img.png?width=1376&amp;amp;height=768&amp;amp;face=0_0_1376_768&quot;&gt;&lt;a href=&quot;https://coding-by-head.tistory.com/entry/trend-npu-tops&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://coding-by-head.tistory.com/entry/trend-npu-tops&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dKasGX/dJMb8SXzP8n/5ljVhMjwHwDWOxXRKn61VK/img.png?width=800&amp;amp;height=446&amp;amp;face=0_0_800_446,https://scrap.kakaocdn.net/dn/r31dL/dJMb8Z3tmKV/Oi00nu5PjSHxHWVweN3u60/img.png?width=800&amp;amp;height=446&amp;amp;face=0_0_800_446,https://scrap.kakaocdn.net/dn/EbFqW/dJMb9jOo0qg/tEkEQh5Yzurag98jJoRupK/img.png?width=1376&amp;amp;height=768&amp;amp;face=0_0_1376_768');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;NPU TOPS 수치에 속지 마라: 임베디드 SW 개발자가 봐야 할 '진짜' AI 성능 지표&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;NPU TOPS 수치에 속지 마라: 임베디드 SW 개발자가 봐야 할 '진짜' AI 성능 지표안녕하세요! 임베디드 개발 전문 블로그 소프트웨어 공장입니다.최근 애플, 퀄컴, 삼성 등 빅테크 기업들이 새로운 프&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;coding-by-head.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Edge AI &amp;amp; Cloud</category>
      <category>BackendAI</category>
      <category>DeepX</category>
      <category>Lablup</category>
      <category>NPU</category>
      <category>딥엑스</category>
      <category>래블업</category>
      <category>엣지AI</category>
      <category>온디바이스AI</category>
      <category>인공지능트렌드</category>
      <category>임베디드개발</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1123</guid>
      <comments>https://coding-by-head.tistory.com/entry/trend-deepx#entry1123comment</comments>
      <pubDate>Mon, 20 Apr 2026 21:21:41 +0900</pubDate>
    </item>
    <item>
      <title>NPU TOPS 수치에 속지 마라: 임베디드 SW 개발자가 봐야 할 '진짜' AI 성능 지표</title>
      <link>https://coding-by-head.tistory.com/entry/trend-npu-tops</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;최근 애플, 퀄컴, 삼성 등 빅테크 기업들이 새로운 프로세서를 발표할 때마다 가장 앞세우는 수치가 있습니다. 바로 &lt;b&gt;&quot;45 TOPS 달성!&quot;, &quot;역대급 AI 연산 속도!&quot;&lt;/b&gt; 같은 마케팅 용어들입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 우리 같은 &lt;b&gt;임베디드 소프트웨어 엔지니어&lt;/b&gt;들은 알고 있습니다. 데이터시트에 적힌 TOPS 수치가 높다고 해서 내가 짠 모델이 무조건 빠르게 돌아가는 것은 아니라는 사실을요. 오늘은 마케팅 수치 뒤에 숨겨진 &lt;b&gt;NPU 성능의 진실과, 실무에서 반드시 체크해야 할 3가지 지표&lt;/b&gt;를 심층 분석해 보겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_zhzvjtzhzvjtzhzv.png&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vHd2y/dJMcagd9zFU/rL4MbyJKM861eLBhRP9e91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vHd2y/dJMcagd9zFU/rL4MbyJKM861eLBhRP9e91/img.png&quot; data-alt=&quot;Gemini AI를 이용해 제작한 NPU 성능과 연관된 이미지 입니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vHd2y/dJMcagd9zFU/rL4MbyJKM861eLBhRP9e91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvHd2y%2FdJMcagd9zFU%2FrL4MbyJKM861eLBhRP9e91%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;589&quot; height=&quot;329&quot; data-filename=&quot;Gemini_Generated_Image_zhzvjtzhzvjtzhzv.png&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Gemini AI를 이용해 제작한 NPU 성능과 연관된 이미지 입니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. TOPS 수치의 함정: INT8인가, FP16인가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TOPS(Tera Operations Per Second)는 초당 1조 번의 연산을 수행한다는 뜻입니다. 하지만 여기서 중요한 것은 &lt;b&gt;'어떤 데이터 타입으로 연산했는가'&lt;/b&gt;입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;INT8 (8-bit Integer):&lt;/b&gt; 대부분의 모바일/임베디드 NPU가 홍보용으로 사용하는 기준입니다. 연산 정밀도는 낮지만 속도는 매우 빠릅니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;FP16 (16-bit Floating Point):&lt;/b&gt; 모델의 정확도를 유지하기 위해 필요한 연산입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제는 많은 하드웨어 제조사가 INT8 기준으로 TOPS를 발표한다는 점입니다.&lt;/b&gt; 만약 여러분의 모델이 FP16 연산을 주로 사용한다면, 홍보된 TOPS의 절반, 혹은 그 이하의 성능밖에 내지 못할 수도 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  개발자 팁:&lt;/b&gt; NPU 데이터시트를 볼 때 단순 TOPS가 아니라 &lt;b&gt;&quot;Data Type별 처리량&quot;&lt;/b&gt;을 반드시 확인해야 모델 최적화(Quantization) 전략을 제대로 세울 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 연산 속도보다 무서운 병목, '메모리 대역폭(Memory Bandwidth)'&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무리 NPU 연산 엔진이 초당 수조 번을 계산할 수 있어도, 데이터를 공급해 주는 도로(메모리)가 좁으면 무용지물입니다. 이를 &lt;b&gt;'Memory Wall'&lt;/b&gt; 현상이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임베디드 환경에서는 특히 다음을 주의 깊게 봐야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;SRAM (Internal Memory) 용량:&lt;/b&gt; 모델의 가중치(Weights)가 내부 메모리에 한 번에 올라가는가?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DRAM 대역폭:&lt;/b&gt; 외부 메모리에서 데이터를 가져오는 속도가 NPU 연산 속도를 따라가는가?&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 실무에서는 &lt;b&gt;&quot;얼마나 빨리 계산하느냐&quot;&lt;/b&gt;보다 &lt;b&gt;&quot;데이터를 얼마나 끊김 없이 공급하느냐&quot;&lt;/b&gt;가 실제 프레임 속도(FPS)를 결정짓는 핵심 지표가 됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 임베디드의 숙명: 와트당 성능 (Performance per Watt)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버급 AI와 임베디드 AI의 결정적인 차이는 &lt;b&gt;'배터리'와 '발열'&lt;/b&gt;입니다. 50 TOPS의 성능을 내더라도 전력을 20W씩 소모한다면 핸드헬드 기기나 팬리스(Fanless) 임베디드 보드에서는 사용할 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 주목해야 할 진짜 지표는 &lt;b&gt;TOPS/W (와트당 연산 수)&lt;/b&gt;입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;발열 스로틀링(Throttling):&lt;/b&gt; 성능 수치가 아무리 좋아도 발열 때문에 1분 만에 성능이 반 토막 난다면 상용화가 불가능합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;에너지 효율:&lt;/b&gt; 딥엑스(DeepX) 같은 국산 NPU들이 글로벌 시장에서 주목받는 이유도 바로 이 '극강의 효율성' 때문입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 결론: 임베디드 개발자를 위한 체크리스트&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 프로젝트에서 AI 하드웨어를 선정하거나 성능을 리포팅해야 한다면, 단순 TOPS 대신 아래 질문을 던져보세요.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;&quot;우리가 타겟팅하는 자료형(INT8/INT16)에서 실제 가용 TOPS는 얼마인가?&quot;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&quot;메모리 병목 없이 모델의 레이어(Layer)를 실시간으로 처리할 수 있는 대역폭을 확보했는가?&quot;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&quot;지속적인 가동 시 발열로 인한 성능 저하(TDP 기준)는 어느 정도인가?&quot;&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마케팅용 수치에 속지 않고 '시스템 전체의 밸런스'를 보는 눈을 가질 때, 비로소 상용화 가능한 고성능 임베디드 AI 서비스를 만들 수 있습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여러분은 NPU 성능 지표 중 무엇이 가장 중요하다고 생각하시나요?&lt;/b&gt; 혹은 특정 칩셋에서 성능 최적화로 고생했던 경험이 있다면 댓글로 공유해 주세요! 함께 토론하며 성장하는 &lt;b&gt;소프트웨어 공장&lt;/b&gt;이 되겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;함께 읽으면 좋은 글&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;Python 데이터 증가&quot; href=&quot;https://coding-by-head.tistory.com/category/Python/Deep%20Learning&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://coding-by-head.tistory.com/category/Python/Deep%20Learning&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776579256010&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;'Python/Deep Learning' 카테고리의 글 목록&quot; data-og-description=&quot;임베디드 소프트웨어 개발을 위한 팁과 정보를 제공하는 '소프트웨어 공장'입니다. 함께 성장하는 개발 친구가 되어드릴게요!&quot; data-og-host=&quot;coding-by-head.tistory.com&quot; data-og-source-url=&quot;https://coding-by-head.tistory.com/category/Python/Deep%20Learning&quot; data-og-url=&quot;https://coding-by-head.tistory.com/category/Python/Deep%20Learning&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/nz599/dJMb86nZt3O/S77O226K2DrKcr2MRLhTiK/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/DJWYn/dJMb8UHQ26L/Wm9yiLebpNhsyhcBobM0w0/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/zSmym/dJMb9aKG0kx/of34l5BaIh8W3DBwAQrcT0/img.png?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256&quot;&gt;&lt;a href=&quot;https://coding-by-head.tistory.com/category/Python/Deep%20Learning&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://coding-by-head.tistory.com/category/Python/Deep%20Learning&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/nz599/dJMb86nZt3O/S77O226K2DrKcr2MRLhTiK/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/DJWYn/dJMb8UHQ26L/Wm9yiLebpNhsyhcBobM0w0/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/zSmym/dJMb9aKG0kx/of34l5BaIh8W3DBwAQrcT0/img.png?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;'Python/Deep Learning' 카테고리의 글 목록&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 소프트웨어 개발을 위한 팁과 정보를 제공하는 '소프트웨어 공장'입니다. 함께 성장하는 개발 친구가 되어드릴게요!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;coding-by-head.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;CAN&quot; href=&quot;https://coding-by-head.tistory.com/category/CAN&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://coding-by-head.tistory.com/category/CAN&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776579321910&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;'CAN' 카테고리의 글 목록&quot; data-og-description=&quot;임베디드 소프트웨어 개발을 위한 팁과 정보를 제공하는 '소프트웨어 공장'입니다. 함께 성장하는 개발 친구가 되어드릴게요!&quot; data-og-host=&quot;coding-by-head.tistory.com&quot; data-og-source-url=&quot;https://coding-by-head.tistory.com/category/CAN&quot; data-og-url=&quot;https://coding-by-head.tistory.com/category/CAN&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ZifvU/dJMb8Rj3P2J/3YtjhZHVvOCknKBcElujXK/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/b4gFMW/dJMb8SXzFrz/h04RWiTIRILRSBUivJkkU1/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/F4rRZ/dJMb8PGx1kb/WTTVSyWIe1Nz2Tv5I774IK/img.png?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256&quot;&gt;&lt;a href=&quot;https://coding-by-head.tistory.com/category/CAN&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://coding-by-head.tistory.com/category/CAN&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ZifvU/dJMb8Rj3P2J/3YtjhZHVvOCknKBcElujXK/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/b4gFMW/dJMb8SXzFrz/h04RWiTIRILRSBUivJkkU1/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/F4rRZ/dJMb8PGx1kb/WTTVSyWIe1Nz2Tv5I774IK/img.png?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;'CAN' 카테고리의 글 목록&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 소프트웨어 개발을 위한 팁과 정보를 제공하는 '소프트웨어 공장'입니다. 함께 성장하는 개발 친구가 되어드릴게요!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;coding-by-head.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Edge AI &amp;amp; Cloud</category>
      <category>AI반도체</category>
      <category>DeepX</category>
      <category>NPU</category>
      <category>Tops</category>
      <category>딥러닝최적화</category>
      <category>스냅드래곤8</category>
      <category>애플m4</category>
      <category>온디바이스AI</category>
      <category>임베디드SW</category>
      <category>임베디드개발</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1119</guid>
      <comments>https://coding-by-head.tistory.com/entry/trend-npu-tops#entry1119comment</comments>
      <pubDate>Sun, 19 Apr 2026 15:18:46 +0900</pubDate>
    </item>
    <item>
      <title>'피지컬 AI' 시대의 개막: 왜 지금 임베디드 개발자의 몸값이 폭등하는가?</title>
      <link>https://coding-by-head.tistory.com/entry/trend-phygical-ai</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요! &lt;b&gt;소프트웨어 공장&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 &lt;b&gt;CES 2026&lt;/b&gt;의 핵심 키워드는 단연 &lt;b&gt;'피지컬 AI(Physical AI)'&lt;/b&gt;였습니다. 이제 AI는 화면 속에서 텍스트를 생성하는 수준을 넘어, 로봇의 관절을 움직이고 자율주행차의 조향을 직접 결정하는 '물리적 실체'가 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 이번 CES에서 화제가 된 &lt;b&gt;딥엑스(DeepX)&lt;/b&gt;와 &lt;b&gt;현대차 아틀라스&lt;/b&gt;의 사례를 통해, 왜 온디바이스 AI 시대에 &lt;b&gt;임베디드 개발자&lt;/b&gt;가 핵심 주인공이 될 수밖에 없는지 분석해 보겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_4zzgw4zzgw4zzgw4.png&quot; data-origin-width=&quot;1408&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q1bLo/dJMcai31Ueu/1QuXVmkyHaK8vyAqK0yJ0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q1bLo/dJMcai31Ueu/1QuXVmkyHaK8vyAqK0yJ0k/img.png&quot; data-alt=&quot;위 이미지는 Gemini ai가 표현한 on device ai 이미지 입니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q1bLo/dJMcai31Ueu/1QuXVmkyHaK8vyAqK0yJ0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq1bLo%2FdJMcai31Ueu%2F1QuXVmkyHaK8vyAqK0yJ0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;572&quot; height=&quot;312&quot; data-filename=&quot;Gemini_Generated_Image_4zzgw4zzgw4zzgw4.png&quot; data-origin-width=&quot;1408&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;위 이미지는 Gemini ai가 표현한 on device ai 이미지 입니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. CES 2026을 뒤흔든 '피지컬 AI'의 실체&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과거의 AI가 클라우드 서버에 의존했다면, 2026년의 AI는 기기 내부에서 스스로 사고합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;현대차 아틀라스(Atlas):&lt;/b&gt; 단순한 동작 반복이 아닌, 주변 환경을 실시간으로 인지하고 판단하여 움직이는 '지능형 로봇'의 정점을 보여주었습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;딥엑스(DeepX) DX-M1:&lt;/b&gt; CES 최고 혁신상을 거머쥔 ALPON X5 기반의 이 NPU 칩은 저전력으로도 고성능 AI 연산을 디바이스 내에서 처리해냅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 AI는 '뇌'만 있는 것이 아니라 '근육'과 '신경'을 갖추게 되었고, 그 신경망을 연결하는 것이 바로 우리 &lt;b&gt;임베디드 소프트웨어&lt;/b&gt;입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 왜 클라우드가 아닌 '온디바이스(On-Device)'인가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임베디드 개발자의 관점에서 온디바이스 AI가 필수적인 이유는 명확합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;① 초저지연성 (Real-time Latency)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자율주행차나 산업용 로봇이 장애물을 발견했을 때, 서버에 데이터를 보내고 응답을 기다릴 시간은 없습니다. 0.001초의 지연이 사고로 이어지는 환경에서 &lt;b&gt;에지(Edge) 단의 실시간 처리&lt;/b&gt;는 선택이 아닌 필수입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;② 에너지 효율과 발열 관리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;성능 좋은 GPU를 무한정 쓸 수 없는 임베디드 환경에서는 &lt;b&gt;Watt당 성능(Performance per Watt)&lt;/b&gt;이 중요합니다. 딥엑스의 DX-M1 같은 전용 NPU가 각광받는 이유도 극도의 전력 효율 때문입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;③ 보안과 프라이버시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기기 내부에서 데이터를 처리하면 민감한 정보가 외부로 유출될 리스크가 사라집니다. 보안(sepolicy)과 데이터 거버넌스가 중요한 B2B 시장에서 온디바이스 AI는 가장 강력한 무기입니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 임베디드 개발자에게 찾아온 '역대급 기회'&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지의 임베디드 개발이 하드웨어 제어와 펌웨어 최적화에 집중했다면, 이제는 &lt;b&gt;'AI 모델 최적화'&lt;/b&gt; 능력이 연봉을 결정합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;모델 경량화(Quantization):&lt;/b&gt; FP32 모델을 하드웨어에 맞게 INT8로 변환하면서도 정확도를 유지하는 기술.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;NPU 아키텍처 이해:&lt;/b&gt; 가속기(Accelerator)의 특성을 이해하고 데이터 파이프라인을 설계하는 능력.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;HW/SW 통합 설계:&lt;/b&gt; 시스템 서비스와 커널 수준에서 AI 연산 리소스를 배분하는 최적화 능력.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 마치며: 소프트웨어 공장의 제언&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;단순 코더는 AI가 대체하겠지만, AI를 기기에 이식하는 임베디드 엔지니어는 대체 불가능합니다.&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 CES 2026은 임베디드 기술이 AI의 종착역임을 증명했습니다. 저 역시 블로그를 통해 &lt;b&gt;NPU 최적화, ESP32 기반 AI 이식, Android Framework 보안&lt;/b&gt; 등 온디바이스 AI 시대를 대비한 기술들을 지속적으로 공유하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여러분이 생각하는 2026년 최고의 유망 기술은 무엇인가요?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;i&gt;함께 보면 좋은 글&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;Android Framework&quot; href=&quot;https://coding-by-head.tistory.com/category/Android/Framework&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://coding-by-head.tistory.com/category/Android/Framework&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776480629103&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;'Android/Framework' 카테고리의 글 목록&quot; data-og-description=&quot;임베디드 소프트웨어 개발을 위한 팁과 정보를 제공하는 '소프트웨어 공장'입니다. 함께 성장하는 개발 친구가 되어드릴게요!&quot; data-og-host=&quot;coding-by-head.tistory.com&quot; data-og-source-url=&quot;https://coding-by-head.tistory.com/category/Android/Framework&quot; data-og-url=&quot;https://coding-by-head.tistory.com/category/Android/Framework&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/MP2FD/dJMb8QMdNcF/vLQTKR4BBuxrktwhHQiCoK/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/bnrWfw/dJMb8WeBrfC/jWHkmFkPGFY1f1lpLL2b70/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/bFvHck/dJMb8XR7ugy/5EaAeKfwP76Fz5O2TrriD1/img.png?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256&quot;&gt;&lt;a href=&quot;https://coding-by-head.tistory.com/category/Android/Framework&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://coding-by-head.tistory.com/category/Android/Framework&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/MP2FD/dJMb8QMdNcF/vLQTKR4BBuxrktwhHQiCoK/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/bnrWfw/dJMb8WeBrfC/jWHkmFkPGFY1f1lpLL2b70/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/bFvHck/dJMb8XR7ugy/5EaAeKfwP76Fz5O2TrriD1/img.png?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;'Android/Framework' 카테고리의 글 목록&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 소프트웨어 개발을 위한 팁과 정보를 제공하는 '소프트웨어 공장'입니다. 함께 성장하는 개발 친구가 되어드릴게요!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;coding-by-head.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;소프트웨어 공장 ESP32&quot; href=&quot;https://coding-by-head.tistory.com/category/ESP32%20IDF&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://coding-by-head.tistory.com/category/ESP32%20IDF&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1776480709570&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;'ESP32 IDF' 카테고리의 글 목록&quot; data-og-description=&quot;임베디드 소프트웨어 개발을 위한 팁과 정보를 제공하는 '소프트웨어 공장'입니다. 함께 성장하는 개발 친구가 되어드릴게요!&quot; data-og-host=&quot;coding-by-head.tistory.com&quot; data-og-source-url=&quot;https://coding-by-head.tistory.com/category/ESP32%20IDF&quot; data-og-url=&quot;https://coding-by-head.tistory.com/category/ESP32%20IDF&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bPQRFK/dJMb8QenX9S/KnQyi4JBZynmTxyI78Mc7K/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/6Gjs3/dJMb8SpJKQV/UgIOdmYZbOQ9tMRkx0y2j0/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/vxLSS/dJMb8Xkg9Ua/IS2LxOMdJHmiqKECejgfl1/img.png?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256&quot;&gt;&lt;a href=&quot;https://coding-by-head.tistory.com/category/ESP32%20IDF&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://coding-by-head.tistory.com/category/ESP32%20IDF&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bPQRFK/dJMb8QenX9S/KnQyi4JBZynmTxyI78Mc7K/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/6Gjs3/dJMb8SpJKQV/UgIOdmYZbOQ9tMRkx0y2j0/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/vxLSS/dJMb8Xkg9Ua/IS2LxOMdJHmiqKECejgfl1/img.png?width=256&amp;amp;height=256&amp;amp;face=0_0_256_256');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;'ESP32 IDF' 카테고리의 글 목록&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 소프트웨어 개발을 위한 팁과 정보를 제공하는 '소프트웨어 공장'입니다. 함께 성장하는 개발 친구가 되어드릴게요!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;coding-by-head.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Edge AI &amp;amp; Cloud</category>
      <category>ces2026</category>
      <category>DeepX</category>
      <category>IT트렌드</category>
      <category>NPU</category>
      <category>딥엑스</category>
      <category>에지컴퓨팅</category>
      <category>온디바이스AI</category>
      <category>임베디드개발자</category>
      <category>피지컬ai</category>
      <category>현대차아틀라스</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1118</guid>
      <comments>https://coding-by-head.tistory.com/entry/trend-phygical-ai#entry1118comment</comments>
      <pubDate>Sat, 18 Apr 2026 12:02:00 +0900</pubDate>
    </item>
    <item>
      <title>임베디드 리눅스 OTA 업데이트 전략: RK3399 네트워크 부팅과 안정적인 업데이트 구현 (TFTP, NFS, 보안부팅)</title>
      <link>https://coding-by-head.tistory.com/entry/u-boot-net-ota</link>
      <description>&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 리눅스 시스템을 개발할 때 네트워크를 통한 펌웨어 업데이트(OTA)는 제품의 유지보수와 안정성을 결정짓는 필수 요소입니다. 특히 Rockchip RK3399와 같은 고성능 SoC 기반 시스템에서 U-Boot는 단순히 부팅을 담당하는 부트로더를 넘어, 펌웨어 무결성을 검증하고 시스템의 생명주기를 관리하는 핵심 도구로 활용됩니다. 이번 글에서는 RK3399 환경에서 네트워크 부팅을 설정하고, 실무에서 활용 가능한 안정적인 OTA 업데이트 구현 전략을 상세히 정리하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_wih52kwih52kwih5.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6Zlqj/dJMcahK3LJz/FrM3KPZ1SESRg3XHUL9PSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6Zlqj/dJMcahK3LJz/FrM3KPZ1SESRg3XHUL9PSK/img.png&quot; data-alt=&quot;Generated by Gemini AI.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6Zlqj/dJMcahK3LJz/FrM3KPZ1SESRg3XHUL9PSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6Zlqj%2FdJMcahK3LJz%2FFrM3KPZ1SESRg3XHUL9PSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;384&quot; height=&quot;384&quot; data-filename=&quot;Gemini_Generated_Image_wih52kwih52kwih5.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Generated by Gemini AI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;1&quot; data-ke-size=&quot;size23&quot;&gt;핵심 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;U-Boot는 기가비트 이더넷 컨트롤러를 지원하여 TFTP 부팅과 NFS 마운트 등 개발 및 업데이트를 위한 강력한 네트워크 기능을 제공합니다.&lt;/li&gt;
&lt;li&gt;개발 환경에서는 TFTP와 NFS를 조합하여 커널 이미지를 매번 굽지 않고 즉시 테스트하는 환경을 구축할 수 있습니다.&lt;/li&gt;
&lt;li&gt;실제 운영 환경에서의 OTA는 부팅 파티션 이중화(A/B 슬롯)와 FIT 이미지 서명 검증을 통해 보안과 안정성을 확보해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;1. RK3399 네트워크 환경 설정&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;RK3399의 이더넷 기능을 사용하려면 먼저 디바이스 트리(DTS)와 U-Boot 설정을 확인해야 합니다. 하드웨어적으로 준비되었다면 다음 환경 변수를 통해 네트워크 환경을 조성할 수 있습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;6&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;변수&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,0,0&quot;&gt;ipaddr&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,1,0&quot;&gt;보드의 고정 IP 주소&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,2,0&quot;&gt;192.168.0.10&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,0,0&quot;&gt;serverip&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,1,0&quot;&gt;TFTP/NFS 서버(개발 PC) IP&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,2,0&quot;&gt;192.168.0.2&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,0,0&quot;&gt;gatewayip&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,1,0&quot;&gt;네트워크 게이트웨이&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,2,0&quot;&gt;192.168.0.1&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;설정 후에는 mii info 명령어를 통해 PHY 연결 상태를 확인하고, ping 명령어로 서버와 통신이 가능한지 먼저 점검하십시오.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size23&quot;&gt;2. TFTP와 NFS 기반 부팅 가이드&lt;/h3&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;매번 SD카드나 eMMC에 펌웨어를 쓰고 다시 부팅하는 방식은 개발 효율을 크게 떨어뜨립니다. 네트워크 부팅을 활용해 개발 속도를 높이십시오.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,0,0&quot;&gt;TFTP 커널 로드&lt;/b&gt;: tftpboot 명령어로 서버에서 커널(Image)과 디바이스 트리(dtb)를 RAM에 다운로드한 후 booti로 실행합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,1,0&quot;&gt;NFS 루트 파일시스템&lt;/b&gt;: bootargs에 root=/dev/nfs nfsroot=... 설정을 추가하면, 개발 PC의 디렉토리를 루트 파일시스템으로 직접 사용하여 별도의 배포 과정 없이 실시간 수정 및 테스트가 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size23&quot;&gt;3. 실전 OTA 업데이트 스크립트&lt;/h3&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;운영 환경에서는 네트워크에서 다운로드한 이미지를 eMMC의 특정 섹터에 기록하는 과정을 자동화해야 합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwijyMu4-8yUAxUAAAAAHQAAAAAQvgM&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;Bash&lt;/span&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;bash&quot;&gt;&lt;code&gt;# 이미지 다운로드 및 eMMC 쓰기 예제
setenv ota_image Image.new
if tftpboot ${loadaddr} ${ota_image}; then
    mmc dev 0
    # 섹터 주소(0x8000)와 크기(0x4000)는 파티션 테이블에 맞춰 조정
    mmc write ${loadaddr} 0x8000 0x4000
    echo &quot;OTA Update Complete!&quot;
else
    echo &quot;OTA Download Failed!&quot;
fi
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size23&quot;&gt;4. 보안 부팅(Secure Boot) 및 무결성 검증&lt;/h3&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;네트워크를 통한 업데이트는 항상 위변조 위험이 있습니다. 이를 방지하기 위해 U-Boot의 FIT(Flattened Image Tree) 구조와 RSA 서명 검증을 활용해야 합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;16&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;기능&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,0,0&quot;&gt;FIT 이미지&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,1,1,0&quot;&gt;커널, DTB, Ramdisk를 하나로 통합 관리&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,2,0,0&quot;&gt;SHA256 해시&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,2,1,0&quot;&gt;데이터의 무결성 검증&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,3,0,0&quot;&gt;RSA 서명&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,3,1,0&quot;&gt;공개키/개인키 기반의 위변조 방지&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;5. 개발을 위한 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;18&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,0,0&quot;&gt;A/B 파티션 설계&lt;/b&gt;: 업데이트 중 전원이 차단되어도 시스템이 부팅 가능하도록 슬롯 A/B 방식을 설계하십시오. 새로운 업데이트는 슬롯 B에 쓰고 성공 시 부팅 우선순위를 변경하는 방식이 가장 안전합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,1,0&quot;&gt;부트 카운터 활용&lt;/b&gt;: CONFIG_BOOTCOUNT_LIMIT를 활성화하면 특정 횟수 이상 부팅 실패 시 자동으로 이전 버전으로 롤백하여 시스템이 영구적으로 부팅 불능 상태가 되는 것을 막을 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size23&quot;&gt;6. 흔히 하는 실수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;20&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,0,0&quot;&gt;섹터 주소 계산 오류&lt;/b&gt;: mmc write 수행 시 섹터 주소나 블록 크기를 파티션 레이아웃과 다르게 지정하면 기존 데이터를 덮어써 시스템 전체가 파괴될 수 있습니다. 반드시 파티션 테이블을 재확인하세요.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,1,0&quot;&gt;네트워크 환경 무시&lt;/b&gt;: 고속 부팅을 시도하면서 serverip와 ipaddr이 같은 서브넷 내에 있는지 확인하지 않아 타임아웃 오류로 고생하는 경우가 많습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;오늘날의 RK3399 시스템에서 U-Boot는 단순히 운영체제를 실행하는 도구가 아니라, 네트워크를 통한 펌웨어 업데이트, 보안 검증, 시스템 복구 기능을 아우르는 통합 관리 도구입니다. 안정적인 OTA 시스템을 설계하려면 오늘 정리한 네트워크 구성과 보안 검증 기술을 바탕으로 이중화된 부팅 전략을 세우는 것이 중요합니다. 견고한 업데이트 시스템을 구축하여 제품의 신뢰도를 한 단계 높이시기 바랍니다.&lt;/p&gt;</description>
      <category>Embedded System/Bootloader &amp;amp; System Startup</category>
      <category>u-boot Network OTA</category>
      <category>u-boot OTA</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1048</guid>
      <comments>https://coding-by-head.tistory.com/entry/u-boot-net-ota#entry1048comment</comments>
      <pubDate>Thu, 11 Dec 2025 20:42:53 +0900</pubDate>
    </item>
    <item>
      <title>임베디드 개발자를 위한 RK3399 U-Boot 부팅 디버깅 및 커스터마이징 가이드</title>
      <link>https://coding-by-head.tistory.com/entry/u-boot-debug</link>
      <description>&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 시스템 개발을 하다 보면 가장 당혹스러운 순간은 전원을 켰는데 UART에 아무런 응답이 없을 때입니다. 특히 Rockchip RK3399와 같은 고성능 SoC는 부팅 단계가 복잡하여 초기 하드웨어 검증과 소프트웨어 디버깅이 쉽지 않습니다. 이번 글에서는 RK3399 보드를 사례로 들어, U-Boot 부팅 과정에서 문제를 추적하는 디버깅 기법과 사용자 경험을 개선하는 커스터마이징 방법을 정리해 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_cvctodcvctodcvct.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rqu0L/dJMcaffq4Nj/o1F51u565aXjoXm6vq81Rk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rqu0L/dJMcaffq4Nj/o1F51u565aXjoXm6vq81Rk/img.png&quot; data-alt=&quot;Generated by Gemini AI.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rqu0L/dJMcaffq4Nj/o1F51u565aXjoXm6vq81Rk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frqu0L%2FdJMcaffq4Nj%2Fo1F51u565aXjoXm6vq81Rk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;381&quot; height=&quot;381&quot; data-filename=&quot;Gemini_Generated_Image_cvctodcvctodcvct.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Generated by Gemini AI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;1&quot; data-ke-size=&quot;size23&quot;&gt;핵심 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;UART 로그는 부팅 단계별 성공 여부를 판단하는 유일한 지표이므로, 초기 부팅 먹통 현상을 해결하는 것이 최우선입니다.&lt;/li&gt;
&lt;li&gt;CONFIG_DEBUG_UART와 같은 커널 설정과 printf 디버깅을 적절히 활용하면 부팅 단계별 흐름을 명확히 파악할 수 있습니다.&lt;/li&gt;
&lt;li&gt;부트 로고 커스터마이징과 bootdelay 최적화를 통해 제품의 완성도를 높이고 사용자 경험을 개선할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;1. UART 로그: 디버깅의 시작과 끝&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot는 ROM &amp;rarr; SRAM Loader &amp;rarr; TPL/SPL &amp;rarr; U-Boot Main으로 이어지는 긴 여정을 거칩니다. 이 과정에서 각 단계가 성공적으로 넘어가는지 확인하는 방법은 오직 UART 로그뿐입니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;6&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;단계&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;확인 사항&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0,0&quot;&gt;ROM&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,1,0&quot;&gt;SoC 내부 코드&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,2,0&quot;&gt;부팅 모드(eMMC/SD) 설정 확인&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,2,0,0&quot;&gt;TPL/SPL&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,1,0&quot;&gt;SRAM 기반 로더&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,2,0&quot;&gt;DRAM 트레이닝 및 UART 초기화 성공 여부&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,3,0,0&quot;&gt;U-Boot Main&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,1,0&quot;&gt;DRAM 기반 로더&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,2,0&quot;&gt;주변 장치 로드 및 커널 실행 단계&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;2. 초기 부팅 이슈 해결: CONFIG_DEBUG_UART&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;부팅 초기에 로그가 전혀 나오지 않는다면 표준 드라이버 로드 전 단계에서 문제가 발생했을 가능성이 높습니다. 이때 CONFIG_DEBUG_UART를 활성화하면 시스템 초기 단계부터 강제로 메시지를 출력할 수 있습니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9&quot;&gt;설정 방법 (defconfig)&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwijyMu4-8yUAxUAAAAAHQAAAAAQnAM&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;Bash&lt;/span&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_BASE=0xFF1A0000  # 회로도에 맞는 UART 주소 입력
CONFIG_DEBUG_UART_CLOCK=24000000
CONFIG_DEBUG_UART_SHIFT=2
CONFIG_DEBUG_UART_BOARD_INIT=y
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size23&quot;&gt;3. 실시간 로그 제어와 코드 디버깅&lt;/h3&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;시스템 동작 중 로그의 양을 조절하거나, 특정 코드 영역을 확인해야 할 때 다음 기법들을 활용하십시오.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;13&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,0,0&quot;&gt;로그 레벨 조절&lt;/b&gt;: CONFIG_CMD_LOG=y를 활성화한 후 U-Boot 콘솔에서 log level 7을 입력하면 가장 상세한 디버깅 메시지를 볼 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,1,0&quot;&gt;printf 기법&lt;/b&gt;: printf(&quot;[DEBUG] %s: Start\n&quot;, &lt;b data-index-in-node=&quot;41&quot; data-path-to-node=&quot;13,1,0&quot;&gt;func&lt;/b&gt;);를 코드 중간에 삽입하여 초기화 루틴의 동작 여부를 추적하십시오. &lt;b data-index-in-node=&quot;84&quot; data-path-to-node=&quot;13,1,0&quot;&gt;func&lt;/b&gt; 매크로를 사용하면 함수 이름을 일일이 적지 않아도 되어 작업 효율이 높아집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size23&quot;&gt;4. 로고 및 부팅 속도 커스터마이징&lt;/h3&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;제품의 완성도는 사용자가 처음 마주하는 화면에서 결정됩니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;16&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;설정 항목&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;기능&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,1,0,0&quot;&gt;CONFIG_VIDEO_LOGO&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,1,1,0&quot;&gt;부팅 로고 활성화&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,1,2,0&quot;&gt;시스템 부팅 시 로고 출력&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,2,0,0&quot;&gt;CONFIG_SPLASH_SCREEN&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,2,1,0&quot;&gt;스플래시 화면&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,2,2,0&quot;&gt;이미지 파일을 로드하여 화면 표시&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,3,0,0&quot;&gt;bootdelay&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,3,1,0&quot;&gt;부팅 지연 시간&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;16,3,2,0&quot;&gt;사용자 대기 시간 조절 (양산 시 0으로 설정)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;5. 개발을 위한 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;18&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,0,0&quot;&gt;키 입력 인터럽트 활용&lt;/b&gt;: bootdelay를 0으로 설정하면 콘솔 진입이 어렵습니다. 이때 CONFIG_AUTOBOOT_KEYED를 활성화하십시오. 특정 키를 입력하는 동안에만 부팅을 멈추고 콘솔로 진입하게 설정할 수 있어 양산과 개발의 균형을 잡을 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,1,0&quot;&gt;핀맵 재확인&lt;/b&gt;: 모든 설정이 완벽한데 로그가 안 나온다면 UART 핀이 하드웨어적으로 올바르게 연결되었는지, 보드 레이아웃의 Debug UART 핀 번호와 코드가 일치하는지 다시 확인하십시오.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size23&quot;&gt;6. 흔히 하는 실수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;20&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,0,0&quot;&gt;UART 주소 오기입&lt;/b&gt;: CONFIG_DEBUG_UART_BASE에 잘못된 주소를 입력하면 CPU가 아무런 반응을 하지 않거나 시스템 멈춤 현상이 발생합니다. 반드시 보드의 회로도를 보고 물리 주소를 확인하세요.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,1,0&quot;&gt;로그 레벨 오해&lt;/b&gt;: 모든 로그가 다 출력될 것이라고 생각하지 마십시오. log level 설정이 낮으면 디버깅 메시지가 필터링되어 보이지 않을 수 있습니다. 문제 발생 시 항상 레벨을 최고치로 설정하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;RK3399와 같이 복잡한 시스템에서 디버깅은 시스템이 내뱉는 작은 신호들을 얼마나 잘 읽고 제어하느냐의 싸움입니다. 오늘 정리한 UART 로그 활용법과 CONFIG_DEBUG_UART 설정을 잘 숙지하신다면, 어떤 형태의 부팅 먹통 현상도 논리적으로 해결하실 수 있을 것입니다. 단계적인 디버깅으로 안정적인 임베디드 시스템을 구축하시기 바랍니다.&lt;/p&gt;</description>
      <category>Embedded System/Bootloader &amp;amp; System Startup</category>
      <category>u-boot debug</category>
      <category>u-boot UART</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1045</guid>
      <comments>https://coding-by-head.tistory.com/entry/u-boot-debug#entry1045comment</comments>
      <pubDate>Wed, 10 Dec 2025 20:12:51 +0900</pubDate>
    </item>
    <item>
      <title>임베디드 개발자를 위한 U-Boot 커널 로딩 및 부팅 시퀀스 완벽 가이드</title>
      <link>https://coding-by-head.tistory.com/entry/u-boot-load-image</link>
      <description>&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 리눅스 시스템 개발에서 U-Boot는 하드웨어와 운영체제 사이의 가교 역할을 하는 핵심 소프트웨어입니다. 단순한 부팅 도구를 넘어 하드웨어를 검증하고 시스템의 첫 단추를 끼우는 부트로더의 역할을 정확히 이해하는 것은 임베디드 엔지니어에게 필수적인 역량입니다. 이번 글에서는 Rockchip RK3399 플랫폼을 예시로, 커널 이미지를 로드하는 다양한 방식과 시스템 부팅의 핵심인 커널 파라미터 전달 과정, 그리고 실제 부팅 로그를 분석하는 방법을 실무 관점에서 정리해 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_xbygy2xbygy2xbyg.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bT0LSo/dJMcahdcYvz/KNUITqPZhJEFesvJlnSuTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bT0LSo/dJMcahdcYvz/KNUITqPZhJEFesvJlnSuTK/img.png&quot; data-alt=&quot;Generated by Gemini AI.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bT0LSo/dJMcahdcYvz/KNUITqPZhJEFesvJlnSuTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbT0LSo%2FdJMcahdcYvz%2FKNUITqPZhJEFesvJlnSuTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;396&quot; height=&quot;396&quot; data-filename=&quot;Gemini_Generated_Image_xbygy2xbygy2xbyg.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Generated by Gemini AI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;1&quot; data-ke-size=&quot;size23&quot;&gt;핵심 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;U-Boot는 Image, uImage, FIT 등 다양한 커널 이미지 형식을 지원하며, 각 플랫폼에 맞는 부팅 명령어를 사용해야 합니다.&lt;/li&gt;
&lt;li&gt;시스템 부팅의 성공 여부는 커널 커맨드라인(bootargs)과 하드웨어 명세서인 Device Tree(DTB)를 얼마나 정확히 전달하느냐에 달려 있습니다.&lt;/li&gt;
&lt;li&gt;부팅 로그의 흐름을 파악하면 커널 패닉이나 하드웨어 인식 실패와 같은 부팅 장애를 빠르게 해결할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;1. 커널 이미지 형식별 로딩 방식&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;아키텍처와 요구사항에 따라 적절한 이미지 형식을 선택해야 합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;6&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;이미지 형식&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;실행 명령어&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0,0&quot;&gt;Image (zImage)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,1,0&quot;&gt;압축된 커널 바이너리, 범용적인 사용&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,2,0&quot;&gt;booti&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,2,0,0&quot;&gt;uImage&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,1,0&quot;&gt;U-Boot 전용 헤더 포함, 이미지 정보 내장&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,2,0&quot;&gt;bootm&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,3,0,0&quot;&gt;FIT Image&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,1,0&quot;&gt;커널, DTB, Ramdisk 통합, 보안 부팅에 필수&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,2,0&quot;&gt;bootm&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;2. 커널의 이정표: bootargs와 DTB 전달&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot는 커널을 실행하기 전, 하드웨어 정보와 운영체제의 구동 환경을 반드시 전달해야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;9&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,0,0&quot;&gt;bootargs (Kernel Command Line)&lt;/b&gt;: /proc/cmdline으로 전달되어 루트 파일 시스템의 위치와 콘솔 출력을 지정합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;9,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;eMMC 부팅 시: setenv bootargs &quot;console=ttyFIQ0,1500000 root=/dev/mmcblk1p7 rw rootwait&quot;&lt;/li&gt;
&lt;li&gt;NFS 부팅 시: setenv bootargs &quot;root=/dev/nfs nfsroot=192.168.0.10:/nfsroot ip=dhcp&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,0&quot;&gt;Device Tree (DTB)&lt;/b&gt;: 커널과는 별도의 메모리 주소에 로드해야 하며, 부팅 명령 시 booti 인자로 메모리 주소를 명시해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;3. 매체별 부팅 시나리오 (Cheat Sheet)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;실무에서 자주 사용하는 저장 매체별 부팅 명령어 요약입니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;12&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;매체 (Media)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;주요 명령어 요약&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,1,0,0&quot;&gt;SD Card&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,1,1,0&quot;&gt;load mmc 0:1 ${loadaddr} Image&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,2,0,0&quot;&gt;eMMC&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,2,1,0&quot;&gt;load mmc 1:1 ${loadaddr} Image&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,3,0,0&quot;&gt;TFTP (Network)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,3,1,0&quot;&gt;tftp ${loadaddr} Image; tftp ${fdt_addr} rk3399.dtb&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;네트워크 부팅을 위해서는 서버 IP와 타겟 IP를 설정한 뒤 tftp 명령으로 커널과 DTB를 메모리에 올리고 booti로 실행합니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size23&quot;&gt;4. 부팅 로그 분석&lt;/h3&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;로그를 추적하면 부팅 과정에서 어디에서 멈추는지 알 수 있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,0,0&quot;&gt;Starting Kernel&lt;/b&gt;: U-Boot가 시스템 제어권을 커널로 넘깁니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,0&quot;&gt;OF: fdt&lt;/b&gt;: 커널이 전달받은 DTB를 파싱하여 하드웨어 정보를 읽어옵니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,2,0&quot;&gt;Mounting RootFS&lt;/b&gt;: bootargs에 지정된 위치에서 루트 파일 시스템을 마운트합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,3,0&quot;&gt;Init Process&lt;/b&gt;: 유저 공간의 첫 프로세스인 /init이 실행됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;5. 개발을 위한 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;18&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,0,0&quot;&gt;NFS 부팅 활용&lt;/b&gt;: 개발 초기 단계에서는 eMMC에 매번 이미지를 굽지 말고 NFS 부팅을 사용하세요. 커널 바이너리 수정 후 즉시 테스트가 가능하여 생산성이 비약적으로 높아집니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,1,0&quot;&gt;메모리 맵 확인&lt;/b&gt;: 이미지 로딩 주소(loadaddr)와 DTB 주소가 겹치면 부팅 도중 데이터가 오염됩니다. SoC 데이터시트를 참고하여 겹치지 않는 적절한 주소를 선점하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size23&quot;&gt;6. 흔히 하는 실수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;20&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,0,0&quot;&gt;주소값 불일치&lt;/b&gt;: booti 명령에 전달한 주소가 실제 load한 주소와 다르면 Kernel Panic이나 시스템 멈춤 현상이 발생합니다. printenv로 로드 주소를 꼭 확인하세요.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,1,0&quot;&gt;bootargs 오타&lt;/b&gt;: root=/dev/mmcblk... 경로가 실제 파티션 구성과 다르면 커널은 마운트할 RootFS를 찾지 못하고 부팅이 중단됩니다. rootwait 옵션을 넣어 파티션 준비 시간을 확보하는 것이 좋습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot의 본질적인 임무는 커널을 안전하게 메모리에 올리고 시스템의 제어권을 넘겨주는 것입니다. 이 과정을 완벽하게 이해하고 있다면, 어떤 환경에서도 부팅 이슈를 논리적으로 해결할 수 있습니다. 오늘 정리한 이미지 로딩 방식과 파라미터 전달 체계를 숙달하여 더욱 안정적인 시스템 개발을 이어가시길 바랍니다.&lt;/p&gt;</description>
      <category>Embedded System/Bootloader &amp;amp; System Startup</category>
      <category>u-boot Load kernel</category>
      <category>u-boot Load rootfs</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1042</guid>
      <comments>https://coding-by-head.tistory.com/entry/u-boot-load-image#entry1042comment</comments>
      <pubDate>Tue, 9 Dec 2025 20:20:11 +0900</pubDate>
    </item>
    <item>
      <title>임베디드 개발자를 위한 U-Boot 환경 변수 완벽 가이드: 부팅 제어와 자동화</title>
      <link>https://coding-by-head.tistory.com/entry/u-boot-env</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;임베디드 리눅스 시스템 개발에서 U-Boot는 하드웨어와 운영체제를 연결하는 핵심 가교입니다. 그중에서도 환경 변수(Environment Variable)는 소스 코드를 재컴파일하지 않고도 부팅 경로, 커널 파라미터, 업데이트 로직 등을 유연하게 제어할 수 있게 해주는 필수 도구입니다. 이번 글에서는 Rockchip RK3399 플랫폼을 예시로, U-Boot 환경 변수의 구조와 실무에서 즉시 활용 가능한 스크립트 작성법을 정리해 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_s7au2bs7au2bs7au.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZ8noj/dJMcafNgzP9/TRaDHCZz2HxlKKUrSuTK5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZ8noj/dJMcafNgzP9/TRaDHCZz2HxlKKUrSuTK5k/img.png&quot; data-alt=&quot;Generated by Gemini AI.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZ8noj/dJMcafNgzP9/TRaDHCZz2HxlKKUrSuTK5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZ8noj%2FdJMcafNgzP9%2FTRaDHCZz2HxlKKUrSuTK5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;389&quot; height=&quot;389&quot; data-filename=&quot;Gemini_Generated_Image_s7au2bs7au2bs7au.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Generated by Gemini AI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;1&quot; data-ke-size=&quot;size23&quot;&gt;핵심 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;환경 변수는 U-Boot의 동작을 결정하는 핵심 설정값으로, 부팅 프로세스와 시스템 파라미터를 소스 수정 없이 변경합니다.&lt;/li&gt;
&lt;li&gt;printenv, setenv, saveenv 명령어의 조합만으로 대부분의 부팅 시나리오를 구성할 수 있습니다.&lt;/li&gt;
&lt;li&gt;환경 변수를 활용하면 단순 부팅을 넘어 펌웨어 업데이트 등 복잡한 자동화 스크립트까지 구현 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;1. U-Boot 핵심 환경 변수&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot 환경 변수는 시스템 부팅 과정에서 결정적인 역할을 수행합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;6&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;변수명&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0,0&quot;&gt;bootcmd&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,1,0&quot;&gt;자동 부팅 카운트다운 후 실행되는 명령어 묶음&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,2,0,0&quot;&gt;bootargs&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,1,0&quot;&gt;리눅스 커널에 전달되는 커맨드 라인 파라미터&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,3,0,0&quot;&gt;bootdelay&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,1,0&quot;&gt;자동 부팅 전 사용자의 입력을 대기하는 시간(초)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,4,0,0&quot;&gt;주소 변수&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,4,1,0&quot;&gt;커널(kernel_addr_r), DTB(fdt_addr_r) 등이 로드될 메모리 주소&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;2. 저장 위치와 생명 주기&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;환경 변수는 실행 시점과 저장 매체에 따라 두 가지 상태로 구분됩니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;9&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;위치&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,0,0&quot;&gt;Runtime&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,1,1,0&quot;&gt;RAM&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,1,2,0&quot;&gt;부팅 직후 복사되며, setenv 수정 시 즉시 적용되지만 재부팅 시 초기화&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,2,0,0&quot;&gt;Persistent&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,2,1,0&quot;&gt;eMMC/Flash&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,2,2,0&quot;&gt;saveenv 명령 시 기록되며, 영구적으로 설정값 유지&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;3. 필수 명령어 가이드&lt;/h3&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;실무 콘솔에서 환경 변수를 다룰 때 가장 많이 사용하는 명령어들입니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;12&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;명령어&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,1,0,0&quot;&gt;printenv&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,1,1,0&quot;&gt;현재 설정된 모든 환경 변수 출력&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,2,0,0&quot;&gt;setenv [var] [val]&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,2,1,0&quot;&gt;변수 생성 및 수정 (값을 비우면 변수 삭제)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,3,0,0&quot;&gt;saveenv&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,3,1,0&quot;&gt;RAM의 변경 사항을 저장 매체에 영구 기록&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,4,0,0&quot;&gt;env default -a&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,4,1,0&quot;&gt;모든 변수를 공장 초기값으로 복구&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;4. 실전! 부팅 스크립트 설정&lt;/h3&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;RK3399 보드에서 커널 부팅을 위한 필수 설정을 적용하는 예시입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;15&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15,0,0&quot;&gt;커널 부팅 인자 설정&lt;/b&gt;&lt;/li&gt;
&lt;li data-ved=&quot;0CAAQhtANahgKEwijyMu4-8yUAxUAAAAAHQAAAAAQ2AI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;Bash&lt;/span&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;excel&quot;&gt;&lt;code&gt;=&amp;gt; setenv bootargs &quot;console=ttyS2,1500000 root=/dev/mmcblk0p5 rw rootwait&quot;

&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwijyMu4-8yUAxUAAAAAHQAAAAAQ2QI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;* **자동 부팅 구성 (bootcmd)**
  ```bash
  =&amp;gt; setenv bootcmd 'mmc dev 0; fatload mmc 0:1 0x02000000 Image; fatload mmc 0:1 0x01f00000 rk3399.dtb; booti 0x02000000 - 0x01f00000'
  =&amp;gt; saveenv
  
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;5. 고급 활용: 펌웨어 업데이트 자동화&lt;/h3&gt;
&lt;p data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot 환경 변수를 활용하면 if-then-else 조건문을 포함한 스크립트 작성이 가능합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwijyMu4-8yUAxUAAAAAHQAAAAAQ2gI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;Bash&lt;/span&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;excel&quot;&gt;&lt;code&gt;# 업데이트 모드 진입 설정
=&amp;gt; setenv upgrade_flag 1

# 조건부 부팅 스크립트
=&amp;gt; setenv bootcmd 'if test &quot;${upgrade_flag}&quot; = &quot;1&quot;; then \
    echo &quot;--- Firmware Update Mode ---&quot;; \
    usb start; \
    fatload usb 0:1 0x20000000 update.img; \
    run update_script; \
    else \
    run normal_boot; \
    fi'
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size23&quot;&gt;6. 개발을 위한 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;21&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,0,0&quot;&gt;변수 백업&lt;/b&gt;: 중요한 설정을 변경하기 전, printenv 결과를 별도로 복사해두거나 saveenv 이전에 설정을 검증하는 습관을 들이세요.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,1,0&quot;&gt;스크립트 모듈화&lt;/b&gt;: 긴 명령어를 하나의 변수에 넣지 말고, run normal_boot와 같이 여러 개의 작은 변수로 나누어 관리하면 가독성과 수정 편의성이 크게 향상됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size23&quot;&gt;7. 흔히 하는 실수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;23&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;23,0,0&quot;&gt;saveenv 누락&lt;/b&gt;: 열심히 setenv로 환경을 구성하고 나서 saveenv를 하지 않아 재부팅 후 초기화되는 사례가 매우 많습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;23,1,0&quot;&gt;메모리 영역 충돌&lt;/b&gt;: 커널 이미지와 DTB가 로드되는 메모리 주소가 겹치면 부팅 도중 시스템이 멈춥니다. 주소 설계 시 충분한 공간을 확보하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;25&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-path-to-node=&quot;26&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot 환경 변수는 임베디드 시스템의 단순 설정값을 넘어, 개발자가 시스템의 흐름을 자유자재로 제어할 수 있게 해주는 자동화 엔진입니다. 오늘 정리한 명령어와 스크립트 작성법을 숙달한다면, 어떤 하드웨어 환경에서도 유연하게 대응할 수 있는 임베디드 엔지니어가 될 것입니다.&lt;/p&gt;</description>
      <category>Embedded System/Bootloader &amp;amp; System Startup</category>
      <category>u-boot env</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1039</guid>
      <comments>https://coding-by-head.tistory.com/entry/u-boot-env#entry1039comment</comments>
      <pubDate>Mon, 8 Dec 2025 19:33:10 +0900</pubDate>
    </item>
    <item>
      <title>임베디드 개발자를 위한 U-Boot 커스텀 명령어 추가 및 활용 가이드  U_BOOT_CMD 완벽 분석</title>
      <link>https://coding-by-head.tistory.com/entry/u-boot-command</link>
      <description>&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 시스템 개발 현장에서 U-Boot는 단순히 운영체제를 부팅하는 통로가 아니라, 하드웨어 초기화와 시스템 검증을 수행하는 핵심적인 개발 플랫폼입니다. 특히 시스템을 브링업(Bring-up)하는 과정에서 개발자가 직접 정의한 사용자 정의 명령어를 추가할 수 있다면, 하드웨어 테스트나 디버깅 자동화를 훨씬 효율적으로 수행할 수 있습니다. 이번 글에서는 Rockchip RK3399 보드를 사례로 들어, U-Boot에 새로운 명령어를 추가하는 메커니즘과 실제 코드 구현 방법을 단계별로 정리해 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_tt5vshtt5vshtt5v.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dpL2ru/dJMcabcXAnJ/VIhzGZrep2wU1kJxybCOEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dpL2ru/dJMcabcXAnJ/VIhzGZrep2wU1kJxybCOEK/img.png&quot; data-alt=&quot;Generated by Gemini AI.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dpL2ru/dJMcabcXAnJ/VIhzGZrep2wU1kJxybCOEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdpL2ru%2FdJMcabcXAnJ%2FVIhzGZrep2wU1kJxybCOEK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;390&quot; height=&quot;390&quot; data-filename=&quot;Gemini_Generated_Image_tt5vshtt5vshtt5v.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Generated by Gemini AI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;1&quot; data-ke-size=&quot;size23&quot;&gt;핵심 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;U-Boot의 모든 명령어는 cmd/ 디렉토리 내에 모듈화되어 관리되며, U_BOOT_CMD 매크로를 통해 등록됩니다.&lt;/li&gt;
&lt;li&gt;명령어 실행 함수(do_xxx)는 표준 C의 main 함수와 유사한 구조를 가지며, 인자 처리와 반환값 설정으로 비즈니스 로직을 구현합니다.&lt;/li&gt;
&lt;li&gt;커스텀 명령어를 추가한 후에는 반드시 Kconfig와 Makefile을 수정하여 빌드 시스템에 해당 파일을 포함시켜야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;1. U-Boot 명령어 시스템 구조&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot는 명령어를 체계적으로 관리하기 위해 고유의 구조를 사용합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;6&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;디렉토리/섹션&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;주요 역할&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,0,0&quot;&gt;cmd/&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,1,0&quot;&gt;명령어 관련 소스 코드 위치 (메모리, GPIO, 네트워크 등)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,0,0&quot;&gt;U_BOOT_CMD 매크로&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,1,0&quot;&gt;새로운 명령어를 U-Boot 시스템에 등록하는 표준 방법&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,0,0&quot;&gt;.u_boot_list_2_cmd_2&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,1,0&quot;&gt;빌드 시 생성되는 명령어 목록이 담긴 특수 섹션&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;2. 명령어 등록 도구: U_BOOT_CMD 매크로&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;명령어 정의 시 사용하는 매크로의 인자들은 다음과 같습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;9&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;인자&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,1,0,0&quot;&gt;name&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,1,1,0&quot;&gt;콘솔에서 호출할 실제 명령어 이름 (예: hello)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,2,0,0&quot;&gt;maxargs&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,2,1,0&quot;&gt;명령어와 인자를 포함한 최대 개수&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,3,0,0&quot;&gt;repeatable&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,3,1,0&quot;&gt;엔터 입력 시 명령 재실행 여부 (0: 불가, 1: 허용)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,4,0,0&quot;&gt;cmd_func&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,4,1,0&quot;&gt;명령 실행 시 호출할 C 언어 함수 (do_xxx 형태)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,5,0,0&quot;&gt;usage&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,5,1,0&quot;&gt;help 명령 시 출력될 짧은 한 줄 요약&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,6,0,0&quot;&gt;help&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,6,1,0&quot;&gt;상세 도움말 (여러 줄 작성 가능)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;3. [실습] RK3399에 커스텀 명령 추가하기&lt;/h3&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;간단한 출력 명령과 실제 하드웨어를 제어하는 GPIO 명령을 구현하는 예제입니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12&quot;&gt;기초: &quot;hello&quot; 출력 명령 (cmd/cmd_hello.c)&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwijyMu4-8yUAxUAAAAAHQAAAAAQqgI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;C&lt;/span&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &amp;lt;common.h&amp;gt;
#include &amp;lt;command.h&amp;gt;

static int do_hello(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) {
    printf(&quot;Welcome to Software Factory! This is RK3399 Custom Command.\n&quot;);
    return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
    hello, 1, 0, do_hello,
    &quot;Print greeting message&quot;,
    &quot;No arguments required. Prints a welcome message for RK3399.&quot;
);
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14&quot;&gt;심화: RK3399 GPIO 제어 명령 (cmd/cmd_gpio_test.c)&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwijyMu4-8yUAxUAAAAAHQAAAAAQqwI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;C&lt;/span&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &amp;lt;common.h&amp;gt;
#include &amp;lt;asm/gpio.h&amp;gt;

static int do_gpio_test(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) {
    int pin = 64; // RK3399 GPIO 핀 번호
    
    if (gpio_request(pin, &quot;test_led&quot;)) {
        printf(&quot;GPIO %d 요청 실패\n&quot;, pin);
        return CMD_RET_FAILURE;
    }

    gpio_direction_output(pin, 1);
    printf(&quot;RK3399 GPIO %d가 HIGH로 설정되었습니다.\n&quot;, pin);
    
    return CMD_RET_SUCCESS;
}

U_BOOT_CMD(
    gpio_test, 1, 0, do_gpio_test,
    &quot;Control RK3399 GPIO for testing&quot;,
    &quot;Sets a predefined GPIO pin to HIGH for hardware validation.&quot;
);
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size23&quot;&gt;4. 빌드 시스템 연결&lt;/h3&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;파일을 작성한 후에는 반드시 빌드 과정에 포함시켜야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;18&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,0,0&quot;&gt;Kconfig 수정&lt;/b&gt;: cmd/Kconfig에 옵션을 추가하여 make menuconfig 메뉴에 보이게 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,1,0&quot;&gt;Makefile 수정&lt;/b&gt;: cmd/Makefile에 해당 오브젝트 파일을 추가하여 조건부로 빌드되게 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size23&quot;&gt;5. 개발을 위한 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;20&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,0,0&quot;&gt;환경 변수 활용&lt;/b&gt;: env_get()과 env_set()을 적극적으로 활용하십시오. 커스텀 명령 내에서 환경 변수를 읽어오면, 코드를 수정하지 않고도 부팅 시나리오나 디버그 레벨을 유연하게 제어할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,1,0&quot;&gt;자동화 로직&lt;/b&gt;: setenv bootcmd &quot;hello; gpio_test; run boot_linux&quot;와 같이 커스텀 명령을 부팅 스크립트에 포함하면, 부팅 시 특정 하드웨어 검증을 자동으로 수행하게 만들 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;21&quot; data-ke-size=&quot;size23&quot;&gt;6. 흔히 하는 실수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;22&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22,0,0&quot;&gt;함수 선언 누락&lt;/b&gt;: 명령어 실행 함수는 반드시 struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[] 인자 구조를 정확히 따라야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22,1,0&quot;&gt;반환값 오류&lt;/b&gt;: 함수의 마지막에 CMD_RET_SUCCESS나 CMD_RET_FAILURE를 적절히 반환하지 않으면, U-Boot 쉘이 해당 명령의 성공 여부를 판단하지 못해 스크립트 실행이 꼬일 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;24&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-path-to-node=&quot;25&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot에 나만의 명령어를 추가하는 것은 단순한 기능을 넘어 하드웨어 브링업 단계에서 매우 강력한 무기가 됩니다. 특히 회로 설계 팀과 협업할 때, 레지스터 상태를 확인하거나 물리 핀을 제어하는 전용 명령어를 제공하면 문제 해결 속도를 비약적으로 높일 수 있습니다. 오늘 다룬 예제를 바탕으로 직접 보드에 필요한 명령어를 추가하여 개발 효율을 극대화해 보시기 바랍니다.&lt;/p&gt;</description>
      <category>Embedded System/Bootloader &amp;amp; System Startup</category>
      <category>u-boot command</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1036</guid>
      <comments>https://coding-by-head.tistory.com/entry/u-boot-command#entry1036comment</comments>
      <pubDate>Sun, 7 Dec 2025 20:33:50 +0900</pubDate>
    </item>
    <item>
      <title>임베디드 개발자를 위한 U-Boot 드라이버 모델(DM) 핵심 분석과 포팅 가이드</title>
      <link>https://coding-by-head.tistory.com/entry/u-boot-driver</link>
      <description>&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 시스템 개발에서 U-Boot는 단순히 운영체제를 로딩하는 부트로더를 넘어, 하드웨어 초기화와 시스템 제어를 담당하는 핵심 소프트웨어입니다. 특히 최근의 U-Boot는 리눅스 커널과 유사한 드라이버 모델(Driver Model, DM)을 도입하여 하드웨어 추상화와 코드 재사용성을 획기적으로 개선했습니다. 이번 포스팅에서는 U-Boot DM의 기본 개념부터 이를 활용한 Rockchip RK3399 UART 드라이버 포팅 실습까지 체계적으로 살펴보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_jlr1jlr1jlr1jlr1.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/StPjY/dJMcaiXrovk/XXcdjf776FYe7Xb4BKO6lK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/StPjY/dJMcaiXrovk/XXcdjf776FYe7Xb4BKO6lK/img.png&quot; data-alt=&quot;Generated by Gemini AI.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/StPjY/dJMcaiXrovk/XXcdjf776FYe7Xb4BKO6lK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FStPjY%2FdJMcaiXrovk%2FXXcdjf776FYe7Xb4BKO6lK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;386&quot; height=&quot;386&quot; data-filename=&quot;Gemini_Generated_Image_jlr1jlr1jlr1jlr1.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Generated by Gemini AI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;1&quot; data-ke-size=&quot;size23&quot;&gt;핵심 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;U-Boot Driver Model(DM)은 장치(udevice)와 드라이버, 클래스(uclass)를 구분하여 하드웨어 제어 코드를 구조화합니다.&lt;/li&gt;
&lt;li&gt;Device Tree를 기반으로 장치를 스캔하고 적절한 드라이버를 할당(Binding)하여 하드웨어를 활성화하는 방식을 취합니다.&lt;/li&gt;
&lt;li&gt;커널 드라이버와 유사한 구조를 가지고 있어, 한번 이해하면 다양한 주변 장치 드라이버 포팅에 즉시 응용 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;1. U-Boot Driver Model(DM)의 핵심&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;과거의 U-Boot는 보드별로 코드가 흩어져 있어 관리가 어려웠습니다. DM은 이를 프레임워크로 표준화하여 유지보수성을 극대화했습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;6&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구성 요소&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0,0&quot;&gt;udevice (Device)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,1,0&quot;&gt;하드웨어 장치를 나타내는 데이터 노드&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,2,0,0&quot;&gt;driver&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,1,0&quot;&gt;하드웨어를 제어하는 실제 로직 (Ops 포함)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,3,0,0&quot;&gt;uclass&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,1,0&quot;&gt;동일한 기능의 드라이버 그룹 (예: UCLASS_SERIAL, UCLASS_SPI)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,4,0,0&quot;&gt;Device Tree (DT)&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,4,1,0&quot;&gt;하드웨어 사양을 정의하는 데이터 구조&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;2. U_BOOT_DRIVER 매크로 분석&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;드라이버는 U_BOOT_DRIVER 매크로를 통해 등록됩니다. 이 매크로는 드라이버의 이름, 클래스, 매칭 정보, 그리고 실행 함수 등을 포함합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;9&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,0,0&quot;&gt;probe 함수&lt;/b&gt;: 장치가 사용되기 직전 호출되어 클럭 설정, 레지스터 맵핑, 리셋 등의 초기화를 수행합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,0&quot;&gt;ops (Operations)&lt;/b&gt;: 드라이버가 외부로 노출하는 기능 함수들을 모아놓은 구조체입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;3. DM의 장치 활성화 과정&lt;/h3&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot는 부팅 시 다음 절차를 통해 하드웨어를 인식하고 준비합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;12&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,0,0&quot;&gt;DTB 로딩&lt;/b&gt;: 하드웨어 명세가 담긴 데이터 블록을 읽습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,1,0&quot;&gt;UCLASS 스캔&lt;/b&gt;: 시스템에 필요한 장치 클래스를 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,2,0&quot;&gt;매칭 (Matching)&lt;/b&gt;: Device Tree의 compatible 필드와 드라이버의 of_match를 대조합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,3,0&quot;&gt;바인딩 및 프로브 (Binding &amp;amp; Probe)&lt;/b&gt;: 장치와 드라이버를 결합하고 probe() 함수를 호출하여 활성화합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;4. 실습: RK3399 UART 드라이버 포팅&lt;/h3&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;최소한의 기능을 갖춘 UART 드라이버 구현 예제입니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15&quot;&gt;드라이버 소스 구현 (drivers/serial/serial_rk3399_simple.c)&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwijyMu4-8yUAxUAAAAAHQAAAAAQhAI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;C&lt;/span&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;#include &amp;lt;common.h&amp;gt;
#include &amp;lt;dm.h&amp;gt;
#include &amp;lt;serial.h&amp;gt;
#include &amp;lt;asm/io.h&amp;gt;

struct rk_uart_priv {
    void __iomem *base;
};

static int rk_uart_probe(struct udevice *dev) {
    struct rk_uart_priv *priv = dev_get_priv(dev);
    priv-&amp;gt;base = (void *)dev_read_addr(dev); // DT에서 주소 정보 획득

    if (!priv-&amp;gt;base) return -EINVAL;
    return 0;
}

static int rk_uart_putc(struct udevice *dev, const char ch) {
    struct rk_uart_priv *priv = dev_get_priv(dev);
    writel(ch, priv-&amp;gt;base + 0x00); // TX 레지스터에 데이터 쓰기
    return 0;
}

static const struct dm_serial_ops rk_uart_ops = {
    .putc = rk_uart_putc,
};

static const struct udevice_id rk_uart_ids[] = {
    { .compatible = &quot;rockchip,rk3399-simple-uart&quot; },
    {}
};

U_BOOT_DRIVER(rk3399_simple_uart) = {
    .name = &quot;rk3399_simple_uart&quot;,
    .id = UCLASS_SERIAL,
    .of_match = rk_uart_ids,
    .probe = rk_uart_probe,
    .ops = &amp;amp;rk_uart_ops,
    .priv_auto = sizeof(struct rk_uart_priv),
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;5. 주요 드라이버 디렉토리 구조&lt;/h3&gt;
&lt;p data-path-to-node=&quot;18&quot; data-ke-size=&quot;size16&quot;&gt;포팅 작업 시 아래 경로의 코드들을 참고하면 표준적인 구현 방식을 배울 수 있습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;19&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;디렉토리&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;담당 기능&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;19,1,0,0&quot;&gt;drivers/serial/&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;19,1,1,0&quot;&gt;UART 등 직렬 통신 드라이버&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;19,2,0,0&quot;&gt;drivers/spi/&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;19,2,1,0&quot;&gt;SPI 컨트롤러 및 메모리 드라이버&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;19,3,0,0&quot;&gt;drivers/mmc/&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;19,3,1,0&quot;&gt;SD/eMMC 카드 제어 드라이버&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;19,4,0,0&quot;&gt;drivers/net/&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;19,4,1,0&quot;&gt;이더넷 컨트롤러 및 PHY 드라이버&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;19,5,0,0&quot;&gt;drivers/clk/&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;19,5,1,0&quot;&gt;시스템 클럭 프레임워크&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size23&quot;&gt;6. 개발을 위한 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;21&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,0,0&quot;&gt;기존 코드 분석&lt;/b&gt;: 새로운 드라이버를 작성하기 전, drivers/ 하위에서 동일한 클래스(예: serial/)의 기존 드라이버를 열어보십시오. 구현 패턴이 거의 일치합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;21,1,0&quot;&gt;디버그 로그 활용&lt;/b&gt;: 드라이버가 로드되지 않는다면 debug() 함수를 probe 내부 곳곳에 배치하여 어느 단계에서 매칭이 실패하는지 확인하십시오.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size23&quot;&gt;7. 흔히 하는 실수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;23&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;23,0,0&quot;&gt;Compatible 문자열 불일치&lt;/b&gt;: Device Tree의 compatible 문자열과 드라이버의 of_match에 정의된 문자열이 한 글자라도 다르면 장치는 프로브되지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;23,1,0&quot;&gt;주소 할당 오류&lt;/b&gt;: dev_read_addr를 통해 가져온 주소가 실제 SoC 데이터시트의 메모리 맵과 일치하는지 다시 확인하십시오.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;25&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-path-to-node=&quot;26&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot 드라이버 모델은 리눅스 커널 드라이버 아키텍처와 매우 유사합니다. DM의 구조를 깊이 이해하면 새로운 하드웨어를 브링업할 때 겪는 시행착오를 크게 줄일 수 있습니다. 본 글의 UART 예제를 시작으로, SPI나 I2C 등 다른 드라이버 모델로 영역을 확장해 보시기 바랍니다. 체계적으로 설계된 드라이버 코드는 시스템의 안정성을 보장하는 가장 확실한 방법입니다.&lt;/p&gt;</description>
      <category>Embedded System/Bootloader &amp;amp; System Startup</category>
      <category>u-boot device driver</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1033</guid>
      <comments>https://coding-by-head.tistory.com/entry/u-boot-driver#entry1033comment</comments>
      <pubDate>Fri, 5 Dec 2025 20:47:14 +0900</pubDate>
    </item>
    <item>
      <title>U-Boot 부팅 시퀀스 완벽 분석: 다단계 부팅 구조와 로그 해석</title>
      <link>https://coding-by-head.tistory.com/entry/u-boot-boot-seq</link>
      <description>&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 리눅스 시스템을 개발하다 보면 반드시 마주하게 되는 과정이 바로 부팅 시퀀스 분석입니다. 하드웨어에 전원이 인가되는 순간부터 운영체제가 구동되기까지, U-Boot는 시스템의 상태를 초기화하고 안정적인 환경을 조성하는 핵심 가교 역할을 합니다. 특히 Rockchip RK3399와 같이 복잡한 고성능 SoC 환경에서는 부팅 과정을 다단계 구조로 분리하여 처리합니다. 이번 글에서는 U-Boot의 내부 동작 원리와 코드 흐름, 그리고 실무에서 부팅 로그를 통해 시스템 문제를 진단하는 방법을 정리해 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_ouk449ouk449ouk4.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MmqUh/dJMcabD38d7/4YjFaKOrTNI8ZGjhZE4cwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MmqUh/dJMcabD38d7/4YjFaKOrTNI8ZGjhZE4cwk/img.png&quot; data-alt=&quot;Generated by Gemini AI.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MmqUh/dJMcabD38d7/4YjFaKOrTNI8ZGjhZE4cwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMmqUh%2FdJMcabD38d7%2F4YjFaKOrTNI8ZGjhZE4cwk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;396&quot; height=&quot;396&quot; data-filename=&quot;Gemini_Generated_Image_ouk449ouk449ouk4.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Generated by Gemini AI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;1&quot; data-ke-size=&quot;size23&quot;&gt;핵심 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;U-Boot는 하드웨어 초기화와 운영체제 로딩을 담당하며, RK3399는 ROM, SPL/TPL, U-Boot, Kernel의 다단계 부팅 구조를 가집니다.&lt;/li&gt;
&lt;li&gt;부팅 흐름은 board_init_f의 초기 설정과 board_init_r의 드라이버 로드 및 커널 실행 단계로 나뉩니다.&lt;/li&gt;
&lt;li&gt;부팅 로그의 출력 지점을 파악하는 것만으로도 시스템 결함의 원인과 해결 방향을 빠르게 특정할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;1. RK3399 부팅 시퀀스&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;RK3399와 같은 고성능 SoC는 효율적인 메모리 관리와 하드웨어 초기화를 위해 다단계 부팅 구조를 사용합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;6&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;단계&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;명칭&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;주요 역할&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0,0&quot;&gt;1st&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,1,0&quot;&gt;ROM&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,2,0&quot;&gt;부트 디바이스 검색 및 SPL 로드&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,3,0&quot;&gt;SoC 내부 고정 코드 (수정 불가)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,2,0,0&quot;&gt;2nd&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,1,0&quot;&gt;SPL/TPL&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,2,0&quot;&gt;DRAM 초기화 및 PMIC 전원 설정&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,3,0&quot;&gt;SRAM 환경에서 동작&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,3,0,0&quot;&gt;3rd&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,1,0&quot;&gt;U-Boot&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,2,0&quot;&gt;주변 장치 로드 및 환경 변수 처리&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,3,0&quot;&gt;DRAM 상에서 동작&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,4,0,0&quot;&gt;4th&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,4,1,0&quot;&gt;Kernel&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,4,2,0&quot;&gt;리눅스 OS 구동 및 rootfs 마운트&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,4,3,0&quot;&gt;시스템 제어권 이관&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;2. U-Boot 코드 흐름 분석&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot 내부의 흐름을 이해하면 포팅 시 발생하는 오류를 논리적으로 추적할 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;9&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,0,0&quot;&gt;진입점 (start.S)&lt;/b&gt;: arch/arm/cpu/armv8/start.S에서 시작합니다. CPU의 Exception Level 설정, MMU 비활성화, 스택 포인터 초기화를 수행합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,0&quot;&gt;초기화 함수 (Front vs Rear)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;9,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;board_init_f (Front): DRAM 준비 전 초기화 단계입니다. UART, 타이머 등 최소한의 필수 자원을 세팅합니다.&lt;/li&gt;
&lt;li&gt;board_init_r (Rear): DRAM 준비 후 시스템이 재배치(Relocation)된 이후입니다. MMC, USB, 네트워크 등 모든 주변 장치 드라이버가 로드됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;3. 부팅 로그 추적 가이드&lt;/h3&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;실제 보드에서 출력되는 로그는 시스템의 상태를 대변합니다. 각 구간별 의미를 파악하는 것이 중요합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;12&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;로그 구간&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;단계&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;상태 및 확인 사항&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,1,0,0&quot;&gt;TPL/SPL&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,1,1,0&quot;&gt;2nd Stage&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,1,2,0&quot;&gt;DRAM 트레이닝 성공 여부 및 전압 상태 확인&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,2,0,0&quot;&gt;U-Boot 콘솔&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,2,1,0&quot;&gt;3rd Stage&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,2,2,0&quot;&gt;주변 장치(eMMC, LAN) 초기화 성공 여부&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,3,0,0&quot;&gt;Hit any key&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,3,1,0&quot;&gt;대기 단계&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,3,2,0&quot;&gt;자동 부팅 중단 및 수동 커널 파라미터 수정 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,4,0,0&quot;&gt;Starting kernel&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,4,1,0&quot;&gt;4th Stage&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,4,2,0&quot;&gt;커널 이미지 압축 해제 및 DTB 로딩 성공 여부&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;4. 개발을 위한 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;14&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,0,0&quot;&gt;로그 출력 포인트 활용&lt;/b&gt;: UART 로그가 어디서 멈추는지 확인하십시오. TPL에서 멈춘다면 DRAM 물리적 결함이나 클럭 설정을, U-Boot 본체에서 멈춘다면 환경 변수나 부팅 경로를 의심해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,1,0&quot;&gt;보드별 핀 설정 확인&lt;/b&gt;: board_init_f 단계에서 UART 출력이 나오지 않는다면 핀먹스(Pinmux) 설정이 올바르게 되었는지 보드 회로도와 비교하십시오.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size23&quot;&gt;5. 흔히 하는 실수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,0,0&quot;&gt;DRAM 초기화 오류&lt;/b&gt;: TPL 로그가 나타나지 않거나 트레이닝에서 계속 실패한다면 메모리 파라미터가 보드의 실제 물리적 사양과 맞지 않을 확률이 매우 높습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,0&quot;&gt;부트 파라미터 오타&lt;/b&gt;: bootargs에 적힌 파티션 경로나 콘솔 설정이 실제 디바이스 환경과 다르면 커널 부팅 직후 화면이 멈추거나 커널 패닉이 발생합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot는 단순히 운영체제를 실행하는 통로가 아니라 하드웨어의 생명력을 불어넣는 첫 번째 운영자입니다. RK3399와 같은 복잡한 시스템에서는 각 부팅 단계를 분리하여 이해하는 것이 무엇보다 중요합니다. 부팅 과정에서 문제가 발생했을 때 당황하지 말고, 위에서 정리한 단계별 흐름과 로그를 역추적해 보십시오. 시스템의 구조를 명확히 파악하고 있다면 문제 해결은 생각보다 훨씬 빠르게 이루어질 것입니다.&lt;/p&gt;</description>
      <category>Embedded System/Bootloader &amp;amp; System Startup</category>
      <category>u-boot boot sequence</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1030</guid>
      <comments>https://coding-by-head.tistory.com/entry/u-boot-boot-seq#entry1030comment</comments>
      <pubDate>Thu, 4 Dec 2025 22:26:45 +0900</pubDate>
    </item>
    <item>
      <title>U-Boot 포팅 가이드: 환경 설정부터 보드 초기화까지</title>
      <link>https://coding-by-head.tistory.com/entry/u-boot-build</link>
      <description>&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 시스템 개발에서 새로운 하드웨어를 구동할 때 가장 먼저 마주하는 관문은 단연 U-Boot 포팅입니다. 보드 특성에 맞춰 부트로더를 최적화하는 과정은 단순히 부팅을 성공시키는 것을 넘어, 시스템의 전체적인 안정성을 결정짓는 핵심 단계입니다. 이번 글에서는 Rockchip RK3399 플랫폼을 예시로, U-Boot 포팅을 위해 반드시 거쳐야 할 필수 준비 요소와 단계별 포팅 전략을 체계적으로 정리해 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_ogx7w0ogx7w0ogx7.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ubX1N/dJMb99TLUWB/LCnbo0NBqbAP1ouG7yckk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ubX1N/dJMb99TLUWB/LCnbo0NBqbAP1ouG7yckk1/img.png&quot; data-alt=&quot;Generated by Gemini AI.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ubX1N/dJMb99TLUWB/LCnbo0NBqbAP1ouG7yckk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FubX1N%2FdJMb99TLUWB%2FLCnbo0NBqbAP1ouG7yckk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;384&quot; height=&quot;384&quot; data-filename=&quot;Gemini_Generated_Image_ogx7w0ogx7w0ogx7.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Generated by Gemini AI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;1&quot; data-ke-size=&quot;size23&quot;&gt;핵심 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;U-Boot 포팅은 크로스 컴파일 환경 구축을 시작으로 defconfig 설정, 소스 코드 수정, Device Tree 작성의 단계를 거칩니다.&lt;/li&gt;
&lt;li&gt;핵심 설정 파일인 헤더 파일과 보드 초기화 루틴, 그리고 하드웨어 명세인 DTS를 수정하는 것이 포팅의 본질입니다.&lt;/li&gt;
&lt;li&gt;효율적인 포팅을 위해서는 기존 레퍼런스 코드를 분석하고, 플랫폼에 필요한 최소한의 변경 사항부터 반영하는 것이 좋습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;1. 개발 환경 준비: 크로스 컴파일러 설정&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot는 호스트 PC에서 빌드하여 타겟 보드에서 실행되므로, ARM64 아키텍처에 맞는 크로스 컴파일러가 필요합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;6&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;명령어&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0,0&quot;&gt;컴파일러 설치&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,1,0&quot;&gt;sudo apt install gcc-aarch64-linux-gnu&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,2,0&quot;&gt;우분투 환경에서 툴체인 설치&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,2,0,0&quot;&gt;환경 변수 설정&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,1,0&quot;&gt;export CROSS_COMPILE=aarch64-linux-gnu-&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,2,0&quot;&gt;컴파일러 접두어 지정&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,3,0,0&quot;&gt;아키텍처 설정&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,1,0&quot;&gt;export ARCH=arm64&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,2,0&quot;&gt;타겟 CPU 아키텍처 명시&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;2. 프로젝트 설정 및 커스터마이징&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;기존 레퍼런스 보드 설정을 가져와 시작하면 작업 시간을 크게 줄일 수 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;9&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,0,0&quot;&gt;기본 설정 적용&lt;/b&gt;: make rockchip_rk3399_defconfig 명령으로 베이스 설정을 불러옵니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,0&quot;&gt;상세 설정 변경&lt;/b&gt;: make menuconfig를 실행하여 UART, 저장 장치, 네트워크 기능을 UI 환경에서 조정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,2,0&quot;&gt;설정 저장&lt;/b&gt;: make savedefconfig를 통해 나만의 보드 전용 설정 파일로 저장합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;3. U-Boot 포팅 필수 수정 파일&lt;/h3&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;새로운 보드를 지원하려면 소스 트리에 다음과 같은 핵심 정보들을 반영해야 합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;12&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구성 요소&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;주요 경로&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,1,0,0&quot;&gt;Config 헤더&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,1,1,0&quot;&gt;include/configs/.h&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,1,2,0&quot;&gt;메모리 맵, UART 속도, 환경 변수 정의&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,2,0,0&quot;&gt;Board 폴더&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,2,1,0&quot;&gt;board///&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,2,2,0&quot;&gt;핀 설정(Pinmux), DRAM 초기화 등&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,3,0,0&quot;&gt;CPU 코드&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,3,1,0&quot;&gt;arch/arm/cpu/armv8/&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,3,2,0&quot;&gt;MMU 및 캐시 설정 등 아키텍처 공용 로직&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,4,0,0&quot;&gt;Device Tree&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,4,1,0&quot;&gt;arch/arm/dts/.dts&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;12,4,2,0&quot;&gt;GPIO, I2C, SPI 등 하드웨어 구성 명세&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;4. 보드 초기화 루틴 및 환경 변수&lt;/h3&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;초기화 코드는 시스템이 켜진 후 가장 먼저 실행되는 C 코드 영역입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;15&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15,0,0&quot;&gt;board.c&lt;/b&gt;: board_init()에서 GPIO 방향이나 PMIC 전원 제어를 수행하고, board_late_init()에서 부팅 직전 필요한 환경 변수를 동적으로 수정합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15,1,0&quot;&gt;환경 변수 최적화&lt;/b&gt;: setenv 명령어를 통해 커널 부팅 파라미터를 설정합니다. 자주 사용하는 부팅 로직은 CONFIG_BOOTCOMMAND를 통해 defconfig에 고정하면 매번 입력하는 번거로움을 덜 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size23&quot;&gt;5. 개발을 위한 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,0,0&quot;&gt;레퍼런스 코드 활용&lt;/b&gt;: RK3399는 오픈소스 레퍼런스가 매우 많습니다. 처음부터 새로 짜려 하지 말고, 유사한 보드의 설정을 찾아 비교하며 필요한 부분만 수정하십시오.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,1,0&quot;&gt;단계별 검증&lt;/b&gt;: 한꺼번에 많은 코드를 수정하지 마십시오. UART 초기화가 되는지 먼저 확인하고, 그다음 저장 장치를 인식시키는 방식으로 점진적으로 진행하는 것이 트러블슈팅에 유리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size23&quot;&gt;6. 흔히 하는 실수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;19&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,0,0&quot;&gt;디버그 시리얼 포트 설정&lt;/b&gt;: UART baud rate가 보드의 실제 하드웨어 사양과 맞지 않으면 부팅 로그가 깨져 나옵니다. 1500000 등 사용하는 보드의 표준 속도를 정확히 확인하십시오.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,1,0&quot;&gt;Device Tree 누락&lt;/b&gt;: 커널 부팅 시 특정 장치가 잡히지 않는다면 대부분 DTS 설정 문제입니다. 전원 레일(Regulator) 정의가 빠졌는지, GPIO 핀맵이 실제 보드 설계와 일치하는지 반드시 다시 확인해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;21&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot 포팅은 복잡해 보이지만, 설정 파일과 보드 코드, 그리고 Device Tree로 이어지는 흐름만 이해하면 충분히 정복할 수 있습니다. 이미 충분한 레퍼런스가 존재하는 RK3399 플랫폼인 만큼, 체계적인 접근으로 포팅 시간을 단축하시길 바랍니다. 다음 글에서는 빌드된 이미지를 직접 보드에 라이팅하고 실제 디버깅하는 과정을 다루겠습니다.&lt;/p&gt;</description>
      <category>Embedded System/Bootloader &amp;amp; System Startup</category>
      <category>u-boot ARCH</category>
      <category>u-boot CROSS_COMPILE</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1027</guid>
      <comments>https://coding-by-head.tistory.com/entry/u-boot-build#entry1027comment</comments>
      <pubDate>Wed, 3 Dec 2025 20:57:23 +0900</pubDate>
    </item>
    <item>
      <title>U-Boot 디렉토리 구조와 빌드 과정 분석 (이미지 파일 생성 원리)</title>
      <link>https://coding-by-head.tistory.com/entry/u-boot-structure</link>
      <description>&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 리눅스 시스템을 개발할 때 U-Boot는 단순한 부트로더를 넘어 시스템의 첫 단추를 끼우는 핵심 소프트웨어입니다. 특히 하드웨어 사양이 복잡한 최신 SoC 플랫폼에서 안정적인 커널 부팅 환경을 구축하려면 U-Boot의 디렉토리 구조와 빌드 과정을 정확히 꿰뚫고 있어야 합니다. 이번 글에서는 RK3399 플랫폼을 예시로 U-Boot의 소스 코드 구조를 분석하고, 효율적인 빌드 과정을 단계별로 정리해 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_agks6iagks6iagks.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FnYIV/dJMcaf7vHXD/GI0NTj4lL5ZO4GsVYz6mU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FnYIV/dJMcaf7vHXD/GI0NTj4lL5ZO4GsVYz6mU0/img.png&quot; data-alt=&quot;Generated by Gemini AI.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FnYIV/dJMcaf7vHXD/GI0NTj4lL5ZO4GsVYz6mU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFnYIV%2FdJMcaf7vHXD%2FGI0NTj4lL5ZO4GsVYz6mU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;386&quot; height=&quot;386&quot; data-filename=&quot;Gemini_Generated_Image_agks6iagks6iagks.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Generated by Gemini AI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;1&quot; data-ke-size=&quot;size23&quot;&gt;핵심 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;U-Boot는 arch, board, drivers 등 계층적인 디렉토리 구조를 통해 다양한 플랫폼을 체계적으로 지원합니다.&lt;/li&gt;
&lt;li&gt;Kconfig와 Makefile을 활용한 빌드 시스템을 통해 보드별 맞춤 설정과 컴파일이 가능합니다.&lt;/li&gt;
&lt;li&gt;빌드 결과물인 각 이미지 파일의 용도를 정확히 파악해야 디버깅 및 보드 포팅 시 발생할 수 있는 문제를 빠르게 해결할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;1. U-Boot 핵심 디렉토리 구조&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot는 방대한 코드를 유지보수하기 위해 아키텍처와 보드별로 코드를 명확히 분리하고 있습니다. 소스 코드를 수정해야 할 때 어디를 찾아야 할지 알려주는 핵심 디렉토리들입니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;6&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;디렉토리&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;담당 범위&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;상세 역할&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0,0&quot;&gt;arch/&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,1,0&quot;&gt;아키텍처별 종속 코드&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,2,0&quot;&gt;ARM, RISC-V 등 아키텍처별 코어 로직 및 SoC 레벨 초기화&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,2,0,0&quot;&gt;board/&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,1,0&quot;&gt;보드별 설정 코드&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,2,0&quot;&gt;특정 제조사/모델의 보드 초기화 및 하드웨어 특화 로직&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,3,0,0&quot;&gt;drivers/&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,1,0&quot;&gt;주변장치 드라이버&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,2,0&quot;&gt;MMC, USB, I2C, Ethernet 등 하드웨어 제어 드라이버&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,4,0,0&quot;&gt;cmd/&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,4,1,0&quot;&gt;명령어 정의&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,4,2,0&quot;&gt;콘솔에서 사용되는 fatls, mmc 등 명령어 소스 코드&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,5,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,5,0,0&quot;&gt;include/&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,5,1,0&quot;&gt;헤더 파일 및 설정&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,5,2,0&quot;&gt;전역 설정 및 보드별 헤더 파일(configs/ 폴더) 위치&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;2. 빌드 시스템 이해하기&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot는 리눅스 커널과 유사한 빌드 메커니즘을 사용합니다. 복잡한 설정을 간편하게 관리하기 위한 시스템 구성 요소는 다음과 같습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;9&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구성 요소&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,0,0&quot;&gt;Kconfig&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,1,1,0&quot;&gt;menuconfig를 통해 UI 기반으로 컴파일 옵션을 선택&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,2,0,0&quot;&gt;Makefile&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,2,1,0&quot;&gt;전체 빌드 과정을 조율하고 각 디렉토리의 소스를 컴파일&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,3,0,0&quot;&gt;defconfig&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,3,1,0&quot;&gt;특정 보드의 빌드 시작점이 되는 기본 설정 파일&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;3. RK3399 빌드 실전&lt;/h3&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;RK3399와 같은 플랫폼을 빌드하는 과정은 일관된 패턴을 따릅니다. 다음 순서로 명령어를 입력하면 빌드가 진행됩니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwijyMu4-8yUAxUAAAAAHQAAAAAQpAE&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&lt;span&gt;Bash&lt;/span&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 1. 크로스 컴파일러 환경 설정
export CROSS_COMPILE=aarch64-linux-gnu-

# 2. 보드별 기본 설정 적용 (.config 파일 생성)
make rockchip_rk3399_defconfig

# 3. 빌드 시작
make -j8
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;4. 빌드 후 생성되는 주요 이미지 파일&lt;/h3&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;빌드가 완료되면 루트 디렉토리에 여러 파일이 생성됩니다. 시스템을 보드에 올릴 때 각 파일이 어떤 역할을 하는지 알아야 합니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;15&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;파일명&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;형식 및 특징&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;용도&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15,1,0,0&quot;&gt;u-boot.elf&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,1,1,0&quot;&gt;ELF (디버깅 심볼 포함)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,1,2,0&quot;&gt;GDB를 사용한 소프트웨어 디버깅용&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15,2,0,0&quot;&gt;u-boot.bin&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,2,1,0&quot;&gt;순수 바이너리&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,2,2,0&quot;&gt;실제 플래시 메모리에 기록되는 실행 데이터&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15,3,0,0&quot;&gt;u-boot.img&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,3,1,0&quot;&gt;mkimage 헤더 포함&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,3,2,0&quot;&gt;보안 검증 및 로딩 정보가 담긴 로더 이미지&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15,4,0,0&quot;&gt;idbloader.img&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,4,1,0&quot;&gt;SPL/TPL 결합&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,4,2,0&quot;&gt;RK3399 부팅 시 가장 먼저 실행되는 초기화 이미지&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size23&quot;&gt;5. 개발을 위한 팁&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,0,0&quot;&gt;전체 빌드보다 변경점 위주 빌드&lt;/b&gt;: 소스 코드 수정 후에는 make 명령만 수행하여 수정된 파일만 다시 컴파일하세요. 시간이 크게 절약됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,1,0&quot;&gt;디버그 모드 활용&lt;/b&gt;: 빌드 시 V=1 옵션을 주면 컴파일러가 출력하는 상세 로그를 확인할 수 있어 빌드 에러를 찾기 쉽습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size23&quot;&gt;6. 흔히 하는 실수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;19&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,0,0&quot;&gt;환경 변수 초기화 누락&lt;/b&gt;: 이전 빌드의 결과물이 남아있으면 엉뚱한 바이너리가 생성될 수 있습니다. 중요한 작업을 하기 전에는 make distclean으로 초기화하는 습관이 좋습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,1,0&quot;&gt;설정 파일 혼동&lt;/b&gt;: configs/ 경로의 defconfig를 직접 수정하지 말고, 빌드 후 생성된 .config 파일을 수정하거나 make menuconfig를 활용하세요.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;21&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot는 코드가 방대하지만, arch, board, drivers라는 핵심 구조만 파악하면 수정 위치를 찾는 것은 어렵지 않습니다. 특히 RK3399와 같은 플랫폼에서는 SPL과 각 이미지 파일의 결합 과정을 잘 이해하는 것이 성공적인 포팅의 열쇠입니다. 이 구조를 기반으로 직접 코드를 따라가 보면서 익숙해지시길 바랍니다.&lt;/p&gt;</description>
      <category>Embedded System/Bootloader &amp;amp; System Startup</category>
      <category>u-boot structure</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1024</guid>
      <comments>https://coding-by-head.tistory.com/entry/u-boot-structure#entry1024comment</comments>
      <pubDate>Tue, 2 Dec 2025 20:40:55 +0900</pubDate>
    </item>
    <item>
      <title>임베디드 개발자의 필수 관문, U-Boot 구조와 부팅 원리 완벽 정리</title>
      <link>https://coding-by-head.tistory.com/entry/u-boot-intro</link>
      <description>&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 시스템 개발을 시작할 때 가장 먼저 마주하는 관문인 U-Boot에 대해 정리했습니다. 하드웨어와 운영체제 사이에서 시스템의 첫 단추를 끼우는 핵심 소프트웨어인 만큼, 그 구조와 동작 원리를 파악하는 것은 임베디드 엔지니어에게 필수적인 과정입니다. 이번 글에서는 U-Boot의 기본 개념부터 내부 구조, 그리고 실제 실무에서 활용하는 방식까지 구체적으로 살펴보고자 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_svfib5svfib5svfi.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RgjTF/dJMcaad6k1D/BdO92F8Bg7LkSrsEw3vBb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RgjTF/dJMcaad6k1D/BdO92F8Bg7LkSrsEw3vBb1/img.png&quot; data-alt=&quot;Generated by Gemini AI.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RgjTF/dJMcaad6k1D/BdO92F8Bg7LkSrsEw3vBb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRgjTF%2FdJMcaad6k1D%2FBdO92F8Bg7LkSrsEw3vBb1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;380&quot; height=&quot;380&quot; data-filename=&quot;Gemini_Generated_Image_svfib5svfib5svfi.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Generated by Gemini AI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;1&quot; data-ke-size=&quot;size23&quot;&gt;핵심 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;U-Boot는 임베디드 시스템에서 하드웨어 초기화와 운영체제 로딩을 담당하는 오픈소스 부트로더입니다.&lt;/li&gt;
&lt;li&gt;하드웨어 제약으로 인해 효율적인 부팅을 위해 SPL과 U-Boot 본체라는 2단계 구조를 채택하고 있습니다.&lt;/li&gt;
&lt;li&gt;네트워크 부팅과 환경 변수 조절 등 강력한 CLI 기능을 제공하여 개발 및 디버깅 효율을 극대화합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;1. U-Boot의 정의와 역할&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot는 Universal Boot Loader의 약자로, 임베디드 환경에서 표준처럼 사용되는 오픈소스 부트로더입니다. 전원이 켜지면 가장 먼저 실행되어 운영체제가 구동될 수 있는 상태를 만듭니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;6&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0,0&quot;&gt;범용성&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,1,0&quot;&gt;ARM, RISC-V, MIPS, x86 등 다양한 아키텍처 지원&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,2,0,0&quot;&gt;유연성&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,1,0&quot;&gt;네트워크, 스토리지, 파일 시스템 드라이버 내장&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,3,0,0&quot;&gt;제어권&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,3,1,0&quot;&gt;CLI를 통해 부트 환경 변수 및 파라미터 관리 가능&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,4,0,0&quot;&gt;확장성&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,4,1,0&quot;&gt;오픈소스 기반으로 특정 보드에 맞춘 커스터마이징 용이&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;2. U-Boot의 2단계 구조: SPL과 Stage 2&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 SoC는 초기에 접근 가능한 메모리(SRAM) 용량이 매우 작습니다. 이 한계를 극복하기 위해 U-Boot는 SPL과 본체로 역할을 나눕니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;9&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;단계&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;역할 및 목적&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,0,0&quot;&gt;Stage 1&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,1,1,0&quot;&gt;SPL (Secondary Program Loader)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,1,2,0&quot;&gt;최소한의 하드웨어(DDR, 클럭) 초기화 및 본체 로딩&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,2,0,0&quot;&gt;Stage 2&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,2,1,0&quot;&gt;U-Boot 본체&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;9,2,2,0&quot;&gt;전체 하드웨어 초기화 및 커널, 장치 트리 로딩&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;3. 실전 예제: RK3399 부트 플로우&lt;/h3&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;Rockchip RK3399 프로세서를 예로 들면 시스템이 구동되는 전체 흐름은 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;12&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,0,0&quot;&gt;BootROM&lt;/b&gt;: 전원 인가 후 하드웨어 고정 코드가 실행되며 부트 장치(SD/eMMC)를 찾습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,1,0&quot;&gt;IDBLoader (SPL)&lt;/b&gt;: DRAM을 초기화하고 U-Boot 본체를 메모리에 올립니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,2,0&quot;&gt;U-Boot (u-boot.itb)&lt;/b&gt;: 설정된 환경 변수를 읽고 커널 로딩을 준비합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,3,0&quot;&gt;Kernel &amp;amp; DTB&lt;/b&gt;: Linux 커널과 하드웨어 명세(Device Tree)를 메모리에 배치합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,4,0&quot;&gt;Linux OS&lt;/b&gt;: 운영체제가 시스템의 주도권을 넘겨받습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;4. PC의 BIOS vs 임베디드 U-Boot&lt;/h3&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;임베디드 시스템에서 왜 BIOS가 아닌 U-Boot를 주로 사용하는지 그 차이를 살펴보겠습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;15&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;BIOS (PC)&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;U-Boot (Embedded)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15,1,0,0&quot;&gt;개방성&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,1,1,0&quot;&gt;폐쇄적 (제조사 제공)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,1,2,0&quot;&gt;오픈소스 (수정 및 포팅 가능)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15,2,0,0&quot;&gt;확장성&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,2,1,0&quot;&gt;제한적&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,2,2,0&quot;&gt;매우 유연함&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15,3,0,0&quot;&gt;부트 대상&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,3,1,0&quot;&gt;HDD, SSD 중심&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,3,2,0&quot;&gt;Flash, SD, eMMC, Network 등 다양&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;15,4,0,0&quot;&gt;인터페이스&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,4,1,0&quot;&gt;GUI 설정 위주&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;15,4,2,0&quot;&gt;강력한 CLI (Command Line)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size23&quot;&gt;5. 개발을 위한 팁&lt;/h3&gt;
&lt;p data-path-to-node=&quot;17&quot; data-ke-size=&quot;size16&quot;&gt;실무에서 U-Boot를 효과적으로 활용하려면 다음 두 가지를 숙지하는 것이 좋습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;18&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,0,0&quot;&gt;네트워크 부팅 (TFTP) 활용&lt;/b&gt;: 매번 SD카드를 쓰지 말고 네트워크를 통해 빌드된 커널을 즉시 전송하여 테스트하십시오. 개발 속도가 크게 향상됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,1,0&quot;&gt;환경 변수 저장&lt;/b&gt;: saveenv 명령어를 통해 설정을 저장하면 매번 수동으로 입력할 필요가 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size23&quot;&gt;6. 흔히 하는 실수&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;20&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,0,0&quot;&gt;DDR 초기화 실패&lt;/b&gt;: SPL 단계에서 DDR 파라미터가 맞지 않으면 부팅이 시작조차 되지 않습니다. 메모리 맵과 타이밍 설정을 꼼꼼히 확인하세요.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,1,0&quot;&gt;환경 변수 초기화&lt;/b&gt;: 잘못된 환경 변수 설정으로 부팅이 막히면, 하드웨어적인 방법(Flash 접근)으로 복구해야 하므로 중요한 설정은 기록해두어야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;U-Boot는 하드웨어와 운영체제 사이를 잇는 든든한 가교입니다. 부팅 과정을 깊이 이해하고 있으면 시스템 트러블슈팅과 성능 최적화의 난이도가 훨씬 낮아집니다. 앞으로 본 블로그에서는 RK3399 기반 시스템에서 직접 U-Boot를 포팅하고 디바이스 드라이버를 추가하는 실전 과정을 이어가겠습니다.&lt;/p&gt;</description>
      <category>Embedded System/Bootloader &amp;amp; System Startup</category>
      <category>u-boot</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/1021</guid>
      <comments>https://coding-by-head.tistory.com/entry/u-boot-intro#entry1021comment</comments>
      <pubDate>Mon, 1 Dec 2025 20:38:13 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen 암호화 및 인증 적용 사례</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-encryption</link>
      <description>&lt;h2&gt;CANOpen 암호화 및 인증 적용 사례&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;CANOpen 네트워크는 산업 자동화, 의료 기기, 로봇 시스템 등 다양한 분야에서 활용됩니다. 하지만 이러한 네트워크는 보안 위협에 취약할 수 있으며, 데이터 무결성과 인증이 중요한 요소로 작용합니다. 본 장에서는 CANOpen에서 암호화 및 인증 기법을 적용하는 방법과 실무적인 사례를 소개합니다.&lt;/p&gt;
&lt;h3&gt;CANOpen 보안의 필요성&lt;/h3&gt;
&lt;p&gt;CANOpen은 기본적으로 브로드캐스트 기반의 메시지 전송을 사용하므로, 공격자가 네트워크 내의 데이터를 가로채거나 위조할 가능성이 있습니다. 따라서 CANOpen 네트워크에서 다음과 같은 보안 요구 사항이 고려되어야 합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;데이터 무결성&lt;/strong&gt;: 메시지가 변조되지 않도록 보호해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;인증(Authentication)&lt;/strong&gt;: 데이터의 출처를 확인하고, 신뢰할 수 있는 노드만 통신할 수 있도록 해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;암호화(Encryption)&lt;/strong&gt;: 기밀성이 필요한 데이터를 보호해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;재전송 방지&lt;/strong&gt;: 동일한 메시지가 반복적으로 전송되는 공격을 방지해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;CANOpen에서 적용 가능한 보안 기법&lt;/h3&gt;
&lt;p&gt;CANOpen 네트워크에서 보안을 강화하기 위해 여러 가지 방법을 적용할 수 있습니다. 여기에서는 대표적인 기법을 설명합니다.&lt;/p&gt;
&lt;h4&gt;1. 메시지 인증 코드(MAC, Message Authentication Code)&lt;/h4&gt;
&lt;p&gt;MAC는 송신자가 메시지를 보낼 때 특정 키를 이용하여 생성하며, 수신자는 동일한 키를 사용하여 메시지의 무결성을 확인할 수 있습니다. 이를 통해 데이터 변조 및 위조를 방지할 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HMAC(Hash-based MAC)&lt;/strong&gt;: SHA-256 또는 SHA-512를 기반으로 하는 메시지 인증 코드&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CMAC(Cipher-based MAC)&lt;/strong&gt;: AES 블록 암호화를 기반으로 하는 인증 코드&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. 전자 서명(Digital Signature)&lt;/h4&gt;
&lt;p&gt;전자 서명은 메시지의 출처를 검증할 수 있는 방법으로, 공개 키 기반의 ECDSA(Elliptic Curve Digital Signature Algorithm) 같은 알고리즘이 사용됩니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;송신자가 메시지와 함께 서명을 생성하여 전송&lt;/li&gt;
&lt;li&gt;수신자는 서명을 검증하여 메시지의 신뢰성을 확보&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. AES 기반 데이터 암호화&lt;/h4&gt;
&lt;p&gt;CANOpen 메시지는 기본적으로 평문으로 전송되므로, 중요한 데이터를 보호하기 위해 AES(Advanced Encryption Standard)를 적용할 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AES-128 또는 AES-256&lt;/strong&gt;을 사용하여 메시지를 암호화&lt;/li&gt;
&lt;li&gt;각 노드에서 사전에 공유한 키를 이용하여 복호화&lt;/li&gt;
&lt;li&gt;CANOpen 프로토콜 내에서 추가적인 데이터 필드를 활용하여 암호화된 메시지 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;보안 적용 사례&lt;/h3&gt;
&lt;h4&gt;사례 1: 산업용 로봇에서 CANOpen 보안 적용&lt;/h4&gt;
&lt;p&gt;한 산업용 로봇 제조업체는 외부 공격으로부터 네트워크를 보호하기 위해 다음과 같은 방법을 적용하였습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ECDSA 전자 서명을 활용하여 명령 메시지의 무결성을 보장&lt;/li&gt;
&lt;li&gt;AES-256 기반으로 중요한 데이터(로봇 위치 정보) 암호화&lt;/li&gt;
&lt;li&gt;HMAC을 사용하여 주요 명령 메시지의 변조 여부 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;사례 2: 의료 기기에서 CANOpen 보안 강화&lt;/h4&gt;
&lt;p&gt;의료 기기에서는 환자의 데이터를 안전하게 보호해야 하므로, 다음과 같은 보안 기법이 활용되었습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CMAC을 사용하여 기기 간 인증 수행&lt;/li&gt;
&lt;li&gt;AES-128을 이용한 데이터 암호화로 기밀성 유지&lt;/li&gt;
&lt;li&gt;주기적인 키 교체 및 보안 업데이트 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;CANOpen 네트워크에서 보안은 필수적인 요소이며, 다양한 암호화 및 인증 기법을 적용하여 안전한 통신을 구현할 수 있습니다. 특히 산업 자동화, 의료 기기, 로봇 시스템과 같이 높은 신뢰성이 요구되는 분야에서는 암호화 및 인증 기술을 적극적으로 도입해야 합니다. 이를 통해 데이터 무결성을 보장하고, 네트워크 공격으로부터 보호할 수 있습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen Encryption</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/823</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-encryption#entry823comment</comments>
      <pubDate>Sun, 24 Aug 2025 20:51:41 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen 네트워크의 보안 강화 방안</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-security1</link>
      <description>&lt;h2&gt;CANOpen 네트워크의 보안 강화 방안&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;CANOpen 네트워크는 산업 자동화, 의료 기기, 자동차 및 다양한 임베디드 시스템에서 널리 사용됩니다. 그러나 CAN 프로토콜 자체는 기본적으로 보안을 고려하여 설계되지 않았기 때문에, CANOpen 네트워크에서 보안 위협에 대한 대비가 필요합니다. 본 장에서는 CANOpen 네트워크의 보안 강화 방안에 대해 다루며, 주요 보안 위협과 이를 방어하기 위한 방법을 설명합니다.&lt;/p&gt;
&lt;h3&gt;CANOpen 네트워크의 주요 보안 위협&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;메시지 스푸핑 (Message Spoofing)&lt;/strong&gt;&lt;br&gt;공격자가 합법적인 노드처럼 가장하여 잘못된 데이터를 전송하는 공격입니다. 이를 통해 원하지 않는 동작을 유발할 수 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;재전송 공격 (Replay Attack)&lt;/strong&gt;&lt;br&gt;정상적인 메시지를 가로채서 동일한 메시지를 다시 전송하는 방식으로, 시스템을 예상하지 못한 상태로 만들 수 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;중간자 공격 (Man-in-the-Middle, MITM)&lt;/strong&gt;&lt;br&gt;공격자가 노드 간의 통신을 가로채고 수정하여 잘못된 데이터를 전송할 수 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;서비스 거부 공격 (Denial of Service, DoS)&lt;/strong&gt;&lt;br&gt;악의적인 노드가 네트워크에 과부하를 주어 정상적인 데이터 통신을 방해하는 공격입니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;악성 코드 삽입 및 변조&lt;/strong&gt;&lt;br&gt;펌웨어 업데이트 과정에서 악성 코드가 삽입되거나, 네트워크 노드의 설정이 변조될 수 있습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;CANOpen 보안 강화 방안&lt;/h3&gt;
&lt;h4&gt;1. 메시지 인증 및 암호화&lt;/h4&gt;
&lt;p&gt;CANOpen에서는 기본적으로 메시지 인증 기능이 없으므로, MAC(Message Authentication Code)을 사용하여 메시지의 무결성을 검증하는 것이 중요합니다. 또한, CAN-FD와 함께 TLS 또는 DTLS 기반의 보안 프로토콜을 적용하여 데이터 암호화를 수행할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;2. 노드 인증 및 접근 제어&lt;/h4&gt;
&lt;p&gt;각 노드는 신뢰할 수 있는 인증을 거쳐 네트워크에 참여해야 합니다. 이를 위해 다음과 같은 접근 제어 기법을 활용할 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;X.509 인증서를 이용한 노드 인증&lt;/li&gt;
&lt;li&gt;CANOpen Object Dictionary에 보안 레벨을 추가하여 접근을 제어&lt;/li&gt;
&lt;li&gt;물리적 보안 강화 (예: 보안 부팅을 통한 펌웨어 보호)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. 보안 게이트웨이 및 방화벽 적용&lt;/h4&gt;
&lt;p&gt;CANOpen 네트워크를 외부 네트워크와 분리하고, 허용된 장치만 통신할 수 있도록 보안 게이트웨이 및 방화벽을 적용합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IDS/IPS(침입 탐지 및 방지 시스템) 적용&lt;/li&gt;
&lt;li&gt;CAN 네트워크 전용 방화벽을 사용하여 비정상적인 트래픽 차단&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;4. 펌웨어 보안 및 안전한 업데이트&lt;/h4&gt;
&lt;p&gt;펌웨어 업데이트 과정에서 악성 코드 삽입을 방지하기 위해, 다음과 같은 방안을 적용해야 합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;펌웨어 코드 서명 및 무결성 검사&lt;/li&gt;
&lt;li&gt;보안 부팅(Secure Boot) 메커니즘 적용&lt;/li&gt;
&lt;li&gt;OTA(Over-the-Air) 업데이트 시 암호화 및 인증 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;5. 네트워크 모니터링 및 이상 감지&lt;/h4&gt;
&lt;p&gt;실시간으로 CANOpen 네트워크의 이상 징후를 감지하는 시스템을 구축하여, 보안 위협을 신속히 탐지할 수 있도록 합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CAN 트래픽 분석 도구를 이용한 이상 패턴 탐지&lt;/li&gt;
&lt;li&gt;머신러닝을 활용한 이상 탐지 시스템 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;CANOpen 네트워크는 다양한 산업 분야에서 중요한 역할을 하지만, 보안에 취약할 수 있습니다. 따라서 암호화, 인증, 접근 제어, 펌웨어 보안 및 네트워크 모니터링을 통해 CANOpen 네트워크의 보안을 강화해야 합니다. 본 장에서 소개한 방안을 통해 보다 안전한 CANOpen 시스템을 구축할 수 있을 것입니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen Security</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/821</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-security1#entry821comment</comments>
      <pubDate>Sat, 23 Aug 2025 19:30:08 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen 보안 위협 및 공격 기법</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-security</link>
      <description>&lt;h2&gt;CANOpen 보안 및 안전&lt;/h2&gt;
&lt;p&gt;CANOpen 네트워크는 산업 자동화, 의료 기기, 교통 시스템 등 다양한 분야에서 중요한 역할을 합니다. 그러나 네트워크를 통한 데이터 전송이 증가함에 따라 보안과 안전에 대한 요구사항도 더욱 강화되고 있습니다. 특히, 산업용 네트워크 환경에서는 데이터 무결성, 인증, 접근 제어, 오류 검출 및 복구 등의 요소가 필수적으로 고려되어야 합니다.&lt;/p&gt;
&lt;p&gt;본 장에서는 CANOpen 네트워크에서 보안과 안전을 확보하는 방법에 대해 살펴봅니다. 먼저 CAN 프로토콜의 기본적인 보안 취약점을 분석하고, CANOpen에서 적용할 수 있는 보안 기법과 안전 메커니즘을 설명합니다. 또한, 보안 기능을 강화하기 위한 하드웨어 및 소프트웨어적 접근 방안을 다루며, 실제 산업 현장에서의 적용 사례를 통해 실질적인 활용 방안을 제시합니다.&lt;/p&gt;
&lt;p&gt;CANOpen의 보안 및 안전을 효과적으로 관리하기 위해서는 다양한 기술이 활용됩니다. 암호화 및 인증 기법을 이용한 데이터 보호, 오류 검출 및 수정 알고리즘, 보안 강화된 CANOpen 프로토콜 확장 등이 대표적인 예시입니다. 이를 통해 산업 환경에서 신뢰할 수 있는 네트워크를 구축할 수 있으며, 데이터 조작 및 무단 접근으로부터 시스템을 보호할 수 있습니다.&lt;/p&gt;
&lt;p&gt;이 장에서는 다음과 같은 주요 내용을 다룹니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CANOpen 네트워크의 보안 위협 분석&lt;/li&gt;
&lt;li&gt;CANOpen에서 적용할 수 있는 보안 기법&lt;/li&gt;
&lt;li&gt;암호화 및 인증 기술을 활용한 데이터 보호&lt;/li&gt;
&lt;li&gt;오류 검출 및 복구 메커니즘&lt;/li&gt;
&lt;li&gt;하드웨어 기반의 보안 강화 방안&lt;/li&gt;
&lt;li&gt;산업 환경에서의 보안 적용 사례&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이를 통해 CANOpen 네트워크의 보안성을 향상시키고, 신뢰할 수 있는 시스템을 구축하는 방법을 익힐 수 있습니다.&lt;/p&gt;
&lt;h2&gt;CANOpen 보안 위협 및 공격 기법&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;CANOpen은 산업 자동화, 의료 기기, 자동차 및 다양한 임베디드 시스템에서 널리 사용되는 네트워크 프로토콜입니다. 그러나 기존의 CAN (Controller Area Network) 기반 프로토콜과 마찬가지로 보안이 기본적으로 고려되지 않은 설계로 인해 다양한 보안 위협에 노출될 수 있습니다. 본 장에서는 CANOpen 시스템이 직면할 수 있는 주요 보안 위협 및 공격 기법을 분석하고, 이를 방어하기 위한 전략을 소개합니다.&lt;/p&gt;
&lt;h3&gt;CANOpen 네트워크의 주요 보안 위협&lt;/h3&gt;
&lt;h4&gt;데이터 스푸핑(Data Spoofing)&lt;/h4&gt;
&lt;p&gt;공격자가 CANOpen 네트워크에서 합법적인 노드처럼 가장하여 악의적인 데이터를 전송하는 공격 기법입니다. 이를 통해 중요한 데이터가 변조되거나 시스템 동작이 예기치 않게 변경될 수 있습니다.&lt;/p&gt;
&lt;h4&gt;중간자 공격(Man-in-the-Middle Attack)&lt;/h4&gt;
&lt;p&gt;CANOpen 네트워크에서 공격자가 두 노드 간의 통신을 가로채어 데이터를 변조하거나 재전송하는 방식으로 공격을 수행합니다. 이를 통해 인증되지 않은 명령을 삽입하거나 중요한 데이터를 탈취할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;재전송 공격(Replay Attack)&lt;/h4&gt;
&lt;p&gt;공격자가 네트워크에서 유효한 메시지를 캡처한 후 나중에 이를 다시 전송하는 방식으로 시스템을 속이는 공격입니다. 이를 통해 특정 동작을 반복 수행하거나 정상적인 인증 절차를 우회할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;서비스 거부 공격(Denial of Service, DoS)&lt;/h4&gt;
&lt;p&gt;공격자가 다량의 메시지를 네트워크에 주입하여 정상적인 노드 간의 통신을 방해하는 공격입니다. CANOpen 네트워크는 높은 실시간성을 요구하므로, 이런 공격이 발생할 경우 전체 시스템의 작동이 중단될 수 있습니다.&lt;/p&gt;
&lt;h4&gt;노드 ID 하이재킹(Node ID Hijacking)&lt;/h4&gt;
&lt;p&gt;공격자가 특정 CANOpen 장치의 Node ID를 가장하여 통신을 가로채고, 정당한 장치가 네트워크에서 동작하지 못하도록 방해하는 공격입니다.&lt;/p&gt;
&lt;h3&gt;CANOpen 보안 강화 기법&lt;/h3&gt;
&lt;h4&gt;메시지 인증 및 무결성 검증&lt;/h4&gt;
&lt;p&gt;HMAC(Hash-based Message Authentication Code) 또는 디지털 서명과 같은 기법을 활용하여 메시지의 출처를 인증하고, 데이터 변조를 방지할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;암호화 적용&lt;/h4&gt;
&lt;p&gt;CANOpen 메시지를 송수신할 때 AES 또는 기타 경량 암호화 알고리즘을 적용하여 데이터 보호를 강화할 수 있습니다. 특히 TLS와 유사한 보안 계층을 추가하여 통신의 기밀성을 확보할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;네트워크 모니터링 및 이상 탐지&lt;/h4&gt;
&lt;p&gt;이상 감지 시스템(IDS, Intrusion Detection System)을 활용하여 비정상적인 트래픽 패턴을 감지하고, 실시간으로 위협을 분석하여 대응할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;물리적 보안 강화&lt;/h4&gt;
&lt;p&gt;CANOpen 네트워크는 물리적인 공격에도 취약하므로, 네트워크 액세스를 제한하고 물리적인 보안 조치를 강화해야 합니다. 이를 위해 방화벽을 활용하거나, 외부 장치의 연결을 제한하는 정책을 적용할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;노드 ID 및 접근 제어 강화&lt;/h4&gt;
&lt;p&gt;각 노드의 ID를 안전하게 관리하고, 정당한 장치만 CANOpen 네트워크에 참여할 수 있도록 인증 절차를 강화하는 것이 중요합니다. 이를 위해 PKI(Public Key Infrastructure) 기반 인증 시스템을 도입할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;CANOpen 네트워크는 다양한 산업 환경에서 활용되지만, 기본적인 보안 기능이 부족하여 여러 공격에 취약할 수 있습니다. 따라서 데이터 인증, 암호화, 접근 제어, 네트워크 모니터링과 같은 보안 기법을 적극적으로 도입하여 보안을 강화하는 것이 필수적입니다. 향후 CANOpen의 보안 표준이 발전함에 따라 보다 안전한 네트워크 환경을 구축하는 방법도 지속적으로 연구되어야 합니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen Security</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/819</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-security#entry819comment</comments>
      <pubDate>Fri, 22 Aug 2025 20:25:27 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen 원격 모니터링 및 데이터 로깅</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-monitoring</link>
      <description>&lt;h2&gt;CANOpen 원격 모니터링 및 데이터 로깅&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;CANOpen 네트워크에서 원격 모니터링과 데이터 로깅은 장치 상태를 실시간으로 감시하고, 문제 발생 시 신속하게 대응할 수 있도록 합니다. 이를 통해 장치의 유지보수 및 장애 예방이 가능하며, 산업 자동화 및 IoT 환경에서 중요한 역할을 합니다.&lt;/p&gt;
&lt;p&gt;본 장에서는 STM32F429와 STM32CubeIDE 및 HAL을 활용하여 CANOpen 네트워크에서 원격 모니터링 및 데이터 로깅을 구현하는 방법을 다룹니다.&lt;/p&gt;
&lt;h3&gt;원격 모니터링 개념&lt;/h3&gt;
&lt;p&gt;원격 모니터링(Remote Monitoring)은 CANOpen 네트워크의 데이터를 외부 시스템에서 실시간으로 감시하는 기능을 의미합니다. 이를 통해 다음과 같은 기능을 수행할 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;장치 상태 및 센서 데이터 모니터링&lt;/li&gt;
&lt;li&gt;오류 감지 및 경보 전송&lt;/li&gt;
&lt;li&gt;실시간 데이터 시각화&lt;/li&gt;
&lt;li&gt;유지보수 일정 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;데이터 로깅 개념&lt;/h3&gt;
&lt;p&gt;데이터 로깅(Data Logging)은 CANOpen 네트워크에서 발생하는 데이터를 저장하여 분석하는 과정입니다. 이는 시스템 성능 평가, 문제 발생 시 원인 분석 및 장기적인 트렌드 파악에 유용합니다.&lt;/p&gt;
&lt;p&gt;데이터 로깅 시스템의 주요 기능은 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CAN 메시지 기록 및 저장&lt;/li&gt;
&lt;li&gt;데이터 압축 및 필터링&lt;/li&gt;
&lt;li&gt;장기적인 데이터 분석 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;원격 모니터링 시스템 구성&lt;/h3&gt;
&lt;p&gt;원격 모니터링 시스템은 다음과 같은 주요 구성 요소로 이루어집니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CANOpen 장치(STM32F429)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;센서 및 액추에이터 데이터 수집&lt;/li&gt;
&lt;li&gt;CAN 메시지 송수신&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;게이트웨이 장치(CAN-Ethernet, CAN-WiFi 모듈)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CAN 메시지를 TCP/IP 기반 네트워크로 변환&lt;/li&gt;
&lt;li&gt;클라우드 서버 또는 원격 데이터베이스와 연동&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;클라우드 서버 또는 로컬 모니터링 시스템&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;데이터 저장 및 시각화&lt;/li&gt;
&lt;li&gt;웹 대시보드 및 모바일 애플리케이션과 연동&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;STM32F429를 이용한 CANOpen 데이터 로깅 구현&lt;/h3&gt;
&lt;p&gt;STM32F429에서 CANOpen 데이터 로깅을 구현하기 위해 STM32CubeIDE와 HAL 라이브러리를 활용할 수 있습니다. 기본적인 구현 절차는 다음과 같습니다.&lt;/p&gt;
&lt;h4&gt;1. CANOpen 네트워크 설정&lt;/h4&gt;
&lt;p&gt;STM32CubeMX에서 CAN 인터페이스를 설정하고, CANOpen 스택을 구성합니다. 대표적인 CANOpen 스택으로 &lt;strong&gt;CANopenNode&lt;/strong&gt; 또는 &lt;strong&gt;CANFestival&lt;/strong&gt;을 사용할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;2. 데이터 수집 및 저장&lt;/h4&gt;
&lt;p&gt;CAN 메시지를 수신하고 데이터 로깅을 수행하는 예제 코드는 다음과 같습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;quot;stm32f4xx_hal.h&amp;quot;
#include &amp;quot;can.h&amp;quot;

void CAN_Receive_Message(void) {
    CAN_RxHeaderTypeDef RxHeader;
    uint8_t RxData[8];

    if (HAL_CAN_GetRxMessage(&amp;amp;hcan1, CAN_RX_FIFO0, &amp;amp;RxHeader, RxData) == HAL_OK) {
        // 수신된 데이터를 SD 카드 또는 플래시 메모리에 저장
        Log_CAN_Message(RxHeader, RxData);
    }
}

void Log_CAN_Message(CAN_RxHeaderTypeDef header, uint8_t *data) {
    // 데이터 저장 로직 (예: 파일 시스템, EEPROM, 클라우드 전송 등)
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3. 원격 전송을 위한 통신 모듈 연동&lt;/h4&gt;
&lt;p&gt;데이터를 원격으로 전송하기 위해 ESP8266 또는 Ethernet 모듈을 활용할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;void Send_Data_Remotely(uint8_t *data, uint16_t length) {
    // WiFi 또는 Ethernet을 사용하여 클라우드 서버로 데이터 전송
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;데이터 시각화 및 모니터링&lt;/h3&gt;
&lt;p&gt;수집된 데이터를 웹 대시보드에서 실시간으로 확인할 수 있도록, MQTT 또는 HTTP 프로토콜을 사용하여 데이터를 전송할 수 있습니다.&lt;/p&gt;
&lt;p&gt;예를 들어, MQTT를 이용하여 CAN 데이터 전송을 구현할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, rc):
    print(&amp;quot;Connected with result code &amp;quot; + str(rc))
    client.subscribe(&amp;quot;canopen/data&amp;quot;)

def on_message(client, userdata, msg):
    print(msg.topic+&amp;quot; &amp;quot;+str(msg.payload))

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(&amp;quot;mqtt.example.com&amp;quot;, 1883, 60)
client.loop_forever()&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;본 장에서는 STM32F429를 활용한 CANOpen 네트워크의 원격 모니터링 및 데이터 로깅 방법을 설명하였습니다. 이를 통해 산업 자동화 및 IoT 시스템에서 실시간 데이터 감시 및 분석이 가능하며, 유지보수 비용 절감과 성능 향상에 기여할 수 있습니다. 향후 이를 확장하여 AI 기반 예측 유지보수 시스템과 연동할 수도 있습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>canopen</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/817</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-monitoring#entry817comment</comments>
      <pubDate>Thu, 21 Aug 2025 19:50:49 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen over Ethernet (EtherCAN, CANOpen over TCP/IP)</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-ethernet</link>
      <description>&lt;h2&gt;CANOpen과 IoT 및 무선 통신&lt;/h2&gt;
&lt;p&gt;CANOpen은 산업 자동화 및 임베디드 시스템에서 널리 사용되는 프로토콜로, 주로 유선 통신 환경에서 안정적으로 동작하도록 설계되었습니다. 그러나 최근 IoT(사물인터넷) 기술의 발전과 함께 무선 통신을 활용한 CANOpen 네트워크 구축이 점점 더 중요해지고 있습니다. 이를 통해 기존 CANOpen 기반 시스템의 확장성을 높이고, 원격 모니터링 및 제어가 가능하도록 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;무선 통신 기술은 BLE(Bluetooth Low Energy), Wi-Fi, LoRa, Zigbee, Thread 등 다양한 방식으로 제공되며, 각각의 기술은 통신 거리, 데이터 전송 속도, 전력 소비 등의 특성에 따라 적절한 용도로 활용됩니다. 특히, CANOpen을 IoT 환경에서 활용하기 위해서는 게이트웨이 장치를 통해 CAN 버스를 무선 네트워크와 연결하는 방식이 일반적으로 사용됩니다.&lt;/p&gt;
&lt;p&gt;본 장에서는 CANOpen과 IoT 기술의 융합에 대한 개념을 설명하고, CANOpen 네트워크를 무선 환경에서 운영하는 방법을 다룹니다. 또한, STM32F429를 활용하여 CANOpen을 지원하는 무선 통신 시스템을 구축하는 실습을 진행하며, CANOpen 게이트웨이 및 브릿지 장치를 설계하는 방법을 소개합니다.&lt;/p&gt;
&lt;h2&gt;CANOpen over Ethernet (EtherCAN, CANOpen over TCP/IP)&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;CANOpen은 일반적으로 CAN(Controller Area Network) 버스를 통해 통신하는 프로토콜이지만, 최근에는 Ethernet을 통한 CANOpen 통신이 점점 중요해지고 있습니다. Ethernet을 통해 CANOpen을 구현하는 방식에는 EtherCAN과 CANOpen over TCP/IP 두 가지 주요 방식이 있습니다. 이를 통해 기존 CANOpen 네트워크를 확장하고, 더 빠른 데이터 전송 속도를 확보할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;EtherCAN&lt;/h3&gt;
&lt;p&gt;EtherCAN은 기존의 CAN 네트워크를 Ethernet 네트워크로 확장하기 위한 기술입니다. 일반적으로 EtherCAN 게이트웨이를 사용하여 CAN 메시지를 Ethernet 패킷으로 변환하여 전송합니다.&lt;/p&gt;
&lt;h4&gt;EtherCAN의 특징&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;CAN 네트워크와 Ethernet 네트워크 간의 브리지 역할 수행&lt;/li&gt;
&lt;li&gt;실시간성을 고려한 전송 방식 지원&lt;/li&gt;
&lt;li&gt;산업 자동화 및 스마트 팩토리에서 활용&lt;/li&gt;
&lt;li&gt;CAN 메시지 필터링 및 라우팅 기능 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;EtherCAN의 주요 활용 사례&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;산업 자동화&lt;/strong&gt;: 공장 내에서 CAN 기반 장치를 Ethernet으로 연결하여 중앙 제어 시스템과 연동 가능&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;자동차 및 운송 시스템&lt;/strong&gt;: 자동차 내 CAN 통신 데이터를 외부 분석 시스템으로 전송&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;의료 장비&lt;/strong&gt;: CAN 기반 의료 장비를 병원의 중앙 관리 시스템과 연동&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;CANOpen over TCP/IP&lt;/h3&gt;
&lt;p&gt;CANOpen over TCP/IP는 기존 CANOpen 프로토콜을 TCP/IP 네트워크를 통해 확장하는 방식입니다. 이는 물리적인 CAN 버스를 사용하지 않고도 CANOpen을 구현할 수 있도록 해줍니다.&lt;/p&gt;
&lt;h4&gt;CANOpen over TCP/IP의 특징&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;기존 CAN 버스를 사용하지 않고, Ethernet 네트워크에서 CANOpen을 구현&lt;/li&gt;
&lt;li&gt;물리적 거리 제한 없이 CANOpen 통신 가능&lt;/li&gt;
&lt;li&gt;기존 TCP/IP 네트워크와 통합하여 유연한 네트워크 아키텍처 구성&lt;/li&gt;
&lt;li&gt;클라우드 기반 모니터링 및 원격 제어 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;CANOpen over TCP/IP의 주요 활용 사례&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;원격 모니터링 및 제어&lt;/strong&gt;: 공장 내 장비의 상태를 원격으로 모니터링 및 조정 가능&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IoT 및 클라우드 통합&lt;/strong&gt;: IoT 장치에서 CANOpen 데이터를 수집하여 클라우드로 전송&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;다중 프로토콜 게이트웨이&lt;/strong&gt;: 다른 산업용 프로토콜(Modbus, OPC UA 등)과 통합하여 복합적인 자동화 시스템 구축&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;EtherCAN과 CANOpen over TCP/IP 비교&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;항목&lt;/th&gt;
&lt;th&gt;EtherCAN&lt;/th&gt;
&lt;th&gt;CANOpen over TCP/IP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;전송 방식&lt;/td&gt;
&lt;td&gt;CAN 메시지를 Ethernet 패킷으로 변환&lt;/td&gt;
&lt;td&gt;TCP/IP를 통해 CANOpen 데이터 전송&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;실시간성&lt;/td&gt;
&lt;td&gt;높은 실시간성 보장&lt;/td&gt;
&lt;td&gt;네트워크 지연이 있을 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;거리 제한&lt;/td&gt;
&lt;td&gt;Ethernet 네트워크 범위 내&lt;/td&gt;
&lt;td&gt;글로벌 네트워크 확장 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;주요 활용 분야&lt;/td&gt;
&lt;td&gt;산업 자동화, 차량 네트워크&lt;/td&gt;
&lt;td&gt;클라우드 기반 IoT, 원격 제어&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;STM32F429를 활용한 CAN 메시지의 Ethernet 패킷 변환 및 전송 구현&lt;/h3&gt;
&lt;p&gt;STM32F429는 강력한 Cortex-M4 기반 MCU로, Ethernet과 CAN을 모두 지원합니다. 이를 활용하여 CAN 메시지를 Ethernet 패킷으로 변환하여 전송하는 방법을 구현할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;필요 구성 요소&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;STM32F429 개발 보드&lt;/li&gt;
&lt;li&gt;STM32CubeIDE 및 HAL 라이브러리&lt;/li&gt;
&lt;li&gt;Ethernet PHY 모듈 (LAN8720 등)&lt;/li&gt;
&lt;li&gt;CAN 트랜시버 (MCP2551 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;구현 절차&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;STM32CubeMX를 이용한 프로젝트 생성&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Ethernet 및 CAN 인터페이스 활성화&lt;/li&gt;
&lt;li&gt;LWIP 스택을 이용하여 TCP/IP 프로토콜 지원&lt;/li&gt;
&lt;li&gt;CAN 드라이버 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ethernet 및 CAN 초기화 코드 작성&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;HAL 라이브러리를 이용하여 Ethernet 및 CAN 초기화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CAN 메시지를 Ethernet 패킷으로 변환 후 전송&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;CAN 메시지를 UDP 패킷으로 변환하여 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TCP/IP 기반 CANOpen 프로토콜 처리&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;CANOpen 데이터 오브젝트를 TCP/IP로 송수신하는 코드 작성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;예제 코드 (CAN 메시지를 UDP 패킷으로 변환 후 Ethernet 전송)&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;quot;main.h&amp;quot;
#include &amp;quot;lwip.h&amp;quot;
#include &amp;quot;can.h&amp;quot;
#include &amp;quot;ethernetif.h&amp;quot;
#include &amp;quot;udp.h&amp;quot;

CAN_HandleTypeDef hcan;
ETH_HandleTypeDef heth;
struct udp_pcb *udp_conn;

void SystemClock_Config(void);
void MX_GPIO_Init(void);
void MX_CAN_Init(void);
void MX_ETH_Init(void);
void send_can_over_udp(uint8_t *data, uint16_t len);

int main(void) {
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();
    MX_CAN_Init();
    MX_ETH_Init();
    MX_LWIP_Init();

    udp_conn = udp_new();
    ip_addr_t dest_ip;
    IP4_ADDR(&amp;amp;dest_ip, 192, 168, 1, 100);
    udp_connect(udp_conn, &amp;amp;dest_ip, 5000);

    CAN_TxHeaderTypeDef txHeader;
    uint32_t txMailbox;
    uint8_t txData[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};

    txHeader.DLC = 8;
    txHeader.StdId = 0x321;
    txHeader.IDE = CAN_ID_STD;
    txHeader.RTR = CAN_RTR_DATA;

    while (1) {
        if (HAL_CAN_AddTxMessage(&amp;amp;hcan, &amp;amp;txHeader, txData, &amp;amp;txMailbox) == HAL_OK) {
            send_can_over_udp(txData, sizeof(txData));
        }
        HAL_Delay(1000);
    }
}

void send_can_over_udp(uint8_t *data, uint16_t len) {
    struct pbuf *packet = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM);
    if (packet != NULL) {
        memcpy(packet-&amp;gt;payload, data, len);
        udp_send(udp_conn, packet);
        pbuf_free(packet);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;EtherCAN과 CANOpen over TCP/IP는 기존 CANOpen 네트워크를 확장하고 보다 유연한 네트워크 구성을 가능하게 하는 강력한 솔루션입니다. STM32F429를 활용하여 CAN 메시지를 Ethernet 패킷으로 변환하여 전송하면, 산업 자동화, IoT, 원격 제어 등 다양한 분야에서 활용할 수 있습니다. 이를 통해 CANOpen 네트워크의 확장성과 실용성을 더욱 극대화할 수 있습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen over Ethernet</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/815</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-ethernet#entry815comment</comments>
      <pubDate>Wed, 20 Aug 2025 22:09:29 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen 성능 최적화</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-optimization</link>
      <description>&lt;h2&gt;CANOpen 성능 최적화&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;실시간 시스템에서 CANOpen을 활용할 때 성능 최적화는 필수적인 요소입니다. CANOpen 네트워크의 응답 속도와 데이터 전송 효율성을 향상시키기 위해 다양한 기법이 활용됩니다. 본 장에서는 CANOpen의 성능을 최적화하는 방법을 다루며, 주요 최적화 기법과 실무 적용 사례를 설명합니다.&lt;/p&gt;
&lt;h3&gt;CANOpen 성능에 영향을 미치는 요인&lt;/h3&gt;
&lt;p&gt;CANOpen 네트워크의 성능은 여러 요인에 의해 결정됩니다. 주요 요소는 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;통신 속도(baud rate):&lt;/strong&gt; CAN 버스의 속도가 높을수록 데이터 전송 시간이 줄어듭니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PDO 매핑 최적화:&lt;/strong&gt; 불필요한 데이터 전송을 줄이고 중요한 데이터만 전송하여 효율성을 높입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;동기화 및 타이밍 조정:&lt;/strong&gt; 실시간성을 유지하기 위해 SDO 및 PDO 전송의 주기를 조정합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CAN 버스 부하 관리:&lt;/strong&gt; 메시지 충돌을 방지하고 네트워크 부하를 줄이기 위한 전략이 필요합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;하드웨어 가속 기능 활용:&lt;/strong&gt; STM32F429 등의 MCU에서 제공하는 CAN 필터링 및 DMA(Direct Memory Access) 활용으로 성능을 향상시킬 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;성능 최적화를 위한 주요 기법&lt;/h3&gt;
&lt;h4&gt;통신 속도 최적화&lt;/h4&gt;
&lt;p&gt;CANOpen 네트워크의 통신 속도를 설정할 때, 시스템의 특성과 네트워크 환경을 고려해야 합니다. 일반적인 속도 설정은 다음과 같습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Baud Rate (kbps)&lt;/th&gt;
&lt;th&gt;최대 케이블 길이 (m)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;td&gt;250&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;125&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;1000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;네트워크의 크기와 사용 환경에 따라 적절한 속도를 설정하여 최적의 성능을 유지해야 합니다.&lt;/p&gt;
&lt;h4&gt;PDO 최적화&lt;/h4&gt;
&lt;p&gt;PDO(Process Data Object)는 실시간 데이터 전송을 위한 CANOpen의 핵심 요소입니다. 성능을 최적화하기 위해 다음과 같은 방법을 활용할 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;불필요한 PDO 전송 최소화:&lt;/strong&gt; 필요한 데이터만 전송하여 네트워크 부하를 줄입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PDO 그룹화:&lt;/strong&gt; 관련된 데이터를 하나의 PDO로 묶어 전송 횟수를 줄입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;이벤트 기반 전송 활용:&lt;/strong&gt; 변화가 있을 때만 데이터를 전송하여 불필요한 트래픽을 줄입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SYNC 메시지 최적화:&lt;/strong&gt; 주기적 PDO 전송의 타이밍을 조정하여 네트워크 충돌을 방지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;SDO 성능 개선&lt;/h4&gt;
&lt;p&gt;SDO(Service Data Object)는 설정 및 비주기적 데이터 전송에 사용됩니다. SDO를 최적화하기 위한 방법은 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;블록 전송(Block Transfer) 사용:&lt;/strong&gt; 다량의 데이터를 전송할 때 블록 모드를 활용하여 속도를 높입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SDO 서버 분산 배치:&lt;/strong&gt; 여러 SDO 서버를 구성하여 특정 노드에 부하가 집중되지 않도록 합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SDO 전송 주기 최적화:&lt;/strong&gt; 설정 데이터를 효율적으로 업데이트하도록 SDO 전송을 적절히 조정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;하드웨어 최적화 기법&lt;/h4&gt;
&lt;p&gt;STM32F429 MCU를 사용할 경우, 하드웨어 최적화를 통해 CANOpen 성능을 더욱 향상시킬 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CAN 필터 설정:&lt;/strong&gt; 불필요한 메시지를 필터링하여 CPU 부하를 줄입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DMA 활용:&lt;/strong&gt; CAN 메시지를 직접 메모리로 전송하여 CPU 개입을 최소화합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Low-Power 모드 활용:&lt;/strong&gt; 저전력 상태에서도 CAN 메시지를 수신할 수 있도록 설정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;실무 적용 사례&lt;/h3&gt;
&lt;h4&gt;사례 1: 산업용 로봇의 CANOpen 최적화&lt;/h4&gt;
&lt;p&gt;산업용 로봇 시스템에서 CANOpen을 활용할 때, 실시간 응답 속도가 중요합니다. 최적화된 PDO 매핑과 이벤트 기반 전송을 통해 네트워크 부하를 줄이고, CAN 필터를 활용하여 불필요한 데이터 수신을 차단함으로써 성능을 향상시켰습니다.&lt;/p&gt;
&lt;h4&gt;사례 2: 스마트 팩토리의 실시간 모니터링&lt;/h4&gt;
&lt;p&gt;스마트 팩토리에서는 다수의 센서가 CANOpen 네트워크를 통해 데이터를 전송합니다. PDO 그룹화와 동기화 메시지 최적화를 통해 네트워크 부하를 감소시키고, 중요한 데이터가 실시간으로 전송되도록 조정하였습니다.&lt;/p&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;실시간 시스템에서 CANOpen의 성능 최적화는 네트워크의 응답 속도와 데이터 처리 효율성을 높이는 중요한 과정입니다. 통신 속도 조정, PDO 최적화, SDO 성능 개선, 하드웨어 가속 기능 활용 등의 기법을 적용하여 CANOpen을 보다 효율적으로 운영할 수 있습니다. 실무에서의 다양한 적용 사례를 참고하여 각 시스템에 맞는 최적화 방법을 선택하는 것이 중요합니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpem Optimization</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/813</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-optimization#entry813comment</comments>
      <pubDate>Tue, 19 Aug 2025 19:49:02 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen 기반의 모터 제어 (CiA 402)</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-motor</link>
      <description>&lt;h2&gt;CANOpen 기반의 모터 제어 (CiA 402)&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;CiA 402(IEC 61800-7-201) 프로파일은 CANOpen을 기반으로 서보 모터 및 인버터 등의 모터 제어 시스템을 표준화하는 데 사용됩니다. 이 프로파일은 다양한 모드에서 모터를 제어할 수 있도록 설계되었으며, 이를 통해 산업 자동화 시스템에서 효율적인 모터 구동을 가능하게 합니다.&lt;/p&gt;
&lt;p&gt;본 장에서는 CiA 402 프로파일의 기본 개념과 주요 기능을 소개하고, STM32F429와 STM32CubeIDE 및 HAL을 활용하여 CiA 402 기반의 모터 제어를 구현하는 방법을 살펴보겠습니다.&lt;/p&gt;
&lt;h3&gt;CiA 402의 주요 개념&lt;/h3&gt;
&lt;p&gt;CiA 402는 모터 제어를 위한 상태 기계(state machine)를 정의하며, 다음과 같은 주요 동작 모드를 포함합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Profile Position Mode&lt;/strong&gt;: 목표 위치까지 모터를 이동시키는 모드&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Profile Velocity Mode&lt;/strong&gt;: 지정된 속도로 모터를 회전시키는 모드&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Profile Torque Mode&lt;/strong&gt;: 특정 토크 값을 유지하며 제어하는 모드&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Homing Mode&lt;/strong&gt;: 모터의 기준점(Zero Position)을 찾는 모드&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cyclic Synchronous Position (CSP) Mode&lt;/strong&gt;: 실시간으로 목표 위치를 조정하는 모드&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cyclic Synchronous Velocity (CSV) Mode&lt;/strong&gt;: 실시간 속도 제어 모드&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cyclic Synchronous Torque (CST) Mode&lt;/strong&gt;: 실시간 토크 제어 모드&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CiA 402 프로파일을 적용한 장치는 위와 같은 다양한 모드를 활용하여 정밀한 모터 제어를 수행할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;CiA 402 상태 기계&lt;/h3&gt;
&lt;p&gt;CiA 402 상태 기계는 모터 드라이브의 상태를 관리하며, 아래와 같은 주요 상태를 포함합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Not Ready to Switch On&lt;/strong&gt;: 초기화되지 않은 상태&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Switch On Disabled&lt;/strong&gt;: 하드웨어 오류 등이 발생하여 실행할 수 없는 상태&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ready to Switch On&lt;/strong&gt;: 구동 준비가 완료된 상태&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Switched On&lt;/strong&gt;: 동작이 가능하지만 아직 활성화되지 않은 상태&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operation Enabled&lt;/strong&gt;: 정상적으로 모터가 작동할 수 있는 상태&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fault&lt;/strong&gt;: 오류가 발생한 상태&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이러한 상태 전이는 &lt;strong&gt;Control Word(제어 워드)&lt;/strong&gt; 및 &lt;strong&gt;Status Word(상태 워드)&lt;/strong&gt;를 이용하여 제어됩니다.&lt;/p&gt;
&lt;h3&gt;STM32에서 CiA 402 기반 모터 제어 구현&lt;/h3&gt;
&lt;p&gt;STM32F429와 STM32CubeIDE, HAL 라이브러리를 활용하여 CiA 402 기반의 모터 제어를 구현하는 방법을 설명하겠습니다.&lt;/p&gt;
&lt;h4&gt;1. 하드웨어 구성&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;STM32F429 개발 보드&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CAN 트랜시버 (MCP2551 또는 TJA1050 등)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BLDC 또는 서보 모터&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CANOpen 지원 모터 드라이버&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. 소프트웨어 설정&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;STM32CubeMX에서 CAN 설정&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;CAN Peripheral 활성화&lt;/li&gt;
&lt;li&gt;CAN 필터 및 Baudrate 설정 (1Mbps 추천)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CANOpen 스택 적용&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CANopenNode&lt;/code&gt; 또는 &lt;code&gt;CANFestival&lt;/code&gt; 등의 오픈소스 CANOpen 스택을 활용하여 통신 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CiA 402 제어 코드 작성&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Control Word를 이용한 상태 전이 관리&lt;/li&gt;
&lt;li&gt;PDO를 통한 실시간 데이터 전송&lt;/li&gt;
&lt;li&gt;SDO를 활용한 매개변수 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;3. 예제 코드 (HAL 기반 CANOpen 제어)&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;void sendCANMessage(uint16_t cob_id, uint8_t* data, uint8_t length) {
    CAN_TxHeaderTypeDef txHeader;
    uint32_t txMailbox;

    txHeader.StdId = cob_id;
    txHeader.IDE = CAN_ID_STD;
    txHeader.RTR = CAN_RTR_DATA;
    txHeader.DLC = length;

    HAL_CAN_AddTxMessage(&amp;amp;hcan1, &amp;amp;txHeader, data, &amp;amp;txMailbox);
}

void setMotorControlWord(uint16_t controlWord) {
    uint8_t data[2];
    data[0] = controlWord &amp;amp; 0xFF;
    data[1] = (controlWord &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;
    sendCANMessage(0x6040, data, 2);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;CiA 402는 다양한 모터 제어 기능을 제공하며, CANOpen을 기반으로 하는 산업 자동화 시스템에서 널리 사용됩니다. STM32F429를 이용하여 CANOpen 기반 모터 제어를 구현하면, 효율적인 실시간 제어 및 정밀한 모션 컨트롤을 수행할 수 있습니다. 이를 위해 CANOpen 스택과 HAL 라이브러리를 조합하여 구현하는 것이 핵심이며, 상태 기계 및 제어 워드를 정확하게 이해하는 것이 중요합니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen Motor</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/811</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-motor#entry811comment</comments>
      <pubDate>Mon, 18 Aug 2025 19:48:10 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen 활용 산업용 로봇 및 PLC</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-robot</link>
      <description>&lt;h2&gt;CANOpen 활용 산업용 로봇 및 PLC&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;CANOpen은 산업 자동화에서 널리 사용되는 프로토콜로, 산업용 로봇과 프로그래머블 로직 컨트롤러(PLC)와 같은 장치 간의 효율적인 통신을 지원합니다. 이 장에서는 CANOpen이 산업용 로봇과 PLC 시스템에서 어떻게 활용되는지 설명하고, 이를 최적화하는 방법을 다룹니다.&lt;/p&gt;
&lt;h3&gt;산업용 로봇에서의 CANOpen 활용&lt;/h3&gt;
&lt;p&gt;산업용 로봇은 정밀한 동작을 수행하기 위해 다수의 서보 모터와 센서를 포함하며, 이들 간의 신뢰성 높은 실시간 통신이 필수적입니다. CANOpen은 이러한 요구사항을 충족하기 위해 다음과 같은 방식으로 활용됩니다.&lt;/p&gt;
&lt;h4&gt;서보 모터 및 드라이브 제어&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;CANOpen의 &lt;strong&gt;PDO(프로세스 데이터 객체)&lt;/strong&gt;를 이용하여 실시간으로 모터 속도, 위치 및 토크를 제어할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SYNC(동기화) 메시지&lt;/strong&gt;를 활용하여 다축 제어에서 정밀한 동기화를 유지할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EMCY(긴급 메시지) 프로토콜&lt;/strong&gt;을 통해 오류 발생 시 즉각적인 대응이 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;센서 및 액추에이터 통합&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;로봇의 위치 센서, 힘 센서 등의 데이터를 CANOpen 네트워크를 통해 실시간으로 PLC나 상위 컨트롤러에 전달할 수 있습니다.&lt;/li&gt;
&lt;li&gt;액추에이터의 동작 상태를 모니터링하고, 필요 시 피드백 루프를 통해 자동 보정이 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;PLC에서의 CANOpen 활용&lt;/h3&gt;
&lt;p&gt;PLC는 산업 자동화에서 핵심적인 역할을 하며, 다양한 장치와의 통신을 원활하게 하기 위해 CANOpen을 지원합니다. CANOpen을 활용하면 다음과 같은 장점을 얻을 수 있습니다.&lt;/p&gt;
&lt;h4&gt;다수의 장치 통합 및 제어&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;CANOpen의 &lt;strong&gt;NMT(네트워크 관리 프로토콜)&lt;/strong&gt;을 사용하여 네트워크 내 여러 장치를 효과적으로 관리할 수 있습니다.&lt;/li&gt;
&lt;li&gt;각 장치의 &lt;strong&gt;EDS(Electronic Data Sheet)&lt;/strong&gt;를 이용하여 손쉽게 설정하고, 파라미터를 구성할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;모듈형 자동화 시스템 구축&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;모듈형 자동화 시스템에서 개별 모듈(예: 센서 모듈, 모터 드라이브 모듈) 간의 통신을 CANOpen 네트워크로 구성하면 배선 복잡도를 줄이고 유지보수를 용이하게 할 수 있습니다.&lt;/li&gt;
&lt;li&gt;확장성이 뛰어나므로, 필요에 따라 장비를 추가하거나 변경하기 용이합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;CANOpen 최적화 및 성능 향상 기법&lt;/h3&gt;
&lt;p&gt;산업용 로봇과 PLC 시스템에서 CANOpen을 효율적으로 활용하기 위해서는 최적화가 필요합니다. 다음은 주요 최적화 기법입니다.&lt;/p&gt;
&lt;h4&gt;통신 지연 최소화&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PDO 매핑을 최적화&lt;/strong&gt;하여 필수 데이터만을 전송하고, 불필요한 통신을 줄입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SYNC 메시지 주기를 조정&lt;/strong&gt;하여 네트워크 부하를 관리하고 실시간 성능을 유지합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;에러 핸들링 및 네트워크 신뢰성 강화&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;EMCY 메시지 및 오류 관리 메커니즘&lt;/strong&gt;을 적극 활용하여 네트워크 장애 발생 시 빠르게 대응할 수 있도록 합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Heartbeat 및 Node Guarding&lt;/strong&gt; 기능을 이용하여 장치의 상태를 지속적으로 모니터링합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;실시간 제어 성능 향상&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CANOpen Manager를 활용한 동적 네트워크 관리&lt;/strong&gt;를 통해 장치 추가 및 제거 시에도 안정적인 네트워크 운영이 가능합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;시간 임계 작업(Time-Critical Tasks)에 대한 우선순위 설정&lt;/strong&gt;을 적용하여 실시간성이 요구되는 작업을 우선적으로 처리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;산업용 로봇 및 PLC 시스템에서 CANOpen은 필수적인 통신 프로토콜로 자리 잡고 있으며, 이를 적절히 활용하면 신뢰성 높은 실시간 제어 및 시스템 확장성을 확보할 수 있습니다. 본 장에서 소개한 최적화 기법을 적용하면, 보다 효율적이고 안정적인 CANOpen 네트워크를 구축할 수 있습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen PLC</category>
      <category>CANOpen Robot</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/809</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-robot#entry809comment</comments>
      <pubDate>Sun, 17 Aug 2025 19:16:56 +0900</pubDate>
    </item>
    <item>
      <title>CANopen PDO 매핑 완벽 가이드: 실시간 데이터 설정 및 최적화 기법</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-pdo-mapping</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Gemini_Generated_Image_h30i51h30i51h30i.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Yzmyo/dJMcadIxCug/V5x0AJsm8ZxHrfag1tJZ70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Yzmyo/dJMcadIxCug/V5x0AJsm8ZxHrfag1tJZ70/img.png&quot; data-alt=&quot;Gemini AI 생성 이미지입니다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Yzmyo/dJMcadIxCug/V5x0AJsm8ZxHrfag1tJZ70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYzmyo%2FdJMcadIxCug%2FV5x0AJsm8ZxHrfag1tJZ70%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;369&quot; height=&quot;369&quot; data-filename=&quot;Gemini_Generated_Image_h30i51h30i51h30i.png&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;1024&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Gemini AI 생성 이미지입니다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PDO (Process Data Object) 개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PDO(Process Data Object)는 CANOpen 네트워크에서 실시간 데이터를 빠르게 전송하기 위한 메시지입니다. CANOpen에서 사용되는 주요 통신 방식 중 하나이며, 데이터를 효율적으로 전송할 수 있도록 설계되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PDO는 크게 두 가지 유형이 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;TPDO (Transmit PDO)&lt;/b&gt;: 데이터를 송신하는 PDO&lt;/li&gt;
&lt;li&gt;&lt;b&gt;RPDO (Receive PDO)&lt;/b&gt;: 데이터를 수신하는 PDO&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 PDO는 미리 정의된 데이터 매핑을 통해 특정 Object Dictionary(OD) 항목과 연결됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PDO Mapping 개념&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PDO Mapping은 특정 OD 항목을 TPDO 또는 RPDO에 할당하는 과정입니다. 이를 통해 장치는 미리 설정된 데이터 구조를 기반으로 신속하게 데이터를 송수신할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PDO Mapping에는 정적(Static)과 동적(Dynamic) 방식이 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정적 매핑(Static Mapping)&lt;/b&gt;: 미리 정의된 PDO Mapping으로, 변경이 불가능한 방식입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동적 매핑(Dynamic Mapping)&lt;/b&gt;: 네트워크 실행 중에 PDO의 데이터를 재구성할 수 있는 방식입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PDO Mapping을 구성하려면 Object Dictionary의 다음 항목을 활용해야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;0x1A00 ~ 0x1A7F&lt;/b&gt;: TPDO Mapping 항목&lt;/li&gt;
&lt;li&gt;&lt;b&gt;0x1600 ~ 0x167F&lt;/b&gt;: RPDO Mapping 항목&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 Mapping 항목에는 특정 OD 엔트리를 추가하여 PDO 데이터를 구성할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PDO Mapping 설정 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PDO Mapping 설정을 위해 Object Dictionary에 다음과 같은 항목을 추가합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;PDO 매핑 활성화 비활성화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PDO 매핑을 변경하기 전에 해당 PDO를 비활성화해야 합니다.&lt;/li&gt;
&lt;li&gt;TPDO 및 RPDO의 &lt;b&gt;sub-index 0&lt;/b&gt;을 &lt;code&gt;0x00&lt;/code&gt;으로 설정하여 매핑을 변경할 준비를 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;uint8_t disable_pdo_mapping = 0x00;
CO_SDO_write(0x1A00, 0x00, &amp;amp;disable_pdo_mapping, sizeof(disable_pdo_mapping));&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;매핑할 OD 항목 추가&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, TPDO에 0x6000 (디지털 입력)과 0x6200 (아날로그 입력) 항목을 매핑하려면 다음과 같이 설정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;uint32_t mapping_entry1 = 0x60000108;  // Index 0x6000, Sub-index 0x01, 8bit 데이터
uint32_t mapping_entry2 = 0x62000110;  // Index 0x6200, Sub-index 0x01, 16bit 데이터

CO_SDO_write(0x1A00, 0x01, &amp;amp;mapping_entry1, sizeof(mapping_entry1));
CO_SDO_write(0x1A00, 0x02, &amp;amp;mapping_entry2, sizeof(mapping_entry2));&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;매핑 활성화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설정이 완료되면, TPDO 또는 RPDO 매핑을 다시 활성화합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;uint8_t enable_pdo_mapping = 0x02; // 매핑된 엔트리 개수
CO_SDO_write(0x1A00, 0x00, &amp;amp;enable_pdo_mapping, sizeof(enable_pdo_mapping));&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PDO 최적화 기법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;효율적인 PDO 통신을 위해 몇 가지 최적화 기법을 적용할 수 있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;데이터 패킹 최적화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PDO 데이터는 최대 8바이트까지 포함할 수 있으므로, 불필요한 패딩을 줄이고 데이터를 최적화하여 매핑하는 것이 중요합니다.&lt;/li&gt;
&lt;li&gt;1비트 또는 8비트 단위 데이터를 적절히 배치하여 데이터 공간을 효율적으로 활용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;통신 주기 및 이벤트 트리거 조정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필요하지 않은 주기적 PDO 전송을 줄이고, 이벤트 기반 전송을 활성화하여 네트워크 부하를 줄입니다.&lt;/li&gt;
&lt;li&gt;예를 들어, 디지털 입력 값이 변경될 때만 TPDO를 전송하도록 설정할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;uint8_t event_triggered_mode = 0xFE;  // 변경 시 전송 모드
CO_SDO_write(0x1800, 0x02, &amp;amp;event_triggered_mode, sizeof(event_triggered_mode));&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비사용 PDO 비활성화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필요하지 않은 PDO는 비활성화하여 불필요한 CAN 메시지 트래픽을 줄입니다.&lt;/li&gt;
&lt;li&gt;사용되지 않는 RPDO 또는 TPDO 항목을 삭제하여 효율성을 높입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PDO 전송 속도 조정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;높은 주파수로 송신되는 TPDO는 적절한 주기로 설정하여 네트워크 대역폭을 절약합니다.&lt;/li&gt;
&lt;li&gt;주기적 송신이 필요한 경우 최소한의 주기를 설정하여 CPU 및 버스 로드를 줄입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PDO Mapping은 CANOpen 네트워크에서 빠르고 효율적인 데이터 전송을 위해 필수적인 요소입니다. 적절한 매핑 설정과 최적화 기법을 적용하면 네트워크 성능을 극대화하고 불필요한 부하를 줄일 수 있습니다. 특히, 이벤트 기반 전송과 데이터 패킹을 활용하면 더욱 효율적인 PDO 통신을 구현할 수 있습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CAN Bus: Protocol &amp;amp; Physical Layer</category>
      <category>canopen pdo</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/807</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-pdo-mapping#entry807comment</comments>
      <pubDate>Sat, 16 Aug 2025 15:29:41 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen NMT 명령을 통한 노드 제어</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-nmt-node</link>
      <description>&lt;h2&gt;CANOpen NMT 명령을 통한 노드 제어&lt;/h2&gt;
&lt;h3&gt;NMT (Network Management) 개요&lt;/h3&gt;
&lt;p&gt;NMT(Network Management)는 CANOpen 네트워크에서 노드를 관리하는 중요한 기능입니다. NMT 명령을 통해 노드의 상태를 변경하고, 네트워크의 정상적인 동작을 유지할 수 있습니다. &lt;/p&gt;
&lt;p&gt;CANOpen에서는 각 노드가 특정 상태를 가지며, 마스터 디바이스는 NMT 명령을 사용하여 슬레이브 노드의 상태를 전환할 수 있습니다. 기본적인 NMT 상태는 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Initialization&lt;/strong&gt;: 노드가 초기화되는 상태&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-Operational&lt;/strong&gt;: 일부 CANOpen 서비스(SDO, NMT 등)를 사용할 수 있는 상태&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operational&lt;/strong&gt;: 모든 CANOpen 서비스(PDO 포함)를 사용할 수 있는 상태&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stopped&lt;/strong&gt;: 노드가 네트워크에서 중단된 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;NMT 명령어 형식&lt;/h3&gt;
&lt;p&gt;NMT 명령은 CAN ID 0x000에 전송되며, 데이터 길이는 2바이트로 구성됩니다. 첫 번째 바이트는 명령을 의미하며, 두 번째 바이트는 대상 노드 ID를 나타냅니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;바이트&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;1바이트&lt;/td&gt;
&lt;td&gt;NMT 명령 코드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2바이트&lt;/td&gt;
&lt;td&gt;노드 ID (0은 전체 노드 대상으로 브로드캐스트)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;대표적인 NMT 명령 코드는 다음과 같습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;NMT 명령 코드&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;0x01&lt;/td&gt;
&lt;td&gt;Operational 모드로 전환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x02&lt;/td&gt;
&lt;td&gt;Stopped 모드로 전환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x80&lt;/td&gt;
&lt;td&gt;Pre-Operational 모드로 전환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x81&lt;/td&gt;
&lt;td&gt;Reset Node (전체 리셋)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x82&lt;/td&gt;
&lt;td&gt;Reset Communication (통신 스택만 리셋)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;STM32에서 NMT 명령 전송하기&lt;/h3&gt;
&lt;p&gt;STM32F429를 사용하여 CANOpen 네트워크에서 NMT 명령을 전송하려면, CAN 통신을 설정한 후 NMT 메시지를 구성하여 전송해야 합니다. 아래 예제 코드는 HAL 라이브러리를 이용하여 NMT 명령을 전송하는 방법을 보여줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;quot;stm32f4xx_hal.h&amp;quot;

extern CAN_HandleTypeDef hcan1;

void send_nmt_command(uint8_t command, uint8_t node_id) {
    CAN_TxHeaderTypeDef txHeader;
    uint8_t txData[2];
    uint32_t txMailbox;

    txHeader.StdId = 0x000; // NMT 명령어의 CAN ID
    txHeader.RTR = CAN_RTR_DATA;
    txHeader.IDE = CAN_ID_STD;
    txHeader.DLC = 2;

    txData[0] = command;
    txData[1] = node_id;

    if (HAL_CAN_AddTxMessage(&amp;amp;hcan1, &amp;amp;txHeader, txData, &amp;amp;txMailbox) != HAL_OK) {
        // 오류 처리
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;NMT 명령 활용 예제&lt;/h3&gt;
&lt;p&gt;다음 예제는 특정 노드를 Operational 모드로 변경하는 코드입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;send_nmt_command(0x01, 0x02); // 노드 ID 2를 Operational 모드로 전환&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;네트워크 내 모든 노드를 Pre-Operational 모드로 변경하려면 다음과 같이 브로드캐스트 ID(0x00)를 사용합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;send_nmt_command(0x80, 0x00); // 모든 노드를 Pre-Operational 모드로 전환&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;NMT 상태 확인&lt;/h3&gt;
&lt;p&gt;NMT 명령을 전송한 후 노드의 상태를 확인하려면, 각 노드가 주기적으로 자신의 상태를 보고하도록 설정할 수 있습니다. 상태 보고는 Heartbeat 또는 Node Guarding 기능을 통해 수행됩니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Heartbeat&lt;/strong&gt;: 노드가 자신의 상태를 정기적으로 CAN 버스로 전송 (ID: 0x700 + 노드 ID)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Node Guarding&lt;/strong&gt;: 마스터가 슬레이브 노드의 상태를 질의하고 응답을 확인하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;예를 들어, Heartbeat 메시지를 확인하면 노드가 현재 어떤 상태인지 알 수 있습니다. 일반적으로 Heartbeat 메시지는 다음과 같은 형식으로 전송됩니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;바이트&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;1바이트&lt;/td&gt;
&lt;td&gt;현재 NMT 상태&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;NMT 상태 값 예제:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;상태 값&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;0x00&lt;/td&gt;
&lt;td&gt;Boot-Up (부팅 완료)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x04&lt;/td&gt;
&lt;td&gt;Stopped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x05&lt;/td&gt;
&lt;td&gt;Operational&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x7F&lt;/td&gt;
&lt;td&gt;Pre-Operational&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;STM32에서 CAN 인터럽트를 활용하여 Heartbeat 메시지를 수신할 수 있도록 설정할 수도 있습니다.&lt;/p&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;NMT 명령을 활용하면 CANOpen 네트워크에서 각 노드의 상태를 제어하고, 네트워크의 정상적인 동작을 유지할 수 있습니다. STM32F429와 HAL을 이용하면 손쉽게 NMT 명령을 전송하고, 네트워크 상태를 모니터링할 수 있습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen NMT</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/805</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-nmt-node#entry805comment</comments>
      <pubDate>Fri, 15 Aug 2025 20:26:39 +0900</pubDate>
    </item>
    <item>
      <title>CANopen NMT 명령을 통한 노드 제어</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-nmt-1</link>
      <description>&lt;h2&gt;CANopen NMT 명령을 통한 노드 제어&lt;/h2&gt;
&lt;h3&gt;NMT (Network Management) 개요&lt;/h3&gt;
&lt;p&gt;NMT(Network Management)는 CANOpen 네트워크에서 노드를 관리하는 중요한 기능입니다. NMT 명령을 통해 노드의 상태를 변경하고, 네트워크의 정상적인 동작을 유지할 수 있습니다. &lt;/p&gt;
&lt;p&gt;CANOpen에서는 각 노드가 특정 상태를 가지며, 마스터 디바이스는 NMT 명령을 사용하여 슬레이브 노드의 상태를 전환할 수 있습니다. 기본적인 NMT 상태는 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Initialization&lt;/strong&gt;: 노드가 초기화되는 상태&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-Operational&lt;/strong&gt;: 일부 CANOpen 서비스(SDO, NMT 등)를 사용할 수 있는 상태&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operational&lt;/strong&gt;: 모든 CANOpen 서비스(PDO 포함)를 사용할 수 있는 상태&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stopped&lt;/strong&gt;: 노드가 네트워크에서 중단된 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;NMT 명령어 형식&lt;/h3&gt;
&lt;p&gt;NMT 명령은 CAN ID 0x000에 전송되며, 데이터 길이는 2바이트로 구성됩니다. 첫 번째 바이트는 명령을 의미하며, 두 번째 바이트는 대상 노드 ID를 나타냅니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;바이트&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;1바이트&lt;/td&gt;
&lt;td&gt;NMT 명령 코드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2바이트&lt;/td&gt;
&lt;td&gt;노드 ID (0은 전체 노드 대상으로 브로드캐스트)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;대표적인 NMT 명령 코드는 다음과 같습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;NMT 명령 코드&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;0x01&lt;/td&gt;
&lt;td&gt;Operational 모드로 전환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x02&lt;/td&gt;
&lt;td&gt;Stopped 모드로 전환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x80&lt;/td&gt;
&lt;td&gt;Pre-Operational 모드로 전환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x81&lt;/td&gt;
&lt;td&gt;Reset Node (전체 리셋)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x82&lt;/td&gt;
&lt;td&gt;Reset Communication (통신 스택만 리셋)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;STM32에서 NMT 명령 전송하기&lt;/h3&gt;
&lt;p&gt;STM32F429를 사용하여 CANOpen 네트워크에서 NMT 명령을 전송하려면, CAN 통신을 설정한 후 NMT 메시지를 구성하여 전송해야 합니다. 아래 예제 코드는 HAL 라이브러리를 이용하여 NMT 명령을 전송하는 방법을 보여줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;quot;stm32f4xx_hal.h&amp;quot;

extern CAN_HandleTypeDef hcan1;

void send_nmt_command(uint8_t command, uint8_t node_id) {
    CAN_TxHeaderTypeDef txHeader;
    uint8_t txData[2];
    uint32_t txMailbox;

    txHeader.StdId = 0x000; // NMT 명령어의 CAN ID
    txHeader.RTR = CAN_RTR_DATA;
    txHeader.IDE = CAN_ID_STD;
    txHeader.DLC = 2;

    txData[0] = command;
    txData[1] = node_id;

    if (HAL_CAN_AddTxMessage(&amp;amp;hcan1, &amp;amp;txHeader, txData, &amp;amp;txMailbox) != HAL_OK) {
        // 오류 처리
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;NMT 명령 활용 예제&lt;/h3&gt;
&lt;p&gt;다음 예제는 특정 노드를 Operational 모드로 변경하는 코드입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;send_nmt_command(0x01, 0x02); // 노드 ID 2를 Operational 모드로 전환&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;네트워크 내 모든 노드를 Pre-Operational 모드로 변경하려면 다음과 같이 브로드캐스트 ID(0x00)를 사용합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;send_nmt_command(0x80, 0x00); // 모든 노드를 Pre-Operational 모드로 전환&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;NMT 상태 확인&lt;/h3&gt;
&lt;p&gt;NMT 명령을 전송한 후 노드의 상태를 확인하려면, 각 노드가 주기적으로 자신의 상태를 보고하도록 설정할 수 있습니다. 상태 보고는 Heartbeat 또는 Node Guarding 기능을 통해 수행됩니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Heartbeat&lt;/strong&gt;: 노드가 자신의 상태를 정기적으로 CAN 버스로 전송 (ID: 0x700 + 노드 ID)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Node Guarding&lt;/strong&gt;: 마스터가 슬레이브 노드의 상태를 질의하고 응답을 확인하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;예를 들어, Heartbeat 메시지를 확인하면 노드가 현재 어떤 상태인지 알 수 있습니다. 일반적으로 Heartbeat 메시지는 다음과 같은 형식으로 전송됩니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;바이트&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;1바이트&lt;/td&gt;
&lt;td&gt;현재 NMT 상태&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;NMT 상태 값 예제:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;상태 값&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;0x00&lt;/td&gt;
&lt;td&gt;Boot-Up (부팅 완료)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x04&lt;/td&gt;
&lt;td&gt;Stopped&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x05&lt;/td&gt;
&lt;td&gt;Operational&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0x7F&lt;/td&gt;
&lt;td&gt;Pre-Operational&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;STM32에서 CAN 인터럽트를 활용하여 Heartbeat 메시지를 수신할 수 있도록 설정할 수도 있습니다.&lt;/p&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;NMT 명령을 활용하면 CANOpen 네트워크에서 각 노드의 상태를 제어하고, 네트워크의 정상적인 동작을 유지할 수 있습니다. STM32F429와 HAL을 이용하면 손쉽게 NMT 명령을 전송하고, 네트워크 상태를 모니터링할 수 있습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen NMT</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/803</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-nmt-1#entry803comment</comments>
      <pubDate>Thu, 14 Aug 2025 19:41:17 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen Slave 개발 (STM32 MCU 활용)</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-slave</link>
      <description>&lt;h2&gt;CANOpen Slave 개발 (STM32 MCU 활용)&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;CANOpen Slave 장치는 CANOpen 네트워크에서 마스터의 명령을 수신하고 응답하는 역할을 합니다. 본 장에서는 STM32F429 MCU와 STM32CubeIDE 및 HAL 라이브러리를 활용하여 CANOpen Slave 장치를 개발하는 방법을 설명합니다.&lt;/p&gt;
&lt;h3&gt;CANOpen Slave 개념&lt;/h3&gt;
&lt;p&gt;CANOpen Slave는 다음과 같은 주요 기능을 수행합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PDO(프로세스 데이터 객체) 전송 및 수신&lt;/li&gt;
&lt;li&gt;SDO(서비스 데이터 객체)를 통한 설정 변경&lt;/li&gt;
&lt;li&gt;NMT(네트워크 관리) 명령 처리&lt;/li&gt;
&lt;li&gt;Heartbeat 및 Node Guarding 기능 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;개발 환경 구축&lt;/h3&gt;
&lt;p&gt;CANOpen Slave 개발을 위해 다음과 같은 환경이 필요합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;하드웨어&lt;/strong&gt;: STM32F429 개발 보드, CAN 트랜시버 (MCP2551 등), CAN 분석기&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;소프트웨어&lt;/strong&gt;: STM32CubeIDE, STM32CubeMX, CANOpenNode (오픈소스 CANOpen 스택)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;STM32CubeMX 설정&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CAN 주변 장치 활성화&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CAN1 또는 CAN2 활성화&lt;/li&gt;
&lt;li&gt;CAN 속도(baud rate) 설정 (예: 125kbps, 250kbps, 500kbps 등)&lt;/li&gt;
&lt;li&gt;필터 설정 (모든 메시지 수신 또는 특정 ID만 수신 가능하도록 설정)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GPIO 설정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CAN RX/TX 핀을 설정 (STM32F429의 경우, 기본적으로 &lt;code&gt;PA11&lt;/code&gt; 및 &lt;code&gt;PA12&lt;/code&gt; 사용 가능)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;클럭 설정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CAN을 위한 적절한 클럭 설정 (APB1 클럭 확인 필요)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;코드 생성 및 프로젝트 열기&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HAL 라이브러리를 활용한 기본 코드 생성&lt;/li&gt;
&lt;li&gt;프로젝트를 STM32CubeIDE에서 열고 코드 수정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;CANOpenNode를 활용한 Slave 개발&lt;/h3&gt;
&lt;p&gt;CANOpenNode는 오픈소스 CANOpen 스택으로, STM32 MCU에서 실행할 수 있도록 포팅할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;CANOpenNode 다운로드 및 설정&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/CANopenNode/CANopenNode&quot;&gt;CANOpenNode GitHub 저장소&lt;/a&gt;에서 코드 다운로드&lt;/li&gt;
&lt;li&gt;&lt;code&gt;device&lt;/code&gt; 폴더 내에 STM32 프로젝트 생성&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CO_driver&lt;/code&gt; 파일 수정하여 STM32 HAL 드라이버에 맞게 변경&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Slave 기본 기능 구현&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SDO 서버 설정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SDO 서버를 통해 파라미터 읽기/쓰기 기능 추가&lt;/li&gt;
&lt;li&gt;객체 사전(Object Dictionary)에 필요한 변수 정의&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PDO 통신 구현&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TPDO (Transmit PDO) 및 RPDO (Receive PDO) 설정&lt;/li&gt;
&lt;li&gt;자동 전송 모드 또는 이벤트 기반 전송 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NMT 상태 관리&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NMT 명령을 수신하여 &lt;code&gt;Pre-Operational&lt;/code&gt;, &lt;code&gt;Operational&lt;/code&gt;, &lt;code&gt;Stopped&lt;/code&gt; 상태 전환 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Heartbeat 및 Node Guarding 설정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Heartbeat 메시지 전송 구현&lt;/li&gt;
&lt;li&gt;Node Guarding 방식으로 슬레이브 상태 모니터링 기능 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;CANOpen Slave 테스트 및 디버깅&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CAN 분석기를 사용하여 메시지 확인&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;슬레이브 장치가 올바른 CANOpen 메시지를 송수신하는지 확인&lt;/li&gt;
&lt;li&gt;SDO 요청에 대한 응답 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PDO 데이터 모니터링&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TPDO 데이터가 올바르게 전송되는지 확인&lt;/li&gt;
&lt;li&gt;RPDO를 통한 입력 데이터 변경 테스트&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NMT 및 Heartbeat 테스트&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NMT 명령에 따라 상태가 정상적으로 변경되는지 검증&lt;/li&gt;
&lt;li&gt;Heartbeat 메시지가 주기적으로 전송되는지 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;마무리&lt;/h3&gt;
&lt;p&gt;본 장에서는 STM32 MCU를 활용하여 CANOpen Slave 장치를 개발하는 방법을 설명하였습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>canopen slave</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/801</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-slave#entry801comment</comments>
      <pubDate>Wed, 13 Aug 2025 20:24:10 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen Master 개발 (STM32 및 C 기반)</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-master</link>
      <description>&lt;h2&gt;CANOpen 마스터 및 슬레이브 개발&lt;/h2&gt;
&lt;p&gt;CANOpen 네트워크에서 노드는 일반적으로 마스터(Master)와 슬레이브(Slave)로 구성됩니다. 마스터는 네트워크를 제어하고 슬레이브 노드와의 통신을 조율하는 역할을 수행하며, 슬레이브는 마스터의 명령을 받아 동작하는 장치입니다. 이러한 구조는 CANOpen을 활용한 산업 자동화, 로봇 제어, 모터 드라이버 시스템 등 다양한 응용에서 핵심적인 역할을 합니다.&lt;/p&gt;
&lt;p&gt;이 장에서는 STM32F429를 활용하여 CANOpen 마스터와 슬레이브 장치를 개발하는 방법을 실습합니다. STM32CubeIDE와 HAL 라이브러리를 이용하여 기본적인 CANOpen 프로토콜을 구현하고, CANOpenNode 및 CANFestival과 같은 오픈소스 라이브러리를 활용하여 보다 효율적인 개발 방법을 소개합니다.&lt;/p&gt;
&lt;p&gt;먼저, CANOpen 마스터와 슬레이브의 기본 개념과 역할을 설명한 후, STM32F429에서 각각의 기능을 구현하는 절차를 살펴봅니다. 이후 실제 네트워크에서 데이터 교환을 수행하는 방법과 마스터-슬레이브 간의 통신을 설정하는 과정을 실습을 통해 익히게 됩니다. 이를 통해 CANOpen 기반 시스템을 설계하고 구현하는 데 필요한 기초 역량을 갖출 수 있습니다.&lt;/p&gt;
&lt;h2&gt;CANOpen Master 개발 (STM32 및 C 기반)&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;CANOpen Master는 네트워크 내에서 슬레이브 장치들을 관리하고 데이터를 주고받는 역할을 합니다. 본 장에서는 STM32F429와 STM32CubeIDE, HAL 라이브러리를 활용하여 CANOpen Master를 개발하는 방법을 다룹니다.&lt;/p&gt;
&lt;h3&gt;CANOpen Master의 역할&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;네트워크 내 슬레이브 장치 검색 및 관리&lt;/li&gt;
&lt;li&gt;PDO (Process Data Object) 및 SDO (Service Data Object) 통신 수행&lt;/li&gt;
&lt;li&gt;슬레이브의 상태 모니터링 및 제어&lt;/li&gt;
&lt;li&gt;네트워크의 NMT (Network Management) 메시지 송수신&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;개발 환경 설정&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;하드웨어 준비&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32F429 보드&lt;/li&gt;
&lt;li&gt;CAN 트랜시버 (MCP2551 또는 TJA1050 등)&lt;/li&gt;
&lt;li&gt;CAN 네트워크 연결을 위한 배선&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;소프트웨어 준비&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32CubeIDE 설치 및 프로젝트 생성&lt;/li&gt;
&lt;li&gt;HAL 라이브러리를 이용한 CAN 설정&lt;/li&gt;
&lt;li&gt;CANOpen 라이브러리 (예: CANopenNode) 통합&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;STM32에서 CAN 초기화&lt;/h3&gt;
&lt;p&gt;STM32에서 CAN을 사용하려면 HAL 라이브러리를 이용하여 초기화해야 합니다. 기본적인 설정 절차는 다음과 같습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;void CAN_Config(void) {
    CAN_HandleTypeDef hcan;
    hcan.Instance = CAN1;
    hcan.Init.Prescaler = 16;
    hcan.Init.Mode = CAN_MODE_NORMAL;
    hcan.Init.SyncJumpWidth = CAN_SJW_1TQ;
    hcan.Init.TimeSeg1 = CAN_BS1_4TQ;
    hcan.Init.TimeSeg2 = CAN_BS2_3TQ;
    hcan.Init.AutoBusOff = ENABLE;
    hcan.Init.AutoWakeUp = ENABLE;
    hcan.Init.AutoRetransmission = ENABLE;
    hcan.Init.ReceiveFifoLocked = DISABLE;
    hcan.Init.TransmitFifoPriority = ENABLE;

    if (HAL_CAN_Init(&amp;amp;hcan) != HAL_OK) {
        // 오류 처리
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;CANOpen Master 기능 구현&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NMT 메시지 전송&lt;/strong&gt;&lt;br&gt;CANOpen Master는 네트워크 관리 메시지를 전송하여 슬레이브의 상태를 변경할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;uint8_t nmt_start_msg[2] = {0x01, 0x00}; // Start Remote Node, Node ID = 0 (전체 대상)
CAN_TxHeaderTypeDef txHeader;
txHeader.StdId = 0x000; // NMT 메시지 ID
txHeader.RTR = CAN_RTR_DATA;
txHeader.IDE = CAN_ID_STD;
txHeader.DLC = 2;

HAL_CAN_AddTxMessage(&amp;amp;hcan, &amp;amp;txHeader, nmt_start_msg, &amp;amp;txMailbox);&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SDO 통신 구현&lt;/strong&gt;&lt;br&gt;SDO를 이용하면 마스터가 슬레이브의 특정 오브젝트를 읽거나 설정할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;uint8_t sdo_read_msg[8] = {0x40, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00};
txHeader.StdId = 0x601; // 슬레이브 노드 ID가 1인 경우
txHeader.DLC = 8;

HAL_CAN_AddTxMessage(&amp;amp;hcan, &amp;amp;txHeader, sdo_read_msg, &amp;amp;txMailbox);&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PDO 전송&lt;/strong&gt;&lt;br&gt;PDO는 실시간 데이터를 주고받을 때 사용됩니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;uint8_t pdo_msg[8] = {0xAB, 0xCD, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC};
txHeader.StdId = 0x181; // Transmit PDO1, Node ID = 1
txHeader.DLC = 8;

HAL_CAN_AddTxMessage(&amp;amp;hcan, &amp;amp;txHeader, pdo_msg, &amp;amp;txMailbox);&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;CANOpen 라이브러리 활용&lt;/h3&gt;
&lt;p&gt;STM32에서 CANOpen을 효과적으로 구현하기 위해 &lt;strong&gt;CANopenNode&lt;/strong&gt; 같은 오픈소스 라이브러리를 사용할 수 있습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CANopenNode 다운로드 및 프로젝트 통합&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/CANopenNode/CANopenNode&quot;&gt;CANopenNode GitHub&lt;/a&gt;에서 코드 다운로드&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CANopenNode&lt;/code&gt;를 STM32CubeIDE 프로젝트에 추가&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CO_driver_STM32.c&lt;/code&gt; 파일을 작성하여 HAL CAN 드라이버와 연동&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CANopen Master 초기화 코드&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;CO_t *co = CO_new(NULL, NULL, NULL);
CO_CANmodule_init(co-&amp;gt;CANmodule, 0, CAN1);
CO_NMT_init(co-&amp;gt;NMT, co-&amp;gt;EM, 1, NULL);
CO_CANsetNormalMode(co-&amp;gt;CANmodule);&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;마무리&lt;/h3&gt;
&lt;p&gt;본 장에서는 STM32에서 HAL과 CANopen 라이브러리를 이용하여 CANOpen Master를 개발하는 방법을 설명하였습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>canopen master</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/799</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-master#entry799comment</comments>
      <pubDate>Tue, 12 Aug 2025 19:53:10 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen STM32F429를 이용한 모터 제어 CiA 402 프로파일</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-cia402</link>
      <description>&lt;h2&gt;CANOpen STM32F429를 이용한 모터 제어 CiA 402 프로파일&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;본 장에서는 CANOpen 프로토콜을 활용하여 STM32F429 보드를 이용한 모터 제어 시스템을 구현하는 방법을 다룹니다. 특히, CiA 402 프로파일을 적용하여 서보 모터 및 스텝 모터 제어를 수행하는 방법을 설명합니다. 이를 통해 실전 프로젝트에서 CANOpen을 활용한 모터 제어 방법을 익힐 수 있습니다.&lt;/p&gt;
&lt;h3&gt;CiA 402 프로파일 개요&lt;/h3&gt;
&lt;p&gt;CiA 402는 CANOpen 프로토콜에서 서보 및 스텝 모터 제어를 위한 표준 프로파일입니다. 이 프로파일을 이용하면 다양한 벤더의 드라이버와 제어 시스템 간의 상호 운용성을 보장할 수 있습니다. 주요 기능은 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;다양한 동작 모드 지원 (위치 제어, 속도 제어, 토크 제어)&lt;/li&gt;
&lt;li&gt;상태 머신을 통한 모터 제어&lt;/li&gt;
&lt;li&gt;표준화된 객체 사전 (Object Dictionary)&lt;/li&gt;
&lt;li&gt;PDO 및 SDO 통신을 통한 데이터 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;개발 환경 설정&lt;/h3&gt;
&lt;p&gt;STM32F429 보드에서 CANOpen을 활용한 모터 제어를 위해 아래와 같은 개발 환경을 구성합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;하드웨어&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32F429 개발 보드&lt;/li&gt;
&lt;li&gt;CAN 트랜시버 (MCP2551 등)&lt;/li&gt;
&lt;li&gt;서보 모터 또는 스텝 모터&lt;/li&gt;
&lt;li&gt;모터 드라이버 (CiA 402 지원)&lt;/li&gt;
&lt;li&gt;전원 공급 장치&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;소프트웨어&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32CubeIDE&lt;/li&gt;
&lt;li&gt;STM32 HAL 라이브러리&lt;/li&gt;
&lt;li&gt;CANopenNode 또는 CANFestival 라이브러리&lt;/li&gt;
&lt;li&gt;CiA 402 지원 펌웨어 코드&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;CiA 402 상태 머신 구현&lt;/h3&gt;
&lt;p&gt;CiA 402 상태 머신은 모터 제어를 위한 중요한 개념입니다. 기본 상태 흐름은 다음과 같습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Not Ready to Switch On&lt;/strong&gt;: 초기 상태, 모터가 동작 준비되지 않음&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Switch On Disabled&lt;/strong&gt;: 안전 모드, 모터 드라이버가 비활성화됨&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ready to Switch On&lt;/strong&gt;: 모터가 동작 가능하지만 아직 활성화되지 않음&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Switched On&lt;/strong&gt;: 모터가 활성화되었지만 동작하지 않음&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operation Enabled&lt;/strong&gt;: 모터가 정상 동작 가능&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fault&lt;/strong&gt;: 오류 발생 시 상태 진입&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;STM32F429에서 CiA 402 상태 머신을 구현하기 위해서는 CANOpen의 SDO 및 PDO 통신을 활용하여 해당 상태 전환을 처리해야 합니다.&lt;/p&gt;
&lt;h3&gt;STM32F429에서 CiA 402 프로파일 적용&lt;/h3&gt;
&lt;p&gt;STM32F429에서 CiA 402 프로파일을 적용하는 주요 단계는 다음과 같습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CANOpen 스택 초기화&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;CO_ReturnError_t err;
err = CO_init(&amp;amp;CANmodule, NODE_ID, CAN_BITRATE);
if (err != CO_ERROR_NO) {
    // 오류 처리
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CiA 402 객체 사전 설정&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;uint16_t controlWord = 0;
CO_SDO_writeOD(&amp;amp;ODlist, 0x6040, 0, &amp;amp;controlWord, sizeof(controlWord));&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;상태 머신에 따른 제어 흐름 구현&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;void motorControlTask(void) {
    uint16_t statusWord;
    CO_SDO_readOD(&amp;amp;ODlist, 0x6041, 0, &amp;amp;statusWord, sizeof(statusWord));

    if ((statusWord &amp;amp; 0x004F) == 0x0040) {  // Ready to Switch On
        controlWord = 0x0006;  // Switch On
    } else if ((statusWord &amp;amp; 0x006F) == 0x0021) {  // Switched On
        controlWord = 0x000F;  // Enable Operation
    }

    CO_SDO_writeOD(&amp;amp;ODlist, 0x6040, 0, &amp;amp;controlWord, sizeof(controlWord));
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;실전 예제: 속도 제어 모드 적용&lt;/h3&gt;
&lt;p&gt;CiA 402에서 속도 제어 모드를 설정하려면 다음 단계를 수행합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;운전 모드 설정&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int8_t mode = 3;  // 속도 모드 (Velocity Mode)
CO_SDO_writeOD(&amp;amp;ODlist, 0x6060, 0, &amp;amp;mode, sizeof(mode));&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;목표 속도 설정 및 전송&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;int32_t targetVelocity = 5000;  // 단위: RPM
CO_SDO_writeOD(&amp;amp;ODlist, 0x60FF, 0, &amp;amp;targetVelocity, sizeof(targetVelocity));&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;제어 워드 설정&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;controlWord = 0x000F;  // Operation Enable
CO_SDO_writeOD(&amp;amp;ODlist, 0x6040, 0, &amp;amp;controlWord, sizeof(controlWord));&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;본 장에서는 STM32F429를 이용하여 CANOpen을 활용한 모터 제어 프로젝트를 진행하였습니다. 특히, CiA 402 프로파일을 적용하여 상태 머신 기반의 모터 제어 방법을 설명하였으며, 속도 제어 모드 예제를 통해 실제 구현 방법을 소개하였습니다. 본 프로젝트를 응용하여 다양한 모터 및 시스템에 CANOpen을 활용한 확장 개발이 가능합니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen CiA 402 Profile</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/797</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-cia402#entry797comment</comments>
      <pubDate>Mon, 11 Aug 2025 20:06:07 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen 노드 구성 및 테스트(STM32F429 활용)</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-node-1</link>
      <description>&lt;h2&gt;CANOpen 노드 구성 및 테스트(STM32F429 활용)&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;STM32F429 마이크로컨트롤러를 활용하여 CANOpen 노드를 구성하고 테스트하는 방법에 대해 설명합니다. CANOpen은 산업 자동화 및 임베디드 시스템에서 널리 사용되는 프로토콜로, 실시간 통신을 지원하며 다양한 기능을 제공합니다. 본 장에서는 STM32CubeIDE와 HAL 라이브러리를 활용하여 CANOpen 노드를 개발하고, 이를 테스트하는 과정을 다룹니다.&lt;/p&gt;
&lt;h3&gt;CANOpen 노드 구성&lt;/h3&gt;
&lt;p&gt;CANOpen 노드를 구성하기 위해 다음과 같은 요소가 필요합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;하드웨어 준비&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32F429 개발 보드 (예: STM32F429I-DISCO 또는 NUCLEO-F429ZI)&lt;/li&gt;
&lt;li&gt;CAN 트랜시버 (예: MCP2551, TJA1050 등)&lt;/li&gt;
&lt;li&gt;CAN 통신을 위한 배선 및 종단 저항 (120Ω)&lt;/li&gt;
&lt;li&gt;CAN 분석기 (예: PEAK-System PCAN-USB, Kvaser 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;소프트웨어 환경 설정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32CubeIDE 설치 및 프로젝트 생성&lt;/li&gt;
&lt;li&gt;STM32 HAL 라이브러리 및 CAN 드라이버 설정&lt;/li&gt;
&lt;li&gt;CANOpen 스택 (예: CANopenNode, CANFestival) 통합&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CANOpen 주요 구성 요소&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Object Dictionary (OD)&lt;/strong&gt;: 노드의 변수 및 매개변수를 저장하는 테이블&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EDS (Electronic Data Sheet)&lt;/strong&gt;: CANOpen 장치의 속성을 정의하는 파일&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SDO (Service Data Object)&lt;/strong&gt; 및 &lt;strong&gt;PDO (Process Data Object)&lt;/strong&gt; 통신 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;STM32F429에서 CANOpen 펌웨어 구현&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;STM32CubeMX를 이용한 CAN 설정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CAN1 또는 CAN2 인터페이스 활성화&lt;/li&gt;
&lt;li&gt;CAN 필터 및 비트 타이밍 설정 (예: 500kbps)&lt;/li&gt;
&lt;li&gt;GPIO 핀 설정 (CAN TX, RX)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CANOpen 스택 적용&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CANopenNode 또는 CANFestival 라이브러리 다운로드 및 프로젝트에 추가&lt;/li&gt;
&lt;li&gt;Object Dictionary 파일 생성 및 매핑&lt;/li&gt;
&lt;li&gt;노드 ID 및 기본 통신 파라미터 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;주요 기능 구현&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SDO 서비스 구현&lt;/strong&gt;: 설정 값 읽기 및 쓰기 지원&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PDO 통신 설정&lt;/strong&gt;: 주기적인 데이터 송수신&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Heartbeat 및 NMT (Network Management) 기능 활성화&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;테스트 및 디버깅&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CAN 분석기를 이용한 데이터 모니터링&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CANOpen 노드가 정상적으로 네트워크에 참여하는지 확인&lt;/li&gt;
&lt;li&gt;SDO 및 PDO 통신 테스트&lt;/li&gt;
&lt;li&gt;Heartbeat 메시지 수신 여부 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;펌웨어 디버깅&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32CubeIDE를 이용한 디버깅&lt;/li&gt;
&lt;li&gt;CAN 통신 오류 처리 및 예외 상황 대응&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;실제 환경에서의 테스트&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;다른 CANOpen 장치와의 상호 운용성 테스트&lt;/li&gt;
&lt;li&gt;산업용 CAN 네트워크에서의 성능 평가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;STM32F429를 활용한 CANOpen 노드 개발 및 테스트 과정에 대해 다루었습니다. 본 장에서 설명한 방법을 따라가면, 기본적인 CANOpen 노드를 구성하고 실제 환경에서 검증할 수 있습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CAN Node</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/795</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-node-1#entry795comment</comments>
      <pubDate>Sun, 10 Aug 2025 21:42:12 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen 네트워크 테스트 및 디버깅</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-network-debug</link>
      <description>&lt;h2&gt;CANOpen 네트워크 테스트 및 디버깅&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;CANOpen 네트워크를 개발한 후에는 반드시 올바르게 동작하는지 테스트하고, 문제 발생 시 디버깅하는 과정이 필요합니다. CANOpen은 실시간 산업 네트워크로서 데이터의 정확성과 안정성이 중요한 역할을 하므로, 철저한 검증 과정이 필수적입니다.&lt;/p&gt;
&lt;p&gt;본 장에서는 CANOpen 네트워크의 테스트 방법과 디버깅 기법에 대해 다루며, 실제 STM32F429 기반의 개발 환경에서 적용할 수 있는 실습 예제를 포함합니다.&lt;/p&gt;
&lt;h3&gt;CANOpen 네트워크 테스트 방법&lt;/h3&gt;
&lt;p&gt;CANOpen 네트워크 테스트는 여러 가지 측면에서 수행될 수 있습니다. 주요 테스트 항목은 다음과 같습니다.&lt;/p&gt;
&lt;h4&gt;1. 물리 계층 테스트&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CAN Bus 신호 무결성 확인&lt;/strong&gt;: 오실로스코프를 사용하여 CAN_H 및 CAN_L 신호의 품질을 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;종단 저항(120Ω) 확인&lt;/strong&gt;: 네트워크의 양 끝단에 올바른 종단 저항이 배치되었는지 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;배선 및 커넥터 상태 점검&lt;/strong&gt;: 배선의 단락(short) 및 개방(open) 여부를 검사합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. 프로토콜 계층 테스트&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CANOpen 노드의 통신 확인&lt;/strong&gt;: 모든 노드가 정상적으로 NMT(Network Management) 명령을 수신하는지 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Heartbeat 및 Node Guarding&lt;/strong&gt;: 각 노드가 정해진 주기대로 Heartbeat 메시지를 송수신하는지 검사합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PDO 및 SDO 통신 테스트&lt;/strong&gt;: 데이터가 정상적으로 송수신되는지, 데이터 무결성이 보장되는지 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. 성능 테스트&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;버스 부하 측정&lt;/strong&gt;: 높은 부하에서 CANOpen 네트워크가 정상적으로 동작하는지 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;지연 시간(Latency) 분석&lt;/strong&gt;: 특정 이벤트 발생 시, CAN 메시지가 얼마나 빠르게 전송되는지 측정합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;에러 프레임 검출&lt;/strong&gt;: CAN Bus에서 오류 프레임이 발생하는지 확인하고, 발생 빈도를 측정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;CANOpen 디버깅 기법&lt;/h3&gt;
&lt;p&gt;CANOpen 네트워크에서 발생할 수 있는 다양한 문제를 분석하고 해결하기 위해 여러 디버깅 기법을 사용할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;1. CAN Bus 분석 도구 활용&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PCAN-View (PEAK Systems)&lt;/strong&gt;: 실시간으로 CAN 메시지를 모니터링하고 분석할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CANalyzer (Vector Informatik)&lt;/strong&gt;: 고급 분석 기능을 제공하며, CANOpen 프로토콜을 깊이 있게 분석할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BusMaster&lt;/strong&gt;: 오픈소스 CAN 분석 도구로, 기본적인 메시지 송수신 기능을 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. 펌웨어 디버깅&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;STM32CubeIDE 디버깅 기능 활용&lt;/strong&gt;: STM32CubeIDE의 디버거를 사용하여 CANOpen 스택 내부 변수와 상태를 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;로그 메시지 출력&lt;/strong&gt;: UART 또는 USB-Serial을 이용하여 CANOpen 스택 내부 로그를 출력하고 분석합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SDO 오류 코드 분석&lt;/strong&gt;: SDO 통신 중 발생하는 오류 코드(Abort Code)를 기반으로 문제를 분석합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. 네트워크 트래픽 분석&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;비정상적인 메시지 패턴 감지&lt;/strong&gt;: CANalyzer 또는 PCAN-View를 사용하여 네트워크 트래픽을 분석하고, 예상치 못한 메시지를 찾아냅니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;오류 프레임 분석&lt;/strong&gt;: CAN Bus에서 발생하는 오류 프레임을 확인하고, 노드의 통신 장애 원인을 파악합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NMT 상태 전이(State Transition) 확인&lt;/strong&gt;: 노드가 정상적으로 &lt;code&gt;Pre-operational&lt;/code&gt;, &lt;code&gt;Operational&lt;/code&gt;, &lt;code&gt;Stopped&lt;/code&gt; 상태를 전이하는지 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;STM32F429 기반의 CANOpen 네트워크 테스트 실습&lt;/h3&gt;
&lt;p&gt;STM32F429와 STM32CubeIDE를 활용하여 CANOpen 네트워크를 테스트하는 실습을 진행합니다.&lt;/p&gt;
&lt;h4&gt;1. 테스트 환경 구축&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;하드웨어 구성&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;STM32F429 보드 2개&lt;/li&gt;
&lt;li&gt;CAN 트랜시버 (MCP2551 또는 TJA1050)&lt;/li&gt;
&lt;li&gt;120Ω 종단 저항 2개&lt;/li&gt;
&lt;li&gt;PC (CAN 분석 도구 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;소프트웨어 준비&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;STM32CubeIDE&lt;/li&gt;
&lt;li&gt;CANopenNode 또는 CANFestival 라이브러리&lt;/li&gt;
&lt;li&gt;PCAN-View 또는 CANalyzer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. 기본 통신 테스트&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NMT 명령 전송 및 응답 확인&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CANopenNode&lt;/code&gt; 또는 &lt;code&gt;CANFestival&lt;/code&gt;을 사용하여 Master에서 NMT(Start Node) 명령을 전송합니다.&lt;/li&gt;
&lt;li&gt;Slave 노드가 해당 명령을 수신하고, Operational 상태로 전이하는지 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Heartbeat 메시지 확인&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;각 Slave 노드에서 주기적으로 Heartbeat 메시지를 송신하는지 확인합니다.&lt;/li&gt;
&lt;li&gt;PCAN-View를 사용하여 메시지 내용을 분석합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SDO 통신 테스트&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Master에서 특정 SDO Read 요청을 보내고, 응답이 올바르게 수신되는지 확인합니다.&lt;/li&gt;
&lt;li&gt;SDO Write 테스트를 수행하고, Slave 노드에서 데이터가 정상적으로 반영되는지 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PDO 통신 테스트&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;주기적으로 PDO 메시지가 정상적으로 송수신되는지 확인합니다.&lt;/li&gt;
&lt;li&gt;PDO 매핑을 변경한 후, 데이터 전송이 올바르게 이루어지는지 테스트합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;3. 장애 상황 시뮬레이션 및 대응&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;노드 전원 차단 후 복구&lt;/strong&gt;: 특정 노드의 전원을 껐다가 다시 켰을 때, 정상적으로 네트워크에 재등록되는지 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;에러 프레임 유발&lt;/strong&gt;: 의도적으로 잘못된 메시지를 송신하여 네트워크가 어떻게 반응하는지 테스트합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;고부하 상태 테스트&lt;/strong&gt;: 여러 개의 PDO를 빠르게 송수신하여 네트워크가 정상적으로 동작하는지 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;CANOpen 네트워크의 올바른 동작을 보장하기 위해서는 철저한 테스트와 효과적인 디버깅이 필수적입니다.&lt;br&gt;STM32F429 기반의 CANOpen 네트워크에서 발생할 수 있는 다양한 문제를 해결하기 위해, 하드웨어 및 소프트웨어 도구를 적절히 활용해야 합니다.&lt;/p&gt;
&lt;p&gt;본 장에서 다룬 테스트 및 디버깅 기법을 활용하여 안정적인 CANOpen 네트워크를 구축하시기 바랍니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen Network debug</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/793</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-network-debug#entry793comment</comments>
      <pubDate>Sat, 9 Aug 2025 20:00:58 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen SDO/PDO 통신 실습 (STM32F429)</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-pdo-sdo</link>
      <description>&lt;h2&gt;CANOpen SDO/PDO 통신 실습 (STM32F429)&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;SDO (Service Data Object)와 PDO (Process Data Object)는 CANOpen 프로토콜에서 가장 중요한 데이터 전송 메커니즘입니다. SDO는 노드 간 설정 값을 읽거나 변경하는 데 사용되며, PDO는 실시간 데이터 교환을 위해 설계되었습니다. 본 장에서는 STM32F429와 CANOpen 스택을 이용하여 SDO 및 PDO 통신을 설정하고 실습하는 방법을 설명합니다.&lt;/p&gt;
&lt;h3&gt;실습 환경 설정&lt;/h3&gt;
&lt;p&gt;SDO/PDO 통신을 실습하기 위해 다음과 같은 개발 환경이 필요합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;하드웨어&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32F429 개발 보드&lt;/li&gt;
&lt;li&gt;CAN 트랜시버 (MCP2551 또는 TJA1050 등)&lt;/li&gt;
&lt;li&gt;CAN 통신을 위한 USB-CAN 인터페이스 (PEAK-System PCAN 또는 Lawicel CANUSB 등)&lt;/li&gt;
&lt;li&gt;120Ω 터미네이션 저항&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;소프트웨어&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32CubeIDE&lt;/li&gt;
&lt;li&gt;STM32CubeMX&lt;/li&gt;
&lt;li&gt;CANopenNode 또는 CANFestival 라이브러리&lt;/li&gt;
&lt;li&gt;CAN 분석 소프트웨어 (PCAN-View, BusMaster 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;SDO (Service Data Object) 개념 및 실습&lt;/h3&gt;
&lt;h4&gt;SDO 개념&lt;/h4&gt;
&lt;p&gt;SDO는 노드 간 데이터를 읽거나 변경하는 데 사용되는 프로토콜로, Master-Slave 방식으로 동작합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;클라이언트 (Master)&lt;/strong&gt;: 데이터 요청을 보내는 노드&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;서버 (Slave)&lt;/strong&gt;: 데이터를 제공하거나 변경하는 노드&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SDO 프레임 구조는 다음과 같이 구성됩니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Byte&lt;/th&gt;
&lt;th&gt;내용&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;명령 (Command Specifier)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1-3&lt;/td&gt;
&lt;td&gt;인덱스 및 서브 인덱스&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4-7&lt;/td&gt;
&lt;td&gt;데이터 값&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h4&gt;SDO 실습&lt;/h4&gt;
&lt;p&gt;SDO를 이용하여 STM32F429 노드의 특정 객체를 읽고 쓰는 실습을 진행합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SDO 서버 설정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Object Dictionary에서 특정 변수를 정의합니다.&lt;/li&gt;
&lt;li&gt;예제: 0x2000 인덱스의 32비트 변수를 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;uint32_t myVariable = 0x12345678;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SDO 읽기 요청 처리&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SDO 클라이언트가 0x2000 인덱스 데이터를 요청할 경우, 해당 값을 응답&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;uint32_t handleSDORead(uint16_t index) {
    if (index == 0x2000) {
        return myVariable;
    }
    return 0;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SDO 쓰기 요청 처리&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;클라이언트가 새로운 값을 보내면 해당 변수를 업데이트&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;void handleSDOWrite(uint16_t index, uint32_t value) {
    if (index == 0x2000) {
        myVariable = value;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;PDO (Process Data Object) 개념 및 실습&lt;/h3&gt;
&lt;h4&gt;PDO 개념&lt;/h4&gt;
&lt;p&gt;PDO는 실시간 데이터를 전송하는 프로토콜로, SDO와 달리 데이터를 빠르게 송수신할 수 있도록 설계되었습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TPDO (Transmit PDO)&lt;/strong&gt;: 노드가 데이터를 전송하는 경우&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RPDO (Receive PDO)&lt;/strong&gt;: 노드가 데이터를 수신하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PDO는 사전 정의된 매핑 테이블을 사용하여 데이터를 송수신합니다.&lt;/p&gt;
&lt;h4&gt;PDO 실습&lt;/h4&gt;
&lt;p&gt;STM32F429에서 PDO를 설정하고 데이터를 송수신하는 실습을 진행합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PDO 매핑 설정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TPDO 및 RPDO에 사용할 변수를 정의&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;uint16_t sensorData = 0x1234;
uint16_t controlCommand = 0x0000;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;TPDO 전송 설정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;주기적으로 센서 데이터를 TPDO로 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;void sendTPDO(void) {
    CAN_TxHeaderTypeDef txHeader;
    uint8_t data[2];

    txHeader.StdId = 0x180 + NODE_ID;
    txHeader.DLC = 2;
    data[0] = sensorData &amp;amp; 0xFF;
    data[1] = (sensorData &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;

    HAL_CAN_AddTxMessage(&amp;amp;hcan, &amp;amp;txHeader, data, &amp;amp;txMailbox);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;RPDO 수신 설정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;수신된 제어 명령을 변수에 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;void receiveRPDO(uint8_t *data) {
    controlCommand = data[0] | (data[1] &amp;lt;&amp;lt; 8);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PDO 활성화 및 주기적 전송&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;타이머 인터럽트를 이용하여 주기적으로 TPDO를 전송&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if (htim-&amp;gt;Instance == TIM2) {
        sendTPDO();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;테스트 및 검증&lt;/h3&gt;
&lt;p&gt;SDO 및 PDO 설정이 완료되면, CAN 분석기를 사용하여 통신을 검증합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SDO 검증&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CAN 분석 소프트웨어에서 특정 SDO 요청을 보내고 응답을 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PDO 검증&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;TPDO 데이터가 주기적으로 전송되는지 확인&lt;/li&gt;
&lt;li&gt;RPDO 데이터를 수신하여 변수 업데이트 여부 확인&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;이번 실습에서는 STM32F429와 CANOpen을 이용하여 SDO/PDO 통신을 설정하고 테스트하였습니다. SDO를 통해 설정 데이터를 읽고 변경하는 방법을 익혔으며, 실시간 데이터 전송을 위해 PDO를 구성하고 송수신하는 방법을 실습하였습니다. 이를 기반으로 보다 복잡한 CANOpen 네트워크를 구성할 수 있습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CAN PDO</category>
      <category>CAN SDO</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/791</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-pdo-sdo#entry791comment</comments>
      <pubDate>Fri, 8 Aug 2025 20:41:33 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen 스택 포팅 방법(STM32F429)</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-stack-porting</link>
      <description>&lt;h2&gt;CANOpen 스택 포팅 방법(STM32F429)&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;CANOpen은 산업 자동화 및 임베디드 시스템에서 널리 사용되는 통신 프로토콜입니다. STM32F429에서 CANOpen 스택을 포팅하는 과정은 CANopenNode 또는 CANFestival과 같은 오픈 소스 스택을 활용하여 구현할 수 있습니다. 본 장에서는 CANOpen 스택을 STM32F429에 포팅하는 방법과 그 과정에서 필요한 설정 및 코드 수정 사항을 설명합니다.&lt;/p&gt;
&lt;h3&gt;CANOpen 스택 선택&lt;/h3&gt;
&lt;p&gt;현재 오픈 소스로 제공되는 주요 CANOpen 스택은 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CANopenNode&lt;/strong&gt;: 경량화된 CANOpen 스택으로, 높은 확장성과 유연성을 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CANFestival&lt;/strong&gt;: 다양한 기능을 제공하는 CANOpen 스택으로, 복잡한 네트워크 환경에서도 활용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;STM32F429의 리소스와 프로젝트 요구사항을 고려하여 적절한 CANOpen 스택을 선택합니다. 일반적으로 CANopenNode가 가벼운 구조를 가지므로 임베디드 환경에서 더 적합할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;개발 환경 설정&lt;/h3&gt;
&lt;h4&gt;1. STM32CubeIDE 및 HAL 드라이버 설정&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;STM32CubeMX를 사용한 CAN 설정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CAN 모듈을 활성화합니다.&lt;/li&gt;
&lt;li&gt;CAN Baudrate 및 필터 설정을 구성합니다.&lt;/li&gt;
&lt;li&gt;HAL CAN 드라이버를 활성화합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;STM32CubeIDE에서 프로젝트 생성&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32CubeMX로 생성한 프로젝트를 STM32CubeIDE에서 열고 필요한 설정을 추가합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stm32f4xx_hal_can.c&lt;/code&gt; 및 &lt;code&gt;stm32f4xx_hal_can.h&lt;/code&gt; 파일을 수정하여 CAN 메시지 송수신을 구현합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;2. CANOpen 스택 다운로드 및 프로젝트 통합&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CANopenNode 다운로드&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/CANopenNode/CANopenNode&quot;&gt;GitHub&lt;/a&gt;에서 CANopenNode 소스를 다운로드합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Device&lt;/code&gt; 폴더에 STM32F429용 드라이버를 추가합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CANFestival 다운로드&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.canfestival.org/&quot;&gt;공식 웹사이트&lt;/a&gt;에서 CANFestival을 다운로드합니다.&lt;/li&gt;
&lt;li&gt;빌드 시스템을 설정하고 STM32F429에 맞게 수정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;CANopenNode 포팅 과정&lt;/h3&gt;
&lt;h4&gt;1. CAN 드라이버 인터페이스 구현&lt;/h4&gt;
&lt;p&gt;CANopenNode는 하드웨어 독립적인 구조를 가지므로, STM32F429의 HAL 드라이버와 연동하는 인터페이스를 구현해야 합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;CO_driver_STM32F4.c&lt;/code&gt; 파일을 생성하고, 다음과 같은 함수를 구현합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;quot;stm32f4xx_hal.h&amp;quot;
#include &amp;quot;CO_driver.h&amp;quot;

extern CAN_HandleTypeDef hcan1;

CO_ReturnError_t CO_CANmodule_init(CO_CANmodule_t *CANmodule, CAN_TypeDef *CANport) {
    CAN_FilterTypeDef sFilterConfig;

    // CAN 필터 설정
    sFilterConfig.FilterBank = 0;
    sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
    sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
    sFilterConfig.FilterIdHigh = 0x0000;
    sFilterConfig.FilterIdLow = 0x0000;
    sFilterConfig.FilterMaskIdHigh = 0x0000;
    sFilterConfig.FilterMaskIdLow = 0x0000;
    sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
    sFilterConfig.FilterActivation = ENABLE;
    HAL_CAN_ConfigFilter(&amp;amp;hcan1, &amp;amp;sFilterConfig);

    // CAN 모듈 시작
    if (HAL_CAN_Start(&amp;amp;hcan1) != HAL_OK) {
        return CO_ERROR_ILLEGAL_ARGUMENT;
    }
    return CO_ERROR_NO;
}

void CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer) {
    CAN_TxHeaderTypeDef TxHeader;
    uint32_t TxMailbox;
    uint8_t data[8];

    TxHeader.StdId = buffer-&amp;gt;ident;
    TxHeader.DLC = buffer-&amp;gt;DLC;
    TxHeader.IDE = CAN_ID_STD;
    TxHeader.RTR = CAN_RTR_DATA;

    memcpy(data, buffer-&amp;gt;data, 8);
    HAL_CAN_AddTxMessage(&amp;amp;hcan1, &amp;amp;TxHeader, data, &amp;amp;TxMailbox);
}

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) {
    CAN_RxHeaderTypeDef RxHeader;
    uint8_t data[8];

    if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &amp;amp;RxHeader, data) == HAL_OK) {
        // 수신된 데이터 처리
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;CO_main.c&lt;/code&gt; 파일에서 메인 루프를 구성하고 CANOpen 프로토콜을 실행합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;2. Object Dictionary (OD) 설정&lt;/h4&gt;
&lt;p&gt;CANOpen에서 Object Dictionary(OD)는 중요한 역할을 합니다. OD는 EDS(Electronic Data Sheet) 파일을 기반으로 설정할 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;od.h&lt;/code&gt;, &lt;code&gt;od.c&lt;/code&gt; 파일을 생성하고 필요한 오브젝트를 추가합니다.&lt;/li&gt;
&lt;li&gt;CANopenNode의 &lt;code&gt;CO_OD.h&lt;/code&gt; 파일을 수정하여 OD 항목을 정의합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. 타이머 및 인터럽트 설정&lt;/h4&gt;
&lt;p&gt;CANopenNode는 주기적으로 실행되는 타이머를 필요로 합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;TIMx&lt;/code&gt;를 이용하여 1ms 타이머 인터럽트를 생성합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CO_process()&lt;/code&gt; 함수를 주기적으로 호출하여 프로토콜이 정상적으로 동작하도록 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;디버깅 및 테스트&lt;/h3&gt;
&lt;h4&gt;1. CAN 메시지 송수신 테스트&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;CAN 분석기 또는 다른 CANOpen 장치를 사용하여 STM32F429의 CAN 메시지를 모니터링합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HAL_CAN_Receive_IT()&lt;/code&gt;를 이용하여 수신된 메시지를 디버깅합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. CANOpen 기능 테스트&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Heartbeat 메시지가 정상적으로 전송되는지 확인합니다.&lt;/li&gt;
&lt;li&gt;Object Dictionary에 정의한 값들이 정상적으로 읽히고 쓰이는지 테스트합니다.&lt;/li&gt;
&lt;li&gt;PDO 및 SDO 통신이 올바르게 동작하는지 점검합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;STM32F429에서 CANOpen 스택을 포팅하는 과정은 CAN 드라이버 구현, Object Dictionary 설정, 타이머 구성 등을 포함합니다. CANopenNode는 경량화된 구조로 임베디드 환경에서 적합하며, CANFestival은 기능이 풍부한 대안이 될 수 있습니다. 본 장에서 다룬 내용을 기반으로 STM32F429에서 CANOpen을 성공적으로 적용할 수 있습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen Stack</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/789</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-stack-porting#entry789comment</comments>
      <pubDate>Thu, 7 Aug 2025 20:15:49 +0900</pubDate>
    </item>
    <item>
      <title>STM32F429의 CAN 컨트롤러 특징 및 설정 방법</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-stm32</link>
      <description>&lt;h2&gt;STM32F429의 CAN 컨트롤러 특징 및 설정 방법&lt;/h2&gt;
&lt;h3&gt;STM32F429의 CAN 컨트롤러 개요&lt;/h3&gt;
&lt;p&gt;STM32F429 마이크로컨트롤러는 강력한 CAN(Controller Area Network) 통신 기능을 내장하고 있어 다양한 산업용 및 자동차 애플리케이션에서 활용될 수 있습니다. STM32F429의 CAN 컨트롤러는 Bosch CAN 2.0B 프로토콜을 지원하며, 최대 1 Mbps의 전송 속도를 제공합니다.&lt;/p&gt;
&lt;p&gt;CAN 컨트롤러는 CAN1과 CAN2 두 개의 독립적인 채널을 제공하며, 각 채널은 별도의 메시지 필터를 갖추고 있어 효율적인 데이터 수신이 가능합니다. 또한, STM32F429의 CAN 인터페이스는 HAL 라이브러리를 통해 쉽게 구성할 수 있으며, 다양한 운영 모드를 지원합니다.&lt;/p&gt;
&lt;h3&gt;STM32F429의 CAN 컨트롤러 특징&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bosch CAN 2.0B 지원&lt;/strong&gt;: 확장 및 표준 프레임을 모두 지원합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;다중 CAN 인터페이스&lt;/strong&gt;: STM32F429는 두 개의 독립적인 CAN 컨트롤러(CAN1, CAN2)를 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;강력한 필터링 기능&lt;/strong&gt;: 수신 메시지를 효율적으로 분류할 수 있는 28개의 필터 뱅크를 지원합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Low-power 모드 지원&lt;/strong&gt;: 저전력 동작을 위한 Sleep 및 Stop 모드를 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;하드웨어 자동 재전송&lt;/strong&gt;: 메시지 전송 실패 시 자동 재전송 기능을 포함합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FIFO 버퍼 제공&lt;/strong&gt;: 수신 데이터 처리를 위한 FIFO 버퍼를 갖추고 있어 메시지 손실을 최소화합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bit Timing Configuration 지원&lt;/strong&gt;: 사용자 정의 비트 타이밍 구성이 가능하여 다양한 CAN 네트워크 환경에 대응할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;STM32F429의 CAN 핀 구성&lt;/h3&gt;
&lt;p&gt;STM32F429의 CAN 인터페이스는 특정 핀에 매핑되어 있으며, CAN1과 CAN2는 각각 다음과 같은 핀을 사용할 수 있습니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;CAN 인터페이스&lt;/th&gt;
&lt;th&gt;TX 핀&lt;/th&gt;
&lt;th&gt;RX 핀&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;CAN1&lt;/td&gt;
&lt;td&gt;PA12&lt;/td&gt;
&lt;td&gt;PA11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CAN2&lt;/td&gt;
&lt;td&gt;PB13&lt;/td&gt;
&lt;td&gt;PB12&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;CAN 통신을 위해서는 반드시 해당 핀을 GPIO로 설정하고, CAN 기능에 맞게 초기화해야 합니다.&lt;/p&gt;
&lt;h3&gt;STM32CubeIDE를 이용한 CAN 초기화 절차&lt;/h3&gt;
&lt;p&gt;STM32CubeIDE를 이용하여 CAN을 설정하는 과정은 다음과 같습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;STM32CubeMX에서 CAN 활성화&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32CubeMX에서 CAN1 또는 CAN2를 활성화합니다.&lt;/li&gt;
&lt;li&gt;해당 핀을 &lt;code&gt;Alternate Function&lt;/code&gt; 모드로 설정합니다.&lt;/li&gt;
&lt;li&gt;CAN 통신 속도 및 필터 설정을 구성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HAL 라이브러리를 이용한 CAN 초기화&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HAL_CAN_Init()&lt;/code&gt; 함수를 호출하여 CAN 모듈을 초기화합니다.&lt;/li&gt;
&lt;li&gt;필터 설정을 적용하여 특정 메시지만 수신할 수 있도록 구성합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HAL_CAN_Start()&lt;/code&gt; 함수를 호출하여 CAN 모듈을 활성화합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CAN 송신 및 수신 설정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HAL_CAN_AddTxMessage()&lt;/code&gt; 함수를 사용하여 CAN 메시지를 송신합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HAL_CAN_GetRxMessage()&lt;/code&gt; 함수를 이용하여 수신된 데이터를 처리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;CAN 필터 설정 방법&lt;/h3&gt;
&lt;p&gt;CAN 통신에서 필터는 특정 ID의 메시지만 수신할 수 있도록 설정하는 중요한 기능입니다. STM32F429에서는 28개의 필터 뱅크를 지원하며, 다음과 같은 방식으로 필터를 설정할 수 있습니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;
sFilterConfig.FilterActivation = ENABLE;

HAL_CAN_ConfigFilter(&amp;amp;hcan1, &amp;amp;sFilterConfig);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 코드는 CAN1 인터페이스에서 모든 메시지를 수신할 수 있도록 필터를 구성하는 예제입니다. 특정 ID의 메시지만 수신하려면 &lt;code&gt;FilterIdHigh&lt;/code&gt; 및 &lt;code&gt;FilterMaskIdHigh&lt;/code&gt; 값을 조정해야 합니다.&lt;/p&gt;
&lt;h3&gt;CAN 송신 예제 코드&lt;/h3&gt;
&lt;p&gt;아래는 STM32F429에서 CAN 메시지를 송신하는 코드 예제입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;CAN_TxHeaderTypeDef TxHeader;
uint8_t TxData[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
uint32_t TxMailbox;

TxHeader.DLC = 8;
TxHeader.IDE = CAN_ID_STD;
TxHeader.RTR = CAN_RTR_DATA;
TxHeader.StdId = 0x321;

if (HAL_CAN_AddTxMessage(&amp;amp;hcan1, &amp;amp;TxHeader, TxData, &amp;amp;TxMailbox) != HAL_OK) {
    // 전송 실패 처리
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;CAN 수신 예제 코드&lt;/h3&gt;
&lt;p&gt;아래는 STM32F429에서 CAN 메시지를 수신하는 코드 예제입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;CAN_RxHeaderTypeDef RxHeader;
uint8_t RxData[8];

if (HAL_CAN_GetRxMessage(&amp;amp;hcan1, CAN_RX_FIFO0, &amp;amp;RxHeader, RxData) == HAL_OK) {
    // 수신된 데이터 처리
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;STM32F429의 CAN 컨트롤러는 강력한 기능을 제공하며, HAL 라이브러리를 활용하여 쉽게 설정할 수 있습니다. 본 장에서는 STM32F429의 CAN 컨트롤러 특징과 설정 방법을 다루었으며, 실습을 통해 CAN 통신을 구현할 수 있도록 하였습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CAN 설정</category>
      <category>stm32</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/787</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-stm32#entry787comment</comments>
      <pubDate>Wed, 6 Aug 2025 19:51:17 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen 노드 구현 (STM32CubeIDE 및 HAL 활용)</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-node</link>
      <description>&lt;h2&gt;CANOpen 노드 구현 (STM32CubeIDE 및 HAL 활용)&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;CANOpen은 산업 자동화 및 임베디드 시스템에서 널리 사용되는 프로토콜로, STM32F429를 활용하여 CANOpen 노드를 구현할 수 있습니다. 본 장에서는 STM32CubeIDE와 HAL 라이브러리를 이용하여 CANOpen 노드를 개발하는 방법을 설명합니다.&lt;/p&gt;
&lt;h3&gt;개발 환경 구성&lt;/h3&gt;
&lt;p&gt;CANOpen 노드 구현을 위해 다음과 같은 개발 환경이 필요합니다:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;하드웨어&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;STM32F429 보드&lt;/li&gt;
&lt;li&gt;CAN 트랜시버 (MCP2551 또는 TJA1050 등)&lt;/li&gt;
&lt;li&gt;CAN Bus 연결을 위한 하드웨어 (케이블, 종단 저항 120Ω)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;소프트웨어&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;STM32CubeIDE&lt;/li&gt;
&lt;li&gt;STM32CubeMX&lt;/li&gt;
&lt;li&gt;CANOpenNode 또는 CANFestival 라이브러리&lt;/li&gt;
&lt;li&gt;HAL (Hardware Abstraction Layer)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;STM32CubeIDE에서 CAN 설정&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;STM32CubeMX 프로젝트 생성&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32CubeIDE를 실행하고 새 프로젝트를 생성합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;STM32F429&lt;/code&gt; 칩을 선택하고 프로젝트를 생성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CAN 주변 장치 활성화&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Peripherals&lt;/code&gt; 메뉴에서 &lt;code&gt;CAN1&lt;/code&gt; 또는 &lt;code&gt;CAN2&lt;/code&gt;를 활성화합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Mode&lt;/code&gt;를 &lt;code&gt;Normal&lt;/code&gt; 또는 &lt;code&gt;Loopback&lt;/code&gt;으로 설정합니다 (테스트 목적).&lt;/li&gt;
&lt;li&gt;CAN의 &lt;code&gt;Baud Rate&lt;/code&gt;를 설정합니다 (예: 125kbps, 250kbps, 500kbps 등).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Filter Configuration&lt;/code&gt;을 기본값으로 설정하거나 필요에 맞게 조정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GPIO 설정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CAN1 또는 CAN2의 &lt;code&gt;TX&lt;/code&gt;, &lt;code&gt;RX&lt;/code&gt; 핀을 확인하고 적절한 핀으로 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Alternate Function&lt;/code&gt;을 &lt;code&gt;CAN_TX&lt;/code&gt;, &lt;code&gt;CAN_RX&lt;/code&gt;로 설정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;코드 생성&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Project Manager&lt;/code&gt;에서 프로젝트 이름과 경로를 설정합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Generate Code&lt;/code&gt; 버튼을 클릭하여 코드를 생성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;CANOpenNode 라이브러리 통합&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CANOpenNode 다운로드 및 프로젝트에 추가&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/CANopenNode/CANopenNode&quot;&gt;CANOpenNode GitHub&lt;/a&gt;에서 라이브러리를 다운로드합니다.&lt;/li&gt;
&lt;li&gt;프로젝트의 &lt;code&gt;Core&lt;/code&gt; 디렉터리 아래에 &lt;code&gt;CANOpenNode&lt;/code&gt; 폴더를 추가합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CAN 드라이버 인터페이스 작성&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CO_driver_STM32.c&lt;/code&gt; 파일을 생성하고 CAN HAL 드라이버를 사용하여 전송 및 수신을 처리하는 코드를 작성합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HAL_CAN_AddTxMessage&lt;/code&gt; 및 &lt;code&gt;HAL_CAN_GetRxMessage&lt;/code&gt; API를 활용하여 CAN 메시지를 송수신합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CANOpenNode 초기화 및 실행&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CO_CANinit()&lt;/code&gt; 함수를 호출하여 CAN 모듈을 초기화합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CO_CANopenInit()&lt;/code&gt;를 호출하여 CANOpen 스택을 초기화합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;while&lt;/code&gt; 루프에서 &lt;code&gt;CO_process()&lt;/code&gt;를 호출하여 CANOpen 프로토콜을 실행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;CAN 메시지 송수신 예제&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;void CAN1_Tx(void) {
    CAN_TxHeaderTypeDef TxHeader;
    uint8_t TxData[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
    uint32_t TxMailbox;

    TxHeader.StdId = 0x123;
    TxHeader.ExtId = 0x01;
    TxHeader.RTR = CAN_RTR_DATA;
    TxHeader.IDE = CAN_ID_STD;
    TxHeader.DLC = 8;
    TxHeader.TransmitGlobalTime = DISABLE;

    if (HAL_CAN_AddTxMessage(&amp;amp;hcan1, &amp;amp;TxHeader, TxData, &amp;amp;TxMailbox) != HAL_OK) {
        // Transmission Error
    }
}

void CAN1_Rx(void) {
    CAN_RxHeaderTypeDef RxHeader;
    uint8_t RxData[8];

    if (HAL_CAN_GetRxMessage(&amp;amp;hcan1, CAN_RX_FIFO0, &amp;amp;RxHeader, RxData) == HAL_OK) {
        // Process received CAN message
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;이 장에서는 STM32CubeIDE와 HAL을 활용하여 CANOpen 노드를 구현하는 방법을 설명하였습니다. CANOpenNode 라이브러리를 활용하여 CAN 메시지를 송수신하고, CANOpen 프로토콜을 적용하는 과정을 살펴보았습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen node</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/785</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-node#entry785comment</comments>
      <pubDate>Tue, 5 Aug 2025 19:55:22 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen 스택 구조 분석</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-stack</link>
      <description>&lt;h2&gt;CANOpen 펌웨어 개발 (STM32F429)&lt;/h2&gt;
&lt;p&gt;CANOpen은 산업 자동화 및 임베디드 시스템에서 널리 사용되는 프로토콜로, STM32F429 마이크로컨트롤러를 활용하여 효율적으로 구현할 수 있습니다. 본 장에서는 STM32CubeIDE와 HAL 라이브러리를 이용하여 CANOpen 펌웨어를 개발하는 방법을 다룹니다.&lt;/p&gt;
&lt;p&gt;STM32F429는 강력한 성능과 다양한 주변 장치를 제공하는 마이크로컨트롤러로, 내장된 CAN(Controller Area Network) 인터페이스를 활용하여 CANOpen 노드를 구현할 수 있습니다. 이를 통해 다양한 산업 환경에서 CANOpen 기반의 통신을 효율적으로 수행할 수 있습니다.&lt;/p&gt;
&lt;p&gt;이 장에서는 먼저 STM32F429의 CAN 인터페이스 설정 방법을 설명한 후, CANOpen 프로토콜을 적용한 펌웨어 개발 과정을 단계별로 안내합니다. 또한, CANOpenNode 및 CANFestival과 같은 오픈소스 라이브러리를 활용하여 보다 쉽게 개발할 수 있는 방법도 다룰 예정입니다.&lt;/p&gt;
&lt;p&gt;CANOpen 펌웨어 개발을 위한 기본적인 개념과 실습을 진행하면서, 실제 산업용 장치에 적용 가능한 CANOpen 기반 펌웨어를 작성하는 방법을 익힐 수 있을 것입니다.&lt;/p&gt;
&lt;h2&gt;CANOpen 스택 구조 분석&lt;/h2&gt;
&lt;p&gt;CANOpen 스택은 CAN 프로토콜을 기반으로 동작하며, 표준화된 통신 규약을 통해 다양한 장치 간의 원활한 데이터 교환을 가능하게 합니다. 본 장에서는 CANOpen 스택의 계층 구조와 주요 구성 요소를 분석하고, STM32F429에서 CANOpen 스택을 구현하기 위한 기본 개념을 설명합니다.&lt;/p&gt;
&lt;h3&gt;CANOpen 스택의 계층 구조&lt;/h3&gt;
&lt;p&gt;CANOpen 스택은 일반적으로 다음과 같은 계층으로 구성됩니다:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;응용 계층 (Application Layer)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;사용자 애플리케이션이 실행되는 부분으로, CANOpen 서비스를 호출하여 데이터 송수신을 수행합니다.&lt;/li&gt;
&lt;li&gt;객체 사전(Object Dictionary)을 통해 노드의 상태 및 데이터를 관리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CANOpen 서비스 계층 (Service Layer)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;네트워크 관리 (NMT), 동기화(SYNC), 시간 스탬프(TIME), PDO(프로세스 데이터 객체), SDO(서비스 데이터 객체) 등을 처리합니다.&lt;/li&gt;
&lt;li&gt;주어진 요청을 처리하고 응답을 생성하는 역할을 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CANOpen 프로토콜 계층 (Protocol Layer)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CAN 프레임 포맷을 정의하고, 노드 간의 데이터 전송을 조정합니다.&lt;/li&gt;
&lt;li&gt;COB-ID(통신 객체 식별자) 할당 및 데이터 우선순위를 관리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;데이터 링크 계층 및 물리 계층 (Data Link &amp;amp; Physical Layer)&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CAN 프로토콜 (ISO 11898) 기반으로 동작하며, 데이터의 전송 및 수신을 담당합니다.&lt;/li&gt;
&lt;li&gt;물리적인 배선, 신호 전송 방식, 오류 검출 등을 처리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;CANOpen 스택의 주요 구성 요소&lt;/h3&gt;
&lt;h4&gt;1. 객체 사전 (Object Dictionary)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;각 노드의 데이터 및 파라미터를 저장하는 테이블 형태의 데이터 구조입니다.&lt;/li&gt;
&lt;li&gt;16비트 인덱스와 8비트 서브인덱스를 통해 접근하며, 노드의 설정 및 상태를 관리합니다.&lt;/li&gt;
&lt;li&gt;주요 데이터 유형: 정수, 부동소수점, 문자열, 배열 등.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. 네트워크 관리 (NMT: Network Management)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;CANOpen 네트워크의 노드 상태를 관리하는 서비스입니다.&lt;/li&gt;
&lt;li&gt;각 노드는 초기화(Initialization), 정지(Stopped), 미운영(Pre-Operational), 운영(Operational) 상태를 가집니다.&lt;/li&gt;
&lt;li&gt;NMT 명령을 통해 네트워크의 활성화 및 제어가 가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. 프로세스 데이터 객체 (PDO: Process Data Object)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;실시간 데이터 전송을 위한 구조이며, 주기적으로 혹은 이벤트 기반으로 데이터가 전송됩니다.&lt;/li&gt;
&lt;li&gt;4바이트에서 8바이트 크기의 데이터가 전송되며, 빠른 응답이 요구되는 시스템에서 사용됩니다.&lt;/li&gt;
&lt;li&gt;TPDO(Transmit PDO)와 RPDO(Receive PDO)로 구분됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;4. 서비스 데이터 객체 (SDO: Service Data Object)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;비주기적인 데이터 전송을 처리하며, 큰 데이터의 읽기 및 쓰기에 사용됩니다.&lt;/li&gt;
&lt;li&gt;요청(Request)과 응답(Response) 방식으로 동작하며, 객체 사전의 항목을 직접 조작할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;5. 동기화 및 시간 관리&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SYNC 메시지&lt;/strong&gt;: 모든 노드의 데이터를 동기화하는 역할을 수행하며, 주기적으로 전송됩니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TIME 메시지&lt;/strong&gt;: CANOpen 네트워크 내에서 시간 동기화를 유지하기 위한 메시지입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;6. 비상 메시지 (Emergency Message)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;노드에서 오류가 발생했을 때 이를 보고하는 메시지입니다.&lt;/li&gt;
&lt;li&gt;빠른 오류 감지 및 복구를 위해 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;STM32F429에서의 CANOpen 스택 구현 개요&lt;/h3&gt;
&lt;p&gt;STM32F429에서 CANOpen 스택을 구현하기 위해서는 다음 요소들이 필요합니다:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CAN 드라이버 설정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32CubeIDE 및 HAL 라이브러리를 사용하여 CAN 통신을 초기화합니다.&lt;/li&gt;
&lt;li&gt;필터 설정 및 인터럽트 핸들링을 구성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CANOpen 스택 라이브러리 활용&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CANopenNode 또는 CANFestival과 같은 오픈소스 CANOpen 스택을 활용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;스택을 포팅하여 STM32 환경에서 동작하도록 조정합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;객체 사전 구성&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32의 EEPROM 또는 플래시 메모리를 이용하여 객체 사전을 저장하고 관리합니다.&lt;/li&gt;
&lt;li&gt;각 노드의 파라미터를 동적으로 설정할 수 있도록 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;NMT 및 SDO/PDO 구현&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NMT 상태 변경을 처리하고, SDO를 통한 데이터 읽기/쓰기 기능을 구현합니다.&lt;/li&gt;
&lt;li&gt;주기적인 PDO 전송을 위한 타이머 설정을 수행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;디버깅 및 테스트&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CAN 분석기 및 디버깅 툴을 이용하여 CAN 메시지를 모니터링하고, 정상 동작 여부를 확인합니다.&lt;/li&gt;
&lt;li&gt;오류 발생 시 비상 메시지를 통한 로그를 남깁니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;본 장에서는 CANOpen 스택의 계층 구조 및 주요 구성 요소를 분석하고, STM32F429에서의 CANOpen 스택 구현을 위한 핵심 개념을 설명하였습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen Stack</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/783</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-stack#entry783comment</comments>
      <pubDate>Mon, 4 Aug 2025 20:08:12 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen 개발 라이브러리 및 툴</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-library-tools</link>
      <description>&lt;h2&gt;CANOpen 개발 라이브러리 및 툴&lt;/h2&gt;
&lt;p&gt;CANOpen을 활용한 임베디드 시스템 개발에서는 효율적인 프로토콜 구현을 위해 오픈소스 라이브러리와 툴을 활용하는 것이 중요합니다. 대표적인 CANOpen 개발 라이브러리로는 &lt;strong&gt;CANopenNode&lt;/strong&gt;와 &lt;strong&gt;CANFestival&lt;/strong&gt;이 있으며, 이들은 다양한 플랫폼에서 CANOpen 프로토콜을 손쉽게 적용할 수 있도록 지원합니다. 본 장에서는 각각의 라이브러리의 특징과 사용법을 설명하고, STM32F429에서의 적용 방법을 다룹니다.&lt;/p&gt;
&lt;h3&gt;CANopenNode&lt;/h3&gt;
&lt;p&gt;CANopenNode는 오픈소스로 제공되는 CANOpen 스택으로, 높은 유연성과 모듈성을 갖춘 것이 특징입니다.&lt;/p&gt;
&lt;h4&gt;주요 특징&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;ANSI C로 구현되어 있어 다양한 마이크로컨트롤러에서 사용 가능&lt;/li&gt;
&lt;li&gt;Object Dictionary 기반의 구조화된 데이터 관리&lt;/li&gt;
&lt;li&gt;기본적인 CANOpen 노드 기능(Heartbeat, NMT, PDO, SDO 등) 지원&lt;/li&gt;
&lt;li&gt;다양한 보드와 MCU에 쉽게 포팅 가능&lt;/li&gt;
&lt;li&gt;GitHub를 통해 지속적인 유지보수 및 업데이트 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;설치 및 구성&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;소스 코드 다운로드&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git clone https://github.com/CANopenNode/CANopenNode.git&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;프로젝트 설정&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CO_driver_target.h&lt;/code&gt; 파일에서 사용자의 하드웨어 환경에 맞게 드라이버 설정&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OD.h&lt;/code&gt; 및 &lt;code&gt;OD.c&lt;/code&gt; 파일을 생성하여 Object Dictionary 구성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;STM32F429에서의 적용&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32CubeIDE에서 프로젝트를 생성하고, CAN 드라이버 설정&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CO_driver_STM32.c&lt;/code&gt; 파일을 작성하여 HAL CAN 드라이버와 연결&lt;/li&gt;
&lt;li&gt;FreeRTOS와 통합하여 멀티태스킹 환경에서 실행 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;CANFestival&lt;/h3&gt;
&lt;p&gt;CANFestival은 또 다른 오픈소스 CANOpen 스택으로, 높은 확장성과 함께 여러 운영체제에서 활용할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;주요 특징&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;동적 Object Dictionary 생성 기능 제공&lt;/li&gt;
&lt;li&gt;다양한 플랫폼 지원 (Linux, Windows, RTOS, Bare-metal)&lt;/li&gt;
&lt;li&gt;XML 기반의 Object Dictionary 관리 기능&lt;/li&gt;
&lt;li&gt;다양한 CAN 인터페이스와 연동 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;설치 및 구성&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;소스 코드 다운로드&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git clone https://github.com/CANFestival/CANFestival.git&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Object Dictionary 생성&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;canod&lt;/code&gt; 도구를 사용하여 XML 기반의 Object Dictionary 생성&lt;/li&gt;
&lt;li&gt;&lt;code&gt;make&lt;/code&gt; 명령어로 Object Dictionary를 C 코드로 변환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;STM32F429에서의 적용&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;STM32CubeIDE에서 프로젝트를 설정하고 CAN 드라이버 구성&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CO_Main.c&lt;/code&gt; 파일에서 CANFestival 라이브러리 초기화 및 실행 코드 추가&lt;/li&gt;
&lt;li&gt;FreeRTOS와 결합하여 실시간 동작 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;비교 및 선택&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;라이브러리&lt;/th&gt;
&lt;th&gt;특징&lt;/th&gt;
&lt;th&gt;장점&lt;/th&gt;
&lt;th&gt;단점&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;CANopenNode&lt;/td&gt;
&lt;td&gt;경량, ANSI C 기반, 다양한 MCU 지원&lt;/td&gt;
&lt;td&gt;유연하고 확장성이 높음&lt;/td&gt;
&lt;td&gt;설정이 다소 복잡&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CANFestival&lt;/td&gt;
&lt;td&gt;XML 기반 Object Dictionary&lt;/td&gt;
&lt;td&gt;설정이 쉬움&lt;/td&gt;
&lt;td&gt;코드 크기가 상대적으로 큼&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;STM32F429 기반의 프로젝트에서는 &lt;strong&gt;CANopenNode&lt;/strong&gt;가 보다 적합한 선택이 될 수 있습니다. 이는 경량화된 구조와 함께 MCU 환경에서의 최적화된 성능을 제공하기 때문입니다. 그러나 XML 기반의 Object Dictionary 관리를 선호하는 경우 &lt;strong&gt;CANFestival&lt;/strong&gt;도 좋은 선택이 될 수 있습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen Library</category>
      <category>CANOpen Tools</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/781</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-library-tools#entry781comment</comments>
      <pubDate>Sun, 3 Aug 2025 11:52:40 +0900</pubDate>
    </item>
    <item>
      <title>CAN 인터페이스 보드 (PEAK, Ixxat, Kvaser 등)</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-interface-board</link>
      <description>&lt;h2&gt;CAN 인터페이스 보드 (PEAK, Ixxat, Kvaser 등)&lt;/h2&gt;
&lt;p&gt;CANOpen 장치를 개발하고 테스트하는 과정에서 PC와 CAN 네트워크 간의 연결이 필요합니다. 이를 위해 다양한 CAN 인터페이스 보드가 활용되며, 대표적인 제품으로 PEAK-System, Ixxat, Kvaser 등의 브랜드가 있습니다. 본 장에서는 각 브랜드별 CAN 인터페이스 보드의 특징과 사용법에 대해 설명하겠습니다.&lt;/p&gt;
&lt;h3&gt;PEAK-System CAN 인터페이스&lt;/h3&gt;
&lt;p&gt;PEAK-System은 산업용 및 연구용 CAN 인터페이스 장치를 제공하는 대표적인 회사 중 하나입니다. 주요 제품으로는 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PCAN-USB&lt;/strong&gt;: USB 인터페이스를 통해 PC와 CAN 네트워크를 연결하는 장치로, 사용이 간편하며 다양한 소프트웨어와 호환됩니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PCAN-PCI&lt;/strong&gt;: PCI 슬롯을 통해 CAN 네트워크에 접속할 수 있는 보드로, 데스크톱 환경에서 사용됩니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PCAN-USB Pro&lt;/strong&gt;: CAN과 LIN 네트워크를 동시에 지원하는 제품으로, 보다 다양한 환경에서 활용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PEAK-System에서 제공하는 &lt;strong&gt;PCAN-View&lt;/strong&gt; 소프트웨어를 사용하면, CAN 메시지를 송수신하고 네트워크 상태를 모니터링할 수 있습니다.&lt;/p&gt;
&lt;h3&gt;Ixxat CAN 인터페이스&lt;/h3&gt;
&lt;p&gt;Ixxat는 HMS Networks에서 제공하는 CAN 인터페이스 브랜드로, 산업용 자동화 및 차량 네트워크 애플리케이션에서 널리 사용됩니다. 대표적인 제품은 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;USB-to-CAN V2&lt;/strong&gt;: USB 기반의 CAN 인터페이스로, 다양한 애플리케이션에서 사용 가능합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CAN@net NT&lt;/strong&gt;: 이더넷과 CAN 네트워크를 연결하는 제품으로, 원격으로 CAN 장치를 관리할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CAN-IB&lt;/strong&gt;: PCIe 기반의 CAN 인터페이스 카드로, 산업용 시스템에서 활용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ixxat는 &lt;strong&gt;canAnalyser&lt;/strong&gt; 소프트웨어를 제공하여 CAN 네트워크를 분석하고 디버깅할 수 있도록 지원합니다.&lt;/p&gt;
&lt;h3&gt;Kvaser CAN 인터페이스&lt;/h3&gt;
&lt;p&gt;Kvaser는 고성능 CAN 인터페이스 솔루션을 제공하는 스웨덴 기반 회사로, 자동차 및 산업 자동화 분야에서 널리 활용됩니다. 대표적인 제품은 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Kvaser Leaf Light&lt;/strong&gt;: USB 기반의 CAN 인터페이스로, 경제적이면서도 신뢰성이 높은 솔루션입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kvaser Memorator&lt;/strong&gt;: CAN 데이터 로깅 기능이 포함된 제품으로, 독립적으로 CAN 데이터를 저장할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Kvaser PCIe&lt;/strong&gt;: 고속 데이터 전송이 필요한 환경에서 사용되는 PCIe 기반의 CAN 인터페이스 보드입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Kvaser는 자체 개발한 &lt;strong&gt;Kvaser CANlib&lt;/strong&gt;를 통해 다양한 프로그래밍 인터페이스를 제공하며, 사용자가 직접 CAN 메시지를 제어하고 분석할 수 있도록 지원합니다.&lt;/p&gt;
&lt;h3&gt;CAN 인터페이스 보드 선택 기준&lt;/h3&gt;
&lt;p&gt;각 브랜드의 CAN 인터페이스 보드는 용도와 요구 사항에 따라 선택할 수 있습니다. 다음과 같은 요소를 고려하여 적절한 제품을 선택하는 것이 중요합니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;연결 방식&lt;/strong&gt;: USB, PCIe, 이더넷 등 네트워크 환경에 적합한 인터페이스 선택&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;지원 프로토콜&lt;/strong&gt;: CAN, CAN FD, LIN 등 필요한 프로토콜을 지원하는지 확인&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;소프트웨어 호환성&lt;/strong&gt;: 제공되는 소프트웨어 및 드라이버의 호환성 검토&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;실시간 성능 요구사항&lt;/strong&gt;: 산업용 환경에서의 실시간 데이터 처리 요구사항 충족 여부&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;추가 기능&lt;/strong&gt;: 데이터 로깅, 원격 연결 등의 부가 기능 지원 여부&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;본 장에서는 PEAK-System, Ixxat, Kvaser의 주요 CAN 인터페이스 보드와 사용 방법을 소개하였으며, 각 제품의 특성과 활용 방법을 비교하였습니다. 이후 실습 과정에서는 STM32F429를 이용하여 CANOpen 네트워크를 구축하고, 다양한 CAN 인터페이스 보드를 활용하여 통신 테스트를 진행할 예정입니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen Interface Board</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/779</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-interface-board#entry779comment</comments>
      <pubDate>Sat, 2 Aug 2025 17:52:00 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen을 지원하는 주요 MCU 및 모듈</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-mcu</link>
      <description>&lt;h2&gt;CANOpen을 지원하는 주요 MCU 및 모듈&lt;/h2&gt;
&lt;p&gt;CANOpen을 구현하기 위해서는 CAN 통신을 지원하는 하드웨어가 필요합니다. 다양한 MCU 및 모듈이 CANOpen을 지원하며, 본 장에서는 대표적인 MCU 및 모듈을 소개하고 특징을 설명하겠습니다.&lt;/p&gt;
&lt;h2&gt;STM32 시리즈&lt;/h2&gt;
&lt;p&gt;STM32 시리즈는 STMicroelectronics에서 제공하는 32비트 ARM Cortex 기반의 MCU로, 다양한 제품군에서 CAN 및 CAN FD를 지원합니다. 특히, STM32F4 시리즈는 성능과 확장성이 뛰어나며, CANOpen 프로토콜을 구현하는 데 적합합니다.&lt;/p&gt;
&lt;h3&gt;STM32F429&lt;/h3&gt;
&lt;p&gt;STM32F429는 강력한 성능과 다양한 주변 장치를 갖춘 MCU로, CAN2.0B를 지원합니다. STM32CubeIDE 및 HAL 라이브러리를 활용하여 CANOpen을 구현할 수 있으며, 듀얼 CAN 컨트롤러를 제공하여 여러 개의 CAN 네트워크를 동시에 관리할 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;주요 특징&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;ARM Cortex-M4 기반 (최대 180MHz 동작 속도)&lt;/li&gt;
&lt;li&gt;듀얼 CAN2.0B 컨트롤러 지원&lt;/li&gt;
&lt;li&gt;DMA와 결합된 CAN 필터 기능 제공&lt;/li&gt;
&lt;li&gt;저전력 모드에서 CAN 통신 가능&lt;/li&gt;
&lt;li&gt;다양한 인터페이스 지원 (SPI, I2C, UART 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;STM32F429를 활용한 CANOpen 개발은 ST의 CubeMX 및 HAL 라이브러리를 이용하면 쉽게 설정할 수 있으며, FreeRTOS와 결합하여 실시간 운영 환경에서도 동작 가능합니다.&lt;/p&gt;
&lt;h3&gt;기타 STM32 시리즈&lt;/h3&gt;
&lt;p&gt;STM32F0, STM32F3, STM32F7, STM32H7 시리즈도 CAN을 지원하는 모델이 있으며, 애플리케이션의 요구 사항에 따라 적절한 MCU를 선택할 수 있습니다.&lt;/p&gt;
&lt;h2&gt;nRF52840&lt;/h2&gt;
&lt;p&gt;Nordic Semiconductor의 nRF52840은 Bluetooth 5 및 Thread, Zigbee 등을 지원하는 저전력 MCU이지만, CAN 통신도 가능합니다. 외부 CAN 트랜시버와 결합하여 CANOpen을 지원할 수 있으며, nRF5 SDK를 활용하면 다양한 프로토콜과 함께 사용할 수 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;주요 특징&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;ARM Cortex-M4 기반 (64MHz 동작 속도)&lt;/li&gt;
&lt;li&gt;저전력 BLE 및 Mesh 네트워크 지원&lt;/li&gt;
&lt;li&gt;CAN 지원을 위한 외부 트랜시버 필요&lt;/li&gt;
&lt;li&gt;강력한 보안 기능 (AES-128, SHA-256, ECC 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;nRF52840은 저전력 IoT 장치에서 CANOpen을 구현할 때 유용하며, 특히 무선 통신과 함께 사용할 경우 유연한 네트워크 구성이 가능합니다.&lt;/p&gt;
&lt;h2&gt;Microchip(Atmel) 제품군&lt;/h2&gt;
&lt;p&gt;Microchip의 AT90CAN, SAMC21 시리즈 등도 CAN을 지원하며, CANOpen을 쉽게 구현할 수 있습니다. 특히, SAMC21은 Cortex-M0+ 기반으로 저전력 애플리케이션에 적합하며, 산업용 자동화 및 로봇 시스템에 널리 사용됩니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;주요 특징&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;CAN FD 지원 (일부 모델)&lt;/li&gt;
&lt;li&gt;저전력 설계&lt;/li&gt;
&lt;li&gt;산업용 표준 인터페이스 지원&lt;/li&gt;
&lt;li&gt;Microchip MPLAB 및 Atmel Studio 개발 환경 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Texas Instruments(TI) C2000 시리즈&lt;/h2&gt;
&lt;p&gt;Texas Instruments의 C2000 시리즈는 실시간 제어 애플리케이션에 최적화된 MCU로, CAN 및 CAN FD를 지원합니다. 특히, 산업 자동화 및 전력 제어 시스템에서 CANOpen을 구현하는 데 적합합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;주요 특징&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;고성능 DSP 기능 제공 (Cortex-M4 기반)&lt;/li&gt;
&lt;li&gt;CAN FD 지원&lt;/li&gt;
&lt;li&gt;고속 ADC 및 PWM 제어 기능&lt;/li&gt;
&lt;li&gt;TI의 Code Composer Studio(CCS) 개발 환경 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;결론&lt;/h2&gt;
&lt;p&gt;CANOpen을 지원하는 다양한 MCU 및 모듈이 있으며, 애플리케이션의 요구 사항에 맞춰 적절한 하드웨어를 선택하는 것이 중요합니다. STM32F429는 강력한 성능과 널리 사용되는 개발 환경을 제공하며, nRF52840은 저전력 무선 통신과 함께 활용할 수 있습니다. 또한, Microchip과 TI의 제품군도 CANOpen을 구현하는 데 유용하게 활용될 수 있습니다. 각 MCU의 특성을 이해하고, 개발 환경과 애플리케이션 요구 사항에 맞는 최적의 솔루션을 선택하는 것이 CANOpen 개발의 핵심입니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen MCU</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/777</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-mcu#entry777comment</comments>
      <pubDate>Fri, 1 Aug 2025 21:31:24 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen 개발을 위한 하드웨어 및 소프트웨어</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-dev-env</link>
      <description>&lt;h2&gt;CANOpen 개발 환경 구축&lt;/h2&gt;
&lt;p&gt;CANOpen 장치를 개발하기 위해서는 적절한 개발 환경을 구축하는 것이 중요합니다. 본 장에서는 STM32F429 보드를 활용하여 CANOpen 장치를 개발할 수 있도록 STM32CubeIDE 및 HAL 라이브러리를 기반으로 개발 환경을 설정하는 방법을 설명합니다. 또한, CANOpen 통신을 테스트할 수 있는 도구와 설정 방법도 함께 다룹니다.&lt;/p&gt;
&lt;p&gt;개발 환경을 구성하는 주요 요소로는 다음과 같은 항목이 포함됩니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;STM32CubeIDE&lt;/strong&gt;: STM32 마이크로컨트롤러 개발을 위한 공식 개발 환경&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;STM32 HAL 라이브러리&lt;/strong&gt;: STM32 하드웨어를 제어하기 위한 HAL API&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CAN 통신 설정&lt;/strong&gt;: STM32F429의 CAN 모듈을 설정하고 초기화하는 방법&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CANOpen 프로토콜 스택&lt;/strong&gt;: CANOpen 프로토콜을 구현하는 소프트웨어 스택 활용&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;테스트 및 디버깅 도구&lt;/strong&gt;: CAN 분석기 및 시뮬레이션 도구를 이용한 테스트 환경 구축&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이 장을 통해 독자들은 CANOpen 장치를 개발하기 위한 기본적인 개발 환경을 구축하고, CANOpen 통신을 설정하는 방법을 익힐 수 있습니다.&lt;/p&gt;
&lt;h2&gt;CANOpen 개발을 위한 하드웨어 및 소프트웨어&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;CANOpen 시스템을 개발하기 위해서는 적절한 하드웨어와 소프트웨어 환경이 필요합니다. 본 장에서는 CANOpen을 구현하기 위한 하드웨어 구성 요소와 소프트웨어 도구에 대해 설명합니다.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;CANOpen 개발을 위한 하드웨어 구성&lt;/h3&gt;
&lt;p&gt;CANOpen을 개발하기 위해서는 CAN 인터페이스를 갖춘 MCU 및 주변 장치가 필요합니다. 다음은 주요 하드웨어 구성 요소입니다.&lt;/p&gt;
&lt;h4&gt;1. 마이크로컨트롤러 (MCU)&lt;/h4&gt;
&lt;p&gt;CANOpen을 지원하는 MCU는 통합 CAN 컨트롤러를 포함하고 있어야 합니다. 대표적인 MCU로는 다음과 같은 제품이 있습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;STM32F429&lt;/strong&gt;: Cortex-M4 기반의 MCU로, CAN1 및 CAN2 인터페이스를 내장하고 있습니다. STM32CubeIDE 및 HAL 라이브러리를 이용하여 CANOpen을 구현할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NXP LPC 시리즈&lt;/strong&gt;: CANOpen을 지원하는 다양한 제품군이 있으며, NXP의 MCUXpresso 환경을 활용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TI TMS320F 시리즈&lt;/strong&gt;: 고성능 실시간 제어 기능을 갖춘 MCU로, CAN 및 CANOpen 스택을 지원합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. CAN 트랜시버&lt;/h4&gt;
&lt;p&gt;MCU의 CAN 컨트롤러는 직접 물리적인 CAN 네트워크와 연결될 수 없으며, CAN 트랜시버를 통해 신호를 변환해야 합니다. 대표적인 CAN 트랜시버는 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MCP2551&lt;/strong&gt;: Microchip에서 제공하는 CAN 트랜시버로, 1 Mbps 속도를 지원합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SN65HVD230&lt;/strong&gt;: Texas Instruments의 저전력 CAN 트랜시버로, 3.3V 및 5V 동작이 가능합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TJA1050&lt;/strong&gt;: NXP의 고속 CAN 트랜시버로, 산업용 애플리케이션에 적합합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. 전원 및 보호 회로&lt;/h4&gt;
&lt;p&gt;CANOpen 장치는 안정적인 전원 공급과 함께 ESD 및 과전압 보호 회로를 갖추어야 합니다. 일반적으로 다음과 같은 보호 장치를 사용합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;TVS 다이오드&lt;/strong&gt;: 서지 보호를 위해 사용됨&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;폴리퓨즈&lt;/strong&gt;: 과전류 보호 기능 제공&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EMI 필터&lt;/strong&gt;: 전자기 간섭을 줄이기 위한 필터링 기능 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;CANOpen 개발을 위한 소프트웨어 환경&lt;/h3&gt;
&lt;p&gt;CANOpen 시스템을 개발하기 위해서는 적절한 소프트웨어 개발 환경이 필요합니다. 다음은 주요 개발 도구 및 라이브러리입니다.&lt;/p&gt;
&lt;h4&gt;1. 개발 환경 (IDE)&lt;/h4&gt;
&lt;p&gt;CANOpen을 개발하기 위해 사용하는 주요 IDE는 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;STM32CubeIDE&lt;/strong&gt;: STMicroelectronics에서 제공하는 무료 통합 개발 환경으로, HAL 라이브러리를 통해 CAN 기능을 손쉽게 구현할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Keil MDK-ARM&lt;/strong&gt;: ARM Cortex-M 기반 MCU 개발을 위한 강력한 IDE로, CAN 드라이버 및 미들웨어 지원이 우수합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IAR Embedded Workbench&lt;/strong&gt;: 코드 최적화 기능이 뛰어나며, 다양한 MCU를 지원하는 강력한 개발 환경입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. 펌웨어 라이브러리 및 스택&lt;/h4&gt;
&lt;p&gt;CANOpen을 지원하는 라이브러리 및 스택을 사용하면 개발을 보다 효율적으로 진행할 수 있습니다. 대표적인 CANOpen 스택은 다음과 같습니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CANOpenNode&lt;/strong&gt;: 오픈소스 기반의 CANOpen 스택으로, 다양한 MCU에서 사용 가능합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Micro CANOpen&lt;/strong&gt;: 경량 CANOpen 구현체로, 리소스가 제한된 임베디드 시스템에 적합합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ST HAL 및 LL 드라이버&lt;/strong&gt;: STM32Cube HAL 및 Low-Layer 드라이버를 활용하여 CAN 기능을 직접 구현할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. 디버깅 및 분석 도구&lt;/h4&gt;
&lt;p&gt;CANOpen 네트워크의 상태를 확인하고 디버깅하기 위해서는 다음과 같은 도구가 필요합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PCAN-View&lt;/strong&gt;: Peak Systems에서 제공하는 CAN 메시지 모니터링 및 분석 도구&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CANalyzer&lt;/strong&gt;: Vector社의 강력한 CAN 분석 도구로, CANOpen 프로토콜을 상세히 분석할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;BusMaster&lt;/strong&gt;: 오픈소스 CAN 네트워크 모니터링 도구로, 기본적인 CAN 메시지 로깅 및 디버깅 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;CANOpen 개발을 위해서는 적절한 MCU, 트랜시버, 보호 회로 등의 하드웨어와 함께, 개발 환경 및 CANOpen 스택을 활용한 소프트웨어 구성이 필수적입니다. 본 장에서 소개한 하드웨어 및 소프트웨어 도구를 기반으로 CANOpen 시스템을 구축할 수 있습니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen Development Environment</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/775</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-dev-env#entry775comment</comments>
      <pubDate>Thu, 31 Jul 2025 20:10:42 +0900</pubDate>
    </item>
    <item>
      <title>CANOpen 오류 메시지 (EMCY) 분석 및 처리 방법</title>
      <link>https://coding-by-head.tistory.com/entry/canopen-emcy-1</link>
      <description>&lt;h2&gt;CANOpen 오류 메시지 (EMCY) 분석 및 처리 방법&lt;/h2&gt;
&lt;h3&gt;개요&lt;/h3&gt;
&lt;p&gt;CANOpen 프로토콜에서 오류 메시지(EMCY, Emergency Message)는 장치에서 발생한 오류를 신속하게 네트워크에 전파하는 중요한 기능입니다. EMCY 메시지는 장치의 상태를 모니터링하고, 오류 발생 시 적절한 대응을 수행할 수 있도록 도와줍니다. 본 장에서는 CANOpen의 EMCY 메시지 형식, 발생 조건, 분석 방법 및 처리 방안을 다룹니다.&lt;/p&gt;
&lt;h3&gt;EMCY 메시지 개요&lt;/h3&gt;
&lt;p&gt;EMCY 메시지는 CANOpen 네트워크에서 특정 장치가 오류를 감지했을 때, 이를 다른 장치에 알리는 역할을 합니다. EMCY 메시지는 일반적으로 짧고, 고정된 길이의 CAN 메시지로 구성됩니다.&lt;/p&gt;
&lt;h4&gt;EMCY 메시지 구조&lt;/h4&gt;
&lt;p&gt;EMCY 메시지는 8바이트 데이터 필드를 포함하는 CAN 메시지이며, 다음과 같은 형식을 가집니다.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;바이트&lt;/th&gt;
&lt;th&gt;내용&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;0-1&lt;/td&gt;
&lt;td&gt;오류 코드&lt;/td&gt;
&lt;td&gt;16비트 오류 코드 (Error Code)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;오류 등록 값&lt;/td&gt;
&lt;td&gt;특정 오류의 추가 정보를 제공&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3-7&lt;/td&gt;
&lt;td&gt;제조사별 데이터&lt;/td&gt;
&lt;td&gt;제조사가 정의하는 추가 정보&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;오류 코드(Error Code)&lt;/strong&gt;: EMCY 메시지의 주요 부분으로, 발생한 오류의 유형을 나타내는 16비트 값입니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;오류 등록 값(Error Register)&lt;/strong&gt;: CANOpen 장치의 오류 상태를 나타내는 8비트 필드로, 장치가 어떤 범주의 오류를 경험하고 있는지 표시합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;제조사별 데이터&lt;/strong&gt;: 제조사가 장치의 특정 오류를 보다 상세하게 표현할 수 있도록 정의하는 부분입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;EMCY 메시지의 송신 조건&lt;/h3&gt;
&lt;p&gt;CANOpen 장치는 다음과 같은 경우에 EMCY 메시지를 전송합니다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;하드웨어 오류 발생 시&lt;/strong&gt;: 센서 오류, 통신 모듈 장애 등&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;소프트웨어 오류 발생 시&lt;/strong&gt;: 펌웨어 실행 중 예외 상황 발생&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;전압 이상 감지 시&lt;/strong&gt;: 전원 공급 장치의 문제 발생&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;통신 오류 발생 시&lt;/strong&gt;: CAN 버스 장애 또는 데이터 전송 오류&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;EMCY 메시지 분석 방법&lt;/h3&gt;
&lt;p&gt;EMCY 메시지를 분석하려면, CAN 분석 툴을 활용하여 네트워크에서 전송된 CAN 메시지를 확인해야 합니다. 일반적인 분석 절차는 다음과 같습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;CAN 메시지 캡처&lt;/strong&gt;: CAN 분석기(예: PCAN-View, CANalyzer)를 이용하여 CANOpen 네트워크의 CAN 메시지를 캡처합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;EMCY 메시지 필터링&lt;/strong&gt;: CANOpen EMCY 메시지의 CAN ID 범위를 기반으로 필터링하여 해당 메시지를 추출합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;오류 코드 확인&lt;/strong&gt;: 수신된 EMCY 메시지의 첫 2바이트를 확인하여 오류 코드 값을 해석합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;오류 등록 값 분석&lt;/strong&gt;: 오류의 종류를 보다 상세하게 분석하기 위해 오류 등록 값을 참고합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;제조사별 데이터 활용&lt;/strong&gt;: 추가적인 정보가 필요한 경우 제조사 문서를 참고하여 특정 오류를 해석합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;예제: EMCY 메시지 분석&lt;/h4&gt;
&lt;p&gt;다음은 EMCY 메시지를 캡처한 예제입니다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CAN 메시지 예제:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ID: 0x80
Data: 0x23 0x01 0x04 0x00 0x00 0x00 0x00 0x00&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;오류 코드 (0x0123)&lt;/strong&gt;: 특정 센서 오류 발생&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;오류 등록 값 (0x04)&lt;/strong&gt;: 전원 이상 오류&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;제조사별 데이터 (0x00 0x00 0x00 0x00 0x00)&lt;/strong&gt;: 추가 정보 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;EMCY 메시지 처리 방안&lt;/h3&gt;
&lt;p&gt;EMCY 메시지가 수신되었을 때, 이를 적절히 처리하는 방법은 다음과 같습니다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;오류 코드 매핑&lt;/strong&gt;: 수신된 오류 코드에 대한 사전 정의된 오류 목록을 기반으로 의미를 해석합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;적절한 대응 수행&lt;/strong&gt;: &lt;ul&gt;
&lt;li&gt;경미한 오류의 경우: 로그 기록 및 모니터링 유지&lt;/li&gt;
&lt;li&gt;치명적인 오류의 경우: 장치 동작 중지 또는 재시작&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;오류 발생 보고&lt;/strong&gt;: 상위 컨트롤러 또는 운영 소프트웨어에 오류 발생 사실을 보고합니다.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;자동 복구 시도&lt;/strong&gt;: 일부 오류의 경우, 소프트웨어적으로 자동 복구를 시도할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;STM32에서 EMCY 메시지 처리 구현&lt;/h3&gt;
&lt;p&gt;STM32F429 기반의 CANOpen 노드에서 EMCY 메시지를 처리하는 예제 코드를 살펴보겠습니다. STM32CubeIDE와 HAL 라이브러리를 이용하여 EMCY 메시지를 송수신하는 코드를 구현할 수 있습니다.&lt;/p&gt;
&lt;h4&gt;EMCY 메시지 송신 예제&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;#include &amp;quot;can.h&amp;quot;

void Send_EMCY_Message(uint16_t error_code, uint8_t error_register) {
    CAN_TxHeaderTypeDef TxHeader;
    uint8_t TxData[8] = {0};
    uint32_t TxMailbox;

    TxHeader.StdId = 0x80;  // EMCY 메시지 ID
    TxHeader.DLC = 8;       // 데이터 길이
    TxHeader.IDE = CAN_ID_STD;
    TxHeader.RTR = CAN_RTR_DATA;

    TxData[0] = error_code &amp;amp; 0xFF;
    TxData[1] = (error_code &amp;gt;&amp;gt; 8) &amp;amp; 0xFF;
    TxData[2] = error_register;

    if (HAL_CAN_AddTxMessage(&amp;amp;hcan1, &amp;amp;TxHeader, TxData, &amp;amp;TxMailbox) != HAL_OK) {
        // 오류 처리 코드
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;EMCY 메시지 수신 및 분석 예제&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-c&quot;&gt;void CAN_Rx_Callback(CAN_RxHeaderTypeDef *RxHeader, uint8_t *RxData) {
    if (RxHeader-&amp;gt;StdId == 0x80) { // EMCY 메시지 확인
        uint16_t error_code = RxData[0] | (RxData[1] &amp;lt;&amp;lt; 8);
        uint8_t error_register = RxData[2];

        // 오류 코드 해석 및 처리
        Process_EMCY_Message(error_code, error_register);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;p&gt;CANOpen 네트워크에서 EMCY 메시지는 오류 발생 시 신속한 대응을 가능하게 하는 중요한 기능입니다. 이를 효과적으로 분석하고 처리함으로써 시스템의 안정성과 신뢰성을 향상시킬 수 있습니다. STM32F429 기반의 CANOpen 장치에서도 HAL 라이브러리를 활용하여 EMCY 메시지를 송수신하고, 이를 적절히 처리하는 것이 중요합니다.&lt;/p&gt;</description>
      <category>Industrial Communication/CANopen: Distributed Control Stack</category>
      <category>CANOpen EMCY</category>
      <author>임베디드 친구</author>
      <guid isPermaLink="true">https://coding-by-head.tistory.com/773</guid>
      <comments>https://coding-by-head.tistory.com/entry/canopen-emcy-1#entry773comment</comments>
      <pubDate>Wed, 30 Jul 2025 20:12:37 +0900</pubDate>
    </item>
  </channel>
</rss>