NRF_LOG_INFO 出力を printf で UART 出力に直す

「Nordic SDK で printf と NRF_LOG」
https://qiita.com/nanbuwks/items/3673691779b2e6eca89a

の実例として、

NRF_LOG_INFO 出力しているプログラムを printf で UART 出力に直してみます。


# 環境

- Nordic nRF5 SDK v15.2.0
- SEGGER Embedded studio for ARM V4.10a
- J-link v8(中華製)
- Raytac MDBT50Q-DB


# 対象プログラム

対象とするのは、

SDK/examples/peripheral/twi_scanner

です。このサンプルプログラムはI2Cのデバイスが何がつながっているかスキャンして表示します。

pca10056/blank/ses/twi_scanner_pca10056.emProject を開き、

実際の配線に合わせて

```

#define ARDUINO_SCL_PIN 31
#define ARDUINO_SDA_PIN 30
```

を書き足しました。
これを実行すると、UARTに以下のように出ます。

```

<info> app: TWI scanner started.
<info> app: No device was found.
```

（あらかじめ、該当の USBシリアルモジュールなどを使ってPCなどで UART 出力を受信できるようにしておく必要があります。）

# printf を Debug Terminal で表示させる

まずは、NRF_LOG_INFO を使わずに、printfを使うようにします。
main.c を以下のように書き換えます。(コード部分だけ抜粋しています)

```

#include <stdio.h>
#include "boards.h"
#include "app_util_platform.h"
#include "app_error.h"
#include "nrf_drv_twi.h"



#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

#define ARDUINO_SCL_PIN 31
#define ARDUINO_SDA_PIN 30

/* TWI instance ID. */
#if TWI0_ENABLED
#define TWI_INSTANCE_ID     0
#elif TWI1_ENABLED
#define TWI_INSTANCE_ID     1
#endif

 /* Number of possible TWI addresses. */
 #define TWI_ADDRESSES      127

/* TWI instance. */
static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);


/**
 * @brief TWI initialization.
 */
void twi_init (void)
{
    ret_code_t err_code;

    const nrf_drv_twi_config_t twi_config = {
       .scl                = ARDUINO_SCL_PIN,
       .sda                = ARDUINO_SDA_PIN,
       .frequency          = NRF_DRV_TWI_FREQ_100K,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
       .clear_bus_init     = false
    };

    err_code = nrf_drv_twi_init(&m_twi, &twi_config, NULL, NULL);
    APP_ERROR_CHECK(err_code);

    nrf_drv_twi_enable(&m_twi);
}


/**
 * @brief Function for main application entry.
 */
int main(void)
{
    ret_code_t err_code;
    uint8_t address;
    uint8_t sample_data;
    bool detected_device = false;

    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
    NRF_LOG_DEFAULT_BACKENDS_INIT();

//    NRF_LOG_INFO("TWI scanner started.");
//    NRF_LOG_FLUSH();
    printf("TWI scanner started printf.\n");
    twi_init();

    for (address = 1; address <= TWI_ADDRESSES; address++)
    {
        err_code = nrf_drv_twi_rx(&m_twi, address, &sample_data, sizeof(sample_data));
        if (err_code == NRF_SUCCESS)
        {
            detected_device = true;
//          NRF_LOG_INFO("TWI device detected at address 0x%x.", address);
            printf("TWI device ddddetected at address 0x%x. printf\n", address);
        }
//      NRF_LOG_FLUSH();
    }

    if (!detected_device)
    {
//      NRF_LOG_INFO("No device was found.");
//      NRF_LOG_FLUSH();
        printf("No deviceddd was found printf.\n");
    }

    while (true)
    {
        /* Empty loop. */
    }
}
```

NRF_LOG_INFO と NRF_LOG_FLUSH を printfに書き換えています。

これを実行してもまだ UART には何も出ませんが、J-Link 経由で Debug Terminalに

```

TWI scanner started printf.
No deviceddd was found printf.
```

と出ます。


これをUART出力に直すには、sdk_config.hにいくつか書き足します。



# sdk_config.h

nRF_Librariesハイブの冒頭に、以下のディレクティブを追加します。

- APP_FIFO_ENABLED
- APP_UART_ENABLED
- APP_UART_DRIVER_INSTANCE

```


//==========================================================

// <h> nRF_Libraries 

//==========================================================
// <e> NRF_BALLOC_ENABLED - nrf_balloc - Block allocator module
//==========================================================
#ifndef NRF_BALLOC_ENABLED
#define NRF_BALLOC_ENABLED 1
#endif
```
↓

```

//==========================================================

// <h> nRF_Libraries 

//==========================================================
// <q> APP_FIFO_ENABLED  - app_fifo - Software FIFO implementation
 

#ifndef APP_FIFO_ENABLED
#define APP_FIFO_ENABLED 1
#endif

// <e> APP_UART_ENABLED - app_uart - UART driver
//==========================================================
#ifndef APP_UART_ENABLED
#define APP_UART_ENABLED 1
#endif
// <o> APP_UART_DRIVER_INSTANCE  - UART instance used
 
// <0=> 0 

#ifndef APP_UART_DRIVER_INSTANCE
#define APP_UART_DRIVER_INSTANCE 0
#endif

// </e>

// <e> NRF_BALLOC_ENABLED - nrf_balloc - Block allocator module
//==========================================================
#ifndef NRF_BALLOC_ENABLED
#define NRF_BALLOC_ENABLED 1
#endif
```

更に、nRF_Librariesハイブの最後に

- NRF_STRERROR_ENABLED

ディレクティブを追加します。

```

// <q> NRF_STRERROR_ENABLED  - nrf_strerror - Library for converting error code to string.
 

#ifndef NRF_STRERROR_ENABLED
#define NRF_STRERROR_ENABLED 1
#endif

// </h> 
//==========================================================

// <h> nRF_Log 

//==========================================================
```
↓

```

// <q> NRF_STRERROR_ENABLED  - nrf_strerror - Library for converting error code to string.
 

#ifndef NRF_STRERROR_ENABLED
#define NRF_STRERROR_ENABLED 1
#endif

// <q> RETARGET_ENABLED  - retarget - Retargeting stdio functions
 

#ifndef RETARGET_ENABLED
#define RETARGET_ENABLED 1
#endif

// </h> 
//==========================================================

// <h> nRF_Log 

//==========================================================
```


# twi_scanner_pca10056.emProject

インクルードパスを追加します。

```

      c_user_include_directories="../../../config;...
```
↓

```

      c_user_include_directories="../../../../../../components/libraries/uart;../../../../../../components/libraries/fifo;../../../config;...
```

cファイルを追加します。

```

    <folder Name="nRF_Libraries">
      <file file_name="../../../../../../components/libraries/util/app_error.c" />
      <file file_name="../../../../../../components/libraries/util/app_error_handler_gcc.c" />
      <file file_name="../../../../../../components/libraries/util/app_error_weak.c" />
      <file file_name="../../../../../../components/libraries/util/app_util_platform.c" />
      <file file_name="../../../../../../components/libraries/util/nrf_assert.c" />
      <file file_name="../../../../../../components/libraries/atomic/nrf_atomic.c" />
      <file file_name="../../../../../../components/libraries/balloc/nrf_balloc.c" />
      <file file_name="../../../../../../external/fprintf/nrf_fprintf.c" />
      <file file_name="../../../../../../external/fprintf/nrf_fprintf_format.c" />
      <file file_name="../../../../../../components/libraries/memobj/nrf_memobj.c" />
      <file file_name="../../../../../../components/libraries/ringbuf/nrf_ringbuf.c" />
      <file file_name="../../../../../../components/libraries/strerror/nrf_strerror.c" />
    </folder>
```
↓

```

    <folder Name="nRF_Libraries">
      <file file_name="../../../../../../components/libraries/util/app_error.c" />
      <file file_name="../../../../../../components/libraries/util/app_error_handler_gcc.c" />
      <file file_name="../../../../../../components/libraries/util/app_error_weak.c" />
      <file file_name="../../../../../../components/libraries/fifo/app_fifo.c" />
      <file file_name="../../../../../../components/libraries/uart/app_uart_fifo.c" />
      <file file_name="../../../../../../components/libraries/util/app_util_platform.c" />
      <file file_name="../../../../../../components/libraries/util/nrf_assert.c" />
      <file file_name="../../../../../../components/libraries/atomic/nrf_atomic.c" />
      <file file_name="../../../../../../components/libraries/balloc/nrf_balloc.c" />
      <file file_name="../../../../../../external/fprintf/nrf_fprintf.c" />
      <file file_name="../../../../../../external/fprintf/nrf_fprintf_format.c" />
      <file file_name="../../../../../../components/libraries/memobj/nrf_memobj.c" />
      <file file_name="../../../../../../components/libraries/ringbuf/nrf_ringbuf.c" />
      <file file_name="../../../../../../components/libraries/strerror/nrf_strerror.c" />
      <file file_name="../../../../../../components/libraries/uart/retarget.c" />
    </folder>
```

# main.c

その上で、以下のように追加していきます。


まず、ふつうにUARTを使うための include や defaine をします。

```

#include "app_uart.h"
#if defined (UART_PRESENT)
#include "nrf_uart.h"
#endif
#if defined (UARTE_PRESENT)
#include "nrf_uarte.h"
#endif

#define UART_TX_BUF_SIZE 256                                          
#define UART_RX_BUF_SIZE 256 
#define UART_HWFC APP_UART_FLOW_CONTROL_DISABLED

#define ARDUINO_SCL_PIN 31
#define ARDUINO_SDA_PIN 30

```

UARTの初期化ルーチンを作ります。

```

void uart_error_handle(app_uart_evt_t * p_event)
{
    if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR)
    {
        APP_ERROR_HANDLER(p_event->data.error_communication);
    }
    else if (p_event->evt_type == APP_UART_FIFO_ERROR)
    {
        APP_ERROR_HANDLER(p_event->data.error_code);
    }
}
static void uart_init(void)
{
  uint32_t err_code;
  const app_uart_comm_params_t comm_params =
  {
   RX_PIN_NUMBER,
   TX_PIN_NUMBER,
   RTS_PIN_NUMBER,
   CTS_PIN_NUMBER,
   UART_HWFC,
   false,
   NRF_UART_BAUDRATE_115200
  };

    APP_UART_FIFO_INIT(&comm_params,
                         UART_RX_BUF_SIZE,
                         UART_TX_BUF_SIZE,
                         uart_error_handle,
                         APP_IRQ_PRIORITY_LOWEST,
                         err_code);

    APP_ERROR_CHECK(err_code);
}

```

main() に以下の構文を入れます。

```

    uart_init();
```

また、RETARGET の設定が元々あるため NRF_LOG が UART に出ていますが、そのままだと競合するので以下のようにコメントうアウトするか、
```

 //   APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
 //   NRF_LOG_DEFAULT_BACKENDS_INIT();
```
sdk_config.h中の以下の行を 0　に書き換えて無効にします。

```
#define NRF_LOG_BACKEND_UART_ENABLED 1
```

上記を反映した main.c は以下のようになります。

```

#include <stdio.h>
#include "boards.h"
#include "app_util_platform.h"
#include "app_error.h"
#include "nrf_drv_twi.h"


#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"

#include "app_uart.h"
#if defined (UART_PRESENT)
#include "nrf_uart.h"
#endif
#if defined (UARTE_PRESENT)
#include "nrf_uarte.h"
#endif

#define UART_TX_BUF_SIZE 256                                          
#define UART_RX_BUF_SIZE 256 
#define UART_HWFC APP_UART_FLOW_CONTROL_DISABLED

#define ARDUINO_SCL_PIN 31
#define ARDUINO_SDA_PIN 30

#if TWI0_ENABLED
#define TWI_INSTANCE_ID     0
#elif TWI1_ENABLED
#define TWI_INSTANCE_ID     1
#endif

 #define TWI_ADDRESSES      127

static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID);

void twi_init (void)
{
    ret_code_t err_code;

    const nrf_drv_twi_config_t twi_config = {
       .scl                = ARDUINO_SCL_PIN,
       .sda                = ARDUINO_SDA_PIN,
       .frequency          = NRF_DRV_TWI_FREQ_100K,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
       .clear_bus_init     = false
    };

    err_code = nrf_drv_twi_init(&m_twi, &twi_config, NULL, NULL);
    APP_ERROR_CHECK(err_code);

    nrf_drv_twi_enable(&m_twi);
}

void uart_error_handle(app_uart_evt_t * p_event)
{
    if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR)
    {
        APP_ERROR_HANDLER(p_event->data.error_communication);
    }
    else if (p_event->evt_type == APP_UART_FIFO_ERROR)
    {
        APP_ERROR_HANDLER(p_event->data.error_code);
    }
}
static void uart_init(void)
{
  uint32_t err_code;
  const app_uart_comm_params_t comm_params =
  {
   RX_PIN_NUMBER,
   TX_PIN_NUMBER,
   RTS_PIN_NUMBER,
   CTS_PIN_NUMBER,
   UART_HWFC,
   false,
   NRF_UART_BAUDRATE_115200
  };

    APP_UART_FIFO_INIT(&comm_params,
                         UART_RX_BUF_SIZE,
                         UART_TX_BUF_SIZE,
                         uart_error_handle,
                         APP_IRQ_PRIORITY_LOWEST,
                         err_code);

    APP_ERROR_CHECK(err_code);
}

/**
 * @brief Function for main application entry.
 */
int main(void)
{
    ret_code_t err_code;
    uint8_t address;
    uint8_t sample_data;
    bool detected_device = false;

 //   APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
 //   NRF_LOG_DEFAULT_BACKENDS_INIT();

    uart_init();

//    NRF_LOG_INFO("TWI scanner started.");
//    NRF_LOG_FLUSH();
    printf("TWI scanner started printf.\n");
    twi_init();

    for (address = 1; address <= TWI_ADDRESSES; address++)
    {
        err_code = nrf_drv_twi_rx(&m_twi, address, &sample_data, sizeof(sample_data));
        if (err_code == NRF_SUCCESS)
        {
            detected_device = true;
//          NRF_LOG_INFO("TWI device detected at address 0x%x.", address);
            printf("TWI device ddddetected at address 0x%x. printf\n", address);
        }
//      NRF_LOG_FLUSH();
    }

    if (!detected_device)
    {
//      NRF_LOG_INFO("No device was found.");
//      NRF_LOG_FLUSH();
        printf("No device was found printf.\n");
    }

    while (true)
    {
        /* Empty loop. */
    }
}
```

# 実行結果

上記のようにしたプログラムを実行すると、USBシリアル接続したPCに以下のように出てきました。

```

TWI scanner started printf.
No device was found printf.
```