v2.0.0
Macros | Functions
pico_platform
Runtime Infrastructure

Macros and definitions (and functions when included by non assembly code) for the RP2 family device / architecture to provide a common abstraction over low level compiler / platform specifics. More...

## Macros
#define | __fast_mul(a, b)
| multiply two integer values using the fastest method possible More...
#define | __isr
| Marker for an interrupt handler. More...
#define | __force_inline __always_inline
| Attribute to force inlining of a function regardless of optimization level. More...
#define | count_of(a) (sizeof(a)/sizeof((a)[0]))
| Macro to determine the number of elements in an array.
#define | MAX(a, b) ((a)>(b)?(a):(b))
| Macro to return the maximum of two comparable values.
#define | MIN(a, b) ((b)>(a)?(a):(b))
| Macro to return the minimum of two comparable values.
#define | __check_type_compatible(type_a, type_b) static_assert(__builtin_types_compatible_p(type_a, type_b), __STRING(type_a) " is not compatible with " __STRING(type_b));
| Utility macro to assert two types are equivalent. More...
#define | __after_data(group) __attribute__((section(".after_data." group)))
| Section attribute macro for placement in RAM after the `.data` section. More...
#define | __scratch_x(group) __attribute__((section(".scratch_x." group)))
| Section attribute macro for placement not in flash (i.e in RAM) More...
#define | __scratch_y(group) __attribute__((section(".scratch_y." group)))
| Section attribute macro for placement in the SRAM bank 5 (known as "scratch Y") More...
#define | __uninitialized_ram(group) __attribute__((section(".uninitialized_data." #group))) group
| Section attribute macro for data that is to be left uninitialized. More...
#define | __in_flash(group) __attribute__((section(".flashdata." group)))
| Section attribute macro for placement in flash even in a COPY_TO_RAM binary. More...
#define | __no_inline_not_in_flash_func(func_name) __noinline __not_in_flash_func(func_name)
| Indicates a function should not be stored in flash. More...

## Functions
static __force_inline void | tight_loop_contents (void)
| No-op function for the body of tight loops. More...
static void | busy_wait_at_least_cycles (uint32_t minimum_cycles)
| Helper method to busy-wait for at least the given number of cycles. More...
static __force_inline void | __breakpoint (void)
| Execute a breakpoint instruction.
static __force_inline uint | get_core_num (void)
| Get the current core number. More...
static __force_inline uint | __get_current_exception (void)
| Get the current exception level on this core. More...
static __force_inline bool | pico_processor_state_is_nonsecure (void)
| Return true if executing in the NonSecure state (Arm-only) More...
uint8_t | rp2350_chip_version (void)
| Returns the RP2350 chip revision number. More...
static uint8_t | rp2040_chip_version (void)
| Returns the RP2040 chip revision number for compatibility. More...
static uint8_t | rp2040_rom_version (void)
| Returns the RP2040 rom version number. More...
static __force_inline int32_t | __mul_instruction (int32_t a, int32_t b)
| Multiply two integers using an assembly `MUL` instruction. More...
static __always_inline void | __compiler_memory_barrier (void)
| Ensure that the compiler does not move memory access across this method call. More...
void | panic_unsupported (void)
| Panics with the message "Unsupported". More...
void | panic (const char *fmt,...)
| Displays a panic message and halts execution. More...

## Detailed Description

Macros and definitions (and functions when included by non assembly code) for the RP2 family device / architecture to provide a common abstraction over low level compiler / platform specifics.

Macros and definitions (and functions when included by non assembly code) to adapt for different compilers.

Macros and definitions for accessing the CPU registers.

This header may be included by assembly code

## Macro Definition Documentation

## ◆ __after_data

#define __after_data | ( |  | group | ) | __attribute__((section(".after_data." group)))

Section attribute macro for placement in RAM after the `.data` section.

For example a 400 element `uint32_t` array placed after the .data section

    uint32_t __after_data("my_group_name") a_big_array[400];

The section attribute is `.after_data.<group>`

Parameters

  group | a string suffix to use in the section name to distinguish groups that can be linker garbage-collected independently

## ◆ __check_type_compatible

#define __check_type_compatible | ( |  | type_a,
|  |  | type_b
| ) |  | static_assert(__builtin_types_compatible_p(type_a, type_b), __STRING(type_a) " is not compatible with " __STRING(type_b));

Utility macro to assert two types are equivalent.

This macro can be useful in other macros along with `typeof` to assert that two parameters are of equivalent type (or that a single parameter is of an expected type)

## ◆ __fast_mul

#define __fast_mul | ( |  | a,
|  |  | b
| ) |  |

Value:
__builtin_choose_expr(__builtin_constant_p(b) && !__builtin_constant_p(a), \
(__builtin_popcount(b) >= 2 ? __mul_instruction(a,b) : (a)*(b)), \
(a)*(b))
__mul_instruction
static __force_inline int32_t __mul_instruction(int32_t a, int32_t b)
Multiply two integers using an assembly MUL instruction.
Definition: platform.h:247

multiply two integer values using the fastest method possible

Efficiently multiplies value a by possibly constant value b.

If b is known to be constant and not zero or a power of 2, then a mul instruction is used rather than gcc's default which is often a slow combination of shifts and adds. If b is a power of 2 then a single shift is of course preferable and will be used

Parameters

  a | the first operand
  b | the second operand

Returns
  a * b

## ◆ __force_inline

#define __force_inline __always_inline

Attribute to force inlining of a function regardless of optimization level.

For example my_function here will always be inlined:

    int __force_inline my_function(int x) {

## ◆ __in_flash

#define __in_flash | ( |  | group | ) | __attribute__((section(".flashdata." group)))

Section attribute macro for placement in flash even in a COPY_TO_RAM binary.

For example a `uint32_t` variable explicitly placed in flash (it will hard fault if you attempt to write it!)

    uint32_t __in_flash("my_group_name") foo = 23;

The section attribute is `.flashdata.<group>`

Parameters

  group | a string suffix to use in the section name to distinguish groups that can be linker garbage-collected independently

## ◆ __isr

#define __isr | ( |  | void | ) |

Marker for an interrupt handler.

For example an IRQ handler function called my_interrupt_handler:

    void __isr my_interrupt_handler(void) {

## ◆ __no_inline_not_in_flash_func

#define __no_inline_not_in_flash_func | ( |  | func_name | ) | __noinline __not_in_flash_func(func_name)

Indicates a function should not be stored in flash.

Decorates a function name, such that the function will execute from RAM (assuming it is not inlined into a flash function by the compiler)

For example a function called my_func taking an int parameter:

    void __not_in_flash_func(my_func)(int some_arg) {

The function is placed in the `.time_critical.<func_name>` linker section

See also
  __no_inline_not_in_flash_func

Indicates a function is time/latency critical and should not run from flash

Decorates a function name, such that the function will execute from RAM (assuming it is not inlined into a flash function by the compiler) to avoid possible flash latency. Currently this macro is identical in implementation to `__not_in_flash_func`, however the semantics are distinct and a `__time_critical_func` may in the future be treated more specially to reduce the overhead when calling such function from a flash function.

For example a function called my_func taking an int parameter:

    void __time_critical(my_func)(int some_arg) {

The function is placed in the `.time_critical.<func_name>` linker section

See also
  __not_in_flash_func

Indicate a function should not be stored in flash and should not be inlined

Decorates a function name, such that the function will execute from RAM, explicitly marking it as noinline to prevent it being inlined into a flash function by the compiler

For example a function called my_func taking an int parameter:

    void __no_inline_not_in_flash_func(my_func)(int some_arg) {

The function is placed in the `.time_critical.<func_name>` linker section

## ◆ __scratch_x

#define __scratch_x | ( |  | group | ) | __attribute__((section(".scratch_x." group)))

Section attribute macro for placement not in flash (i.e in RAM)

For example a 3 element `uint32_t` array placed in RAM (even though it is `static const`)

    static const uint32_t __not_in_flash("my_group_name") an_array[3];

The section attribute is `.time_critical.<group>`

Parameters

  group | a string suffix to use in the section name to distinguish groups that can be linker garbage-collected independently

Section attribute macro for placement in the SRAM bank 4 (known as "scratch X")

Scratch X is commonly used for critical data and functions accessed only by one core (when only one core is accessing the RAM bank, there is no opportunity for stalls)

For example a `uint32_t` variable placed in "scratch X"

    uint32_t __scratch_x("my_group_name") foo = 23;

The section attribute is `.scratch_x.<group>`

Parameters

  group | a string suffix to use in the section name to distinguish groups that can be linker garbage-collected independently

## ◆ __scratch_y

#define __scratch_y | ( |  | group | ) | __attribute__((section(".scratch_y." group)))

Section attribute macro for placement in the SRAM bank 5 (known as "scratch Y")

Scratch Y is commonly used for critical data and functions accessed only by one core (when only one core is accessing the RAM bank, there is no opportunity for stalls)

For example a `uint32_t` variable placed in "scratch Y"

    uint32_t __scratch_y("my_group_name") foo = 23;

The section attribute is `.scratch_y.<group>`

Parameters

  group | a string suffix to use in the section name to distinguish groups that can be linker garbage-collected independently

## ◆ __uninitialized_ram

#define __uninitialized_ram | ( |  | group | ) | __attribute__((section(".uninitialized_data." #group))) group

Section attribute macro for data that is to be left uninitialized.

Data marked this way will retain its value across a reset (normally uninitialized data - in the .bss section) is initialized to zero during runtime initialization

For example a `uint32_t` foo that will retain its value if the program is restarted by reset.

    uint32_t __uninitialized_ram(foo);

The section attribute is `.uninitialized_data.<group>`

Parameters

  group | a string suffix to use in the section name to distinguish groups that can be linker garbage-collected independently

## Function Documentation

## ◆ __compiler_memory_barrier()

static __always_inline void __compiler_memory_barrier | ( | void |  | ) |
| static

Ensure that the compiler does not move memory access across this method call.

For example in the following code:

    *some_memory_location = var_a;
    __compiler_memory_barrier();
    uint32_t var_b = *some_other_memory_location

The compiler will not move the load from `some_other_memory_location` above the memory barrier (which it otherwise might - even above the memory store!)

## ◆ __get_current_exception()

static __force_inline uint __get_current_exception | ( | void |  | ) |
| static

Get the current exception level on this core.

On Cortex-M this is the exception number defined in the architecture reference, which is equal to VTABLE_FIRST_IRQ + irq num if inside an interrupt handler. (VTABLE_FIRST_IRQ is defined in platform_defs.h).

On Hazard3, this function returns VTABLE_FIRST_IRQ + irq num if inside of an external IRQ handler (or a fault from such a handler), and 0 otherwise, generally aligning with the Cortex-M values.

Returns
  the exception number if the CPU is handling an exception, or 0 otherwise

## ◆ __mul_instruction()

static __force_inline int32_t __mul_instruction | ( | int32_t | a,
|  | int32_t | b
| ) |  |
| static

Multiply two integers using an assembly `MUL` instruction.

This multiplies a by b using multiply instruction using the ARM mul instruction regardless of values (the compiler might otherwise choose to perform shifts/adds), i.e. this is a 1 cycle operation.

Parameters

  a | the first operand
  b | the second operand

Returns
  a * b

## ◆ busy_wait_at_least_cycles()

static void busy_wait_at_least_cycles | ( | uint32_t | minimum_cycles | ) |
| inlinestatic

Helper method to busy-wait for at least the given number of cycles.

This method is useful for introducing very short delays.

This method busy-waits in a tight loop for the given number of system clock cycles. The total wait time is only accurate to within 2 cycles, and this method uses a loop counter rather than a hardware timer, so the method will always take longer than expected if an interrupt is handled on the calling core during the busy-wait; you can of course disable interrupts to prevent this.

You can use clock_get_hz(clk_sys) to determine the number of clock cycles per second if you want to convert an actual time duration to a number of cycles.

Parameters

  minimum_cycles | the minimum number of system clock cycles to delay for

## ◆ get_core_num()

static __force_inline uint get_core_num | ( | void |  | ) |
| static

Get the current core number.

Returns
  The core number the call was made from

## ◆ panic()

void panic | ( | const char * | fmt,
|  |  | ...
| ) |  |

Displays a panic message and halts execution.

An attempt is made to output the message to all registered STDOUT drivers after which this method executes a BKPT instruction.

Parameters

  fmt | format string (printf-like)
  ... | printf-like arguments

## ◆ panic_unsupported()

void panic_unsupported | ( | void |  | ) |

Panics with the message "Unsupported".

See also
  panic

## ◆ pico_processor_state_is_nonsecure()

static __force_inline bool pico_processor_state_is_nonsecure | ( | void |  | ) |
| static

Return true if executing in the NonSecure state (Arm-only)

Returns
  True if currently executing in the NonSecure state on an Arm processor

## ◆ rp2040_chip_version()

static uint8_t rp2040_chip_version | ( | void |  | ) |
| inlinestatic

Returns the RP2040 chip revision number for compatibility.

Returns
  2 RP2040 errata fixed in B2 are fixed in RP2350

## ◆ rp2040_rom_version()

static uint8_t rp2040_rom_version | ( | void |  | ) |
| inlinestatic

Returns the RP2040 rom version number.

Returns
  the RP2040 rom version number (1 for RP2040-B0, 2 for RP2040-B1, 3 for RP2040-B2)

## ◆ rp2350_chip_version()

uint8_t rp2350_chip_version | ( | void |  | ) |

Returns the RP2350 chip revision number.

Returns
  the RP2350 chip revision number (1 for B0/B1, 2 for B2)

## ◆ tight_loop_contents()

static __force_inline void tight_loop_contents | ( | void |  | ) |
| static

No-op function for the body of tight loops.

No-op function intended to be called by any tight hardware polling loop. Using this ubiquitously makes it much easier to find tight loops, but also in the future #ifdef-ed support for lockup debugging might be added