add instrumentation to monitor interrupts

This commit is contained in:
Samuel Sadok
2020-07-21 13:02:03 +02:00
parent 2d256f43cb
commit b7283bf1e0
9 changed files with 185 additions and 21 deletions
+18 -18
View File
@@ -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 */
+10 -2
View File
@@ -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);
+4
View File
@@ -0,0 +1,4 @@
#include "stm32_system.h"
uint32_t irq_counters[254]; // 14 core interrupts, 240 NVIC interrupts
+13
View File
@@ -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();
+16
View File
@@ -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;
+1
View File
@@ -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',
+11
View File
@@ -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
+2 -1
View File
@@ -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,
+110
View File
@@ -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))