ANN: Bareboard tasking runtimes for the RP2350 (Raspberry Pi Pico 2)

I finally got my hands on a Pico 2, so I’ve been able to release runtime crates for the RP2350. The new crates are:

Like the RP2040 crates I announced previously, these crates are also configurable through crate configuration variable. See the readmes on the GitHub page for more info on configuring them (in particular, README-RP2350.md)

For the moment the runtimes only support the Cortex-M33 cores. I might explore the RISC-V cores later if there’s demand for it.

6 Likes

Hi,

Thanks for your work. That’s very useful.

I don’t really understand the difference between both runtimes. It seems to be tasking related. But what are these differences ?

“light tasking” and “embedded” are two pre-defined runtime profiles for GNAT, which provide different levels of language support. For bareboard targets, there are generally three different profiles that can be supported:

  • “light” runtimes are the smallest runtimes but lack support for some Ada features. In particular, they don’t support tasking or exception propagation, and have a simple heap allocator (Unchecked_Deallocate is a no-op). They do, however, provide support for things like assertions, ’Image and ’Value attributes for scalar types, simplified Ada.Text_IO, secondary stack.
  • “light-tasking” runtimes include everything in “light”, but also add support for a tasking subset based on the Ravenscar and Jorvik profiles. For these RP2350 runtimes, this means you can declare multiple tasks and assign them to either of the two Cortex-M33 cores. For example, task My_Task with CPU => 2; declares a task that will run on the second core of the RP2350. You can also use Ada’s delay until statement for task delays, and use protected objects for inter-task communication and for interrupt handlers.
  • “embedded” runtimes include everything in “light-tasking”, but also adds support for exception propagation and has a full heap allocator (so you can use Unchecked_Deallocate to free memory).

For more information on what’s supported in each runtime, see this part of the GNAT User’s Guide Supplement for Cross Platforms: 5. Predefined GNAT Pro Run-Times — GNAT User's Guide Supplement for Cross Platforms 27.0w documentation

I hope this helps. Happy to answer any more questions if something isn’t clear.

Thanks for your answer.

Reading the GNAT documentation didn’t enlighten me on the differences between light-tasking and embedded runtimes.

Just to be sure, no profile allows a timeout in a task select. Right ?
Something like this :

   select
      data := GetData();
      Put_Line(data);
   or
      delay 1.0;
      Put_Line("timeout");
   end select;


That’s right. select statements are not allowed since only a subset of the tasking features are supported (Jorvik profile). You can read a bit more about the tasking restrictions for Ravenscar and Jorvik here: The Ravenscar and Jorvik Profiles

Thanks for your answer.

No Timeout… a significant limitation.

Nice.

How does this compare to:

?

No Timeout… a significant limitation.

Indeed, but there are other ways to achieve timeouts that fit within the restrictions of the Jorvik profile. For example, both the light-tasking and embedded runtimes have package Ada.Real_Time.Timing_Events which can be used to notify a protected object when a timeout has passed.

There’s also the Guide for the use of Ada Ravenscar Profile in high integrity systems technical report which has various examples of using the Ravenscar profile. Note that Ravenscar is a subset of Jorvik, so anything you can do within the Ravenscar profile you can also do within the Jorvik profile.

How does this compare to:

rp2040_hal and the runtime crates have different purposes, but complement each other. The purpose of the runtime is to implement the semantics of the Ada language needed at run-time. For example, when you use the ‘Image attribute, a call is made to the runtime to generate the string representation of the object. Similarly, when you declare a task, the runtime takes care of setting up and managing the execution of that task.

As mentioned above, there are different profiles available so you can choose which level of language support you want. The embedded profile provides the most language support for bare-metal targets like the RP2350, but it is also the largest and uses the most memory (code space, RAM). The light-tasking runtime is smaller and uses less resources, but also doesn’t provide some language features like exception propagation.

The goal of rp2040_hal on the other hand is to provide a nice API to access the various peripherals on the RP2040 chip (GPIO, SPI, DMA, etc).

Simply put: the runtime implements the dynamic semantics of the Ada language, and rp2040_hal provides access to the RP2040 peripherals.

To build a real application for the RP2040 you would need both a runtime (either a very minimal one like light-cortex-m0p, or a more featureful one like light_tasking_rp2040), plus rp2040_hal to be able to configure and use the peripherals.

Yes, I know. I studied all this few years ago. At that time Jorvik profile was still not official. I was wondering if it evolved on this aspect since then.

I think a full profile, or at least a much less restrictive profile, would be very useful in embedded world. I know the reasons of such restrictive profiles. Not every project needs to be provable. Not all projects use a microcontroller with very limited resources.

Thanks!!! Highly appreciated.

1 Like