gap_sdk
gap_sdk copied to clipboard
Unable to use PMSIS API with PULP OS
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.
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
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?