FreeRTOS example for nRF9160

There are examples of using FreeRTOS with ARM Cortex M33 processors. Can this be used directly with a Nordic nRF9160 SoC? Is there a specific example/demo that implements FreeRTOS on an nRF9160?

You should be able to use the FreeRTOS Cortex-M33 port. This page provides more details - Using FreeRTOS on ARMv8-M Microcontrollers - FreeRTOS

Thanks.

Thanks, @aggarg, I’ll definitely give it a try. I was hoping that someone had already tried it and could relay their experience of porting FreeRTOS to the nRF9160. It appears that Nordic is only supporting Zephyr for their nRF9160.

Thanks. Let me know if you face any problem.

Hi Guarav,

You seem to be the native expert in porting FreeRTOS to the ARM Cortex M33 MCU core. I’m trying to port FreeRTOS to the nRF9160DK evaluation board from Nordic. I’ve downloaded the Nordic SDK which contains Zephyr as its RTOS. I’m using the recommended Segger Embedded Studio for development. Nordic will not support any other RTOS.

I don’t wish to use Zephyr as the RTOS. While it claims to have many great features, it seems to be overly complicated and takes abstraction to the extreme. It’s an RTOS written by developers from the Linux Foundation. I had a hard time finding main.c!!

Sorry, for the long background. I’ve had a long history with FreeRTOS, I trust it and it’s simple in its design and use. I’ve ported it over to many microcontrollers including ARM cores in the past. I’m having a bit of an issue with the nRF9160 due to the complication of the Trust Zone. Being unfamiliar with the TZ architecture (learning many things though) and with a bunch of IDEs, compilers, assemblers, and libraries all thrown into the FreeRTOS demos mix, I’m just not able to properly build a project.

I’m trying to do a simple template at this point to get me started and could use some guidance. For instance, I’m trying to set the Segger Embedded Studio IDE to use GCC throughout. I don’t want to be dependent on licensed software such as Keil, Embedded Workbench, etc. and their proprietary compilers/assemblers/linkers/libraries to achieve my goal. For instance, if I’m using GCC, what libraries should I use? I know I’ll have more questions to follow. Thanks for any guidance you can give me.

I’d suggest to first start with a bare metal first project and first get it to boot to the secure side. You then need to configure the Security Attribution Unit (SAU) for the non-secure software and then jump to the non-secure side. After that, you should add FreeRTOS.

Do you have a bare metal project to start with? I am happy to have a call if that can be helpful.

Thanks.

No, I don’t have a bare metal project. A call would be very helpful. In the meantime, is there somewhere you can point me to that can help me create and build this bare metal project?

I am not familiar with this platform and cannot say that. Usually the vendor examples have bare metal project that I use as a starting point. Please DM me with your email and preferred time and I will setup a call.

Thanks.

For everyone else, we have added the demo projects for nRF9160-DK:

Thanks.

Hi Gaurav,

It’s been a while. I have a new question regarding the use of FreeRTOS with the nRF9160. In this new effort, I’ve been trying to use Keil uVision for the same purposes that I used Segger Embedded Studio in terms of setting up a project and debugging with the tool.

I am running into a problem regarding the placement and use of the non-secure callable functions in uVision. On the secure side, I need to make sure that the NSC functions reside in a pre-determined section of flash. Once that is done, the SPU registers can set up the NSC flash section for the non-secure domain. Unfortunately, this is not a default set up for uVision (at least my set up doesn’t seem to have it as a default). I’ve tried multiple methods using the scatter file to relocate the NSC functions within the NSC section of flash with no luck. I’ve installed the Nordic family pack which includes the nRF9160. The scatter file does include a variable called, Veneer$$CMSE, which seems to be the key to all of this. I just can’t seem to unlock its secret. Here is my scatter file (I’ve commented out the original line and moved it. My attempted placement of the NSC functions have no effect (I’ve checked the map file). Also, there is a reference to a partition.h file which I cannot find although there is a partition_ARMCM33.h file.

Here is my scatter file:

; *************************************************************
; *** Scatter-Loading Description File generated by uVision ***
; *************************************************************

LR_IROM_S 0x00000000 0x00010000 ; load region size_region
{
    ER_IROM_S +0 ; load address = execution address
    {
        *.o (RESET, +First)
        *(InRoot$$Sections)
; Original code
;        *(Veneer$$CMSE)         ; This region is marked as Non-Secure callable in partition.h.
        .ANY (+RO)
        .ANY (+XO)
    }
	
; Move NSC functions to this section of flash
	ER_IROM_S_NSC 0x0000f000
	{
		*(Veneer$$CMSE)
	}
	
    RW_IRAM_S 0x20036000 0x00008000 ; RW data
    {
        .ANY (+RW +ZI)
    }
}

I’m hoping there’s a simple solution. Please advise.

Thanks,

Johnas

Can you try something like this - FreeRTOS/FreeRTOSDemo_s.sct at main · FreeRTOS/FreeRTOS · GitHub

Yes, that seems to have solved my problem. Thanks again.

Glad that it worked for you.

Hi Gaurav,

OK, I got FreeRTOS to start using uVision, but when I try to run the TZ_Demo/MPU_Demo, I get into trouble. I’m seeing a hard fault and an unintended memory fault. I tried isolating the issues by starting with TZ_Demo first. This is producing a hard fault when calling:

portALLOCATE_SECURE_CONTEXT( configMINIMAL_SECURE_STACK_SIZE );

inside the prvSecureCallingTask task.

I believe this probably means that I’m trying to access secure memory from the non-secure domain.

I can upload my project for you to try if that helps.

Did you figure out the exact instruction generating the fault?

Please do.

Did you figure out the exact instruction generating the fault?

Yes. In the file, port.c inside the function, vPortSVCHandler_C(), a call is made to SecureContext_AllocateContext(). I get a hard fault (PC = 0x4aa) at that point.
Here’s a screenshot:

Here is the entire project (compressed in zip file):
TZ-MPU_Demo.zip (517.2 KB)

Thanks for your help.

I discovered something that might help. The call is to the secure side through the veneer function. On the secure side, I set the compiler variable secureconfigTOTAL_HEAP_SIZE=0. When I set it to 256 bytes, the call to SecureContext_AllocateContext() returns, but the return value is 0 (securecontextINVALID_CONTEXT_ID). I probably need to set a larger heap size. However, when I attempt to do that, I get build errors (not enough space). I will try to expand the secure RAM size to see if this fixes it. I thought FreeRTOS makes its own heap. The secure side is bare metal. Is the heap that FreeRTOS use just for the nonsecure domain?

There is a component of FreeRTOS which runs on the secure side to help manage the secure side context associated with a task. The secure side heap is used to allocate the secure side context for a task. Increasing secureconfigTOTAL_HEAP_SIZE should fix your problem.

OK, I found the issue with the TZ_Demo so far. It seems that the startup code (secure side) looks to see if __STARTUP_CONFIG is defined. If not, it allocates 15872 bytes to the stack and the same to the heap for a total of 31 kBytes. Where did this number come from? How do I get __STARTUP_CONFIG defined and set to a smaller number (if not zero)? It seems that the stack and heap may be defined in multiple places.

I’ll keep digging.

So, I changed the stack and heap size in the file, arm_startup_nrf9160.s to zero and both the MPU and TZ demos now work at optimization 0 (-O0). Here’s the code that was affected:

                IF :DEF: __STARTUP_CONFIG
#ifdef  __STARTUP_CONFIG
#include "startup_config.h"
#ifndef __STARTUP_CONFIG_STACK_ALIGNEMENT
#define __STARTUP_CONFIG_STACK_ALIGNEMENT 3
#endif
#endif
	
                ENDIF

                IF :DEF: __STARTUP_CONFIG
Stack_Size      EQU __STARTUP_CONFIG_STACK_SIZE
                ELIF :DEF: __STACK_SIZE
Stack_Size      EQU __STACK_SIZE
                ELSE
Stack_Size      EQU 	0	;15872 <-------------------
                ENDIF
                
                IF :DEF: __STARTUP_CONFIG
Stack_Align     EQU __STARTUP_CONFIG_STACK_ALIGNEMENT
                ELSE
Stack_Align     EQU 3
                ENDIF

                AREA    STACK, NOINIT, READWRITE, ALIGN=Stack_Align
Stack_Mem       SPACE   Stack_Size
__initial_sp

                IF :DEF: __STARTUP_CONFIG
Heap_Size       EQU __STARTUP_CONFIG_HEAP_SIZE
                ELIF :DEF: __HEAP_SIZE
Heap_Size       EQU __HEAP_SIZE
                ELSE
Heap_Size       EQU 	0	;15872 <-------------------

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit
				ENDIF

If I use the default optimization (-O1), only the TZ demo works. The MPU demo is giving me an unintended memory fault.