This tutorial demonstrates how Mongoose Library can be used to implement a device dashboard on a Raspberry Pi Pico W using the Pico-SDK with FreeRTOS and lwIP.

This tutorial is an example following on the device dashboard tutorial. You should read and follow that tutorial first.

Project structure

This example uses the Pico-SDK and includes configuration files for lwIP and FreeRTOS:

  • raspberry-pi-pico-w/ - the main example code that we clone from a sibling repo
    • raspberry-pi-pico-w/main.c - main application file, contains Mongoose logic and WiFi network initialization code
    • raspberry-pi-pico-w/mongoose.c - Mongoose Library source code
    • raspberry-pi-pico-w/mongoose.h - Mongoose Library header file
    • raspberry-pi-pico-w/net.c - the common code for this example
    • raspberry-pi-pico-w/packed_fs.c - a packed filesystem containing the web files to be served
    • raspberry-pi-pico-w/lwipopts.h - some lwIP config macros tweaked to suit this implementation
    • raspberry-pi-pico-w/FreeRTOSConfig.h - some FreeRTOS config macros tweaked to suit this implementation
  • Makefile - mainly invokes Docker to call the toolchain compiler

Build the project

It is assumed that you're using Linux or Mac as a workstation, you have Docker installed, and your user is able to run it. If in doubt, check it:

$ docker ps

Start a terminal in the project directory; clone the Mongoose Library repo, and run the make command:

$ git clone https://github.com/cesanta/mongoose
$ cd mongoose/examples/raspberry/raspberry-pi-pico-w/
$ make

This will clone the git repository with the project files; before building the project we need to edit the WiFi credentials, so open the raspberry-pi-pico-w/Makefile file and edit your WiFi network name and WiFi password settings:

The next step is to build the project.

  • Run make build.
    $ make build
  • Once the build succeeds, boot your Pico W in USB Mass Storage Mode by holding down the BOOTSEL button while you plug it into the USB port. Once it is connected, then release the BOOTSEL button. It should automatically mount as a new USB disk in your machine. Now either manually copy or drag and drop the generated firmware.uf2 file into this new USB disk device.
  • The Pico W will flash this code and reboot, unmounting this disk and running the flashed code.
  • Now open a second terminal, this will be our serial console to see the logs. Run a serial port software (we use minicom; make sure you configure it at 115200bps). Device name is usually /dev/ttyACM0
    $ minicom -D /dev/ttyACM0

Try it out

Start a browser on http://IP_ADDRESS where IP_ADDRESS is the board's IP address assigned by your DHCP server. You should see a login screen.

From here on, please go to the device dashboard tutorial and repeat some of the steps depicted there

Main task

The main() function initializes the board and starts the FreeRTOS scheduler, creating a new task for us. This task has two blocks:

  1. Initialize WiFi and wait until the netwok is ready (DHCP has assigned us an IP address)
  2. Run Mongoose

Initialize the network

We call the function in charge of initializing the wireless chip, then call the WiFi connect function, which is a blocking function and returns when we have a valid IP address or the process has failed

Run Mongoose

Next goes Mongoose. It should be run after network initialization is complete. The logic is standard; we initialize the event manager, start a listener on port 80, and fall into an infinite event loop:

For this example we've chosen to embed all the web files in a packed filesystem, more information on the embedded filesystem tutorial

Note that Mongoose has been configured to run under FreeRTOS and lwIP, we do so in the Makefile by defining MG_ARCH=MG_ARCH_FREERTOS_LWIP

We have covered those aspects that are specific to the Pico W implementation, for the details on the application and the UI, please see the device dashboard tutorial.

Configuring FreeRTOS

  • Task Memory allocation defaults to dynamic. This means that memory for the stack of each new task, will be allocated from FreeRTOS heap. To work with applications requiring a high stack size, FreeRTOS heap size must be large:
  • Some tasks, like the WiFi chip driver, need a stack a bit over the bare minimum that is usually FreeRTOS default. As it will use the configured minimum, we define that on the FreeRTOS configuration file (in words):
  • Mongoose needs a large stack, we specify that at the task creation function call (in words):

Configuring lwIP

  • Since we'll be using several connections simultaneously, we need to tell lwIP so. Even though we are using the socket interface, internally in lwIP it uses a decoupling API called netconn, so we'll set the number of allowed connections high enough:
    Make sure you don't modify `LWIP_NETCONN`, the default is for it to be enabled, so leave it as it is and don't redefine it in your lwipopts.h file
  • lwIP default priorities are simple numbers which might or might not coincide with the RTOS defined range; we take care to assign them in accordance with the rest of our project. Don't go much higher as the WiFi chip driver task is currently at tskIDLE_PRIORITY + 4. Furthermore, lwIP stack size default definitions are in bytes, while FreeRTOS uses words, so there is a macro to clearly express our choice on the stack sizes beyond doubt: