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; }