FreeRTOS on RISC-V runs "slowly"

nickolasb wrote on Friday, April 05, 2019:

Hi all,
I recently put together FreeRTOS and freedom-e-sdk to run on a HiFive1 board, but it was running slower than it should. I realised later that FreeRTOS was working correctly, but that the calculated ticks were too long. For example: the demo used pdMS_TO_TICKS( 1000 ) to delay a task for 1 second. However that would take minutes of real time.
In the end I had to use these values to get close to the real time delays:
define configCPU_CLOCK_HZ ( 17500 )
define configTICK_RATE_HZ ( ( TickType_t ) 100 )

Please, have anyone tried FreeRTOS on a HiFive1 and got different results?
And do you think it is a problem to “lie” to FreeRTOS about the clock, in order to get timers close to real time values?
Thanks!

More details:

richarddamon wrote on Friday, April 05, 2019:

You shouldn’t need to ‘lie’ to FreeRTOS. The likely problem is that the port layer has a bug for that system and isn’t setting up the tick timer right. The define configCPU_CLOCK_HZ should only be used by the port layer to setup the timer, which should also be using the configTICK_RATE_HZ define. If the ticks aren’t occuring at the right rate, that setup function is wrong.

I don’t know those particular systems/projects, but I do know how FreeRTOS works, and getting wrong period tick interurpts it the responsibility/fault of the port layer in port.c in a function called an named to set up the system timer (I don’t have the code in front of me to get the exact name, but it should be obvious looking throgh port.c). Values being that far off sounds like something may be wanting values scaled differently than being provided.

rtel wrote on Friday, April 05, 2019:

What is generating the clock input to the MCU? Does the part have a
CLINT (I think it does)? If so, does it have a machine clock (mclock -
I think it does)? If so, how do you know how fast the machine clock is
running? Maybe the clock needs initialising to do something like enable
the PLL to make it go quickly.

nickolasb wrote on Tuesday, April 09, 2019:

Thanks for you prompt response.
And thanks to your answers I (almost) found the issue!

There are two cycle counters on RISC-V, as described on the The RISC-V Instruction Set Manual Volume II: Privileged Architecture (https://content.riscv.org/wp-content/uploads/2017/05/riscv-privileged-v1.10.pdf):

  • “The mcycle CSR holds a countof the number of cycles the hart has executed since some arbitrary time in the past.” (section 3.1.16)
  • “Platforms provide a real-time counter, exposed as a memory-mapped machine-mode register, mtime. mtime must run at constant frequency, and the platform must provide a mechanism for determining the time base of mtime.” (section 3.1.15)

I found considerable evidence that mtime frequency is 32768 Hz, or 32KHz:

  • The SiFive E31 Core Complex Manual v2p0 (https://sifive.cdn.prismic.io/sifive%2Fb06a2d11-19ea-44ec-bf53-3e4c497c7997_sifive-e31-manual-v2p0.pdf) on section 6.3 says:
    “mtime is a 64-bit read-write register that contains the number of cycles counted from the rtc_toggle signal described in the E31 Core Complex User Guide.”
  • And in turn the E31 Core Complex User Guide says on section 8.2.1:
    “Generally, rtc_toggle is connected to either a Real Time Clock (e.g. 32.768 kHz) or to the base clock input frequency of the platform.”

The code that tries to measure the clock takes the mcycle/mtime difference into account:
https://github.com/sifive/freedom-e-sdk/blob/dca1dfaf1cfb80ec30a7a16b899efa1040e3451d/bsp/env/freedom-e300-hifive1/init.c#L42
It looks to correctly measure how many “mcycle cycles” happened between each “mtime cycle”, and then uses the 32KHz to calculate the mcycle frequency.

But the code on FreeRTOS/Source/portable/GCC/RISCV/port.c, more specifically, the function vPortSetupTimerInterrupt, wasn’t considering it. I “fixed” it dividing the clock by 32KHz, which is the frequency of the mtime cycles:
const uint32_t ulTimerIncrementsForOneTick = ( uint32_t ) ( ( configCPU_CLOCK_HZ / 32768) / configTICK_RATE_HZ );
Now it calculates the next tick using “mtime cycles”, which happen at a frequency of 32KHz.

By the end the timers are no longer wrong by a factor of 8000. However, they are still wrong by a factor of 4. (32/8=4)
So I’ll continue looking into what is wrong. I’ll probably explore this sentence:
“Generally, rtc_toggle is connected to either a Real Time Clock (e.g. 32.768 kHz) or to the base clock input frequency of the platform.”
Please, if you have anything to say, or know who could I talk to about fixing the file above, leave a response.

rtel wrote on Tuesday, April 09, 2019:

Thanks for reporting back. Grateful if you can post any updates to the
port code you made too.

nickolasb wrote on Thursday, April 25, 2019:

Since my last post I was able to run the “test suite” found on FreeRTOS/Demo/RISC-V-Qemu-sifive_e-FreedomStudio/full_demo/main_full.c with mixed results.
When running them all (dynamic tasks, block timer, etc) they mostly failed.
When running them individually they all pass.
I think it might be related to timing, and I’m having better results by, for example, tweaking configTICK_RATE_HZ from 1000 to 10. Some tests use small delays that when converted using the macro pdMS_TO_TICKS would result in a 0 ticks delay.
Anyway, the whole thing still feels unstable.
Side note: I’ve also run out of memory and I had to re-program Arty’s SRAM from 16KB to 64KB.

rtel wrote on Thursday, April 25, 2019:

I have not tried running on the Arty - what is the clock frequency it is
using? You are right in that the tests are self monitoring and check
their own timing. Depending on how many you are running, if the
hardware is slow, physics might get in the way of them all passing at
once. I have an Arty and can give this a go myself (although not sure
when I will get the chance) so please let me know as much about your
hardware configuration as possible.