This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

BMD-350 not waking up from system off mode even after accelerometer interrupt

Hi all,

We have designed a PCB where we use BMD-350 ( which is based on nrf52832 ) , HX711 and the accelerometer ( MMA8452Q ) as primary components. The device is supposed to stay in a deep sleep mode and wake up only when the accelerometer detects an orientation change of more than a set threshold. It is supposed to wake up, transmit hx711 data through the BMD-350 and go back to sleep. Though we have tested the code with sd_app_event_wait () and it works fine, we wanted to test the deepest sleep mode i.e. System off mode of BLE. We have used the nrf_gpio_config_sense_input () and then used the command sd_power_system off. But after entering the system off mode, the BLE doesn't wake up from the accelerometer interrupt.

Here is the code snippet of int main:

int main(void)
{
	
	// Enable DC DC Converter for lower power usage
	nrf_power_dcdcen_set(true);
	
	while (1)
	{
		switch (system_state)
		{
		case SYSTEM_INIT:
			// System Init tings
			timers_init ();
			leds_init ();
			// Internal Peripheral Power Up
			// SAADC
			saadc_init ();
			saadc_sampling_event_init ();
			saadc_sampling_event_enable ();
			// User Timer
			start_timer ();
			// I2C
			twi_init ();
			enableAcclMOtionDetection ();
			// External Device Power Up
			ledInit ();
			nrf_gpio_pin_write (LED_BLUE, RESET);
			system_state = SYSTEM_RUNNING;
		
		case SYSTEM_RUNNING:
			watch_accl ();
			sd_app_evt_wait ();
			if (system_sleep_counter) break;
		
		case SYSTEM_BROADCAST_START:
			// BLE Stack Enable
			ble_stack_init ();
			HX711_power_up ();
			HX711_begin (128);
			HX711_set_offset (HX711_VALUE_OFFSET);
			advertising_activeate ();
			system_sleep_counter = SYSTEM_DATA_SEND_DURATION;
			system_state = SYSTEM_BROADCAST;
			break;
		
		case SYSTEM_BROADCAST:
			adv_active_machine ();
			if (system_sleep_counter) break;
		
		case SYSTEM_DEINIT:
			// External Device Power Down
			HX711_power_down ();
			nrf_gpio_pin_write (LED_BLUE, SET);
			// Internal Peripheral Power Down
			timers_deinit ();
			timerStop ();
			twi_disable ();
			saadc_deinit ();
			// BLE Power Down
			advertising_stop ();
			nrf_gpio_cfg_sense_input(ACCL_INT_1_PIN, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_SENSE_LOW);
			sd_power_system_off ();

		default:
			system_state = SYSTEM_INIT;
		}
	}

}

I have also attached the accelerometer c file ( accl.c ) for your reference. Can anyone help me in identifying why is the system not waking up from the accelerometer-generated interrupt in this configuration ?

#include "i2c_control.h"

#include "nrf_drv_gpiote.h"
#include "sdk_macros.h"
#include "boards.h"
#include "common_decl.h"
#include "timer_user.h"

extern uint32_t system_sleep_counter; /**< System sleep counter used in main for power managment */

// Accl related flags
uint8_t accl_int1_flag = RESET; /**< Accl intterupt flag */
uint8_t accl_read_flag = RESET; /**< Flag to tell it's time to read Accl */


/**@brief Accelerometer Interupt handler.
 *
 * @details This gets called when accelerometer raises hardware interrupt
 * 
 * @param pin Which pin raised interrupr
 * 
 * @param action Polarity of the Pin
 */
void acclIntHandler (nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
	// Clear interrupt flags
	NRF_GPIOTE->EVENTS_PORT = RESET;
	NRF_GPIOTE->EVENTS_IN[0] = RESET;
	NRF_GPIOTE->EVENTS_IN[1] = RESET;
	NRF_GPIOTE->EVENTS_IN[2] = RESET;
	NRF_GPIOTE->EVENTS_IN[3] = RESET;

	accl_int1_flag = SET;
	return;
}


/**@brief Chec if motion happening in Accelerometer
 *
 * @details Reads Accelerometer and gets the flags in Accelerometer 
 *					which tells wether acceleration is crossing threhhold
 * 
 * @return 1: Acceleration is crossing threhhold, 0: Acceleration not crossing threhhold
 * 
 */
uint8_t accl_check_motion_happening (void)
{
	uint8_t sub_addr_data[2];
	sub_addr_data[0] = 0x16;
	/*ret_code_t twi_write_read(uint8_t addr, uint8_t subaddr[], 
															uint8_t subaddr_len, uint8_t data_read[], 
															uint8_t data_len)
	*/
	twi_write_read (ACCL_SLAVE_ADDR, &sub_addr_data[0], 1, &sub_addr_data[1], 1);
	return (sub_addr_data[1] & 0x80);
}


/**@brief Watch Accelerometer
 *
 * @details Controls the main program by using *system_sleep_counter*
 *					according to status of *accl_int1_flag* *accl_read_flag* and *system_sleep_counter*
 * 
 */
void watch_accl (void)
{
	/* 
		When system_sleep_counter is 0, and interrupt is rasied by accelerometer
		system_sleep_counter will be set to SYSTEM_UP_DURATION which will wake up 
		the system. If system_sleep_counter goes to 0 the system goes to sleep
	*/
	if (accl_int1_flag && (!system_sleep_counter))
	{
		accl_int1_flag = RESET;
		system_sleep_counter = SYSTEM_UP_DURATION;
	}
	/*
		When is wakeup mode system_sleep_counter will be non zero.
		In wakeup mode at every ACCL_READ_FREQ the accelerometer's register will be read
		and if motion is going on, the system_sleep_counter will be set to SYSTEM_UP_DURATION
	*/
	if (system_sleep_counter)
	{
		if ((accl_read_flag) && (accl_check_motion_happening()))
		{
			accl_read_flag = RESET;
			system_sleep_counter = SYSTEM_UP_DURATION;
		}
	}
	return;
}


/**@brief Enable external interupt used by Accelerometer
 *
 * @details Enable external interupt used by Accelerometer and the callback function
 *
 * @return 32-bit success/error code
 * 
 */
uint32_t enableAcclExtInt (void)
{
	uint32_t err_code;
	// Configure the device INT1 Pin Input as Interrupt
	nrf_drv_gpiote_init ();
	nrf_drv_gpiote_in_config_t config = GPIOTE_RAW_CONFIG_IN_SENSE_HITOLO(false);
	config.pull = NRF_GPIO_PIN_PULLUP;
	config.skip_gpio_setup = false;
	err_code = nrf_drv_gpiote_in_init(ACCL_INT_1_PIN, &config, acclIntHandler);
	VERIFY_SUCCESS(err_code);
	nrf_drv_gpiote_in_event_enable (ACCL_INT_1_PIN, true);
	return err_code;
}


/**@brief Enable motion detection in Accelerometer
 *
 * @details Enable motion detection and configure Accelerometer for power saving 
 *					by wrting into it's registers over I2C.
 *
 * @return 32-bit success/error code
 * 
 */
uint32_t enableAcclMOtionDetection (void)
{
	uint8_t send_array [3];
	uint32_t err_code;
	
	// Put Module in Standby mode do the settings
	// And set Data Rate and auto_sleep to 12.5 Hz
	// Auto Wakeup Sleep frrequency to 12.5 Hz
	// Normal mode for LNOis and Fast Read
	send_array[0] = 0x2A; // Register adress CTRL_REG1
	send_array[1] = 0xF8; // Data to be written in the register
	err_code = twi_write (ACCL_SLAVE_ADDR, send_array, 2);
	VERIFY_SUCCESS(err_code);
	
	
	// Auto Sleep counter
	send_array[0] = 0x29; // Register adress FF_MT_CFG
	send_array[1] = 0x00; // Data to be written in the register
	err_code = twi_write (ACCL_SLAVE_ADDR, send_array, 2);
	VERIFY_SUCCESS(err_code);
	
	
	// Setting to detect motion, X and Y axis will be considered
	// only X and Y is considered beacause Z will always be 1g
	// and status registers will reset after event is over
	send_array[0] = 0x15; // Register adress FF_MT_CFG
	send_array[1] = 0xD8; // Data to be written in the register
	err_code = twi_write (ACCL_SLAVE_ADDR, send_array, 2);
	VERIFY_SUCCESS(err_code);
	
	// Setting to set threshhold to 1.25g 
	// The step count is 0.063g/ count� 1.25/0.063g = 19.4; //Round up to 20
	// DBCNTM bit is a logic �1�, the debounce counter is cleared to 0 
	// whenever the inertial event of interest is no longer true
	send_array[0] = 0x17; // Register adress FF_MT_THS
	send_array[1] = 0x82; // Data to be written in the register
	err_code = twi_write (ACCL_SLAVE_ADDR, send_array, 2);
	VERIFY_SUCCESS(err_code);
	
	// Debouce counter to avoid false reading
	// Set to 10 Counts
	send_array[0] = 0x18; // Register adress FF_MT_COUNT
	send_array[1] = 0x0A; // Data to be written in the register
	err_code = twi_write (ACCL_SLAVE_ADDR, send_array, 2);
	VERIFY_SUCCESS(err_code);
	
	// Enable Motion Interrupt Function in the System
	send_array[0] = 0x2D; // Register adress CTRL_REG4
	send_array[1] = 0x04; // Data to be written in the register
	err_code = twi_write (ACCL_SLAVE_ADDR, send_array, 2);
	VERIFY_SUCCESS(err_code);
	
	// Route the Motion Interrupt Function to INT1 hardware pin
	send_array[0] = 0x2E; // Register adress CTRL_REG5
	send_array[1] = 0x04; // Data to be written in the register
	err_code = twi_write (ACCL_SLAVE_ADDR, send_array, 2);
	VERIFY_SUCCESS(err_code);
		
	// Self test disabled, Reset at 0 
	// Sleep mode and normal mode power profile is se to Low power
	// Auto sleep enabled
	send_array[0] = 0x2B; // Register adress CTRL_REG2
	send_array[1] = 0x1F; // Data to be written in the register
	err_code = twi_write (ACCL_SLAVE_ADDR, send_array, 2);
	VERIFY_SUCCESS(err_code);
	
	// Activate the device aftr settings are done
	// And set Data Rate to 12.5 Hz
	// Auto Wakeup Sleep frrequency to 12.5 Hz
	// Normal mode for LNOis and Fast Read
	send_array[0] = 0x2A; // Register adress CTRL_REG1
	send_array[1] = 0xF9; // Data to be written in the register
	err_code = twi_write (ACCL_SLAVE_ADDR, send_array, 2);
	VERIFY_SUCCESS(err_code);
	
	err_code = enableAcclExtInt ();
	
	return err_code;
}

Any help would be appreciated. Thanks !

  • Hello,

    Though we have tested the code with sd_app_event_wait () and it works fine, we wanted to test the deepest sleep mode i.e. System off mode of BLE.

    It sounds like you are on the right path here, but I suspect a slight modification to your code is necessary to achieve this. The pin needs to be configured as a specific wakeup pin before going to SYSTEM OFF, while as waking from sd_app_evt_wait ( SYSTEM ON ) only requires an event.

    This is demonstrated in a lot of the BLE peripheral examples in the SDK, and I highly recommend that you take a look at how it is implemented there.
    For example, you could take a look at the sleep_mode_enter function of the BLE Peripheral HID Keyboard example from the SDK v.17.0.2.
    This functions is called to put the device in SYSTEM OFF, and prepares it for wakeup as the last thing it does before going to SYSTEM OFF.

    Please do not hesitate to let me know if anything should still be unclear, or if you have any questions related to this.

    Best regards,
    Karl

Related