ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SystemView 移植

SystemView 移植 前言我想要使用 SystemView 可以精确调试 FreeRTOS 系统而且调试接口是 SW 接口不使用串口进行 SystemView 调试。接下来我需要将 SystemView 移植到 STM32G473RCT6 中。如果想和我保持一致那么这里有一些需要准备的东西表1类别名称备注硬件ARM 仿真器我的版本是“高配版独立SN LINK V9”具有 SW 调试接口的主控板MCU 使用 STM332G473RCT6软件STM32 HAL库cubemx 生成FreeRTOS Kernel V10.3.1cubemx 生成FreeRTOS.h 文件开头注释可见版本SystemView官方软件以及配套示例代码资料准备 SystemView 文件从 下载链接 下载并安装好 SystemView 后在安装目录中有如下路径图1需要备份的文件如下可以将他们打包到新建文件夹 SystemView 中之后将其添加到 MDK 的工程中注意 MDK 设置好头文件路径。表2相对路径文件备注\Src\ConfigGlobal.hSEGGER_RTT_Conf.hSEGGER_SYSVIEW_Conf.h\Src\Sample\FreeRTOSV10SEGGER_SYSVIEW_FreeRTOS.cSEGGER_SYSVIEW_FreeRTOS.h适配FreeRTOS Kernel V10.3.1\Src\Sample\FreeRTOSV10\Config\Cortex-MSEGGER_SYSVIEW_Config_FreeRTOS.c\Src\SEGGERSEGGER.hSEGGER_RTT.cSEGGER_RTT.hSEGGER_RTT_printf.cSEGGER_SYSVIEW.cSEGGER_SYSVIEW.hSEGGER_SYSVIEW_ConfDefaults.hSEGGER_SYSVIEW_Int.h移植细节cubemx 生成 HAL 库cubemx 中需要注意的是我使用的 FreeRTOS 如图2所示。图2如图3所示FreeRTOS 设置 configCHECK_FOR_STACK_OVERFLOW 和 configUSE_TRACE_FACILITY 都要使能。图3cubemx 的中断优先级如图4的 Priority Group 所示即默认配置。图4cubemx 的 HAL库时基使用定时器不使用 SysTick 时钟如图5所示。图5文件 SEGGER_SYSVIEW_Conf.h添加如下代码/********************************************************************* * TODO: Add your defines here. * ********************************************************************** */ // 1. 时间戳使用 Cortex-M DWT 周期计数器地址固定 #define SEGGER_SYSVIEW_GET_TIMESTAMP() (*(volatile U32 *)(0xE0001004)) #define SEGGER_SYSVIEW_TIMESTAMP_BITS 32 // 2. 中断 ID读取 ICSR 的 ACTIVEVECTOR 字段 #define SEGGER_SYSVIEW_GET_INTERRUPT_ID() ((*(volatile U32 *)(0xE000ED04)) 0x1FF) // 3. ID 压缩STM32G473 指针在 SRAM 中4 字节对齐 #define SEGGER_SYSVIEW_ID_BASE 0x20000000 #define SEGGER_SYSVIEW_ID_SHIFT 2 // 4. 临界区保护与 RTT 共用锁使用 BASEPRI // 注意此值需与 FreeRTOS 的 configMAX_SYSCALL_INTERRUPT_PRIORITY 协调 // 假设你使用 NVIC_PriorityGroup_4configMAX_SYSCALL_INTERRUPT_PRIORITY 0x50 #define SEGGER_SYSVIEW_LOCK() SEGGER_RTT_LOCK() #define SEGGER_SYSVIEW_UNLOCK() SEGGER_RTT_UNLOCK() // 5. 缓冲区大小连续记录 1-4KB 足够 #define SEGGER_SYSVIEW_RTT_BUFFER_SIZE 2048 // 6. 使用静态缓冲区节省栈空间 #define SEGGER_SYSVIEW_USE_STATIC_BUFFER 1 #endif // SEGGER_SYSVIEW_CONF_H /*************************** End of file ****************************/文件 SEGGER_RTT_Conf.h不使用 RTT 功能保持默认。文件 SEGGER_SYSVIEW_Config_FreeRTOS.c修改和添加如下代码/********************************************************************* * * Defines, configurable * ********************************************************************** */ // The application name to be displayed in SystemViewer #define SYSVIEW_APP_NAME STM32G473_FreeRTOS // The target device name #define SYSVIEW_DEVICE_NAME STM32G473RCT6 // Frequency of the timestamp. Must match SEGGER_SYSVIEW_GET_TIMESTAMP in SEGGER_SYSVIEW_Conf.h #define SYSVIEW_TIMESTAMP_FREQ (configCPU_CLOCK_HZ) // System Frequency. SystemcoreClock is used in most CMSIS compatible projects. #define SYSVIEW_CPU_FREQ configCPU_CLOCK_HZ // The lowest RAM address used for IDs (pointers) #define SYSVIEW_RAM_BASE (0x20000000) // DWT 寄存器 #define DEMCR (*(volatile unsigned long *)(0xE000EDFCuL)) #define TRACEENA_BIT (1uL 24) #define DWT_CTRL (*(volatile unsigned long *)(0xE0001000uL)) #define NOCYCCNT_BIT (1uL 25) #define CYCCNTENA_BIT (1uL 0) // vTaskSwitchContext 函数内使用宏 traceTASK_SWITCHED_OUT 和 traceTASK_SWITCHED_IN 将这些宏重定向 #undef traceTASK_SWITCHED_OUT #define traceTASK_SWITCHED_OUT() SYSVIEW_RecordTaskStopExec() #undef traceTASK_SWITCHED_IN #define traceTASK_SWITCHED_IN() SYSVIEW_RecordTaskStartExec() /********************************************************************* * * _cbSendSystemDesc() * * Function description * Sends SystemView description strings. */ static void _cbSendSystemDesc(void) { SEGGER_SYSVIEW_SendSysDesc(NSYSVIEW_APP_NAME,DSYSVIEW_DEVICE_NAME,OFreeRTOS); SEGGER_SYSVIEW_SendSysDesc(I#15SysTick, I#14PendSV, I#11SVC \ I#17PVD, I#42TimeBase, I#53RS485_USART, I#71RS485_TIM); } /********************************************************************* * * Global functions * ********************************************************************** */ void SEGGER_SYSVIEW_Conf(void) { // 使能 DWT 周期计数器无调试器连接时必须由应用开启 if ((DEMCR TRACEENA_BIT) 0) { DEMCR | TRACEENA_BIT; } if ((DWT_CTRL NOCYCCNT_BIT) 0) { // 支持 CYCCNT if ((DWT_CTRL CYCCNTENA_BIT) 0) { DWT_CTRL | CYCCNTENA_BIT; } } SEGGER_SYSVIEW_Init(SYSVIEW_TIMESTAMP_FREQ, SYSVIEW_CPU_FREQ, SYSVIEW_X_OS_TraceAPI, _cbSendSystemDesc); SEGGER_SYSVIEW_SetRAMBase(SYSVIEW_RAM_BASE); }其中 _cbSendSystemDesc 函数的 I#15SysTick 表示“Interrupt #15 SysTick”而 15 是从启动文件 startup_stm32g473xx.s 的中断向量表中得到的其中 __initial_sp 是0号中断号。__Vectors DCD __initial_sp ; Top of Stack DCD Reset_Handler ; Reset Handler DCD NMI_Handler ; NMI Handler DCD HardFault_Handler ; Hard Fault Handler DCD MemManage_Handler ; MPU Fault Handler DCD BusFault_Handler ; Bus Fault Handler DCD UsageFault_Handler ; Usage Fault Handler DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD SVC_Handler ; SVCall Handler DCD DebugMon_Handler ; Debug Monitor Handler DCD 0 ; Reserved DCD PendSV_Handler ; PendSV Handler DCD SysTick_Handler ; SysTick Handler ; External Interrupts DCD WWDG_IRQHandler ; Window WatchDog DCD PVD_PVM_IRQHandler ; PVD/PVM1/PVM2/PVM3/PVM4 through EXTI Line detection DCD RTC_TAMP_LSECSS_IRQHandler ; RTC, TAMP and RCC LSE_CSS through the EXTI line DCD RTC_WKUP_IRQHandler ; RTC Wakeup through the EXTI line DCD FLASH_IRQHandler ; FLASH DCD RCC_IRQHandler ; RCC DCD EXTI0_IRQHandler ; EXTI Line0 DCD EXTI1_IRQHandler ; EXTI Line1 DCD EXTI2_IRQHandler ; EXTI Line2 DCD EXTI3_IRQHandler ; EXTI Line3 DCD EXTI4_IRQHandler ; EXTI Line4 DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1 DCD DMA1_Channel2_IRQHandler ; DMA1 Channel 2 DCD DMA1_Channel3_IRQHandler ; DMA1 Channel 3 DCD DMA1_Channel4_IRQHandler ; DMA1 Channel 4 DCD DMA1_Channel5_IRQHandler ; DMA1 Channel 5 DCD DMA1_Channel6_IRQHandler ; DMA1 Channel 6 DCD DMA1_Channel7_IRQHandler ; DMA1 Channel 7 DCD ADC1_2_IRQHandler ; ADC1 and ADC2 DCD USB_HP_IRQHandler ; USB Device High Priority DCD USB_LP_IRQHandler ; USB Device Low Priority DCD FDCAN1_IT0_IRQHandler ; FDCAN1 interrupt line 0 DCD FDCAN1_IT1_IRQHandler ; FDCAN1 interrupt line 1 DCD EXTI9_5_IRQHandler ; External Line[9:5]s DCD TIM1_BRK_TIM15_IRQHandler ; TIM1 Break, Transition error, Index error and TIM15 DCD TIM1_UP_TIM16_IRQHandler ; TIM1 Update and TIM16 DCD TIM1_TRG_COM_TIM17_IRQHandler ; TIM1 Trigger, Commutation, Direction change, Index and TIM17 DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare DCD TIM2_IRQHandler ; TIM2 DCD TIM3_IRQHandler ; TIM3 DCD TIM4_IRQHandler ; TIM4 DCD I2C1_EV_IRQHandler ; I2C1 Event DCD I2C1_ER_IRQHandler ; I2C1 Error DCD I2C2_EV_IRQHandler ; I2C2 Event DCD I2C2_ER_IRQHandler ; I2C2 Error DCD SPI1_IRQHandler ; SPI1 DCD SPI2_IRQHandler ; SPI2 DCD USART1_IRQHandler ; USART1 DCD USART2_IRQHandler ; USART2 DCD USART3_IRQHandler ; USART3 DCD EXTI15_10_IRQHandler ; External Line[15:10] DCD RTC_Alarm_IRQHandler ; RTC Alarm (A and B) through EXTI Line DCD USBWakeUp_IRQHandler ; USB Wakeup through EXTI line DCD TIM8_BRK_IRQHandler ; TIM8 Break, Transition error and Index error Interrupt DCD TIM8_UP_IRQHandler ; TIM8 Update Interrupt DCD TIM8_TRG_COM_IRQHandler ; TIM8 Trigger, Commutation, Direction change and Index Interrupt DCD TIM8_CC_IRQHandler ; TIM8 Capture Compare Interrupt DCD ADC3_IRQHandler ; ADC3 DCD FMC_IRQHandler ; FMC DCD LPTIM1_IRQHandler ; LP TIM1 interrupt DCD TIM5_IRQHandler ; TIM5 DCD SPI3_IRQHandler ; SPI3 DCD UART4_IRQHandler ; UART4 DCD UART5_IRQHandler ; UART5 DCD TIM6_DAC_IRQHandler ; TIM6 and DAC13 underrun errors DCD TIM7_DAC_IRQHandler ; TIM7 and DAC24 underrun errors DCD DMA2_Channel1_IRQHandler ; DMA2 Channel 1 DCD DMA2_Channel2_IRQHandler ; DMA2 Channel 2 DCD DMA2_Channel3_IRQHandler ; DMA2 Channel 3 DCD DMA2_Channel4_IRQHandler ; DMA2 Channel 4 DCD DMA2_Channel5_IRQHandler ; DMA2 Channel 5 DCD ADC4_IRQHandler ; ADC4 DCD ADC5_IRQHandler ; ADC5 DCD UCPD1_IRQHandler ; UCPD1 DCD COMP1_2_3_IRQHandler ; COMP1, COMP2 and COMP3 DCD COMP4_5_6_IRQHandler ; COMP4, COMP5 and COMP6 DCD COMP7_IRQHandler ; COMP7 DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD CRS_IRQHandler ; CRS Interrupt DCD SAI1_IRQHandler ; Serial Audio Interface 1 global interrupt DCD TIM20_BRK_IRQHandler ; TIM20 Break, Transition error and Index error DCD TIM20_UP_IRQHandler ; TIM20 Update DCD TIM20_TRG_COM_IRQHandler ; TIM20 Trigger, Commutation, Direction change and Index DCD TIM20_CC_IRQHandler ; TIM20 Capture Compare DCD FPU_IRQHandler ; FPU DCD I2C4_EV_IRQHandler ; I2C4 event DCD I2C4_ER_IRQHandler ; I2C4 error DCD SPI4_IRQHandler ; SPI4 DCD 0 ; Reserved DCD FDCAN2_IT0_IRQHandler ; FDCAN2 interrupt line 0 DCD FDCAN2_IT1_IRQHandler ; FDCAN2 interrupt line 1 DCD FDCAN3_IT0_IRQHandler ; FDCAN3 interrupt line 0 DCD FDCAN3_IT1_IRQHandler ; FDCAN3 interrupt line 1 DCD RNG_IRQHandler ; RNG global interrupt DCD LPUART1_IRQHandler ; LP UART 1 interrupt DCD I2C3_EV_IRQHandler ; I2C3 Event DCD I2C3_ER_IRQHandler ; I2C3 Error DCD DMAMUX_OVR_IRQHandler ; DMAMUX overrun global interrupt DCD QUADSPI_IRQHandler ; QUADSPI DCD DMA1_Channel8_IRQHandler ; DMA1 Channel 8 DCD DMA2_Channel6_IRQHandler ; DMA2 Channel 6 DCD DMA2_Channel7_IRQHandler ; DMA2 Channel 7 DCD DMA2_Channel8_IRQHandler ; DMA2 Channel 8 DCD CORDIC_IRQHandler ; CORDIC DCD FMAC_IRQHandler ; FMAC __Vectors_End文件 FreeRTOSConfig.h添加如下代码/* USER CODE BEGIN Defines */ /* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */ // 解决 xTaskIncrementTick 导致触发 HardFault_Handler #undef xPortSysTickHandler #define osSystickHandler SysTick_Handler #ifdef SYSTEM_VIEW // SystemView #include SEGGER_SYSVIEW_FreeRTOS.h #define INCLUDE_xTaskGetIdleTaskHandle 1 #define INCLUDE_pxTaskGetStackStart 1 // 解决 error: A1586E: Bad operand types (UnDefOT, Constant) for operator ( #undef configPRIO_BITS #define configPRIO_BITS 4 #endif // SYSTEM_VIEW /* USER CODE END Defines */ #endif /* FREERTOS_CONFIG_H */其中 #ifdef SYSTEM_VIEW 指令是方便我的后续调试可以去掉但注意同时删除对应的 #endif 指令。函数 xPortSysTickHandler该函数最终对应 SysTick_Handler 。修改如下代码void xPortSysTickHandler( void ) { #ifdef SYSTEM_VIEW traceISR_ENTER(); #endif /* The SysTick runs at the lowest interrupt priority, so when this interrupt executes all interrupts must be unmasked. There is therefore no need to save and then restore the interrupt mask value as its value is already known - therefore the slightly faster vPortRaiseBASEPRI() function is used in place of portSET_INTERRUPT_MASK_FROM_ISR(). */ vPortRaiseBASEPRI(); { /* Increment the RTOS tick. */ if( xTaskIncrementTick() ! pdFALSE ) { /* A context switch is required. Context switching is performed in the PendSV interrupt. Pend the PendSV interrupt. */ portNVIC_INT_CTRL_REG portNVIC_PENDSVSET_BIT; } } vPortClearBASEPRIFromISR(); #ifdef SYSTEM_VIEW traceISR_EXIT(); #endif }不触发 FreeRTOS 调度的中断不调用 portYIELD_FROM_ISR(xHigherPriorityTaskWoken) 的中断不会强制触发 FreeRTOS 任务调度。如果没有回调函数那么有如下代码void TIM2_IRQHandler(void) { SEGGER_SYSVIEW_RecordEnterISR(); // 记录中断进入 // ... HAL_TIM_IRQHandler(htim2); SEGGER_SYSVIEW_RecordExitISR(); // 记录中断退出 }如果有对应的回调函数那么有如下代码void TIM2_IRQHandler(void) { SEGGER_SYSVIEW_RecordEnterISR(); // ← 中断开始 HAL_TIM_IRQHandler(htim2); // ← 内部会调用 } // HAL_TIM_PeriodElapsedCallback() { // ... SEGGER_SYSVIEW_RecordExitISR(); // ← 中断结束 }SystemView 软件图6图7图8图9图10参考链接移植Systemviewend
返回列表