【Jlink & C#】通过C#实现Jlink RTT上位机的功能

4 篇文章 2 订阅

目的

某天看到安富莱家的自己开发的调试器可以实现输出中文调试信息到自己编写的Jlink RTT上位机上,觉得无比神奇,略好奇到底是如何做的,找了很久,发现其上位机的对应的实现好像也没有完全开源出来。

后来经过很多搜索确认,知道了几个事实:

  1. Jlink自己自带的上位机J-Link RTT Viewer 不支持中文调试信息显示
  2. Jlink自己自带的命令行终端J-Link RTT Client是可以显示中文的,它的原理应该类似一个客户端连接到服务器,socket那种搞法的
  3. Jlink本身其实有提供一个叫SDK的东西,也就是直接控制Jlink的的库,但是很遗憾,这个是收费的,贼贵!!!!
  4. 某个国内的大佬使用pylink(python实现的控制Jlink的一个库)实现了一个类似与J-Link RTT Viewer 那样的东西,虽然比较简陋,但是我感觉已经很不错了,链接-》RTT-T

那么有没有可能用C#来控制Jlink呢?

C#控制Jlink的可能性

答案是,有!!!
解决思路在于,C#调用JLinkARM.dll里面的函数
这里转载下我认为很有意义的发现

  1. JLinkARM.dll部分导出函数定义
  2. JlinkARM.DLL API与VB声明
  3. c#的 JLINK API,自己用的

我和一个老哥讨论的一些成果

感谢这个老哥xtq0009和我探讨了下Jlink DLL的问题,他也在做类似的东西~
我总结下我和他探讨的成果~

  1. 他认为这个RTT的API可能不是那样用的,RTT的功能是通过芯片上的一篇内存区域来做的的,这个可以参考SEGGER JLINK的WIKI
    老哥说他感觉可能只要找到这个图中Up和Down描述描述符的位置,然后通过现在已知可以用的接口(读写寄存器的接口)可能就可以实现RTT了,之前我没有朝这个方向去找,去IDA反编译找API了~ 但是好像直接去读对应的RTT结构体的内存地址,会有问题,它提示是保护的,读不了!!
  2. 目前找这个描述符的位置似乎只能是通过编译固件出来之后的map文件来找,我原来其实也很好奇Jlink的RTT终端下面有一个自动获取地址的输入窗,我一直纳闷怎么用,是不是也和这个地址有关系,或者说这个地址是通过内核,芯片来决定的
    在这里插入图片描述
    连接上芯片的LOG,感觉对照数据手册,是有关联的,跟调试组件有关系,具体什么关系,具体Jlink RTT它用了啥组件,暂时不知道
    在这里插入图片描述

我的研究

结合以上的几个发现,加上我自己的测试,我把我对接JLinkARM.dll的C#接口分享出来,不保证都能用,我只是测试了几个常用的功能,RTT功能还有些问题,不稳定,有时候可以连上,有时候不能,但是连接Jlink,读取CPU ID,读取Jlink固件版本啥的似乎可以。

稳定性问题

不稳定的原因有可能找到了,原来RTT Read的接口,我没有指定传入缓存区的大小,指定了之后,基本上打开运行就是稳定的了
但是数据有时候还是会重复读取一次,暂时没有找到原因,以下是运行截图,TEST那句话是我从板子输出的
在这里插入图片描述

中文RTT输出

这个真实牛逼到我了
我找到让Jlink RTT输出中文的方法了

需要这么干:
首先芯片的代码编码格式选择UTF-8编码
注意是你输出RTT的代码的那个编码,因为RTT组件,它本身就是UTF-8编码的~~
然后RTT_Read接口
charset写auto

这么写

        /// <summary>
        /// 从RTT回读数据
        /// </summary>
        /// <param name="terminal"></param>
        /// <param name="rxBuffer"></param>
        /// <param name="len"></param>
        [DllImport("JLinkARM.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINK_RTTERMINAL_Read(int terminal, [Out(), MarshalAs(UnmanagedType.LPArray)] byte[] rxBuffer, UInt32 size);

然后C#调用这里使用UTF8编码读取RTT发送来的字符

        public static string JLINKARM_ReadRTT_String()
        {
            try
            {
                byte[] aa = new byte[1000];
                JLINK_RTTERMINAL_Read(0, aa,1000);

               ASCIIEncoding kk = new ASCIIEncoding();
                //使用UTF-8编码
                UTF8Encoding uu = new UTF8Encoding();
                string ss = uu.GetString(aa);
                if(ss.Length>1)
                {
                    Console.Write(ss);
                }
                return ss;
            }
            catch(Exception ex)
            {

            }
            return String.Empty;

        }

然后见证奇迹的一刻~
其实我非常想写埃斯B Jlink,真是够~~
在这里插入图片描述

RTT输入输出缓冲区的默认值

注意SEGGER_RTT_Conf.h里面上下行数据缓冲区有默认值,
默认值 上行1K,下行64字节,printf的空间是64字节
在这里插入图片描述
如果你需要收发比较长的数据请修改三个宏.

使用的.net 4.8框架
JLinkHandler.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

/*引入C/C++生成的dll时需要添加*/
using System.Runtime.InteropServices;
using System.Threading;

namespace Jlink_demo
{
    internal class JLinkHandler
    {
        public static  void JLINKARM_Sleep(int ms)
        {
            Thread.Sleep(ms);
        }

        /// <summary>
        /// 打开JLINK设备
        /// </summary>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_Open();


        /// <summary>
        /// 关闭JLINK设备
        /// </summary>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_Close();

        /// <summary>
        /// 连接设备
        /// </summary>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_Connect();

        /// <summary>
        /// 开启RTT
        /// </summary>
        /// <param name="terminal"></param>
        /// <param name="size"></param>
        [DllImport("JLinkARM.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern UInt32 JLINK_RTTERMINAL_Control(UInt32 CMD, UInt32 size);

        /// <summary>
        /// 从RTT回读数据
        /// </summary>
        /// <param name="terminal"></param>
        /// <param name="rxBuffer"></param>
        /// <param name="len"></param>
        [DllImport("JLinkARM.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINK_RTTERMINAL_Read(int terminal, [Out(), MarshalAs(UnmanagedType.LPArray)] byte[] rxBuffer, UInt32 size);


        static string gbk_ansi(string str)
        {
            string keyword;
            byte[] buffer = Encoding.GetEncoding("GB2312").GetBytes(str);
            keyword = Encoding.UTF8.GetString(buffer);
            return keyword;
        }

        public static string JLINKARM_ReadRTT_String()
        {
            try
            {
                byte[] aa = new byte[1000];
                JLINK_RTTERMINAL_Read(0, aa,1000);

               ASCIIEncoding kk = new ASCIIEncoding();
                //使用UTF-8编码
                UTF8Encoding uu = new UTF8Encoding();
                string ss = uu.GetString(aa);
                if(ss.Length>1)
                {
                    Console.Write(ss);
                }
                return ss;
            }
            catch(Exception ex)
            {

            }
            return String.Empty;

        }


        /// <summary>
        /// 写数据到RTT
        /// </summary>
        /// <param name="terminal"></param>
        /// <param name="txBuffer"></param>
        /// <param name="len"></param>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINK_RTTERMINAL_Write(int terminal, [In(), MarshalAs(UnmanagedType.LPArray)] byte[] txBuffer, UInt32 size);




        /// <summary>
        /// 系统复位
        /// </summary>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_Reset();


        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_GoAllowSim();


        /// <summary>
        /// 执行程序
        /// </summary>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_Go();


        /// <summary>
        /// 中断程序执行
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern bool JLINKARM_Halt();

        /// <summary>
        /// 单步执行
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern bool JLINKARM_Step();


        /// <summary>
        /// 清除错误信息
        /// </summary>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_ClrError();


        /// <summary>
        /// 设置JLINK接口速度
        /// </summary>
        /// <param name="speed"></param>
        /// <remarks>0为自动调整</remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_SetSpeed(int speed);


        /// <summary>
        /// 设置JTAG为最高速度
        /// </summary>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_SetMaxSpeed()
        ;

        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern UInt16 JLINKARM_GetSpeed()
       ;

        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern UInt32 JLINKARM_GetVoltage()
    ;

        /// <summary>
        /// 当前MCU是否处于停止状态
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern bool JLINKARM_IsHalted()
        ;

        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern bool JLINKARM_IsConnected()
       ;

        /// <summary>
        /// JLINK是否已经可以操作了
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern bool JLINKARM_IsOpen()
        ;

        /// <summary>
        /// 取消程序断点
        /// </summary>
        /// <param name="index">断点序号</param>
        /// <remarks>配合JLINKARM_SetBP()使用</remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_ClrBP(UInt32 index)
       ;

        /// <summary>
        /// 设置程序断点
        /// </summary>
        /// <param name="index">断点序号</param>
        /// <param name="addr">目标地址</param>
        /// <remarks>建议使用JLINKARM_SetBPEx()替代</remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_SetBP(UInt32 index, UInt32 addr)
        ;

        /// <summary>
        /// 设置程序断点
        /// </summary>
        /// <param name="addr">目标地址</param>
        /// <param name="mode">断点类型</param>
        /// <returns>Handle,提供给JLINKARM_ClrBPEx()使用</returns>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int JLINKARM_SetBPEx(UInt32 addr, BP_MODE mode)
      ;
        /// <summary>
        /// 取消程序断点
        /// </summary>
        /// <param name="handle"></param>
        /// <remarks>配合JLINKARM_SetBPEx()使用</remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_ClrBPEx(int handle)
        ;

        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        private static extern int JLINKARM_SetWP(UInt32 addr, UInt32 addrmark, UInt32 dat, UInt32 datmark, byte ctrl, byte ctrlmark)
        ;

        /// <summary>
        /// 取消数据断点
        /// </summary>
        /// <param name="handle"></param>
        /// <remarks>配合JLINKARM_SetWP()使用</remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_ClrWP(int handle)
        ;

        /// <summary>
        /// 设置寄存器
        /// </summary>
        /// <param name="index"></param>
        /// <param name="dat"></param>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_WriteReg(ARM_REG index, UInt32 dat)
       ;

        /// <summary>
        /// 读取寄存器
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern UInt32 JLINKARM_ReadReg(ARM_REG index)
        ;

        /// <summary>
        /// 写入一段数据
        /// </summary>
        /// <param name="addr"></param>
        /// <param name="size"></param>
        /// <param name="buf"></param>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_WriteMem(UInt32 addr, UInt32 size, byte[] buf)
        ;

        /// <summary>
        /// 读取一段数据
        /// </summary>
        /// <param name="addr"></param>
        /// <param name="size"></param>
        /// <param name="buf"></param>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_ReadMem(UInt32 addr, UInt32 size, [Out(), MarshalAs(UnmanagedType.LPArray)] byte[] buf)
        ;

        /// <summary>
        /// 从调试通道获取一串数据
        /// </summary>
        /// <param name="buf"></param>
        /// <param name="size">需要获取的数据长度</param>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_ReadDCCFast([Out(), MarshalAs(UnmanagedType.LPArray)] UInt32[] buf, UInt32 size)
       ;

        /// <summary>
        /// 从调试通道获取一串数据
        /// </summary>
        /// <param name="buf"></param>
        /// <param name="size">希望获取的数据长度</param>
        /// <param name="timeout"></param>
        /// <returns>实际获取的数据长度</returns>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern UInt32 JLINKARM_ReadDCC([Out(), MarshalAs(UnmanagedType.LPArray)] UInt32[] buf, UInt32 size, int timeout)
        ;

        /// <summary>
        /// 向调试通道写入一串数据
        /// </summary>
        /// <param name="buf"></param>
        /// <param name="size">需要写入的数据长度</param>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_WriteDCCFast(UInt32[] buf, UInt32 size)
        ;

        /// <summary>
        /// 向调试通道写入一串数据
        /// </summary>
        /// <param name="buf"></param>
        /// <param name="size">希望写入的数据长度</param>
        /// <param name="timeout"></param>
        /// <returns>实际写入的数据长度</returns>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern UInt32 JLINKARM_WriteDCC(UInt32[] buf, UInt32 size, int timeout)
        ;

        /// <summary>
        /// 获取JLINK的DLL版本号
        /// </summary>
        /// <returns></returns>
        /// <remarks>使用10进制数表示</remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern UInt32 JLINKARM_GetDLLVersion()
       ;

        /// <summary>
        /// 执行命令
        /// </summary>
        /// <param name="oBuffer"></param>
        /// <param name="a"></param>
        /// <param name="b"></param>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_ExecCommand([In(), MarshalAs(UnmanagedType.LPArray)] byte[] oBuffer,int a,int b);

        /// <summary>
        /// 选择接口,0是JTAG 1是SWD
        /// </summary>
        /// <param name="type"></param>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_TIF_Select(int type);





        /// <summary>
        /// 获取JLINK的固件版本号
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern UInt32 JLINKARM_GetHardwareVersion()
        ;
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        private static extern void JLINKARM_GetFeatureString([Out(), MarshalAs(UnmanagedType.LPArray)] byte[] oBuffer)
       ;

        [DllImport("JLinkARM.dll", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        private static extern void JLINKARM_GetOEMString([Out(), MarshalAs(UnmanagedType.LPArray)] byte[] oBuffer)
        ;

        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_SetLogFile([In(), MarshalAs(UnmanagedType.LPArray)] byte[] oBuffer)
;


        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern StringBuilder JLINKARM_GetCompileDateTime()
        ;

        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern UInt32 JLINKARM_GetSN()
        ;

        /// <summary>
        /// 获取当前MCU的ID号
        /// </summary>
        /// <returns></returns>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern UInt32 JLINKARM_GetId()
        ;

        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        private static extern void JLINKARM_ReadMemU32(UInt32 addr, UInt32 leng, ref UInt32 buf, ref byte status)
       ;

        /// <summary>
        /// 写入32位的数据
        /// </summary>
        /// <param name="addr"></param>
        /// <param name="dat"></param>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_WriteU32(UInt32 addr, UInt32 dat)
      ;

        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        private static extern void JLINKARM_ReadMemU16(UInt32 addr, UInt32 leng, ref UInt16 buf, ref byte status)
       ;
        /// <summary>
        /// 写入16位的数据
        /// </summary>
        /// <param name="addr"></param>
        /// <param name="dat"></param>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_WriteU16(UInt32 addr, UInt16 dat)
  ;

        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        private static extern void JLINKARM_ReadMemU8(UInt32 addr, UInt32 leng, ref byte buf, ref byte status)
;

        /// <summary>
        /// 写入8位的数据
        /// </summary>
        /// <param name="addr"></param>
        /// <param name="dat"></param>
        /// <remarks></remarks>
        [DllImport("JLinkARM.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern void JLINKARM_WriteU8(UInt32 addr, byte dat)
       ;

        /// <summary>
        /// 读取32位的数据
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public UInt32 JLINKARM_ReadU32(UInt32 addr)
        {
            UInt32 dat = 0;
            byte stu = 0;
            JLINKARM_ReadMemU32(addr, 1, ref dat, ref stu);
            return dat;
        }

        /// <summary>
        /// 读取16位的数据
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public UInt16 JLINKARM_ReadU16(UInt32 addr)
        {
            UInt16 dat = 0;
            byte stu = 0;
            JLINKARM_ReadMemU16(addr, 1, ref dat, ref stu);
            return dat;
        }

        /// <summary>
        /// 读取8位的数据
        /// </summary>
        /// <param name="addr"></param>
        /// <returns></returns>
        /// <remarks></remarks>
        public byte JLINKARM_ReadU8(UInt32 addr)
        {
            byte dat = 0;
            byte stu = 0;
            JLINKARM_ReadMemU8(addr, 1, ref dat, ref stu);
            return dat;
        }

        /// <summary>
        /// 设置数据断点
        /// </summary>
        /// <param name="addr">目标地址</param>
        /// <param name="addrmark">地址屏蔽位</param>
        /// <param name="dat">目标数据</param>
        /// <param name="datmark">数据屏蔽位</param>
        /// <param name="mode">触发模式</param>
        /// <returns>Handle,提供给JLINKARM_ClrWP()函数使用</returns>
        /// <remarks>当前数值除了屏蔽位以外的数据位,与目标数据除了屏蔽位以外的数据位,一致即可产生触发</remarks>
        public int JLINKARM_SetWP(UInt32 addr, UInt32 addrmark, UInt32 dat, UInt32 datmark, WP_MODE mode)
        {
            switch (mode)
            {
                case WP_MODE.READ_WRITE:
                    return JLINKARM_SetWP(addr, addrmark, dat, datmark, 0x8, 0xf7);
                case WP_MODE.READ:
                    return JLINKARM_SetWP(addr, addrmark, dat, datmark, 0x8, 0xf6);
                case WP_MODE.WRITE:
                    return JLINKARM_SetWP(addr, addrmark, dat, datmark, 0x9, 0xf6);
                default:
                    {
                        return 0xff;
                    }
            }
        }

        public string JLINKARM_StringFeature()
        {
            byte[] aa = new byte[1000];
            JLINKARM_GetFeatureString(aa);
            ASCIIEncoding kk = new ASCIIEncoding();
            string ss = kk.GetString(aa);
            return ss;
        }

        public string JLINKARM_StringOEM()
        {
            byte[] aa = new byte[1000];
            JLINKARM_GetOEMString(aa);
            ASCIIEncoding kk = new ASCIIEncoding();
            string ss = kk.GetString(aa);
            return ss;
        }

        public void JLINKARM_Setup(string cmdstr)
        {
            //RmAnnotate rm = new RmAnnotate();
            //rm.MarkDosMode = false;
            //rm.MarkStartSpaceToTab = 0;
            //cmdstr = rm.Convert(cmdstr);
            cmdstr = cmdstr.Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", "");
            string[] cmd = cmdstr.Split(';');
            for (int i = 0; i <= cmd.Length - 1; i++)
            {
                _setupDoCmd(cmd[i]);
            }
        }
        private void _setupDoCmd(string cmdstr)
        {
            string cmd = cmdstr.ToLower();
            cmd = cmd.Replace("(", ",");
            cmd = cmd.Replace(")", "");
            cmd = cmd.TrimEnd(',');
            string[] arg = cmd.Split(',');

            UInt32 val1;
            UInt32 val2;
            if (arg.Length == 3)
            {
                cmd = arg[0];
                val1 = _setupGetVal(arg[1]);
                val2 = _setupGetVal(arg[2]);
            }
            else if (arg.Length == 2)
            {
                cmd = arg[0];
                val1 = _setupGetVal(arg[1]);
                val2 = 0;
            }
            else if (arg.Length == 1)
            {
                cmd = arg[0];
                val1 = 0;
                val2 = 0;
            }
            else
            {
                cmd = "";
                val1 = 0;
                val2 = 0;
            }

            if (cmd != "")
            {
                Console.WriteLine("Do CMD: " + cmdstr);
                switch (cmd)
                {
                    case "setjtagspeed":
                        JLINKARM_SetSpeed((int)val1);
                        break;
                    case "delay":
                        JLINKARM_Sleep((int)val1);
                        break;
                    case "disablemmu":
                        Console.WriteLine("...........................CMD not Supported");
                        break;
                    case "go":
                        JLINKARM_Go(); break;
                    case "halt":
                        JLINKARM_Halt(); break;
                    case "reset":
                        JLINKARM_Reset();
                        if (val1 > 0)
                        {
                            JLINKARM_Sleep((int)val1);
                        }
                        break;
                    case "resetbp0":
                        Console.WriteLine("...........................CMD not Supported"); break;
                    case "resetadi":
                        Console.WriteLine("...........................CMD not Supported"); break;
                    case "read8":
                        JLINKARM_ReadU8(val1); break;
                    case "read16":
                        JLINKARM_ReadU16(val1); break;
                    case "read32":
                        JLINKARM_ReadU32(val1); break;
                    case "verify8":
                        do
                        {
                            byte aa = JLINKARM_ReadU8(val1);
                            if (aa == ((byte)val2 & 0xff))
                            {
                                break; // TODO: might not be correct. Was : Exit Do
                            }
                            JLINKARM_Sleep(1);
                        } while (true);
                        break;
                    case "verify16":
                        do
                        {
                            ushort aa = JLINKARM_ReadU16(val1);
                            if (aa == ((ushort)val2 & 0xffff))
                            {
                                break; // TODO: might not be correct. Was : Exit Do
                            }
                            JLINKARM_Sleep(1);
                        } while (true);
                        break;
                    case "verify32":
                        do
                        {
                            uint aa = JLINKARM_ReadU32(val1);
                            if (aa == val2)
                            {
                                break; // TODO: might not be correct. Was : Exit Do
                            }
                            JLINKARM_Sleep(1);
                        } while (true);
                        break;
                    case "write8":
                        JLINKARM_WriteU8(val1, (byte)val2);
                        break;
                    case "write16":
                        JLINKARM_WriteU16(val1, (ushort)val2);
                        break;
                    case "write32":
                        JLINKARM_WriteU32(val1, val2);
                        break;
                    case "writeverify8":
                        do
                        {
                            JLINKARM_WriteU8(val1, (byte)val2);
                            byte aa = JLINKARM_ReadU8(val1);
                            if (aa == ((byte)val2 & 0xff))
                            {
                                break; // TODO: might not be correct. Was : Exit Do
                            }
                            JLINKARM_Sleep(1);
                        } while (true);
                        break;
                    case "writeverify16":
                        do
                        {
                            JLINKARM_WriteU16(val1, (ushort)val2);
                            ushort aa = JLINKARM_ReadU16(val1);
                            if (aa == ((ushort)val2 & 0xffff))
                            {
                                break; // TODO: might not be correct. Was : Exit Do
                            }
                            JLINKARM_Sleep(1);
                        } while (true);
                        break;
                    case "writeverify32":
                        do
                        {
                            JLINKARM_WriteU32(val1, val2);
                            uint aa = JLINKARM_ReadU32(val1);
                            if (aa == val2)
                            {
                                break; // TODO: might not be correct. Was : Exit Do
                            }
                            JLINKARM_Sleep(1);
                        } while (true);
                        break;

                    case "writeregister":
                        JLINKARM_WriteReg((ARM_REG)val1, val2);
                        break;
                    case "writejtag_ir":
                        Console.WriteLine("...........................CMD not Supported");
                        break;
                    case "writejtag_dr":
                        Console.WriteLine("...........................CMD not Supported");
                        break;
                    default:
                        Console.WriteLine("...........................Unkonwned CMD");
                        break;
                }
            }
        }
        private UInt32 _setupGetVal(string str)
        {
            UInt32 dd;
            if (str.StartsWith("0x") && str.Length >= 3)
            {
                dd = Convert.ToUInt32(str.Substring(2), 16);
            }
            else
            {
                dd = Convert.ToUInt32(str);
            }
            return dd;
        }

        /// <summary>
        /// ARM内部寄存器
        /// </summary>
        /// <remarks></remarks>
        public enum ARM_REG : UInt32
        {
            R0,
            R1,
            R2,
            R3,
            R4,
            R5,
            R6,
            R7,
            CPSR,
            R15,
            R8_USR,
            R9_USR,
            R10_USR,
            R11_USR,
            R12_USR,
            R13_USR,
            R14_USR,
            SPSR_FIQ,
            R8_FIQ,
            R9_FIQ,
            R10_FIQ,
            R11_FIQ,
            R12_FIQ,
            R13_FIQ,
            R14_FIQ,
            SPSR_SVC,
            R13_SVC,
            R14_SVC,
            SPSR_ABT,
            R13_ABT,
            R14_ABT,
            SPSR_IRQ,
            R13_IRQ,
            R14_IRQ,
            SPSR_UND,
            R13_UND,
            R14_UND,
            SPSR_SYS,
            R13_SYS,
            R14_SYS,
            PC = 9
        }

        /// <summary>
        /// 程序断点模式
        /// </summary>
        /// <remarks></remarks>
        public enum BP_MODE : UInt32
        {
            ARM = 1,
            THUMB = 2,
            HARD_ARM = 0xffffff01u,
            HARD_THUMB = 0xffffff02u,
            SOFT_ARM = 0xf1u,
            SOFT_THUMB = 0xf2u
        }

        /// <summary>
        /// 数据断点模式
        /// </summary>
        /// <remarks></remarks>
        public enum WP_MODE : UInt32
        {
            READ_WRITE,
            READ,
            WRITE
        }
    }
}

Program.cs

using Jlink_demo;
using System;
using System.Text;

namespace MyApp // Note: actual namespace depends on the project name.
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Jlink操作演示");
            JLinkHandler.JLINKARM_SetLogFile(System.Text.Encoding.UTF8.GetBytes("this_log.txt"));
            JLinkHandler.JLINKARM_Open();
            var ver = JLinkHandler.JLINKARM_GetDLLVersion();
            Console.WriteLine("DLL 版本: "+ver);
            Console.WriteLine("SN:" + JLinkHandler.JLINKARM_GetSN());
            Console.WriteLine("硬件版本: " + JLinkHandler.JLINKARM_GetHardwareVersion());
            JLinkHandler.JLINKARM_ExecCommand(System.Text.Encoding.UTF8.GetBytes("device = STM32H743VI"), 0, 0);
            JLinkHandler.JLINKARM_TIF_Select(1);
            JLinkHandler.JLINKARM_SetSpeed(4000);
            Console.WriteLine("CPU ID: "+JLinkHandler.JLINKARM_GetId());
            //JLinkHandler.JLINKARM_Connect();
            //JLinkHandler.JLINKARM_Halt();

            //RTT control函数传入的控制参数
            const UInt32 JLINKARM_RTTERMINAL_CMD_START = 0;
            const UInt32 JLINKARM_RTTERMINAL_CMD_STOP = 1;
            const UInt32 JLINKARM_RTTERMINAL_CMD_GETDESC = 2;
            const UInt32 JLINKARM_RTTERMINAL_CMD_GETNUMBUF = 3;
            const UInt32 JLINKARM_RTTERMINAL_CMD_GETSTAT = 4;
            //JLinkHandler.JLINK_RTTERMINAL_Control(JLINKARM_RTTERMINAL_CMD_STOP, 0);
            //JLinkHandler.JLINKARM_Sleep(10);
            //JLINK_RTTERMINAL_Control这个函数的传入参数不太确定
            JLinkHandler.JLINK_RTTERMINAL_Control(JLINKARM_RTTERMINAL_CMD_START, 0);
            JLinkHandler.JLINKARM_Sleep(10);

            //不确认能否正常使用的接口

            //var des = JLinkHandler.JLINK_RTTERMINAL_Control(JLINKARM_RTTERMINAL_CMD_GETDESC, 0);
            //Console.WriteLine($"查找到的描述符:{des:X8}");
            //var num_buf = JLinkHandler.JLINK_RTTERMINAL_Control(JLINKARM_RTTERMINAL_CMD_GETNUMBUF, 0);
            //Console.WriteLine($"缓冲区数量:{num_buf:D4}");
            //var stat = JLinkHandler.JLINK_RTTERMINAL_Control(JLINKARM_RTTERMINAL_CMD_GETSTAT, 0);
            //Console.WriteLine($"状态:{stat:X8}");
            //尝试读取RTT,但是不是每一次都可以成功读取到硬件的RTT调试信息

            int num = 500;
            while (num-- >0)
            {
                Console.Write(JLinkHandler.JLINKARM_ReadRTT_String());//读取RTT接口也是,参数还不确定,有时候可以正常工作,有时候不能
                JLinkHandler.JLINKARM_Sleep(100);
            }
            Console.WriteLine("结束");
            JLinkHandler.JLINK_RTTERMINAL_Control(JLINKARM_RTTERMINAL_CMD_STOP, 0);
            JLinkHandler.JLINKARM_Close();

        }
    }
}

最终成果

我基于上面这些发现写了一个属于我自己的RTT工具,我叫它RTT_ViewerPlusProMax
链接
自用的,可能有些许不完善的,但是简单用应该是可以了…

基本功能如下:
在这里插入图片描述
支持的功能大概就这些
使用时的一些截图~
在这里插入图片描述
定时发送:
在这里插入图片描述

  • 10
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
### 回答1: jlink rtt(Real-Time Transfer)是针对实时系统开发者的一种调试技术,它使用了一种特殊的数据通信方式,通过调试接口和目标设备之间实现实时传输和交互。 在jlink rtt中,对于浮点数的处理与其他数据类型是相同的。可以使用相应的函数来发送和接收浮点数数据。通常,开发者可以使用jlink rtt提供的API来进行浮点数的发送和接收操作。 首先,开发者需要在目标设备的代码中集成jlink rtt库,并初始化RTT通信。然后,可以使用相关的API函数来发送浮点数数据到主机,或者从主机接收浮点数数据。 例如,可以使用函数`SEGGER_RTT_printf()`来发送浮点数数据到主机,函数的用法与打印其他类型数据类似,只需指定格式为"%f"即可。另外,可以使用函数`SEGGER_RTT_Read()`从主机接收浮点数数据,读取到的数据可以直接赋值给浮点数变量。 需要注意的是,由于嵌入式系统的特殊性,浮点数的运算和表示可能会受到硬件和编译器的限制。在使用jlink rtt进行浮点数调试时,开发者需要注意目标设备上浮点数运算的精度、范围和所使用的浮点数格式。 总的来说,jlink rtt可以很好地支持对浮点数数据的发送和接收,方便开发者进行实时调试和数据交互,提高开发效率。 ### 回答2: J-Link Real-Time Transfer(RTT)是Segger公司开发的一种调试技术,可以在嵌入式系统中实现实时的数据传输和交互。浮点(Floating-Point)是一种用于表示和处理实数的数学运算方法。结合起来,J-Link RTT浮点指的是在使用J-Link RTT技术进行嵌入式系统调试时,涉及到实数类型的数据传输和处理。 在使用J-Link RTT时,可以通过RTT通道将浮点数发送到主机端的调试工具,从而达到实时监视和分析嵌入式系统中涉及到的浮点数数据。这对于调试和性能优化很有帮助,特别是当系统涉及到复杂的浮点计算时。通过J-Link RTT浮点技术,开发人员可以随时监控实时的浮点数据并进行相关的分析,从而提高系统的稳定性和性能。 J-Link RTT浮点技术的应用还可以扩展到调试和验证嵌入式系统中的浮点算法的正确性。通过实时传输浮点数据,可以比较和验证系统的计算结果是否正确,从而提高开发效率和减少调试时间。同时,J-Link RTT还支持通过调试工具与嵌入式系统进行交互,可以发送指令和参数到系统中,以控制和调整浮点计算的过程。 综上所述,J-Link RTT浮点是一种在嵌入式系统调试中使用J-Link RTT技术实现实时浮点数据传输和分析的方法,可提高系统的性能和稳定性,并支持浮点算法的验证和调试。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值