coretex-m4(STM32F407VG discovery) Questions about implementing vTaskDelay and Delay

jonginkk wrote on Friday, January 12, 2018:

Hello. I am new to FreeRTOS.
I have analyzed and understood the Scheduling method using Task.
I want to run the PID control source through FreeRTOS scheduling.

I included several functions in the FreeRTOS, such as the libraries tm_stm32f4_delay.h and tm_stm32f4_delay.c, which were imported from outside, and found that SysTick_Handler duplicated.
tm_stm32f4_delay.c defines the millis and delay functions we need to do the PID.

To solve this problem, I commented out the SysTick_Handler in the section of tm_stm32f4_delay.c and solved the compilation problem. I understood that [[#define xPortSysTickHandler SysTick_Handler]], which is embedded in FreeRTOS, is used for interrupts and is absolutely necessary.

After all, we need to implement the Delay function needed for the PID. The tool I am using is IAR.

The above is a description of the situation I experienced, and the questions are as follows.

  1. I want to use the function defined in the header file included in TaskFunction via vTaskDelay. Can this header file serve as a delay through a function called vTaskDelay?

  2. I read the contents of https://www.freertos.org/FreeRTOS_Support_Forum_Archive/November_2013/freertos_configTICK_RATE_HZ_8fc54ac4j.html, but I do not understand.
    We implemented a delay using the vTaskDelay function, but this did not allow accurate ms Delay.
    I set it to #define configTICK_RATE_HZ ((TickType_t) 1000) and I wanted a delay of 500ms, but when I measured it with an oscilloscope, it took about 2 seconds of delay.
    There is only one external_LED_TASK task to operate.

//delay.h function
void external_delay_test (void)
{
// const TickType_t xDelay = 500 / portTICK_PERIOD_MS;

unsigned int n_iCnt = 0;
for (;;)
{

// vTaskList (ptrTaskList);
// printf (“ptrTaskList \ n”);
if ((n_iCnt% 2) == 0)
{
GPIO_SetBits (GPIOD, GPIO_Pin_4);
}
else if ((n_iCnt% 2) == 1)
{
GPIO_ResetBits (GPIOD, GPIO_Pin_4);
}
// puts (“LED2”);
printf (“PD4 ::::% d \ n”, n_iCnt);

    vTaskDelay (500);
    n_iCnt ++;
}

}

//main.c Taskfunction
void external_LED_TASK (void * pvParameter)
{
external_delay_test ();
}

I have implemented a for (;:wink: loop in external_delay_test, which is not implemented as a loop in TaskFunction itself.
We have confirmed that it works well when scheduling multiple TaskFunctions.

  1. Is the structure I think is wrong? If so, can you use vTaskDelay to delay for exactly one second? Or can I re-implement Delay?

I need help.

rtel wrote on Friday, January 12, 2018:

I included several functions in the FreeRTOS, such as the libraries
tm_stm32f4_delay.h and tm_stm32f4_delay.c,

These are ST files that call FreeRTOS functions - rather than FreeRTOS
files.

which were imported from
outside, and found that SysTick_Handler duplicated.

If you were to create the FreeRTOS project yourself it shouldn’t be
duplicated. Likewise, if you were to create the project using STM32Cube
it shouldn’t be duplicated. Note however that if you are using a
project generated by STM32Cube then it will install the ST HAL systick
handler, and call the FreeRTOS systick handler from that.

I want to use the function defined in the header file included in
TaskFunction via vTaskDelay. Can this header file serve as a delay
through a function called vTaskDelay?

Sorry - I don’t understand the question. If you want to use
vTaskDelay() then #include FreeRTOS.h and task.h (in that order), and
just call vTaskDelay(). The delay period is in ‘ticks’, so if you want
to specify it in ms then use the pdTICK_TO_MS() macro.

I read the contents of
https://www.freertos.org/FreeRTOS_Support_Forum_Archive/November_2013/freertos_configTICK_RATE_HZ_8fc54ac4j.html,
but I do not understand.

That is a rather old and somewhat random page to reference. Better to
reference the API documentation and the free to download book.

We implemented a delay using the vTaskDelay function, but this did
not allow accurate ms Delay.
I set it to #define configTICK_RATE_HZ ((TickType_t) 1000) and I
wanted a delay of 500ms, but when I measured it with an
oscilloscope, it took about 2 seconds of delay.

I’m guessing the value of configCPU_CLOCK_HZ is wrong.
configTICK_RATE_HZ is derived from configCPU_CLOCK_HZ so if the later is
wrong then the former will be calculated incorrectly.

configCPU_CLOCK_HZ should be set to the frequency of the clock that is
feeding the SysTick timer.

jonginkk wrote on Friday, January 12, 2018:

Thank you for your reply. I am a beginner, so the question would be insufficient.

I include FreeRTOS.h and task.h in global.h and global.h in the source definition file.
vTaskDelay () works. However, accurate time calculation is not possible.
My board is stm32f407, which has a clock of 168 MHz.

#if defined (STM32F40_41xxx)
uint32_t SystemCoreClock = 168000000;

#define configCPU_CLOCK_HZ (SystemCoreClock)

If so, where is the macro called pdTICK_TO_MS?

Is it possible to use the pdTICK_TO_MS to make the exact ms calculation possible with vTaskDelay?
I have checked #define portTICK_RATE_MS portTICK_PERIOD_MS similar to FreeRTOS.h. pdTICK_TO_MS is invisible.
If possible, please give an example of how to use this.
I need a delay function that can calculate the exact ms or s and give a delay.

please help me. thanks.

rtel wrote on Friday, January 12, 2018:

uint32_t SystemCoreClock = 168000000;

define configCPU_CLOCK_HZ (SystemCoreClock)

Setting the variable SystemCoreClock is not enough to actually program
the clocks on the MCU so that the actual clock frequency matches
SystmeCoreClock. That is normally done by a function called something
like (but not actually) SystemInit(). Search the source files using
grep or something similar for every instance of SystemCoreClock to see
where it is used, and if it is used in a function that sets up the
actual clocks, make sure the function is being used.

If so, where is the macro called pdTICK_TO_MS?

Sorry - I had that the wrong way around. It is pdMS_TO_TICKS(). You
specify a time in ms and get back the equivalent time in ticks. So
pdMS_TO_TICKS( 10 ) gives you the number of ticks in 10ms.

jonginkk wrote on Friday, January 12, 2018:

grep, or SystemCoreClock to find the source file and use the actual clock
When used in a function to set the function to use
Make sure you’re on.

  • I did not understand this part. SystemCloreClock is defined in system_stm32f4xx.c, and SystemCoreClock is also used.
    If so, can you suggest how to set up SystemCoreClock to do the right thing?

With configTIC_RATE_HZ = 1000,
vTaskDelay (100); Was measured at 321ms.

As your reply
vTaskDelay (pdMS_TO_TICKS (100))Was measured at 160ms.
vTaskDelay (pdMS_TO_TICKS (200))Was measured at 176ms…

I do not know what problem this is caused by.

rtel wrote on Friday, January 12, 2018:

grep, or SystemCoreClock to find the source file and use the actual clock
When used in a function to set the function to use
Make sure you’re on.

  • I did not understand this part. SystemCloreClock is defined in
    system_stm32f4xx.c, and SystemCoreClock is also used.
    If so, can you suggest how to set up SystemCoreClock to do the right
    thing?

SystemCoreClock will not be used in many places within the source files

  • just look in the source files to see every place it is used. Once of
    the places it will be used is in a function that configures the MCU
    clocks. SystemCoreClock holds the desired clock frequency, so the
    function will use SystemCoreClock to set the actual clock frequency to
    the desired clock frequency. Once you find the function that sets the
    actual clock frequency then make sure the function is actually being
    called. If the function is not called then it is likely the MCU clocks
    are just left at their default power up values, so your timing will not
    be accurate.

jonginkk wrote on Sunday, January 14, 2018:

Thank you for your answer.

I have analyzed HSE_VALUE in the stm32f4xx.h file for your answer.
This variable appears to have a constant value of 25MHz. Is this really the true external clock value, which means XTAL?

jonginkk wrote on Sunday, January 14, 2018:

Thank you for your answer.

I have analyzed HSE_VALUE in the stm32f4xx.h file for your answer.
This variable appears to have a constant value of 25MHz. Is this really the true external clock value, which means XTAL?

heinbali01 wrote on Sunday, January 14, 2018:

Although your question about frequencies is outside the scope of FreeRTOS, I will try to answer it shortly:

The clock starts with a High-Speed External oscillator (HSE), which has a frequency of e.g. 8, 12, or 25 Mhz (between 4 and 26 MHz).

This clock rate will go through a PLL: a unit that can both divide and multiply clock rates.
Every STM32F part has its own optimum working frequency (SystemCoreClock). This frequency has nothing to do with the oscillator but with the part itself.

Here is an example:

OSC (HSE) = 25 MHz

    #define HSE_VALUE    ((uint32_t)25000000)

PLL_M: The Oscillator frequency will first be divided by PLL_M to get 1 MHz. So for a 25 MHz oscillator, PLL_M is set to 25.

PLL_N: Main PLL (PLL) multiplication factor to get VCO (Voltage Controlled Oscillator). If PLL_N equals 336, then 1 MHz will turn into 336 MHz. This is a very high frequency which will be divided again to get workable frequencies: both for the CPU itself, as well as for some peripherals (e.g. USB).

PLL_P: Main PLL (PLL) division factor for main system clock

    00: PLLP = 2  // 336/2 = 168 Mhz
    01: PLLP = 4  // 336/4 = 84 MHz
    10: PLLP = 6
    11: PLLP = 8

PLL_Q: Main PLL (PLL) division factor for USB OTG FS

PLL_Q is often set at 7 to get : 336/7 = 48 MHz, which is the working speed for USB.

In the STM32F reference you will find a “clock tree”, which explains every detail.

Personally, I found the HAL drivers and example projects confusing. I would have liked to see a set of obligatory defines for the above values. These defines depend both on the part (maximum speed), as well as on the hardware (oscillator).

jonginkk wrote on Monday, January 15, 2018:

Thank you. I changed PPL_M = 25 to PPL_M = 8,
We changed the HSE_VALUE = 2500000 to HSE_VALUE = 800000 to get the correct clock value. The external clock settings on my board were set differently.
I have solved this problem with your help. I learned a lot.
If you use printf with freeRTOS, can you explain why the delays increase and explain the solution?

heinbali01 wrote on Monday, January 15, 2018:

I’m not sure how your printf() is implemented, most probably it will send the bytes to a serial port in a polling way. If so, try to set the baudrate at 115200 baud, which will give a throughput of about 11 KByte/sec. Still you will see delays of a few msec.
There are other ways of using the serial port: either interrupt-driven and/or with DMA. Please refer the ST’s site and forum to get more information about logging and printf().
And further: printf() is probably not thread-aware, and I think that you may never call it from within an ISR (Interrupt Service Routine).
If you want to log a time-critical process, I think you better just put the information into an array of strings, and inspect that when the process is ready.