The following GNAT runtimes are provided for the RP2040:
light_rp2040light_tasking_rp2040embedded_rp2040
The pre-generated runtimes are distributed as crates in the Alire community index. This section describes how to set up your project to use one of those crates.
Using the light_tasking_rp2040 runtime as an example, first edit your
alire.toml file and add the following elements:
- Add
light_tasking_rp2040in the dependency list:[[depends-on]] light_tasking_rp2040 = "*"
Then edit your project file to add the following elements:
- "with" the run-time project files:
with "runtime_build.gpr"; with "ravenscar_build.gpr";
- specify the
TargetandRuntimeattributes:for Target use Runtime_Build'Target; for Runtime ("Ada") use Runtime_Build'Runtime ("Ada");
- specify the
Linkerswitches:package Linker is for Switches ("Ada") use Runtime_Build.Linker_Switches & ("-Wl,--gc-sections"); end Linker;
Tip
The --gc-sections linker switch is recommended (but not mandatory) to
remove any unused code and data sections from the executable and therefore
reduce memory usage.
The light-tasking and embedded runtime profiles support multitasking across
both cores on the RP2040 using the Ada language's task and protected
object mechanisms. By default, tasks run on the first core. Tasks can be pinned
to the second core using the CPU aspect or pragma in the task declaration.
For example, to declare a task that runs on the second core:
task My_Task with CPU => 2;Interrupt handlers can also be assigned execute on a specific core on a
per-interrupt basis.
Each interrupt in package Ada.Interrupts.Names has two variants: the
ones ending in _CPU_1 are executed on the first core, and the ones ending
in _CPU_2 are executed on the second core.
For example, to handle the PIO0_IRQ_0 interrupt on the second core:
protected My_PO with Interrupt_Priority => System.Interrupt_Priority'Last is
-- Declare public protected subprograms here
private
procedure PIO0_Interrupt_Handler with
Attach_Handler => Ada.Interrupts.Names.PIO0_IRQ_0_Interrupt_CPU_2;
end My_PO;Tip
If you don't want the runtime to use the second core, then you can configure
the runtime to only use the first core by setting the Max_CPUs crate
configuration variable to 1. The light runtime profile always uses 1 core.
The following peripherals are reserved for use by the the runtime (light-tasking and embedded runtime profiles only):
- One of the System Timer ALARM channels is used to implement Ada semantics
for time, i.e., delay statements and the package
Ada.Real_Time. The timer interrupt runs at the highest priority. The specific ALARM channel that is used is configurable. - When the runtime is configured to use both cores (i.e.
Max_CPUs > 1in the runtime configuration), then both the SIO FIFO and SPINLOCK31 are reserved for use by the runtime. For a single-core configuration (Max_CPUs = 1), these are not reserved and can be used by the application.
The following peripherals configured by the runtime:
- The runtime configures
clk_refto run at the reference clock speed, either XOSC or ROSC depending on the runtime configuration.clk_reftherefore runs at 12 MHz unless a different XOSC frequency is used. - The runtime configures
clk_usbandclk_sysusing the PLL settings specified by the user in the runtime configuration. The default configuration setsclk_usbto 48 MHz andclk_systo 125 MHz. - The runtime sets
clk_usbandclk_adcto run frompll_usb, and setsclk_rtcto run frompll_usbdivided by 1024 (46.875 kHz). - The runtime configures the watchdog tick to run at 1 MHz.
The runtime libraries provide a minimal version of package Ada.Text_IO
supporting character and string-based input and output routines. These are
implemented using semihosting, which requires a debugger to be attached.
Calling the semihosted Text_IO routines without a debugger attached will
trigger a HardFault on the processor that uses it.
The runtime can be configured by setting various crate configuration variables
in your project's alire.toml. The available configuration options are described
in the following subsections:
Note
The following configuration items apply to the light-tasking and embedded runtime profiles only.
| Variable | Values | Default | Description |
|---|---|---|---|
| Time_Base_Alarm |
"ALARM0" "ALARM1" "ALARM2" "ALARM3" |
"ALARM3" | Selects which ALARM interrupt the runtime uses to implement the semantics of Ada.Real_Time. The specified ALARM interrupt will be reserved by the runtime and will not be available for use by the user program. |
| Max_CPUs | 1, 2 | 2 |
Selects how many of the Cortex-M0+ cores are used by the runtime.
By default, the runtime uses both cores and tasks can be assigned to either
core using the CPU pragma or aspect on the task declaration. For example:
task My_Task with CPU => 2; runs My_Task on the second core. When this is set to 1, the runtime will ignore the second CPU and will schedule all tasks and interrupts on the first core. |
| Interrupt_Stack_Size | Any positive integer | 1024 | Sets the size of the primary stack used for interrupt handlers in bytes. |
| Interrupt_Secondary_Stack_Size | Any positive integer | 128 | Sets the size of the secondary stack used for interrupt handlers in bytes. |
For example, to configure the light_tasking_rp2040 runtime to only use the
first core, add this to your alire.toml:
[configuration.values]
light_tasking_rp2040.Max_CPUs = 1The following variables can be set to change the pll_sys clock configuration.
By default, a 125 MHz clock is generated, assuming a 12 MHz XOSC.
| Variable | Values | Default | Description |
|---|---|---|---|
| PLL_Sys_Reference_Div | 1 .. 63 | 1 | Sets the REFDIV for pll_sys |
| PLL_Sys_VCO_Multiple | 16 .. 320 | 125 | Sets the VCO multiplier for pll_sys |
| PLL_Sys_Post_Div_1 | 1 .. 7 | 6 | Sets POSTDIV1 for pll_sys |
| PLL_Sys_Post_Div_2 | 1 .. 7 | 2 | Sets POSTDIV2 for pll_sys |
The following variables can be set to change the pll_usb clock configuration.
By default, a 48 MHz USB clock is generated assuming a 12 MHz XOSC.
| Variable | Values | Default | Description |
|---|---|---|---|
| PLL_USB_Reference_Div | 1 .. 63 | 1 | Sets the REFDIV for pll_usb |
| PLL_USB_VCO_Multiple | 16 .. 320 | 40 | Sets the VCO multiplier for pll_usb |
| PLL_USB_Post_Div_1 | 1 .. 7 | 5 | Sets POSTDIV1 for pll_usb |
| PLL_USB_Post_Div_2 | 1 .. 7 | 2 | Sets POSTDIV2 for pll_usb |
For example, to configure a 133 MHz clock add the following to your alire.toml:
[configuration.values]
light_tasking_rp2040.PLL_Sys_Reference_Div = 1
light_tasking_rp2040.PLL_Sys_VCO_Multiple = 133
light_tasking_rp2040.PLL_Sys_Post_Div_1 = 6
light_tasking_rp2040.PLL_Sys_Post_Div_2 = 2| Variable | Values | Default | Description |
|---|---|---|---|
| Board |
"generic_board" "rpi_pico2" "pimoroni_pico_lipo_2_xl_w" "pimoroni_pico_plus_2" "pimoroni_plasma_2040" "pimoroni_tiny_2040" "pimoroni_rp2040_stamp_xl" "pimoroni_rp2040_stamp" "pimoroni_pga2040" "adafruit_feather_rp2040" "adafruit_metro_rp2040" "adafruit_fruit_jam" |
"rpi_pico2" |
Configures the runtime for a specific board. This is used to select the
appropriate linker script and XOSC based on the board. When "generic_board" is selected, the board parameters must be set manually (see below). |
When "generic_board" is selected as the board, then the following configuration
variables can be set to specify the board parameters.
These variables are ignored for non-generic boards.
| Variable | Values | Default | Description |
|---|---|---|---|
| XOSC_Frequency | Any non-negative value | 12000000 | Specifies the frequency of the on-board XOSC in Hertz. Set to 0 if the board does not have an XOSC. |
| XOSC_Startup_Delay_Mult | 1 .. 16383 | 64 | Sets the startup delay for the XOSC in milliseconds. |
| Flash_Size |
2 4 8 16 |
2 | Sets the size of the flash chip that is fitted on the board in megabytes. This is used to set the memory size in the linker script. |
The runtime project files expose *_BUILD and and *_LIBRARY_TYPE GPR
scenario variables to configure the build mode (e.g. debug/production) and
library type. These variables are prefixed with the name of the runtime in
upper case. For example, for the light_tasking_rp2040 runtime the variables
are LIGHT_TASKING_RP2040_BUILD and LIGHT_TASKING_RP2040_LIBRARY_TYPE
respectively.
The *_BUILD variable can be set to the following values:
Production(default) builds the runtime with optimization enabled and with all run-time checks suppressed.Debugdisables optimization and adds debug symbols.Assertenables assertions.Gnatcovdisables optimization and enables flags to help coverage.
The *_LIBRARY_TYPE variable can be set to either static (default) or
dynamic, though only static libraries are supported on this target.
You can usually leave these set to their defaults, but if you want to set them explicitly then you can set them either by passing them on the command line when building your project with Alire:
alr build -- -XLIGHT_TASKING_RP2040_BUILD=Debugor by setting them in your project's alire.toml:
[gpr-set-externals]
LIGHT_TASKING_RP2040_BUILD = "Debug"