이제 실제로 펌웨어 데이터를 받아서 Flash에 쓰자.
버퍼 전략
RAM에 페이지 버퍼:
#define PAGE_SIZE 2048
uint8_t page_buffer[PAGE_SIZE];
uint32_t page_offset = 0;
8바이트씩 받아서 버퍼에 채움. 페이지 다 차면 Flash에 씀.
데이터 수신
void iap_handle_data(uint8_t *data, uint8_t len) {
if (iap.state != IAP_RECEIVING) return;
// 버퍼에 복사
if (page_offset + len <= PAGE_SIZE) {
memcpy(&page_buffer[page_offset], data, len);
page_offset += len;
// CRC 업데이트
iap.crc = crc32_update(iap.crc, data, len);
}
}
페이지 끝 처리
void iap_handle_page_end(uint8_t *data) {
// PC가 보낸 CRC
uint32_t pc_crc;
memcpy(&pc_crc, &data[1], 4);
// CRC 비교
if (iap.crc != pc_crc) {
iap_send_error(ERR_CRC);
// 페이지 재요청
iap_request_page(iap.current_page);
return;
}
// Flash에 쓰기
uint32_t addr = BUFFER_ADDR + (iap.current_page * PAGE_SIZE);
flash_unlock();
if (!flash_erase_page(addr)) {
iap_send_error(ERR_FLASH);
flash_lock();
return;
}
if (!flash_program_buffer(addr, page_buffer, page_offset)) {
iap_send_error(ERR_FLASH);
flash_lock();
return;
}
flash_lock();
// 다음 페이지
iap.current_page++;
iap.received += page_offset;
page_offset = 0;
iap.crc = 0xFFFFFFFF;
// ACK
uint8_t resp[3] = {RESP_PAGE_ACK};
resp[1] = iap.current_page & 0xFF;
resp[2] = (iap.current_page >> 8) & 0xFF;
can_send(CAN_ID_BMS_TO_PC, resp, 3);
// 다 받았나?
if (iap.received >= iap.fw_size) {
iap.state = IAP_VERIFYING;
iap_start_verify();
} else {
iap_request_page(iap.current_page);
}
}
페이지 요청
void iap_request_page(uint16_t page_num) {
uint8_t req[3] = {RESP_PAGE_REQ};
req[1] = page_num & 0xFF;
req[2] = (page_num >> 8) & 0xFF;
can_send(CAN_ID_BMS_TO_PC, req, 3);
// 버퍼 초기화
memset(page_buffer, 0xFF, PAGE_SIZE);
page_offset = 0;
iap.crc = 0xFFFFFFFF;
}
진행률
uint8_t get_progress(void) {
if (iap.fw_size == 0) return 0;
return (iap.received * 100) / iap.fw_size;
}
LED 깜빡이거나 CAN으로 진행률 전송 가능.
속도
CAN 500kbps에서:
- 프레임당 약 250µs (8바이트)
- 2KB 페이지 = 256프레임 ≈ 64ms
- 246KB = 123페이지 ≈ 8초
실제론 Flash 쓰기 시간 포함해서 10~15초 정도.
흐름 제어
PC가 너무 빨리 보내면?
BMS가 PAGE_REQ 보낼 때까지 PC는 대기.
BMS: PAGE_REQ (page 0)
PC: PAGE_START
PC: data × 256
PC: PAGE_END
(여기서 대기)
BMS: PAGE_ACK
BMS: PAGE_REQ (page 1) ← 이거 받으면 다음 페이지 전송
다음 글에서 CRC 검증.