LoginSignup
5
1

More than 5 years have passed since last update.

nRF5 SDKのQueueとタイマとSPIを使ってみた。

Posted at

nRF5 SDKをちょっと使ってみたのでメモ

BLEな部分は触らずマイコンみたいに使いました。

環境:
 Hardware: nRF52832 搭載の nRF52-DK PCA10040
 Software: nRF5 SDK 14.2.0 / SoftDevice S123 5.0.0

Queue

タスク間のデータ転送などに使う。

数年前のnRF5 SDKではmailboxがあったが、現時点ではmailboxが廃止されており、その代わりにQueueを使用します。

Queueはマクロを使って定義する。

NRF_QUEUE_DEF(uint8_t, myQueue, 15, NRF_QUEUE_MODE_OVERFLOW);

ここで定義されるQueueはスコープがstaticなので、ファイル外からアクセスする場合はアクセス用の関数を用意する。

Queue操作のAPIはいろいろとあるけど、4つだけ使用。

nrf_queue_reset(&myQueue);
nrf_queue_push(&myAppQ, &ev);
nrf_queue_is_empty(&myQueue);
nrf_queue_pop(&myQueue, &ev);

このQueueを使ってイベント処理を実装してみた。

doEvent(void)
{
    uint8_t e;
    if (nrf_queue_is_empty(&myQueue)) {
        return;
    }
    nrf_queue_pop(&myQueue, &e);

    swith(e){
    ....
    }
}

アプリケーションタイマ

RTOSのタスクをタイマ起動に置き換えてみた。
今回はFreeRTOSは使いたくなかったので、タイマからの定期起動として実装してみました。

アプリケーションタイマの種類として、周期タイマとシングルショットタイマがある

周期タイマ


APP_TIMER_DEF(my_timer_id); 

app_timer_create(&my_timer_id, APP_TIMER_MODE_REPEATED, smac_loop_handler);
app_timer_start(my_timer_id, APP_TIMER_TICKS(1), NULL);

シングルショットタイマ

uint32_t timer_ms = 10;
app_timer_create(&my_timer_id, APP_TIMER_MODE_SINGLE_SHOT, WaitSendTimerCallBack));
uint64_t tick =  ( timer_ms * APP_TIMER_CLOCK_FREQ ) / ( 1000 * (APP_TIMER_CONFIG_RTC_FREQUENCY + 1) );
app_timer_start(my_timer_id, tick, NULL);

タイマの周期を変数で指定する場合は、APP_TIMER_TICKSマクロは使えないので、APP_TIMER_TICKS()相当の計算を行う、そのときuint64_tで計算する。

アプリケーションタイマからのコールバックは、タイマ割り込みのコンテキストで実行される。 割り込みを必要とするような処理は行えないことに注意。

ハードウェアタイマ

高精度のカウント処理が使いたいのでハードウェアタイマを使ってみた。

    nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
    timer_cfg.frequency = NRF_TIMER_FREQ_2MHz;
    timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
    APP_ERROR_CHECK(nrf_drv_timer_init(&NRF_DRV_TIMER_INSTANCE(1), &timer_cfg, timer_void_event_handler));

    nrf_drv_timer_disable(&NRF_DRV_TIMER_INSTANCE(1));
    nrf_drv_timer_clear(&NRF_DRV_TIMER_INSTANCE(1));
    nrf_drv_timer_enable(&NRF_DRV_TIMER_INSTANCE(1));

カウント値の取得

  count = nrf_drv_timer_capture(&NRF_DRV_TIMER_INSTANCE(1), NRF_TIMER_CC_CHANNEL0)

SPIマスタ

SPIの設定

SPIの設定は構造体にパラメータを設定してAPIを呼ぶ

デフォルト設定の定義があるので、これを使う。

/**
 * @brief SPI master instance default configuration.
 */
#define NRF_DRV_SPI_DEFAULT_CONFIG                           \
{                                                            \
    .sck_pin      = NRF_DRV_SPI_PIN_NOT_USED,                \
    .mosi_pin     = NRF_DRV_SPI_PIN_NOT_USED,                \
    .miso_pin     = NRF_DRV_SPI_PIN_NOT_USED,                \
    .ss_pin       = NRF_DRV_SPI_PIN_NOT_USED,                \
    .irq_priority = SPI_DEFAULT_CONFIG_IRQ_PRIORITY,         \
    .orc          = 0xFF,                                    \
    .frequency    = NRF_DRV_SPI_FREQ_4M,                     \
    .mode         = NRF_DRV_SPI_MODE_0,                      \
    .bit_order    = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST,         \
}
#define SPI_SS_PIN 29
#define SPI_MISO_PIN 28
#define SPI_MOSI_PIN 4
#define SPI_SCK_PIN 3

    nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
    spi_config.ss_pin   = SPI_SS_PIN;
    spi_config.miso_pin = SPI_MISO_PIN;
    spi_config.mosi_pin = SPI_MOSI_PIN;
    spi_config.sck_pin  = SPI_SCK_PIN;
    spi_config. frequency = NRF_DRV_SPI_FREQ_1M
    APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));

SPIデータの送受信

    uint8_t tx[2] = 0x01;
    uint8_t rx[2];

    APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, tx, 2, rx, 2));
5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1