데이터 전송 중 비트 에러 날 수 있다.

CRC로 무결성 검증하자.


CRC32

가장 널리 쓰는 CRC-32 (IEEE 802.3).

다항식: 0x04C11DB7
초기값: 0xFFFFFFFF
XOR 출력: 0xFFFFFFFF

소프트웨어 CRC

static const uint32_t crc32_table[256] = {
    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
    // ... 256개 테이블
};

uint32_t crc32_calc(uint8_t *data, uint32_t len) {
    uint32_t crc = 0xFFFFFFFF;
    
    for (uint32_t i = 0; i < len; i++) {
        uint8_t idx = (crc ^ data[i]) & 0xFF;
        crc = (crc >> 8) ^ crc32_table[idx];
    }
    
    return crc ^ 0xFFFFFFFF;
}

점진적 CRC

한 번에 계산 안 하고 데이터 받을 때마다:

uint32_t crc32_update(uint32_t crc, uint8_t *data, uint32_t len) {
    for (uint32_t i = 0; i < len; i++) {
        uint8_t idx = (crc ^ data[i]) & 0xFF;
        crc = (crc >> 8) ^ crc32_table[idx];
    }
    return crc;
}

uint32_t crc32_final(uint32_t crc) {
    return crc ^ 0xFFFFFFFF;
}

// 사용
iap.crc = 0xFFFFFFFF;
iap.crc = crc32_update(iap.crc, data, len);  // 매 패킷
uint32_t final = crc32_final(iap.crc);       // 마지막에

STM32 내장 CRC

STM32에 CRC 하드웨어 있음:

// CRC 클럭 활성화
__HAL_RCC_CRC_CLK_ENABLE();

// 리셋
CRC->CR = CRC_CR_RESET;

// 계산 (Word 단위)
for (uint32_t i = 0; i < len/4; i++) {
    CRC->DR = ((uint32_t *)data)[i];
}

uint32_t crc = CRC->DR;

근데 STM32F103 내장 CRC는 다항식이 다름. 호환 안 될 수 있음.

소프트웨어 CRC가 호환성 좋음.


검증 단계

1. 페이지 단위 CRC

매 페이지 전송 후 CRC 체크:

PC:  PAGE_END + CRC(페이지 데이터)
BMS: CRC 비교 → 틀리면 재요청

2. 전체 CRC

모든 페이지 수신 후 전체 검증:

void iap_start_verify(void) {
    // Buffer 영역 전체 CRC 계산
    uint32_t calc = crc32_calc((uint8_t *)BUFFER_ADDR, iap.fw_size);
    
    // PC에게 검증 시작 알림
    uint8_t resp[1] = {RESP_VERIFY_START};
    can_send(CAN_ID_BMS_TO_PC, resp, 1);
    
    // 계산된 CRC 전송 (PC가 가진 값과 비교)
    uint8_t crc_msg[5] = {RESP_VERIFY_OK};
    memcpy(&crc_msg[1], &calc, 4);
    can_send(CAN_ID_BMS_TO_PC, crc_msg, 5);
    
    iap.state = IAP_COMPLETE;
}

Buffer → App 복사

검증 통과하면 복사:

void iap_copy_to_app(void) {
    flash_unlock();
    
    // App 영역 삭제
    for (uint32_t addr = APP_ADDR; addr < APP_ADDR + iap.fw_size; addr += PAGE_SIZE) {
        flash_erase_page(addr);
    }
    
    // Buffer → App 복사
    uint8_t *src = (uint8_t *)BUFFER_ADDR;
    for (uint32_t i = 0; i < iap.fw_size; i += 2) {
        uint16_t data = src[i] | (src[i+1] << 8);
        flash_program_halfword(APP_ADDR + i, data);
    }
    
    flash_lock();
}

에러 복구

복사 중 에러나면?

Buffer에 펌웨어 아직 있음. 재부팅 후 다시 복사 시도 가능.


다음 글에서 Python 업로더.

#17 - Python 업로더