nRF52 でSleepからGPIOで復帰

「nRF52840 の sleep を試す (Nordic SDK/Softdevice)」
https://qiita.com/nanbuwks/items/c2f098793899001b5087
で、System OFF modeからの復帰について、

>データーシートによると以下のトリガで復帰することができる。
>
>1.The DETECT signal, optionally generated by the GPIO peripheral.
>2.The ANADETECT signal, optionally generated by the LPCOMP module.
>3.The SENSE signal, optionally generated by the NFC module to wake-on-field.
>4.Detecting a valid USB voltage on the VBUS pin (V BUS,DETECT ).
>5.A reset.

と書いた。このうち1.を実現するもの。



# 環境

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

# ひながた

元々、Nordic の SDK 中のサンプルプログラム
examples/ble_peripheral/
に収録されているble_app_uart を使ってテスト。

これには、

sleep解除はボタン1または2で解除するようになっている。


```

static void sleep_mode_enter(void)
{
    uint32_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
    APP_ERROR_CHECK(err_code);

    // Prepare wakeup buttons.
    err_code = bsp_btn_ble_sleep_mode_prepare();
    APP_ERROR_CHECK(err_code);

    // Go to system-off mode (this function will not return; wakeup will cause a reset).
    err_code = sd_power_system_off();
    APP_ERROR_CHECK(err_code);
}
```
これの、bsp_btn_ble_sleep_mode_prepare();によってボード上のタクトスイッチによって復帰する設定になっている。


bsp_btn_ble.c
の

```

uint32_t bsp_btn_ble_sleep_mode_prepare(void)
{
    uint32_t err_code;

    err_code = bsp_wakeup_button_enable(BTN_ID_WAKEUP);
    RETURN_ON_ERROR_NOT_NOT_SUPPORTED(err_code);

    err_code = bsp_wakeup_button_enable(BTN_ID_WAKEUP_BOND_DELETE);
    RETURN_ON_ERROR_NOT_NOT_SUPPORTED(err_code);

    return NRF_SUCCESS;
}
```


とあり、このBTN_ID_WAKEUがボタンスイッチ1,
BTN_ID_WAKEUP_BOND_DELETEがボタンスイッチ2になる。

これらのボタンスイッチはGPIOに接続しているので同じGPIOにセンサなり外部信号なりをつなげたらいいのであるが、自由にGPIOに接続したいですね。

ということでbsp_wakeup_button_enable を辿って行くと同じ bsp_btn_ble.c に

```

uint32_t bsp_wakeup_button_enable(uint32_t button_idx)
{
    return wakeup_button_cfg(button_idx, true);
}

uint32_t bsp_wakeup_button_disable(uint32_t button_idx)
{
    return wakeup_button_cfg(button_idx, false);
}
```

とあり、wakeup_button_cfg も同様に bsp_btn_ble.c で以下のように定義されている。

```
static uint32_t wakeup_button_cfg(uint32_t button_idx, bool enable)
{
#if !defined(BSP_SIMPLE)
    if (button_idx <  BUTTONS_NUMBER)
    {
        nrf_gpio_pin_sense_t sense = enable ?
                         (BUTTONS_ACTIVE_STATE ? NRF_GPIO_PIN_SENSE_HIGH : NRF_GPIO_PIN_SENSE_LOW) :
                         NRF_GPIO_PIN_NOSENSE;
        nrf_gpio_cfg_sense_set(bsp_board_button_idx_to_pin(button_idx), sense);
        return NRF_SUCCESS;
    }
#else
    UNUSED_PARAMETER(button_idx);
    UNUSED_PARAMETER(enable);
#endif
    return NRF_ERROR_NOT_SUPPORTED;

}
```

ということなので、以下の処理を行えば良い。
　


HでSleep解除する場合

```

        nrf_gpio_cfg_sense_set(pin_number, NRF_GPIO_PIN_SENSE_HIGH);
```
LをSleep解除する場合

```

        nrf_gpio_cfg_sense_set(pin_number, NRF_GPIO_PIN_SENSE_LOW);
```
Sleep解除を無効にする場合

```

        nrf_gpio_cfg_sense_set(pin_number, NRF_GPIO_PIN_NOSENSE);
```


なお、この引数ですが

modules/nrfx/hal/nrf_gpio.h

において、

```

    NRF_GPIO_PIN_SENSE_HIGH = GPIO_PIN_CNF_SENSE_High,     ///<  Pin sense high level.
```

とあり、更に
modules/nrfx/mdk/nrf52_bitfields.h
において、

```

#define GPIO_PIN_CNF_SENSE_High (2UL)
#define GPIO_PIN_CNF_SENSE_Low (3UL) /*!< Sense for low level */

```
とあります。
また、　pin_number については、

```

modules/nrfx/hal/nrf_gpio.h
内で

__STATIC_INLINE void nrf_gpio_cfg_sense_set(uint32_t pin_number, nrf_gpio_pin_sense_t sense_config)
{
    NRF_GPIO_Type * reg = nrf_gpio_pin_port_decode(&pin_number);

    /*lint -e{845} // A zero has been given as right argument to operator '|'" */
    reg->PIN_CNF[pin_number] &= ~GPIO_PIN_CNF_SENSE_Msk;
    reg->PIN_CNF[pin_number] |= (sense_config << GPIO_PIN_CNF_SENSE_Pos);
}
```

とあり、データーシートの「6.9.2.10 PIN_CNF[n] (n=0..31)」にあるレジスタの記述を読むと、この説明のID=Eである「RW SENSE」に2を書き込むとHをディテクト、3を書き込むとLをディテクトするということで先の



```

#define GPIO_PIN_CNF_SENSE_High (2UL)
#define GPIO_PIN_CNF_SENSE_Low (3UL) /*!< Sense for low level */

```

に対応していることになります。

# pullup

なお、外部にプルアップなどをつなげている場合はこのままでもいいですがそうではない場合、プルアップ指定をしているのがいいでしょう。
以下は、GPIO の P0.18 を（Reset指定を解除した上で）プルアップして、GNDレベルになるるとスリープ解除するようにした例です。

```

    nrf_gpio_cfg_input(NRF_GPIO_PIN_MAP(0,18),NRF_GPIO_PIN_PULLUP);
    nrf_gpio_cfg_sense_set(18, NRF_GPIO_PIN_SENSE_LOW);
```