mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-09-20 22:55:00 +08:00
add instrumentation to monitor interrupts
This commit is contained in:
@@ -37,7 +37,7 @@
|
||||
#include "cmsis_os.h"
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
#include <Drivers/STM32/stm32_system.h>
|
||||
/* USER CODE END 0 */
|
||||
|
||||
/* External variables --------------------------------------------------------*/
|
||||
@@ -67,7 +67,7 @@ extern TIM_HandleTypeDef htim14;
|
||||
void NMI_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(NonMaskableInt_IRQn);
|
||||
/* USER CODE END NonMaskableInt_IRQn 0 */
|
||||
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
|
||||
|
||||
@@ -110,7 +110,7 @@ void HardFault_Handler(void)
|
||||
void MemManage_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN MemoryManagement_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(MemoryManagement_IRQn);
|
||||
/* USER CODE END MemoryManagement_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
@@ -128,7 +128,7 @@ void MemManage_Handler(void)
|
||||
void BusFault_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN BusFault_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(BusFault_IRQn);
|
||||
/* USER CODE END BusFault_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
@@ -146,7 +146,7 @@ void BusFault_Handler(void)
|
||||
void UsageFault_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN UsageFault_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(UsageFault_IRQn);
|
||||
/* USER CODE END UsageFault_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
@@ -164,7 +164,7 @@ void UsageFault_Handler(void)
|
||||
void DebugMon_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DebugMonitor_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(DebugMonitor_IRQn);
|
||||
/* USER CODE END DebugMonitor_IRQn 0 */
|
||||
/* USER CODE BEGIN DebugMonitor_IRQn 1 */
|
||||
|
||||
@@ -177,7 +177,7 @@ void DebugMon_Handler(void)
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN SysTick_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(SysTick_IRQn);
|
||||
/* USER CODE END SysTick_IRQn 0 */
|
||||
osSystickHandler();
|
||||
/* USER CODE BEGIN SysTick_IRQn 1 */
|
||||
@@ -198,7 +198,7 @@ void SysTick_Handler(void)
|
||||
void DMA1_Stream0_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DMA1_Stream0_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(DMA1_Stream0_IRQn);
|
||||
/* USER CODE END DMA1_Stream0_IRQn 0 */
|
||||
HAL_DMA_IRQHandler(&hdma_spi3_rx);
|
||||
/* USER CODE BEGIN DMA1_Stream0_IRQn 1 */
|
||||
@@ -212,7 +212,7 @@ void DMA1_Stream0_IRQHandler(void)
|
||||
void DMA1_Stream2_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DMA1_Stream2_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(DMA1_Stream2_IRQn);
|
||||
/* USER CODE END DMA1_Stream2_IRQn 0 */
|
||||
HAL_DMA_IRQHandler(&hdma_uart4_rx);
|
||||
/* USER CODE BEGIN DMA1_Stream2_IRQn 1 */
|
||||
@@ -226,7 +226,7 @@ void DMA1_Stream2_IRQHandler(void)
|
||||
void DMA1_Stream4_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DMA1_Stream4_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(DMA1_Stream4_IRQn);
|
||||
/* USER CODE END DMA1_Stream4_IRQn 0 */
|
||||
HAL_DMA_IRQHandler(&hdma_uart4_tx);
|
||||
/* USER CODE BEGIN DMA1_Stream4_IRQn 1 */
|
||||
@@ -240,7 +240,7 @@ void DMA1_Stream4_IRQHandler(void)
|
||||
void DMA1_Stream5_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN DMA1_Stream5_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(DMA1_Stream5_IRQn);
|
||||
/* USER CODE END DMA1_Stream5_IRQn 0 */
|
||||
HAL_DMA_IRQHandler(&hdma_spi3_tx);
|
||||
/* USER CODE BEGIN DMA1_Stream5_IRQn 1 */
|
||||
@@ -254,7 +254,7 @@ void DMA1_Stream5_IRQHandler(void)
|
||||
void CAN1_TX_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN CAN1_TX_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(CAN1_TX_IRQn);
|
||||
/* USER CODE END CAN1_TX_IRQn 0 */
|
||||
HAL_CAN_IRQHandler(&hcan1);
|
||||
/* USER CODE BEGIN CAN1_TX_IRQn 1 */
|
||||
@@ -268,7 +268,7 @@ void CAN1_TX_IRQHandler(void)
|
||||
void CAN1_RX0_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN CAN1_RX0_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(CAN1_RX0_IRQn);
|
||||
/* USER CODE END CAN1_RX0_IRQn 0 */
|
||||
HAL_CAN_IRQHandler(&hcan1);
|
||||
/* USER CODE BEGIN CAN1_RX0_IRQn 1 */
|
||||
@@ -282,7 +282,7 @@ void CAN1_RX0_IRQHandler(void)
|
||||
void CAN1_RX1_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN CAN1_RX1_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(CAN1_RX1_IRQn);
|
||||
/* USER CODE END CAN1_RX1_IRQn 0 */
|
||||
HAL_CAN_IRQHandler(&hcan1);
|
||||
/* USER CODE BEGIN CAN1_RX1_IRQn 1 */
|
||||
@@ -296,7 +296,7 @@ void CAN1_RX1_IRQHandler(void)
|
||||
void CAN1_SCE_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN CAN1_SCE_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(CAN1_SCE_IRQn);
|
||||
/* USER CODE END CAN1_SCE_IRQn 0 */
|
||||
HAL_CAN_IRQHandler(&hcan1);
|
||||
/* USER CODE BEGIN CAN1_SCE_IRQn 1 */
|
||||
@@ -310,7 +310,7 @@ void CAN1_SCE_IRQHandler(void)
|
||||
void TIM8_TRG_COM_TIM14_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN TIM8_TRG_COM_TIM14_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(TIM8_TRG_COM_TIM14_IRQn);
|
||||
/* USER CODE END TIM8_TRG_COM_TIM14_IRQn 0 */
|
||||
HAL_TIM_IRQHandler(&htim8);
|
||||
HAL_TIM_IRQHandler(&htim14);
|
||||
@@ -325,7 +325,7 @@ void TIM8_TRG_COM_TIM14_IRQHandler(void)
|
||||
void SPI3_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN SPI3_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(SPI3_IRQn);
|
||||
/* USER CODE END SPI3_IRQn 0 */
|
||||
HAL_SPI_IRQHandler(&hspi3);
|
||||
/* USER CODE BEGIN SPI3_IRQn 1 */
|
||||
@@ -339,7 +339,7 @@ void SPI3_IRQHandler(void)
|
||||
void UART4_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN UART4_IRQn 0 */
|
||||
|
||||
COUNT_IRQ(UART4_IRQn);
|
||||
/* USER CODE END UART4_IRQn 0 */
|
||||
HAL_UART_IRQHandler(&huart4);
|
||||
/* USER CODE BEGIN UART4_IRQn 1 */
|
||||
|
||||
@@ -355,16 +355,19 @@ void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) {
|
||||
|
||||
|
||||
void TIM1_UP_TIM10_IRQHandler(void) {
|
||||
COUNT_IRQ(TIM1_UP_TIM10_IRQn);
|
||||
__HAL_TIM_CLEAR_IT(&htim1, TIM_IT_UPDATE);
|
||||
motors[0].tim_update_cb();
|
||||
}
|
||||
|
||||
void TIM8_UP_TIM13_IRQHandler(void) {
|
||||
COUNT_IRQ(TIM8_UP_TIM13_IRQn);
|
||||
__HAL_TIM_CLEAR_IT(&htim8, TIM_IT_UPDATE);
|
||||
motors[1].tim_update_cb();
|
||||
}
|
||||
|
||||
void TIM5_IRQHandler(void) {
|
||||
COUNT_IRQ(TIM5_IRQn);
|
||||
pwm0_input.on_capture();
|
||||
}
|
||||
|
||||
@@ -386,6 +389,8 @@ void ADC_IRQ_Dispatch(ADC_HandleTypeDef* hadc, void(*callback)(ADC_HandleTypeDef
|
||||
}
|
||||
|
||||
void ADC_IRQHandler(void) {
|
||||
COUNT_IRQ(ADC_IRQn);
|
||||
|
||||
// The HAL's ADC handling mechanism adds many clock cycles of overhead
|
||||
// So we bypass it and handle the logic ourselves.
|
||||
//@TODO add vbus measurement on adc1 here
|
||||
@@ -395,14 +400,17 @@ void ADC_IRQHandler(void) {
|
||||
}
|
||||
|
||||
void I2C1_EV_IRQHandler(void) {
|
||||
HAL_I2C_EV_IRQHandler(&hi2c1);
|
||||
COUNT_IRQ(I2C1_EV_IRQn);
|
||||
HAL_I2C_EV_IRQHandler(&hi2c1);
|
||||
}
|
||||
|
||||
void I2C1_ER_IRQHandler(void) {
|
||||
HAL_I2C_ER_IRQHandler(&hi2c1);
|
||||
COUNT_IRQ(I2C1_ER_IRQn);
|
||||
HAL_I2C_ER_IRQHandler(&hi2c1);
|
||||
}
|
||||
|
||||
void OTG_FS_IRQHandler(void) {
|
||||
COUNT_IRQ(OTG_FS_IRQn);
|
||||
// Mask interrupt, and signal processing of interrupt by usb_cmd_thread
|
||||
// The thread will re-enable the interrupt when all pending irqs are clear.
|
||||
HAL_NVIC_DisableIRQ(OTG_FS_IRQn);
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
#include "stm32_system.h"
|
||||
|
||||
uint32_t irq_counters[254]; // 14 core interrupts, 240 NVIC interrupts
|
||||
@@ -13,6 +13,19 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Uncomment the following line to sacrifice 1kB of RAM for the ability to
|
||||
// monitor the number of times each interrupt fires.
|
||||
//#define ENABLE_IRQ_COUNTER
|
||||
|
||||
#ifdef ENABLE_IRQ_COUNTER
|
||||
extern uint32_t irq_counters[];
|
||||
#define COUNT_IRQ(irqn) (++irq_counters[irqn + 14])
|
||||
#define GET_IRQ_COUNTER(irqn) irq_counters[irqn + 14]
|
||||
#else
|
||||
#define COUNT_IRQ(irqn) ((void)0)
|
||||
#define GET_IRQ_COUNTER(irqn) 0
|
||||
#endif
|
||||
|
||||
static inline uint32_t cpu_enter_critical() {
|
||||
uint32_t primask = __get_PRIMASK();
|
||||
__disable_irq();
|
||||
|
||||
@@ -180,6 +180,22 @@ public:
|
||||
Axis& get_axis(int num) { return axes[num]; }
|
||||
ODriveCAN& get_can() { return *odCAN; }
|
||||
|
||||
uint32_t get_interrupt_status(int32_t irqn) {
|
||||
if ((irqn < -14) || (irqn >= 240)) {
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
uint8_t priority = (irqn < -12)
|
||||
? 0 // hard fault and NMI always have maximum priority
|
||||
: NVIC_GetPriority((IRQn_Type)irqn);
|
||||
uint32_t counter = GET_IRQ_COUNTER((IRQn_Type)irqn);
|
||||
bool is_enabled = (irqn < 0)
|
||||
? true // processor interrupt vectors are always enabled
|
||||
: NVIC->ISER[(((uint32_t)(int32_t)irqn) >> 5UL)] & (uint32_t)(1UL << (((uint32_t)(int32_t)irqn) & 0x1FUL));
|
||||
|
||||
return priority | ((counter & 0x7ffffff) << 8) | (is_enabled ? 0x80000000 : 0);
|
||||
}
|
||||
|
||||
float& vbus_voltage_ = ::vbus_voltage; // TODO: make this the actual variable
|
||||
float& ibus_ = ::ibus_; // TODO: make this the actual variable
|
||||
float ibus_report_filter_k_ = 1.0f;
|
||||
|
||||
@@ -196,6 +196,7 @@ sources = {
|
||||
'MotorControl/trapTraj.cpp',
|
||||
'MotorControl/pwm_input.cpp',
|
||||
'MotorControl/main.cpp',
|
||||
'Drivers/STM32/stm32_system.cpp',
|
||||
'Drivers/STM32/stm32_gpio.cpp',
|
||||
'Drivers/STM32/stm32_nvm.c',
|
||||
'Drivers/STM32/stm32_spi_arbiter.cpp',
|
||||
|
||||
@@ -241,6 +241,17 @@ interfaces:
|
||||
erase_configuration:
|
||||
reboot:
|
||||
enter_dfu_mode:
|
||||
get_interrupt_status:
|
||||
in: {irqn: {type: int32, doc: '-12...-1: processor interrupts, 0...239: NVIC interrupts'}}
|
||||
out:
|
||||
status:
|
||||
type: uint32
|
||||
doc: |
|
||||
bit 31: enabled (1) or disabled (0)
|
||||
bits 30:8: number of times the interrupt fired (modulo 0x800000)
|
||||
bits 7:0: priority (0 is highest priority)
|
||||
0xffffffff if the specified number is not a valid interrupt number.
|
||||
doc: Returns information about the specified interrupt number.
|
||||
|
||||
ODrive.Can:
|
||||
c_is_class: True
|
||||
|
||||
@@ -5,7 +5,7 @@ import threading
|
||||
import fibre
|
||||
import odrive
|
||||
import odrive.enums
|
||||
from odrive.utils import calculate_thermistor_coeffs, set_motor_thermistor_coeffs, start_liveplotter, dump_errors, oscilloscope_dump, BulkCapture, step_and_plot
|
||||
from odrive.utils import calculate_thermistor_coeffs, set_motor_thermistor_coeffs, start_liveplotter, dump_errors, dump_interrupts, oscilloscope_dump, BulkCapture, step_and_plot
|
||||
|
||||
def print_banner():
|
||||
print("Website: https://odriverobotics.com/")
|
||||
@@ -85,6 +85,7 @@ def launch_shell(args, logger, app_shutdown_token):
|
||||
'start_liveplotter': start_liveplotter,
|
||||
'dump_errors': dump_errors,
|
||||
'oscilloscope_dump': oscilloscope_dump,
|
||||
'dump_interrupts': dump_interrupts,
|
||||
'BulkCapture': BulkCapture,
|
||||
'step_and_plot': step_and_plot,
|
||||
'calculate_thermistor_coeffs': calculate_thermistor_coeffs,
|
||||
|
||||
@@ -361,3 +361,113 @@ def yes_no_prompt(question, default=None):
|
||||
return False
|
||||
elif choice == '' and default is not None:
|
||||
return default
|
||||
|
||||
def dump_interrupts(odrv):
|
||||
interrupts = [
|
||||
(-12, "MemoryManagement_IRQn"),
|
||||
(-11, "BusFault_IRQn"),
|
||||
(-10, "UsageFault_IRQn"),
|
||||
(-5, "SVCall_IRQn"),
|
||||
(-4, "DebugMonitor_IRQn"),
|
||||
(-2, "PendSV_IRQn"),
|
||||
(-1, "SysTick_IRQn"),
|
||||
(0, "WWDG_IRQn"),
|
||||
(1, "PVD_IRQn"),
|
||||
(2, "TAMP_STAMP_IRQn"),
|
||||
(3, "RTC_WKUP_IRQn"),
|
||||
(4, "FLASH_IRQn"),
|
||||
(5, "RCC_IRQn"),
|
||||
(6, "EXTI0_IRQn"),
|
||||
(7, "EXTI1_IRQn"),
|
||||
(8, "EXTI2_IRQn"),
|
||||
(9, "EXTI3_IRQn"),
|
||||
(10, "EXTI4_IRQn"),
|
||||
(11, "DMA1_Stream0_IRQn"),
|
||||
(12, "DMA1_Stream1_IRQn"),
|
||||
(13, "DMA1_Stream2_IRQn"),
|
||||
(14, "DMA1_Stream3_IRQn"),
|
||||
(15, "DMA1_Stream4_IRQn"),
|
||||
(16, "DMA1_Stream5_IRQn"),
|
||||
(17, "DMA1_Stream6_IRQn"),
|
||||
(18, "ADC_IRQn"),
|
||||
(19, "CAN1_TX_IRQn"),
|
||||
(20, "CAN1_RX0_IRQn"),
|
||||
(21, "CAN1_RX1_IRQn"),
|
||||
(22, "CAN1_SCE_IRQn"),
|
||||
(23, "EXTI9_5_IRQn"),
|
||||
(24, "TIM1_BRK_TIM9_IRQn"),
|
||||
(25, "TIM1_UP_TIM10_IRQn"),
|
||||
(26, "TIM1_TRG_COM_TIM11_IRQn"),
|
||||
(27, "TIM1_CC_IRQn"),
|
||||
(28, "TIM2_IRQn"),
|
||||
(29, "TIM3_IRQn"),
|
||||
(30, "TIM4_IRQn"),
|
||||
(31, "I2C1_EV_IRQn"),
|
||||
(32, "I2C1_ER_IRQn"),
|
||||
(33, "I2C2_EV_IRQn"),
|
||||
(34, "I2C2_ER_IRQn"),
|
||||
(35, "SPI1_IRQn"),
|
||||
(36, "SPI2_IRQn"),
|
||||
(37, "USART1_IRQn"),
|
||||
(38, "USART2_IRQn"),
|
||||
(39, "USART3_IRQn"),
|
||||
(40, "EXTI15_10_IRQn"),
|
||||
(41, "RTC_Alarm_IRQn"),
|
||||
(42, "OTG_FS_WKUP_IRQn"),
|
||||
(43, "TIM8_BRK_TIM12_IRQn"),
|
||||
(44, "TIM8_UP_TIM13_IRQn"),
|
||||
(45, "TIM8_TRG_COM_TIM14_IRQn"),
|
||||
(46, "TIM8_CC_IRQn"),
|
||||
(47, "DMA1_Stream7_IRQn"),
|
||||
(48, "FMC_IRQn"),
|
||||
(49, "SDMMC1_IRQn"),
|
||||
(50, "TIM5_IRQn"),
|
||||
(51, "SPI3_IRQn"),
|
||||
(52, "UART4_IRQn"),
|
||||
(53, "UART5_IRQn"),
|
||||
(54, "TIM6_DAC_IRQn"),
|
||||
(55, "TIM7_IRQn"),
|
||||
(56, "DMA2_Stream0_IRQn"),
|
||||
(57, "DMA2_Stream1_IRQn"),
|
||||
(58, "DMA2_Stream2_IRQn"),
|
||||
(59, "DMA2_Stream3_IRQn"),
|
||||
(60, "DMA2_Stream4_IRQn"),
|
||||
(61, "ETH_IRQn"),
|
||||
(62, "ETH_WKUP_IRQn"),
|
||||
(63, "CAN2_TX_IRQn"),
|
||||
(64, "CAN2_RX0_IRQn"),
|
||||
(65, "CAN2_RX1_IRQn"),
|
||||
(66, "CAN2_SCE_IRQn"),
|
||||
(67, "OTG_FS_IRQn"),
|
||||
(68, "DMA2_Stream5_IRQn"),
|
||||
(69, "DMA2_Stream6_IRQn"),
|
||||
(70, "DMA2_Stream7_IRQn"),
|
||||
(71, "USART6_IRQn"),
|
||||
(72, "I2C3_EV_IRQn"),
|
||||
(73, "I2C3_ER_IRQn"),
|
||||
(74, "OTG_HS_EP1_OUT_IRQn"),
|
||||
(75, "OTG_HS_EP1_IN_IRQn"),
|
||||
(76, "OTG_HS_WKUP_IRQn"),
|
||||
(77, "OTG_HS_IRQn"),
|
||||
# gap
|
||||
(80, "RNG_IRQn"),
|
||||
(81, "FPU_IRQn"),
|
||||
(82, "UART7_IRQn"),
|
||||
(83, "UART8_IRQn"),
|
||||
(84, "SPI4_IRQn"),
|
||||
(85, "SPI5_IRQn"),
|
||||
# gap
|
||||
(87, "SAI1_IRQn"),
|
||||
# gap
|
||||
(91, "SAI2_IRQn"),
|
||||
(92, "QUADSPI_IRQn"),
|
||||
(93, "LPTIM1_IRQn"),
|
||||
# gap
|
||||
(103, "SDMMC2_IRQn")
|
||||
]
|
||||
|
||||
print(" # Name En Prio Count")
|
||||
for irqn, irq_name in interrupts:
|
||||
status = odrv.get_interrupt_status(irqn)
|
||||
if (status != 0):
|
||||
print(str(irqn).rjust(3) + " " + irq_name.ljust(23) + " " + str("*" if (status & 0x80000000) else " ") + " " + str(status & 0xff).rjust(4) + " " + str((status >> 8) & 0x7fffff).rjust(7))
|
||||
|
||||
Reference in New Issue
Block a user