Raspberry Pi Pico

Introduction

The Raspberry Pi Pico series is a range of tiny, fast, and versatile boards built using RP2040, the flagship microcontroller chip designed by Raspberry Pi in the UK

Designed by Raspberry Pi, RP2040 features a dual-core Arm Cortex-M0+ processor with 264kB internal RAM and support for up to 16MB of off-chip flash. A wide range of flexible I/O options includes I2C, SPI, and - uniquely - Programmable I/O (PIO). These support endless possible applications for this small and affordable package.

Specification
  • 21 mm × 51 mm form factor

  • RP2040 microcontroller chip designed by Raspberry Pi in the UK

  • Dual-core Arm Cortex-M0+ processor, flexible clock running up to 133 MHz

  • 264kB on-chip SRAM

  • 2MB on-board QSPI flash

  • 2.4GHz 802.11n wireless LAN (Raspberry Pi Pico W and WH only)

  • Bluetooth 5.2 (Raspberry Pi Pico W and WH only)

  • 26 multifunction GPIO pins, including 3 analogue inputs

  • 2 × UART, 2 × SPI controllers, 2 × I2C controllers, 16 × PWM channels

  • 1 × USB 1.1 controller and PHY, with host and device support

  • 8 × Programmable I/O (PIO) state machines for custom peripheral support

  • Supported input voltage 1.8–5.5V DC

  • Operating temperature -20°C to +85°C (Raspberry Pi Pico and Pico H); -20°C to +70°C (Raspberry Pi Pico W and Pico WH)

  • Castellated module allows soldering direct to carrier boards (Raspberry Pi Pico and Pico W only)

  • Drag-and-drop programming using mass storage over USB

  • Low-power sleep and dormant modes

  • Accurate on-chip clock

  • Temperature sensor

  • Accelerated integer and floating-point libraries on-chip

BUILDING

Get the PICO SDK

Setup the Raspberry Pi Pico SDK build environment by following the instructions for Getting Started With Pico. Ensure that PICO_SDK_PATH is set in your environment, or pass it via -DPICO_SDK_PATH=xxx on the CMake command line.

The Pico Examples repository provides a set of example applications that are written using the SDK. To clone these repositories start by creating a pico directory to keep all pico related checkouts in. These instructions create a pico directory at /home/pi/pico.

$ cd ~/
$ mkdir pico
$ cd pico

Then clone the pico-sdk and pico-examples git repositories.

$ git clone https://github.com/raspberrypi/pico-sdk.git --branch master
$ cd pico-sdk
$ git submodule update --init
$ cd ..
$ git clone https://github.com/raspberrypi/pico-examples.git --branch master

There are additional repositories: Pico Extras, and Pico Playground that you may also be interested in.

Install the Toolchain

To build the applications in pico-examples, you’ll need to install some extra tools. To build projects you’ll need CMake, a cross-platform tool used to build the software, and the GNU Embedded Toolchain for Arm. You can install both of these via apt from the command line. Anything you already have installed will be ignored by apt.

$ sudo apt update
$ sudo apt install cmake gcc-arm-none-eabi libnewlib-arm-none-eabi build-essential libstdc++-arm-none-eabi-newlib

Updating the SDK

$ cd pico-sdk
$ git pull
$ git submodule update

Updating Environment Path

echo 'export PICO_SDK_PATH=~/pico/pico-sdk' >> ~/.bashrc 
source ~/.bashrc

Download FreeRTOS

$ git clone --recursive https://github.com/FreeRTOS/FreeRTOS.git
$ cd FreeRTOS/Demo/ThirdParty/Community-Supported-Demos/CORTEX_M0+_RP2040
$ mkdir build
$ cd build
$ cmake ..
$ make 

This will generate .uf2 files for each demo application:

  • Blinky Demo - FreeRTOS/Demo/ThirdParty/Community-Supported-Demos/CORTEX_M0+_RP2040/build/Standard_smp/main_blinky_smp.uf2.

  • Comprehensive Demo - FreeRTOS/Demo/ThirdParty/Community-Supported-Demos/CORTEX_M0+_RP2040/build/Standard/main_full_smp.uf2

  • Multicore Demo

    • FreeRTOS/Demo/ThirdParty/Community-Supported-Demos/CORTEX_M0+_RP2040/build/OnEitherCore/on_core_zero.uf2

    • FreeRTOS/Demo/ThirdParty/Community-Supported-Demos/CORTEX_M0+_RP2040/build/OnEitherCore/on_core_one.uf2

Running

  1. Connect the Raspberry Pi Pico to your computer while holding the BOOTSEL button. This will force the board into USB Mass Storage Mode.

  2. Drag-and-drop the .uf2 file for the demo you want to run onto the Mass Storage Device.

RTOS Configuration and Usage Details
  • Configuration items specific to the blinky and comprehensive demos are in the FreeRTOS/Demo/ThirdParty/Community-Supported-Demos/CORTEX_M0+_RP2040/Standard_smp/FreeRTOSConfig.h file and those specific to the multicore demo are in the FreeRTOS/Demo/Community-Supported-Demos/CORTEX_M0+_RP2040/OnEitherCore/FreeRTOSConfig.h file. The constants defined in these files can be edited to suit your application. The following configuration options are specific to the SMP support in the FreeRTOS Kernel:

    • configNUMBER_OF_CORES - Set the number of cores.

    • configRUN_MULTIPLE_PRIORITIES - Enable/Disable simultaneously running tasks with multiple priorities.

    • configUSE_CORE_AFFINITY - Enable/Disable setting a task's affinity to certain cores.

  • Source/Portable/MemMang/heap_4.c is included in the project to provide the memory allocation required by the RTOS kernel. Please refer to the Memory Management section of the API documentation for complete information.

  • vPortEndScheduler() has not been implemented.

Output

Code

/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

/* Library includes. */
#include <stdio.h>
#include "hardware/gpio.h"

/* Priorities at which the tasks are created. */
#define mainQUEUE_RECEIVE_TASK_PRIORITY		( tskIDLE_PRIORITY + 2 )
#define	mainQUEUE_SEND_TASK_PRIORITY		( tskIDLE_PRIORITY + 1 )

/* The rate at which data is sent to the queue.  The 200ms value is converted
to ticks using the portTICK_PERIOD_MS constant. */
#define mainQUEUE_SEND_FREQUENCY_MS			( 1000 / portTICK_PERIOD_MS )

/* The number of items the queue can hold.  This is 1 as the receive task
will remove items as they are added, meaning the send task should always find
the queue empty. */
#define mainQUEUE_LENGTH					( 1 )

/* The LED toggled by the Rx task. */
#define mainTASK_LED						( PICO_DEFAULT_LED_PIN )

/*-----------------------------------------------------------*/

/*
 * Called by main when mainCREATE_SIMPLE_BLINKY_DEMO_ONLY is set to 1 in
 * main.c.
 */
void main_blinky( void );

/*
 * The tasks as described in the comments at the top of this file.
 */
static void prvQueueReceiveTask( void *pvParameters );
static void prvQueueSendTask( void *pvParameters );

/*-----------------------------------------------------------*/

/* The queue used by both tasks. */
static QueueHandle_t xQueue = NULL;

/*-----------------------------------------------------------*/

void main_blinky( void )
{
    printf(" Starting main_blinky.\n");

    /* Create the queue. */
	xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( uint32_t ) );

	if( xQueue != NULL )
	{
		/* Start the two tasks as described in the comments at the top of this
		file. */
		xTaskCreate( prvQueueReceiveTask,				/* The function that implements the task. */
					"Rx", 								/* The text name assigned to the task - for debug only as it is not used by the kernel. */
					configMINIMAL_STACK_SIZE, 			/* The size of the stack to allocate to the task. */
					NULL, 								/* The parameter passed to the task - not used in this case. */
					mainQUEUE_RECEIVE_TASK_PRIORITY, 	/* The priority assigned to the task. */
					NULL );								/* The task handle is not required, so NULL is passed. */

		xTaskCreate( prvQueueSendTask, "TX", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL );

		/* Start the tasks and timer running. */
		vTaskStartScheduler();
	}

	/* If all is well, the scheduler will now be running, and the following
	line will never be reached.  If the following line does execute, then
	there was insufficient FreeRTOS heap memory available for the Idle and/or
	timer tasks to be created.  See the memory management section on the
	FreeRTOS web site for more details on the FreeRTOS heap
	http://www.freertos.org/a00111.html. */
	for( ;; );
}
/*-----------------------------------------------------------*/

static void prvQueueSendTask( void *pvParameters )
{
TickType_t xNextWakeTime;
const unsigned long ulValueToSend = 100UL;

	/* Remove compiler warning about unused parameter. */
	( void ) pvParameters;

	/* Initialise xNextWakeTime - this only needs to be done once. */
	xNextWakeTime = xTaskGetTickCount();

	for( ;; )
	{
		/* Place this task in the blocked state until it is time to run again. */
		vTaskDelayUntil( &xNextWakeTime, mainQUEUE_SEND_FREQUENCY_MS );

		/* Send to the queue - causing the queue receive task to unblock and
		toggle the LED.  0 is used as the block time so the sending operation
		will not block - it shouldn't need to block as the queue should always
		be empty at this point in the code. */
		xQueueSend( xQueue, &ulValueToSend, 0U );
	}
}
/*-----------------------------------------------------------*/

static void prvQueueReceiveTask( void *pvParameters )
{
unsigned long ulReceivedValue;
const unsigned long ulExpectedValue = 100UL;

	/* Remove compiler warning about unused parameter. */
	( void ) pvParameters;

	for( ;; )
	{
		/* Wait until something arrives in the queue - this task will block
		indefinitely provided INCLUDE_vTaskSuspend is set to 1 in
		FreeRTOSConfig.h. */
		xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY );

		/*  To get here something must have been received from the queue, but
		is it the expected value?  If it is, toggle the LED. */
		if( ulReceivedValue == ulExpectedValue )
		{
			gpio_xor_mask( 1u << mainTASK_LED );
			ulReceivedValue = 0U;
		}
	}
}
/*-----------------------------------------------------------*/

Last updated