Настройка и использование таймслотов SoftDevice Печать
Добавил(а) microsin   

Когда необходимо использовать блок radio строго определенным образом, сохраняя при этом соединение BLE, или когда нужно выполнить некую задачу, которая не должна быть прервана активностью radio, Вы можете настроить таймслот (timeslot). Таймслот это период времени от 100 мкс до 128 сек, в течение которого SoftDevice обеспечит для пользователя полный контроль над радиотрактом или другими периферийными устройствами.

Для экспериментов с таймслотами понадобится следующее:

• Keil 5.20 или более свежий.
• Плата разработчика nRF52 DK (или nRF51 DK).
• S132 SoftDevice (S130 для nRF51).
• nRF5 SDK 11 или более свежий.

Приложение запрашивает таймслот, длительность которого может быть от 100 мкс до 100 мс. Более длинные таймслоты могут быть предоставлены путем запросов расширений (timeslot extension), максимум до 128 сек.

Тайслоты запрашиваются в пределах сессии, которая может состоять из нескольких таймслотов. Разные типы сессий и сценариев использования timeslot можно увидеть в примерах использования timeslot, которые находятся в Infocenter (см. также главу 10 "Multiprotocol support" руководства SoftDevice Specification [2]).

SoftDevice timeslot complete session example

Когда запрашивается timeslot, приложение должно указать SoftDevice использовать high или normal приоритет для timeslot. Для большинства приложений во избежание конфликтов следует использовать приоритет normal. Если у Вас приложение, которое очень критично по времени выполнения кода, как например проприетарный radio-протокол или реализация OneWire [3], то используйте приоритет high.

Существует 2 типа запросов: выполнить как можно быстрее (earliest possible) и в течение заданного времени (given time). Тип earliest possible предназначен для однократных или реактивных событий, и он предоставляет timeslot так быстро, как это только возможно. Тип given time предназначен для повторяющихся событий, и он предоставляет таймслот через некоторое время после начала предыдущего таймслота.

Когда timeslot был предоставлен, приложение получает доступ к модулям RADIO, TIMER0, CCM, AAR и PPI (каналы 14-15) на время таймслота.

[События и действия для таймслотов]

Существуют следующие функции для использования таймслотов:

uint32_t sd_radio_session_open (nrf_radio_signal_callback_t p_radio_signal_callback);

Откроет сессию для запроса выделенного интервала времени (таймслота), в течение которого можно реализовать собственные операции с радиотрактом.

Важный момент: одновременно может быть открыта только одна сессия таймслота.

Параметры sd_radio_session_open:

[in] p_radio_signal_callback Callback-функция, обрабатывающая сигналы Timeslot API.

Параметр p_radio_signal_callback это указатель на функцию обратного вызова, которая будет принимать на входе сигнал NRF_RADIO_CALLBACK_SIGNAL_xxx от системы поддержки таймслота.

p_radio_signal_callback(NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) будет вызвана, когда начнется формирование таймслота. Начиная с этого момента периферийные устройства NRF_RADIO и NRF_TIMER0 свободно доступны для приложения.

p_radio_signal_callback(NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0) будет вызвана всякий раз, когда происходит прерывание NRF_TIMER0.

p_radio_signal_callback(NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO) будет вызвана всякий раз, когда произойдет прерывание NRF_RADIO.

Функция p_radio_signal_callback() будет вызвана с самым высоким приоритетом прерывания (ARM interrupt priority level 0). Подразумевается, что никакая из API-функций SoftDevice (начинающаяся с префикса sd_*) не может быть вызвана из тела p_radio_signal_callback().

Возвращаемые значения sd_radio_session_open:

NRF_ERROR_INVALID_ADDR указатель p_radio_signal_callback является недопустимым указателем на функцию.
NRF_ERROR_BUSY Если сессия не может быть открыта.
NRF_ERROR_INTERNAL Если новая сессия не может быть открыта из-за внутренней ошибки.
NRF_SUCCESS Успешное открытие сессии.

uint32_t sd_radio_session_close (void);

Закроет сессию для запросов таймслотов radio.

Любой текущий таймслот radio будет завершен перед закрытием сессии. Если был запланирован таймслот radio, когда сессия закрыта, то этот таймслот будет отменен. Приложение не может считать сессию закрытой, пока не получит событие NRF_EVT_RADIO_SESSION_CLOSED.

Возвращаемые значения sd_radio_session_close:

NRF_ERROR_FORBIDDEN Если сессия не была открыта.
NRF_ERROR_BUSY Если сессия в настоящий момент закрывается.
NRF_SUCCESS Сессия была успешно закрыта.

uint32_t sd_radio_request (nrf_radio_request_t * p_request);

Запрашивает таймслот radio.

Тип запроса определяется полем p_request->request_type, и может быть либо NRF_RADIO_REQ_TYPE_EARLIEST, либо NRF_RADIO_REQ_TYPE_NORMAL. Первый запрос в сессии всегда должен быть типа NRF_RADIO_REQ_TYPE_EARLIEST.

Для запросов с обычным приоритетом (NRF_RADIO_REQ_TYPE_NORMAL) время начала таймслота указывается полем p_request->distance_us относительно начала предыдущего таймслота.

Слишком малая величина p_request->distance_us приведет к событию NRF_EVT_RADIO_BLOCKED. К такому же событию приведут таймслоты, запланированные слишком близко друг к другу.

Для дополнительной информации по планированию, дистанции и длительности тамслотов см. SoftDevice Specification [2].

Если не найдена возможность организовать первый таймслот radio в течение 100 мс после вызова этой функции, то таймслот не будет запланирован, и будет отправлено событие NRF_EVT_RADIO_BLOCKED. При получении этого события приложение может попытаться снова запланировать первый таймслот radio.

Успешное планирование таймслота будет в случае запуска callback-функции nrf_radio_signal_callback_t с параметром NRF_RADIO_CALLBACK_SIGNAL_TYPE_START (см. выше описание функции sd_radio_session_open). Неудачный запрос приведет к генерации события NRF_EVT_RADIO_BLOCKED, см. описание событий SoC (NRF_SOC_EVTS).

Джиттер во времени запуска таймслотов radio будет +/- NRF_RADIO_START_JITTER_US мкс. У вызова nrf_radio_signal_callback_t(NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) существует латентность относительно указанного начала таймслота radio, но это не влияет на реальное время начала таймслота.

NRF_TIMER0 сбрасывается в начале таймслота radio, и тактируется от частоты 1 МГц, вырабатываемой от высокочастоного источника тактов (16 МГц). Если p_request->hfclk_force_xtal == true, генерация высокой частоты гарантируется от внешнего кварцевого резонатора.

Во время таймслота radio код SoftDevice не обращается ни к периферийному устройству NRF_RADIO, ни к периферийному устройству NRF_TIMER0.

Параметры sd_radio_request:

[in] p_request Указатель на параметры запроса таймслота.

Возвращаемые значения sd_radio_request:

NRF_ERROR_FORBIDDEN Сессия не открыта, или сессия не в состоянии ожидания (не в IDLE).
NRF_ERROR_INVALID_ADDR Если указатель p_request недопустимый.
NRF_ERROR_INVALID_PARAM Если параметры p_request недопустимы.
NRF_SUCCESS Запрос таймслота успешный.

Timeslot events. В дополнение к этим вызовам есть единственный обработчик сигнала, который вызывается через диспетчер событий системы (system event dispatcher), это соответствует следующим случаям (событиям):

NRF_EVT_RADIO_SESSION_IDLE - у сессии больше нет запланированных таймслотов. Если сработало это событие, то приложение завершит сессию. Обратите внимание, что в этот момент можно запросить новые таймслоты (подробнее об этом далее).

NRF_EVT_RADIO_SESSION_CLOSED - сессия закрыта и захваченные для неё ресурсы освобождены.

NRF_EVT_RADIO_BLOCKED - запрошенный таймслот запланировать не удалось, из-за конфликта с другими активностями в системе. Приложение должно запросить новый таймслот либо как можно раньше, либо в следующей normal-позиции.

NRF_EVT_RADIO_CANCELED - запланированный таймслот был отменен активностью с более высоким приоритетом. Приложение должно запросить новый таймслот.

NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN - последнее значение, возвращенное обработчиком сигнала, содержит недопустимые параметры. В Вашем приложении должен сработать assert.

Timeslot signals. Адрес timeslot-обработчика передается как аргумент в функцию, которая открывает radio-сессию. Обработчик таймслота будет обслуживать следующие случаи:

NRF_RADIO_CALLBACK_SIGNAL_TYPE_START - запуск таймслота. В этот момент получает доступ к периферийным устройствам на длительность таймслота. Перед тем, как начать инициализировать свой таймслот, Вы должны использовать таймер (например TIMER0), который запускает событие 100 мкс около того до истечения таймслота. TIMER0 запускается автоматически с нуля изнутри SoftDevice в начале таймслота, и конфигурируется для тактирования от 1 МГц. Если Вам не удастся завершить работу до окончания таймслота, то приложение упадет в hardfault.

NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO - прерывание Radio, подробнее см. описание 2.4GHz radio на сайте Infocenter.

NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0 - прерывание таймера. В этом месте корректно завершается работа таймера, который был вами настроен ранее. Здесь нужно выполнить деинициализацию и подготовиться к возврату активности SoftDevice. Также в этом месте также можно запросить следующий таймслот.

NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEDED - последнее расширение сессии выполнено успешно. Обычно в этом месте не нужно предпринимать никаких действий.

NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED - последнее расширение сессии потерпело неудачу, попробуйте заново запланировать свой таймслот.

Обработчик таймслота возвратит некоторые параметры callback-а, которые используются в SoftDevice. Их использование мы рассмотрим позже.

NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE - Ничего не делать.

NRF_RADIO_SIGNAL_CALLBACK_ACTION_END - Сигнализирует о завершении текущего события выполняемого таймслота. SoftDevice может возобновить свои активности. Обычно используется для завершения свободного текущего таймслота.

NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END - сигнализирует о событии завершения текущего таймслота, запрашивает новый таймслот перед сигнализацией о том, что SoftDevice может возобновить свои активности.

NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND - попытка расширения выполняющегося таймслота.

Обработчик таймслота выполняется с самым высоким уровнем приоритета прерывания 0, поэтому Вы не можете вызвать функции с более низким приоритетом.

[Настройка таймслота]

Код таймслота часто довольно большой, обычно его базовый уровень составляет порядка 150 строк. Однако код даже может быть значительно больше, когда Вы добавите в таймслот свой функционал. По этой причине лучше всего добавлять таймслоты в отдельном файле, а не в основной модуль main.c.

Дальнейшие описываемые шаги производятся в Keil µVision V5.34, с SDK v12.3.0 (nRF5_SDK_12.3.0_d7731ad), с использованием PCA10040 DK (чип nRF52832 QFAA).

1. Откройте проект, который Вы хотите изменить. В этом примере автор [1] использует в качестве основы проект ble_app_template из SDK (нужно открыть ble_app_template_pca10040_s132.uvprojx, который находится в папке ble_peripheral\ble_app_template\pca10040\s132\arm5_no_packs примеров SDK).

Это простейший пример периферийного устройства BLE (сервера), который обладает только базовым функционалом. Если сейчас проект скомпилировать (F7) и запрограммировать в память чипа (F8), то на плате DK начнет мигать светодиод LED1, сигнализируя о начале выдачи в эфир advertising-пакетов BLE. Можно открыть приложение nRF Connect [5] и подключиться к этому устройству по имени Nordic_Template. Светодиод LED1 начнет гореть непрерывно, и nRF Connect покажет базовые атрибуты устройства Nordic_Template.

2. Выполните правый клик на папке приложения (Application) и выберите Add New Item to Group 'Application'...

Keil add new module to ble app template

3. Выберите C File, дайте имя файла timeslot.c, кликните Add.

Далее нам нужно добавить в этот модуль некий код. В следующем примере кода будет запрос сессии и переключение состояния LED4 в начале каждого таймслота. Нам также надо поменять целевую ножку, которая будет переключаться, вызовом nrf_gpio_pin_toggle(n), в зависимости от используемого DK. Для зажигания светодиода на nRF51 DK (PCA10028) используйте ножку 24, для nRF52 DK (PCA10040) ножку 20.

Конфигурации таймслотов можно увидеть в функциях request_next_event_earliest(), configure_next_event_earliest() и configure_next_event_normal(). Здесь мы настраиваем таймслоты, которые используют нормальный приоритет и гарантированное использование кристаллов, что необходимо для использования radio. Обратите внимание, что мы настраиваем прерывание таймера непосредственно перед окончанием таймслота, чтобы приложение знало, что оно должно завершить активность таймслота.

#include < stdint.h>
#include < stdbool.h>
#include "nrf.h"
#include "app_error.h"
#include "nrf_gpio.h"
#include "softdevice_handler.h"
#include "boards.h"
 
/** Константы для timeslot API
 */
static nrf_radio_request_t  m_timeslot_request;
static uint32_t             m_slot_length;
 
static nrf_radio_signal_callback_return_param_t signal_callback_return_param;
 
/**@brief Запрос следующего события таймслота в конфигурации
 *        "earliest" (как можно быстрее).
 */
uint32_t request_next_event_earliest(void)
{
   m_slot_length                                 = 15000;
   m_timeslot_request.request_type               = NRF_RADIO_REQ_TYPE_EARLIEST;
   m_timeslot_request.params.earliest.hfclk      = NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED;
   m_timeslot_request.params.earliest.priority   = NRF_RADIO_PRIORITY_NORMAL;
   m_timeslot_request.params.earliest.length_us  = m_slot_length;
   m_timeslot_request.params.earliest.timeout_us = 1000000;
   return sd_radio_request(&m_timeslot_request);
}
 
/**@brief Конфигурирование следующего события таймслота
  *        в конфигурации "earliest"
 */
void configure_next_event_earliest(void)
{
   m_slot_length                                 = 15000;
   m_timeslot_request.request_type               = NRF_RADIO_REQ_TYPE_EARLIEST;
   m_timeslot_request.params.earliest.hfclk      = NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED;
   m_timeslot_request.params.earliest.priority   = NRF_RADIO_PRIORITY_NORMAL;
   m_timeslot_request.params.earliest.length_us  = m_slot_length;
   m_timeslot_request.params.earliest.timeout_us = 1000000;
}
 
/**@brief Конфигурирование следующего события таймслота
 *        в конфигурации "normal"
 */
void configure_next_event_normal(void)
{
   m_slot_length                                = 15000;
   m_timeslot_request.request_type              = NRF_RADIO_REQ_TYPE_NORMAL;
   m_timeslot_request.params.normal.hfclk       = NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED;
   m_timeslot_request.params.normal.priority    = NRF_RADIO_PRIORITY_HIGH;
   m_timeslot_request.params.normal.distance_us = 100000;
   m_timeslot_request.params.normal.length_us   = m_slot_length;
}
 
/**@brief Обработчик сигналов таймслота (Timeslot signal handler)
 */
void nrf_evt_signal_handler(uint32_t evt_id)
{
   uint32_t err_code;
   switch (evt_id)
   {
   case NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN:
      // Здесь не нужна никакая реализация
      break;
   case NRF_EVT_RADIO_SESSION_IDLE:
      // Здесь не нужна никакая реализация
      break;
   case NRF_EVT_RADIO_SESSION_CLOSED:
      // Здесь не нужна никакая реализация, session ended
      break;
   case NRF_EVT_RADIO_BLOCKED:
      // Провалимся дальше...
   case NRF_EVT_RADIO_CANCELED:
      err_code = request_next_event_earliest();
      APP_ERROR_CHECK(err_code);
      break;
   default:
      break;
   }
}
 
/**@brief Обработчик событий таймслота (Timeslot event handler)
 */
nrf_radio_signal_callback_return_param_t * radio_callback(uint8_t signal_type)
{
   switch(signal_type)
   {
   case NRF_RADIO_CALLBACK_SIGNAL_TYPE_START:
      // Старт таймслота - настройка прерывания таймера
      signal_callback_return_param.params.request.p_next = NULL;
      signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
 
      NRF_TIMER0->INTENSET = TIMER_INTENSET_COMPARE0_Msk;
      NRF_TIMER0->CC[0] = m_slot_length - 1000;
      NVIC_EnableIRQ(TIMER0_IRQn);   
 
      nrf_gpio_pin_toggle(20);   // Переключение LED4
      break;
 
   case NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO:
      signal_callback_return_param.params.request.p_next = NULL;
      signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
      break;
 
   case NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0:
      // Прерывание таймера - делаем корректный shutdown - планируем следующий таймслот
      configure_next_event_normal();
      signal_callback_return_param.params.request.p_next = &m_timeslot_request;
      signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END;
      break;
 
   case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED:
      // Здесь не нужна никакая реализация
      break;
 
   case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED:
      // Попытка запланировать новый таймслот
      configure_next_event_earliest();
      signal_callback_return_param.params.request.p_next = &m_timeslot_request;
      signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END;
      break;
 
   default:
      // Здесь не нужна никакая реализация
      break;
   }
   return (&signal_callback_return_param);
}
 
/**@brief Функция для инициализации timeslot API.
 */
uint32_t timeslot_sd_init(void)
{
    uint32_t err_code;
    
    err_code = sd_radio_session_open(radio_callback);
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }
    
    err_code = request_next_event_earliest();
    if (err_code != NRF_SUCCESS)
    {
        (void)sd_radio_session_close();
        return err_code;
    }
    return NRF_SUCCESS;
}

[Взаимодействие с кодом main]

Следующее, что нам нужно - реализовать интерфейс timeslot.c с модулем main. Начнем с создания файла заголовка.

1. Сделайте правый клик на папке приложения, и выберите Add New Item to Group 'Application'...

2. Выберите Header File, и дайте ему имя timeslot.h.

3. Скопируйте в этот файл следующий код.

#ifndef TIMESLOT_H__
#define TIMESLOT_H__
 
#include < stdint.h>
#include "nrf.h"
#include "app_error.h"
#include "nrf_gpio.h"
#include "softdevice_handler.h"
#include "boards.h"
 
/**@brief Обработчик события радио (Radio event handler)
 */
void RADIO_timeslot_IRQHandler(void);
 
/**@brief Запрос следующего события таймслота
 *        в конфигурации "earliest"
 */
uint32_t request_next_event_earliest(void);
 
/**@brief Конфигурирование следующего события таймслота
 *        в конфигурации "earliest"
 */
void configure_next_event_earliest(void);
 
/**@brief Запрос следующего события таймслота
 *        в конфигурации "normal"
 */
void configure_next_event_normal(void);
 
/**@brief Обработчик сигнала таймслота (Timeslot signal handler)
 */
void nrf_evt_signal_handler(uint32_t evt_id);
 
/**@brief Обработчик события таймслота (Timeslot event handler)
 */
nrf_radio_signal_callback_return_param_t * radio_callback(uint8_t signal_type);
 
/**@brief Функция для инициализации timeslot API.
 */
uint32_t timeslot_sd_init(void);
 
#endif

Теперь надо добавить путь поиска до созданного заголовка в проект.

4. Перейдите в меню Projects -> Options for Target (Alt+F7).

5. Выберите закладку C/C++, добавьте в Include Paths путь до файла заголовка timeslot.h. В нашем примере это папка ..\arm5_no_packs.

Keil Project Options edit include search paths

6. Добавьте в файл main.c подключение заголовка timeslot.h:

#include "timeslot.h"

7. Нужно добавить обработчик сигнала (signal handler) к диспетчеру системных событий (system event dispatcher). Для этого в тело подпрограммы диспетчера sys_evt_dispatch добавьте вызов nrf_evt_signal_handler (изначальный код может выглядеть немного иначе):

static void sys_evt_dispatch(uint32_t sys_evt)
{
   pstorage_sys_event_handler(sys_evt);
   ble_advertising_on_sys_evt(sys_evt);
   // Эта строка была добавлена:
   nrf_evt_signal_handler(sys_evt);
}

8. В тело функции main нужно добавить инициализацию таймслота непосредственно перед входом в бесконечный цикл main:

timeslot_sd_init();

Скомпилируйте и прошейте код проекта в свой DK. Убедитесь, что в DK запрограммирован S130/132 SoftDevice. Если все в порядке, то будет наблюдаться периодическое мигание LED4, и устройство будет выдавать пакеты радиооповещения (advertising) как Nordic_Template. Если подключиться к устройству (например, с помощью приложения nRF Correct), то это никак не повлияет на функциональность миганий LED4.

[Запрос расширения интервала]

Можно запросить расширение (extension) формируемого таймслота. Это расширение может быть больше 200 мкс, и не может быть кумулятивно больше чем 128 сек. Следующий пример показывает создание расширения интервала:

case NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0:
   // Прерывание таймера - попытка увеличить (расширить) длительность таймслота:
   signal_callback_return_param.params.extend.length_us = m_slot_length;
   signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND;
   break;
 
case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED:
   // Расширение было успешным, сброс таймера (конфигурация остается допустимой,
   // поскольку длительность слота та же самая):
   NRF_TIMER0->TASKS_CLEAR = 1;
   break;
 
case NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED:
   // Неудача расширения длительности, планирование нового таймслота
   // в самое ближайшее (earliest) время:
   configure_next_event_earliest();
   signal_callback_return_param.params.request.p_next = &m_timeslot_request;
   signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END;
   break;

[Пример чтения датчика температуры DS18B20]

Для примера использовался код из проекта [6]. С помощью тайм-слотов реализация протокола оказалась довольно простой. Код чтения датчика добавляется в case-ветку NRF_RADIO_CALLBACK_SIGNAL_TYPE_START обработчика событий таймслота radio_callback (добавленный код показан жирным шрифтом):

/**@brief Обработчик событий таймслота (Timeslot event handler)
 */
nrf_radio_signal_callback_return_param_t * radio_callback (uint8_t signal_type)
{
   uint32_t temp32;
   switch(signal_type)
   {
   case NRF_RADIO_CALLBACK_SIGNAL_TYPE_START:
      // Старт таймслота - настройка прерывания таймера
      signal_callback_return_param.params.request.p_next = NULL;
      signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
 
      NRF_TIMER0->INTENSET = TIMER_INTENSET_COMPARE0_Msk;
      NRF_TIMER0->CC[0] = m_slot_length;
      NVIC_EnableIRQ(TIMER0_IRQn);   
 
      ds18b20_setResolution(12);
      temp32 = ds18b20_get_temp_method_1();
      SEGGER_RTT_printf(0, "%u.%04u\n", temp32/10000, temp32%10000);
break; ...

Примечание: необязательно делать вызов функции ds18b20_setResolution(12), потому что по умолчанию DS18B20 работает с разрешающей способностью измерения температуры в 12 бит.

Отладочный вывод в RTT результатов чтения DS18B20:

OneWire read DS18B20 RTT output

[Ссылки]

1. Setting up the Timeslot API site:devzone.nordicsemi.com.
2. SoftDevice Specification S132 SoftDevice v3.0 site:infocenter.nordicsemi.com.
3. iButton: описание протокола, электронный замок на ключах-таблетках.
4. Running micro-ESB concurrently with BLE site:devzone.nordicsemi.com.
5. nRF Connect site:nordicsemi.com.
6. sigurdnev / Nordic-DS18B20 site:github.com.
7220209nRF5x-timeslot-OneWire-sdk12_3_0.zip - примеры кода с использованием Timeslot API и реализацией OneWire на nRF5x.