3

I am learning FreeRTOS on a STM32F103C8T6 (on a Blue-Pill board). I am trying to use queues and tasks.

#include <FreeRTOS.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/rcc.h>
#include <queue.h>
#include <task.h>

static QueueHandle_t queue;

static void
task_receive(void *args __attribute__((unused)))
{
  bool nothing;
  while (1)
  {
    if (xQueueReceive(queue, &nothing, 10) == pdPASS)
      gpio_set(GPIOC, GPIO13); // Turn off
    else
      taskYIELD(); // Yeld so that other taks can run
  }
}

static void
task_send(void *args __attribute__((unused)))
{
  bool nothing = false;
  while (1)
  {
    gpio_clear(GPIOC, GPIO13); // Turn on
    vTaskDelay(pdMS_TO_TICKS(100));
    xQueueSendToBack(queue, &nothing, portMAX_DELAY);
    vTaskDelay(pdMS_TO_TICKS(1000));
  }
}

int
main(void)
{
  rcc_clock_setup_in_hse_8mhz_out_72mhz();

  // Blue-Pill led
  rcc_periph_clock_enable(RCC_GPIOC);
  gpio_set_mode(
    GPIOC,
    GPIO_MODE_OUTPUT_2_MHZ,
    GPIO_CNF_OUTPUT_PUSHPULL,
    GPIO13);
  gpio_set(GPIOC, GPIO13); // Turn off (polarity of the led is inversed!)

  queue = xQueueCreate(32, sizeof(bool));
  if (queue == 0)
  {
    while (1)
    {
      gpio_toggle(GPIOC, GPIO13);
      for (uint32_t i = 0; i < 80000; ++i)
        __asm__("nop");
    };
  }
  xTaskCreate(task_receive, "RECEIVE", 200, NULL, configMAX_PRIORITIES-1, NULL);
  xTaskCreate(task_send, "SEND", 200, NULL, configMAX_PRIORITIES-2, NULL);
  vTaskStartScheduler();
  while(1);
  return 0;
}

Expected behavior:

  • main

    • Configures the clocks
    • Configures GPIO for Blue Pill LED
    • Turns off the led
    • Creates a queue
    • Checks the queue was correctly created: if not blink the LED fast and forever.
    • Schedule two tasks
    • Runs the scheduler
  • task_send (loops indefinetely)

    • Turn on the LED
    • Wait 100 ms
    • Push a message in the queue (content does not matter here)
    • Wait 1 sec
  • task_receive (loops indefinetely)

    • Check if a message is in the queue
      • Yes: turn off the led
      • No: yeld

I expect the led to be turned on for 100 ms and then turned off for 900 ms.

Real behavior: The led is always on, the execution of the program seems to be blocking at xQueueSendToBack.

Why is the call blocking?


FreeRTOSConfig.h

#define configUSE_PREEMPTION        1
#define configUSE_IDLE_HOOK     0
#define configUSE_TICK_HOOK     0
#define configCPU_CLOCK_HZ      ( ( unsigned long ) 72000000 )  
#define configSYSTICK_CLOCK_HZ      ( configCPU_CLOCK_HZ / 8 ) /* fix for vTaskDelay() */
#define configTICK_RATE_HZ      ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES        ( 5 )
#define configMINIMAL_STACK_SIZE    ( ( unsigned short ) 128 )
#define configTOTAL_HEAP_SIZE       ( ( size_t ) ( 17 * 1024 ) )
#define configMAX_TASK_NAME_LEN     ( 16 )
#define configUSE_TRACE_FACILITY    0
#define configUSE_16_BIT_TICKS      0
#define configIDLE_SHOULD_YIELD     1
#define configUSE_MUTEXES       1

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES       0
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */

#define INCLUDE_vTaskPrioritySet        1
#define INCLUDE_uxTaskPriorityGet       1
#define INCLUDE_vTaskDelete             1
#define INCLUDE_vTaskCleanUpResources   0
#define INCLUDE_vTaskSuspend            1
#define INCLUDE_vTaskDelayUntil         1
#define INCLUDE_vTaskDelay              1

/* This is the raw value as per the Cortex-M3 NVIC.  Values can be 255
(lowest) to 0 (1?) (highest). */
#define configKERNEL_INTERRUPT_PRIORITY         255
/* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!!
See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */
#define configMAX_SYSCALL_INTERRUPT_PRIORITY    191 /* equivalent to 0xb0, or priority 11. */


/* This is the value being used as per the ST library which permits 16
priority values, 0 to 15.  This must correspond to the
configKERNEL_INTERRUPT_PRIORITY setting.  Here 15 corresponds to the lowest
NVIC value of 255. */
#define configLIBRARY_KERNEL_INTERRUPT_PRIORITY 15
Victor Lamoine
  • 389
  • 1
  • 2
  • 21
  • In your example `task_receive` priority is higher than the `task_send` priority, therefore yielding in the higher priority task would yield the calling task over again. Therefore your `send_task` won't be preempted at all. Have a look at this https://www.freertos.org/a00020.html#taskYIELD – aep Mar 18 '19 at 09:46

2 Answers2

2

Your task_receive priority is higher than the task_send priority. taskYIELD will run the same calling task over and over again if there are no higher priority tasks.

To achieve what you want, try changing the task_receive in the following manner.

static void
task_receive(void *args __attribute__((unused)))
{
  bool nothing;
  while (1)
  {
    if (xQueueReceive(queue, &nothing, portMAX_DELAY) == pdPASS)
      gpio_set(GPIOC, GPIO13); // Turn off
  }
}

For more information on taskYIELD please refer the following.

https://www.freertos.org/a00020.html#taskYIELD

aep
  • 1,583
  • 10
  • 18
  • I have tried this change but it does not improve the behavior of the led (it is turned on and never turns off). I have also tried to make the two tasks have the same priority: no better. – Victor Lamoine Mar 18 '19 at 09:59
  • 1
    Let me make an educated guess here. Isn't your code getting stuck at `vTaskDelay` rather than in `xQueueSendToBack`. If that is the case make sure that your systick ISR(I assume systick is the RTOS tick source) is properly configured to call FreeRTOS tick function. Have a look as how `libopencm3` takes care of the systick ISR. – aep Mar 18 '19 at 10:16
  • I think it is is correctly configured. I have created an example to blink the led with two tasks (one tasks turns the led on, the other turns the led off), each of them calls `vTaskDelay` and it works fine. https://gist.github.com/VictorLamoine/8bbb9caeaae32f0d3348ecdba060eae7 – Victor Lamoine Mar 18 '19 at 10:29
  • 1
    Do you have the facility to step through the source code via a debugger? It seems that you are hitting a `configAssert` in FreeRTOS code. Again, I hope that by this time you've already checked if the stack size of `200` words is sufficient for the 2 tasks. – aep Mar 18 '19 at 11:16
  • I have tried with stack sizes 400, 800, 1400, upto 1800 words with no visible change. Yes I can debug with my ST-Link. I get stuck on a comparison call, when I hit step on the statement nothing happens. https://gist.github.com/VictorLamoine/8bbb9caeaae32f0d3348ecdba060eae7#file-queue_test-gdb. File can be read at https://github.com/cjlano/freertos/blob/master/FreeRTOS/Source/queue.c#L2100 – Victor Lamoine Mar 18 '19 at 13:30
  • 1
    @VictorLamoine I can't find anything wrong with the code(with the non `taskYIELD` one). I tried a similar code on a different board and seems to work completely fine(I replaced you GPIO calls with UART-printfs). May be you better try to do the same thing with STM32Cube HAL bypassing libopencm3 dependencies - just a suggestion. For further help you better use FreeRTOS discussion forum. – aep Mar 18 '19 at 23:36
  • @VictorLamoine Further, depending upon your heap allocation strategy(heap_1,..heap_5), FreeRTOS may or may not allocate all the memory (stack & FreeRTOS heap) from the HEAP_SIZE you specifies. See if it fits within the maximum RAM available in the chip as well. May be you better muck around a bit with `HEAP_SIZE` configuration in `FreeRTOS_Config.h` file as well to see if it makes a difference. – aep Mar 18 '19 at 23:51
  • Discussion continues here: https://sourceforge.net/p/freertos/discussion/382005/thread/8127550229/. There is a problem with memcpy, not sure what yet. – Victor Lamoine Mar 21 '19 at 16:23
0

The problem was solved by updating the compiler to the latest version.

Kubuntu 18.04 ships with arm-none-eabi-gcc (15:6.3.1+svn253039-1build1) 6.3.1 20170620, with this compiler the code does not work.

memcpy seems to be the problematic function call in the code, it is called by FreeRTOS when adding an element to the queue.

If I use the Version 8-2018-q4-major Linux 64-bit compiler then the code executes fine. It can be downloaded here: https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads

Victor Lamoine
  • 389
  • 1
  • 2
  • 21