Qt--通过JLinkARM.dll实现Jlink自动烧写

一、调用的动态库

在Jlink的安装目录下包含 JLinkARM.dll 动态库,将其拷贝到工程中。

并将 JLinkDevices.xml 与 Devices 文件夹 拷贝到工程运行文件夹,Jlink需要调用识别芯片设备。

二、库函数原型

添加库对应函数原型的头文件,“函数名_Func_Ptr”。

 
//JLINK TIF
#define JLINKARM_TIF_JTAG	0
#define JLINKARM_TIF_SWD	1
#define JLINKARM_TIF_DBM3	2
#define JLINKARM_TIF_FINE	3
#define JLINKARM_TIF_2wire_JTAG_PIC32	4
 
//RESET TYPE
#define JLINKARM_RESET_TYPE_NORMAL 0
#define JLINKARM_RESET_TYPE_CORE   1
#define JLINKARM_RESET_TYPE_PIN    2
 
//REGISTER INDEX
/*
  0 - 15     R0 - R15(SP=R13, PC=R15)
 16          XPSR
 17          MSP
 18          PSP
 19          RAZ
 20          CFBP
 21          APSR
 22          EPSR
 23          IPSR
 24          PRIMASK
 25          BASEPRI
 26          FAULTMASK
 27          CONTROL
 28          BASEPRI_MAX
 29          IAPSR
 30          EAPSR
 31          IEPSR
 */
 
typedef BOOL  (*JLINKARM_Open_Func_Ptr)(void);               //打开设备
typedef void  (*JLINKARM_Close_Func_Ptr)(void);              //关闭设备
typedef BOOL  (*JLINKARM_IsOpen_Func_Ptr)(void);             //是否打开
typedef BOOL  (*JLINKARM_Connect_Func_Ptr)(void);            //连接
typedef BOOL  (*JLINKARM_IsConnected_Func_Ptr)(void);        //是否连接
typedef void  (*JLINKARM_Reset_Func_Ptr)(void);              //复位系统
typedef void  (*JLINKARM_Go_Func_Ptr)(void);                 //制行程序
typedef void  (*JLINKARM_SetSpeed_Func_Ptr)(int);            //设置接口速度
typedef int   (*JLINKARM_Halt_Func_Ptr)(void);               //中断程序,进入停止状态
typedef int   (*JLINKARM_ReadMem_Func_Ptr)(DWORD addr, int len, void *buf);
typedef int   (*JLINKARM_WriteMem_Func_Ptr)(DWORD addr, int len, void *buf);

typedef int   (*JLINK_EraseChip_Func_Ptr)(void);
typedef int   (*JLINK_HSS_Stop_Func_Ptr)(void);


typedef DWORD (*JLINKARM_TIF_Select_Func_Ptr)(int);
typedef void  (*JLINKARM_SetLogFile_Func_Ptr)(char *file);
typedef DWORD (*JLINKARM_GetDLLVersion_Func_Ptr)(void);
typedef DWORD (*JLINKARM_GetHardwareVersion_Func_Ptr)(void);
typedef DWORD (*JLINKARM_GetFirmwareString_Func_Ptr)(char *buff, int count);
typedef DWORD (*JLINKARM_GetSN_Func_Ptr)(void);
 
typedef BOOL  (*JLINKARM_ExecCommand_Func_Ptr)(char* cmd, int a, int b);
typedef DWORD (*JLINKARM_TIF_Select_Func_Ptr)(int type);
typedef void  (*JLINKARM_SetSpeed_Func_Ptr)(int speed);
typedef DWORD (*JLINKARM_GetSpeed_Func_Ptr)(void);
typedef DWORD (*JLINKARM_GetId_Func_Ptr)(void);
typedef DWORD (*JLINKARM_GetDeviceFamily_Func_Ptr)(void);

typedef BOOL  (*JLINKARM_IsHalted_Func_Ptr)(void);
typedef void  (*JLINKARM_SetResetType_Func_Ptr)(int type);
typedef void  (*JLINKARM_GoIntDis_Func_Ptr)(void);
typedef DWORD (*JLINKARM_ReadReg_Func_Ptr)(int index);
typedef int   (*JLINKARM_WriteReg_Func_Ptr)(int index, DWORD data);
 
typedef int   (*JLINKARM_WriteU8_Func_Ptr)(DWORD addr, BYTE data);
typedef int   (*JLINKARM_WriteU16_Func_Ptr)(DWORD addr, WORD data);
typedef int   (*JLINKARM_WriteU32_Func_Ptr)(DWORD addr, DWORD data);
 
typedef int   (*JLINKARM_DownloadFile_Func_Ptr)(LPCSTR file, DWORD addr);
typedef void  (*JLINKARM_BeginDownload_Func_Ptr)(int index);
typedef void  (*JLINKARM_EndDownload_Func_Ptr)(void);

三、动态库的调用

.h

#include <QLibrary>

//建立一个动态库
QLibrary *jlink_lib;


//根据动态库的头文件函数列表进行映射
JLINKARM_Open_Func_Ptr JLINKARM_Open_Entry = NULL;
JLINKARM_IsOpen_Func_Ptr JLINKARM_IsOpen_Entry = NULL;
//...


//新建调用函数,为了方便直接与库函数同名
bool JLINKARM_Open();
bool JLINKARM_IsOpen();

.cpp

//进行动态库函数解析
jlink_lib= new QLibrary("JLink_x64.dll");

if(jlink_lib->load())
{
  qDebug()<<"加载JLink_x64.dll成功, 开始解析函数";
  JLINKARM_Open_Entry = (JLINKARM_Open_Func_Ptr)jlink_lib->resolve("JLINKARM_Open");
  JLINKARM_IsOpen_Entry = (JLINKARM_IsOpen_Func_Ptr)jlink_lib->resolve("JLINKARM_IsOpen");
  //...

  qDebug()<<"解析函数完成";
}
else
{
  qDebug()<<"加载JLink_x64.dll失败!!";
}


//调用函数--根据函数原型进行调用函数的建立
bool JLINKARM_Open()
{
  if(JLINKARM_Open_Entry)
  {
     return JLINKARM_Open_Entry();
  }
  return false;
}
//...

四、具体操作的实现

4.1 Connect 连接设备

//传入参数:芯片名称例如:STM32F429IG
bool OpenDevice(QString device)
{
  if(JLINKARM_IsOpen())
  {
     qDebug()<<"JLINKARM was Opened!";
     return true;
  }

  JLINKARM_Open();
  if(JLINKARM_IsOpen())
  {
     qDebug()<<"JLINKARM open success!";
     QString Str = "device = " + device;
     QByteArray ba = Str.toLatin1();
     char *strInc = ba.data();

     JLINKARM_ExecCommand(strInc,NULL,0);
     JLINKARM_TIF_Select(JLINKARM_TIF_SWD);
     JLINKARM_SetSpeed(4000);
     JLINKARM_Connect();

     if(JLINKARM_IsConnected())
     {
        if(JLINKARM_IsHalted() == 0)
        {
            JLINKARM_Halt();
        }
        qDebug()<<"JlinkARM is connected!";
        return true;
     }
     else
     {
        qDebug()<<"JlinkARM connect failed!";
     }
  }
  else
  {
      qDebug()<<"JlinkARM open failed!";
  }
  return false;
}

4.2 Disconnect 断开连接

bool DisconnectDevice()
{
    JLINKARM_Close();
    if(!JLINKARM_IsOpen())
    {
        qDebug()<<"JLINKARM Close success !";
        return true;
    }
    else
    {
        qDebug()<<"JLINKARM Close fail !";
    }
    return false;
}

4.3 Erase擦除芯片

bool EraseChip()
{
    if(!JLINKARM_IsOpen())
    {
        return false;
    }

    int rHSS_Stop = JLINK_HSS_Stop();
    qDebug()<<QString("JLINK_HSS_Stop: %1 ").arg(rHSS_Stop);

    int rEraseChip = JLINK_EraseChip();
    qDebug()<<QString("EraseChip: %1 ").arg(rEraseChip);

    if(rEraseChip == 0)
    {
        qDebug()<<"JLINK EraseChip success!";
        return true;
    }
    DisconnectDevice();
    qDebug()<<"JLINK EraseChip failed !";
    return false;
}

4.4 Production Programming 烧录文件

#define BURN_STEP_SIZE 1024
#define BURN_DELAY 5


QTimer *timer_burn;
int GetFlashPos;                //Flash烧写递增地址
QByteArray burn_bin_data;       //烧写bin的文件缓冲区


connect(timer_burn, SIGNAL(timeout()),this, SLOT(on_timer_burn_timeout()));


//传参为烧写的起始地址与bin文件的文件路径,只支持bin文件烧录
bool FileBurnBegin(int FlashPos, QString FlashBinFile)
{
    GetFlashPos = FlashPos;        
    burn_bin_data.clear();

    if(FlashBinFile.right(3) != "bin")
    {
        return false;
    }

    QFile burn_file;
    burn_file.setFileName(FlashBinFile);
    burn_file.open(QIODevice::ReadOnly);         //打开文件
    if(burn_file.isOpen())
    {
        burn_bin_data = burn_file.readAll();     //将要烧录的数据读取到内存中
        burn_file.close();                       //关闭文件
        if(burn_bin_data.size() > 1024*1024)
        {
            qDebug()<<"文件大小不允许超过1MB!";
            burn_bin_data.clear();
            DisconnectDevice();
            return;
        }
        qDebug()<<"开始烧录固件, 请稍后...";
        timer_burn->start(BURN_DELAY);
    }
    else
    {
        qDebug()<<"打开固件失败, 请检查文件是否存在!";
        DisconnectDevice();
        return false;
    }
}


void on_timer_burn_timeout()
{
    if(timer_burn->isActive())
    {
        timer_burn->stop();
        if(burn_bin_data.isEmpty())  //烧录完成
        {
            DisconnectDevice();
            return;
        }
        else  //烧录的数据非空
        {
            if(burn_bin_data.size() > BURN_STEP_SIZE)   //大小超过1K
            {
                int ret = JLINKARM_WriteMem(GetFlashPos, 
                                            BURN_STEP_SIZE,
                                            burn_bin_data.data());

                GetFlashPos += BURN_STEP_SIZE; 
                burn_bin_data.remove(0, BURN_STEP_SIZE);
            }
            else    //大小不到1K
            {
                int ret = JLINKARM_WriteMem(GetFlashPos, 
                                            burn_bin_data.size(), 
                                            burn_bin_data.data());

                GetFlashPos += burn_bin_data.size();
                burn_bin_data.clear();
            }
            timer_burn->start(BURN_DELAY);
        }
    }
}

4.5 Start Application 运行程序

JLINKARM_Reset();
OpenDevice();
JLINKARM_Go();

4.6 Verify 校验

//传参为 起始地址,大小与比较的bin文件内容
bool VerifyFlashContent(uint32_t startAddr, uint32_t size, const uint8_t* expectedData)
{
    uint8_t* flashData = (uint8_t*)malloc(size);
    if (!flashData)
    {
        qDebug()<<"内存分配失败...";
        return false;
    }

    if (JLINKARM_ReadMem(startAddr, size, flashData) != 0)
    {
        qDebug()<<"读取Flash失败...";
        free(flashData);
        return false;
    }

    bool match = true;
    for (uint32_t i = 0; i < size; i++) 
    {
        if (flashData[i] != expectedData[i]) {

            qDebug() << QString("数据不匹配在地址 0x%1: Flash=0x%2, 期望=0x%3")
                        .arg(startAddr + i, 8, 16, QLatin1Char('0'))
                        .arg(flashData[i], 2, 16, QLatin1Char('0'))
                        .arg(expectedData[i], 2, 16, QLatin1Char('0'));
            match = false;
            break;
        }
    }
    free(flashData);
    
    if (match) 
    {
        qDebug() << "Flash验证成功!所有数据匹配。";
    } 
    else 
    {
        qDebug() << "Flash验证失败!发现数据不匹配。";
    }
    return match;
}

参考文章:

QT写J-link上位机实现烧录功能

JLinkARM.dll部分导出函数定义

自制J-Flash烧录工具——Qt调用jlinkARM.dll方式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值