The following GNAT runtimes are provided for the RP2350:
light_rp2350light_tasking_rp2350embedded_rp2350
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_rp2350 runtime as an example, first edit your
alire.toml file and add the following elements:
- Add
light_tasking_rp2350in the dependency list:[[depends-on]] light_tasking_rp2350 = "*"
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 RP2350 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 Timers' 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 System Timer and 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 the SIO doorbell is reserved for use by the runtime. For a single-core configuration (Max_CPUs = 1), the SIO doorbell is not reserved and can be used by the application.
The following peripherals configured by the runtime:
- The runtime enables the redundancy coprocessor at startup.
- 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 150 MHz. - The runtime sets
clk_usbandclk_adcto run frompll_usb.
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_Timer |
"TIMER0" "TIMER1" |
"TIMER0" | Selects which Sytem Timer peripheral is used by the runtime uses to implement the semantics of Ada.Real_Time. |
| Time_Base_Alarm |
"ALARM0" "ALARM1" "ALARM2" "ALARM3" |
"ALARM3" | Selects which ALARM interrupt of the System Timer chosen by Time_Base_Timer that the runtime uses to implement the semantics of Ada.Real_Time. The specified ALARM interrupt will be reserved by the runtime and must not be used by the user program. |
| Max_CPUs | 1, 2 | 2 |
Selects how many of the Cortex-M33 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. |
| Security_Level |
"Secure" "Non_Secure" |
"Secure" |
Configures the TrustZone execution state for the partition.
The runtime embeds this information into the Image Definition
metadata block. Note that the Non_Secure execution state requires a partition table to be configured in the final image, which you can embed using picotool from pico-sdk-tools. |
| 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_rp2350 runtime to only use the
first core, add this to your alire.toml:
[configuration.values]
light_tasking_rp2350.Max_CPUs = 1The following variables can be set to change the pll_sys clock configuration.
By default, a 150 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 | 5 | 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_rp2350.PLL_Sys_Reference_Div = 1
light_tasking_rp2350.PLL_Sys_VCO_Multiple = 133
light_tasking_rp2350.PLL_Sys_Post_Div_1 = 6
light_tasking_rp2350.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_2350" "pimoroni_tiny_2350" "pimoroni_rp2350_stamp_xl" "pimoroni_rp2350_stamp" "pimoroni_pga2350" "adafruit_feather_rp2350" "adafruit_metro_rp2350" "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_rp2350 runtime the variables
are LIGHT_TASKING_RP2350_BUILD and LIGHT_TASKING_RP2350_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_RP2350_BUILD=Debugor by setting them in your project's alire.toml:
[gpr-set-externals]
LIGHT_TASKING_RP2350_BUILD = "Debug"