「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.