FreeRTOS on Raspberry Pi Pico?

After spending many hours trying to get coreMQTT to work with lwIP and BearSSL, I finally gave up. The problem was incompatible APIs. coreMQTT doesn’t really work with asynchronous functions (sending N bytes and being told that M have been sent via an asynchronous callback).

Using the simplified I/O in BearSSL doesn’t work either - coreMQTT wants recv to return immediately if there’s nothing to read (and a single byte was requested). However, BearSSL insists that recv blocks until at least one byte has been read.

So after fighting this for a while, I decided to try something new. FreeRTOS.

This and follow-up posts document my attempts at running FreeRTOS, lwIP, mbedTLS and coreMQTT on Raspberry Pi Pico.

FreeRTOS

Following the information in [FreeRTOS-Kernel](https://forums.raspberrypi.com/viewtopic.php?t=320182 I am using https://github.com/FreeRTOS/FreeRTOS-Kernel/tree/smp). There are fairly clear instructions in the README.

For FreeRTOSConfig.h I’m using the example from GitHub.

To build it with lwIP, one small change is required:

-#define configENABLE_BACKWARD_COMPATIBILITY     0
+#define configENABLE_BACKWARD_COMPATIBILITY     1

otherwise:

pico/pico-sdk/lib/lwip/contrib/ports/freertos/sys_arch.c: In function 'sys_arch_msleep':
pico/pico-sdk/lib/lwip/contrib/ports/freertos/sys_arch.c:192:39: error: 'portTICK_RATE_MS' undeclared (first use in this function); did you mean 'portTICK_PERIOD_MS'?
   TickType_t delay_ticks = delay_ms / portTICK_RATE_MS;
                                       ^~~~~~~~~~~~~~~~
                                       portTICK_PERIOD_MS

Now it compiles, but the linker is missing a couple of functions:

  • undefined reference to ‘vApplicationMallocFailedHook’
  • undefined reference to ‘vApplicationTickHook’

There’s information about those hooks here. It says that setting configUSE_TICK_HOOK and configUSE_MALLOC_FAILED_HOOK to 0 should allow this to build without implementing the hooks, but that’s not what I’m seeing.

Using the sample code for now.

Running a minimal amount of code fails immediately with:

assertion "pxNewQueue" failed: file "/home/omrib/FreeRTOS-Kernel/queue.c", line 480, function: xQueueGenericCreate

Adding this to the bottom of lwipopts.h helps:

#if !NO_SYS
#define TCPIP_THREAD_STACKSIZE 1024
#define DEFAULT_THREAD_STACKSIZE 1024
#define DEFAULT_RAW_RECVMBOX_SIZE 8

#define TCPIP_MBOX_SIZE 8
#define LWIP_TIMEVAL_PRIVATE 0

#define DEFAULT_UDP_RECVMBOX_SIZE TCPIP_MBOX_SIZE
#define DEFAULT_TCP_RECVMBOX_SIZE TCPIP_MBOX_SIZE

// not necessary, can be done either way
#define LWIP_TCPIP_CORE_LOCKING_INPUT 1
#endif

(taken from another example)

and changing the stack size in FreeRTOSConfig.h

-#define configMINIMAL_STACK_SIZE                ( configSTACK_DEPTH_TYPE ) 256
+#define configMINIMAL_STACK_SIZE                ( configSTACK_DEPTH_TYPE ) 1024

And now things can build and run. But the story isn’t over yet, of course.