IAP 프로토콜 분석 결과를 소스코드로 복원한다.


can_iap.h

#ifndef CAN_IAP_H
#define CAN_IAP_H

#define IAP_RX_ID       0x5FF
#define IAP_TX_ID       0x5FE

#define CMD_CONNECT     0x30
#define CMD_KEY         0x31
#define CMD_SIZE        0x32
#define CMD_DATA        0x33
#define CMD_PAGE_END    0x34
#define CMD_VERIFY      0x35
#define CMD_JUMP        0x36

#define RSP_CONNECT     0x40
#define RSP_KEY         0x41
#define RSP_SIZE        0x42
#define RSP_DATA        0x43
#define RSP_PAGE_END    0x44
#define RSP_VERIFY      0x45
#define RSP_JUMP        0x46
#define RSP_ERROR       0x4F

typedef enum {
    STATE_IDLE = 0,
    STATE_WAIT_KEY,
    STATE_CONNECTED,
    STATE_WAIT_DATA,
    STATE_PROGRAMMING,
    STATE_VERIFY,
    STATE_COMPLETE
} IAP_State_t;

void CAN_Init(void);
void IAP_Process(void);

extern volatile uint8_t g_iap_complete;

#endif

CAN 초기화

void CAN_Init(void) {
    // 클럭 활성화
    RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;
    RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
    
    // CAN GPIO (PA11: RX, PA12: TX)
    GPIOA->CRH &= ~0x000FF000;
    GPIOA->CRH |= 0x000B8000;  // TX: AF PP, RX: Input
    
    // 초기화 모드 진입
    CAN1->MCR |= CAN_MCR_INRQ;
    while (!(CAN1->MSR & CAN_MSR_INAK));
    
    // 500kbps (36MHz / 4 / 18 = 500k)
    CAN1->BTR = 0x001C0003;
    
    // 필터 설정 (모든 ID 수신)
    CAN1->FMR |= CAN_FMR_FINIT;
    CAN1->FA1R |= 0x01;
    CAN1->sFilterRegister[0].FR1 = 0;
    CAN1->sFilterRegister[0].FR2 = 0;
    CAN1->FMR &= ~CAN_FMR_FINIT;
    
    // Normal 모드
    CAN1->MCR &= ~CAN_MCR_INRQ;
    while (CAN1->MSR & CAN_MSR_INAK);
    
    // RX 인터럽트 활성화
    CAN1->IER |= CAN_IER_FMPIE0;
    NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
}

메시지 처리

void IAP_Process(void) {
    if (!g_msg_pending) return;
    g_msg_pending = 0;
    
    uint8_t cmd = g_rx_data[0];
    
    switch (g_iap_state) {
    case STATE_IDLE:
        if (cmd == CMD_CONNECT) Handle_Connect();
        break;
        
    case STATE_WAIT_KEY:
        if (cmd == CMD_KEY) Handle_Key();
        break;
        
    case STATE_CONNECTED:
        if (cmd == CMD_SIZE) Handle_Size();
        break;
        
    case STATE_WAIT_DATA:
        Handle_Data();
        break;
        
    case STATE_VERIFY:
        if (cmd == CMD_VERIFY) Handle_Verify();
        break;
        
    case STATE_COMPLETE:
        if (cmd == CMD_JUMP) Handle_Jump();
        break;
    }
}

핵심 핸들러

void Handle_Connect(void) {
    uint8_t resp[8];
    resp[0] = RSP_CONNECT;
    memcpy(&resp[1], g_fw_check, 4);
    memcpy(&resp[5], g_fw_date, 3);
    
    CAN_Send(resp, 8);
    g_iap_state = STATE_WAIT_KEY;
}

void Handle_Key(void) {
    uint32_t rx_key = *(uint32_t *)&g_rx_data[1];
    uint32_t calc_key = CalcKey();
    
    if (rx_key == calc_key) {
        CAN_Send_Byte(RSP_KEY);
        g_iap_state = STATE_CONNECTED;
    } else {
        CAN_Send_Byte(RSP_ERROR);
        g_iap_state = STATE_IDLE;
    }
}

다음 글에서 Flash 드라이버 복원.

#29 - Flash 드라이버 복원