@@ -182,6 +182,9 @@ extern "C" void loop1() __attribute__((weak));
182182extern " C" bool core1_separate_stack;
183183extern " C" uint32_t * core1_separate_stack_address;
184184
185+ /* *
186+ @brief RP2040/RP2350 helper function for HW-specific features
187+ */
185188class RP2040 {
186189public:
187190 RP2040 () { /* noop */ }
@@ -207,26 +210,50 @@ class RP2040 {
207210#endif
208211 }
209212
210- // Convert from microseconds to PIO clock cycles
213+ /* *
214+ @brief Convert from microseconds to PIO clock cycles
215+
216+ @returns the PIO cycles for a given microsecond delay
217+ */
211218 static int usToPIOCycles (int us) {
212219 // Parenthesis needed to guarantee order of operations to avoid 32bit overflow
213220 return (us * (clock_get_hz (clk_sys) / 1'000'000 ));
214221 }
215222
216- // Get current clock frequency
223+ /* *
224+ @brief Gets the active CPU speed (may differ from F_CPU
225+
226+ @returns CPU frequency in Hz
227+ */
217228 static int f_cpu () {
218229 return clock_get_hz (clk_sys);
219230 }
220231
221- // Get current CPU core number
232+ /* *
233+ @brief Get the core ID that is currently executing this code
234+
235+ @returns 0 for Core 0, 1 for Core 1
236+ */
222237 static int cpuid () {
223238 return sio_hw->cpuid ;
224239 }
225240
226- // Get CPU cycle count. Needs to do magic to extens 24b HW to something longer
241+ /* *
242+ @brief CPU cycle counter epoch (24-bit cycle). For internal use
243+ */
227244 volatile uint64_t _epoch = 0 ;
245+ /* *
246+ @brief Get the count of CPU clock cycles since power on.
247+
248+ @details
249+ The 32-bit count will overflow every 4 billion cycles, so consider using ``getCycleCount64`` for
250+ longer measurements
251+
252+ @returns CPU clock cycles since power up
253+ */
228254 inline uint32_t getCycleCount () {
229255#if !defined(__riscv) && !defined(__PROFILE)
256+ // Get CPU cycle count. Needs to do magic to extend 24b HW to something longer
230257 if (!__isFreeRTOS) {
231258 uint32_t epoch;
232259 uint32_t ctr;
@@ -242,7 +269,11 @@ class RP2040 {
242269 }
243270#endif
244271 }
272+ /* *
273+ @brief Get the count of CPU clock cycles since power on as a 64-bit quantrity
245274
275+ @returns CPU clock cycles since power up
276+ */
246277 inline uint64_t getCycleCount64 () {
247278#if !defined(__riscv) && !defined(__PROFILE)
248279 if (!__isFreeRTOS) {
@@ -261,23 +292,53 @@ class RP2040 {
261292#endif
262293 }
263294
295+ /* *
296+ @brief Gets total unused heap (dynamic memory)
297+
298+ @details
299+ Note that the allocations of the size of the total free heap may fail due to fragmentation.
300+ For example, ``getFreeHeap`` can report 100KB available, but an allocation of 90KB may fail
301+ because there may not be a contiguous 90KB space available
302+
303+ @returns Free heap in bytes
304+ */
264305 inline int getFreeHeap () {
265306 return getTotalHeap () - getUsedHeap ();
266307 }
267308
309+ /* *
310+ @brief Gets total used heap (dynamic memory)
311+
312+ @returns Used heap in bytes
313+ */
268314 inline int getUsedHeap () {
269315 struct mallinfo m = mallinfo ();
270316 return m.uordblks ;
271317 }
272318
319+ /* *
320+ @brief Gets total heap (dynamic memory) compiled into the program
321+
322+ @returns Total heap size in bytes
323+ */
273324 inline int getTotalHeap () {
274325 return &__StackLimit - &__bss_end__;
275326 }
276327
328+ /* *
329+ @brief On the RP2350, returns the amount of heap (dynamic memory) available in PSRAM
330+
331+ @returns Total free heap in PSRAM, or 0 if no PSRAM present
332+ */
277333 inline int getFreePSRAMHeap () {
278334 return getTotalPSRAMHeap () - getUsedPSRAMHeap ();
279335 }
280336
337+ /* *
338+ @brief On the RP2350, returns the total amount of PSRAM heap (dynamic memory) used
339+
340+ @returns Bytes used in PSRAM, or 0 if no PSRAM present
341+ */
281342 inline int getUsedPSRAMHeap () {
282343#if defined(RP2350_PSRAM_CS)
283344 extern size_t __psram_total_used ();
@@ -287,6 +348,11 @@ class RP2040 {
287348#endif
288349 }
289350
351+ /* *
352+ @brief On the RP2350, gets total heap (dynamic memory) compiled into the program
353+
354+ @returns Total PSRAM heap size in bytes, or 0 if no PSRAM present
355+ */
290356 inline int getTotalPSRAMHeap () {
291357#if defined(RP2350_PSRAM_CS)
292358 extern size_t __psram_total_space ();
@@ -296,6 +362,11 @@ class RP2040 {
296362#endif
297363 }
298364
365+ /* *
366+ @brief Gets the current stack pointer in a ARM/RISC-V safe manner
367+
368+ @returns Current SP
369+ */
299370 inline uint32_t getStackPointer () {
300371 uint32_t *sp;
301372#if defined(__riscv)
@@ -306,6 +377,14 @@ class RP2040 {
306377 return (uint32_t )sp;
307378 }
308379
380+ /* *
381+ @brief Calculates approximately how much stack space is still available for the running core. Handles multiprocessing and separate stacks.
382+
383+ @details
384+ Not valid in FreeRTOS. Use the FreeRTOS internal functions to access this information.
385+
386+ @returns Approximation of the amount of stack available for use on the specific core
387+ */
309388 inline int getFreeStack () {
310389 const unsigned int sp = getStackPointer ();
311390 uint32_t ref = 0x20040000 ;
@@ -319,6 +398,11 @@ class RP2040 {
319398 return sp - ref;
320399 }
321400
401+ /* *
402+ @brief On the RP2350, gets the size of attached PSRAM
403+
404+ @returns PSRAM size in bytes, or 0 if no PSRAM present
405+ */
322406 inline size_t getPSRAMSize () {
323407#if defined(RP2350_PSRAM_CS)
324408 extern size_t __psram_size;
@@ -328,31 +412,65 @@ class RP2040 {
328412#endif
329413 }
330414
415+ /* *
416+ @brief Freezes the other core in a flash-write-safe state. Not generally needed by applications
417+
418+ @details
419+ When the external flash chip is erasing or writing, the Pico cannot fetch instructions from it.
420+ In this case both the core doing the writing and the other core (if active) need to run from a
421+ routine that's contained in RAM. This call forces the other core into a tight, RAM-based loop
422+ safe for this operation. When flash erase/write is completed, ``resumeOtherCore`` to return
423+ it to operation.
424+
425+ Be sure to disable any interrupts or task switches before calling to avoid deadlocks.
426+
427+ If the second core is not started, this is a no-op.
428+ */
331429 void idleOtherCore () {
332430 fifo.idleOtherCore ();
333431 }
334432
433+ /* *
434+ @brief Resumes normal operation of the other core
435+ */
335436 void resumeOtherCore () {
336437 fifo.resumeOtherCore ();
337438 }
338439
440+ /* *
441+ @brief Hard resets the 2nd core (CORE1).
442+
443+ @details
444+ Because core1 will restart with the heap and global variables not in the same state as
445+ power-on, this call may not work as desired and a full CPU reset may be necessary in
446+ certain cases.
447+ */
339448 void restartCore1 () {
340449 multicore_reset_core1 ();
341450 fifo.clear ();
342451 multicore_launch_core1 (main1);
343452 }
344453
454+ /* *
455+ @brief Warm-reboots the chip in normal mode
456+ */
345457 void reboot () {
346458 watchdog_reboot (0 , 0 , 10 );
347459 while (1 ) {
348460 continue ;
349461 }
350462 }
351463
464+ /* *
465+ @brief Warm-reboots the chip in normal mode
466+ */
352467 inline void restart () {
353468 reboot ();
354469 }
355470
471+ /* *
472+ @brief Warm-reboots the chip into the USB bootloader mode
473+ */
356474 inline void rebootToBootloader () {
357475 reset_usb_boot (0 , 0 );
358476 while (1 ) {
@@ -364,16 +482,32 @@ class RP2040 {
364482 static void enableDoubleResetBootloader ();
365483#endif
366484
485+ /* *
486+ @brief Starts the hardware watchdog timer. The CPU will reset if the watchdog is not fed every delay_ms
487+
488+ @param [in] delay_ms Milliseconds without a wdt_reset before rebooting
489+ */
367490 void wdt_begin (uint32_t delay_ms) {
368491 watchdog_enable (delay_ms, 1 );
369492 }
370493
494+ /* *
495+ @brief Feeds the watchdog timer, resetting it for another delay_ms countdown
496+ */
371497 void wdt_reset () {
372498 watchdog_update ();
373499 }
374500
501+ /* *
502+ @brief Best-effort reasons for chip reset
503+ */
375504 enum resetReason_t {UNKNOWN_RESET, PWRON_RESET, RUN_PIN_RESET, SOFT_RESET, WDT_RESET, DEBUG_RESET, GLITCH_RESET, BROWNOUT_RESET};
376505
506+ /* *
507+ @brief Attempts to determine the reason for the last chip reset. May not always be able to determine accurately
508+
509+ @returns Reason for reset
510+ */
377511 resetReason_t getResetReason (void ) {
378512 io_rw_32 *WD_reason_reg = (io_rw_32 *)(WATCHDOG_BASE + WATCHDOG_REASON_OFFSET);
379513
@@ -427,6 +561,10 @@ class RP2040 {
427561 return UNKNOWN_RESET;
428562 }
429563
564+ /* *
565+ @brief Get unique ID string for the running board
566+ @returns String with the unique board ID as determined by the SDK
567+ */
430568 const char *getChipID () {
431569 static char id[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1 ] = { 0 };
432570 if (!id[0 ]) {
@@ -437,6 +575,17 @@ class RP2040 {
437575
438576#pragma GCC push_options
439577#pragma GCC optimize ("Os")
578+ /* *
579+ @brief Perform a memcpy using a DMA engine for speed
580+
581+ @details
582+ Uses the DMA to copy to and from RAM. Only works on 4-byte aligned, 4-byte multiple length
583+ sources and destination (i.e. word-aligned, word-length). Falls back to normal memcpy otherwise.
584+
585+ @param [out] dest Memcpy destination, 4-byte aligned
586+ @param [in] src Memcpy source, 4-byte aligned
587+ @param [in] n Count in bytes to transfer (should be a multiple of 4 bytes)
588+ */
440589 void *memcpyDMA (void *dest, const void *src, size_t n) {
441590 // Allocate a DMA channel on 1st call, reuse it every call after
442591 if (memcpyDMAChannel < 1 ) {
@@ -465,14 +614,32 @@ class RP2040 {
465614 }
466615#pragma GCC pop_options
467616
468- // Multicore comms FIFO
617+ /* *
618+ @brief Multicore communications FIFO
619+ */
469620 _MFIFO fifo;
470621
471622
623+ /* *
624+ @brief Return a 32-bit from the hardware random number generator
625+
626+ @returns Random value using appropriate hardware (RP2350 has true RNG, RP2040 has a less true RNG method)
627+ */
472628 uint32_t hwrand32 () {
473629 return get_rand_32 ();
474630 }
475631
632+ /* *
633+ @brief Determines if code is running on a Pico or a PicoW
634+
635+ @details
636+ Code compiled for the RP2040 PicoW can run on the RP2040 Pico. This call lets an application
637+ identify if the current device is really a Pico or PicoW and handle appropriately. For
638+ the RP2350, this runtime detection is not available and the call returns whether it was
639+ compiled for the CYW43 WiFi driver
640+
641+ @returns True if running on a PicoW board with CYW43 WiFi chip.
642+ */
476643 bool isPicoW () {
477644#if !defined(PICO_CYW43_SUPPORTED)
478645 return false ;
0 commit comments