GD32VF103移植SVSTEMVIEW
文章目錄
- GD32VF103移植SVSTEMVIEW
- SystemView
- 移植源文件加入工程
- 修改freertos源碼
- 添加串口移植
- 修改systemview配置
- 完成移植
GD32VF103移植SVSTEMVIEW
最近兆易推出了基于RISCV的MCU-GD32VF103,得到了一個GD32VF103C-START 學習板,以前只用過arm內核mcu,從沒用過RISCV內核,打算玩一下這塊板子。這次打算移植一下SEGGER 的SystemView,RTOS選擇FreeRTOS。本文開發環境為Linux Mint 19.1。
SystemView
SEGGER SystemView是一種用于嵌入式系統的實時記錄和可視化工具,可以顯示應用程序的真實運行時行為,遠遠超過調試器提供的系統洞察。在開發和使用包含多個線程和中斷的復雜嵌入式系統時,尤其有效。SystemView可以確保系統按設計執行,可以追蹤低效率,并顯示意外的交互和資源沖突,重點關注每個系統的詳細信息。并且可以免費使用。
目前官方最新版本是V3.10,在這個版本里提供了UART采集的功能,正好GD32VF103目前使用的gdlink不是jlink,在之前的systemview版本里都只支持jlink采集不支持UART采集的功能.
V3.10版本下載地址:https://www.segger.com/downloads/systemview/
但是這個頁面上并未提供串口采集移植的示例,不過在SEGGER的官方論壇里的一個帖子找到了一個示例工程:https://forum.segger.com/index.php/Thread/6874-SOLVED-SystemView-serial-port/
移植源文件加入工程
將sysvtemiew的target源碼加入工程編譯,這里需要注意用于ARM的專用匯編代碼可不必加入編譯,Syscalls的四個文件可根據需要加入編譯,這里我沒有加入.
修改freertos源碼
這個步驟分為兩步,首先根據FreeRTOSV10_Core.patch內容修改freertos源碼
然后為gd32vf103的port.c、portasm.h文件里的內核tick中斷添加trace調用包含以下四處
void vPortSysTickHandler(void) {volatile uint64_t * mtime = (uint64_t*) (TIMER_CTRL_ADDR + TIMER_MTIME);volatile uint64_t * mtimecmp = (uint64_t*) (TIMER_CTRL_ADDR + TIMER_MTIMECMP);UBaseType_t uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();#if CONFIG_SYSTEMVIEW_ENtraceISR_ENTER();#endifuint64_t now = *mtime;now += (configRTC_CLOCK_HZ / configTICK_RATE_HZ);*mtimecmp = now;/* 調用freertos的tick增加接口 */if( xTaskIncrementTick() != pdFALSE ){#if CONFIG_SYSTEMVIEW_ENtraceISR_EXIT_TO_SCHEDULER();#endifportYIELD();}#if CONFIG_SYSTEMVIEW_ENelse{traceISR_EXIT();}#endifportCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); } #if CONFIG_SYSTEMVIEW_EN #define portEND_SWITCHING_ISR(xSwitchRequired) { if( xSwitchRequired != pdFALSE) { traceISR_EXIT_TO_SCHEDULER(); portYIELD(); } else {traceISR_EXIT(); } } #else #define portEND_SWITCHING_ISR(xSwitchRequired) if( xSwitchRequired != pdFALSE) portYIELD() #endif添加串口移植
創建SYSVIEW_Serial.c文件,內容如下,這里使用串口0來輸出trace采集信息。
#include "SEGGER_RTT.h" #include "SEGGER_SYSVIEW.h" #include "SYSVIEW_Serial_Conf.h" #include "gd32vf103.h"#define _SERVER_HELLO_SIZE (4) #define _TARGET_HELLO_SIZE (4)static struct {U8 NumBytesHelloRcvd;U8 NumBytesHelloSent;int ChannelID; } _SVInfo;static const U8 _abHelloMsg[_TARGET_HELLO_SIZE] = {'S', 'V', (SEGGER_SYSVIEW_VERSION / 10000), (SEGGER_SYSVIEW_VERSION / 1000) % 10}; // "Hello" message expected by SysView: [ 'S', 'V', <PROTOCOL_MAJOR>, <PROTOCOL_MINOR> ]/*** @brief This function starts and initializes a SystemView session, if necessary.* */ static void _StartSysView(void) {int r;r = SEGGER_SYSVIEW_IsStarted();if (r == 0){SEGGER_SYSVIEW_Start();} }/*** @brief This function is called when the UART receives data.* * @param Data */ static void _cbOnRx(U8 Data) {if (_SVInfo.NumBytesHelloRcvd < _SERVER_HELLO_SIZE){ // Not all bytes of <Hello> message received by SysView yet?_SVInfo.NumBytesHelloRcvd++;/* 目前版本V3.10,增加這個判斷才能正確啟動 modify by QQM */if(_SVInfo.NumBytesHelloRcvd == _SERVER_HELLO_SIZE-1){_StartSysView();}goto Done;}_StartSysView();SEGGER_RTT_WriteDownBuffer(_SVInfo.ChannelID, &Data, 1); // Write data into corresponding RTT buffer for application to read and handle accordingly Done:return; }/*** @brief This function is called when the UART should transmit data.* * @param pChar * @return int */ static int _cbOnTx(U8 *pChar) {int r;if (_SVInfo.NumBytesHelloSent < _TARGET_HELLO_SIZE){ // Not all bytes of <Hello> message sent to SysView yet?*pChar = _abHelloMsg[_SVInfo.NumBytesHelloSent];_SVInfo.NumBytesHelloSent++;r = 1;goto Done;}r = SEGGER_RTT_ReadUpBufferNoLock(_SVInfo.ChannelID, pChar, 1);if (r < 0){ // Failed to read from up buffer?r = 0;} Done:return r; }void vSYSVIEWUARTEnableTXEInterrupt(U32 NumBytes) {usart_interrupt_enable(USART0, USART_INT_TBE); }/*** @brief sysview uart handle* */ void vSYSVIEWUARTInterruptHandler(void) {U8 cChar;if(RESET != usart_interrupt_flag_get(CONFIG_SYSVIEW_UART_PORT, USART_INT_FLAG_RBNE)){/* receive data */cChar = usart_data_receive(CONFIG_SYSVIEW_UART_PORT);_cbOnRx(cChar);}if(RESET != usart_interrupt_flag_get(CONFIG_SYSVIEW_UART_PORT, USART_INT_FLAG_TBE)){if (0 == _cbOnTx(&cChar)){usart_interrupt_disable(CONFIG_SYSVIEW_UART_PORT, USART_INT_TBE);}else{/* transmit data */usart_data_transmit(CONFIG_SYSVIEW_UART_PORT, cChar);}} }/*** @brief sysview uart init* */ void vSYSVIEWUARTInit(void) {_SVInfo.ChannelID = SEGGER_SYSVIEW_GetChannelID(); // Store system view channel ID for later communicationif(CONFIG_SYSVIEW_UART_PORT == USART0){/* 初始化uart0 TX PA9 RX PA10 */rcu_periph_clock_enable(RCU_GPIOA);rcu_periph_clock_enable(RCU_USART0);gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_10);usart_deinit(CONFIG_SYSVIEW_UART_PORT);usart_baudrate_set(CONFIG_SYSVIEW_UART_PORT, 115200U);usart_word_length_set(CONFIG_SYSVIEW_UART_PORT, USART_WL_8BIT);usart_stop_bit_set(CONFIG_SYSVIEW_UART_PORT, USART_STB_1BIT);usart_parity_config(CONFIG_SYSVIEW_UART_PORT, USART_PM_NONE);usart_hardware_flow_rts_config(CONFIG_SYSVIEW_UART_PORT, USART_RTS_DISABLE);usart_hardware_flow_cts_config(CONFIG_SYSVIEW_UART_PORT, USART_CTS_DISABLE);usart_receive_config(CONFIG_SYSVIEW_UART_PORT, USART_RECEIVE_ENABLE);usart_transmit_config(CONFIG_SYSVIEW_UART_PORT, USART_TRANSMIT_ENABLE);usart_interrupt_disable(CONFIG_SYSVIEW_UART_PORT, USART_INT_TBE);usart_interrupt_enable(CONFIG_SYSVIEW_UART_PORT, USART_INT_RBNE);usart_enable(CONFIG_SYSVIEW_UART_PORT);eclic_irq_enable(USART0_IRQn, 1, 0);} }修改systemview配置
- SEGGER/Config/SEGGER_RTT_Conf.h,增加SEGGER_RTT_LOCK、SEGGER_RTT_UNLOCK定義,通過eclic控制器mth閾值來關閉中斷上鎖
- SEGGER/Config/SEGGER_SYSVIEW_Conf.h,定義SEGGER_SYSVIEW_ON_EVENT_RECORDED為觸發USART_INT_TBE中斷
- SEGGER/FreeRTOSV10/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c定義中斷號查詢以及tick數獲取函數,以及一些設備信息的填寫,包括設備名稱,應用名稱,內核名稱,cpu時鐘等
- gd32vf103_it.c 添加Application/gd32vf103_it.c到USART0_IRQHandler內
完成移植
在main函數調用SEGGER_SYSVIEW_Conf()和vSYSVIEWUARTInit()函數,創建兩個測試任務看看。
void task1(void *p) {for(;;){gpio_bit_write(GPIOA, GPIO_PIN_7, (bit_status)(1-gpio_input_bit_get(GPIOA, GPIO_PIN_7)));vTaskDelay(pdMS_TO_TICKS(500));} }void task2(void *p) {char *taskStatus = (char *)pvPortMalloc( uxTaskGetNumberOfTasks() * sizeof( TaskStatus_t ) );for(;;){vTaskList(taskStatus);printf("\nTaskName\tStatus\tPRI\tStack\tTaskNumber\n%s",taskStatus);printf("current tick is %ld\n",xTaskGetTickCount());vTaskDelay(pdMS_TO_TICKS(5000));} }int main(void) { eclic_priority_group_set(ECLIC_PRIGROUP_LEVEL4_PRIO0); //四位優先級組全配置為lvleclic_global_interrupt_enable(); //使能全局中斷#if CONFIG_SYSTEMVIEW_ENSEGGER_SYSVIEW_Conf();printf("Segger Sysview Control Block Detection Address is 0x%lx\n", (uint32_t)&_SEGGER_RTT);vSYSVIEWUARTInit();#endif#if UARTLOGENuart_log_init();#endif/* 初始化led PA7 */rcu_periph_clock_enable(RCU_GPIOA);gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);gpio_bit_reset(GPIOA, GPIO_PIN_7);xTaskCreate(task1,"task1",521,NULL,2,NULL);xTaskCreate(task2,"task2",521,NULL,2,NULL);vTaskStartScheduler(); }編譯生成bin
通過gdb調試下載運行
打開systemview設置串口com號和波特率,這里systemview我安裝在虛擬機里,因為我的主機開發環境是linux,systemview官方一直是支持linux和mac環境的,但是V3.10這個版本存在bug,只能使用windous版本,目前官方已知道該問題后續版本會修復,但截止本文完成還未發布新版本,所以這里只能用虛擬機里跑windous版本的systemview
點擊開始采集,最終效果如下
本文使用的源碼工程已開源到我的github:https://github.com/QQxiaoming/gd32vf103_freertos
總結
以上是生活随笔為你收集整理的GD32VF103移植SVSTEMVIEW的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java学习(60):java最终类(了
- 下一篇: 项目管理(2):备战pmp