Hi,
nRF52832, SDK 17.1.0 with Softdevice S132.
Softdevice sleep does not work when advertising. Application flow is to advertise one packet, then go to sleep for X seconds. Sleep part waits for a flag from "BLE_GAP_EVT_ADV_SET_TERMINATED" event.
If "sd_app_evt_wait" is replaced with "__WFI" when sleep works but BLE does not advertise anymore(even BLE_GAP_EVT_ADV_SET_TERMINATED is received).
Any idea how to put device to sleep?
This code works
//BLE::advertise(&data, sizeof(data));
while (1)
{
/*if (System::isWoken() == Return_t::OK)
{
BLE::advertise(&data, sizeof(data));
}*/
//if (BLE::isAdvertiseDone() == Return_t::OK)
if (1)
{
System::startWakeupTimer();
System::sleep();
}
// Feed the dog
System::feedWatchdog();
}
This code does not work(consumption around ~3.5mA)
BLE::advertise(&data, sizeof(data));
while (1)
{
if (System::isWoken() == Return_t::OK)
{
BLE::advertise(&data, sizeof(data));
}
if (BLE::isAdvertiseDone() == Return_t::OK)
//if (1)
{
System::startWakeupTimer();
System::sleep();
}
// Feed the dog
System::feedWatchdog();
}
sleep function:
void sleep(void)
{
__set_FPSCR(__get_FPSCR() & ~(0x0000009F));
(void) __get_FPSCR();
sd_nvic_ClearPendingIRQ(FPU_IRQn);
sd_power_dcdc_mode_set(NRF_POWER_DCDC_DISABLE);
_PRINT("Sleep\n");
sd_app_evt_wait();
sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE);
}
Only RTC2 IRQ is enabled. FPU is disabled(soft FPU is used).
System init
Return_t init(void)
{
// Test crystals only in debug build
#ifdef DEBUG
_PRINT("Wait for HFXO\n");
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
NRF_CLOCK->TASKS_HFCLKSTART = 1;
while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
_PRINT("HFXO started\n");
_PRINT("Wait for LFXO\n");
NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
NRF_CLOCK->TASKS_LFCLKSTART = 1;
while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0);
NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
_PRINT("LFXO started\n");
#endif // DEBUG
// Configure power
NRF_POWER->POFCON = 0;
NRF_POWER->DCDCEN = 1;
// Init watchdog
NRF_WDT->CRV = (AppConfig::wdtTimeout * 32768) - 1;
#ifdef DEBUG
NRF_WDT->CONFIG = 1;
#else
NRF_WDT->CONFIG = 9;
#endif // DEBUG
NRF_WDT->TASKS_START = 1;
// Enable RTC interrupt
ret_code_t ret = sd_nvic_SetPriority(RTC2_IRQn, 2);
if (ret != NRF_SUCCESS)
{
APP_ERROR_CHECK(ret);
return Return_t::NOK;
}
ret = sd_nvic_EnableIRQ(RTC2_IRQn);
if (ret != NRF_SUCCESS)
{
APP_ERROR_CHECK(ret);
return Return_t::NOK;
}
// Enable compare0 interrupt
NRF_RTC2->INTENSET = (1 << 16);
// Set counter resolution of 125ms
NRF_RTC2->PRESCALER = 4095;
startWakeupTimer();
return Return_t::OK;
}
void startWakeupTimer(void)
{
NRF_RTC2->TASKS_CLEAR = 1;
NRF_RTC2->CC[0] = (AppConfig::measurePeriod * 1000) / 125;
NRF_RTC2->TASKS_START = 1;
_PRINT_INFO("Wakeup timer started\n");
}
EDIT: BLE init functions
Return_t init(void)
{
ret_code_t ret;
ret = nrf_sdh_enable_request();
if (ret != NRF_SUCCESS)
{
APP_ERROR_CHECK(ret);
return Return_t::NOK;
}
// Configure the BLE stack using the default settings.
uint32_t ramStart = 0;
ret = nrf_sdh_ble_default_cfg_set(AppConfig::bleTag, &ramStart);
if (ret != NRF_SUCCESS)
{
APP_ERROR_CHECK(ret);
return Return_t::NOK;
}
// Enable BLE stack.
ret = nrf_sdh_ble_enable(&ramStart);
if (ret != NRF_SUCCESS)
{
APP_ERROR_CHECK(ret);
return Return_t::NOK;
}
// Register a handler for BLE events.
NRF_SDH_BLE_OBSERVER(m_ble_observer, 3, onBLEEvent, NULL);
// Init GAP profile
if (gapInit() != Return_t::OK)
{
return Return_t::NOK;
}
// Get MAC address
ble_gap_addr_t addr;
ret = sd_ble_gap_addr_get(&addr);
if (ret != NRF_SUCCESS)
{
APP_ERROR_CHECK(ret);
return Return_t::NOK;
}
_PRINTF_INFO("MAC: %02X%02X%02X%02X%02X%02X\n", addr.addr[5], addr.addr[4], addr.addr[3], addr.addr[2], addr.addr[1], addr.addr[0]);
// Request HFXO
ret = sd_clock_hfclk_request();
if (ret != NRF_SUCCESS)
{
APP_ERROR_CHECK(ret);
return Return_t::NOK;
}
// Init advertise
return advInit();
}
/**
* @brief Advertise data.
*
* @return \c Return_t::NOK on fail.
* @return \c Return_t::OK on success.
*/
Return_t advertise(const void* data, const uint8_t len)
{
// Set custom data
ble_advdata_manuf_data_t mnfData;
mnfData.company_identifier = AppConfig::bleMnfID;
mnfData.data.p_data = (uint8_t*)data;
mnfData.data.size = len;
// Set advertise data
ble_advdata_t advData;
memset(&advData, 0, sizeof(advData));
advData.name_type = BLE_ADVDATA_FULL_NAME;
advData.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
advData.p_manuf_specific_data = &mnfData;
advData.p_tx_power_level = &txPower;
// Encode advertise data
ret_code_t ret = ble_advdata_encode(&advData, gapAdvData.adv_data.p_data, &gapAdvData.adv_data.len);
if (ret != NRF_SUCCESS)
{
APP_ERROR_CHECK(ret);
return Return_t::NOK;
}
// Advertise data
advDone = 0;
ret = sd_ble_gap_adv_start(advHandle, AppConfig::bleTag);
if (ret != NRF_SUCCESS)
{
APP_ERROR_CHECK(ret);
return Return_t::NOK;
}
return Return_t::OK;
}
/**
* @brief Init BLE GAP profile.
*
* @return \c Return_t::NOK on fail.
* @return \c Return_t::OK on success.
*/
static Return_t gapInit(void)
{
ble_gap_conn_sec_mode_t securtiyMode;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&securtiyMode);
ret_code_t ret = sd_ble_gap_device_name_set(&securtiyMode, (const uint8_t*)AppConfig::deviceName, __CONST_STR_LEN(AppConfig::deviceName));
if (ret != NRF_SUCCESS)
{
APP_ERROR_CHECK(ret);
return Return_t::NOK;
}
return Return_t::OK;
}
/**
* @brief Init BLE advertise.
*
* @return \c Return_t::NOK on fail.
* @return \c Return_t::OK on success.
*/
static Return_t advInit(void)
{
// Set advertise config
advConfig.primary_phy = BLE_GAP_PHY_AUTO;
advConfig.duration = 0;
advConfig.properties.type = BLE_GAP_ADV_TYPE_NONCONNECTABLE_SCANNABLE_UNDIRECTED;
advConfig.max_adv_evts = AppConfig::advCount;
advConfig.p_peer_addr = nullptr;
advConfig.filter_policy = BLE_GAP_ADV_FP_ANY;
advConfig.interval = 32; // Does not matter since max advertise event is set to 1
ret_code_t ret = sd_ble_gap_adv_set_configure(&advHandle, &gapAdvData, &advConfig);
if (ret != NRF_SUCCESS)
{
APP_ERROR_CHECK(ret);
return Return_t::NOK;
}
// Set TX power
ret = sd_ble_gap_tx_power_set(BLE_GAP_TX_POWER_ROLE_ADV, advHandle, txPower);
if (ret != NRF_SUCCESS)
{
APP_ERROR_CHECK(ret);
return Return_t::NOK;
}
return Return_t::OK;
}