Wake up from deep sleep and make a specific button action with nrf52 on thread

Hey,

I want to build something like a door sensor. So my device should sleep and if the button is pressed it should wake up and send a message to the leader via thread. I am using two nRF52480 DK.

I am struggling with different Problems

1)with using thread_sleep() the sending and receiving of the data is working, but the energy consumption is very high. So instead I tried to use nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF). The power consumption is good, but if I am pressing a button the system is just reseting and the action of the button is not exeecuted. How can I implement the button event?

2) the shutdown is executed before everything is printed on the terminal. How can I prevent this?

I attached my code and would be really glad about any help.

Best regards 

Verena

#include "app_scheduler.h"
#include "app_timer.h"
#include "nrf_log_ctrl.h"
#include "nrf_log.h"
#include "nrf_log_default_backends.h"
#include "bsp.h"
#include "thread_utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <boards.h>
#include "nrf_delay.h"
#include "nrf_gpio.h"
#include "nrf_drv_gpiote.h"
#include "nrf_pwr_mgmt.h"

#include <openthread/thread.h>
#include <openthread/udp.h>
#include <openthread/cli.h>
#include <openthread/coap.h>

#define SCHED_QUEUE_SIZE 32 /**< Maximum number of events in the scheduler queue. */
#define SCHED_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE /**< Maximum app_scheduler event size. */

#define MY_THREAD_PANID 0xcafe
#define MY_THREAD_EXT_PANID {0xca, 0xfe, 0x00, 0x00, 0xab, 0xce, 0x11, 0x22}
#define MY_THREAD_NETWORK_NAME "WSN"

#define INTERRUPT_PIN BUTTON_2
const uint32_t led_pin[] = {13,14,15,16};
#define PIN_IN BSP_BUTTON_0
#define PIN_OUT_1 BSP_LED_1
#define PIN_OUT_2 BSP_LED_2


static void bsp_event_handler(bsp_event_t event);
static void coap_send_data_request(void);
static void coap_send_data_response_handler(void * p_context, otMessage * p_message,
const otMessageInfo * p_message_info, otError result);

/**@brief Function for sending a data request. */
static void coap_send_data_request(void){
otError error = OT_ERROR_NONE;
otMessage * myMessage;
otMessageInfo myMessageInfo;
otInstance * p_instance = thread_ot_instance_get();
const char * serverIpAddr = "ff02::1";
//"fd00:0:fb01:1:bd5f:a165:30e9:52de";
//"fd00:0:fb01:1::1";
const char * myTemperatureJson = "{\"temperature\": 23.32}";

do{
//Create a new message
myMessage = otCoapNewMessage(p_instance, NULL);
if (myMessage == NULL) {
NRF_LOG_INFO("Failed to allocate message for CoAP Request\r\n");
return;
}
//Set CoAP type and code in the message
otCoapMessageInit(myMessage, OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_PUT);

//Add the URI path option in the message
error = otCoapMessageAppendUriPathOptions(myMessage, "storedata");
if (error != OT_ERROR_NONE){ break; }

//Add the content format option in the message
error = otCoapMessageAppendContentFormatOption(myMessage, OT_COAP_OPTION_CONTENT_FORMAT_JSON );
if (error != OT_ERROR_NONE){ break; }

//Set the payload delimiter in the message
error = otCoapMessageSetPayloadMarker(myMessage);
if (error != OT_ERROR_NONE){ break; }

///Append the payload to the message
error = otMessageAppend(myMessage, myTemperatureJson, strlen(myTemperatureJson));
if (error != OT_ERROR_NONE){ break; }

//Set the UDP-destination port of the CoAP-server
memset(&myMessageInfo, 0, sizeof(myMessageInfo));
myMessageInfo.mPeerPort = OT_DEFAULT_COAP_PORT;

//Set the IP-address of the CoAP-server
error = otIp6AddressFromString(serverIpAddr, &myMessageInfo.mPeerAddr);
if (error != OT_ERROR_NONE){ break; }

//Send CoAP-request
error = otCoapSendRequest(p_instance, myMessage, &myMessageInfo, coap_send_data_response_handler, NULL);
}while(false);

if (error != OT_ERROR_NONE) {
NRF_LOG_INFO("Failed to send CoAP Request: %d\r\n", error);
otMessageFree(myMessage);
}else{
otCliOutputFormat("CoAP data send.\r\n\0");
}
}

/**@brief Function for handling the response of the request. */
static void coap_send_data_response_handler(void * p_context, otMessage * p_message,
const otMessageInfo * p_message_info, otError result){
if (result == OT_ERROR_NONE) {
otCliOutputFormat("Delivery confirmed.\r\n\0");
} else {
NRF_LOG_INFO("Delivery not confirmed: %d\r\n", result);
}
}

/**@brief Function for initializing the CoAP modul. */
void coap_init(void){
otInstance * p_instance = thread_ot_instance_get();
otError error = otCoapStart(p_instance, OT_DEFAULT_COAP_PORT);
if (error!=OT_ERROR_NONE)
NRF_LOG_INFO("Failed to start Coap: %d\r\n", error);
}

/**@brief Button handler. */
static void bsp_event_handler(bsp_event_t event){
switch (event) {
case BSP_EVENT_KEY_0:
nrf_gpio_pin_clear(led_pin[0]);
coap_send_data_request();
break;
default:
return; // no implementation needed
}
}

/**@brief Function for initializing the app timer module. */
static void timer_init(void){
uint32_t err_code = app_timer_init();
APP_ERROR_CHECK(err_code);
}

/**@brief Function for initializing the nrf log module. */
static void log_init(void){
ret_code_t err_code = NRF_LOG_INIT(NULL);
APP_ERROR_CHECK(err_code);

//NRF_LOG_DEFAULT_BACKENDS_INIT();
}

/**@brief Function for initializing the Thread Stack. */
static void thread_instance_init(void){
thread_configuration_t thread_configuration = {
.radio_mode = THREAD_RADIO_MODE_RX_ON_WHEN_IDLE,
.autocommissioning = false,
.autostart_disable = true,
};

thread_init(&thread_configuration);
thread_cli_init();

}

/**@brief Function for initializing scheduler module. */
static void scheduler_init(void){
APP_SCHED_INIT(SCHED_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
}

/*
* If no dataset is stored in the non-volitile storage we define the
* parameter for the thread-network:
* Network Name, Mesh Local Prefix, Extended PAN ID, PAN ID,
* Channel, Channel Mask, Network Key, PSKc, Security Policy
*/
void setNetworkParameter(void){

otInstance * myOtInstance = thread_ot_instance_get();
if(!otDatasetIsCommissioned(myOtInstance)){

otOperationalDataset aDataset;
memset(&aDataset, 0, sizeof(otOperationalDataset));

aDataset.mActiveTimestamp = 0;
aDataset.mComponents.mIsActiveTimestampPresent = true;

aDataset.mChannel = 11;
aDataset.mComponents.mIsChannelPresent = true;

aDataset.mChannelMask = (otChannelMask)0x7fff800;
aDataset.mComponents.mIsChannelMaskPresent = true;

aDataset.mPanId = (otPanId)MY_THREAD_PANID;
aDataset.mComponents.mIsPanIdPresent = true;

uint8_t extPanId[OT_EXT_PAN_ID_SIZE] = MY_THREAD_EXT_PANID;
memcpy(aDataset.mExtendedPanId.m8, extPanId, sizeof(aDataset.mExtendedPanId));
aDataset.mComponents.mIsExtendedPanIdPresent = true;

uint8_t key[OT_MASTER_KEY_SIZE] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff};
memcpy(aDataset.mMasterKey.m8, key, sizeof(aDataset.mMasterKey));
aDataset.mComponents.mIsMasterKeyPresent = true;

static char aNetworkName[] = MY_THREAD_NETWORK_NAME;
size_t length = strlen(aNetworkName);
ASSERT(length <= OT_NETWORK_NAME_MAX_SIZE);
memcpy(aDataset.mNetworkName.m8, aNetworkName, length);
aDataset.mComponents.mIsNetworkNamePresent = true;

uint8_t meshLocalPrefix[OT_MESH_LOCAL_PREFIX_SIZE]= {0xfd, 0x00, 0x00, 0x00, 0xfb, 0x01, 0x00, 0x01};
memcpy(aDataset.mMeshLocalPrefix.m8, meshLocalPrefix, sizeof(aDataset.mMeshLocalPrefix));
aDataset.mComponents.mIsMeshLocalPrefixPresent = true;

otDatasetSetActive(myOtInstance, &aDataset);
}
}

void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
if(nrf_gpio_pin_read(pin))
{
nrf_drv_gpiote_out_toggle(PIN_OUT_1);
coap_send_data_request();

}
else
{
nrf_drv_gpiote_out_toggle(PIN_OUT_2);
}
}

/**@brief Function for starting or joining the thread network. */
static void thread_network_start(void){
otInstance *myInstance;
myInstance = thread_ot_instance_get();

/* Start the Thread network interface (CLI cmd > ifconfig up) */
otIp6SetEnabled(myInstance, true);

/* Start the Thread stack (CLI cmd > thread start) */
otThreadSetEnabled(myInstance, true);
}

/*
Dieser Code läuft soweit, der Ruheverbrauch sind 3,2 uA. Der Aktive Energieverbauch sind ~16 mA. Der Code schläft
und lässt sich mit einem Button wieder aufwecken. ALlerdings wird das Programm dann wieder neu gestartet. Auf der Konsole
kommen nur "11gleich sende ich was " an. Die restlichen Nachrichten kommen nicht an. Ich weiß nicht genau warum. (evtl. wird
der Prozess zu früh abgeschalten?)
*/
int main(int argc, char *argv[]){

nrf_gpio_cfg_output(led_pin[3]);
nrf_gpio_pin_set(led_pin[3]);

log_init();
scheduler_init();
timer_init();
thread_instance_init();
setNetworkParameter();
thread_network_start();
coap_init();
uint32_t err_code = bsp_init(BSP_INIT_BUTTONS, bsp_event_handler);
APP_ERROR_CHECK(err_code);
otCliOutputFormat("11gleich sende ich was\r\n");
uint32_t counter = 0;
//this is for testing the connection and the coap data are send and received. only the confirmation is not printed
coap_send_data_request();
//NRF_LOG_DEFAULT_BACKENDS_INIT();
while (true) {

nrf_gpio_pin_clear(led_pin[3]);
thread_process();
app_sched_execute();
otCliOutputFormat("mhmmm das licht aus%d\r\n",counter);
if (NRF_LOG_PROCESS() == false &&counter == 1000) {
otCliOutputFormat("mööp, gleich geht das licht aus\r\n");
//thread_sleep();

nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF);
}
counter = counter +1;
}
//code after this will be never executed

}

Parents
  • Hi Verena

    1)with using thread_sleep() the sending and receiving of the data is working, but the energy consumption is very high. So instead I tried to use nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF). The power consumption is good, but if I am pressing a button the system is just reseting and the action of the button is not exeecuted. How can I implement the button event?

    Which version of the SDK are you using?

    Is your Thread device configured as a Sleepy End Device?

    You say "he energy consumption is very high". Can you give specific numbers?

    the shutdown is executed before everything is printed on the terminal. How can I prevent this?

    Try to use NRF_LOG_PROCESS().
    If you struggle to catch all the steps before the crash, I can also recommend using the debugging functionality.

    PS: In DevZone, we have functionality for adding code in formatted form.
    This will make it easier to work with the tickets, so I recommend that you use next time you want to share your code. See Insert-> Code.

    Regards,
    Sigurd Hellesvik

Reply
  • Hi Verena

    1)with using thread_sleep() the sending and receiving of the data is working, but the energy consumption is very high. So instead I tried to use nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_SYSOFF). The power consumption is good, but if I am pressing a button the system is just reseting and the action of the button is not exeecuted. How can I implement the button event?

    Which version of the SDK are you using?

    Is your Thread device configured as a Sleepy End Device?

    You say "he energy consumption is very high". Can you give specific numbers?

    the shutdown is executed before everything is printed on the terminal. How can I prevent this?

    Try to use NRF_LOG_PROCESS().
    If you struggle to catch all the steps before the crash, I can also recommend using the debugging functionality.

    PS: In DevZone, we have functionality for adding code in formatted form.
    This will make it easier to work with the tickets, so I recommend that you use next time you want to share your code. See Insert-> Code.

    Regards,
    Sigurd Hellesvik

Children
No Data
Related