Commit 401af50d authored by Damien George's avatar Damien George
Browse files

stmhal: Add pyb.irq_stats() to get statistics about IRQ calls.

Adds a lot of code, makes IRQs a bit less efficient, but is very useful
for debugging.  Usage: pyb.irq_stats() returns a memory view that can be
read and written, eg:

    list(pyb.irq_stats())
    pyb.irq_stats()[0]
    pyb.irq_stats()[0] = 0

The patch provides general IRQ_ENTER() and IRQ_EXIT() macros that can be
modified to provide further IRQ statistics if desired.
parent abd0fcfc
......@@ -86,22 +86,22 @@ volatile dma_idle_count_t dma_idle;
#define DMA_CHANNEL_AS_UINT8(dma_channel) (((dma_channel) & DMA_SxCR_CHSEL) >> 24)
void DMA1_Stream0_IRQHandler(void) { if (dma_handle[0] != NULL) { HAL_DMA_IRQHandler(dma_handle[0]); } }
void DMA1_Stream1_IRQHandler(void) { if (dma_handle[1] != NULL) { HAL_DMA_IRQHandler(dma_handle[1]); } }
void DMA1_Stream2_IRQHandler(void) { if (dma_handle[2] != NULL) { HAL_DMA_IRQHandler(dma_handle[2]); } }
void DMA1_Stream3_IRQHandler(void) { if (dma_handle[3] != NULL) { HAL_DMA_IRQHandler(dma_handle[3]); } }
void DMA1_Stream4_IRQHandler(void) { if (dma_handle[4] != NULL) { HAL_DMA_IRQHandler(dma_handle[4]); } }
void DMA1_Stream5_IRQHandler(void) { if (dma_handle[5] != NULL) { HAL_DMA_IRQHandler(dma_handle[5]); } }
void DMA1_Stream6_IRQHandler(void) { if (dma_handle[6] != NULL) { HAL_DMA_IRQHandler(dma_handle[6]); } }
void DMA1_Stream7_IRQHandler(void) { if (dma_handle[7] != NULL) { HAL_DMA_IRQHandler(dma_handle[7]); } }
void DMA2_Stream0_IRQHandler(void) { if (dma_handle[8] != NULL) { HAL_DMA_IRQHandler(dma_handle[8]); } }
void DMA2_Stream1_IRQHandler(void) { if (dma_handle[9] != NULL) { HAL_DMA_IRQHandler(dma_handle[9]); } }
void DMA2_Stream2_IRQHandler(void) { if (dma_handle[10] != NULL) { HAL_DMA_IRQHandler(dma_handle[10]); } }
void DMA2_Stream3_IRQHandler(void) { if (dma_handle[11] != NULL) { HAL_DMA_IRQHandler(dma_handle[11]); } }
void DMA2_Stream4_IRQHandler(void) { if (dma_handle[12] != NULL) { HAL_DMA_IRQHandler(dma_handle[12]); } }
void DMA2_Stream5_IRQHandler(void) { if (dma_handle[13] != NULL) { HAL_DMA_IRQHandler(dma_handle[13]); } }
void DMA2_Stream6_IRQHandler(void) { if (dma_handle[14] != NULL) { HAL_DMA_IRQHandler(dma_handle[14]); } }
void DMA2_Stream7_IRQHandler(void) { if (dma_handle[15] != NULL) { HAL_DMA_IRQHandler(dma_handle[15]); } }
void DMA1_Stream0_IRQHandler(void) { IRQ_ENTER(DMA1_Stream0_IRQn); if (dma_handle[0] != NULL) { HAL_DMA_IRQHandler(dma_handle[0]); } IRQ_EXIT(DMA1_Stream0_IRQn); }
void DMA1_Stream1_IRQHandler(void) { IRQ_ENTER(DMA1_Stream1_IRQn); if (dma_handle[1] != NULL) { HAL_DMA_IRQHandler(dma_handle[1]); } IRQ_EXIT(DMA1_Stream1_IRQn); }
void DMA1_Stream2_IRQHandler(void) { IRQ_ENTER(DMA1_Stream2_IRQn); if (dma_handle[2] != NULL) { HAL_DMA_IRQHandler(dma_handle[2]); } IRQ_EXIT(DMA1_Stream2_IRQn); }
void DMA1_Stream3_IRQHandler(void) { IRQ_ENTER(DMA1_Stream3_IRQn); if (dma_handle[3] != NULL) { HAL_DMA_IRQHandler(dma_handle[3]); } IRQ_EXIT(DMA1_Stream3_IRQn); }
void DMA1_Stream4_IRQHandler(void) { IRQ_ENTER(DMA1_Stream4_IRQn); if (dma_handle[4] != NULL) { HAL_DMA_IRQHandler(dma_handle[4]); } IRQ_EXIT(DMA1_Stream4_IRQn); }
void DMA1_Stream5_IRQHandler(void) { IRQ_ENTER(DMA1_Stream5_IRQn); if (dma_handle[5] != NULL) { HAL_DMA_IRQHandler(dma_handle[5]); } IRQ_EXIT(DMA1_Stream5_IRQn); }
void DMA1_Stream6_IRQHandler(void) { IRQ_ENTER(DMA1_Stream6_IRQn); if (dma_handle[6] != NULL) { HAL_DMA_IRQHandler(dma_handle[6]); } IRQ_EXIT(DMA1_Stream6_IRQn); }
void DMA1_Stream7_IRQHandler(void) { IRQ_ENTER(DMA1_Stream7_IRQn); if (dma_handle[7] != NULL) { HAL_DMA_IRQHandler(dma_handle[7]); } IRQ_EXIT(DMA1_Stream7_IRQn); }
void DMA2_Stream0_IRQHandler(void) { IRQ_ENTER(DMA2_Stream0_IRQn); if (dma_handle[8] != NULL) { HAL_DMA_IRQHandler(dma_handle[8]); } IRQ_EXIT(DMA2_Stream0_IRQn); }
void DMA2_Stream1_IRQHandler(void) { IRQ_ENTER(DMA2_Stream1_IRQn); if (dma_handle[9] != NULL) { HAL_DMA_IRQHandler(dma_handle[9]); } IRQ_EXIT(DMA2_Stream1_IRQn); }
void DMA2_Stream2_IRQHandler(void) { IRQ_ENTER(DMA2_Stream2_IRQn); if (dma_handle[10] != NULL) { HAL_DMA_IRQHandler(dma_handle[10]); } IRQ_EXIT(DMA2_Stream2_IRQn); }
void DMA2_Stream3_IRQHandler(void) { IRQ_ENTER(DMA2_Stream3_IRQn); if (dma_handle[11] != NULL) { HAL_DMA_IRQHandler(dma_handle[11]); } IRQ_EXIT(DMA2_Stream3_IRQn); }
void DMA2_Stream4_IRQHandler(void) { IRQ_ENTER(DMA2_Stream4_IRQn); if (dma_handle[12] != NULL) { HAL_DMA_IRQHandler(dma_handle[12]); } IRQ_EXIT(DMA2_Stream4_IRQn); }
void DMA2_Stream5_IRQHandler(void) { IRQ_ENTER(DMA2_Stream5_IRQn); if (dma_handle[13] != NULL) { HAL_DMA_IRQHandler(dma_handle[13]); } IRQ_EXIT(DMA2_Stream5_IRQn); }
void DMA2_Stream6_IRQHandler(void) { IRQ_ENTER(DMA2_Stream6_IRQn); if (dma_handle[14] != NULL) { HAL_DMA_IRQHandler(dma_handle[14]); } IRQ_EXIT(DMA2_Stream6_IRQn); }
void DMA2_Stream7_IRQHandler(void) { IRQ_ENTER(DMA2_Stream7_IRQn); if (dma_handle[15] != NULL) { HAL_DMA_IRQHandler(dma_handle[15]); } IRQ_EXIT(DMA2_Stream7_IRQn); }
#define DMA1_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA1EN) != 0)
#define DMA2_IS_CLK_ENABLED() ((RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN) != 0)
......
......@@ -31,6 +31,10 @@
/// \moduleref pyb
#if IRQ_ENABLE_STATS
uint32_t irq_stats[FPU_IRQn + 1] = {0};
#endif
/// \function wfi()
/// Wait for an interrupt.
/// This executies a `wfi` instruction which reduces power consumption
......@@ -62,3 +66,11 @@ STATIC mp_obj_t pyb_enable_irq(uint n_args, const mp_obj_t *arg) {
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_enable_irq_obj, 0, 1, pyb_enable_irq);
#if IRQ_ENABLE_STATS
// return a memoryview of the irq statistics array
STATIC mp_obj_t pyb_irq_stats(void) {
return mp_obj_new_memoryview(0x80 | 'I', MP_ARRAY_SIZE(irq_stats), &irq_stats[0]);
}
MP_DEFINE_CONST_FUN_OBJ_0(pyb_irq_stats_obj, pyb_irq_stats);
#endif
......@@ -28,6 +28,19 @@
#define IRQ_STATE_DISABLED (0x00000001)
#define IRQ_STATE_ENABLED (0x00000000)
// Enable this to get a count for the number of times each irq handler is called,
// accessible via pyb.irq_stats().
#define IRQ_ENABLE_STATS (0)
#if IRQ_ENABLE_STATS
extern uint32_t irq_stats[FPU_IRQn + 1];
#define IRQ_ENTER(irq) ++irq_stats[irq]
#define IRQ_EXIT(irq)
#else
#define IRQ_ENTER(irq)
#define IRQ_EXIT(irq)
#endif
static inline mp_uint_t query_irq(void) {
return __get_PRIMASK();
}
......@@ -60,6 +73,7 @@ static inline void restore_irq_pri(uint32_t basepri) {
MP_DECLARE_CONST_FUN_OBJ(pyb_wfi_obj);
MP_DECLARE_CONST_FUN_OBJ(pyb_disable_irq_obj);
MP_DECLARE_CONST_FUN_OBJ(pyb_enable_irq_obj);
MP_DECLARE_CONST_FUN_OBJ(pyb_irq_stats_obj);
// IRQ priority definitions.
//
......
......@@ -139,6 +139,9 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_wfi), (mp_obj_t)&pyb_wfi_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_disable_irq), (mp_obj_t)&pyb_disable_irq_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_enable_irq), (mp_obj_t)&pyb_enable_irq_obj },
#if IRQ_ENABLE_STATS
{ MP_OBJ_NEW_QSTR(MP_QSTR_irq_stats), (mp_obj_t)&pyb_irq_stats_obj },
#endif
{ MP_OBJ_NEW_QSTR(MP_QSTR_stop), (mp_obj_t)&machine_sleep_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_standby), (mp_obj_t)&machine_deepsleep_obj },
......
......@@ -40,6 +40,7 @@ Q(wfi)
Q(disable_irq)
Q(enable_irq)
Q(reset)
Q(irq_stats)
Q(stop)
Q(standby)
Q(idle)
......
......@@ -196,7 +196,9 @@ uint64_t sdcard_get_capacity_in_bytes(void) {
}
void SDIO_IRQHandler(void) {
IRQ_ENTER(SDIO_IRQn);
HAL_SD_IRQHandler(&sd_handle);
IRQ_EXIT(SDIO_IRQn);
}
mp_uint_t sdcard_read_blocks(uint8_t *dest, uint32_t block_num, uint32_t num_blocks) {
......
......@@ -72,6 +72,7 @@
#include "py/obj.h"
#include "pendsv.h"
#include "irq.h"
#include "extint.h"
#include "timer.h"
#include "uart.h"
......@@ -306,12 +307,16 @@ void SysTick_Handler(void) {
*/
#if defined(USE_USB_FS)
void OTG_FS_IRQHandler(void) {
IRQ_ENTER(OTG_FS_IRQn);
HAL_PCD_IRQHandler(&pcd_fs_handle);
IRQ_EXIT(OTG_FS_IRQn);
}
#endif
#if defined(USE_USB_HS)
void OTG_HS_IRQHandler(void) {
IRQ_ENTER(OTG_HS_IRQn);
HAL_PCD_IRQHandler(&pcd_hs_handle);
IRQ_EXIT(OTG_HS_IRQn);
}
#endif
......@@ -363,12 +368,14 @@ STATIC void OTG_CMD_WKUP_Handler(PCD_HandleTypeDef *pcd_handle) {
* @retval None
*/
void OTG_FS_WKUP_IRQHandler(void) {
IRQ_ENTER(OTG_FS_WKUP_IRQn);
OTG_CMD_WKUP_Handler(&pcd_fs_handle);
/* Clear EXTI pending Bit*/
__HAL_USB_FS_EXTI_CLEAR_FLAG();
IRQ_EXIT(OTG_FS_WKUP_IRQn);
}
#endif
......@@ -379,12 +386,14 @@ void OTG_FS_WKUP_IRQHandler(void) {
* @retval None
*/
void OTG_HS_WKUP_IRQHandler(void) {
IRQ_ENTER(OTG_HS_WKUP_IRQn);
OTG_CMD_WKUP_Handler(&pcd_hs_handle);
/* Clear EXTI pending Bit*/
__HAL_USB_HS_EXTI_CLEAR_FLAG();
IRQ_EXIT(OTG_HS_WKUP_IRQn);
}
#endif
......@@ -399,6 +408,7 @@ void OTG_HS_WKUP_IRQHandler(void) {
// Handle a flash (erase/program) interrupt.
void FLASH_IRQHandler(void) {
IRQ_ENTER(FLASH_IRQn);
// This calls the real flash IRQ handler, if needed
/*
uint32_t flash_cr = FLASH->CR;
......@@ -408,6 +418,7 @@ void FLASH_IRQHandler(void) {
*/
// This call the storage IRQ handler, to check if the flash cache needs flushing
storage_irq_handler();
IRQ_EXIT(FLASH_IRQn);
}
/**
......@@ -416,163 +427,231 @@ void FLASH_IRQHandler(void) {
* @retval None
*/
void EXTI0_IRQHandler(void) {
IRQ_ENTER(EXTI0_IRQn);
Handle_EXTI_Irq(0);
IRQ_EXIT(EXTI0_IRQn);
}
void EXTI1_IRQHandler(void) {
IRQ_ENTER(EXTI1_IRQn);
Handle_EXTI_Irq(1);
IRQ_EXIT(EXTI1_IRQn);
}
void EXTI2_IRQHandler(void) {
IRQ_ENTER(EXTI2_IRQn);
Handle_EXTI_Irq(2);
IRQ_EXIT(EXTI2_IRQn);
}
void EXTI3_IRQHandler(void) {
IRQ_ENTER(EXTI3_IRQn);
Handle_EXTI_Irq(3);
IRQ_EXIT(EXTI3_IRQn);
}
void EXTI4_IRQHandler(void) {
IRQ_ENTER(EXTI4_IRQn);
Handle_EXTI_Irq(4);
IRQ_EXIT(EXTI4_IRQn);
}
void EXTI9_5_IRQHandler(void) {
IRQ_ENTER(EXTI9_5_IRQn);
Handle_EXTI_Irq(5);
Handle_EXTI_Irq(6);
Handle_EXTI_Irq(7);
Handle_EXTI_Irq(8);
Handle_EXTI_Irq(9);
IRQ_EXIT(EXTI9_5_IRQn);
}
void EXTI15_10_IRQHandler(void) {
IRQ_ENTER(EXTI15_10_IRQn);
Handle_EXTI_Irq(10);
Handle_EXTI_Irq(11);
Handle_EXTI_Irq(12);
Handle_EXTI_Irq(13);
Handle_EXTI_Irq(14);
Handle_EXTI_Irq(15);
IRQ_EXIT(EXTI15_10_IRQn);
}
void PVD_IRQHandler(void) {
IRQ_ENTER(PVD_IRQn);
#if defined(MICROPY_HW_USE_ALT_IRQ_FOR_CDC)
extern void USBD_CDC_HAL_TIM_PeriodElapsedCallback(void);
USBD_CDC_HAL_TIM_PeriodElapsedCallback();
#endif
Handle_EXTI_Irq(EXTI_PVD_OUTPUT);
IRQ_EXIT(PVD_IRQn);
}
void RTC_Alarm_IRQHandler(void) {
IRQ_ENTER(RTC_Alarm_IRQn);
Handle_EXTI_Irq(EXTI_RTC_ALARM);
IRQ_EXIT(RTC_Alarm_IRQn);
}
#if defined(ETH) // The 407 has ETH, the 405 doesn't
void ETH_WKUP_IRQHandler(void) {
IRQ_ENTER(ETH_WKUP_IRQn);
Handle_EXTI_Irq(EXTI_ETH_WAKEUP);
IRQ_EXIT(ETH_WKUP_IRQn);
}
#endif
void TAMP_STAMP_IRQHandler(void) {
IRQ_ENTER(TAMP_STAMP_IRQn);
Handle_EXTI_Irq(EXTI_RTC_TIMESTAMP);
IRQ_EXIT(TAMP_STAMP_IRQn);
}
void RTC_WKUP_IRQHandler(void) {
IRQ_ENTER(RTC_WKUP_IRQn);
RTC->ISR &= ~(1 << 10); // clear wakeup interrupt flag
Handle_EXTI_Irq(EXTI_RTC_WAKEUP); // clear EXTI flag and execute optional callback
IRQ_EXIT(RTC_WKUP_IRQn);
}
void TIM1_BRK_TIM9_IRQHandler(void) {
IRQ_ENTER(TIM1_BRK_TIM9_IRQn);
timer_irq_handler(9);
IRQ_EXIT(TIM1_BRK_TIM9_IRQn);
}
void TIM1_UP_TIM10_IRQHandler(void) {
IRQ_ENTER(TIM1_UP_TIM10_IRQn);
timer_irq_handler(1);
timer_irq_handler(10);
IRQ_EXIT(TIM1_UP_TIM10_IRQn);
}
void TIM1_TRG_COM_TIM11_IRQHandler(void) {
IRQ_ENTER(TIM1_TRG_COM_TIM11_IRQn);
timer_irq_handler(11);
IRQ_EXIT(TIM1_TRG_COM_TIM11_IRQn);
}
void TIM2_IRQHandler(void) {
IRQ_ENTER(TIM2_IRQn);
timer_irq_handler(2);
IRQ_EXIT(TIM2_IRQn);
}
void TIM3_IRQHandler(void) {
IRQ_ENTER(TIM3_IRQn);
#if defined(MICROPY_HW_USE_ALT_IRQ_FOR_CDC)
timer_irq_handler(3);
#else
HAL_TIM_IRQHandler(&TIM3_Handle);
#endif
IRQ_EXIT(TIM3_IRQn);
}
void TIM4_IRQHandler(void) {
IRQ_ENTER(TIM4_IRQn);
timer_irq_handler(4);
IRQ_EXIT(TIM4_IRQn);
}
void TIM5_IRQHandler(void) {
IRQ_ENTER(TIM5_IRQn);
timer_irq_handler(5);
HAL_TIM_IRQHandler(&TIM5_Handle);
IRQ_EXIT(TIM5_IRQn);
}
void TIM6_DAC_IRQHandler(void) {
IRQ_ENTER(TIM6_DAC_IRQn);
timer_irq_handler(6);
IRQ_EXIT(TIM6_DAC_IRQn);
}
void TIM7_IRQHandler(void) {
IRQ_ENTER(TIM7_IRQn);
timer_irq_handler(7);
IRQ_EXIT(TIM7_IRQn);
}
void TIM8_BRK_TIM12_IRQHandler(void) {
IRQ_ENTER(TIM8_BRK_TIM12_IRQn);
timer_irq_handler(12);
IRQ_EXIT(TIM8_BRK_TIM12_IRQn);
}
void TIM8_UP_TIM13_IRQHandler(void) {
IRQ_ENTER(TIM8_UP_TIM13_IRQn);
timer_irq_handler(8);
timer_irq_handler(13);
IRQ_EXIT(TIM8_UP_TIM13_IRQn);
}
void TIM8_TRG_COM_TIM14_IRQHandler(void) {
IRQ_ENTER(TIM8_TRG_COM_TIM14_IRQn);
timer_irq_handler(14);
IRQ_EXIT(TIM8_TRG_COM_TIM14_IRQn);
}
// UART/USART IRQ handlers
void USART1_IRQHandler(void) {
IRQ_ENTER(USART1_IRQn);
uart_irq_handler(1);
IRQ_EXIT(USART1_IRQn);
}
void USART2_IRQHandler(void) {
IRQ_ENTER(USART2_IRQn);
uart_irq_handler(2);
IRQ_EXIT(USART2_IRQn);
}
void USART3_IRQHandler(void) {
IRQ_ENTER(USART3_IRQn);
uart_irq_handler(3);
IRQ_EXIT(USART3_IRQn);
}
void UART4_IRQHandler(void) {
IRQ_ENTER(UART4_IRQn);
uart_irq_handler(4);
IRQ_EXIT(UART4_IRQn);
}
void UART5_IRQHandler(void) {
IRQ_ENTER(UART5_IRQn);
uart_irq_handler(5);
IRQ_EXIT(UART5_IRQn);
}
void USART6_IRQHandler(void) {
IRQ_ENTER(USART6_IRQn);
uart_irq_handler(6);
IRQ_EXIT(USART6_IRQn);
}
#if MICROPY_HW_ENABLE_CAN
void CAN1_RX0_IRQHandler(void) {
IRQ_ENTER(CAN1_RX0_IRQn);
can_rx_irq_handler(PYB_CAN_1, CAN_FIFO0);
IRQ_EXIT(CAN1_RX0_IRQn);
}
void CAN1_RX1_IRQHandler(void) {
IRQ_ENTER(CAN1_RX1_IRQn);
can_rx_irq_handler(PYB_CAN_1, CAN_FIFO1);
IRQ_EXIT(CAN1_RX1_IRQn);
}
void CAN2_RX0_IRQHandler(void) {
IRQ_ENTER(CAN2_RX0_IRQn);
can_rx_irq_handler(PYB_CAN_2, CAN_FIFO0);
IRQ_EXIT(CAN2_RX0_IRQn);
}
void CAN2_RX1_IRQHandler(void) {
IRQ_ENTER(CAN2_RX1_IRQn);
can_rx_irq_handler(PYB_CAN_2, CAN_FIFO1);
IRQ_EXIT(CAN2_RX1_IRQn);
}
#endif // MICROPY_HW_ENABLE_CAN
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment