my k_work or main loop seem to be starved by BLE

I'm using nRF connect SDK2.9.0. I don't create my threads. Instead, I have a GPIO interrupt and a k_timer interrupt, each doing their own job.

In my timer expiry function, I submit a work to the workqueue that do temperature sensing and PID control.

// Timer structure
static struct k_timer my_timer;

// thread context: temperature control and data transmission (temperature and ad5940)
static void temprt_work_handler(struct k_work *work);
K_WORK_DEFINE(temprt_work, temprt_work_handler);

// thread context: read ad5940 data
static void ECAFE_work_handler(struct k_work *work);
K_WORK_DEFINE(ECAFE_work, ECAFE_work_handler);




// Timer callback function
// timer callback should not do too much operation, otherwise will block other functions like ADC read
void timer_expiry_function(struct k_timer *timer_id)
{
	// Do minimal, non-blocking things here, then submit work. 
	k_work_submit(&temprt_work);
}

static void temprt_work_handler(struct k_work *work)
{

	uint64_t time_stamp;
	int64_t delta_time;

	time_stamp = k_uptime_get();

    log_count++;
	// LOG_INF("Timer callback triggered! Count = %d\n", log_count);
    // Add your processing here (e.g., reading the ADC)
	float adc_temp_reading = fetch_adc_value();
	
	// PID operations...
	k_yield();
}

static void ECAFE_work_handler(struct k_work *work){
	DataCount = APPBUFF_SIZE;
	//Deal with it and provide a buffer to store data we got
	AppAMPISR(AppBuff, &DataCount); 

	//Show the results to UART
	AMPShowResult((float*)AppBuff, DataCount); 

	k_yield();
}

In contrast, I didn't submit my work directly in my GPIO interrupt callback handler. Instead, I set a global flag to 1 interrupt callback handler, and inspect the flag in the main loop:

	while (1) {
		

		/* Check if interrupt flag which will be set when interrupt occurred. */
		if(AD5940_GetMCUIntFlag())
		{
		  AD5940_ClrMCUIntFlag(); /* Clear this flag */
		  LOG_INF("AD5940 INT flag on\n");
		  k_work_submit(&ECAFE_work);

		}

		//k_sleep(K_MSEC(delay_in_ms));
		k_usleep(200);

	}

Now, my problem is that if I enable BLE, my k_timer work is executed properly, but my ECAFE_work is never executed, although I can see the GPIO interrupt triggered and flag is set to 1. It seems that the flag inspection part in my main-loop is never executed. 

In my prj.conf I didn't set anything related to thread and priority. I'm wondering what's the default priority for my work queue and for the BLE? Could you help me identify the problem? Thank you very much.

  • Hi Kenneth

    I can see in dk_buttons_init() you do have an button_changed callback, so you could potentially trigger AD5940_EXTI_callback() from there.

    Do you mean that if I press a button, my AD5940_EXTI_callback() may be triggered?

    In fact I didn't press the button, the problem is that my AD5940_EXTI_callback() seems to never get executed. 

    Here's my implementation :

    /* Callback function for handling interrupts */
    static void AD5940_EXTI_callback(const struct device *dev, struct gpio_callback *cb,
      uint32_t pins)
    {
      printk("Interrupt detected on GPIO\n");
      /* Check if our pin triggered the interrupt */
      if (pins & BIT(INT_PIN)) {
        printk("Interrupt detected on pin %d\n", INT_PIN);
        /* Set your interrupt flag or perform additional processing here */
        AD5940IntFlag = 1;
      }
    }

    Though I am wondering if you need to place it after dk_buttons_init()

    I did try to place my AD5940_MCUResourceInit() after dk_buttons_init(), but the project didn't work as expected. Instead, it showes some weird behavior in COM port. So in my ECAFE_work (when AD5940_GetMCUIntFlag() is 1), the expected function is to print 5 sensor reading. If I place my AD5940_MCUResourceInit() after dk_buttons_init(), rather than disable dk_buttons_init(), I will need to wait a long time to see any output and have 1000 readings printed at the same time. This is some behavior I didn't expect.

    So I'm wondering how  dk_buttons_init() will affect my own gpio configurations. Thank you very much

  • Are you sure you have full control over the pins configured by dk_buttons_init(), that they for instance are all pulled-up and not by accident triggering continuously.

    Kenneth

  • Hi Kenneth,

    Thanks for pointing this out. This is a key point that helped me find the problem.  I was using some dk_button GPIO pins for SPI communication. So I found that if I enable dk_buttons_init(), those GPIO interrupts will be constantly triggered, resulting in the failure of my SPI data transmission. 

    Now I've understood and resolved this issue. Thank you very much.

Related