美文网首页工作生活
通过jlink实现不需要下位机的“上位机”开发

通过jlink实现不需要下位机的“上位机”开发

作者: tianxiaoMCU | 来源:发表于2019-07-14 09:37 被阅读0次

    平时写上位机,串口、USB或者网口,不论哪种方式都需要下位机的配合。也就是得开发两套程序才能实现完整的功能,无论功能繁简。所以经常是嫌麻烦,连简单的都不想弄。直到xx年xx月xx日,挖到了宝:不用写下位机就能达到同样的效果。但是这种方式也是有局限的,就是需要一个调试器,比如jlink、daplink!!!有时候需要一些简易的小工具,我就直接这样搞了,省事点,反正自己用。

    原理

    前面有提到如何使用pylink访问SEGGER RTT,就是程序主动的去读写MCU中SEGGER RTT控制块的数据,也就是程序(上位机)主动去操作(读写)RTT的数据(内存)。在ARM中,内存和寄存器是统一编址的,因此也可以直接去读写寄存器,能读写寄存器意味着就能直接控制外设了。而JLinkARM.dll正好提供了读写某个地址的接口,因此pylink配合jlink就可以达到预期的效果。如果使用其他调试器可以尝试使用pyOCD,应该可以达到样的效果,我还没有试过。

    读写接口

    pylink没有现成封装好的写接口,下面是我封装的。使用的时候添加到pylink\pylink\jlink.py文件的class JLink(object)类中,或者可以到我的仓库下载。
    读接口使用pylink提供的memory_read8memory_read16memory_read32即可。

        @connection_required
        def peripheral_write8(self, addr, value):
            """Writes byte to peripheral register of target system.
            Args:
              self (JLink): the ``JLink`` instance
              addr (int): start address to write to
              value (int): the value to write to the register
            Returns:
              The value written to the register.
            Raises:
              JLinkException: on write error.
            """
            res = self._dll.JLINKARM_WriteU8(addr, value)
            if res != 0:
                raise errors.JLinkWriteException('Error writing to %d' % addr)
            return value
    
        @connection_required
        def peripheral_write16(self, addr, value):
            """Writes half-word to peripheral register of target system.
            Args:
              self (JLink): the ``JLink`` instance
              addr (int): start address to write to
              value (int): the value to write to the register
            Returns:
              The value written to the register.
            Raises:
              JLinkException: on write error.
            """
            res = self._dll.JLINKARM_WriteU16(addr, value)
            if res != 0:
                raise errors.JLinkWriteException('Error writing to %d' % addr)
            return value
    
        @connection_required
        def peripheral_write32(self, addr, value):
            """Writes word to peripheral register of target system.
            Args:
              self (JLink): the ``JLink`` instance
              addr (int): start address to write to
              value (int): the value to write to the register
            Returns:
              The value written to the register.
            Raises:
              JLinkException: on write error.
            """
            res = self._dll.JLINKARM_WriteU32(addr, value)
            if res != 0:
                raise errors.JLinkWriteException('Error writing to %d' % addr)
            return value
    
        @connection_required
        def peripheral_write64(self, addr, value):
            """Writes long word to peripheral register of target system.
            Args:
              self (JLink): the ``JLink`` instance
              addr (int): start address to write to
              value (long): the value to write to the register
            Returns:
              The value written to the register.
            Raises:
              JLinkException: on write error.
            """
            # Default type is uint32_t,so specify the parameter type of the C function, otherwise get "ArgumentError"
            self._dll.JLINKARM_WriteU64.argtypes = [ctypes.c_uint32, ctypes.c_uint64]
            res = self._dll.JLINKARM_WriteU64(addr, value)
            if res != 0:
                raise errors.JLinkWriteException('Error writing to %d' % addr)
            return value
    

    例子:点灯大法

    像USB转串口、转SPI、转IIC,又或者通过ADC实现桌面示波器这种就不多说了,尽情发挥想象。这里简单的演示一下用法:按键(PA0)按下LED(PB10)亮,松开则灭。MCU使用的是NUC472HI8AE。

    import pylink
    import time
    
    # GPIO相关的寄存器地址,从手册上可以得到
    GPIO_BA = 0x40004000
    
    PA_MODE = GPIO_BA + 0x000
    PA_PIN = GPIO_BA + 0x010
    
    PB_MODE = GPIO_BA + 0x040
    PB_DOUT = GPIO_BA + 0x048
    
    jlink = pylink.JLink()
    jlink.open()
    jlink.set_tif(pylink.enums.JLinkInterfaces.SWD)
    jlink.connect('NUC472HI8AE')
    jlink.reset(halt=False)
    
    # 配置按键(PA0)为双向IO(带内部上拉),这里偷懒,直接将整组PA口都设为双向IO
    jlink.peripheral_write32(PA_MODE, 0xFFFFFFFF)
    
    # 配置LED(PB10)为输出
    jlink.peripheral_write32(PB_MODE, 0x01 << 20)
    
    while True:
        # 读取PA引脚的值
        gpio_value = jlink.memory_read32(PA_PIN, 1)
        if gpio_value[0] & 0x01:
            # 关闭LED
            jlink.peripheral_write32(PB_DOUT, 0x01 << 10)
        else:
            # 点亮LED
            jlink.peripheral_write32(PB_DOUT, 0x00 << 10)
        # 10ms 检测一次
        time.sleep(0.01)
    
    jlink.close()
    
    说明

    可以看到,这相当于将原本在mcu上写的程序放到了PC上用python来写。例子中并没有初始化时钟这些操作,是因为使用的NUC472HI8AE上电复位后系统时钟、IO的时钟这些都直接可用,为了简化例子就没有再去配置一遍。如果使用别的MCU,比如STM32L4xx这种,上电复位后IO的时钟默认关闭的,还是得先配置好时钟。

    相关文章

      网友评论

        本文标题:通过jlink实现不需要下位机的“上位机”开发

        本文链接:https://www.haomeiwen.com/subject/rgtrhctx.html