When I have time I will see if I can setup a couple of different tasks and see how it goes.
Looks interesting.
I’m still trying to find a good IDE to test stuff like this (bootloaders, RTOS, etc) using windows, but none of the IDEs that I could use have the ability to import sources (Arduino IDE, Coocox coIDE, emIDE). Tried eclipse and derivatives and I can get the code to import, but with these I have problems with the toolchain. Hope I can find a solution without dealing with the command line, still have to try with linux running on virtualbox.
All the files I used at in that repository (https://github.com/victorpv/STM32F1_Modified/)
I am keeping that repo for the experiments, and if something works I report it here. I need to update my main one up to Rogers master, and then I can send him pull requests to make updates easier, I feel bad having to ask him to pull files from one repo to update another when I could just do a pull request.
I don’t think I had to modify anything in the freeRTOS files, just took them off the untested libraries folder. I did create one example off of code I found in the leaflabs forums. It is just a blink one. I plan of doing a larger test with the ILI 9341 display using DMA transfers.
If that works, it would be great cause DMA can transfer hundreds of bytes, while the RTOS can assign time to some other function until DMA completes.
If I get it working, I will post an example of it.
I decided to test something more complicated than a blink, so I took the Cube example from the ILI9163 library, tweaked it a bit to make it a function that I can call several times to have multiple cubes in the screen, and added 2 rotating cubes as additional threads to the Cube example.
Everything seems works really good.
I am uploading the example to my repo, for anyone to use as an example.
Currently it runs 4 tasks in parallel:
-Blinking the board led.
-Drawing a rotating cube in the center of the screen.
-Drawing another rotating cube in a corner.
-Sqrt calculations with the lowest priority.
Both cube drawing tasks use a semaphore to signal when one of them writing to the display, so the other will not try to do it at the same time.
It’s doing all that, while using the Serial port to print the time it takes for the square root calculations, and using SPI with DMA for the display.
And the ILI library is not optimized for FreeRTOS, otherwise if it released the CPU every time it is waiting for the DMA to complete, it could free up a lot more CPU cycles.
I want to test FreeRTOS 8.2, I am really liking how easy is to schedule a bunch of different tasks with different priorities easily.
I want to test FreeRTOS 8.2, I am really liking how easy is to schedule a bunch of different tasks with different priorities easily.
I believe it will use more RAM because of the way the RTOS reserves head space directly, rather than letting malloc() manage it, but I don’t know for sure.
Do you have any interesting example that could benefit from running in RTOS that would try? I only used the cubes ones to confirm peripheral access and DMA run good, but I don’t have anything bigger than that to test with right now.
EDIT: Just quickly tested.
FreeRTOS heap space can be configured, as in my tests was set to 8KB.
I can check in the memory map that 8KB are reserved for xHeap, so out of the total memory used by the sketch at compile time, we should substract those 8KB. For the test I commented out the led blinking task and the Sqrt task from the FreeRTOS example, so it only has the 2 rotatin cubes, exactly as the sketch without FreeRTOS.
These are the numbers:
FreeRTOS:
Sketch uses 26,444 bytes (21%) of program storage space. Maximum is 122,880 bytes.
Global variables use 11,672 bytes of dynamic memory.
No RTOS:
Sketch uses 22,980 bytes (18%) of program storage space. Maximum is 122,880 bytes.
Global variables use 3,168 bytes of dynamic memory.
I believe it will use more RAM because of the way the RTOS reserves head space directly, rather than letting malloc() manage it, but I don’t know for sure.
Do you have any interesting example that could benefit from running in RTOS that would try? I only used the cubes ones to confirm peripheral access and DMA run good, but I don’t have anything bigger than that to test with right now.
<…>
Taking out the 8KB of reserved heap, the differences are:
FreeRTOS uses 312 bytes of RAM, and 3464 bytes of flash.
I think those numbers are pretty good for what it does.
EDIT: Just tested FreeRTOS 8.2.1. I took their CortexM3 port, then did the 3 changes I had found were done to the Maple port of the 7.0.1, and with those 3 changes both my examples compile and run fine. I have not tested every single functionality, so there could be things that do not work.
With 8.2.1 there are 5 choices for heap management. With the most basic one it results in 80 more bytes used of Flash, but 40 less used bytes of RAM.
At this point the LCD library is not even optimized for the RTOS. I am sure with some small changes so it releases the CPU to the RTOS whenever a long enough DMA is taking place, would improve performance greatly. Probably not for small transfers that just take a few cycles, but anything over a few hundred cycles should take longer than the task switching in the RTOS. I may give it a shot later.
I’ve move FreeRTOS from untested into the normal part of the libraries folder
When Ray has had chance to confirm its working OK for him, and perhaps when we have a some examples people can try, we can post an announcement as I’m sure a lot of people would be very interested
Thanks
Roger
For the old 8-bit Arduino units, the revised library freeRTOS library above (updated 4/2015) looks promising, too. As I was discussing in another thread, the very cheap 328P 16MHz mini boards under $2 may become useful in future projects to manage sensors and pre-digest some of the data before sending over to the STM32 (master/hub).
Ray
Do you have any interesting example that could benefit from running in RTOS that would try?
FreeRTOS uses systick with 1khz interrupts, and set the systick callback function to call an RTOS function that does the scheduling.
I believe RTC uses a different clock source, but if it uses systick, we could have 2 solutions:
-Change the callback from systick to RTC, and RTC calls the freeRTOS scheduler.
-Let RTOS have the callback from systick, but then RTOS calls the RTC.
Besides systick, and 2 functions in assembler that save the stack and restore the stack each time a task is switched, RTOS does not interfere with anything else.
I have successfully used DMA and the DMA ISR without any modification whatsoever, it doesn’t care. As the cortex has a NVIC I guess that takes cares of priorities and serving any interrupt that triggers while another is being served, so they don’t block each other.
In my most complex example to the moment, I have 2 functions drawing to the screen, with another function doing sqrt calculations in the background, pretty intense math. The sqrt performance goes down like 30% 40% compare as running by itself, but it has the lowest priorities, so at the same time the drawing ones are working at almost full speed.
If I used an mcu with 64KB, and reserved 32KB for frame buffer for a 128×128 full color TFT, I could the screen refresh completely on DMA at whatever frequency I wanted using just a few CPU cycles.
It’s something I want to test, but I need to rewrite the ILI9163 driver to do all the drawing to a frame buffer.
Sadly, that would not work on in the nicer bigger 9341, cause the 1 full frame would take 144KB ![]()
I believe using the frame buffer could provide a huge performance impact, as writing a pixel would imply just writing 2 bytes to RAM, rather than having to send control data to the display, then the address of the pixel, then the pixel data itself, and wait for all those SPI transactions to complete…
Still the need for speed in such a small lcd display is doubtful…
For the old 8-bit Arduino units, the revised library freeRTOS library above (updated 4/2015) looks promising, too. As I was discussing in another thread, the very cheap 328P 16MHz mini boards under $2 may become useful in future projects to manage sensors and pre-digest some of the data before sending over to the STM32 (master/hub).
Ray
FreeRTOS uses systick with 1khz interrupts, and set the systick callback function to call an RTOS function that does the scheduling.
I believe RTC uses a different clock source, but if it uses systick, we could have 2 solutions:
-Change the callback from systick to RTC, and RTC calls the freeRTOS scheduler.
-Let RTOS have the callback from systick, but then RTOS calls the RTC.
Besides systick, and 2 functions in assembler that save the stack and restore the stack each time a task is switched, RTOS does not interfere with anything else.
I have successfully used DMA and the DMA ISR without any modification whatsoever, it doesn’t care. As the cortex has a NVIC I guess that takes cares of priorities and serving any interrupt that triggers while another is being served, so they don’t block each other.
In my most complex example to the moment, I have 2 functions drawing to the screen, with another function doing sqrt calculations in the background, pretty intense math. The sqrt performance goes down like 30% 40% compare as running by itself, but it has the lowest priorities, so at the same time the drawing ones are working at almost full speed.
If I used an mcu with 64KB, and reserved 32KB for frame buffer for a 128×128 full color TFT, I could the screen refresh completely on DMA at whatever frequency I wanted using just a few CPU cycles.
It’s something I want to test, but I need to rewrite the ILI9163 driver to do all the drawing to a frame buffer.
Sadly, that would not work on in the nicer bigger 9341, cause the 1 full frame would take 144KB ![]()
I believe using the frame buffer could provide a huge performance impact, as writing a pixel would imply just writing 2 bytes to RAM, rather than having to send control data to the display, then the address of the pixel, then the pixel data itself, and wait for all those SPI transactions to complete…
Still the need for speed in such a small lcd display is doubtful…
That would kill the main advantage I was thinking about, that was using a frame buffer so the whole screen is written at once by the DMA controller with no CPU cycles used.
I guess there could be one routine that translates from the binary frame buffer to 1 full scan line of color data, then have DMA send the scan line, then the routine translates the next line from binary to the 16bit color data, but this still would cost a lot of cpu cycles.
Where you thinking some other way to reduce cpu usage?

Is #define USE_SEMAPHORE_DMA1 needed ?
#define USE_SEMAPHORE_DMA1
#include <MapleFreeRTOS821.h>
#include <SPI.h>
#include <Adafruit_GFX_AS.h> // Core graphics library, with extra fonts.
#include <Adafruit_ILI9341_STM.h> // STM32 DMA Hardware-specific library
// For the Adafruit shield, these are the default.
#define TFT_CS PC13
#define TFT_DC PC15
#define TFT_RST PC14
Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC, TFT_RST); // Use hardware SPI
xSemaphoreHandle xDisplayFree;
#define BOARD_LED_PIN PA5
const float sin_d[] = {
0, 0.17, 0.34, 0.5, 0.64, 0.77, 0.87, 0.94, 0.98, 1, 0.98, 0.94,
0.87, 0.77, 0.64, 0.5, 0.34, 0.17, 0, -0.17, -0.34, -0.5, -0.64,
-0.77, -0.87, -0.94, -0.98, -1, -0.98, -0.94, -0.87, -0.77,
-0.64, -0.5, -0.34, -0.17
};
const float cos_d[] = {
1, 0.98, 0.94, 0.87, 0.77, 0.64, 0.5, 0.34, 0.17, 0, -0.17, -0.34,
-0.5, -0.64, -0.77, -0.87, -0.94, -0.98, -1, -0.98, -0.94, -0.87,
-0.77, -0.64, -0.5, -0.34, -0.17, 0, 0.17, 0.34, 0.5, 0.64, 0.77,
0.87, 0.94, 0.98
};
const float d = 5;
float cube1_px[] = {
-d, d, d, -d, -d, d, d, -d
};
float cube1_py[] = {
-d, -d, d, d, -d, -d, d, d
};
float cube1_pz[] = {
-d, -d, -d, -d, d, d, d, d
};
float cube1_p2x[] = {
0, 0, 0, 0, 0, 0, 0, 0
};
float cube1_p2y[] = {
0, 0, 0, 0, 0, 0, 0, 0
};
int cube1_r[] = {
0, 0, 0
};
const float d2 = 10;
float cube2_px[] = {
-d2, d2, d2, -d2, -d2, d2, d2, -d2
};
float cube2_py[] = {
-d2, -d2, d2, d2, -d2, -d2, d2, d2
};
float cube2_pz[] = {
-d2, -d2, -d2, -d2, d2, d2, d2, d2
};
float cube2_p2x[] = {
0, 0, 0, 0, 0, 0, 0, 0
};
float cube2_p2y[] = {
0, 0, 0, 0, 0, 0, 0, 0
};
int cube2_r[] = {
0, 0, 0
};
uint16 cube1_x, cube1_y, cube2_x, cube2_y, cube1_color, cube2_color;
static void vLEDFlashTask(void *pvParameters) {
for (;;) {
vTaskDelay(1000);
digitalWrite(BOARD_LED_PIN, HIGH);
vTaskDelay(50);
digitalWrite(BOARD_LED_PIN, LOW);
}
}
static void vCube1LoopTask(void *pvParameters) {
while (1) {
if ( xSemaphoreTake( xDisplayFree, ( portTickType ) 10 ) == pdTRUE )
{
cube(cube1_px, cube1_py, cube1_pz, cube1_p2x, cube1_p2y, cube1_r, &cube1_x, &cube1_y, &cube1_color);
xSemaphoreGive( xDisplayFree );
vTaskDelay(15);
}
}
}
static void vCube2LoopTask(void *pvParameters) {
while (1) {
if ( xSemaphoreTake( xDisplayFree, ( portTickType ) 10 ) == pdTRUE )
{
cube(cube2_px, cube2_py, cube2_pz, cube2_p2x, cube2_p2y, cube2_r, &cube2_x, &cube2_y, &cube2_color);
xSemaphoreGive( xDisplayFree );
vTaskDelay(40);
}
}
}
void cube(float *px, float *py, float *pz, float *p2x, float *p2y, int *r, uint16 *x, uint16 *y, uint16 *color) {
for (int i = 0; i < 3; i++) {
tft.drawLine(p2x[i], p2y[i], p2x[i + 1], p2y[i + 1], ILI9341_WHITE);
tft.drawLine(p2x[i + 4], p2y[i + 4], p2x[i + 5], p2y[i + 5], ILI9341_WHITE);
tft.drawLine(p2x[i], p2y[i], p2x[i + 4], p2y[i + 4], ILI9341_WHITE);
}
tft.drawLine(p2x[3], p2y[3], p2x[0], p2y[0], ILI9341_WHITE);
tft.drawLine(p2x[7], p2y[7], p2x[4], p2y[4], ILI9341_WHITE);
tft.drawLine(p2x[3], p2y[3], p2x[7], p2y[7], ILI9341_WHITE);
r[0] = r[0] + 1;
r[1] = r[1] + 1;
if (r[0] == 36) r[0] = 0;
if (r[1] == 36) r[1] = 0;
if (r[2] == 36) r[2] = 0;
for (int i = 0; i < 8; i++)
{
float px2 = px[i];
float py2 = cos_d[r[0]] * py[i] - sin_d[r[0]] * pz[i];
float pz2 = sin_d[r[0]] * py[i] + cos_d[r[0]] * pz[i];
float px3 = cos_d[r[1]] * px2 + sin_d[r[1]] * pz2;
float py3 = py2;
float pz3 = -sin_d[r[1]] * px2 + cos_d[r[1]] * pz2;
float ax = cos_d[r[2]] * px3 - sin_d[r[2]] * py3;
float ay = sin_d[r[2]] * px3 + cos_d[r[2]] * py3;
float az = pz3 - 190;
p2x[i] = *x + ax * 500 / az;
p2y[i] = *y + ay * 500 / az;
}
for (int i = 0; i < 3; i++) {
tft.drawLine(p2x[i], p2y[i], p2x[i + 1], p2y[i + 1], *color);
tft.drawLine(p2x[i + 4], p2y[i + 4], p2x[i + 5], p2y[i + 5], *color);
tft.drawLine(p2x[i], p2y[i], p2x[i + 4], p2y[i + 4], *color);
}
tft.drawLine(p2x[3], p2y[3], p2x[0], p2y[0], *color);
tft.drawLine(p2x[7], p2y[7], p2x[4], p2y[4], *color);
tft.drawLine(p2x[3], p2y[3], p2x[7], p2y[7], *color);
}
static void vSqrtTask(void *pvParameters) {
while (1){
Serial.println ("Starting Sqrt calculations...");
uint16 x = 0;
uint16 ixx[1001];
// Library Sqrt
uint32_t t0 = millis();
for (uint32_t n = 247583650 ; n > 247400000 ; n--) {
x = sqrt (n);
}
uint32_t t1 = millis() - t0;
Serial.print ("Sqrt calculations took (ms): ");
Serial.println (t1);
delay (5000);
}
}
void setup() {
// initialize the digital pin as an output:
Serial.begin(9600);
delay (5000);
Serial.println ("Running...");
pinMode(BOARD_LED_PIN, OUTPUT);
tft.begin();
tft.fillScreen(ILI9341_WHITE);
cube1_x = ((tft.width()) / 4);
cube1_y = ((tft.height()) / 4);
cube2_x = ((tft.width()) / 2);
cube2_y = ((tft.height()) / 2);
cube1_color = ILI9341_BLACK;
cube2_color = ILI9341_RED;
vSemaphoreCreateBinary(xDisplayFree);
xTaskCreate(vLEDFlashTask,
"Task1",
configMINIMAL_STACK_SIZE,
NULL,
tskIDLE_PRIORITY + 2,
NULL);
xTaskCreate(vCube1LoopTask,
"Cube1",
configMINIMAL_STACK_SIZE,
NULL,
tskIDLE_PRIORITY + 2,
NULL);
xTaskCreate(vCube2LoopTask,
"Cube2",
configMINIMAL_STACK_SIZE,
NULL,
tskIDLE_PRIORITY+1,
NULL);
xTaskCreate(vSqrtTask,
"Sqrt",
configMINIMAL_STACK_SIZE,
NULL,
tskIDLE_PRIORITY,
NULL);
vTaskStartScheduler();
}
void loop() {
// Do not write any code here, it would not execute.
}
#include <Adafruit_ILI9341_STM_SPI2.h> // STM32 DMA Hardware-specific libraryYou could first try to run the sketch without blink
Ok, with larger Cube_stack_sizes (ie. 512bytes, the default configMINIMAL_STACK_SIZE is 120 shorts) it works now with SPI2 as well:
..
xTaskCreate(vCube1LoopTask,
"Cube1",
512,
NULL,
tskIDLE_PRIORITY + 2,
NULL);
xTaskCreate(vCube2LoopTask,
"Cube2",
512,
NULL,
tskIDLE_PRIORITY + 1,
NULL);
..// Cube FreeRtos Demo
// for Maple Mini and SPI2 display
// uses "SPI2" ILI9341 library
// uses UART at 115k2
// ide 1.6.10
// mods 8/2016 by Pito
#include <MapleFreeRTOS821.h>
#include <SPI.h>
#include <Adafruit_GFX_AS.h> // Core graphics library, with extra fonts.
#include <Adafruit_ILI9341_STM_SPI2.h> // SPI2 DMA Hardware-specific library
// Maple Mini with SPI2
#define TFT_CS PA8
#define TFT_DC PA13
Adafruit_ILI9341_STM tft = Adafruit_ILI9341_STM(TFT_CS, TFT_DC); // Use hardware SPI
xSemaphoreHandle xDisplayFree;
#define BOARD_LED_PIN PB1
const float sin_d[] = {
0, 0.17, 0.34, 0.5, 0.64, 0.77, 0.87, 0.94, 0.98, 1, 0.98, 0.94,
0.87, 0.77, 0.64, 0.5, 0.34, 0.17, 0, -0.17, -0.34, -0.5, -0.64,
-0.77, -0.87, -0.94, -0.98, -1, -0.98, -0.94, -0.87, -0.77,
-0.64, -0.5, -0.34, -0.17
};
const float cos_d[] = {
1, 0.98, 0.94, 0.87, 0.77, 0.64, 0.5, 0.34, 0.17, 0, -0.17, -0.34,
-0.5, -0.64, -0.77, -0.87, -0.94, -0.98, -1, -0.98, -0.94, -0.87,
-0.77, -0.64, -0.5, -0.34, -0.17, 0, 0.17, 0.34, 0.5, 0.64, 0.77,
0.87, 0.94, 0.98
};
const float d = 5;
float cube1_px[] = {
-d, d, d, -d, -d, d, d, -d
};
float cube1_py[] = {
-d, -d, d, d, -d, -d, d, d
};
float cube1_pz[] = {
-d, -d, -d, -d, d, d, d, d
};
float cube1_p2x[] = {
0, 0, 0, 0, 0, 0, 0, 0
};
float cube1_p2y[] = {
0, 0, 0, 0, 0, 0, 0, 0
};
int cube1_r[] = {
0, 0, 0
};
const float d2 = 10;
float cube2_px[] = {
-d2, d2, d2, -d2, -d2, d2, d2, -d2
};
float cube2_py[] = {
-d2, -d2, d2, d2, -d2, -d2, d2, d2
};
float cube2_pz[] = {
-d2, -d2, -d2, -d2, d2, d2, d2, d2
};
float cube2_p2x[] = {
0, 0, 0, 0, 0, 0, 0, 0
};
float cube2_p2y[] = {
0, 0, 0, 0, 0, 0, 0, 0
};
int cube2_r[] = {
0, 0, 0
};
uint16 cube1_x, cube1_y, cube2_x, cube2_y, cube1_color, cube2_color;
// Perform an LED blink every 1000msecs
static void vLEDFlashTask( void * pvParameters )
{
portTickType xLastWakeTime;
const portTickType xPeriod = 1000; // =1second with 1ms Tick
// Initialise the xLastWakeTime variable with the current time.
xLastWakeTime = xTaskGetTickCount();
for( ;; )
{
// Wait for the next blink cycle.
vTaskDelayUntil( &xLastWakeTime, xPeriod );
// Perform the LED blink
digitalWrite(BOARD_LED_PIN, HIGH);
vTaskDelay(50); // 50msec blink
digitalWrite(BOARD_LED_PIN, LOW);
}
}
static void vCube1LoopTask(void *pvParameters) {
while (1) {
if ( xSemaphoreTake( xDisplayFree, ( portTickType ) 10 ) == pdTRUE )
{
cube(cube1_px, cube1_py, cube1_pz, cube1_p2x, cube1_p2y, cube1_r, &cube1_x, &cube1_y, &cube1_color);
xSemaphoreGive( xDisplayFree );
vTaskDelay(50);
}
}
}
static void vCube2LoopTask(void *pvParameters) {
while (1) {
if ( xSemaphoreTake( xDisplayFree, ( portTickType ) 10 ) == pdTRUE )
{
cube(cube2_px, cube2_py, cube2_pz, cube2_p2x, cube2_p2y, cube2_r, &cube2_x, &cube2_y, &cube2_color);
xSemaphoreGive( xDisplayFree );
vTaskDelay(40);
}
}
}
void cube(float *px, float *py, float *pz, float *p2x, float *p2y, int *r, uint16 *x, uint16 *y, uint16 *color) {
for (int i = 0; i < 3; i++) {
tft.drawLine(p2x[i], p2y[i], p2x[i + 1], p2y[i + 1], ILI9341_WHITE);
tft.drawLine(p2x[i + 4], p2y[i + 4], p2x[i + 5], p2y[i + 5], ILI9341_WHITE);
tft.drawLine(p2x[i], p2y[i], p2x[i + 4], p2y[i + 4], ILI9341_WHITE);
}
tft.drawLine(p2x[3], p2y[3], p2x[0], p2y[0], ILI9341_WHITE);
tft.drawLine(p2x[7], p2y[7], p2x[4], p2y[4], ILI9341_WHITE);
tft.drawLine(p2x[3], p2y[3], p2x[7], p2y[7], ILI9341_WHITE);
r[0] = r[0] + 1;
r[1] = r[1] + 1;
if (r[0] == 36) r[0] = 0;
if (r[1] == 36) r[1] = 0;
if (r[2] == 36) r[2] = 0;
for (int i = 0; i < 8; i++)
{
float px2 = px[i];
float py2 = cos_d[r[0]] * py[i] - sin_d[r[0]] * pz[i];
float pz2 = sin_d[r[0]] * py[i] + cos_d[r[0]] * pz[i];
float px3 = cos_d[r[1]] * px2 + sin_d[r[1]] * pz2;
float py3 = py2;
float pz3 = -sin_d[r[1]] * px2 + cos_d[r[1]] * pz2;
float ax = cos_d[r[2]] * px3 - sin_d[r[2]] * py3;
float ay = sin_d[r[2]] * px3 + cos_d[r[2]] * py3;
float az = pz3 - 190;
p2x[i] = *x + ax * 500 / az;
p2y[i] = *y + ay * 500 / az;
}
for (int i = 0; i < 3; i++) {
tft.drawLine(p2x[i], p2y[i], p2x[i + 1], p2y[i + 1], *color);
tft.drawLine(p2x[i + 4], p2y[i + 4], p2x[i + 5], p2y[i + 5], *color);
tft.drawLine(p2x[i], p2y[i], p2x[i + 4], p2y[i + 4], *color);
}
tft.drawLine(p2x[3], p2y[3], p2x[0], p2y[0], *color);
tft.drawLine(p2x[7], p2y[7], p2x[4], p2y[4], *color);
tft.drawLine(p2x[3], p2y[3], p2x[7], p2y[7], *color);
}
static void vSqrtTask(void *pvParameters) {
while (1){
Serial1.println (F("Starting Sqrt calculations..."));
uint32 x = 0;
uint32 Ns = 100000; // number of sqrt calcs
// Library Sqrt
uint32_t t0 = millis();
for (uint32_t n = 1 ; n < Ns ; n++) {
x = sqrt (247400000 + n);
}
uint32_t t1 = millis() - t0;
Serial1.print (F("100k Sqrt calculations took (ms): "));
Serial1.println (t1);
vTaskDelay (70);
}
}
void setup() {
// initialize the digital pin as an output:
Serial1.begin(115200);
delay (1000);
Serial1.println (F("Running..."));
pinMode(BOARD_LED_PIN, OUTPUT);
tft.begin();
tft.fillScreen(ILI9341_WHITE);
cube1_x = ((tft.width()) / 4);
cube1_y = ((tft.height()) / 4);
cube2_x = ((tft.width()) / 2);
cube2_y = ((tft.height()) / 2);
cube1_color = ILI9341_BLACK;
cube2_color = ILI9341_RED;
vSemaphoreCreateBinary(xDisplayFree);
xTaskCreate(vLEDFlashTask,
"Task1",
configMINIMAL_STACK_SIZE,
NULL,
tskIDLE_PRIORITY + 3,
NULL);
xTaskCreate(vCube1LoopTask,
"Cube1",
configMINIMAL_STACK_SIZE + 200,
NULL,
tskIDLE_PRIORITY + 2,
NULL);
xTaskCreate(vCube2LoopTask,
"Cube2",
configMINIMAL_STACK_SIZE + 200,
NULL,
tskIDLE_PRIORITY + 1,
NULL);
xTaskCreate(vSqrtTask,
"Sqrt",
configMINIMAL_STACK_SIZE,
NULL,
tskIDLE_PRIORITY,
NULL);
vTaskStartScheduler();
Serial.println(F("Insufficient RAM"));
while(1);
}
void loop() {
// Do not write any code here, it would not execute.
}
The Serial usually address a single device (terminal) so not using a mutex around Serial must not necessarily crash the code (but mess the input/output), however resources like SPI and I2C when be called out of various tasks and address various task-related devices can crash, thus a mutex here is required, afaik.
In that model, not mutex is required.
Cheers, Ollie
Some other question related to memory handling. I’ve programmed in multithread environments for many years but with PC’s mostly. Embedded stuff is so different as we all know.
I found that FreeRTOS has own memory model where you define in the config file how much memory (heap) it can use. Where is this defined? From build log I can see that 8kB is allocated so I’m guessing 8kB is the amount defined. Also is the 8kB heap available globally for use within all tasks ?
Second question:
In one of my tasks I added some my code and when I start it it hangs. Is there any methods in FreeRTOS available to trace if for example stack is out of memory, can i get some callback function or such ? if there is fault at processor level can this be traced or found out also ?
Thanks.
There are several heap models there..
I need to make sure I found the right version of the sketch and then will post it, but I had the following all working together under FreeRTOS 8.2.1 as included in the core:
ILI9163 display in SPI2
Sdcard in SPI1
Hardware timers, playing a wav file read from the sdcard.
DMA transfers for both SPI sdcard and display.
I did use Mutexes to make sure the SPI ports would not be used at the same time, because I was using the SPI.setmodule function. Since that functions selects one port OR the other to be used with SPI functions, I needed the mutex to make sure only one would be used at a time.
I did in the past test rewritting the ILI9163 library to use SPI2, coded in the library, not using SPI.setmodule, and that did work fine too, but I think I still used mutex to not have 2 functions use the SPI ports at the same time. May not have been needed.
What I can say is, at the point I pushed the SPI DMA routines to the repo, both SPI 1 & 2 ports could be used with DMA in the same sketch as long as mutex were used. I do not know all the changes that have been pushed to the repo since then though, something may have broken.
Also I do not remember if the SPI dma functions may share some variable between both ports, they may, in which case if you try to use one port while a previous transfer has not finished for the other port, it may corrupt some variable and cause issues.
P.S. correction, I had all the above working on CoOS. I do not remember if I tested the same in FreeRTOS, but have no reason to believe it would not have worked the same.


