Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

WIP: Add Doxygen documentation to core and libraries #2780

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions cores/rp2040/Bootsel.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,21 @@

#pragma once

/**
@brief Wrapper class for polling the BOOTSEL button
*/
class __Bootsel {
public:
__Bootsel() { }
/**
@brief Get state of the BOOTSEL pin

@returns True if BOOTSEL pushed
*/
operator bool();
};

/**
@brief BOOTSEL accessor instance
*/
extern __Bootsel BOOTSEL;
177 changes: 172 additions & 5 deletions cores/rp2040/RP2040Support.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ extern "C" void loop1() __attribute__((weak));
extern "C" bool core1_separate_stack;
extern "C" uint32_t* core1_separate_stack_address;

/**
@brief RP2040/RP2350 helper function for HW-specific features
*/
class RP2040 {
public:
RP2040() { /* noop */ }
Expand All @@ -207,26 +210,50 @@ class RP2040 {
#endif
}

// Convert from microseconds to PIO clock cycles
/**
@brief Convert from microseconds to PIO clock cycles

@returns the PIO cycles for a given microsecond delay
*/
static int usToPIOCycles(int us) {
// Parenthesis needed to guarantee order of operations to avoid 32bit overflow
return (us * (clock_get_hz(clk_sys) / 1'000'000));
}

// Get current clock frequency
/**
@brief Gets the active CPU speed (may differ from F_CPU

@returns CPU frequency in Hz
*/
static int f_cpu() {
return clock_get_hz(clk_sys);
}

// Get current CPU core number
/**
@brief Get the core ID that is currently executing this code

@returns 0 for Core 0, 1 for Core 1
*/
static int cpuid() {
return sio_hw->cpuid;
}

// Get CPU cycle count. Needs to do magic to extens 24b HW to something longer
/**
@brief CPU cycle counter epoch (24-bit cycle). For internal use
*/
volatile uint64_t _epoch = 0;
/**
@brief Get the count of CPU clock cycles since power on.

@details
The 32-bit count will overflow every 4 billion cycles, so consider using ``getCycleCount64`` for
longer measurements

@returns CPU clock cycles since power up
*/
inline uint32_t getCycleCount() {
#if !defined(__riscv) && !defined(__PROFILE)
// Get CPU cycle count. Needs to do magic to extend 24b HW to something longer
if (!__isFreeRTOS) {
uint32_t epoch;
uint32_t ctr;
Expand All @@ -242,7 +269,11 @@ class RP2040 {
}
#endif
}
/**
@brief Get the count of CPU clock cycles since power on as a 64-bit quantrity

@returns CPU clock cycles since power up
*/
inline uint64_t getCycleCount64() {
#if !defined(__riscv) && !defined(__PROFILE)
if (!__isFreeRTOS) {
Expand All @@ -261,23 +292,53 @@ class RP2040 {
#endif
}

/**
@brief Gets total unused heap (dynamic memory)

@details
Note that the allocations of the size of the total free heap may fail due to fragmentation.
For example, ``getFreeHeap`` can report 100KB available, but an allocation of 90KB may fail
because there may not be a contiguous 90KB space available

@returns Free heap in bytes
*/
inline int getFreeHeap() {
return getTotalHeap() - getUsedHeap();
}

/**
@brief Gets total used heap (dynamic memory)

@returns Used heap in bytes
*/
inline int getUsedHeap() {
struct mallinfo m = mallinfo();
return m.uordblks;
}

/**
@brief Gets total heap (dynamic memory) compiled into the program

@returns Total heap size in bytes
*/
inline int getTotalHeap() {
return &__StackLimit - &__bss_end__;
}

/**
@brief On the RP2350, returns the amount of heap (dynamic memory) available in PSRAM

@returns Total free heap in PSRAM, or 0 if no PSRAM present
*/
inline int getFreePSRAMHeap() {
return getTotalPSRAMHeap() - getUsedPSRAMHeap();
}

/**
@brief On the RP2350, returns the total amount of PSRAM heap (dynamic memory) used

@returns Bytes used in PSRAM, or 0 if no PSRAM present
*/
inline int getUsedPSRAMHeap() {
#if defined(RP2350_PSRAM_CS)
extern size_t __psram_total_used();
Expand All @@ -287,6 +348,11 @@ class RP2040 {
#endif
}

/**
@brief On the RP2350, gets total heap (dynamic memory) compiled into the program

@returns Total PSRAM heap size in bytes, or 0 if no PSRAM present
*/
inline int getTotalPSRAMHeap() {
#if defined(RP2350_PSRAM_CS)
extern size_t __psram_total_space();
Expand All @@ -296,6 +362,11 @@ class RP2040 {
#endif
}

/**
@brief Gets the current stack pointer in a ARM/RISC-V safe manner

@returns Current SP
*/
inline uint32_t getStackPointer() {
uint32_t *sp;
#if defined(__riscv)
Expand All @@ -306,6 +377,14 @@ class RP2040 {
return (uint32_t)sp;
}

/**
@brief Calculates approximately how much stack space is still available for the running core. Handles multiprocessing and separate stacks.

@details
Not valid in FreeRTOS. Use the FreeRTOS internal functions to access this information.

@returns Approximation of the amount of stack available for use on the specific core
*/
inline int getFreeStack() {
const unsigned int sp = getStackPointer();
uint32_t ref = 0x20040000;
Expand All @@ -319,6 +398,11 @@ class RP2040 {
return sp - ref;
}

/**
@brief On the RP2350, gets the size of attached PSRAM

@returns PSRAM size in bytes, or 0 if no PSRAM present
*/
inline size_t getPSRAMSize() {
#if defined(RP2350_PSRAM_CS)
extern size_t __psram_size;
Expand All @@ -328,31 +412,65 @@ class RP2040 {
#endif
}

/**
@brief Freezes the other core in a flash-write-safe state. Not generally needed by applications

@details
When the external flash chip is erasing or writing, the Pico cannot fetch instructions from it.
In this case both the core doing the writing and the other core (if active) need to run from a
routine that's contained in RAM. This call forces the other core into a tight, RAM-based loop
safe for this operation. When flash erase/write is completed, ``resumeOtherCore`` to return
it to operation.

Be sure to disable any interrupts or task switches before calling to avoid deadlocks.

If the second core is not started, this is a no-op.
*/
void idleOtherCore() {
fifo.idleOtherCore();
}

/**
@brief Resumes normal operation of the other core
*/
void resumeOtherCore() {
fifo.resumeOtherCore();
}

/**
@brief Hard resets the 2nd core (CORE1).

@details
Because core1 will restart with the heap and global variables not in the same state as
power-on, this call may not work as desired and a full CPU reset may be necessary in
certain cases.
*/
void restartCore1() {
multicore_reset_core1();
fifo.clear();
multicore_launch_core1(main1);
}

/**
@brief Warm-reboots the chip in normal mode
*/
void reboot() {
watchdog_reboot(0, 0, 10);
while (1) {
continue;
}
}

/**
@brief Warm-reboots the chip in normal mode
*/
inline void restart() {
reboot();
}

/**
@brief Warm-reboots the chip into the USB bootloader mode
*/
inline void rebootToBootloader() {
reset_usb_boot(0, 0);
while (1) {
Expand All @@ -364,16 +482,32 @@ class RP2040 {
static void enableDoubleResetBootloader();
#endif

/**
@brief Starts the hardware watchdog timer. The CPU will reset if the watchdog is not fed every delay_ms

@param [in] delay_ms Milliseconds without a wdt_reset before rebooting
*/
void wdt_begin(uint32_t delay_ms) {
watchdog_enable(delay_ms, 1);
}

/**
@brief Feeds the watchdog timer, resetting it for another delay_ms countdown
*/
void wdt_reset() {
watchdog_update();
}

/**
@brief Best-effort reasons for chip reset
*/
enum resetReason_t {UNKNOWN_RESET, PWRON_RESET, RUN_PIN_RESET, SOFT_RESET, WDT_RESET, DEBUG_RESET, GLITCH_RESET, BROWNOUT_RESET};

/**
@brief Attempts to determine the reason for the last chip reset. May not always be able to determine accurately

@returns Reason for reset
*/
resetReason_t getResetReason(void) {
io_rw_32 *WD_reason_reg = (io_rw_32 *)(WATCHDOG_BASE + WATCHDOG_REASON_OFFSET);

Expand Down Expand Up @@ -427,6 +561,10 @@ class RP2040 {
return UNKNOWN_RESET;
}

/**
@brief Get unique ID string for the running board
@returns String with the unique board ID as determined by the SDK
*/
const char *getChipID() {
static char id[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1] = { 0 };
if (!id[0]) {
Expand All @@ -437,6 +575,17 @@ class RP2040 {

#pragma GCC push_options
#pragma GCC optimize ("Os")
/**
@brief Perform a memcpy using a DMA engine for speed

@details
Uses the DMA to copy to and from RAM. Only works on 4-byte aligned, 4-byte multiple length
sources and destination (i.e. word-aligned, word-length). Falls back to normal memcpy otherwise.

@param [out] dest Memcpy destination, 4-byte aligned
@param [in] src Memcpy source, 4-byte aligned
@param [in] n Count in bytes to transfer (should be a multiple of 4 bytes)
*/
void *memcpyDMA(void *dest, const void *src, size_t n) {
// Allocate a DMA channel on 1st call, reuse it every call after
if (memcpyDMAChannel < 1) {
Expand Down Expand Up @@ -465,14 +614,32 @@ class RP2040 {
}
#pragma GCC pop_options

// Multicore comms FIFO
/**
@brief Multicore communications FIFO
*/
_MFIFO fifo;


/**
@brief Return a 32-bit from the hardware random number generator

@returns Random value using appropriate hardware (RP2350 has true RNG, RP2040 has a less true RNG method)
*/
uint32_t hwrand32() {
return get_rand_32();
}

/**
@brief Determines if code is running on a Pico or a PicoW

@details
Code compiled for the RP2040 PicoW can run on the RP2040 Pico. This call lets an application
identify if the current device is really a Pico or PicoW and handle appropriately. For
the RP2350, this runtime detection is not available and the call returns whether it was
compiled for the CYW43 WiFi driver

@returns True if running on a PicoW board with CYW43 WiFi chip.
*/
bool isPicoW() {
#if !defined(PICO_CYW43_SUPPORTED)
return false;
Expand Down
Loading