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, 

    sorry for the shitty code formation.  I am using no nrf connect sdk at the moment. I am running the code on windows in Segger Embedded Studio. My device is at least configured as mtd, but  I don't know there to configure it as a SED. Is there any example code?
    the high energy consumption is around 11 mA. If it is in the shutdown mode the energy consumption ist 4 uA.

    I am already using NRF_LOG_PROCESS == false, but it is shutting down before everything is on the command line. 

Reply
  • Hi, 

    sorry for the shitty code formation.  I am using no nrf connect sdk at the moment. I am running the code on windows in Segger Embedded Studio. My device is at least configured as mtd, but  I don't know there to configure it as a SED. Is there any example code?
    the high energy consumption is around 11 mA. If it is in the shutdown mode the energy consumption ist 4 uA.

    I am already using NRF_LOG_PROCESS == false, but it is shutting down before everything is on the command line. 

Children
  • Hi

    To avoid misunderstandings, I would like to make sure which SDK is used.
    Are you using the nRF5 SDK or the nRF Connect SDK?
    Which version are you using of the relevant SDK?
    (For example "nRF5 SDK 17.1.0" or "nRF Connect SDK v1.9.1")

    Verena said:
    I don't know there to configure it as a SED. Is there any example code?

    This question depends on SDK.

    Verena said:
    I am already using NRF_LOG_PROCESS == false, but it is shutting down before everything is on the command line. 

    Try to use the debugging feature in Segger Embedded Studio. This might give insight into your issue with the crash.

    Regards,
    Sigurd Hellesvik

Related