Skip to content

First version based on FreeRTOS 9.0.0 #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jan 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,47 @@
# STM32 FreeRTOS Library for Arduino

This is a port of FreeRTOS for STM32 as Arduino libraries.

For more information about FreeRTOS, visit the [FreeRTOS Web Site](http://www.freertos.org/ "FreeRTOS").
Also, See the very useful [Getting Started](http://www.freertos.org/FreeRTOS-quick-start-guide.html "Quick Start Guide") page.

Current FreeRTOS version used for this library is [9.0.0](http://www.freertos.org/FreeRTOS-V9.html) and has been modified by ST (See st_readme.txt in FreeRTOS Source).

This is the current one provided with the [STM32Cube MCU Packages](http://www.st.com/en/embedded-software/stm32cube-mcu-packages.html)

## Configuration

FreeRTOS has several configuration options, which can be specified from within the FreeRTOSConfig.h file.

This library provides a default FreeRTOS configuration file named `FreeRTOSConfig_Default.h`.

User can provide his own FreeRTOS configuration file at sketch level by adding his configuration in a file named `STM32FreeRTOSConfig.h`.

Heap allocation schemes are provided by FreeRTOS, see [Memory allocation implementations included in the RTOS source](https://www.freertos.org/a00111.html).
By default, the `heap_3.c` is used. It can be changed thanks a define in the configuration file:
```
/* Default (3) Memory allocation implementations (heap_[1-5].c) */
/*#define configMEMMANG_HEAP_NB 3*/
```

## Limitations

* MPU: not supported.

## Files & Configuration

* STM32FreeRTOS.h : Must always be #include first. It references required include files.
* STM32FreeRTOSConfig.h : If exist at sketch level, it contains the FreeRTOS configurations.
* FreeRTOSConfig_Default.h : Contains the default FreeRTOS configurations for this STM32 port if `STM32FreeRTOSConfig.h` doesn't exist.

## Test results (using [Arduino_Core_STM32](https://github.com/stm32duino/Arduino_Core_STM32))
| Board | AnalogRead_DigitalRead | Blink_AnalogRead | frBlink | frBlinkPrint | frJitter | frLiuLayland |
| --- | :---: | :---: | :---: | :---: | :---: | :---: |
| [Nucleo F091RC](http://www.st.com/en/evaluation-tools/nucleo-f091rc.html) | PASSED | PASSED | PASSED | PASSED | PASSED | FAILED |
| [Nucleo F103RB](http://www.st.com/en/evaluation-tools/nucleo-f103rb.html) | PASSED | PASSED | PASSED | PASSED | PASSED | PASSED |
| [Nucleo F303RE](http://www.st.com/en/evaluation-tools/nucleo-f303re.html) | PASSED | PASSED | PASSED | PASSED | PASSED | PASSED |
| [Nucleo F429ZI](http://www.st.com/en/evaluation-tools/nucleo-f429zi.html) | PASSED | PASSED | PASSED | PASSED | PASSED | PASSED |
| [STM32F746G-DISCOVERY](http://www.st.com/en/evaluation-tools/32f746gdiscovery.html) | PASSED | PASSED | PASSED | PASSED | PASSED | PASSED |
| [Nucleo L053R8](http://www.st.com/en/evaluation-tools/nucleo-l053r8.html) | PASSED | PASSED | PASSED | PASSED | PASSED | FAILED |
| [Nucleo L152RE](http://www.st.com/en/evaluation-tools/nucleo-l152re.html) | PASSED | PASSED | PASSED | PASSED | PASSED | PASSED |
| [B-L475E-IOT01A](http://www.st.com/en/evaluation-tools/b-l475e-iot01a.html) | PASSED | PASSED | PASSED | PASSED | PASSED | PASSED |
134 changes: 134 additions & 0 deletions examples/AnalogRead_DigitalRead/AnalogRead_DigitalRead.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
/*
* Based on AnalogRead_DigitalRead example from: https://github.com/feilipu/Arduino_FreeRTOS_Library
* Modified by: Frederic Pillon <frederic.pillon (at) st.com>
*/
#include <STM32FreeRTOS.h>

// If no default pin for user button (USER_BTN) is defined, define it
#ifndef USER_BTN
#define USER_BTN 2
#endif

// Declare a mutex Semaphore Handle which we will use to manage the Serial Port.
// It will be used to ensure only only one Task is accessing this resource at any time.
SemaphoreHandle_t xSerialSemaphore;

// define two Tasks for DigitalRead & AnalogRead
void TaskDigitalRead( void *pvParameters );
void TaskAnalogRead( void *pvParameters );

// the setup function runs once when you press reset or power the board
void setup() {

// initialize serial communication at 9600 bits per second:
Serial.begin(9600);

while (!Serial) {
; // wait for serial port to connect. Needed for native USB, on LEONARDO, MICRO, YUN, and other 32u4 based boards.
}

// Semaphores are useful to stop a Task proceeding, where it should be paused to wait,
// because it is sharing a resource, such as the Serial port.
// Semaphores should only be used whilst the scheduler is running, but we can set it up here.
if ( xSerialSemaphore == NULL ) // Check to confirm that the Serial Semaphore has not already been created.
{
xSerialSemaphore = xSemaphoreCreateMutex(); // Create a mutex semaphore we will use to manage the Serial Port
if ( ( xSerialSemaphore ) != NULL )
xSemaphoreGive( ( xSerialSemaphore ) ); // Make the Serial Port available for use, by "Giving" the Semaphore.
}

// Now set up two Tasks to run independently.
xTaskCreate(
TaskDigitalRead
, (const portCHAR *)"DigitalRead" // A name just for humans
, 128 // This stack size can be checked & adjusted by reading the Stack Highwater
, NULL
, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
, NULL );

xTaskCreate(
TaskAnalogRead
, (const portCHAR *) "AnalogRead"
, 128 // Stack size
, NULL
, 1 // Priority
, NULL );

// start scheduler
vTaskStartScheduler();
Serial.println("Insufficient RAM");
while(1);
}

void loop()
{
// Empty. Things are done in Tasks.
}

/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/

void TaskDigitalRead( void *pvParameters __attribute__((unused)) ) // This is a Task.
{
/*
DigitalReadSerial
Reads a digital input on pin defined with USER_BTN, prints the result to the serial monitor

This example code is in the public domain.
*/

// defined USER_BTN digital pin has a pushbutton attached to it. Give it a name:
uint8_t pushButton = USER_BTN;

// make the pushbutton's pin an input:
pinMode(pushButton, INPUT);

for (;;) // A Task shall never return or exit.
{
// read the input pin:
int buttonState = digitalRead(pushButton);

// See if we can obtain or "Take" the Serial Semaphore.
// If the semaphore is not available, wait 5 ticks of the Scheduler to see if it becomes free.
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
// We were able to obtain or "Take" the semaphore and can now access the shared resource.
// We want to have the Serial Port for us alone, as it takes some time to print,
// so we don't want it getting stolen during the middle of a conversion.
// print out the state of the button:
Serial.print("Button state: ");
Serial.println(buttonState);

xSemaphoreGive( xSerialSemaphore ); // Now free or "Give" the Serial Port for others.
}

vTaskDelay(1); // one tick delay (15ms) in between reads for stability
}
}

void TaskAnalogRead( void *pvParameters __attribute__((unused)) ) // This is a Task.
{

for (;;)
{
// read the input on analog pin 0:
int sensorValue = analogRead(A0);

// See if we can obtain or "Take" the Serial Semaphore.
// If the semaphore is not available, wait 5 ticks of the Scheduler to see if it becomes free.
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
// We were able to obtain or "Take" the semaphore and can now access the shared resource.
// We want to have the Serial Port for us alone, as it takes some time to print,
// so we don't want it getting stolen during the middle of a conversion.
// print out the value you read:
Serial.println(sensorValue);

xSemaphoreGive( xSerialSemaphore ); // Now free or "Give" the Serial Port for others.
}

vTaskDelay(1); // one tick delay (15ms) in between reads for stability
}
}

115 changes: 115 additions & 0 deletions examples/Blink_AnalogRead/Blink_AnalogRead.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Based on Blink_AnalogRead example from: https://github.com/feilipu/Arduino_FreeRTOS_Library
* Modified by: Frederic Pillon <frederic.pillon (at) st.com>
*/
#include <STM32FreeRTOS.h>

// define two tasks for Blink & AnalogRead
void TaskBlink( void *pvParameters );
void TaskAnalogRead( void *pvParameters );

// the setup function runs once when you press reset or power the board
void setup() {

// initialize serial communication at 9600 bits per second:
Serial.begin(9600);

while (!Serial) {
; // wait for serial port to connect. Needed for native USB, on LEONARDO, MICRO, YUN, and other 32u4 based boards.
}

// Now set up two tasks to run independently.
xTaskCreate(
TaskBlink
, (const portCHAR *)"Blink" // A name just for humans
, 128 // This stack size can be checked & adjusted by reading the Stack Highwater
, NULL
, 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
, NULL );

xTaskCreate(
TaskAnalogRead
, (const portCHAR *) "AnalogRead"
, 128 // Stack size
, NULL
, 1 // Priority
, NULL );

// start scheduler
vTaskStartScheduler();
Serial.println("Insufficient RAM");
while(1);
}

void loop()
{
// Empty. Things are done in Tasks.
}

/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/

void TaskBlink(void *pvParameters) // This is a task.
{
(void) pvParameters;

/*
Blink
Turns on an LED on for one second, then off for one second, repeatedly.

Most Arduinos have an on-board LED you can control. On the UNO, LEONARDO, MEGA, and ZERO
it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN takes care
of use the correct LED pin whatever is the board used.

The MICRO does not have a LED_BUILTIN available. For the MICRO board please substitute
the LED_BUILTIN definition with either LED_BUILTIN_RX or LED_BUILTIN_TX.
e.g. pinMode(LED_BUILTIN_RX, OUTPUT); etc.

If you want to know what pin the on-board LED is connected to on your Arduino model, check
the Technical Specs of your board at https://www.arduino.cc/en/Main/Products

This example code is in the public domain.

modified 8 May 2014
by Scott Fitzgerald

modified 2 Sep 2016
by Arturo Guadalupi
*/

// initialize digital LED_BUILTIN on pin 13 as an output.
pinMode(LED_BUILTIN, OUTPUT);

for (;;) // A Task shall never return or exit.
{
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
}
}

void TaskAnalogRead(void *pvParameters) // This is a task.
{
(void) pvParameters;

/*
AnalogReadSerial
Reads an analog input on pin 0, prints the result to the serial monitor.
Graphical representation is available using serial plotter (Tools > Serial Plotter menu)
Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground.

This example code is in the public domain.
*/

for (;;)
{
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// print out the value you read:
Serial.println(sensorValue);
vTaskDelay(1); // one tick delay (15ms) in between reads for stability
}
}

82 changes: 82 additions & 0 deletions examples/frBlink/frBlink.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Example to demonstrate thread definition, semaphores, and thread sleep.
*/
#include <STM32FreeRTOS.h>

// Define the LED pin is attached
const uint8_t LED_PIN = LED_BUILTIN;

// 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) {
UNUSED(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) {
UNUSED(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("Insufficient RAM");
while(1);
}

//------------------------------------------------------------------------------
// WARNING idle loop has a very small stack (configMINIMAL_STACK_SIZE)
// loop must never block
void loop() {
// Not used.
}
Loading