1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-16 04:45:24 +03:00

Adding RP2350 SDK and target framework (#13988)

* Adding RP2350 SDK and target framework

* Spacing

* Removing board definitions
This commit is contained in:
J Blackman 2024-10-23 10:02:48 +11:00 committed by GitHub
parent 462cb05930
commit 2dd6f95aad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
576 changed files with 435012 additions and 0 deletions

View file

@ -0,0 +1,220 @@
/*
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "pico/flash.h"
#include "hardware/sync.h"
#if PICO_FLASH_SAFE_EXECUTE_PICO_SUPPORT_MULTICORE_LOCKOUT
#include "pico/multicore.h"
#endif
#if PICO_FLASH_SAFE_EXECUTE_SUPPORT_FREERTOS_SMP
#include "FreeRTOS.h"
#include "task.h"
// now we have FreeRTOS header we can check core count... we can only use FreeRTOS SMP mechanism
// with two cores
#if configNUMBER_OF_CORES == 2
#if configUSE_CORE_AFFINITY
#define PICO_FLASH_SAFE_EXECUTE_USE_FREERTOS_SMP 1
#else
#error configUSE_CORE_AFFINITY is required for PICO_FLASH_SAFE_EXECUTE_SUPPORT_FREERTOS_SMP
#endif
#endif
#endif
// There are multiple scenarios:
//
// 1. No use of core 1 - we just want to disable IRQs and not wait on core 1 to acquiesce
// 2. Regular pico_multicore - we need to use multicore lockout.
// 3. FreeRTOS on core 0, no use of core 1 - we just want to disable IRQs
// 4. FreeRTOS SMP on both cores - we need to schedule a high priority task on the other core to disable IRQs.
// 5. FreeRTOS on one core, but application is using the other core. ** WE CANNOT SUPPORT THIS TODAY ** without
// the equivalent PICO_FLASH_ASSUME_COREx_SAFE (i.e. the user making sure the other core is fine)
static bool default_core_init_deinit(bool init);
static int default_enter_safe_zone_timeout_ms(uint32_t timeout_ms);
static int default_exit_safe_zone_timeout_ms(uint32_t timeout_ms);
// note the default methods are combined, rather than having a separate helper for
// FreeRTOS, as we may support mixed multicore and non SMP FreeRTOS in the future
static flash_safety_helper_t default_flash_safety_helper = {
.core_init_deinit = default_core_init_deinit,
.enter_safe_zone_timeout_ms = default_enter_safe_zone_timeout_ms,
.exit_safe_zone_timeout_ms = default_exit_safe_zone_timeout_ms
};
#if PICO_FLASH_SAFE_EXECUTE_USE_FREERTOS_SMP
enum {
FREERTOS_LOCKOUT_NONE = 0,
FREERTOS_LOCKOUT_LOCKER_WAITING,
FREERTOS_LOCKOUT_LOCKEE_READY,
FREERTOS_LOCKOUT_LOCKER_DONE,
FREERTOS_LOCKOUT_LOCKEE_DONE,
};
// state for the lockout operation launched from the corresponding core
static volatile uint8_t lockout_state[NUM_CORES];
#endif
__attribute__((weak)) flash_safety_helper_t *get_flash_safety_helper(void) {
return &default_flash_safety_helper;
}
bool flash_safe_execute_core_init(void) {
flash_safety_helper_t *helper = get_flash_safety_helper();
return helper ? helper->core_init_deinit(true) : false;
}
bool flash_safe_execute_core_deinit(void) {
flash_safety_helper_t *helper = get_flash_safety_helper();
return helper ? helper->core_init_deinit(false) : false;
}
int flash_safe_execute(void (*func)(void *), void *param, uint32_t enter_exit_timeout_ms) {
flash_safety_helper_t *helper = get_flash_safety_helper();
if (!helper) return PICO_ERROR_NOT_PERMITTED;
int rc = helper->enter_safe_zone_timeout_ms(enter_exit_timeout_ms);
if (!rc) {
func(param);
rc = helper->exit_safe_zone_timeout_ms(enter_exit_timeout_ms);
}
return rc;
}
static bool default_core_init_deinit(__unused bool init) {
#if PICO_FLASH_ASSUME_CORE0_SAFE
if (!get_core_num()) return true;
#endif
#if PICO_FLASH_ASSUME_CORE1_SAFE
if (get_core_num()) return true;
#endif
#if PICO_FLASH_SAFE_EXECUTE_USE_FREERTOS_SMP
return true;
#endif
#if PICO_FLASH_SAFE_EXECUTE_PICO_SUPPORT_MULTICORE_LOCKOUT
if (!init) {
return false;
}
multicore_lockout_victim_init();
#endif
return true;
}
// irq_state for the lockout operation launched from the corresponding core
static uint32_t irq_state[NUM_CORES];
static bool use_irq_only(void) {
#if PICO_FLASH_ASSUME_CORE0_SAFE
if (get_core_num()) return true;
#endif
#if PICO_FLASH_ASSUME_CORE1_SAFE
if (!get_core_num()) return true;
#endif
return false;
}
#if PICO_FLASH_SAFE_EXECUTE_USE_FREERTOS_SMP
static void __not_in_flash_func(flash_lockout_task)(__unused void *vother_core_num) {
uint other_core_num = (uintptr_t)vother_core_num;
while (lockout_state[other_core_num] != FREERTOS_LOCKOUT_LOCKER_WAITING) {
__wfe(); // we don't bother to try to let lower priority tasks run
}
uint32_t save = save_and_disable_interrupts();
lockout_state[other_core_num] = FREERTOS_LOCKOUT_LOCKEE_READY;
__sev();
while (lockout_state[other_core_num] == FREERTOS_LOCKOUT_LOCKEE_READY) {
__wfe(); // we don't bother to try to let lower priority tasks run
}
restore_interrupts(save);
lockout_state[other_core_num] = FREERTOS_LOCKOUT_LOCKEE_DONE;
__sev();
// bye bye
vTaskDelete(NULL);
}
#endif
static int default_enter_safe_zone_timeout_ms(__unused uint32_t timeout_ms) {
int rc = PICO_OK;
if (!use_irq_only()) {
#if PICO_FLASH_SAFE_EXECUTE_USE_FREERTOS_SMP
// Note that whilst taskENTER_CRITICAL sounds promising (and on non SMP it disabled IRQs), on SMP
// it only prevents the other core from also entering a critical section.
// Therefore, we must do our own handshake which starts a task on the other core and have it disable interrupts
uint core_num = get_core_num();
// create at low priority
TaskHandle_t task_handle;
if (pdPASS != xTaskCreate(flash_lockout_task, "flash lockout", configMINIMAL_STACK_SIZE, (void *)core_num, 0, &task_handle)) {
return PICO_ERROR_INSUFFICIENT_RESOURCES;
}
lockout_state[core_num] = FREERTOS_LOCKOUT_LOCKER_WAITING;
__sev();
// bind to other core
vTaskCoreAffinitySet(task_handle, 1u << (core_num ^ 1));
// and make it super high priority
vTaskPrioritySet(task_handle, configMAX_PRIORITIES -1);
absolute_time_t until = make_timeout_time_ms(timeout_ms);
while (lockout_state[core_num] != FREERTOS_LOCKOUT_LOCKEE_READY && !time_reached(until)) {
__wfe(); // we don't bother to try to let lower priority tasks run
}
if (lockout_state[core_num] != FREERTOS_LOCKOUT_LOCKEE_READY) {
lockout_state[core_num] = FREERTOS_LOCKOUT_LOCKER_DONE;
rc = PICO_ERROR_TIMEOUT;
}
// todo we may get preempted here, but I think that is OK unless what is pre-empts requires
// the other core to be running.
#elif PICO_FLASH_SAFE_EXECUTE_PICO_SUPPORT_MULTICORE_LOCKOUT
// we cannot mix multicore_lockout and FreeRTOS as they both use the multicore FIFO...
// the user, will have to roll their own mechanism in this case.
#if LIB_FREERTOS_KERNEL
#if PICO_FLASH_ASSERT_ON_UNSAFE
assert(false); // we expect the other core to have been initialized via flash_safe_execute_core_init()
// unless PICO_FLASH_ASSUME_COREX_SAFE is set
#endif
rc = PICO_ERROR_NOT_PERMITTED;
#else // !LIB_FREERTOS_KERNEL
if (multicore_lockout_victim_is_initialized(get_core_num()^1)) {
if (!multicore_lockout_start_timeout_us(timeout_ms * 1000ull)) {
rc = PICO_ERROR_TIMEOUT;
}
} else {
#if PICO_FLASH_ASSERT_ON_UNSAFE
assert(false); // we expect the other core to have been initialized via flash_safe_execute_core_init()
// unless PICO_FLASH_ASSUME_COREX_SAFE is set
#endif
rc = PICO_ERROR_NOT_PERMITTED;
}
#endif // !LIB_FREERTOS_KERNEL
#else
// no support for making other core safe provided, so fall through to irq
// note this is the case for a regular single core program
#endif
}
if (rc == PICO_OK) {
// we always want to disable IRQs on our core
irq_state[get_core_num()] = save_and_disable_interrupts();
}
return rc;
}
static int default_exit_safe_zone_timeout_ms(__unused uint32_t timeout_ms) {
// assume if we're exiting we're called then entry happened successfully
restore_interrupts_from_disabled(irq_state[get_core_num()]);
if (!use_irq_only()) {
#if PICO_FLASH_SAFE_EXECUTE_USE_FREERTOS_SMP
uint core_num = get_core_num();
lockout_state[core_num] = FREERTOS_LOCKOUT_LOCKER_DONE;
__sev();
absolute_time_t until = make_timeout_time_ms(timeout_ms);
while (lockout_state[core_num] != FREERTOS_LOCKOUT_LOCKEE_DONE && !time_reached(until)) {
__wfe(); // we don't bother to try to let lower priority tasks run
}
if (lockout_state[core_num] != FREERTOS_LOCKOUT_LOCKEE_DONE) {
return PICO_ERROR_TIMEOUT;
}
#elif PICO_FLASH_SAFE_EXECUTE_PICO_SUPPORT_MULTICORE_LOCKOUT
return multicore_lockout_end_timeout_us(timeout_ms * 1000ull) ? PICO_OK : PICO_ERROR_TIMEOUT;
#endif
}
return PICO_OK;
}

View file

@ -0,0 +1,139 @@
/*
* Copyright (c) 2023 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef _PICO_FLASH_H
#define _PICO_FLASH_H
#include "pico.h"
/** \file pico/flash.h
* \defgroup pico_flash pico_flash
*
* \brief High level flash API
*
* Flash cannot be erased or written to when in XIP mode. However the system cannot directly access memory in the flash
* address space when not in XIP mode.
*
* It is therefore critical that no code or data is being read from flash while flash is been written or erased.
*
* If only one core is being used, then the problem is simple - just disable interrupts; however if code is running on
* the other core, then it has to be asked, nicely, to avoid flash for a bit. This is hard to do if you don't have
* complete control of the code running on that core at all times.
*
* This library provides a \ref flash_safe_execute method which calls a function back having successfully gotten
* into a state where interrupts are disabled, and the other core is not executing or reading from flash.
*
* How it does this is dependent on the supported environment (Free RTOS SMP or pico_multicore). Additionally
* the user can provide their own mechanism by providing a strong definition of \ref get_flash_safety_helper().
*
* Using the default settings, flash_safe_execute will only call the callback function if the state is safe
* otherwise returning an error (or an assert depending on \ref PICO_FLASH_ASSERT_ON_UNSAFE).
*
* There are conditions where safety would not be guaranteed:
*
* 1. FreeRTOS smp with `configNUM_CORES=1` - FreeRTOS still uses pico_multicore in this case, so \ref flash_safe_execute
* cannot know what the other core is doing, and there is no way to force code execution between a FreeRTOS core
* and a non FreeRTOS core.
* 2. FreeRTOS non SMP with pico_multicore - Again, there is no way to force code execution between a FreeRTOS core and
* a non FreeRTOS core.
* 3. pico_multicore without \ref flash_safe_execute_core_init() having been called on the other core - The
* \ref flash_safe_execute method does not know if code is executing on the other core, so it has to assume it is. Either
* way, it is not able to intervene if \ref flash_safe_execute_core_init() has not been called on the other core.
*
* Fortunately, all is not lost in this situation, you may:
*
* * Set \ref PICO_FLASH_ASSUME_CORE0_SAFE=1 to explicitly say that core 0 is never using flash.
* * Set \ref PICO_FLASH_ASSUME_CORE1_SAFE=1 to explicitly say that core 1 is never using flash.
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Initialize a core such that the other core can lock it out during \ref flash_safe_execute.
* \ingroup pico_flash
*
* \note This is not necessary for FreeRTOS SMP, but should be used when launching via \ref multicore_launch_core1
* \return true on success; there is no need to call \ref flash_safe_execute_core_deinit() on failure.
*/
bool flash_safe_execute_core_init(void);
/**
* \brief De-initialize work done by \ref flash_safe_execute_core_init
* \ingroup pico_flash
* \return true on success
*/
bool flash_safe_execute_core_deinit(void);
/**
* \brief Execute a function with IRQs disabled and with the other core also not executing/reading flash
* \ingroup pico_flash
*
* \param func the function to call
* \param param the parameter to pass to the function
* \param enter_exit_timeout_ms the timeout for each of the enter/exit phases when coordinating with the other core
*
* \return PICO_OK on success (the function will have been called).
* PICO_ERROR_TIMEOUT on timeout (the function may have been called).
* PICO_ERROR_NOT_PERMITTED if safe execution is not possible (the function will not have been called).
* PICO_ERROR_INSUFFICIENT_RESOURCES if the method fails due to dynamic resource exhaustion (the function will not have been called)
* \note if \ref PICO_FLASH_ASSERT_ON_UNSAFE is 1, this function will assert in debug mode vs returning
* PICO_ERROR_NOT_PERMITTED
*/
int flash_safe_execute(void (*func)(void *), void *param, uint32_t enter_exit_timeout_ms);
// PICO_CONFIG: PICO_FLASH_ASSERT_ON_UNSAFE, Assert in debug mode rather than returning an error if flash_safe_execute cannot guarantee safety to catch bugs early, type=bool, default=1, group=pico_flash
#ifndef PICO_FLASH_ASSERT_ON_UNSAFE
#define PICO_FLASH_ASSERT_ON_UNSAFE 1
#endif
// PICO_CONFIG: PICO_FLASH_ASSUME_CORE0_SAFE, Assume that core 0 will never be accessing flash and so doesn't need to be considered during flash_safe_execute, type=bool, default=0, group=pico_flash
#ifndef PICO_FLASH_ASSUME_CORE0_SAFE
#define PICO_FLASH_ASSUME_CORE0_SAFE 0
#endif
// PICO_CONFIG: PICO_FLASH_ASSUME_CORE1_SAFE, Assume that core 1 will never be accessing flash and so doesn't need to be considered during flash_safe_execute, type=bool, default=0, group=pico_flash
#ifndef PICO_FLASH_ASSUME_CORE1_SAFE
#define PICO_FLASH_ASSUME_CORE1_SAFE 0
#endif
// PICO_CONFIG: PICO_FLASH_SAFE_EXECUTE_SUPPORT_FREERTOS_SMP, Support using FreeRTOS SMP to make the other core safe during flash_safe_execute, type=bool, default=1 when using FreeRTOS SMP, group=pico_flash
#ifndef PICO_FLASH_SAFE_EXECUTE_SUPPORT_FREERTOS_SMP
#if LIB_FREERTOS_KERNEL && FREE_RTOS_KERNEL_SMP // set by RP2040 SMP port
#define PICO_FLASH_SAFE_EXECUTE_SUPPORT_FREERTOS_SMP 1
#endif
#endif
// PICO_CONFIG: PICO_FLASH_SAFE_EXECUTE_PICO_SUPPORT_MULTICORE_LOCKOUT, Support using multicore_lockout functions to make the other core safe during flash_safe_execute, type=bool, default=1 when using pico_multicore, group=pico_flash
#ifndef PICO_FLASH_SAFE_EXECUTE_PICO_SUPPORT_MULTICORE_LOCKOUT
#if LIB_PICO_MULTICORE
#define PICO_FLASH_SAFE_EXECUTE_PICO_SUPPORT_MULTICORE_LOCKOUT 1
#endif
#endif
typedef struct {
bool (*core_init_deinit)(bool init);
int (*enter_safe_zone_timeout_ms)(uint32_t timeout_ms);
int (*exit_safe_zone_timeout_ms)(uint32_t timeout_ms);
} flash_safety_helper_t;
/**
* \brief Internal method to return the flash safety helper implementation.
* \ingroup pico_flash
*
* Advanced users can provide their own implementation of this function to perform
* different inter-core coordination before disabling XIP mode.
*
* @return the \ref flash_safety_helper_t
*/
flash_safety_helper_t *get_flash_safety_helper(void);
#ifdef __cplusplus
}
#endif
#endif