RAK13011 power consumption

Hi,

Could you help me verify if a power draw of 13011 while in sleep mode is normal?

If I disconnect it, the reading drops automatically.

/**
 * @file RUI3-RAK13011-Alarm.ino
 * @author Bernd Giesecke ([email protected])
 * @brief RUI3 based code for a window and door alarm system
 * @version 0.1
 * @date 2022-10-29
 *
 * @copyright Copyright (c) 2022
 *
 */
#include "inc/app.h"

/** Initialization results */
bool ret;

/** LoRaWAN packet */
WisCayenne g_solution_data(255);

/** Packet is confirmed/unconfirmed (Set with AT commands) */
bool g_confirmed_mode = false;
/** If confirmed packet, number or retries (Set with AT commands) */
uint8_t g_confirmed_retry = 0;
/** Data rate  (Set with AT commands) */
uint8_t g_data_rate = 3;

/** Flag if transmit is active, used by some sensors */
volatile bool tx_active = false;

/** fPort to send packages */
uint8_t set_fPort = 2;

/** Flag if RAK1901 was found */
bool has_rak1901 = false;

/** Enable automatic DR selection based on payload size */
#if AUTO_DR == 1
bool auto_dr_enabled = true;
#else
bool auto_dr_enabled = false;
#endif

/**
 * @brief Callback after packet was received
 *
 * @param data Structure with the received data "este codigo recibe comando At y ejecuta en consola"
 */
void receiveCallback(SERVICE_LORA_RECEIVE_T *data)
{
    MYLOG("RX-CB", "RX, port %d, DR %d, RSSI %d, SNR %d", data->Port, data->RxDatarate, data->Rssi, data->Snr);
    for (int i = 0; i < data->BufferSize; i++)
    {
        Serial.printf("%02X", data->Buffer[i]);
    }
    Serial.print("\r\n");
    tx_active = false;

    // Parse the incoming command
    switch (data->Buffer[0] & 0xff)
    {
    // Change send interval (custom AT command)
    case 0x41:
    {
      if (data->BufferSize == 4) //---->AT+SENDINT
      {
         uint32_t new_value = (data->Buffer[1] << 16 | data->Buffer[2] << 8 | data->Buffer[3]);

    save_and_set_sendfreq(new_value);
        break;
      }
    }
    // Change data rate (standard AT command)
    case 0x02:
    {
        uint8_t new_value = data->Buffer[1];
        api.lorawan.dr.set(new_value);
        break;
    }
    // Other commands
    default:
        // Add additional cases for other commands if needed
      
        break;
    }
}

/**
 * @brief Handler for send frequency AT commands
 *
 * @param port Serial port used
 * @param cmd char array with the received AT command
 * @param param char array with the received AT command parameters
 * @return int result of command parsing
 * 			AT_OK AT command & parameters valid
 * 			AT_PARAM_ERROR command or parameters invalid
 */

/**
 * @brief Save and set new send interval
 * 
 * @param new_interval new interval time in milliseconds
 */

void save_and_set_sendfreq(uint32_t new_interval)
{
	// Assign new value
	g_custom_parameters.send_interval = new_interval;

   	MYLOG("APP", "New sendint %08X %d", new_interval, new_interval);
	// Stop the timer
	api.system.timer.stop(RAK_TIMER_0);
	if (g_custom_parameters.send_interval != 0)
	{
		// Restart the timer
		api.system.timer.start(RAK_TIMER_0, g_custom_parameters.send_interval, NULL);
	}
	// Save custom settings
	save_at_setting();
}


/**
 * @brief Callback after TX is finished
 *
 * @param status TX status
 */
void sendCallback(int32_t status)
{
	MYLOG("TX-CB", "TX status %d", status);
	digitalWrite(LED_BLUE, LOW);
	tx_active = false;
}

/**
 * @brief Callback after join request cycle
 *
 * @param status Join result
 */
void joinCallback(int32_t status)
{
	// MYLOG("JOIN-CB", "Join result %d", status);
	if (status != 0)
	{
		MYLOG("JOIN-CB", "LoRaWan OTAA - join fail! \r\n");
		// Do not leave the LED on while sleeping
		digitalWrite(LED_BLUE, LOW);
		// To be checked if this makes sense
		// api.lorawan.join();
	}
	else
	{
		// bool result_set = api.lorawan.dr.set(g_data_rate);
		// MYLOG("JOIN-CB", "Set the data rate  %s", result_set ? "Success" : "Fail");
		MYLOG("JOIN-CB", "LoRaWan OTAA - joined! \r\n");
		digitalWrite(LED_BLUE, LOW);
	}
}


/**
 * @brief Arduino setup, called once after reboot/power-up
 *
 */
void setup()
{
	// api.ble.advertise.start(30);

	if (api.lorawan.nwm.get() == 1)
	{
		g_confirmed_mode = api.lorawan.cfm.get();

		g_confirmed_retry = api.lorawan.rety.get();

		g_data_rate = api.lorawan.dr.get();

		// Setup the callbacks for joined and send finished
		api.lorawan.registerRecvCallback(receiveCallback);
		api.lorawan.registerSendCallback(sendCallback);
		api.lorawan.registerJoinCallback(joinCallback);
	}
	else
	{

	}

	pinMode(LED_GREEN, OUTPUT);
	digitalWrite(LED_GREEN, HIGH);
	pinMode(LED_BLUE, OUTPUT);
	digitalWrite(LED_BLUE, HIGH);

	// pinMode(WB_IO2, OUTPUT);
	// digitalWrite(WB_IO2, LOW);

	// Start Serial
	Serial.begin(115200);

	// Delay for 5 seconds to give the chance for AT+BOOT
	delay(5000);
	api.system.firmwareVersion.set("RUI3-Door-Alarm-V1.0.0");
	Serial.println("RAKwireless RUI3 Node");
	Serial.println("------------------------------------------------------");
	Serial.println("Setup the device with WisToolBox or AT commands before using it");
	Serial.printf("Ver %s\n", api.system.firmwareVersion.get().c_str());
	Serial.println("------------------------------------------------------");

	// Initialize module
	Wire.begin();
	if (!init_rak13011())
	{
		// MYLOG("SETUP", "Could not initialize RAK13011");
	}
	else
	{
		Serial.println("+EVT:RAK13011 OK");
	}

	// Register the custom AT command to get device status
	if (!init_status_at())
	{
		MYLOG("SETUP", "Add custom AT command STATUS fail");
	}
	digitalWrite(LED_GREEN, LOW);

	// Register the custom AT command to set the send interval
	if (!init_interval_at())
	{
		MYLOG("SETUP", "Add custom AT command Send Interval fail");
	}

	// Get saved sending interval from flash
	get_at_setting();

	/*
	if (!init_verification_at())
	{
	MYLOG("SETUP", "Add custom AT command VERINT fail");
	}
	else
	{
	MYLOG("SETUP", "VERINT AT command added successfully");
	Serial.printf("Verification interval: %ld seconds\r\n", 
				 g_custom_parameters.verification_interval / 1000);
	}
    */

	// Create a timer.
	api.system.timer.create(RAK_TIMER_0, sensor_handler, RAK_TIMER_PERIODIC);
	if (g_custom_parameters.send_interval != 0)
	{
		// Start a timer.
		api.system.timer.start(RAK_TIMER_0, g_custom_parameters.send_interval, NULL);
	}

	if (api.lorawan.nwm.get() == 0)
	{
		digitalWrite(LED_BLUE, LOW);

		sensor_handler(NULL);
	}
#if MY_DEBUG == 0
	MYLOG("SETUP", "Debug is disabled");
#else
	MYLOG("SETUP", "Debug is enabled");
#endif
#if AUTO_DR == 0
	MYLOG("SETUP", "Auto DR is disabled");
#else
	MYLOG("SETUP", "Auto DR is enabled");
#endif

	if (api.lorawan.nwm.get() == 1)
	{
		if (g_confirmed_mode)
		{
			MYLOG("SETUP", "Confirmed enabled");
		}
		else
		{
			MYLOG("SETUP", "Confirmed disabled");
		}

		MYLOG("SETUP", "Retry = %d", g_confirmed_retry);

		MYLOG("SETUP", "DR = %d", g_data_rate);
	}

	// To be checked if this makes sense
	// api.lorawan.join();

	// Force low power mode
	api.system.lpm.set(1);

#if defined(_VARIANT_RAK3172_) || defined(_VARIANT_RAK3172_SIP_)
// No BLE
#else
	Serial6.begin(115200, RAK_AT_MODE);
	api.ble.advertise.start(30);
#endif

// Check if sensors are connected and initialize them
	has_rak1901 = init_rak1901();
	if (has_rak1901)
	{
		Serial.println("+EVT:RAK1901");
	}

}

/**
 * @brief sensor_handler is a timer function called every
 * g_custom_parameters.send_interval milliseconds. Can be
 * changed with ATC+SENDINT command
 *
 */
void sensor_handler(void *)
{
    MYLOG("UPLINK", "Start");
    digitalWrite(LED_BLUE, HIGH);

    // Chequeo si estamos en LoRaWAN y si el nodo está unido
    if (api.lorawan.nwm.get() == 1)
    {
        if (!api.lorawan.njs.get())
        {
            MYLOG("UPLINK", "Not joined, skip sending");
            digitalWrite(LED_BLUE, LOW);
            return;
        }
    }

    // Limpiar payload
    g_solution_data.reset();

    // Leer sensores
    if (has_rak1901)
    {
        read_rak1901();
    }

    // Añadir batería y estado del switch
    g_solution_data.addVoltage(LPP_CHANNEL_BATT, api.system.bat.get());
    g_solution_data.addPresence(LPP_CHANNEL_SWITCH, switch_status);

    // Enviar el paquete
     send_packet();
    }
  

/**
 * @brief This example is complete timer
 * driven. The loop() does nothing than
 * sleep.
 *
 */
void loop()
{
	api.system.sleep.all();
	// api.system.scheduler.task.destroy();
}

/**
 * @brief Send the data packet that was prepared in
 * Cayenne LPP format by the different sensor and location
 * aqcuision functions
 *
 */
void send_packet(void)
{
	if (api.lorawan.nwm.get() == 1)
	{
		uint8_t proposed_dr = get_min_dr(api.lorawan.band.get(), g_solution_data.getSize());
		MYLOG("UPLINK", "Check if datarate allows payload size, proposed is DR %d, current DR is %d", proposed_dr, api.lorawan.dr.get());

		if (proposed_dr == 16)
		{
			MYLOG("UPLINK", "No matching DR found");
		}
		else
		{
			if (proposed_dr < api.lorawan.dr.get())
			{
				if (auto_dr_enabled)
				{
					MYLOG("UPLINK", "Proposed DR is lower than current selected, if enabled, switching to lower DR");
					api.lorawan.dr.set(proposed_dr);
				}
			}

			if (proposed_dr > api.lorawan.dr.get())
			{
				if (auto_dr_enabled)
				{
					MYLOG("UPLINK", "Proposed DR is higher than current selected, if enabled, switching to higher DR");
					api.lorawan.dr.set(proposed_dr);
				}
			}
		}

		// Send the packet
		if (api.lorawan.send(g_solution_data.getSize(), g_solution_data.getBuffer(), set_fPort, g_confirmed_mode, g_confirmed_retry))
		{
			MYLOG("UPLINK", "Packet enqueued, size %d", g_solution_data.getSize());
			tx_active = true;
		}
		else
		{
			MYLOG("UPLINK", "Send failed");
			// No send callback will come, turn the LED off here
			digitalWrite(LED_BLUE, LOW);
			tx_active = false;
		}
	}
	else
	{
		MYLOG("UPLINK", "Send packet with size %d over P2P", g_solution_data.getSize() + 8);

		digitalWrite(LED_BLUE, LOW);
		uint8_t packet_buffer[g_solution_data.getSize() + 8];
		if (!api.lorawan.deui.get(packet_buffer, 8))
		{
			MYLOG("UPLINK", "Could not get DevEUI");
		}

		memcpy(&packet_buffer[8], g_solution_data.getBuffer(), g_solution_data.getSize());

		for (int idx = 0; idx < g_solution_data.getSize() + 8; idx++)
		{
			Serial.printf("%02X", packet_buffer[idx]);
		}
		Serial.println("");

		if (api.lora.psend(g_solution_data.getSize() + 8, packet_buffer))
		{
			MYLOG("UPLINK", "Packet enqueued");
		}
		else
		{
			MYLOG("UPLINK", "Send failed");
		}
	}
}

What Core module?
What LoRaWAN class?
What Base Board?
What Sensor Slot?

Hi beegee,

Core: rak4630
Lorawan clase A
Base rak19007
Sensor slop A

I also use a temperature rak 1901 sensor in slop C.

No problems with the setup.
The measurement looks like the RAK4630 is permanently waking up. Could be caused by false interrupts on the RAK13011. (didn’t look on the time resolution, you recorded for > 20 seconds)

Run a quick test, average consumption 56 uA, so similar to yours.

Hello beegge,

So, this behavior is normal, because the RAK13011 is always powered by the 3V3S rail, waiting for an interrupt to send an uplink.

Alternatively, you could check with the development team regarding this behavior of the RAK13011.

 /**
 * @file RAK13011_switch.cpp
 * @author Bernd Giesecke ([email protected])
 * @brief RAK13011 Reed relay switch
 * @version 0.1
 * @date 2022-10-30
 *
 * @copyright Copyright (c) 2022
 *
 */
#include "../inc/app.h"
#include "../inc/ArrayQueue.h"

//******************************************************************//
// RAK13011 INT1_PIN
//******************************************************************//
// Slot A      WB_IO1
// Slot B      WB_IO2 ( not recommended, pin conflict with IO2)
// Slot C      WB_IO3
// Slot D      WB_IO5
// Slot E      WB_IO4
// Slot F      WB_IO6
//******************************************************************//

#define RAK13011_SLOT 'A'

/** Interrupt pin, depends on slot */
// #include "RAK13011_switch_S_A.h"

/** Interrupt pin, depends on slot */
// Slot A
#if RAK13011_SLOT == 'A'
#pragma message "Slot A"
#define SW_INT_PIN WB_IO1
// Slot B
#elif RAK13011_SLOT == 'B'
#pragma message "Slot B"
#define SW_INT_PIN WB_IO2
// Slot C
#elif RAK13011_SLOT == 'C'
#pragma message "Slot C"
#define SW_INT_PIN WB_IO3
// Slot D
#elif RAK13011_SLOT == 'D'
#pragma message "Slot D"
#define SW_INT_PIN WB_IO5
// Slot E
#elif RAK13011_SLOT == 'E'
#pragma message "Slot E"
#define SW_INT_PIN WB_IO4
// Slot F
#elif RAK13011_SLOT == 'F'
#pragma message "Slot F"
#define SW_INT_PIN WB_IO6
#endif

ArrayQueue Fifo;

volatile int switch_status = 0;

volatile bool handler_available = true;


void switch_int_handler(void)
{
	// No MYLOG here: it uses delay() and this runs in interrupt context
	switch_status = digitalRead(SW_INT_PIN);
	api.system.timer.start(RAK_TIMER_2, 50, NULL);
}

void switch_bounce_check(void *)
{
	MYLOG("REED", "Bounce check");
	// Serial.println("Interrupt");
	int new_switch_status = digitalRead(SW_INT_PIN);
	if (new_switch_status != switch_status)
	{
		MYLOG("REED", "Bounce detected");
		return;
	}
	if (switch_status == LOW)
	{
		// digitalWrite(LED_GREEN, HIGH);
		// digitalWrite(LED_BLUE, LOW);
		// disable_interrupts();
		if (!Fifo.enQueue(false))
		{
			// enable_interrupts();
			MYLOG("REED", "FiFo full");
			return;
		}
		// enable_interrupts();
	}
	else
	{
		// digitalWrite(LED_GREEN, LOW);
		// digitalWrite(LED_BLUE, HIGH);
		// disable_interrupts();
		if (!Fifo.enQueue(true))
		{
			// enable_interrupts();
			MYLOG("REED", "FiFo full");
			return;
		}
		// enable_interrupts();
	}

	MYLOG("REED", "Added event to queue");
	// if (Fifo.getSize() == 1)
	if (handler_available)
	{
		MYLOG("REED", "Start event handler");
		// Wake the switch handler
		// api.system.timer.start(RAK_TIMER_2, 50, NULL);
		handler_available = false;
		handle_rak13011(NULL);
	}
}

bool init_rak13011(void)
{
	// Create a timers for handling the events
	api.system.timer.create(RAK_TIMER_2, switch_bounce_check, RAK_TIMER_ONESHOT);
	api.system.timer.create(RAK_TIMER_3, handle_rak13011, RAK_TIMER_ONESHOT);


	MYLOG("REED", "Initialize Interrupt on pin %d", SW_INT_PIN);
	pinMode(SW_INT_PIN, INPUT);
	attachInterrupt(SW_INT_PIN, switch_int_handler, CHANGE);
	MYLOG("REED", "Interrupt Initialized ");

	return true;
}

void handle_rak13011(void *)
{
	if (!tx_active)
	{
		// Reset automatic interval sending if active
		if (g_custom_parameters.send_interval != 0)
		{
			// Restart a timer
			api.system.timer.stop(RAK_TIMER_0);
			api.system.timer.start(RAK_TIMER_0, g_custom_parameters.send_interval, NULL);
		}

		// Clear payload
		g_solution_data.reset();

		noInterrupts();
		g_solution_data.addPresence(LPP_CHANNEL_SWITCH, !Fifo.deQueue() ? 0 : 1);
		interrupts();

		// Add battery voltage
		g_solution_data.addVoltage(LPP_CHANNEL_BATT, api.system.bat.get());

		// Send the packet
		send_packet();
	}
	else
	{
		MYLOG("REED", "TX still active");
		// Fifo.deQueue();
	}

	MYLOG("REED", "Queue entries = %d", Fifo.getSize());
	if (!Fifo.isEmpty())
	{
		// Event queue is not empty. Trigger next packet in 5 seconds
		api.system.timer.start(RAK_TIMER_3, 5000, NULL);
	}
	else
	{
		handler_available = true;
		Serial.println("Queue is empty");
	}
}```

RAK13011 is not connected to 3V3_S. It is connected to the permanent 3.3V supply.

If the switch is open, you have current going through R4, roughly 33uA + the current taken by the base of the resistor.
If the switch is closed, you have roughly 33uA going through R5.

1 Like