@@ -182,6 +182,9 @@ extern "C" void loop1() __attribute__((weak));
182
182
extern " C" bool core1_separate_stack;
183
183
extern " C" uint32_t * core1_separate_stack_address;
184
184
185
+ /* *
186
+ @brief RP2040/RP2350 helper function for HW-specific features
187
+ */
185
188
class RP2040 {
186
189
public:
187
190
RP2040 () { /* noop */ }
@@ -207,26 +210,50 @@ class RP2040 {
207
210
#endif
208
211
}
209
212
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
+ */
211
218
static int usToPIOCycles (int us) {
212
219
// Parenthesis needed to guarantee order of operations to avoid 32bit overflow
213
220
return (us * (clock_get_hz (clk_sys) / 1'000'000 ));
214
221
}
215
222
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
+ */
217
228
static int f_cpu () {
218
229
return clock_get_hz (clk_sys);
219
230
}
220
231
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
+ */
222
237
static int cpuid () {
223
238
return sio_hw->cpuid ;
224
239
}
225
240
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
+ */
227
244
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
+ */
228
254
inline uint32_t getCycleCount () {
229
255
#if !defined(__riscv) && !defined(__PROFILE)
256
+ // Get CPU cycle count. Needs to do magic to extend 24b HW to something longer
230
257
if (!__isFreeRTOS) {
231
258
uint32_t epoch;
232
259
uint32_t ctr;
@@ -242,7 +269,11 @@ class RP2040 {
242
269
}
243
270
#endif
244
271
}
272
+ /* *
273
+ @brief Get the count of CPU clock cycles since power on as a 64-bit quantrity
245
274
275
+ @returns CPU clock cycles since power up
276
+ */
246
277
inline uint64_t getCycleCount64 () {
247
278
#if !defined(__riscv) && !defined(__PROFILE)
248
279
if (!__isFreeRTOS) {
@@ -261,23 +292,53 @@ class RP2040 {
261
292
#endif
262
293
}
263
294
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
+ */
264
305
inline int getFreeHeap () {
265
306
return getTotalHeap () - getUsedHeap ();
266
307
}
267
308
309
+ /* *
310
+ @brief Gets total used heap (dynamic memory)
311
+
312
+ @returns Used heap in bytes
313
+ */
268
314
inline int getUsedHeap () {
269
315
struct mallinfo m = mallinfo ();
270
316
return m.uordblks ;
271
317
}
272
318
319
+ /* *
320
+ @brief Gets total heap (dynamic memory) compiled into the program
321
+
322
+ @returns Total heap size in bytes
323
+ */
273
324
inline int getTotalHeap () {
274
325
return &__StackLimit - &__bss_end__;
275
326
}
276
327
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
+ */
277
333
inline int getFreePSRAMHeap () {
278
334
return getTotalPSRAMHeap () - getUsedPSRAMHeap ();
279
335
}
280
336
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
+ */
281
342
inline int getUsedPSRAMHeap () {
282
343
#if defined(RP2350_PSRAM_CS)
283
344
extern size_t __psram_total_used ();
@@ -287,6 +348,11 @@ class RP2040 {
287
348
#endif
288
349
}
289
350
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
+ */
290
356
inline int getTotalPSRAMHeap () {
291
357
#if defined(RP2350_PSRAM_CS)
292
358
extern size_t __psram_total_space ();
@@ -296,6 +362,11 @@ class RP2040 {
296
362
#endif
297
363
}
298
364
365
+ /* *
366
+ @brief Gets the current stack pointer in a ARM/RISC-V safe manner
367
+
368
+ @returns Current SP
369
+ */
299
370
inline uint32_t getStackPointer () {
300
371
uint32_t *sp;
301
372
#if defined(__riscv)
@@ -306,6 +377,14 @@ class RP2040 {
306
377
return (uint32_t )sp;
307
378
}
308
379
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
+ */
309
388
inline int getFreeStack () {
310
389
const unsigned int sp = getStackPointer ();
311
390
uint32_t ref = 0x20040000 ;
@@ -319,6 +398,11 @@ class RP2040 {
319
398
return sp - ref;
320
399
}
321
400
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
+ */
322
406
inline size_t getPSRAMSize () {
323
407
#if defined(RP2350_PSRAM_CS)
324
408
extern size_t __psram_size;
@@ -328,31 +412,65 @@ class RP2040 {
328
412
#endif
329
413
}
330
414
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
+ */
331
429
void idleOtherCore () {
332
430
fifo.idleOtherCore ();
333
431
}
334
432
433
+ /* *
434
+ @brief Resumes normal operation of the other core
435
+ */
335
436
void resumeOtherCore () {
336
437
fifo.resumeOtherCore ();
337
438
}
338
439
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
+ */
339
448
void restartCore1 () {
340
449
multicore_reset_core1 ();
341
450
fifo.clear ();
342
451
multicore_launch_core1 (main1);
343
452
}
344
453
454
+ /* *
455
+ @brief Warm-reboots the chip in normal mode
456
+ */
345
457
void reboot () {
346
458
watchdog_reboot (0 , 0 , 10 );
347
459
while (1 ) {
348
460
continue ;
349
461
}
350
462
}
351
463
464
+ /* *
465
+ @brief Warm-reboots the chip in normal mode
466
+ */
352
467
inline void restart () {
353
468
reboot ();
354
469
}
355
470
471
+ /* *
472
+ @brief Warm-reboots the chip into the USB bootloader mode
473
+ */
356
474
inline void rebootToBootloader () {
357
475
reset_usb_boot (0 , 0 );
358
476
while (1 ) {
@@ -364,16 +482,32 @@ class RP2040 {
364
482
static void enableDoubleResetBootloader ();
365
483
#endif
366
484
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
+ */
367
490
void wdt_begin (uint32_t delay_ms) {
368
491
watchdog_enable (delay_ms, 1 );
369
492
}
370
493
494
+ /* *
495
+ @brief Feeds the watchdog timer, resetting it for another delay_ms countdown
496
+ */
371
497
void wdt_reset () {
372
498
watchdog_update ();
373
499
}
374
500
501
+ /* *
502
+ @brief Best-effort reasons for chip reset
503
+ */
375
504
enum resetReason_t {UNKNOWN_RESET, PWRON_RESET, RUN_PIN_RESET, SOFT_RESET, WDT_RESET, DEBUG_RESET, GLITCH_RESET, BROWNOUT_RESET};
376
505
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
+ */
377
511
resetReason_t getResetReason (void ) {
378
512
io_rw_32 *WD_reason_reg = (io_rw_32 *)(WATCHDOG_BASE + WATCHDOG_REASON_OFFSET);
379
513
@@ -427,6 +561,10 @@ class RP2040 {
427
561
return UNKNOWN_RESET;
428
562
}
429
563
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
+ */
430
568
const char *getChipID () {
431
569
static char id[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1 ] = { 0 };
432
570
if (!id[0 ]) {
@@ -437,6 +575,17 @@ class RP2040 {
437
575
438
576
#pragma GCC push_options
439
577
#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
+ */
440
589
void *memcpyDMA (void *dest, const void *src, size_t n) {
441
590
// Allocate a DMA channel on 1st call, reuse it every call after
442
591
if (memcpyDMAChannel < 1 ) {
@@ -465,14 +614,32 @@ class RP2040 {
465
614
}
466
615
#pragma GCC pop_options
467
616
468
- // Multicore comms FIFO
617
+ /* *
618
+ @brief Multicore communications FIFO
619
+ */
469
620
_MFIFO fifo;
470
621
471
622
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
+ */
472
628
uint32_t hwrand32 () {
473
629
return get_rand_32 ();
474
630
}
475
631
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
+ */
476
643
bool isPicoW () {
477
644
#if !defined(PICO_CYW43_SUPPORTED)
478
645
return false ;
0 commit comments