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

SPI calls and bluetooth send from GPIOTE handler

Hello!

I have based myself on the ble_app_uart example, taken out the UART bit, and all that remains is the bluetooth functionality.

I have also implemented SPI communication which works fine in a Timer and directly in the main loop.

However, it seems to go into a hard fault when I am using a GPIOTE handler:

#define SCHED_MAX_EVENT_DATA_SIZE       sizeof(app_timer_event_t)                   /**< Maximum size of scheduler events. Note that scheduler BLE stack events do not contain any data, as the events are being pulled from the stack in the event handler. */
#define SCHED_QUEUE_SIZE                10                                          /**< Maximum number of events in the scheduler queue. */

static void gpio_init(void)
{
	ret_code_t err_code;

	nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_LOTOHI(true);
	//in_config.pull = NRF_GPIO_PIN_PULLUP;

	err_code = nrf_drv_gpiote_in_init(ADXL362_INTERRUPT_PIN, &in_config, in_pin_handler);
	APP_ERROR_CHECK(err_code);

	nrf_drv_gpiote_in_event_enable(ADXL362_INTERRUPT_PIN, true);
}

// .....
    
void in_pin_handler(void *data, uint16_t size)
{
	// Call SPI spi_master_send_recv
	// Call ble_nus_string_send
}

This didn't work out, so I tried app_scheduler.

static void scheduler_init()
{
	APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
}

// ...

void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{	
	UNUSED_VARIABLE(m_buffer);
	app_sched_event_put(NULL, 0, in_pin_scheduler_func);
}

// ...

int main(void)
{
	uint32_t err_code;
	timers_init();
	gpio_init(); // GPIOTE
	scheduler_init();
	ble_stack_init();
	gap_params_init();
	services_init();
	advertising_init();
	conn_params_init();		
	err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
	APP_ERROR_CHECK(err_code);
	Adxl362_Initialize();  // SPI
	nrf_drv_gpiote_out_set(BSP_LED_0);
	// Enter main loop.
	for (;;)
	{
		app_sched_execute();
		power_manage();
	}
}

So when the ADXL362 interrupt goes high, then it does trigger the GPIOTE interrupt, and according to ADXL362 's spec I need to invoke STATUS read from it to reset the event ( for it to go low ). This is where it crashes.

Is it supposed to hard fault like this?

  • Well no it's not supposed to hardfault, that would be bad.

    Most common cause of hardfault is calling an sd_* function from an interrupt level higher (ie numerically lower) than the SVC call is set up to use, which is 2.

    You're shuffling the GPIOTE interrupt servicing off to a scheduler routine, ok so what's in that runs in main thread context, so that shouldn't be it - you have anything else, anything in a timer handler, GPIOTE handler, any other handler at all which calls any kind of BTLE-related code which ends up calling an sd_* function? If so what's the priority of the context you're calling it in, if it's APP_HIGH, it's too high and the device will hardfault.

    If not - what's the exact line of code you're crashing on?

  • Thanks for your quick answer!

    I thought passing it to the scheduler is smart to not hinder the IRQ and to not cause issues. This is the right design, right?

    There is nothing else in the IRQ handler. My "in_pin_handler" has nothing else than in the code I posted. It seems like my ISP is unstable (wiring problem). Good to know that my code is "clean"!

    However, when I try to connect through the Nordic UART Android I get disconnected as fast as I connect.

    #define APP_TIMER_MAX_TIMERS            (2 + BSP_APP_TIMERS_NUMBER)                 /**< Maximum number of simultaneously created timers. */
    void in_pin_scheduler_func(void *data, uint16_t size)
    {	
    	uint8_t status = Adxl362_GetStatus();
    	UNUSED_VARIABLE(status);
    
    	int16_t x, y, z;
    	Adxl362_GetAcceleration(&x, &y, &z);
    	//
    	sprintf((char *)&m_buffer[0], "%X (%d) - %d,%d,%d", status, status & (1 << 6) ? 1 : 0, x,y,z);
    	ble_nus_string_send(&m_nus, m_buffer, sizeof(m_buffer));
    
    	//nrf_drv_gpiote_out_toggle(BSP_LED_3);
    }
    

    Is this correct? I stopped initializing LEDs and buttons as you can see in main ()

    EDIT: The m_buffer was too small for the string. How big strings can I send in one go?

    EDIT2: Found it! BLE_NUS_MAX_DATA_LEN

Related