Preface#
Before starting to build the web server, we need to set up a few things. The most important one is a real-time operating system (RTOS). Now that the project is slowly getting larger, it is wise to use an RTOS instead of doing everything bare metal.
The Project Template#
FreeRTOS is the RTOS I chose for this project. It is quite minimal and open source. I also created a minimal template that I can use in later projects.
Here is the repo: https://github.com/codetit4n/nrf52840-freertos-template
NOTE: This repo contains a simple Blinky example and some starter code for using FreeRTOS with the nRF52840.
Dependencies#
The FreeRTOS Kernel. This is the core of FreeRTOS and contains the scheduler and other essential components. It is included as a submodule in the template repo.
NOTE: Remember to clone the repo with
--recurse-submodules, or rungit submodule update --init --recursiveafter cloning, as the submodule is not cloned by default.The CMSIS (Common Microcontroller Software Interface Standard) headers for the nRF52840. These headers provide the standard Cortex-M definitions that connect the C code to the ARM core and the nRF52840 device headers. They are included as-is.
Linker files, startup files, and some important C files for the nRF52840. The whole nrfx MDK is included in the repo, but only the required files are compiled and linked using the Makefile.
The Makefile#
The template uses a single Makefile, which means we can manage most of the project using that file alone. Here are some important parts of the Makefile:
The whole FreeRTOS Kernel is not included in the final binary. Only the required files are included:
FREERTOS_SRCS := \ $(FREERTOS)/list.c \ $(FREERTOS)/queue.c \ $(FREERTOS)/tasks.c \ $(FREERTOS)/portable/GCC/ARM_CM4F/port.c \ $(FREERTOS)/portable/MemMang/heap_4.cThe
list.c,queue.c, andtasks.cfiles are part of the FreeRTOS core. Theport.cfile is the port layer for the Cortex-M4F processor, whileheap_4.cis the memory-management implementation used in this project. It provides a simple memory allocator that uses a fixed-size region of memory to manage dynamic allocations.MCU-specific compiler flags are added for the nRF52840’s Cortex-M4F processor, including Thumb instruction generation, hardware floating-point support, optimization, debugging information, and compiler warnings:
# ------------------------------------------------- # CPU flags (nRF52840 = Cortex-M4F) # ------------------------------------------------- CFLAGS := -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard CFLAGS += -O2 -g3 -ffunction-sections -fdata-sections CFLAGS += -Wall -WextraApart from these, it is fairly standard, containing compile rules, linker rules, and some additional targets for flashing and cleaning the project.
FreeRTOS Configuration#
Apart from all the above, there are a few more files required for FreeRTOS to work.
FreeRTOSConfig.h— this header file contains the configuration for FreeRTOS. It is a very important file and should be configured properly. The configuration is based on the FreeRTOS API Reference. It is quite a long file, but it is well documented. It controls the clock frequency, task priorities, tick rate, stack sizes, and more. Here are a few examples from the file:/* nRF52840 runs at 64 MHz after SystemInit() */ #define configCPU_CLOCK_HZ ( 64000000UL ) /* 1 ms tick */ #define configTICK_RATE_HZ ( 1000 ) /* Max number of priorities (0 .. 2) */ #define configMAX_PRIORITIES ( 3 ) /* Stack sizes are in WORDS (not bytes) */ #define configMINIMAL_STACK_SIZE ( 128 ) // ...and many more configurations...freertos_hooks.c— this file defines handlers for two critical FreeRTOS failures: task stack overflow and heap-allocation failure. In either case, interrupts are disabled and execution is stopped in an infinite loop, making the failure deterministic and easier to inspect with a debugger:void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) { (void)xTask; (void)pcTaskName; taskDISABLE_INTERRUPTS(); for (;;) ; } void vApplicationMallocFailedHook(void) { taskDISABLE_INTERRUPTS(); for (;;) ; }
The Template Code: Blinky Example#
The template code is a simple Blinky example that uses FreeRTOS to blink an LED connected to pin P0.13 of the
nRF52840. The pin is defined in the board.h
file:
#include "nrf52840.h"
#define BOARD_LED1_PORT NRF_P0
#define BOARD_LED1_PIN 13Apart from that, it contains inline
functions to initialize the LED, toggle it, and turn it on or off.
NOTE: This template also uses the nrf52840.h header from the MDK. It contains definitions for the nRF52840 registers and peripherals.
The main code is in the main.c file.
The main() function initializes the board and creates a FreeRTOS task to blink the LED:
int main(void) {
/* Basic board init (GPIO only for now) */
board_led1_init();
/* Create LED task */
BaseType_t ok = xTaskCreate(led_task, /* Task function */
"LED", /* Name (for debug) */
128, /* Stack size (words, not bytes) */
NULL, /* Parameters */
1, /* Priority */
NULL /* Task handle */
);
/* If task creation failed, halt */
if (ok != pdPASS) {
taskDISABLE_INTERRUPTS();
for (;;)
;
}
/* Start scheduler (never returns on success) */
vTaskStartScheduler();
/* Should never reach here */
taskDISABLE_INTERRUPTS();
for (;;)
;
}This code initializes the board, creates a task to blink the LED, and starts the FreeRTOS scheduler. The led_task()
function is defined as follows:
static void led_task(void *arg) {
(void)arg;
for (;;) {
board_led1_toggle();
vTaskDelay(pdMS_TO_TICKS(500));
}
}This task toggles the LED every 500 milliseconds using the vTaskDelay() function, which puts the task to sleep
for the specified duration in ticks. The pdMS_TO_TICKS() macro converts milliseconds to ticks based on the configured
tick rate.
You can use this template to start your own FreeRTOS project for the nRF52840. If you find it useful, consider giving the repo a star.