gap_sdk icon indicating copy to clipboard operation
gap_sdk copied to clipboard

Unable to use PMSIS API with PULP OS

Open Gualor opened this issue 3 years ago • 2 comments

Hi! I'm working on a project on the Gapuino board v2 which requires real-time data processing. I manage to do just that using freeRTOS by using an ISR (connected to the gpio pin where the data ready signal is sent) which can notify the main task and start reading new data. I read on some forum that freeRTOS is not as optimized as PULP OS for GAP8 in terms of memory usage and ovarall characteristics and I am considering rewriting the OS functions to work with PULP OS instead, but I'm having some headaches trying to do that.

Here is the example code written for freeRTOS (which is working fine):

#include "pmsis.h"

/* Variables used. */
TaskHandle_t xHandler[1] = { NULL };

void vDataReadyISR(void *args)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;                                            
    xTaskNotifyFromISR(xHandler[0], 1, eNoAction, &xHigherPriorityTaskWoken);   // notify task
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken); // yield
}

/**
 * Main task.
 */
void vMainTask(void)
{
    /////////////////////////////////////// Setup data ready interrupt /////////////////////////////////////////////////////////

    struct pi_device gpio;
    int32_t errors = 0;
    struct pi_gpio_conf gpio_conf = {0};    // create gpio config struct
    pi_gpio_conf_init(&gpio_conf);          // initialize gpio config with default values
    pi_open_from_conf(&gpio, &gpio_conf);   // open gpio device from config
    errors = pi_gpio_open(&gpio);           // open gpio device, must stay alive
    if (errors)
    {
        printf("Error opening GPIO %d\n", errors);
        pmsis_exit(errors);
    }

    pi_gpio_e gpio_in = PI_GPIO_A5_PAD_17_B40;          // assign pin name
    pi_gpio_notif_e irq_type = PI_GPIO_NOTIF_FALL;       // assign pin event type
    pi_gpio_flags_e cfg_flags = PI_GPIO_INPUT|               // assign config flags
                                PI_GPIO_PULL_DISABLE|
                                PI_GPIO_DRIVE_STRENGTH_LOW;

    pi_gpio_pin_configure(&gpio, gpio_in, cfg_flags);         // configure gpio pin
    pi_gpio_pin_notif_configure(&gpio, gpio_in, irq_type);  // configure gpio notification
    
    pi_gpio_callback_t cb_gpio = {0}; // create pin callback                           
    uint32_t gpio_mask = (1 << (gpio_in & PI_GPIO_NUM_MASK));  // create pin mask
    pi_gpio_callback_init(&cb_gpio, gpio_mask, vDataReadyISR, (void *)gpio_in); // setup callback and handler
    pi_gpio_callback_add(&gpio, &cb_gpio); // Attach callback to gpio pin

    /////////////////////////////////////// Start main loop /////////////////////////////////////////////

    uint32_t ulInterruptStatus;

    while( 1 )
    {
      // Wait for notification from data ready ISR
      xTaskNotifyWait( 0x00, UINT32_MAX, &ulInterruptStatus, portMAX_DELAY );
  
      /* DO SOMETHING */
  
      taskYIELD();
    }
    pi_gpio_close(&gpio);   // close gpio device
    pmsis_exit(0);          // terminate execution
}

/**
 * System kickoff.
 */
int main(void)
{
    printf("\n\n\t *** Test ***\n\n");
    return pmsis_kickoff((void *) vMainTask);
}

I tried doing something similar by only using PMSIS API but without success as either the main task or the ISR gets stuck permanently.

Here is the PULP OS version of the code above:

#include "pmsis.h"

/* Variables used. */
pi_task_t drdy_wait_task;  

void data_ready_isr(void *args)
{
  pi_task_block(&drdy_wait_task);     // Init blocking task
  pi_task_push(&drdy_wait_task);      // Trigger blocking event
}

/**
 * Main task.
 */
void main_task(void)
{
    /////////////////////////////////////// Setup data ready interrupt /////////////////////////////////////////////////////////

    struct pi_device gpio;
    int32_t errors = 0;
    struct pi_gpio_conf gpio_conf = {0};    // create gpio config struct
    pi_gpio_conf_init(&gpio_conf);          // initialize gpio config with default values
    pi_open_from_conf(&gpio, &gpio_conf);   // open gpio device from config
    errors = pi_gpio_open(&gpio);           // open gpio device, must stay alive
    if (errors)
    {
        printf("Error opening GPIO %d\n", errors);
        pmsis_exit(errors);
    }

    pi_gpio_e gpio_in = PI_GPIO_A5_PAD_17_B40;          // assign pin name
    pi_gpio_notif_e irq_type = PI_GPIO_NOTIF_FALL;       // assign pin event type
    pi_gpio_flags_e cfg_flags = PI_GPIO_INPUT|               // assign config flags
                                PI_GPIO_PULL_DISABLE|
                                PI_GPIO_DRIVE_STRENGTH_LOW;

    pi_gpio_pin_configure(&gpio, gpio_in, cfg_flags);         // configure gpio pin
    pi_gpio_pin_notif_configure(&gpio, gpio_in, irq_type);  // configure gpio notification
    
    pi_gpio_callback_t cb_gpio = {0}; // create pin callback                           
    uint32_t gpio_mask = (1 << (gpio_in & PI_GPIO_NUM_MASK));  // create pin mask
    pi_gpio_callback_init(&cb_gpio, gpio_mask, data_ready_isr, (void *)gpio_in); // setup callback and handler
    pi_gpio_callback_add(&gpio, &cb_gpio); // Attach callback to gpio pin

    /////////////////////////////////////// Start main loop /////////////////////////////////////////////

    while( 1 )
    {
      // Wait for notification from data ready ISR
      pi_task_wait_on(&drdy_wait_task);       // Wait data ready signal

      /* DO SOMETHING */
  
      pi_yield();
    }
    pi_gpio_close(&gpio);   // close gpio device
    pmsis_exit(0);          // terminate execution
}

/**
 * System kickoff.
 */
int main(void)
{
    printf("\n\n\t *** Test ***\n\n");
    return pmsis_kickoff((void *) main_task);
}

(also the NO_PREEMPTION flag is set to true in the Makefile)

It is the first time using PULP OS so forgive me if I accidentally made a beginner mistake. Thank you in advance for your support.

Best regards.

Gualor avatar Mar 20 '21 20:03 Gualor

Hi @Gualor

First of all, thanks for your comments, but "I read on some forum that freeRTOS is not as optimized as PULP OS for GAP8 in terms of memory usage and ovarall characteristics", this is not true anymore. We have optimized freeRTOS on GAP and it's maturity is the same as PULP-OS on GAP8.

About your problem, it's because your wait in this block has blocked the scheduler and it hangs the scheduling:

    while( 1 )
    {
      // Wait for notification from data ready ISR
      pi_task_wait_on(&drdy_wait_task);       // Wait data ready signal

      /* DO SOMETHING */
  
      pi_yield();
    }

PULP-OS is not like freeRTOS! It's not a preemptive system, but a reactive system (event driven system). Therefore, there's no multi-thread in pulp-os, but only one scheduler which will schedule the tasks based on some events (IRQ, notify, sw event, etc).

Therefore, when we using pulp-os, once the task started, we should NEVER hold the PC on waiting, but give the hands to the scheduler (using the yield).

You could take a look into our examples in pmsis, and you will see, we never do something in the loop of yield, because this will hold the PC and block the scheduler.

Please tell me if it's clear for you.

Yao

Yaooooo avatar Mar 24 '21 20:03 Yaooooo

Thank you for the useful reply! I'm trying to optimize the execution without taking too much CPU time doing something trivial as waiting for a flag to be set in a ISR:

volatile data_ready_flag; // declaration in header file
void data_ready_ISR()
{
    data_ready_flag = true; // set flag
}
// main loop

data_ready_flag = false; // init flag
for(;;)
{
    if (data_ready_flag == false)
    {
        /* DO STUFF ... */
        data_ready_flag = false; // set flag back to false
    }
}

So is this simple implementation the correct way to do it in PULP OS?

Gualor avatar Mar 25 '21 10:03 Gualor