본문 바로가기

BLE/버그 리포트

nRF_SDK12.3 buttonless_dfu 예제 GCC 프로젝트 버그

예전에 BLE를 이용하여 펌웨어를 업데이트(On-The-Air Device Firmware Update)하는 예제인 experimental_ble_app_buttonless_dfu를 실행시켜 본 적이 있습니다. 당시엔 BLE 공부를 처음 시작할 때여서 개발자 블로그에 나온대로 따라하기만 했습니다. 그때는 여러 SDK 버전을 오가며 dual bank dfu도 실행해 보고 secure dfu도 실행해 보고 이것저것 해볼 때라 지금 다시 시도해보려니 많이 헤깔렸습니다.


그래서 예전에 사용했던 DFU 관련 프로젝트, 파일들을 완전히 지우고, 새로 만들어 봤습니다. 그런데 GCC와 이클립스로 다시 세팅을 하고, 오류없이 빌드하고 플래시했음에도 불구하고 실행이 되지 않았습니다. 이상한 것은 동일한 파일을 사용하여 Keil로 빌드하고 플래시하면 잘 실행되더군요. 파일에는 이상이 없다고 생각하고 다른 곳에서 원인을 찾아봤습니다.


터미널을 이용해 로그 메세지를 분석해 보니 nrf_dfu_settings.c 파일의 m_dfu_settings_buffer 변수에서 오류가 발생했던 것이었습니다. m_dfu_settings_buffer 변수는 부트로더와 사용자 어플리케이션이 공유하는 플래시 공간입니다. 부트로더 펌웨어와 DFU 기능을 포함한 사용자 어플리케이션은 둘 다 nrf_dfu_settings.c 파일을 사용하며, 이 파일의 m_dfu_settings_buffer 변수는 같은 공간을 가져야 합니다. 따라서 이 변수는 아래와 같이 __attribute__ 속성에 의해 항상 특정 공간에 위치해야 합니다.

#if defined (__CC_ARM )
    uint8_t  m_dfu_settings_buffer[CODE_PAGE_SIZE] __attribute__((at(BOOTLOADER_SETTINGS_ADDRESS)))
                                                   __attribute__((used));
#elif defined ( __GNUC__ )
    uint8_t m_dfu_settings_buffer[CODE_PAGE_SIZE] __attribute__ ((section(".bootloaderSettings")))
                                                  __attribute__((used));
#elif defined ( __ICCARM__ )
    __no_init __root uint8_t m_dfu_settings_buffer[CODE_PAGE_SIZE] @ BOOTLOADER_SETTINGS_ADDRESS;
#else
    #error Not a valid compiler/linker for m_dfu_settings placement.
#endif

위 코드에서 Keil에서 사용되는 BOOTLOADER_SETTINGS_ADDRESS는 nrf_dfu_types.h에 특정 주소로 명시되어 있습니다. 하지만 GCC에서는 .bootloaderSettings 섹션을 사용하여 m_dfu_settings_buffer 변수의 공간을 지정하고, 이것은 링커 스크립터에 지정되어 있어야 합니다. 그런데 부트로더인 bootloader_secure 예제의 링커 스크립터에는 .bootloaderSettings 섹션이 지정되어 있었지만, 부트로더 기능을 가진 experimental_ble_app_buttonless_dfu 어플리케이션 예제의 링커 스크립터에는 해당 섹션이 지정되어 있지 않았습니다. 또한 링커는 __attribute__로 지정한 섹션이 실제 없더라도 어떠한 오류도 나타내지 않습니다. 따라서 experimental_ble_app_buttonless_dfu 예제의 링커 스크립터를 아래와 같이 수정하여  bootloader_secure 예제의 .bootloaderSettings 섹션과 동일한 공간을 갖도록 수정하면 정상적으로 작동합니다.

/* Linker script to configure memory regions. */

SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)

MEMORY
{
  FLASH (rx) : ORIGIN = 0x1b000, LENGTH = 0x25000
  RAM (rwx) :  ORIGIN = 0x20001fe8, LENGTH = 0x6018
  
  /** Location of bootloader setting in at the last flash page. */
  BOOTLOADER_SETTINGS (rw) : ORIGIN = 0x0003FC00, LENGTH = 0x0400
}

SECTIONS
{
  /* Ensures the bootloader settings are placed at the last flash page. */
  .bootloaderSettings(NOLOAD) :
  {

  } > BOOTLOADER_SETTINGS
  
  .fs_data :
  {
    PROVIDE(__start_fs_data = .);
    KEEP(*(.fs_data))
    PROVIDE(__stop_fs_data = .);
  } > RAM
  .pwr_mgmt_data :
  {
    PROVIDE(__start_pwr_mgmt_data = .);
    KEEP(*(.pwr_mgmt_data))
    PROVIDE(__stop_pwr_mgmt_data = .);
  } > RAM
} INSERT AFTER .data;

INCLUDE "nrf5x_common.ld"

여러 칩 제조사의 SDK 함수를 볼 때마다 한 분야에 얼마나 정통하면 이렇게 만들 수 있을까 생각하며 작아지는 제 자신을 느꼈습니다. 그래서 오류가 발생하면 내가 잘못 설정한게 있나 먼저 확인해 봅니다. 이것 때문에 제가 설정한 부분만 계속 확인해 보다가 하루가 그냥 날라갔습니다. 고급 개발자들도 실수를 하긴 하더군요. 그런데 의미가 없지는 않았습니다. 오류를 추적하면서 DFU 시스템 흐름을 일부(현재 진행형) 확인할 수 있었고, 추상적으로만 알고 있던 링커 스크립트에 대해 아주 약간 구체적인 개념을 잡을 수 있었습니다.

'BLE > 버그 리포트' 카테고리의 다른 글

GNU ARM Toolchain 버전 선택시 주의사항  (0) 2018.02.25