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

Work queues

Hi 

Technically this is a Zephyr question, but googling the issue gave no success. Also, reading the Zephyr docs gavve me no clue. 

I have a custom nrf9160 board with an accelerometer (ADXL343). I have two scheduled tasks (starting and stopping GPS, starting and stopping accelerometer) that both are submitted to a work queue. 

First I tried to submit both tasks (as delayed work items) to the system work queue, with different delays. This did not work, only the last item pushed to the queue was started, and it was started at the time I expected  the first to start, even though the delay was much higher. 

Then I tried to define a work queue to solely for my gsensor task, and keeping the system work queue for my GPS task. The new work queue is specified and initialized according to Zephyr docs, see developer.nordicsemi.com/.../workqueue.html Now both tasks were started on the same millisec, according to the logs. This is happening every time I restart the device. 

[3.16 14.05.06.762]i2c	gsensor	init complete!
[3.16 14.05.06.762]Starting gsensor process in	4 minutes
[3.16 14.05.16.533]Send triggered!
[3.16 14.05.16.533]Gsensor	work started with thread id  0x20023434
[3.16 14.05.16.533]Locking	VDD_SENSOR high
[3.16 14.05.16.533]Turning gsensor ON
[3.16 14.05.16.775]Turning LNA	ON
[3.16 14.05.16.775]Turned LNA ON
[3.16 14.05.17.778]GPS thread_id: 0x20028ce0
[3.16 14.05.17.778]GPS started successfully.
[3.16 14.05.17.808]Searching for satellites to get position fix. This may take several minutes.
[3.16 14.05.17.808]The device will attempt to get a fix for 150 seconds, before the GPS is stopped.
[3.16 14.05.17.808]GPS operation started

GSensor code looks like this

void nRFGSensorInit(void) {
    printk("Starting GSensor init\n");
    gpio_vdd_sensor(true);
    i2c_gpio_init();

    nRFGSensorInitWorkQueue();
    printk("Gsensor work queue init complete\n");
    //set Shock	Level for the accelerometer
    adxl343_init(GSENSOR_STARTUP_SHOCKLEVEL);

    gpio_vdd_sensor(false);
    //Turn on all axes
    //setActivityXYZ(true, true, true);
    gpio_adxl343_interrupt_configure(gpio_adxl_interrupt_handler);

    k_delayed_work_init(&gsensor_work.work, gsensor_handler);

    printk("i2c	gsensor	init complete!\n");
    
    k_delayed_work_submit_to_queue(&gsensor_work_q, &gsensor_work.work,	K_SECONDS(240));
    printk("Starting gsensor process in	4 minutes\n");
}

void nRFGSensorInitWorkQueue(void){
    k_work_q_start(&gsensor_work_q, gsensor_stack_area,
	       K_THREAD_STACK_SIZEOF(gsensor_stack_area), GSENSOR_THREAD_PRIORITY);
}

Parents
  • Hello,

    can you share the code where you use the system work queue, and also the rest of the code where you use a dedicated work queue. That way I can see if you are doing something wrong in the code.

  • Hi 

    This is how I use the system work queue (GPS work item): 

    void  gps_control_stop(u32_t delay_ms) {
    #if !defined(CONFIG_GPS_SIM)
        if (gps_control_is_active()) {
            setLNAState(false);
            atomic_set(&gps_is_active, 0);
    
            k_delayed_work_cancel(&gps_work.work);
            gps_work.type = GPS_WORK_STOP;
            k_delayed_work_submit(&gps_work.work, delay_ms);
        }
    #endif
    }
    
    void gps_control_start(u32_t delay_ms) {
    #if !defined(CONFIG_GPS_SIM)
        setLNAState(true);
        atomic_set(&gps_is_active, 1);
        //    setLedState(LED_RED, true);
        k_delayed_work_cancel(&gps_work.work);
        gps_work.type = GPS_WORK_START;
        k_delayed_work_init(&gps_work.work, gps_work_handler);
    
        k_delayed_work_submit(&gps_work.work, delay_ms);
    #endif
    }
    

    The code for using the dedicated work queue is as follows: 

    void nRFGSensorInit(void) {
        printk("Starting GSensor init\n");
        gpio_vdd_sensor(true);
        i2c_gpio_init();
    
        nRFGSensorInitWorkQueue();
        printk("Gsensor work queue init complete\n");
        //set Shock	Level for the accelerometer
        adxl343_init(GSENSOR_STARTUP_SHOCKLEVEL);
    
        gpio_vdd_sensor(false);
        //Turn on all axes
        //setActivityXYZ(true, true, true);
        gpio_adxl343_interrupt_configure(gpio_adxl_interrupt_handler);
    
        k_delayed_work_init(&gsensor_work.work, gsensor_handler);
    
        printk("i2c	gsensor	init complete!\n");
        
        k_delayed_work_submit_to_queue(&gsensor_work_q, &gsensor_work.work,	K_SECONDS(240));
        printk("Starting gsensor process in	4 minutes\n");
    }
    
    
    void gpio_adxl_interrupt_handler(struct	device *port, struct gpio_callback *cb,	u32_t pins) {
        printk("Interrupt from GSensor received!\n");
        if (callback != NULL) {
    	callback(NULL);
        }
        k_delayed_work_cancel(&gsensor_work.work);
        gsensor_work.type=GSENSOR_STOP;
        k_delayed_work_submit_to_queue(&gsensor_work_q, &gsensor_work.work,	K_NO_WAIT);
    }
    

    As far as I can see, there is no API call to cansel a delayed work item from a specific work queue, Therefore the k_delayed_work_cancel without the queue parameter. 

    Hope this helps 

  • What priorities do you have on the work queues and on main?

Reply Children
Related