FreeRTOS scheduler performing context switching for the same task - operating-system

I noticed strange behavior when debugging the system I am analyzing. The system has three periodic tasks:
"Task-1", with 10 milliseconds of periodicity. High priority.
"Task-2", with 10 milliseconds of periodicity. Medium priority.
"Task-3" with 10 milliseconds of periodicity. Low priority.
The content of the three tasks is just a critical section, a critical section that is shared. The inversion of priorities occurs frequently, and I am forcing this situation to see how the system behaves temporally. The Systick has a period of 1ms.
From what I read about FreeRTOS, in Cortex-M the context change of a task is done through a pending bit, which in the scenario of periodic tasks can be activated through:
Tick timer handler finds a task with the highest priority in the
ready queue and sets the pending context switch bit;
In the “vDelayTaskUntil” function, which waits for the next
activation;
When a semaphore is busy and the task that tries to acquire it.
That said, I found this behavior:
Sometimes, while the high priority task is within the semaphore, the context switching takes place for itself, as explained below.
As noted, task-1 does a context switch for itself.
Do you know how to tell me why this happens?
Attaching the code of test:
Task-1:
void vTask1_handler(void *params) {
TickType_t xLastWakeTime;
const TickType_t xFrequency = 10;
xLastWakeTime = xTaskGetTickCount();
int i = 0, to =0;
for (;;) {
vTaskDelayUntil(&xLastWakeTime, xFrequency);
to = DWT->CYCCNT;
for (i = 0; i < to % 500; i++);
if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
to = DWT->CYCCNT;
for (i = 0; i < to % 5000; i++);
xSemaphoreGive(xSemaphore);
}
}
}
Task-2:
void vTask2_handler(void *params) {
TickType_t xLastWakeTime;
const TickType_t xFrequency = 10;
xLastWakeTime = xTaskGetTickCount();
int i = 0, to = 0;
for (;;) {
vTaskDelayUntil(&xLastWakeTime, xFrequency);
to = DWT->CYCCNT;
for (i = 0; i < to % 200; i++);
if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
to = DWT->CYCCNT;
for (i = 0; i < to % 10000; i++);
xSemaphoreGive(xSemaphore);
}
}
Task-3:
void vTask3_handler(void *params) {
TickType_t xLastWakeTime;
const TickType_t xFrequency = 10;
xLastWakeTime = xTaskGetTickCount();
int i = 0, to=0;
for (;;) {
vTaskDelayUntil(&xLastWakeTime, xFrequency);
to = DWT->CYCCNT;
for (i = 0; i < to % 200; i++);
if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
to = DWT->CYCCNT;
for (i = 0; i < to % 10000; i++);
xSemaphoreGive(xSemaphore);
}
}
}
Thank you.

I suspect it is going to the scheduler in the give or take semaphore API call and concluding it is still the highest priority ready task.

freertos have a periodic interrupt, that when happening it is checking if it is now time to unblock or wake a task. I think what you see is this interrupt.
please look at https://www.freertos.org/implementation/a00011.html for details about the tick interrupt.
you also may want to look at https://www.freertos.org/low-power-tickless-rtos.html if you want to disable it when entering idle low power task.

Related

How to insert delay in event loop to avoid blocking UI during image processing in Flutter?

I'm working on an image processing app. I have an animated gif to show progress. As Dart is a single thread, every time the image is being processed, it locks UI, including the animated gif. I don't want to use isolates to avoid potential memory leaks. I want to implement something using event loop, similar to the link below.
https://hackernoon.com/executing-heavy-tasks-without-blocking-the-main-thread-on-flutter-6mx31lh
I have tried to insert some delay during pixel looping as suggested in this thread but it doesn't work.
Dart future blocking main thread
Future<image> process2() {
return Future(() async {
for (var x = 0; x < width; x++) {
for (var y = 0; y < height; y++) {
// process
}
if (x % 100 == 0) {
await Future.delayed(Duration(seconds: 100));
}
}
});
}

STM32F4 Discovery

I have STM32F4 Discovery. I use IAR embedded Workbench. I am new to this kit. I want to measure distance. my code does not give an error. the distance is always zero. What could be the error? please help me . thanks everyone
#include "stm32f4_discovery.h"
#include "delay.h"
uint32_t Read_Distance(void);
void Init();
uint32_t distance ;
int main()
{
Init(); // initialisation de pin
SysTick_Init(); // pour pouvoire utiliser la fonction delay :)
while (1)
{
distance=Read_Distance();
delay_nms(100);
}
}
void Init()
{
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_InitTypeDef gpioStructure;
gpioStructure.GPIO_Pin = GPIO_Pin_10;
gpioStructure.GPIO_Mode = GPIO_Mode_OUT;
gpioStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOD, &gpioStructure);
gpioStructure.GPIO_Pin = GPIO_Pin_11;
gpioStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_Init(GPIOD, &gpioStructure);
}
//Les Pins pour le Test sont PD10 (Trig) et PD11(echo)
uint32_t Read_Distance(void)
{
__IO uint8_t flag=0;
__IO uint32_t disTime=0;
GPIO_SetBits(GPIOD,GPIO_Pin_10);
delay_nus(10);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
while(flag == 0)
{
while(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == SET)
{
disTime++;
flag = 1;
}
}
return disTime;
}
Looks like you're using one of those ultrasonic distance measurement modules
Try this:
while(flag == 0)
{
disTime++;
if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == SET)
{
flag = 1;
}
}
You should use one of the hardware timers to get a more accurate time measurement.
Now I've had time to think more about it I remember now that you get a pulse sent back with a width proportional to the distance. I think this is the correct answer:
// Wait for pulse to start
while (GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == RESET)
{
NOP;
}
// Measure pulse width
while(flag == 0)
{
disTime++;
// Has pulse ended
if(GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_11) == RESET)
{
flag = 1;
}
}
You may also want to tackle the case where the pulse is never received because this could will block forever.
If I understand correctly, D10 is wired to D11 and you want to check how long your signal remains high. If this is the case, you should increment a counter in timer interrupt handler when your pin is high and reset that counter variable once you've read it.

Using signal() inside handler function

I have taken this example from GNU library. And I wonder why they call signal() function twice, first time in main() when setting up the signal handler and second time inside handler function itself.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
/* This flag controls termination of the main loop. */
volatile sig_atomic_t keep_going = 1;
/* The signal handler just clears the flag and re-enables itself. */
void
catch_alarm (int sig)
{
keep_going = 0;
signal (sig, catch_alarm);
}
void
do_stuff (void)
{
puts ("Doing stuff while waiting for alarm....");
}
int
main (void)
{
/* Establish a handler for SIGALRM signals. */
signal (SIGALRM, catch_alarm);
/* Set an alarm to go off in a little while. */
alarm (2);
/* Check the flag once in a while to see when to quit. */
while (keep_going)
do_stuff ();
return EXIT_SUCCESS;
}
Now my code...
void createTimer(long freq_nanosec)
{
timer_t timerid;
struct sigevent sev;
struct itimerspec timerint;
struct sigaction saction;
/* Establish handler for timer signal */
saction.sa_flags = 0;
saction.sa_handler = OnTimer;
sigemptyset(&saction.sa_mask);
sigaddset (&saction.sa_mask, SIGIO);
if (sigaction(SIGALRM, &saction, NULL) == -1) error("sigaction");
else printf("OnTimer handler created\n");
/* Create real time signal */
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGALRM;
sev.sigev_value.sival_ptr = &timerid;
if (timer_create(CLOCKID, &sev, &timerid) == -1) error("timer_create");
else printf("timer ID is 0x%lx\n", (long) timerid);
/* Arm the timer */
timerint.it_value.tv_sec = timerint.it_interval.tv_sec =
freq_nanosec / 1000000000;
timerint.it_value.tv_nsec = timerint.it_interval.tv_nsec =
freq_nanosec % 1000000000;
if (timer_settime(timerid, 0, &timerint, NULL) == -1)
error("timer_settime");
else printf("Timer armed\n");
}
From the man page for signal, we see that when a signal arrives:
first either the disposition is reset to SIG_DFL, or the signal is blocked (see Portability below), and then handler is called with argument signum.
So after the signal arrives, further signals will revert to default behavior. In your sample code, the handler is choosing to re-set the signal handler so further signals will be handled in the same manner as the first.
This is noted in the comment for the function catch_alarm in the code you found.
There are two popular versions of signal, which differ in whether the disposition of a signal is reset to the default when the handler is called, and whether a signal is blocked for the duration of its handler's execution.
The standard says those two behaviors are implementation-defined. The first code sample
void
catch_alarm (int sig)
{
keep_going = 0;
signal (sig, catch_alarm);
}
is assuming that the implementation may reset the signal disposition to the default when the handler is called. That's like calling signal(sig, SIG_DFL) in the first line of the handler. You almost never want that, because the next time a SIGALRM signal comes in, the default action is for the program to be killed. So the handler calls signal(sig, catch_alarm) to re-establish itself as the handler.
Your second code sample
saction.sa_flags = 0;
saction.sa_handler = OnTimer;
sigemptyset(&saction.sa_mask);
sigaddset (&saction.sa_mask, SIGIO);
if (sigaction(SIGALRM, &saction, NULL) == -1) error("sigaction");
uses sigaction, which is generally preferred over signal because you can specify exactly the behavior you want. The standard says
new applications should use sigaction() rather than signal().
When .sa_flags has the SA_RESETHAND flag on, the disposition of the signal is reset to the default when the handler starts, just like in (one version of) signal.
But in your case, that flag is off because you set .sa_flags to 0, so you don't need to write any code to re-establish the handler.

How to offset note scheduling for interactive recording of notes via user controls

In the code below I have a note scheduler that increments a variable named current16thNote up to 16 and then looping back around to 1. The ultimate goal of the application is to allow the user to click a drum pad and push the current16thNote value to an array. On each iteration of current16thNote a loop is run on the track arrays looking for the current current16thNote value, if it finds it the sound will play.
//_________________________________________________________General variable declarations
var isPlaying = false,
tempo = 120.0, // tempo (in beats per minute)
current16thNote = 1,
futureTickTime = 0.0,
timerID = 0,
noteLength = 0.05; // length of "beep" (in seconds)
//_________________________________________________________END General variable declarations
//_________________________________________________________Load sounds
var kick = audioFileLoader("sounds/kick.mp3"),
snare = audioFileLoader("sounds/snare.mp3"),
hihat = audioFileLoader("sounds/hihat.mp3"),
shaker = audioFileLoader("sounds/shaker.mp3");
//_________________________________________________________END Load sounds
//_________________________________________________________Track arrays
var track1 = [],
track2 = [5, 13],
track3 = [],
track4 = [1, 3, 5, 7, 9, 11, 13, 15];
//_________________________________________________________END Track arrays
//_________________________________________________________Future tick
function futureTick() {
var secondsPerBeat = 60.0 / tempo;
futureTickTime += 0.25 * secondsPerBeat;
current16thNote += 1;
if (current16thNote > 16) {
current16thNote = 1
}
}
//_________________________________________________________END Future tick
function checkIfRecordedAndPlay(trackArr, sound, beatDivisionNumber, time) {
for (var i = 0; i < trackArr.length; i += 1) {
if (beatDivisionNumber === trackArr[i]) {
sound.play(time);
}
}
}
//__________________________________________________________Schedule note
function scheduleNote(beatDivisionNumber, time) {
var osc = audioContext.createOscillator(); //____Metronome
if (beatDivisionNumber === 1) {
osc.frequency.value = 800;
} else {
osc.frequency.value = 400;
}
osc.connect(audioContext.destination);
osc.start(time);
osc.stop(time + noteLength);//___________________END Metronome
checkIfRecordedAndPlay(track1, kick, beatDivisionNumber, time);
checkIfRecordedAndPlay(track2, snare, beatDivisionNumber, time);
checkIfRecordedAndPlay(track3, hihat, beatDivisionNumber, time);
checkIfRecordedAndPlay(track4, shaker, beatDivisionNumber, time);
}
//_________________________________________________________END schedule note
//_________________________________________________________Scheduler
function scheduler() {
while (futureTickTime < audioContext.currentTime + 0.1) {
scheduleNote(current16thNote, futureTickTime);
futureTick();
}
timerID = window.requestAnimationFrame(scheduler);
}
//_________________________________________________________END Scheduler
The Problem
In addition to the previous code I have some user interface controls as shown in the following image.
When a user mousedowns on a “drum pad” I want to do two things. The first is to hear the sound immediately , and the second is to push the current16thNote value to the respective array.
If I use the following code to do this a few problems emerge.
$("#kick").on("mousedown", function() {
kick.play(audioContext.currentTime)
track1.push(current16thNote)
})
The first problem is that the sound plays twice. This is because when the sound is pushed to the array it is immediately recognized by the next iteration of the note scheduler and immediately plays. I fixed this by creating a delay with setInterval to offset the push to the array.
$("#kick").on("mousedown", function() {
kick.play(audioContext.currentTime)
window.setTimeout(function() {
track1.push(note)
}, 500)
})
The second problem is musical.
When a user clicks a drum pad the value that the user anticipates the drum will be recorded at is one 16th value earlier. In other words if you listen to the metronome and click on the kick drum pad with the intent of landing right on the 1/1 down beat this won't happen. Instead, when the metronome loops back around it will have been “recorded” at one 16th increment later.
This can be remedied by writing code that intentionally offsets the value that is pushed to the array by -1 .
I wrote a helper function named pushNote to do this.
$("#kick").on("mousedown", function() {
var note = current16thNote;
kick.play(audioContext.currentTime)
window.setTimeout(function() {
pushNote(track1, note)
}, 500)
})
//________________________________________________Helper
function pushNote(trackArr, note) {
if (note - 1 === 0) {
trackArr.push(16)
} else {
trackArr.push(note - 1)
}
}
//________________________________________________END Helper
My question is really a basic one. Is there a way to solve this problem without creating these odd “offsets” ?
I suspect there is a way to set/write/place the current16thNote increment without having to create offsets to other parts of the program. But I'm hazy on what it could be.
In the world of professional audio recording there isn't a tick per 16th division value , you usually have 480 ticks per quarter note. I want to begin exploring writing my apps using this larger value but I want to resolve this "offset" issue before I go down that rabbit hole.

How to suspend a task using FreeRTOS

Am trying to learn freeRTOS. How can I make a task to go to sleep after running for 2 seconds? I've tried using vTaskSuspend() to stop the task immediately and i also tried to put v taskDelay(2000), but it doesn't work either.
I want to sleep the fast blinking task 2 seconds after it was called and run the normal blinking task.
void resourse(const TickType_t xFrequency)
{
TickType_t xLastWakeTime;
xLastWakeTime = xTaskGetTickCount();
while(1)
{
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
vTaskDelayUntil( &xLastWakeTime, xFrequency);
}
}
xSemaphoreHandle botton_one = 0;
void botton(void* r)
{
while(1)
{
if(xSemaphoreTake(botton_one, 1))
{
HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin);
xSemaphoreGive(botton_one);
}
vTaskDelay(1);
}
}
void normal_blinking(void* r)
{
while(1)
{
if(xSemaphoreTake(botton_one, 1))
{
resourse(500);
xSemaphoreGive(botton_one);
}
}
}
void fast_blinking(void* s)
{
while(1){
if((HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin))== 0)
{
xSemaphoreTake(botton_one, 1);
resourse(50);
xSemaphoreGive(botton_one);
}
vTaskDelay(2000);
vTaskSuspend(NULL);
}
}
int main(void)
{
TaskHandle_t xHandle;
botton_one = xSemaphoreCreateMutex();
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
xTaskCreate(botton, (const char*)"task_1", 1024, 0, 3, 0);
xTaskCreate(normal_blinking, (const char*)"task_2", 1024, 0, 2,0);
xTaskCreate(fast_blinking, (const char*)"task_3", 1024, 0, 1,0);
vTaskStartScheduler();
while (1){
}
}
It is not clear what you are wanting to do, or what is not working as you want. You suggest using both vTaskSuspend() and vTaskDelay(), but they are used for different things.
If you call vTaskDelay() then the task will enter the Blocked state (stop being available as a task that can be actually executing) for whatever period you specify, then automatically leave the Blocked state after that period.
If you call vTaskSuspend() then the task will enter the Suspended state, and will never run again unless another task or interrupt calls vTaskResume().
Do you just want the task to run for two seconds, and then never again? In which case you could do something simple like:
void mytask( void *pv )
{
TickType_t xTimeOnEntering = xTaskGetTickCount();
while( xTaskGetTickCount() - xTimeOnEntering < pdMS_TO_TICKS( 2000 ) )
{
/* Run your code here. */
}
/* Two seconds of execution is up, delete the task. */
vTaskDelete( NULL );
}