Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 12 of 12

Thread: FreeRTOS 8.0.1 for Teensy 3.x, Due, and AVR boards.

  1. #1
    Senior Member
    Join Date
    Nov 2012
    Posts
    240

    FreeRTOS 8.0.1 for Teensy 3.x, Due, and AVR boards.

    A port of FreeRTOS 8.0.1 for AVR, Due, and Teensy 3.0, 3.1 is available here https://github.com/greiman/FreeRTOS-Arduino.

    This is an Arduino library for the FreeRTOS kernel. It uses the standard Arduino/Teensy IDE.

    FreeRTOS 8 is a major change from version 7 so please read the html documentation for decisions I made.

  2. #2
    Senior Member
    Join Date
    Jun 2013
    Location
    So. Calif
    Posts
    2,828
    Thanks so much for this work.
    May I add that many people can avoid the risk and issues with preemptive scheduling in FreeRTOS due to the lack of compatibility with many of the Arduino library code (non-reentrant/thread safe).

    If you change the FreeRTOS configuration file's option for preemption to false/no, then the scheduler becomes cooperative, not preemptive. This avoids the compatibility issue. But the user's tasks need to make an RTOS call that yields to the scheduler, such as a delay/sleep, a wait for semaphore, etc. Rather than user program long or infinite loop with no such calls.
    I've used this, and if you don't hog the CPU too long without making a yielding call, the task switching is fine for most applications. You still get the benefits of a stack for each task and ability to pause the task for a time period or wait for an event such as a semaphore set in an interrupt routine or by another task, or wait for message queue to be non-empty, etc.

  3. #3
    Senior Member onehorse's Avatar
    Join Date
    Apr 2014
    Location
    Danville, California
    Posts
    920
    Is there a simple demo/tutorial that shows how to use FreeRTOS to blink an LED or whatever. I would like to understand what this is and how to use it but the one FreeRTOS tutorial I tried to read through did nothing but confuse me!

  4. #4
    Senior Member
    Join Date
    Nov 2012
    Posts
    240
    stevech
    If you change the FreeRTOS configuration file's option for preemption to false/no, then the scheduler becomes cooperative, not preemptive.
    Thanks for reminding me. I didn't test cooperative scheduling and there was a problem with AVR. It is now fixed on GitHub.

    onehorse
    Is there a simple demo/tutorial that shows how to use FreeRTOS to blink an LED or whatever.
    My simplest blink example has two threads and a semaphore. You need at least two threads to demo a RTOS. Here is that example.
    Code:
    /*
     * Example to demonstrate thread definition, semaphores, and thread sleep.
     */
    #include <FreeRTOS_ARM.h>
    
    // The LED is attached to pin 13 on Arduino.
    const uint8_t LED_PIN = 13;
    
    // Declare a semaphore handle.
    SemaphoreHandle_t sem;
    //------------------------------------------------------------------------------
    /*
     * Thread 1, turn the LED off when signalled by thread 2.
     */
    // Declare the thread function for thread 1.
    static void Thread1(void* arg) {
      while (1) {
    
        // Wait for signal from thread 2.
        xSemaphoreTake(sem, portMAX_DELAY);
    
        // Turn LED off.
        digitalWrite(LED_PIN, LOW);
      }
    }
    //------------------------------------------------------------------------------
    /*
     * Thread 2, turn the LED on and signal thread 1 to turn the LED off.
     */
    // Declare the thread function for thread 2.
    static void Thread2(void* arg) {
    
      pinMode(LED_PIN, OUTPUT);
    
      while (1) {
        // Turn LED on.
        digitalWrite(LED_PIN, HIGH);
    
        // Sleep for 200 milliseconds.
        vTaskDelay((200L * configTICK_RATE_HZ) / 1000L);
    
        // Signal thread 1 to turn LED off.
        xSemaphoreGive(sem);
    
        // Sleep for 200 milliseconds.
        vTaskDelay((200L * configTICK_RATE_HZ) / 1000L);
      }
    }
    //------------------------------------------------------------------------------
    void setup() {
      portBASE_TYPE s1, s2;
    
      Serial.begin(9600);
      
      // initialize semaphore
      sem = xSemaphoreCreateCounting(1, 0);
    
      // create task at priority two
      s1 = xTaskCreate(Thread1, NULL, configMINIMAL_STACK_SIZE, NULL, 2, NULL);
    
      // create task at priority one
      s2 = xTaskCreate(Thread2, NULL, configMINIMAL_STACK_SIZE, NULL, 1, NULL);
    
      // check for creation errors
      if (sem== NULL || s1 != pdPASS || s2 != pdPASS ) {
        Serial.println(F("Creation problem"));
        while(1);
      }
      // start scheduler
      vTaskStartScheduler();
      Serial.println(F("Insufficient RAM"));
      while(1);
    }
    //------------------------------------------------------------------------------
    // WARNING idle loop has a very small stack (configMINIMAL_STACK_SIZE)
    // loop must never block
    void loop() {
      // Not used.
    }
    There are many tutorials on the web. I have included the 16 examples from the FreeRTOS companion book. They want $35 for it.

    http://shop.freertos.org/RTOS_primer...ual_s/1819.htm

  5. #5
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    18,300
    I've been considering whether to add conditionally compiled semaphores to the Teensyduino core library functions that can block, like Serial.write(). At this point, I'm not entirely sure how to go about this, or even whether it's a good idea?

  6. #6
    Senior Member
    Join Date
    Jun 2013
    Location
    So. Calif
    Posts
    2,828
    Quote Originally Posted by PaulStoffregen View Post
    I've been considering whether to add conditionally compiled semaphores to the Teensyduino core library functions that can block, like Serial.write(). At this point, I'm not entirely sure how to go about this, or even whether it's a good idea?
    The UART drivers I did for ARM7 that used FreeRTOS used message queues for receive data arrival (buffer now not empty) as well as a means to get buffer empty as a boolean in a poll. Also had a transmit buffer full poll, transmit buffer free space as a count via a poll, and transmit buffer empty as a queue empty event. This was/is used for very heavy I/O to UARTs that interact with XBee modules in binary API mode at 115200 baud, and with the 16 deep FIFO buffers in the UART. That's key to reducing the UART interrupts per second, at high baud rates.
    As I recall, FreeRTOS requires fixed-lenth message queue member data, where the size is defined when the queue is created. Using a queue was simpler than semaphores because UART drivers can fill/empty queues at the ISR level with FreeRTOS ISR-save APIs.

    Fixed length queue items are OK for an app where the data is framed as it is for XBee (UART) and most any packet based thing like WizNet ethernet. In that same FreeRTOS ARM7, I wrote an interrupt driven WizNet 5100 chip driver for FreeRTOS so that there was no need to constantly poll.

    I didn't tackle SPI hardware port sharing in FreeRTOS as it was too hard to manage latency, and the WizNet was the sole SPI device in that project.

    With cooperative rather than preemptive scheduling (which is much like the YIELD concept in Arduino), the Arduino libraries will work, and the only thing the novice user has to do is remember to not write CPU hoggy loops that never call an RTOS function like delay (and more advanced like wait on semaphore or wait on queue, each of which can have a timeout).
    Last edited by stevech; 08-14-2014 at 10:25 PM.

  7. #7
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,652
    I am thinking of trying this out on a version of my Hexapod code base.

    I am thinking of doing it for my PhantomX hexapod, that uses an Arbotix Commander (XBee) for input, 18 AX-12 servos. The servo code uses some form of background process that does interpolation. The servos built-in interpolation code does not work well, so this code base (as well as most others) has code that N times per second, does the interpolation and then tells all of the servos to move using half duplex serial running at 1mbits. For the fun of it, I may also have touch Adafruit 2.8" tft display on it...

    So question: On Linux versions, I handle the Arbotix Commander, by using a thread, that simply waits for serial input... My quick reading through some of the FreeRTOS gives me the impression that some versions/ports have Serial/Usart objects that would allow me to do the same. But so far I don't see them in this port. Suggestions? Likewise I have a debug monitor, that has some simple debug commands. With the Current teensy version at the end of each call to loop, I simply call off to my debug monitor function that does a Serial.available... But this also could live as it's own thread/process...

    Thanks again for your work on this
    Kurt

  8. #8
    Senior Member
    Join Date
    Jun 2013
    Location
    So. Calif
    Posts
    2,828
    The FreeRTOS port for T3 done quite a while ago - enabled using the Teensyduino libraries as usual, including USB Serial, hardware serial, and so on.
    The serial drivers I did were for a bare metal ARM7 that had no libraries.
    The FreeRTOS drivers are for starting with bare metal.

  9. #9
    Senior Member
    Join Date
    Nov 2012
    Posts
    240
    I only ported the kernel since the purpose is to be able to use Arduino libraries and I/O. It is better to abandon the Arduino IDE if you want to use I/O from a port. The only Kinetis ARM Cortex-M4 port listed on the FreeRTOS site is a K60 port using the IAR tool chain.

    Since HardwareSerial uses the USART ISR vector, You can't just grab part of a port and use it in place of the Arduino/Teensy code.

    To work well, HardwareSerial would need to to use a FreeRTOS queue http://www.freertos.org/FreeRTOS-Plu...TOS_read.shtml. A thread could then sleep on a read.

    Sorry, sophisticated use of a USART is problem when porting an RTOS as an Arduino library.

    I don't see any Board Support Packages for Freescale http://www.freertos.org/FreeRTOS-Plu...eRTOS_BSP.html.

    Many chip companies support FreeRTOS but Freescale has its own RTOS http://www.freescale.com/webapp/sps/...y.jsp?code=MQX.
    Last edited by Bill Greiman; 08-19-2014 at 07:50 PM.

  10. #10
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,652
    As I mentioned in a different thread, I thought it would be interesting to make a version of my hexapod code base that uses the rtos. It would be nice to split things off, that need to happen at specific intervals to be their own tasks, instead of littering the code with calls off, to some place that checks the time and if appropriate does the work. Note: I could probably use interval timer to do some of these. Example: with the robotis AX servos, Their built-in interpolation stuff does not work very well, so we instead, have the processor do this N times per second. Thought it would be nice to have this done automatically for me.

    I have completed a first pass through the code base and started to try it out. The first tries have not been completely successful. At first the Teensy was so hung up, the comm port associated with the USB would not longer talk to windows... Making progress. Now backing off and doing a normal thing of trying out bits and pieces first.

    Was not sure where the processor was hanging, so started to add some debug stuff... First trying to figure out which task is running so I added:
    Code:
    #define traceTASK_SWITCHED_IN() {if (pxCurrentTCB->pxTaskTag) digitalWrite(( int ) pxCurrentTCB->pxTaskTag, 1 );}
    #define traceTASK_SWITCHED_OUT() {if (pxCurrentTCB->pxTaskTag) digitalWrite(( int ) pxCurrentTCB->pxTaskTag, 0 );}
    I had to turn on an option to allow task tags:
    #define configUSE_APPLICATION_TASK_TAG 1 // was 0

    Added a task tag for the different task, where the tag was an IO pin number:
    vTaskSetApplicationTaskTag( NULL, ( TaskHookFunction_t ) 20);

    Now when I run my program I do see which tasks run when which is nice.

    But then I wondered if maybe I was over running one of my stacks, so I added a debug command to my quick and dirty terminal monitor, to print out stack high water marks...
    Code:
          DBGSerial.println("Stack Usage");
          for(int i=0; i< 4; i++) {
            DBGSerial.print(i, DEC);
            DBGSerial.print(" ");
            DBGSerial.println (uxTaskGetStackHighWaterMark(g_aTasks[i]));
          }
    The task creates fill in the array g_aTasks
    xTaskCreate(NothingTask, "Nothing", 1000, NULL, 2, &g_aTasks[3]);

    However I am not sure I trust the results. as from my extracted code, I am seeing:
    Code:
    Stack Usage
    0 3956
    1 962
    2 1962
    3 988
    As I understand this, these are in stack units or in this case 32 bit elements. But these just don't seam right. Example the task 3 shows it uses 988 bytes, but this task does absolutely nothing:
    Code:
    void NothingTask(void *pv) {
      vTaskSetApplicationTaskTag( NULL, ( TaskHookFunction_t ) 23  );
      for(;;) {
        vTaskDelay((200L * configTICK_RATE_HZ) / 1000L);
      }
    }
    It says it uses more stack than the debug monitor task(1) that, looked for serial input, checked what it was and in this case looped calling off to print stuff.
    And if I understand this properly it says it used 988 (units or) almost 4K bytes. Which seam way too high as the example programs like frBlink, create their threads, using a stack size of: configMINIMAL_STACK_SIZE, which in the RTOS configuration file is defined as 130.

    Thoughts/Suggestions? My first one is that there is a problem with the high water mark stuff, but my first quick look through did not notice anything obvious.

    Thanks
    Kurt

    Edit: Actually I think I am looking at this wrong, instead of telling me how much of the stack was used, it instead is telling me how much of it is not used. Example I changed the create of the Nothing task from 1000 to 300 and now the command shows: 288
    Last edited by KurtE; 09-22-2014 at 03:48 PM. Reason: I think I misunderstood what the high water mark was returning

  11. #11
    Senior Member
    Join Date
    Jun 2013
    Location
    So. Calif
    Posts
    2,828
    did you set the option for task preemption to false?
    Beware most/lots of the libraries aren't reentrant.

    Teensy has relatively large RAM. So I set the task stack size larger than the default.

  12. #12
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,652
    Thanks, I have tried both ways. i am mostly using my own code bases, but that is not to say that some of the main Teensy stuff might not have issues like Serial ports may not have re-entrant issues. With my XBee handling in this case on Serial1, I am experimenting with my own version of the Serial class that uses the FreeRtos queues for input and output and added a function to wait on input that uses the input queue... Wish the internal functions that waits for input that functions like readBytes call, was virtual, in that case would implement a version that again waits on the queue.

    I think I now have the XBee stuff working (extracted to other program), so will try disabling everything that talks to AX servos and see if it still works...

    Thanks again
    Kurt

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •