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 XPSR17 MSP18 PSP19 RAZ20 CFBP21 APSR22 EPSR23 IPSR24 PRIMASK25 BASEPRI26 FAULTMASK27 CONTROL28 BASEPRI_MAX29 IAPSR30 EAPSR31 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 5QTimer *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方式
