STM32 FreeRTOS - Tasks with same priority running serial - c

I am starting on the FreeRTOS.
During my first tests I found something not clear for me.
Created 4 tasks with the same priority (osPriorityNormal). All 4 tasks have the same code:
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN 5 */
uint8_t DebugString[50];
uint32_t ui32_SysTimer;
/* Infinite loop */
for(;;)
{
ui32_SysTimer = xTaskGetTickCount();
snprintf(DebugString, 30, "%10lu : DefaultTask\n", ui32_SysTimer);
HAL_UART_Transmit(&huart2, DebugString, strlen(DebugString), 1000);
vTaskDelay(500);
}
/* USER CODE END 5 */
}
Looking to the output data on the serial monitor, I was expecting to see all 4 tasks being called almost in parallel. Since the 500ms should not block the processing flow.
But they are running in series!
Same priorities
Changing the priorities than I see the expected behavior.
Different priorities
Why they are not starting in parallel when using the same priority?
Is the vTaskDelay() appropriate to give this minimum time to the task run again?
Thank you.

It seems the problem was in the output to the console.
The HAL_UART_Transmit function is getting a busy status and losing some of the data. That is the reason for the serial timing sequency.
One possible solution is to store the data in a buffer and print it to the console only once, in a dedicated task.

Related

While loop inside STM32F3xx HardFault handler does not execute forever as expected

I would like to find the cause of mysterious microcontroller resets that I am seeing in my project. The microcontroller I am using is an STM32F3 device with STM32F3xx driver library.
My setup also includes a J-link Ultra+ debugger, however frustratingly I have not yet figured out how to reproduce the resets. They occur almost always after leaving the device running for 12+ hours, and do not seem to occur when connected on a programming jig designed to interface with the debugger.
I believe that when the resets occur, the HardFault handler will be called. I have a number of these devices, and given I cannot connect them all to the debugger and the resets occur at inopportune times, I would like to be able to send some information via a serial line from the HardFault handler. The serial line would then be observed by an external device.
Further complicating things is the lack of unused UART pins. I am attempting to create a poor man's UART by flicking a GPIO on and off in the hard fault handler, with delays in between. To begin with, I just want to figure out how to flick this LED on and off with 50% duty cycle. My code currently looks something like this:
/**
* #brief This function handles Hard fault interrupt.
*/
void HardFault_Handler(void)
{
/* USER CODE BEGIN HardFault_IRQn 0 */
GPIO_InitTypeDef GPIO_InitStruct = {LED_Pin, GPIO_MODE_OUTPUT_PP,
GPIO_NOPULL, GPIO_SPEED_FREQ_LOW, 0};
HAL_GPIO_Init(LED_Port, &GPIO_InitStruct);
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
HAL_GPIO_WritePin(LED_Port, LED_Pin, GPIO_PIN_RESET);
HAL_Delay(10);
HAL_GPIO_WritePin(LED_Port, LED_Pin, GPIO_PIN_SET);
HAL_Delay(10);
/* USER CODE END W1_HardFault_IRQn 0 */
}
}
I am testing this by triggering a divide-by-zero reset. I have disabled all watchdogs yet I am finding that when this while loop is entered, it does not while forever, in fact the device restarts when it first hits a HAL_Delay() command.
Questions:
What might be causing the resets upon reaching HAL_Delay()?
Can I execute instructions indefinitely in the HardFault handler, or is there a limited amount of time I have to do things before a reset occurs?
Can I use timers in the hard fault handler?
Thanks very much for your help.
HAL_Delay(10); uses systick interrupt. When in HF you will not get any interrupts and this function will wait forever and your diodes will not flash. You need to delay another way, for example:
for(unsigned x = 0; x < 100000; x++) asm("");
Can I execute instructions indefinitely in the HardFault handler, or
is there a limited amount of time I have to do things before a reset
occurs?
Yes you can stay there as long as you wish. But no interrupts!!!!
Can I use timers in the hard fault handler?
Yes, but no timer interrupts. Basically, you can use all the peripherals if you wish.
What might be causing the resets upon reaching HAL_Delay
Hard to say. Did you enable watchdog?
Basically do not use HAL in HF as most of the functions use HAL_Delay internally. Program bare registers instead

Cyclic data reading (like 1Wire DS18B20 temperature) without blocking main program

I'm trying to do some temperature reading using DS18B20 sensor on Raspberry Pi. My problem is that reading data from this sensor takes time. It's not much, more or less 1 s, but I cannot allow my main program to wait until this is done. I don't need to have 'most recent value'. It's temperature, so I'm gonna ask about it every minute or so. But the sensor can make measurement for example every 10 s and this will provide me recent enough value. In mean time I have to process other requests made to application. So I am thinking of some kind of endless measure loop. In general it would look like:
> start time measurement
> get DS18B20 value from 1 wire
> parse output
> stop measure time
> get the execution time, and put it in some global variable
> sleep for UPDATE_EVERY_X - execution time
So I thought of using fork(), but this creates zombies when the main process exit. Main application is some kind of server, so it won't exit gently in most times, so I need some kind of additional protection and this should be not Linux unique method. I'm trying to write my app as portable I can.
Second thought of mine is to use threads. Dispatch one thread to do this infinite loop, and implement some basic producer - consumer, with mutexes etc. That thread will only lock the output temperature when all is done, so this will make significant difference in blocking time.
Third option is to use asynchronous IO. But this is kind of magic for me right know. I did not used this before but it appears in search results.
And for claryfication, this is not strictly about 1Wire DS18B20, but about main approach when you need to do task every x sec and share information between processes, kind of embedded timer interupts.
Best regards, voodoo16.
If you want the simplest option, remember that the "Convert T" and "Read Scratchpad" commands are two distinct steps. Your program can read the temperature, then come back for the value later. There's no need to stall the program, unless you want to get the temperature value the exact instant the conversion finishes.
mainLoop() {
while(1) {
// Do things
int16_t rawTemperature = readScratchpad(myTemperatureSensor); // Get the last temperature reading
if(!getTemperature(myTemperatureSensor)) { // Start the next conversion
//Temperature conversion was not done, throw out value
rawTemperature = INT16_MAX;
}
else {
float temperature = ((float)rawTemperature / 4.0f);
saveTemperature(temperature);
}
// Do other things while temperature conversion happens
}
}
Where in this case, getTemperature issues a "Convert T" command, and returns 0 or 1 according to the datasheet (replies 0 if the prior conversion wasn't done, 1 if a new conversion has been started).

Digital Clock program in C - use interrupt?

I am writing a monitoring program for a computer cluster that displays a lot of data onto an LCD screen. As part of the display, I would like to have a digital clock running showing the current date, hour, minute, and second. The problem is, I have a bunch of tasks going on in a big loop (ping requests, A/D conversions, file scanning) and I just don't have time to update the clock during the loop.
I'm using C under Linux (Debian).
Any suggestions of how I should got about solving this? I was thinking of maybe using an interrupt to update the clock every second, but how does one go about doing that under Linux? I've only really used interrupts with microntrollers before now.
You need to run some parallel code to do that. The best way I can think of for this application, is, by the use of threads using pthread_create() with a function like this:
void * clock_routine(void * args) {
while(1) {
// update clock
}
}
Call it similarly to this, in your main function:
pthread_t clock_tid; // Clock thread handle
int rc = pthread_create(&clock_tid, NULL, clock_routine, NULL);
And compile the file with the -lpthread flag.
The code in clock_routine will run in parallel to your other code, and since it's only a clock, you don't have any dependency/synchronization issues to deal with.
P.S.: (Kinda useless, but here goes:) I'm not sure, but using a sleep function inside your while(1) loop, to sleep for a few microseconds, "might" improve your program, since you don't need "real" time clock update, but just a few microseconds of accuracy. Constantly updating the clock like this, "might" be considered busy-waiting. If anyone knows more on this, please, correct me.

FreeRTOS tasks are not context switching

I'm using FreeRTOS port for PIC32 microcontroller on the PIC32MX starter kit. Was just playing with tasks but the tasks aren't context switching. Here are my main config settings:
#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 5 )
#define configKERNEL_INTERRUPT_PRIORITY 0x01
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 0x03
#define configTICK_RATE_HZ ( ( portTickType ) 100 )
Now I have two tasks defined which blink two LEDs. Both have priority of 4(highest). Under normal operation the LEDs should alternatively blink for each 100 ticks. But this doesn't happen. The second LED blinks for 100 ticks and the control goes to the general exception handler. Why does this happen? Seems like there is no scheduling at all.
FreeRTOS is a priority based pre-emptive scheduler, tasks of equal priority that do not yield processor time will be round-robin scheduled. Relying on round-robin scheduling is seldom suitable for real-time tasks, and depending on the configured time slice, that may mess up your timing. Time-slicing may even be disabled.
Your tasks must enter the Blocked state waiting on some event (such as elapsed time) to allow each other to run as intended.
That said, entering the exception handler rather than simply one task starving another or not running with the intended timing is a different matter. For that you will need to post additional information, though your first approach should be to deploy your debugger.
The absolute first thing to check is your "tick" interrupt. Often interrupts are not enabled, timers aren't set up right, clocks are not configured properly in the #pragma's that set up the PIC32.. and all those issues manifest themselves first in a lack of a "tick".
This is the #1 cause of not task switching: if you're not getting the tick interrupt. That's where the normal pre-emptive task switching happens.
Assuming you're using the "off the shelf demo", in MPLAB, set a breakpoint in the void vPortIncrementTick( void ) function (around line 177 in FreeRTOS\Source\portable\MPLAB\PIC32MX\port.c) and run your code. If it breakpoints in there, your timer tick is working.
Are you sure both tasks are well registered and the scheduler has been launched?
Something like the following code would do the job:
xTaskCreate( yourFirstTask, "firstTask", STACK_SIZE, NULL, TASK_PRIORITY, NULL );
xTaskCreate( yourSecondTask, "secondTask", STACK_SIZE, NULL, TASK_PRIORITY, NULL );
vTaskStartScheduler();
You can also add an application tick hook to see if the tick interruption occurs correctly or if there is a problem with the tick timer.
There are standard demo tasks that just blink LEDs in the FreeRTOS/Demo/Common/Minimal/flash.c source file. The tasks created in that file are included in the standard PIC32 demo application (which targets the Microchip Explorer16 board).
In its very simplest form, a task that just toggles and LED every 500ms would look like this:
/* Standard task prototype, the parameter is not used in this case. */
void vADummyTask( void *pvParameters )
{
const portTickType xDelayTime = 500 / portTICK_RATE_MS;
for( ;; )
{
ToggleLED();
vTaskDelay( xDelayTime );
}
}
Do you have a round-robin scheduler? Are your tasks sleeping for any length of time, or just yielding (or busy waiting)?
A very common gotcha in embedded OSs is that the scheduler will frequently not attempt to schedule multiple processes of the same priority fairly. That is, once A yields, if A is runnable A may get scheduled again immediately even if B has not had any CPU for ages. This is very counterintuitive if you're used to desktop OSs which go to a lot of effort to do fair scheduling (or at least, it was to me).
If you're running into this, you'll want to make sure that your tasks look like this:
for (;;)
{
led(on); sleep(delay);
led(off); sleep(delay);
}
...to ensure that the task actually stops being runnable between blinks. It won't work if it looks like this:
for (;;)
{
led(on);
led(off);
}
(Also, as a general rule, you want to use normal priority rather than high priority unless you know you'll really need it --- if you starve a system task the system can behave oddly or crash.)

ioctl and execution time

I have a program running two threads - they communicate using message queues.
In one thread, I call ioctl() to access the hardware decryptor. The code goes like:
void Decrypt
{
...
..
...
if(<condition 1>)
{.
...
...
retVal = ioctl(...);
comesInHere1++;
}
if(<condition 2>)
{
...
...
retVal = ioctl(...);
comesInHere2++;
}
comesInHere1 and comesInHere2 are used to count the number of times it goes in that particular if loop.
The entire program takes 80 ms to execute. But if I comment out the test variables (comesInHere1, comesInHere2 within the if loops), the execution time increases by 8 ms to 88 ms!
How is that possible? I cant comment out the variables now since it increases the time taken, cant keep them either - will get killed in code review :)
Kindly let me know
Thanks
Cache? It's possible that by adding a bit more data you're moving code to different cache lines that would somehow be placed together, causing thrashing. You could experiment by running on different systems and by adding padding data between variables that are used exclusively in each thread.
What happens if you serialize the processing onto a single core?

Resources