From c68a57aa34250533a428bc0a3714692085451582 Mon Sep 17 00:00:00 2001 From: graham sanderson Date: Mon, 8 Mar 2021 12:23:44 -0600 Subject: [PATCH 01/14] start 1.1.1 patch branch --- pico_sdk_version.cmake | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pico_sdk_version.cmake b/pico_sdk_version.cmake index 86ba04390..9bea16949 100644 --- a/pico_sdk_version.cmake +++ b/pico_sdk_version.cmake @@ -6,7 +6,15 @@ set(PICO_SDK_VERSION_MAJOR 1) set(PICO_SDK_VERSION_MINOR 1) # PICO_BUILD_DEFINE: PICO_SDK_VERSION_REVISION, SDK version revision, type=int, pico_base # PICO_CONFIG: PICO_SDK_VERSION_REVISION, SDK version revision, type=int, pico_base -set(PICO_SDK_VERSION_REVISION 0) +set(PICO_SDK_VERSION_REVISION 1) +# PICO_BUILD_DEFINE: PICO_SDK_VERSION_PRE_RELEASE_ID, optional SDK pre-release version identifier, type=string, pico_base +# PICO_CONFIG: PICO_SDK_VERSION_PRE_RELEASE_ID, SDK version revision, type=string, pico_base +set(PICO_SDK_VERSION_PRE_RELEASE_ID develop) + # PICO_BUILD_DEFINE: PICO_SDK_VERSION_STRING, SDK version, type=string, group=pico_base # PICO_CONFIG: PICO_SDK_VERSION_STRING, SDK version, type=string, group=pico_base set(PICO_SDK_VERSION_STRING "${PICO_SDK_VERSION_MAJOR}.${PICO_SDK_VERSION_MINOR}.${PICO_SDK_VERSION_REVISION}") + +if (PICO_SDK_VERSION_PRE_RELEASE_ID) + set(PICO_SDK_VERSION_STRING "${PICO_SDK_VERSION_STRING}-${PICO_SDK_VERSION_PRE_RELEASE_ID}") +endif() \ No newline at end of file From c4e35d914d628ff9d17abdb73566c75b664aa89c Mon Sep 17 00:00:00 2001 From: graham sanderson Date: Mon, 8 Mar 2021 15:12:07 -0600 Subject: [PATCH 02/14] build: fix mismatched config descriptions --- pico_sdk_version.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pico_sdk_version.cmake b/pico_sdk_version.cmake index 9bea16949..5cbdd8fc1 100644 --- a/pico_sdk_version.cmake +++ b/pico_sdk_version.cmake @@ -8,7 +8,7 @@ set(PICO_SDK_VERSION_MINOR 1) # PICO_CONFIG: PICO_SDK_VERSION_REVISION, SDK version revision, type=int, pico_base set(PICO_SDK_VERSION_REVISION 1) # PICO_BUILD_DEFINE: PICO_SDK_VERSION_PRE_RELEASE_ID, optional SDK pre-release version identifier, type=string, pico_base -# PICO_CONFIG: PICO_SDK_VERSION_PRE_RELEASE_ID, SDK version revision, type=string, pico_base +# PICO_CONFIG: PICO_SDK_VERSION_PRE_RELEASE_ID, optional SDK pre-release version identifier, type=string, pico_base set(PICO_SDK_VERSION_PRE_RELEASE_ID develop) # PICO_BUILD_DEFINE: PICO_SDK_VERSION_STRING, SDK version, type=string, group=pico_base From d36b1ca8aec854f822c7df1619dd7c45d83b4127 Mon Sep 17 00:00:00 2001 From: Graham Sanderson Date: Wed, 10 Mar 2021 12:04:04 -0600 Subject: [PATCH 03/14] hardware_timer: fix race condition whem a new timer being added becomes missed thus obviating the need for an IRQ but there is an IRQ already pending for another timer (#243) --- src/rp2_common/hardware_timer/timer.c | 27 ++++++++++++++-------- test/pico_time_test/pico_time_test.c | 32 ++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/rp2_common/hardware_timer/timer.c b/src/rp2_common/hardware_timer/timer.c index 774548496..23bea050b 100644 --- a/src/rp2_common/hardware_timer/timer.c +++ b/src/rp2_common/hardware_timer/timer.c @@ -166,8 +166,9 @@ bool hardware_alarm_set_target(uint alarm_num, absolute_time_t target) { // 1) actually set the hardware timer spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER); uint32_t save = spin_lock_blocking(lock); - timer_hw->intr = 1u << alarm_num; + uint8_t old_timer_callbacks_pending = timer_callbacks_pending; timer_callbacks_pending |= (uint8_t)(1u << alarm_num); + timer_hw->intr = 1u << alarm_num; // clear any IRQ timer_hw->alarm[alarm_num] = (uint32_t) t; // Set the alarm. Writing time should arm it target_hi[alarm_num] = (uint32_t)(t >> 32u); @@ -178,18 +179,26 @@ bool hardware_alarm_set_target(uint alarm_num, absolute_time_t target) { assert(timer_hw->ints & 1u << alarm_num); } else { if (time_us_64() >= t) { - // ok well it is time now; the irq isn't being handled yet because of the spin lock - // however the other core might be in the IRQ handler itself about to do a callback - // we do the firing ourselves (and indicate to the IRQ handler if any that it shouldn't + // we are already at or past the right time; there is no point in us racing against the IRQ + // we are about to generate. note however that, if there was already a timer pending before, + // then we still let the IRQ fire, as whatever it was, is not handled by our setting missed=true here missed = true; - // disarm the timer - timer_hw->armed = 1u << alarm_num; - timer_hw->intr = 1u << alarm_num; // clear the IRQ too - // and set flag in case we're already in the IRQ handler waiting on the spinlock (on the other core) - timer_callbacks_pending &= (uint8_t)~(1u << alarm_num); + if (timer_callbacks_pending != old_timer_callbacks_pending) { + // disarm the timer + timer_hw->armed = 1u << alarm_num; + // clear the IRQ... + timer_hw->intr = 1u << alarm_num; + // ... including anything pending on the processor - perhaps unnecessary, but + // our timer flag says we aren't expecting anything. + irq_clear(harware_alarm_irq_number(alarm_num)); + // and clear our flag so that if the IRQ handler is already active (because it is on + // the other core) it will also skip doing anything + timer_callbacks_pending = old_timer_callbacks_pending; + } } } spin_unlock(lock, save); + // note at this point any pending timer IRQ can likely run } return missed; } diff --git a/test/pico_time_test/pico_time_test.c b/test/pico_time_test/pico_time_test.c index 1093dd6fa..2209fd546 100644 --- a/test/pico_time_test/pico_time_test.c +++ b/test/pico_time_test/pico_time_test.c @@ -64,12 +64,13 @@ static bool repeating_timer_callback(struct repeating_timer *t) { #define RESOLUTION_ALLOWANCE PICO_HARDWARE_TIMER_RESOLUTION_US #endif +int issue_195_test(void); + int main() { setup_default_uart(); alarm_pool_init_default(); PICOTEST_START(); - struct alarm_pool *pools[NUM_TIMERS]; for(uint i=0; i 0, "near the end of time should be before the end of time") PICOTEST_END_SECTION(); + if (issue_195_test()) { + return -1; + } + PICOTEST_END_TEST(); } +#define ISSUE_195_TIMER_DELAY 50 +volatile int issue_195_counter; +int64_t issue_195_callback(alarm_id_t id, void *user_data) { + issue_195_counter++; + return -ISSUE_195_TIMER_DELAY; +} + +int issue_195_test(void) { + PICOTEST_START_SECTION("Issue #195 race condition - without fix may hang on gcc 10.2.1 release builds"); + absolute_time_t t1 = get_absolute_time(); + int id = add_alarm_in_us(ISSUE_195_TIMER_DELAY, issue_195_callback, NULL, true); + for(uint i=0;i<5000;i++) { + sleep_us(100); + sleep_us(100); + uint delay = 9; // 9 seems to be the magic number (at least for reproducing on 10.2.1) + sleep_us(delay); + } + absolute_time_t t2 = get_absolute_time(); + cancel_alarm(id); + int expected_count = absolute_time_diff_us(t1, t2) / ISSUE_195_TIMER_DELAY; + printf("Timer fires approx_expected=%d actual=%d\n", expected_count, issue_195_counter); + PICOTEST_END_SECTION(); + return 0; +} + From fe3408b28662fb9f63179078ee809c00983a7dcd Mon Sep 17 00:00:00 2001 From: Graham Sanderson Date: Wed, 17 Mar 2021 13:05:48 -0500 Subject: [PATCH 04/14] Small fixes (#260) * pico_stdio_usb: be more explicit about includes, fix warning (#257) * pico_base: NDEBUG backwards for absolute_time_t (#255) * pico_util: missing extern C in queue.h (#249) * build: remove -march which was masking -mcpu, now SVC available (#253) --- cmake/preload/toolchains/pico_arm_gcc.cmake | 5 +++-- src/common/pico_base/include/pico/types.h | 8 ++++---- src/common/pico_util/include/pico/util/queue.h | 9 ++++++++- src/rp2_common/pico_stdio_usb/reset_interface.c | 2 +- src/rp2_common/pico_stdio_usb/stdio_usb.c | 3 ++- test/kitchen_sink/kitchen_sink.c | 3 +++ 6 files changed, 21 insertions(+), 9 deletions(-) diff --git a/cmake/preload/toolchains/pico_arm_gcc.cmake b/cmake/preload/toolchains/pico_arm_gcc.cmake index 4fc0950ec..b0c26488e 100644 --- a/cmake/preload/toolchains/pico_arm_gcc.cmake +++ b/cmake/preload/toolchains/pico_arm_gcc.cmake @@ -52,8 +52,9 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) option(PICO_DEOPTIMIZED_DEBUG "Build debug builds with -O0" 0) # todo move to platform/Generix-xxx -set(ARM_GCC_COMMON_FLAGS " -march=armv6-m -mcpu=cortex-m0plus -mthumb") -#set(ARM_GCC_COMMON_FLAGS " -mcpu=cortex-m0plus -mthumb") + +# on ARM -mcpu should not be mixed with -march +set(ARM_GCC_COMMON_FLAGS " -mcpu=cortex-m0plus -mthumb") foreach(LANG IN ITEMS C CXX ASM) set(CMAKE_${LANG}_FLAGS_INIT "${ARM_GCC_COMMON_FLAGS}") if (PICO_DEOPTIMIZED_DEBUG) diff --git a/src/common/pico_base/include/pico/types.h b/src/common/pico_base/include/pico/types.h index 51debf232..6b8e66f62 100644 --- a/src/common/pico_base/include/pico/types.h +++ b/src/common/pico_base/include/pico/types.h @@ -25,7 +25,7 @@ typedef unsigned int uint; \see update_us_since_boot() \ingroup timestamp */ -#ifndef NDEBUG +#ifdef NDEBUG typedef uint64_t absolute_time_t; #else typedef struct { @@ -40,7 +40,7 @@ typedef struct { * \ingroup timestamp */ static inline uint64_t to_us_since_boot(absolute_time_t t) { -#ifndef NDEBUG +#ifdef NDEBUG return t; #else return t._private_us_since_boot; @@ -55,7 +55,7 @@ static inline uint64_t to_us_since_boot(absolute_time_t t) { * \ingroup timestamp */ static inline void update_us_since_boot(absolute_time_t *t, uint64_t us_since_boot) { -#ifndef NDEBUG +#ifdef NDEBUG *t = us_since_boot; #else assert(us_since_boot <= INT64_MAX); @@ -63,7 +63,7 @@ static inline void update_us_since_boot(absolute_time_t *t, uint64_t us_since_bo #endif } -#ifndef NDEBUG +#ifdef NDEBUG #define ABSOLUTE_TIME_INITIALIZED_VAR(name, value) name = value #else #define ABSOLUTE_TIME_INITIALIZED_VAR(name, value) name = {value} diff --git a/src/common/pico_util/include/pico/util/queue.h b/src/common/pico_util/include/pico/util/queue.h index 8281d8b06..60a450a1f 100644 --- a/src/common/pico_util/include/pico/util/queue.h +++ b/src/common/pico_util/include/pico/util/queue.h @@ -18,6 +18,10 @@ * \ingroup pico_util */ +#ifdef __cplusplus +extern "C" { +#endif + typedef struct { spin_lock_t *lock; uint8_t *data; @@ -69,7 +73,7 @@ void queue_free(queue_t *q); static inline uint queue_get_level_unsafe(queue_t *q) { int32_t rc = (int32_t)q->wptr - (int32_t)q->rptr; if (rc < 0) { - rc += + q->element_count + 1; + rc += q->element_count + 1; } return (uint)rc; } @@ -181,4 +185,7 @@ void queue_remove_blocking(queue_t *q, void *data); */ void queue_peek_blocking(queue_t *q, void *data); +#ifdef __cplusplus +} +#endif #endif diff --git a/src/rp2_common/pico_stdio_usb/reset_interface.c b/src/rp2_common/pico_stdio_usb/reset_interface.c index 252548692..12328577c 100644 --- a/src/rp2_common/pico_stdio_usb/reset_interface.c +++ b/src/rp2_common/pico_stdio_usb/reset_interface.c @@ -60,7 +60,7 @@ static bool resetd_control_request_cb(uint8_t __unused rhport, tusb_control_requ #if PICO_STDIO_USB_RESET_INTERFACE_SUPPORT_RESET_TO_FLASH_BOOT if (request->bRequest == RESET_REQUEST_FLASH) { - watchdog_reboot(0, SRAM_END, PICO_STDIO_USB_RESET_RESET_TO_FLASH_DELAY_MS); + watchdog_reboot(0, 0, PICO_STDIO_USB_RESET_RESET_TO_FLASH_DELAY_MS); return true; } #endif diff --git a/src/rp2_common/pico_stdio_usb/stdio_usb.c b/src/rp2_common/pico_stdio_usb/stdio_usb.c index c122b44f2..d86879f44 100644 --- a/src/rp2_common/pico_stdio_usb/stdio_usb.c +++ b/src/rp2_common/pico_stdio_usb/stdio_usb.c @@ -10,12 +10,13 @@ #include "pico/time.h" #include "pico/stdio/driver.h" #include "pico/binary_info.h" +#include "pico/mutex.h" #include "hardware/irq.h" static_assert(PICO_STDIO_USB_LOW_PRIORITY_IRQ > RTC_IRQ, ""); // note RTC_IRQ is currently the last one static mutex_t stdio_usb_mutex; -static void low_priority_worker_irq() { +static void low_priority_worker_irq(void) { // if the mutex is already owned, then we are in user code // in this file which will do a tud_task itself, so we'll just do nothing // until the next tick; we won't starve diff --git a/test/kitchen_sink/kitchen_sink.c b/test/kitchen_sink/kitchen_sink.c index 7c19b1eb2..033df3d07 100644 --- a/test/kitchen_sink/kitchen_sink.c +++ b/test/kitchen_sink/kitchen_sink.c @@ -83,6 +83,7 @@ int main(void) { dma_channel_configure(0, &config, &dma_to, &dma_from, 1, true); dma_channel_set_config(0, &config, false); + // note this loop expects to cause a breakpoint!! for (int i = 0; i < 20; i++) { puts("sleepy"); sleep_ms(1000); @@ -94,4 +95,6 @@ int main(void) { irq_remove_handler(DMA_IRQ_1, dma_handler_b); } } + // this should compile as we are Cortex M0+ + __asm volatile("SVC #3"); } From f6d32f87a1effd1e5ddac40eb8b12d58164888c3 Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Thu, 18 Mar 2021 19:41:40 +0000 Subject: [PATCH 05/14] Fix typo in sparkfun_micromod.h (#268) --- src/boards/include/boards/sparkfun_micromod.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/boards/include/boards/sparkfun_micromod.h b/src/boards/include/boards/sparkfun_micromod.h index 52dcaeb0c..973a9e184 100644 --- a/src/boards/include/boards/sparkfun_micromod.h +++ b/src/boards/include/boards/sparkfun_micromod.h @@ -19,7 +19,7 @@ #ifndef PICO_DEFAULT_UART #define PICO_DEFAULT_UART 0 -#define +#endif #ifndef PICO_DEFAULT_UART_TX_PIN #define PICO_DEFAULT_UART_TX_PIN 0 From 304ab7dd92fedde6241daf2abaf22cf1af852bb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Sim=C3=B5es?= Date: Thu, 18 Mar 2021 20:02:21 +0000 Subject: [PATCH 06/14] Fix loading of PICO_TOOLCHAIN_PATH (#262) - Add double quotes because build option it's a string. - Remove comment as requested by @kilograham. - Resolves #258. --- cmake/pico_pre_load_toolchain.cmake | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmake/pico_pre_load_toolchain.cmake b/cmake/pico_pre_load_toolchain.cmake index 9fc933d01..6c01357af 100644 --- a/cmake/pico_pre_load_toolchain.cmake +++ b/cmake/pico_pre_load_toolchain.cmake @@ -1,6 +1,5 @@ # PICO_CMAKE_CONFIG: PICO_TOOLCHAIN_PATH, Path to search for compiler, default=none (i.e. search system paths), group=build -# Set your compiler path here if it's not in the PATH environment variable. -set(PICO_TOOLCHAIN_PATH "" CACHE INTERNAL "") +set(PICO_TOOLCHAIN_PATH "${PICO_TOOLCHAIN_PATH}" CACHE INTERNAL "") # Set a default build type if none was specified set(default_build_type "Release") From f76567eb7f00f8c0bd459030b631128780fb454d Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Fri, 19 Mar 2021 14:11:42 +0000 Subject: [PATCH 07/14] Merge pico_sdk_version.cmake changes from develop branch into develop-1.1.1 branch --- pico_sdk_version.cmake | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/pico_sdk_version.cmake b/pico_sdk_version.cmake index 5cbdd8fc1..9f2aa6106 100644 --- a/pico_sdk_version.cmake +++ b/pico_sdk_version.cmake @@ -1,14 +1,14 @@ -# PICO_BUILD_DEFINE: PICO_SDK_VERSION_MAJOR, SDK major version number, type=int, pico_base -# PICO_CONFIG: PICO_SDK_VERSION_MAJOR, SDK major version number, type=int, pico_base +# PICO_BUILD_DEFINE: PICO_SDK_VERSION_MAJOR, SDK major version number, type=int, group=pico_base +# PICO_CONFIG: PICO_SDK_VERSION_MAJOR, SDK major version number, type=int, group=pico_base set(PICO_SDK_VERSION_MAJOR 1) -# PICO_BUILD_DEFINE: PICO_SDK_VERSION_MINOR, SDK minor version number, type=int, pico_base -# PICO_CONFIG: PICO_SDK_VERSION_MINOR, SDK minor version number, type=int, pico_base +# PICO_BUILD_DEFINE: PICO_SDK_VERSION_MINOR, SDK minor version number, type=int, group=pico_base +# PICO_CONFIG: PICO_SDK_VERSION_MINOR, SDK minor version number, type=int, group=pico_base set(PICO_SDK_VERSION_MINOR 1) -# PICO_BUILD_DEFINE: PICO_SDK_VERSION_REVISION, SDK version revision, type=int, pico_base -# PICO_CONFIG: PICO_SDK_VERSION_REVISION, SDK version revision, type=int, pico_base +# PICO_BUILD_DEFINE: PICO_SDK_VERSION_REVISION, SDK version revision, type=int, group=pico_base +# PICO_CONFIG: PICO_SDK_VERSION_REVISION, SDK version revision, type=int, group=pico_base set(PICO_SDK_VERSION_REVISION 1) -# PICO_BUILD_DEFINE: PICO_SDK_VERSION_PRE_RELEASE_ID, optional SDK pre-release version identifier, type=string, pico_base -# PICO_CONFIG: PICO_SDK_VERSION_PRE_RELEASE_ID, optional SDK pre-release version identifier, type=string, pico_base +# PICO_BUILD_DEFINE: PICO_SDK_VERSION_PRE_RELEASE_ID, optional SDK pre-release version identifier, type=string, group=pico_base +# PICO_CONFIG: PICO_SDK_VERSION_PRE_RELEASE_ID, optional SDK pre-release version identifier, type=string, group=pico_base set(PICO_SDK_VERSION_PRE_RELEASE_ID develop) # PICO_BUILD_DEFINE: PICO_SDK_VERSION_STRING, SDK version, type=string, group=pico_base @@ -17,4 +17,4 @@ set(PICO_SDK_VERSION_STRING "${PICO_SDK_VERSION_MAJOR}.${PICO_SDK_VERSION_MINOR} if (PICO_SDK_VERSION_PRE_RELEASE_ID) set(PICO_SDK_VERSION_STRING "${PICO_SDK_VERSION_STRING}-${PICO_SDK_VERSION_PRE_RELEASE_ID}") -endif() \ No newline at end of file +endif() From e9a521a9b1ecc66f4e90c3b40cd9625dea57583d Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 21 Mar 2021 13:23:24 -0500 Subject: [PATCH 08/14] rtc_get_datetime: read the rtc registers just once each In order for the returned value to accurately reflect a single moment in time, ensure the registers are read just once and in the datasheet order. Before this change, the RTC registers would each be read multiple times, leading (infrequently) to the returned fields not all reflecting the same moment in time. The rp2040 datasheet has what I believe is an incorrect example (embedding the source of this function); will the datasheet be updated if this function is fixed? This problem is only a speculative one; I did not actually observe it in the wild. --- src/rp2_common/hardware_rtc/rtc.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/rp2_common/hardware_rtc/rtc.c b/src/rp2_common/hardware_rtc/rtc.c index 813b5f121..5429acd4b 100644 --- a/src/rp2_common/hardware_rtc/rtc.c +++ b/src/rp2_common/hardware_rtc/rtc.c @@ -92,13 +92,16 @@ bool rtc_get_datetime(datetime_t *t) { } // Note: RTC_0 should be read before RTC_1 - t->dotw = (rtc_hw->rtc_0 & RTC_RTC_0_DOTW_BITS ) >> RTC_RTC_0_DOTW_LSB; - t->hour = (rtc_hw->rtc_0 & RTC_RTC_0_HOUR_BITS ) >> RTC_RTC_0_HOUR_LSB; - t->min = (rtc_hw->rtc_0 & RTC_RTC_0_MIN_BITS ) >> RTC_RTC_0_MIN_LSB; - t->sec = (rtc_hw->rtc_0 & RTC_RTC_0_SEC_BITS ) >> RTC_RTC_0_SEC_LSB; - t->year = (rtc_hw->rtc_1 & RTC_RTC_1_YEAR_BITS ) >> RTC_RTC_1_YEAR_LSB; - t->month = (rtc_hw->rtc_1 & RTC_RTC_1_MONTH_BITS) >> RTC_RTC_1_MONTH_LSB; - t->day = (rtc_hw->rtc_1 & RTC_RTC_1_DAY_BITS ) >> RTC_RTC_1_DAY_LSB; + uint32_t rtc_0 = rtc_hw->rtc_0; + uint32_t rtc_1 = rtc_hw->rtc_1; + + t->dotw = (rtc_0 & RTC_RTC_0_DOTW_BITS ) >> RTC_RTC_0_DOTW_LSB; + t->hour = (rtc_0 & RTC_RTC_0_HOUR_BITS ) >> RTC_RTC_0_HOUR_LSB; + t->min = (rtc_0 & RTC_RTC_0_MIN_BITS ) >> RTC_RTC_0_MIN_LSB; + t->sec = (rtc_0 & RTC_RTC_0_SEC_BITS ) >> RTC_RTC_0_SEC_LSB; + t->year = (rtc_1 & RTC_RTC_1_YEAR_BITS ) >> RTC_RTC_1_YEAR_LSB; + t->month = (rtc_1 & RTC_RTC_1_MONTH_BITS) >> RTC_RTC_1_MONTH_LSB; + t->day = (rtc_1 & RTC_RTC_1_DAY_BITS ) >> RTC_RTC_1_DAY_LSB; return true; } @@ -185,4 +188,4 @@ void rtc_disable_alarm(void) { while(rtc_hw->irq_setup_0 & RTC_IRQ_SETUP_0_MATCH_ACTIVE_BITS) { tight_loop_contents(); } -} \ No newline at end of file +} From 1d4588a565026ffa599e3221faad9df4c9122632 Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Wed, 24 Mar 2021 14:15:36 +0000 Subject: [PATCH 09/14] Board-header typos (#270) --- src/boards/include/boards/pimoroni_keybow2040.h | 2 +- src/boards/include/boards/vgaboard.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/boards/include/boards/pimoroni_keybow2040.h b/src/boards/include/boards/pimoroni_keybow2040.h index 46c51342e..eeab40919 100644 --- a/src/boards/include/boards/pimoroni_keybow2040.h +++ b/src/boards/include/boards/pimoroni_keybow2040.h @@ -107,7 +107,7 @@ #define KEYBOW2040_SW15_PIN 6 #endif -#ifndef KEYBOW2040_NUM_SWITCHES +#ifndef KEYBOW2040_NUM_SWITCHES_PINS #define KEYBOW2040_NUM_SWITCHES_PINS 16 #endif diff --git a/src/boards/include/boards/vgaboard.h b/src/boards/include/boards/vgaboard.h index b03eaa7f6..d9cb7ac28 100644 --- a/src/boards/include/boards/vgaboard.h +++ b/src/boards/include/boards/vgaboard.h @@ -26,8 +26,8 @@ #define VGABOARD_VGA_COLOR_PIN_BASE 0 #define VGABOARD_VGA_SYNC_PIN_BASE 16 -// Note DAT2/3 are shared with UART TX/RX (pull jumpers off header to access -// UART pins and disconnect SD DAT2/3) +// Note DAT1/2 are shared with UART TX/RX (pull jumpers off header to access +// UART pins and disconnect SD DAT1/2) #define VGABOARD_SD_CLK_PIN 5 #define VGABOARD_SD_CMD_PIN 18 #define VGABOARD_SD_DAT0_PIN 19 @@ -57,10 +57,12 @@ #define PICO_SD_CMD_PIN VGABOARD_SD_CMD_PIN #define PICO_SD_DAT0_PIN VGABOARD_SD_DAT0_PIN +// 1 or 4 #ifndef PICO_SD_DAT_PIN_COUNT #define PICO_SD_DAT_PIN_COUNT 4 #endif +// 1 or -1 #define PICO_SD_DAT_PIN_INCREMENT 1 #define PICO_AUDIO_I2S_DATA_PIN VGABOARD_I2S_DIN_PIN From a47d6d6e14d4cd5d135606cf839c47340eaddfdc Mon Sep 17 00:00:00 2001 From: Mike Bell Date: Wed, 24 Mar 2021 14:26:54 +0000 Subject: [PATCH 10/14] Allow heap end to be equal to stack limit (#266) --- src/rp2_common/pico_runtime/runtime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rp2_common/pico_runtime/runtime.c b/src/rp2_common/pico_runtime/runtime.c index 796284ea0..2340ba796 100644 --- a/src/rp2_common/pico_runtime/runtime.c +++ b/src/rp2_common/pico_runtime/runtime.c @@ -175,9 +175,9 @@ void *_sbrk(int incr) { prev_heap_end = heap_end; char *next_heap_end = heap_end + incr; - if (__builtin_expect(next_heap_end >= (&__StackLimit), false)) { + if (__builtin_expect(next_heap_end > (&__StackLimit), false)) { #if PICO_USE_OPTIMISTIC_SBRK - if (next_heap_end == &__StackLimit) { + if (heap_end == &__StackLimit) { // errno = ENOMEM; return (char *) -1; } From 0c941d9767572abcf757da91221f4737e3e39af0 Mon Sep 17 00:00:00 2001 From: Andrew Scheller Date: Wed, 24 Mar 2021 14:32:38 +0000 Subject: [PATCH 11/14] Tweaks to PIO clkdiv-setting code (#254) - refactor to reduce duplication - add extra param-validation --- .../hardware_pio/include/hardware/pio.h | 82 ++++++++++--------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/src/rp2_common/hardware_pio/include/hardware/pio.h b/src/rp2_common/hardware_pio/include/hardware/pio.h index 247849537..36194b8d8 100644 --- a/src/rp2_common/hardware_pio/include/hardware/pio.h +++ b/src/rp2_common/hardware_pio/include/hardware/pio.h @@ -196,29 +196,6 @@ static inline void sm_config_set_sideset(pio_sm_config *c, uint bit_count, bool (bool_to_bit(pindirs) << PIO_SM0_EXECCTRL_SIDE_PINDIR_LSB); } -/*! \brief Set the state machine clock divider (from a floating point value) in a state machine configuration - * \ingroup sm_config - * - * The clock divider slows the state machine's execution by masking the - * system clock on some cycles, in a repeating pattern, so that the state - * machine does not advance. Effectively this produces a slower clock for the - * state machine to run from, which can be used to generate e.g. a particular - * UART baud rate. See the datasheet for further detail. - * - * \param c Pointer to the configuration structure to modify - * \param div The fractional divisor to be set. 1 for full speed. An integer clock divisor of n - * will cause the state machine to run 1 cycle in every n. - * Note that for small n, the jitter introduced by a fractional divider (e.g. 2.5) may be unacceptable - * although it will depend on the use case. - */ -static inline void sm_config_set_clkdiv(pio_sm_config *c, float div) { - uint div_int = (uint)div; - uint div_frac = (uint)((div - (float)div_int) * (1u << 8u)); - c->clkdiv = - (div_frac << PIO_SM0_CLKDIV_FRAC_LSB) | - (div_int << PIO_SM0_CLKDIV_INT_LSB); -} - /*! \brief Set the state machine clock divider (from integer and fractional parts - 16:8) in a state machine configuration * \ingroup sm_config * @@ -238,6 +215,38 @@ static inline void sm_config_set_clkdiv_int_frac(pio_sm_config *c, uint16_t div_ (((uint)div_int) << PIO_SM0_CLKDIV_INT_LSB); } +static inline void pio_calculate_clkdiv_from_float(float div, uint16_t *div_int, uint8_t *div_frac) { + valid_params_if(PIO, div >= 1 && div <= 65536); + *div_int = (uint16_t)div; + if (*div_int == 0) { + *div_frac = 0; + } else { + *div_frac = (uint8_t)((div - (float)*div_int) * (1u << 8u)); + } +} + +/*! \brief Set the state machine clock divider (from a floating point value) in a state machine configuration + * \ingroup sm_config + * + * The clock divider slows the state machine's execution by masking the + * system clock on some cycles, in a repeating pattern, so that the state + * machine does not advance. Effectively this produces a slower clock for the + * state machine to run from, which can be used to generate e.g. a particular + * UART baud rate. See the datasheet for further detail. + * + * \param c Pointer to the configuration structure to modify + * \param div The fractional divisor to be set. 1 for full speed. An integer clock divisor of n + * will cause the state machine to run 1 cycle in every n. + * Note that for small n, the jitter introduced by a fractional divider (e.g. 2.5) may be unacceptable + * although it will depend on the use case. + */ +static inline void sm_config_set_clkdiv(pio_sm_config *c, float div) { + uint16_t div_int; + uint8_t div_frac; + pio_calculate_clkdiv_from_float(div, &div_int, &div_frac); + sm_config_set_clkdiv_int_frac(c, div_int, div_frac); +} + /*! \brief Set the wrap addresses in a state machine configuration * \ingroup sm_config * @@ -978,37 +987,36 @@ static inline uint32_t pio_sm_get_blocking(PIO pio, uint sm) { */ void pio_sm_drain_tx_fifo(PIO pio, uint sm); -/*! \brief set the current clock divider for a state machine +/*! \brief set the current clock divider for a state machine using a 16:8 fraction * \ingroup hardware_pio * * \param pio The PIO instance; either \ref pio0 or \ref pio1 * \param sm State machine index (0..3) - * \param div the floating point clock divider + * \param div_int the integer part of the clock divider + * \param div_frac the fractional part of the clock divider in 1/256s */ -static inline void pio_sm_set_clkdiv(PIO pio, uint sm, float div) { +static inline void pio_sm_set_clkdiv_int_frac(PIO pio, uint sm, uint16_t div_int, uint8_t div_frac) { check_pio_param(pio); check_sm_param(sm); - uint div_int = (uint16_t) div; - uint div_frac = (uint8_t) ((div - (float)div_int) * (1u << 8u)); pio->sm[sm].clkdiv = - (div_frac << PIO_SM0_CLKDIV_FRAC_LSB) | - (div_int << PIO_SM0_CLKDIV_INT_LSB); + (((uint)div_frac) << PIO_SM0_CLKDIV_FRAC_LSB) | + (((uint)div_int) << PIO_SM0_CLKDIV_INT_LSB); } -/*! \brief set the current clock divider for a state machine using a 16:8 fraction +/*! \brief set the current clock divider for a state machine * \ingroup hardware_pio * * \param pio The PIO instance; either \ref pio0 or \ref pio1 * \param sm State machine index (0..3) - * \param div_int the integer part of the clock divider - * \param div_frac the fractional part of the clock divider in 1/256s + * \param div the floating point clock divider */ -static inline void pio_sm_set_clkdiv_int_frac(PIO pio, uint sm, uint16_t div_int, uint8_t div_frac) { +static inline void pio_sm_set_clkdiv(PIO pio, uint sm, float div) { check_pio_param(pio); check_sm_param(sm); - pio->sm[sm].clkdiv = - (((uint)div_frac) << PIO_SM0_CLKDIV_FRAC_LSB) | - (((uint)div_int) << PIO_SM0_CLKDIV_INT_LSB); + uint16_t div_int; + uint8_t div_frac; + pio_calculate_clkdiv_from_float(div, &div_int, &div_frac); + pio_sm_set_clkdiv_int_frac(pio, sm, div_int, div_frac); } /*! \brief Clear a state machine's TX and RX FIFOs From c1f164b9fdc6008afcc65295facafd3271a23e95 Mon Sep 17 00:00:00 2001 From: Tom Wasiluk Date: Wed, 24 Mar 2021 15:35:02 +0100 Subject: [PATCH 12/14] corrected clk_gpout3 to gpio pin 25 as per the rp2040 datasheet (#250) --- src/rp2_common/hardware_clocks/clocks.c | 2 +- src/rp2_common/hardware_clocks/include/hardware/clocks.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rp2_common/hardware_clocks/clocks.c b/src/rp2_common/hardware_clocks/clocks.c index 848e878ca..ac1168038 100644 --- a/src/rp2_common/hardware_clocks/clocks.c +++ b/src/rp2_common/hardware_clocks/clocks.c @@ -322,7 +322,7 @@ void clock_gpio_init(uint gpio, uint src, uint div) { if (gpio == 21) gpclk = clk_gpout0; else if (gpio == 23) gpclk = clk_gpout1; else if (gpio == 24) gpclk = clk_gpout2; - else if (gpio == 26) gpclk = clk_gpout3; + else if (gpio == 25) gpclk = clk_gpout3; else { invalid_params_if(CLOCKS, true); } diff --git a/src/rp2_common/hardware_clocks/include/hardware/clocks.h b/src/rp2_common/hardware_clocks/include/hardware/clocks.h index 297dfa2ec..04d373dcb 100644 --- a/src/rp2_common/hardware_clocks/include/hardware/clocks.h +++ b/src/rp2_common/hardware_clocks/include/hardware/clocks.h @@ -170,7 +170,7 @@ void clocks_enable_resus(resus_callback_t resus_callback); /*! \brief Output an optionally divided clock to the specified gpio pin. * \ingroup hardware_clocks * - * \param gpio The GPIO pin to output the clock to. Valid GPIOs are: 21, 23, 24, 26. These GPIOs are connected to the GPOUT0-3 clock generators. + * \param gpio The GPIO pin to output the clock to. Valid GPIOs are: 21, 23, 24, 25. These GPIOs are connected to the GPOUT0-3 clock generators. * \param src The source clock. See the register field CLOCKS_CLK_GPOUT0_CTRL_AUXSRC for a full list. The list is the same for each GPOUT clock generator. * \param div The amount to divide the source clock by. This is useful to not overwhelm the GPIO pin with a fast clock. */ From ddd0e22623bc7edd8125fc596cd511cf07b5dc4f Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 24 Mar 2021 09:10:39 -0700 Subject: [PATCH 13/14] Use pico_unique_id as the USB device serial number Use the pico_unique_id to generate a unique serial number for the STDIO_USB device, allowing for individual boards to be identified. --- src/rp2_common/pico_stdio_usb/CMakeLists.txt | 3 ++- .../pico_stdio_usb/stdio_usb_descriptors.c | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/rp2_common/pico_stdio_usb/CMakeLists.txt b/src/rp2_common/pico_stdio_usb/CMakeLists.txt index 8bc88537d..170c516a7 100644 --- a/src/rp2_common/pico_stdio_usb/CMakeLists.txt +++ b/src/rp2_common/pico_stdio_usb/CMakeLists.txt @@ -13,9 +13,10 @@ if (TARGET tinyusb_device_unmarked) tinyusb_device_unmarked pico_stdio pico_time + pico_unique_id ) target_compile_definitions(pico_stdio_usb INTERFACE PICO_STDIO_USB=1 ) -endif() \ No newline at end of file +endif() diff --git a/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c b/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c index c66df42a4..bde9db20f 100644 --- a/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c +++ b/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c @@ -30,6 +30,7 @@ #include "tusb.h" #include "pico/stdio_usb/reset_interface.h" +#include "pico/unique_id.h" #define USBD_VID (0x2E8A) // Raspberry Pi #define USBD_PID (0x000a) // Raspberry Pi Pico SDK CDC @@ -98,10 +99,12 @@ static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = { #endif }; +static char usbd_serial_str[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1]; + static const char *const usbd_desc_str[] = { [USBD_STR_MANUF] = "Raspberry Pi", [USBD_STR_PRODUCT] = "Pico", - [USBD_STR_SERIAL] = "000000000000", // TODO + [USBD_STR_SERIAL] = usbd_serial_str, [USBD_STR_CDC] = "Board CDC", #if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE [USBD_STR_RPI_RESET] = "Reset", @@ -121,6 +124,18 @@ const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { #define DESC_STR_MAX (20) static uint16_t desc_str[DESC_STR_MAX]; + // lazy update the serial number if not set yet + if (!usbd_serial_str[0]) { + pico_unique_board_id_t id; + pico_get_unique_board_id(&id); + + for (int i = 0; i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES; i++) { + char hx[3]; + sprintf(hx, "%02X", id.id[i]); + strcat(usbd_serial_str, hx); + } + } + uint8_t len; if (index == 0) { desc_str[1] = 0x0409; // supported language is English @@ -141,4 +156,4 @@ const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { return desc_str; } -#endif \ No newline at end of file +#endif From 8a7d377197f333b8d2b2a477b6bb1e8e2c7c7485 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 24 Mar 2021 09:10:39 -0700 Subject: [PATCH 14/14] Use pico_unique_id as the USB device serial number Use the pico_unique_id to generate a unique serial number for the STDIO_USB device, allowing for individual boards to be identified. --- src/rp2_common/pico_stdio_usb/CMakeLists.txt | 3 ++- .../pico_stdio_usb/stdio_usb_descriptors.c | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/rp2_common/pico_stdio_usb/CMakeLists.txt b/src/rp2_common/pico_stdio_usb/CMakeLists.txt index 8bc88537d..170c516a7 100644 --- a/src/rp2_common/pico_stdio_usb/CMakeLists.txt +++ b/src/rp2_common/pico_stdio_usb/CMakeLists.txt @@ -13,9 +13,10 @@ if (TARGET tinyusb_device_unmarked) tinyusb_device_unmarked pico_stdio pico_time + pico_unique_id ) target_compile_definitions(pico_stdio_usb INTERFACE PICO_STDIO_USB=1 ) -endif() \ No newline at end of file +endif() diff --git a/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c b/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c index c66df42a4..bde9db20f 100644 --- a/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c +++ b/src/rp2_common/pico_stdio_usb/stdio_usb_descriptors.c @@ -30,6 +30,7 @@ #include "tusb.h" #include "pico/stdio_usb/reset_interface.h" +#include "pico/unique_id.h" #define USBD_VID (0x2E8A) // Raspberry Pi #define USBD_PID (0x000a) // Raspberry Pi Pico SDK CDC @@ -98,10 +99,12 @@ static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = { #endif }; +static char usbd_serial_str[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1]; + static const char *const usbd_desc_str[] = { [USBD_STR_MANUF] = "Raspberry Pi", [USBD_STR_PRODUCT] = "Pico", - [USBD_STR_SERIAL] = "000000000000", // TODO + [USBD_STR_SERIAL] = usbd_serial_str, [USBD_STR_CDC] = "Board CDC", #if PICO_STDIO_USB_ENABLE_RESET_VIA_VENDOR_INTERFACE [USBD_STR_RPI_RESET] = "Reset", @@ -121,6 +124,18 @@ const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { #define DESC_STR_MAX (20) static uint16_t desc_str[DESC_STR_MAX]; + // lazy update the serial number if not set yet + if (!usbd_serial_str[0]) { + pico_unique_board_id_t id; + pico_get_unique_board_id(&id); + + for (int i = 0; i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES; i++) { + char hx[3]; + sprintf(hx, "%02X", id.id[i]); + strcat(usbd_serial_str, hx); + } + } + uint8_t len; if (index == 0) { desc_str[1] = 0x0409; // supported language is English @@ -141,4 +156,4 @@ const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) { return desc_str; } -#endif \ No newline at end of file +#endif