GD32VF103移植SVSTEMVIEW

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_EN
	traceISR_ENTER();
	#endif

	uint64_t now = *mtime;
	now += (configRTC_CLOCK_HZ / configTICK_RATE_HZ);
	*mtimecmp = now;

	/* 调用freertos的tick增加接口 */
	if( xTaskIncrementTick() != pdFALSE )
	{
		#if CONFIG_SYSTEMVIEW_EN
		traceISR_EXIT_TO_SCHEDULER();
		#endif
		portYIELD();
	}
	#if CONFIG_SYSTEMVIEW_EN
	else
	{
		traceISR_EXIT();
	}
	#endif

	portCLEAR_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 communication

    if(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阈值来关闭中断上锁
/*********************************************************************
*
*       RTT lock configuration for SEGGER Embedded Studio,
*       Rowley CrossStudio and GCC
*/
#if (defined(__SES_ARM) || defined(__CROSSWORKS_ARM) || defined(__GNUC__) || defined(__clang__)) && !defined (__CC_ARM)
  #if (defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__))
    #define SEGGER_RTT_LOCK()   {                                                                   \
                                    unsigned int LockState;                                         \
                                  __asm volatile ("mrs   %0, primask  \n\t"                         \
                                                  "movs  r1, $1       \n\t"                         \
                                                  "msr   primask, r1  \n\t"                         \
                                                  : "=r" (LockState)                                \
                                                  :                                                 \
                                                  : "r1"                                            \
                                                  );

    #define SEGGER_RTT_UNLOCK()   __asm volatile ("msr   primask, %0  \n\t"                         \
                                                  :                                                 \
                                                  : "r" (LockState)                                 \
                                                  :                                                 \
                                                  );                                                \
                                }
  #elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__))
    #ifndef   SEGGER_RTT_MAX_INTERRUPT_PRIORITY
      #define SEGGER_RTT_MAX_INTERRUPT_PRIORITY   (0x20)
    #endif
    #define SEGGER_RTT_LOCK()   {                                                                   \
                                    unsigned int LockState;                                         \
                                  __asm volatile ("mrs   %0, basepri  \n\t"                         \
                                                  "mov   r1, %1       \n\t"                         \
                                                  "msr   basepri, r1  \n\t"                         \
                                                  : "=r" (LockState)                                \
                                                  : "i"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY)          \
                                                  : "r1"                                            \
                                                  );

    #define SEGGER_RTT_UNLOCK()   __asm volatile ("msr   basepri, %0  \n\t"                         \
                                                  :                                                 \
                                                  : "r" (LockState)                                 \
                                                  :                                                 \
                                                  );                                                \
                                }

  #elif defined(__ARM_ARCH_7A__)
    #define SEGGER_RTT_LOCK() {                                                \
                                 unsigned int LockState;                       \
                                 __asm volatile ("mrs r1, CPSR \n\t"           \
                                                 "mov %0, r1 \n\t"             \
                                                 "orr r1, r1, #0xC0 \n\t"      \
                                                 "msr CPSR_c, r1 \n\t"         \
                                                 : "=r" (LockState)            \
                                                 :                             \
                                                 : "r1"                        \
                                                 );

    #define SEGGER_RTT_UNLOCK() __asm volatile ("mov r0, %0 \n\t"              \
                                                "mrs r1, CPSR \n\t"            \
                                                "bic r1, r1, #0xC0 \n\t"       \
                                                "and r0, r0, #0xC0 \n\t"       \
                                                "orr r1, r1, r0 \n\t"          \
                                                "msr CPSR_c, r1 \n\t"          \
                                                :                              \
                                                : "r" (LockState)              \
                                                : "r0", "r1"                   \
                                                );                             \
                            }
  #else
    #include "portmacro.h"
    #define SEGGER_RTT_LOCK()   {                                                      \
                                    unsigned int LockState = xPortSetInterruptMask();
    #define SEGGER_RTT_UNLOCK()   vPortClearInterruptMask(LockState);                  \
                                 }
  #endif
#endif
  • SEGGER/Config/SEGGER_SYSVIEW_Conf.h,定义SEGGER_SYSVIEW_ON_EVENT_RECORDED为触发USART_INT_TBE中断
#ifndef   SEGGER_SYSVIEW_ON_EVENT_RECORDED
  extern void vSYSVIEWUARTEnableTXEInterrupt(U32 NumBytes); 
  #define SEGGER_SYSVIEW_ON_EVENT_RECORDED(NumBytes)     vSYSVIEWUARTEnableTXEInterrupt(NumBytes)     // Needed for SystemView via non-J-Link Recorder. Macro to enable the UART or notify IP task.
#endif
  • SEGGER/FreeRTOSV10/Config/SEGGER_SYSVIEW_Config_FreeRTOS.c定义中断号查询以及tick数获取函数,以及一些设备信息的填写,包括设备名称,应用名称,内核名称,cpu时钟等
/*********************************************************************
*
*       Defines, configurable
*
**********************************************************************
*/
// The application name to be displayed in SystemViewer
#define SYSVIEW_APP_NAME        "GD32VF103_SYSVIEW"

// The target device name
#define SYSVIEW_DEVICE_NAME     "GD32VF103"

// The target core name
#define SYSVIEW_CORE_NAME       "RV32"

// Frequency of the timestamp. Must match SEGGER_SYSVIEW_GET_TIMESTAMP in SEGGER_SYSVIEW_Conf.h
#define SYSVIEW_TIMESTAMP_FREQ  (configRTC_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)

/********************************************************************* 
*
*       _cbSendSystemDesc()
*
*  Function description
*    Sends SystemView description strings.
*/
static void _cbSendSystemDesc(void) {
  SEGGER_SYSVIEW_SendSysDesc("N="SYSVIEW_APP_NAME",D="SYSVIEW_DEVICE_NAME",C="SYSVIEW_CORE_NAME",O=FreeRTOS");
  SEGGER_SYSVIEW_SendSysDesc("I#7=SysTick");
}

/*********************************************************************
*
*       Global functions
*
**********************************************************************
*/
void SEGGER_SYSVIEW_Conf(void) {
  SEGGER_SYSVIEW_Init(SYSVIEW_TIMESTAMP_FREQ, SYSVIEW_CPU_FREQ, 
                      &SYSVIEW_X_OS_TraceAPI, _cbSendSystemDesc);
  SEGGER_SYSVIEW_SetRAMBase(SYSVIEW_RAM_BASE);
}

U32  SEGGER_SYSVIEW_X_GetTimestamp(void)
{
	return (*(U32 *)(TIMER_CTRL_ADDR+TIMER_MTIME));
}

U32  SEGGER_SYSVIEW_X_GetInterruptId(void)
{
	return 0xFFF&read_csr(mcause);
}
  • gd32vf103_it.c 添加Application/gd32vf103_it.c到USART0_IRQHandler内
/*!
    \brief      this function handles USART RBNE interrupt request and TBE interrupt request
    \param[in]  none
    \param[out] none
    \retval     none
*/
void USART0_IRQHandler(void)
{
    #if CONFIG_SYSTEMVIEW_EN
    vSYSVIEWUARTInterruptHandler();
    #endif
}
完成移植

在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); //四位优先级组全配置为lvl
    eclic_global_interrupt_enable();                       //使能全局中断

    #if CONFIG_SYSTEMVIEW_EN
    SEGGER_SYSVIEW_Conf();
    printf("Segger Sysview Control Block Detection Address is 0x%lx\n", (uint32_t)&_SEGGER_RTT);
    vSYSVIEWUARTInit();
    #endif

    #if UARTLOGEN
    uart_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

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Quard_D

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值