본문 바로가기
Embedded/nRF52 BLE 개발 안내서

nRF52 BLE 개발하기 - dfu

by 큐찡 2021. 1. 28.
728x90
반응형

시작하기

이번에는 Device Firmware Update(DFU)에 대해서 알아보도록 하자.

DFU는 부트로더에서 지원하는 핵심 기능 중 하나이며 DFU의 주요 기능은 펌웨어, SoftDevice 등을 블루투스, UART, USBD로 업데이트할 수 있게 한다.

개발한 장치의 유지보수 측면에서 중요한 기능이며 일반적으로 OTA를 떠올리면 이해하기 쉽다.

nRF52832는 블루투스와 UART DFU를 지원하는데 여기서는 가장 많이 쓰인다고 생각되는 블루투스 DFU에 대해서 알아보도록 하겠다.

\examples\dfu\secure_bootloader\pca10040_s132_ble\ses 폴더에서 프로젝트를 실행해보자.

/** @file
 *
 * @defgroup bootloader_secure_ble main.c
 * @{
 * @ingroup dfu_bootloader_api
 * @brief Bootloader project main file for secure DFU.
 *
 */

#include <stdint.h>
#include "boards.h"
#include "nrf_mbr.h"
#include "nrf_bootloader.h"
#include "nrf_bootloader_app_start.h"
#include "nrf_bootloader_dfu_timers.h"
#include "nrf_dfu.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "app_error.h"
#include "app_error_weak.h"
#include "nrf_bootloader_info.h"
#include "nrf_delay.h"

static void on_error(void)
{
    NRF_LOG_FINAL_FLUSH();

#if NRF_MODULE_ENABLED(NRF_LOG_BACKEND_RTT)
    // To allow the buffer to be flushed by the host.
    nrf_delay_ms(100);
#endif
#ifdef NRF_DFU_DEBUG_VERSION
    NRF_BREAKPOINT_COND;
#endif
    NVIC_SystemReset();
}


void app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name)
{
    NRF_LOG_ERROR("%s:%d", p_file_name, line_num);
    on_error();
}


void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
{
    NRF_LOG_ERROR("Received a fault! id: 0x%08x, pc: 0x%08x, info: 0x%08x", id, pc, info);
    on_error();
}


void app_error_handler_bare(uint32_t error_code)
{
    NRF_LOG_ERROR("Received an error: 0x%08x!", error_code);
    on_error();
}

/**
 * @brief Function notifies certain events in DFU process.
 */
static void dfu_observer(nrf_dfu_evt_type_t evt_type)
{
    switch (evt_type)
    {
        case NRF_DFU_EVT_DFU_FAILED:
        case NRF_DFU_EVT_DFU_ABORTED:
        case NRF_DFU_EVT_DFU_INITIALIZED:
            bsp_board_init(BSP_INIT_LEDS);
            bsp_board_led_on(BSP_BOARD_LED_0);
            bsp_board_led_on(BSP_BOARD_LED_1);
            bsp_board_led_off(BSP_BOARD_LED_2);
            break;
        case NRF_DFU_EVT_TRANSPORT_ACTIVATED:
            bsp_board_led_off(BSP_BOARD_LED_1);
            bsp_board_led_on(BSP_BOARD_LED_2);
            break;
        case NRF_DFU_EVT_DFU_STARTED:
            break;
        default:
            break;
    }
}


/**@brief Function for application main entry. */
int main(void)
{
    uint32_t ret_val;

    // Must happen before flash protection is applied, since it edits a protected page.
    nrf_bootloader_mbr_addrs_populate();

    // Protect MBR and bootloader code from being overwritten.
    ret_val = nrf_bootloader_flash_protect(0, MBR_SIZE);
    APP_ERROR_CHECK(ret_val);
    ret_val = nrf_bootloader_flash_protect(BOOTLOADER_START_ADDR, BOOTLOADER_SIZE);
    APP_ERROR_CHECK(ret_val);

    (void) NRF_LOG_INIT(nrf_bootloader_dfu_timer_counter_get);
    NRF_LOG_DEFAULT_BACKENDS_INIT();

    NRF_LOG_INFO("Inside main");

    ret_val = nrf_bootloader_init(dfu_observer);
    APP_ERROR_CHECK(ret_val);

    NRF_LOG_FLUSH();

    NRF_LOG_ERROR("After main, should never be reached.");
    NRF_LOG_FLUSH();

    APP_ERROR_CHECK_BOOL(false);
}

예제의 main.c 소스코드에서 특별히 수정할 부분은 없으나 수정을 하게 된다면 dfu_observer 함수의 LED 정도 변경 가능하다.

나머지 부분은 크게 신경 쓰지 말고 예제를 컴파일해보자.

"uECC.h: No such file or directory" 에러와 함께 정상적으로 컴파일이 완료되지 않는다.

지금부터 uECC.h 에러 해결 방법에 대해서 알아보자.

nRF5_SDK_17.0.2_d674dde\external 폴더에 들어가서 micro-ecc 폴더를 SHIFT+우클릭하면 여기에 PowerShell 창 열기 항목이 나타난다.

PowerShell 창이 뜨면 build_all.bat을 입력해보자.

그럼 에러 메시지가 뜨면서 실행이 안 되는 것을 알 수 있다.

이는 make 파일이 없어서 발생하는 문제로 해결을 위해서 링크에 접속해 GNU Make를 다운로드하고 설치한다.

GNU Make를 환경변수로 등록해주고 다시 작업을 수행해보자.

이번에도 에러와 함께 진행이 안 되는 것을 볼 수 있다.

이는 GNU Tools ARM Embedded가 없어서 발생하는 문제이므로 링크에 접속해 다운로드하고 설치하도록 하자.

설치하고 작업을 수행하면 똑같은 에러가 발생하면서 진행이 안되는데 이는 SDK의 Makefile에 GNU Tool의 버전 정보가 다르기 때문이다.

\components\toolchain\gcc 폴더에 들어가면 Makefile.windows 파일을 찾을 수 있다.

이 파일을 문서 편집기로 열어보자.

GNU_INSTALL_ROOT에 GNU Tool이 설치된 경로로 변경한다.

여기서는 C:/Program Files (x86)/GNU Arm Embedded Toolchain/10 2020-q4-major/bin/으로 변경하였다.

이번에도 에러와 함께 진행이 안되지만 이유는 git이 설치되어 있지 않기 때문이다.

링크에 접속해 git을 다운로드하고 설치한 다음 다시 한번 build_all.bat을 실행해보자.

성공적으로 작업이 완료된 것을 확인할 수 있다.

이제 다시 SES로 돌아와 컴파일을 진행해보자.

새로운 에러가 반겨준다.

에러 위치에 사이트 주소를 남겨놓았으니 접속해보자.

nrfutil을 사용해서 private key를 생성해야 하는데 파이썬으로 nrfutil 실행 파일을 만들어줘야 하는 번거로움이 있다.

nrfutil 실행 파일을 검색해서 다운로드하여 사용하도록 하자.

nrfutil을 사용해서 private key를 생성하는 방법은 노르딕 인포센터에서 확인할 수 있다.

nrfutil 실행 파일이 있는 경로에서 PowerShell을 실행하고 아래와 같이 private key를 생성하는 명령어를 입력해보자.

> .\nrfutil.exe keys generate private.pem
> .\nrfutil.exe keys display --key pk --format code private.pem

입력한 명령어에 의해 private key를 private.pem 파일로 생성하고 소스코드 형식으로 public key를 보여준다.

PowerShell에 출력된 public key 소스코드를 복사해서 에러가 발생한 위치인 dfu_public_key.c에 붙여 넣고 다시 컴파일을 해보자.

이렇게 블루투스 부트로더 컴파일이 완료되었다.

이제 nRF52 DK에 부트로더를 다운로드하고 nRF Toolbox 애플리케이션을 실행한다.

DFU 항목을 선택하고 SELECT DEVICE를 눌러 장치 목록에서 DfuTarg을 연결을 한다.

그리고 SELECT FILE을 눌러보면 파일 타입을 선택하는 창이 나타난다.

Distribution packet(ZIP), Soft Device, Bootloader, Application의 4가지 항목을 선택할 수 있다.

여기서는 Application을 선택해서 ble_app_blinky 예제의 펌웨어를 올려보도록 하자.

\examples\ble_peripheral\ble_app_blinky\pca10040\s132\ses\Output\Release\Exe 폴더에서 ble_app_blinky_pca10040_s132.hex 파일을 스마트폰으로 옮기고 펌웨어 파일을 선택해보자.

그럼 Init packet을 선택하라는 창이 나오며 이를 무시하고 UPLOAD를 진행하면 실패했다는 메시지가 출력된다.

여기서 우리는 init packet이라고 불리는 dat 형식의 파일이 필요한 것을 알았으니 이제 이것을 만드는 방법을 알아보도록 하자.

노르딕 인포센터에서 내용을 찾아보니 DFU 패키지를 만들면 펌웨어, init packet, manifest 파일이 포함된 파일을 만들 수 있다고 한다.

nrfutil 실행 파일이 있는 폴더에 ble_app_blinky_pca10040_s132.hex 파일을 옮긴다.

PowerShell에서 DFU 패키지를 만들기 위한 명령어는 아래와 같다.

여기서 --hw-version은 nRF52832 이므로 52를 전달하고 --sd-req는 SoftDevice 정보인데 다운로드한 SoftDevice 7.2.0의 폴더의 릴리스 노트를 통해 확인할 수 있다.

> .\nrfutil.exe pkg generate --hw-version 52 --sd-req 0x0101 --application-version 4 --application .\ble_app_blinky_pca10040_s132.hex --key-file .\private.pem app_dfu_package.zip

정상적으로 작업이 수행되었다면 폴더에 app_dfu_package.zip 파일이 생성된다.

파일 압축을 해제하면 펌웨어, init packet, manifest 파일이 생성된 것을 알 수 있다.

이제 app_dfu_package.zip 파일을 다시 스마트폰으로 옮겨주자.

다시 nRF Toolbox 애플리케이션의 DFU 항목으로 돌아와 Distribution packet(ZIP)을 선택한다.

그리고 app_dfu_package.zip 파일을 선택하면 Select scope 선택창이 나타나는데 All을 선택하고 UPLOAD를 눌러보자.

펌웨어가 블루투스를 통해 업로드되며 업로드가 끝나면 nRF52 DK에 ble_app_blinky 펌웨어가 동작하는지 확인해보자.

nRF Toolbox 애플리케이션에서 BLINKY 항목을 선택하고 장치 목록을 확인 후 페어링 연결을 해보자.

블루투스 DFU를 통해 ble_app_blinky 펌웨어가 업로드되어 Nordic_Blinky 애플리케이션이 정상적으로 동작되는 것을 확인할 수 있다.

앞으로

지금까지 블루투스 DFU를 이용해 펌웨어를 업로드하는 방법에 대해서 알아보았다.

다시 블루투스 DFU를 이용해 펌웨어를 올리기 위해선 부트로더를 다시 다운로드하고 펌웨어를 업로드하는 과정을 거쳐야 한다.

다음에는 부트로더를 원할 때 다시 동작시킬 수 있는 방법에 대해서 알아보도록 하자.

728x90
반응형

댓글