Skip to content

Latest commit

 

History

History
405 lines (362 loc) · 12.3 KB

File metadata and controls

405 lines (362 loc) · 12.3 KB

RP2040 Runtimes

The following GNAT runtimes are provided for the RP2040:

  • light_rp2040
  • light_tasking_rp2040
  • embedded_rp2040

Usage

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_rp2040 in 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 Target and Runtime attributes:
    for Target use Runtime_Build'Target;
    for Runtime ("Ada") use Runtime_Build'Runtime ("Ada");
  • specify the Linker switches:
    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.

Multitasking

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.

Resources Used

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 > 1 in 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_ref to run at the reference clock speed, either XOSC or ROSC depending on the runtime configuration. clk_ref therefore runs at 12 MHz unless a different XOSC frequency is used.
  • The runtime configures clk_usb and clk_sys using the PLL settings specified by the user in the runtime configuration. The default configuration sets clk_usb to 48 MHz and clk_sys to 125 MHz.
  • The runtime sets clk_usb and clk_adc to run from pll_usb, and sets clk_rtc to run from pll_usb divided by 1024 (46.875 kHz).
  • The runtime configures the watchdog tick to run at 1 MHz.

Ada.Text_IO

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.

Runtime Configuration

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:

General Configuration

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 = 1

Clock Configuration

The 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

Board Configuration

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.

GPR Scenario Variables

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.
  • Debug disables optimization and adds debug symbols.
  • Assert enables assertions.
  • Gnatcov disables 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=Debug

or by setting them in your project's alire.toml:

[gpr-set-externals]
LIGHT_TASKING_RP2040_BUILD = "Debug"