diff --git a/Firmware/MotorControl/main.cpp b/Firmware/MotorControl/main.cpp index cd76941d..510f68ab 100644 --- a/Firmware/MotorControl/main.cpp +++ b/Firmware/MotorControl/main.cpp @@ -177,20 +177,26 @@ void vApplicationIdleHook(void) { if (odrv.system_stats_.fully_booted) { odrv.system_stats_.uptime = xTaskGetTickCount(); odrv.system_stats_.min_heap_space = xPortGetMinimumEverFreeHeapSize(); + uint32_t min_stack_space[AXIS_COUNT]; std::transform(axes.begin(), axes.end(), std::begin(min_stack_space), [](auto& axis) { return uxTaskGetStackHighWaterMark(axis.thread_id_) * sizeof(StackType_t); }); - odrv.system_stats_.min_stack_space_axis = *std::min_element(std::begin(min_stack_space), std::end(min_stack_space)); - odrv.system_stats_.min_stack_space_usb = uxTaskGetStackHighWaterMark(usb_thread) * sizeof(StackType_t); - odrv.system_stats_.min_stack_space_uart = uxTaskGetStackHighWaterMark(uart_thread) * sizeof(StackType_t); - odrv.system_stats_.min_stack_space_startup = uxTaskGetStackHighWaterMark(defaultTaskHandle) * sizeof(StackType_t); - odrv.system_stats_.min_stack_space_can = uxTaskGetStackHighWaterMark(odCAN->thread_id_) * sizeof(StackType_t); + odrv.system_stats_.max_stack_usage_axis = axes[0].stack_size_ - *std::min_element(std::begin(min_stack_space), std::end(min_stack_space)); + odrv.system_stats_.max_stack_usage_usb = stack_size_usb_thread - uxTaskGetStackHighWaterMark(usb_thread) * sizeof(StackType_t); + odrv.system_stats_.max_stack_usage_uart = stack_size_uart_thread - uxTaskGetStackHighWaterMark(uart_thread) * sizeof(StackType_t); + odrv.system_stats_.max_stack_usage_startup = stack_size_default_task - uxTaskGetStackHighWaterMark(defaultTaskHandle) * sizeof(StackType_t); + odrv.system_stats_.max_stack_usage_can = odCAN->stack_size_ - uxTaskGetStackHighWaterMark(odCAN->thread_id_) * sizeof(StackType_t); - // Actual usage, in bytes, so we don't have to math - odrv.system_stats_.stack_usage_axis = axes[0].stack_size_ - odrv.system_stats_.min_stack_space_axis; - odrv.system_stats_.stack_usage_usb = stack_size_usb_thread - odrv.system_stats_.min_stack_space_usb; - odrv.system_stats_.stack_usage_uart = stack_size_uart_thread - odrv.system_stats_.min_stack_space_uart; - odrv.system_stats_.stack_usage_startup = stack_size_default_task - odrv.system_stats_.min_stack_space_startup; - odrv.system_stats_.stack_usage_can = odCAN->stack_size_ - odrv.system_stats_.min_stack_space_can; + odrv.system_stats_.stack_size_axis = axes[0].stack_size_; + odrv.system_stats_.stack_size_usb = stack_size_usb_thread; + odrv.system_stats_.stack_size_uart = stack_size_uart_thread; + odrv.system_stats_.stack_size_startup = stack_size_default_task; + odrv.system_stats_.stack_size_can = odCAN->stack_size_; + + odrv.system_stats_.prio_axis = osThreadGetPriority(axes[0].thread_id_); + odrv.system_stats_.prio_usb = osThreadGetPriority(usb_thread); + odrv.system_stats_.prio_uart = osThreadGetPriority(uart_thread); + odrv.system_stats_.prio_startup = osThreadGetPriority(defaultTaskHandle); + odrv.system_stats_.prio_can = osThreadGetPriority(odCAN->thread_id_); } } diff --git a/Firmware/MotorControl/odrive_main.h b/Firmware/MotorControl/odrive_main.h index 694f682d..57535b00 100644 --- a/Firmware/MotorControl/odrive_main.h +++ b/Firmware/MotorControl/odrive_main.h @@ -29,17 +29,23 @@ typedef struct { bool fully_booted; uint32_t uptime; // [ms] uint32_t min_heap_space; // FreeRTOS heap [Bytes] - uint32_t min_stack_space_axis; // minimum remaining space since startup [Bytes] - uint32_t min_stack_space_usb; - uint32_t min_stack_space_uart; - uint32_t min_stack_space_startup; - uint32_t min_stack_space_can; + uint32_t max_stack_usage_axis; // minimum remaining space since startup [Bytes] + uint32_t max_stack_usage_usb; + uint32_t max_stack_usage_uart; + uint32_t max_stack_usage_startup; + uint32_t max_stack_usage_can; - uint32_t stack_usage_axis; - uint32_t stack_usage_usb; - uint32_t stack_usage_uart; - uint32_t stack_usage_startup; - uint32_t stack_usage_can; + uint32_t stack_size_axis; + uint32_t stack_size_usb; + uint32_t stack_size_uart; + uint32_t stack_size_startup; + uint32_t stack_size_can; + + int32_t prio_axis; + int32_t prio_usb; + int32_t prio_uart; + int32_t prio_startup; + int32_t prio_can; USBStats_t& usb = usb_stats_; I2CStats_t& i2c = i2c_stats_; diff --git a/Firmware/odrive-interface.yaml b/Firmware/odrive-interface.yaml index 8dfde3e8..fd0ddf56 100644 --- a/Firmware/odrive-interface.yaml +++ b/Firmware/odrive-interface.yaml @@ -126,16 +126,21 @@ interfaces: attributes: uptime: readonly uint32 min_heap_space: readonly uint32 - min_stack_space_axis: readonly uint32 - min_stack_space_usb: readonly uint32 - min_stack_space_uart: readonly uint32 - min_stack_space_can: readonly uint32 - min_stack_space_startup: readonly uint32 - stack_usage_axis: readonly uint32 - stack_usage_usb: readonly uint32 - stack_usage_uart: readonly uint32 - stack_usage_startup: readonly uint32 - stack_usage_can: readonly uint32 + max_stack_usage_axis: readonly uint32 + max_stack_usage_usb: readonly uint32 + max_stack_usage_uart: readonly uint32 + max_stack_usage_can: readonly uint32 + max_stack_usage_startup: readonly uint32 + stack_size_axis: readonly uint32 + stack_size_usb: readonly uint32 + stack_size_uart: readonly uint32 + stack_size_startup: readonly uint32 + stack_size_can: readonly uint32 + prio_axis: readonly int32 + prio_usb: readonly int32 + prio_uart: readonly int32 + prio_startup: readonly int32 + prio_can: readonly int32 usb: c_is_class: False attributes: diff --git a/docs/resources.md b/docs/resources.md index dac2e0c7..bb35ff4b 100644 --- a/docs/resources.md +++ b/docs/resources.md @@ -1,5 +1,5 @@ -Most information in this file can be reproduced by running `dump_interrupts(odrv0)` and `dump_dma(odrv0)` in `odrivetool`. +Most information in this file can be reproduced by running `dump_interrupts(odrv0)`, `dump_dma(odrv0)` and `dump_threads(odrv0)` in `odrivetool` (minor manual postprocessing was applied to the output of those functions). Take this info with a grain of salt as we might forget to update it from time to time. When in doubt check the file history. @@ -55,3 +55,18 @@ Take this info with a grain of salt as we might forget to update it from time to | DMA1_Stream5 | 2 | 0 (SPI3_TX) | SPI | | DMA2_Stream0 | 0 | 0 (ADC1) | freerunning ADC | + +## Threads + + - lowest priority: -3 + - highest priority: 3 + +| Name | Stack Size [B] | Prio | +|---------|----------------|------| +| axis0 | 2048 | 3 | +| axis1 | 2048 | 2 | +| can | 1024 | 0 | +| startup | 2048 | 0 | +| uart | 4096 | 0 | +| usb | 4096 | 0 | + diff --git a/tools/odrive/shell.py b/tools/odrive/shell.py index e6fcb072..8f3274ea 100644 --- a/tools/odrive/shell.py +++ b/tools/odrive/shell.py @@ -86,6 +86,7 @@ def launch_shell(args, logger, app_shutdown_token): 'dump_errors': dump_errors, 'oscilloscope_dump': oscilloscope_dump, 'dump_interrupts': dump_interrupts, + 'dump_threads': dump_threads, 'dump_dma': dump_dma, 'dump_timing': dump_timing, 'BulkCapture': BulkCapture, diff --git a/tools/odrive/utils.py b/tools/odrive/utils.py index 1f211e75..b9fc8e9b 100755 --- a/tools/odrive/utils.py +++ b/tools/odrive/utils.py @@ -487,6 +487,25 @@ def dump_interrupts(odrv): " *" if (status & 0x80000000) else " ", str((status >> 8) & 0x7fffff).rjust(7))) +def dump_threads(odrv): + prefixes = ["max_stack_usage_", "stack_size_", "prio_"] + keys = [k[len(prefix):] for k in dir(odrv.system_stats) for prefix in prefixes if k.startswith(prefix)] + good_keys = set([k for k in set(keys) if keys.count(k) == len(prefixes)]) + if len(good_keys) > len(set(keys)): + print("Warning: incomplete thread information for threads {}".format(set(keys) - good_keys)) + + print("| Name | Stack Size [B] | Max Ever Stack Usage [B] | Prio |") + print("|---------|----------------|--------------------------|------|") + for k in sorted(good_keys): + sz = getattr(odrv.system_stats, "stack_size_" + k) + use = getattr(odrv.system_stats, "max_stack_usage_" + k) + print("| {} | {} | {} | {} |".format( + k.ljust(7), + str(sz).rjust(14), + "{} ({:.1f}%)".format(use, use / sz * 100).rjust(24), + str(getattr(odrv.system_stats, "prio_" + k)).rjust(4) + )) + def dump_dma(odrv): if odrv.hw_version_major == 3: