当前位置:网站首页>Self made j-flash burning tool -- QT calls jlinkarm DLL mode
Self made j-flash burning tool -- QT calls jlinkarm DLL mode
2022-07-06 22:26:00 【fangye945a】
Background introduction
I must have played STM32、GD32 All students have used the following burning tool , It is J-Flash. Through it, we can buy jlink、jlink-ob Wait for the burner , Can be very convenient to achieve cortext-M Series of single-chip microcomputer program burning .
But in the production and application of products , We usually have some customized needs , For example, reading MCU Chip ID, According to the chip ID Calculate the secret key , While burning the program, burn the secret key into Flash An area of , So as to realize software encryption and other functions .
Principle analysis
After the analysis of the online bosses, we got an internal message ,J-Flash Most interfaces of the burning tool are encapsulated in the installation directory JLinkARM.dll In dynamic library .
Knowing the news , We can Use depends Tool pair dll Analysis of Library , Get dll All function symbols in the Library , Then find the parameter types and numbers of these functions on the Internet , Then define a function pointer , Point the pointer to the function at dll Address in , To implement the call .
Calling method
Theoretically , As long as it is windows All programs can call dll.
adopt Visual Studio( C#) call JLinkARM.dll, To realize the program download, a big man has written an article .
Here I will Qt( C++) For example , call JLinkARM.dll, Realize program download function and chip ID Read function . The calling method is QLibrary Class is explicitly called .
The sample program
Here are some sample programs for your reference , Including the definition of function pointer 、 Usage method 、 Device to connect 、 Read 、 Burning steps, etc .
Macro definition and function pointer type definition
//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
typedef BOOL (*JLINKARM_Open_Func_Ptr)(void); // Define the type of exported function
typedef void (*JLINKARM_Close_Func_Ptr)(void);
typedef DWORD (*JLINKARM_TIF_Select_Func_Ptr)(int);
typedef void (*JLINKARM_SetSpeed_Func_Ptr)(int);
typedef void (*JLINKARM_Reset_Func_Ptr)(void);
typedef void (*JLINKARM_Go_Func_Ptr)(void);
typedef BOOL (*JLINKARM_IsOpen_Func_Ptr)(void);
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_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 int (*JLINKARM_Halt_Func_Ptr)(void);
typedef BOOL (*JLINKARM_IsHalted_Func_Ptr)(void);
typedef void (*JLINKARM_SetResetType_Func_Ptr)(int type);
typedef void (*JLINKARM_Reset_Func_Ptr)(void);
typedef void (*JLINKARM_Go_Func_Ptr)(void);
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_ReadMem_Func_Ptr)(DWORD addr, int len, void *buf);
typedef int (*JLINKARM_WriteMem_Func_Ptr)(DWORD addr, int len, void *buf);
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 (*JLINK_EraseChip_Func_Ptr)(void);
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);
Function pointer definition
JLINKARM_GetDLLVersion_Func_Ptr JLINKARM_GetDLLVersion_Entry = NULL; // obtain DLL edition
JLINKARM_Open_Func_Ptr JLINKARM_Open_Entry = NULL; // Turn on the device
JLINKARM_IsOpen_Func_Ptr JLINKARM_IsOpen_Entry = NULL; // Has it been opened
JLINKARM_Close_Func_Ptr JLINKARM_Close_Entry = NULL; // Turn off the device
JLINKARM_TIF_Select_Func_Ptr JLINKARM_TIF_Select_Entry = NULL; // Choose the device
JLINKARM_SetSpeed_Func_Ptr JLINKARM_SetSpeed_Entry = NULL; // Set up JLINK Interface speed 0 For automatic adjustment
JLINKARM_Reset_Func_Ptr JLINKARM_Reset_Entry = NULL; // Reset the system
JLINKARM_Halt_Func_Ptr JLINKARM_Halt_Entry = NULL; // Interrupt program execution , Enter the stop state
JLINKARM_Go_Func_Ptr JLINKARM_Go_Entry = NULL; // Execution procedure
JLINKARM_WriteMem_Func_Ptr JLINKARM_WriteMem_Entry = NULL; // Write memory
JLINKARM_ReadMem_Func_Ptr JLINKARM_ReadMem_Entry = NULL; // Read memory
Function entry loading
// Constructor initialization ,new QLibaray When it is passed in dll file
QLibrary jlink_lib = new QLibrary("JLinkARM.dll");
void Widget::load_library_function()
{
if(jlink_lib->load()){
qDebug()<<" load JLinkARM.dll success , Start parsing function ";
JLINKARM_Open_Entry = (JLINKARM_Open_Func_Ptr)jlink_lib->resolve("JLINKARM_Open");
JLINKARM_IsOpen_Entry = (JLINKARM_IsOpen_Func_Ptr)jlink_lib->resolve("JLINKARM_IsOpen");
JLINKARM_Close_Entry = (JLINKARM_Close_Func_Ptr)jlink_lib->resolve("JLINKARM_Close");
JLINKARM_ExecCommand_Entry = (JLINKARM_ExecCommand_Func_Ptr)jlink_lib->resolve("JLINKARM_ExecCommand");
JLINKARM_GetDLLVersion_Entry = (JLINKARM_GetDLLVersion_Func_Ptr)jlink_lib->resolve("JLINKARM_GetDLLVersion");
JLINKARM_TIF_Select_Entry = (JLINKARM_TIF_Select_Func_Ptr)jlink_lib->resolve("JLINKARM_TIF_Select");
JLINKARM_SetSpeed_Entry = (JLINKARM_SetSpeed_Func_Ptr)jlink_lib->resolve("JLINKARM_SetSpeed");
JLINKARM_GetSpeed_Entry = (JLINKARM_GetSpeed_Func_Ptr)jlink_lib->resolve("JLINKARM_GetSpeed");
JLINKARM_Connect_Entry = (JLINKARM_Connect_Func_Ptr)jlink_lib->resolve("JLINKARM_Connect");
JLINKARM_IsConnected_Entry = (JLINKARM_IsConnected_Func_Ptr)jlink_lib->resolve("JLINKARM_IsConnected");
JLINKARM_GetId_Entry = (JLINKARM_GetId_Func_Ptr)jlink_lib->resolve("JLINKARM_GetId");
JLINKARM_GetSN_Entry = (JLINKARM_GetSN_Func_Ptr)jlink_lib->resolve("JLINKARM_GetSN");
JLINKARM_Reset_Entry = (JLINKARM_Reset_Func_Ptr)jlink_lib->resolve("JLINKARM_Reset");
JLINKARM_Halt_Entry = (JLINKARM_Halt_Func_Ptr)jlink_lib->resolve("JLINKARM_Halt");
JLINKARM_WriteMem_Entry = (JLINKARM_WriteMem_Func_Ptr)jlink_lib->resolve("JLINKARM_WriteMem");
JLINKARM_ReadMem_Entry = (JLINKARM_ReadMem_Func_Ptr)jlink_lib->resolve("JLINKARM_ReadMem");
JLINK_EraseChip_Entry = (JLINK_EraseChip_Func_Ptr)jlink_lib->resolve("JLINK_EraseChip");
qDebug()<<" Parsing function completed ";
}
else
{
qDebug()<<" load JLinkARM.dll Failure !!";
}
}
Connecting device
Make sure the equipment is connected before all operations , The following is an example program for device connection .
bool Widget::connect_device()
{
if(JLINKARM_IsOpen())
{
qDebug()<<"JLINKARM was Opened!";
return true;
}
qDebug()<<"Try Open JLINKARM...";
JLINKARM_Open();
if(JLINKARM_IsOpen())
{
qDebug()<<"JLINKARM Open success!";
JLINKARM_ExecCommand("device = STM32F407IG", 0, 0);
JLINKARM_TIF_Select(JLINKARM_TIF_SWD);
JLINKARM_SetSpeed(4000); // Set the download speed
JLINKARM_Connect();
if(JLINKARM_IsConnected()){
return true;
}else
{
print_log(" Failed to connect device ! Please check the device connection ..");
}
}
else {
qDebug()<<"JLINKARM Open fail!";
print_log(" Failed to connect device ! Please check the connection of the burner ..");
}
return false;
}
Read chip ID
After connecting the device, we can use JLINKARM_ReadMem Interface , Read chip ID, That is to read CPUID Value of register address .
QString Widget::get_cpu_id()
{
unsigned char cpuid[12]={
0};
char cpu_id_tmp[128]={
0};
JLINKARM_ReadMem(0x1FFF7A10, 12, cpuid);
JLINKARM_ReadMem(0x1FFF7A10, 12, cpuid); // Read again to solve the problem of reading errors
sprintf(cpu_id_tmp, "%02X%02X%02X%02X-%02X%02X%02X%02X-%02X%02X%02X%02X",
cpuid[3],cpuid[2],cpuid[1],cpuid[0],
cpuid[7],cpuid[6],cpuid[5],cpuid[4],
cpuid[11],cpuid[10],cpuid[9],cpuid[8]);
for(int i=0; i<sizeof(cpuid); i++)
qDebug("cpuid[%d]=%02X", i, cpuid[i]);
qDebug("cpuid=%s",cpu_id_tmp);
return QString(cpu_id_tmp);
}
void Widget::on_pushButton_cpuid_clicked()
{
static int cpuid_reading_flag = 0;
if(cpuid_reading_flag)
{
print_log(QString(" obtain CPUID in , Please later ..."));
return;
}
if( connect_device()){
// qDebug("JLink Info:");
// qDebug("SN = %08u", JLINKARM_GetSN());
// qDebug("ID = %08X", JLINKARM_GetId());
// qDebug("VER = %u", JLINKARM_GetDLLVersion());
// qDebug("Speed = %u", JLINKARM_GetSpeed());
print_log(QString(" obtain CPUID in , Please later ..."));
cpu_id_str = get_cpu_id();
print_log(QString(" obtain CPUID success : ")+cpu_id_str);
disconnect_device();
}
}
Burn program
The burning procedure takes into account that it will last for a period of time , It may cause the interface to fake death . So I used a QTimer Timer to realize the program burning process , Burn at the end of each timing 1KB data , At the same time, update the burning progress bar , Until the burning is over . But in actual use , I don't feel like I really burned the program to MCU In the middle , Just to jlinkARM.dll Interface memory . When disconnected , Will automatically trigger jlinkARM.dll Burning function in , One will pop up JFLASH A small burning window for real burning .
// Constructor initialization , Connect timer timeout signal and slot function
connect(timer_burn, SIGNAL(timeout()),this, SLOT(on_timer_burn_timeout()));
void Widget::on_pushButton_burn_clicked()
{
if(burnning_flag)
{
print_log(" Accelerating burning , Please later ...");
return;
}
burn_bin_data.clear();
total_file_size = 0;
if(target_bin_path.isEmpty())
{
print_log(" Please select the firmware to burn !");
return;
}
if( connect_device() ){
// Connecting device
cpu_id_str = get_cpu_id();// obtain CPUID
bool ok = false; // Check the starting address information
write_start_addr = ui->lineEdit_start_addr->text().trimmed().toInt(&ok, 16);
if(!ok)
{
print_log(" The format of burning start address is incorrect !");
disconnect_device();
return;
}
QFile burn_file;
burn_file.setFileName(target_bin_path);
burn_file.open(QIODevice::ReadOnly); // Open file
if(burn_file.isOpen())
{
burn_bin_data = burn_file.readAll(); // Read the data to be burned into memory
burn_file.close(); // Close file
if(burn_bin_data.size() > 1024*1024)
{
print_log(" The file size cannot exceed 1MB!");
burn_bin_data.clear();
disconnect_device();
return;
}
print_log(" Start burning firmware , Please later ...");
burnning_flag = 1; // Burning
timer_burn->start(BURN_DELAY);
}
else
{
print_log(" Failed to open firmware , Please check whether the file exists !");
disconnect_device();
}
}
}
void Widget::on_timer_burn_timeout()
{
if(timer_burn)
{
timer_burn->stop();
// Burning the firmware
if(burn_bin_data.isEmpty()) // Burn complete
{
ui->progressBar->setValue(100);
burnning_flag = 0;
disconnect_device();
print_log(" Burn complete !");
return;
}
else // The burned data is not empty
{
if(burn_bin_data.size() > BURN_STEP_SIZE) // Larger than 1K
{
int ret = JLINKARM_WriteMem(write_start_addr, BURN_STEP_SIZE, burn_bin_data.data());
// qDebug()<<"JLINKARM_WriteMem ret = "<<ret;
write_start_addr += BURN_STEP_SIZE; // Write address incrementally
burn_bin_data.remove(0, BURN_STEP_SIZE);
}
else // Less than the size of 1K
{
int ret = JLINKARM_WriteMem(write_start_addr, burn_bin_data.size(), burn_bin_data.data());
// qDebug()<<"JLINKARM_WriteMem ret = "<<ret;
write_start_addr += burn_bin_data.size(); // Write address incrementally
burn_bin_data.clear();
}
unsigned int percent = 1.0*(total_file_size - burn_bin_data.size())/total_file_size*100;
// qDebug()<<"Burn progress: "<<percent;
ui->progressBar->setValue(percent);
timer_burn->start(BURN_DELAY);//5ms Then continue to burn
}
}
}
Learn to refer to the portal
In the development process , Stepped on a lot of pits , Here, I'll sort out several articles with reference .
https://www.amobbs.com/thread-5670237-1-1.html
https://www.amobbs.com/thread-5718918-1-1.html
https://blog.csdn.net/qq446252221/article/details/89878996
disclaimer
segger The official website has supporting SDK, Contains the complete header file 、 Library files and PDF file , Students with conditions suggest supporting the genuine .
https://www.segger.com/products/debug-probes/j-link/technology/j-link-sdk
This article is for reference only , Not for commercial use , In case of infringement, please contact to delete .
边栏推荐
猜你喜欢
Classic sql50 questions
Senior soft test (Information System Project Manager) high frequency test site: project quality management
MySQL数据库基本操作-DML
基于 QEMUv8 搭建 OP-TEE 开发环境
The nearest common ancestor of binary (search) tree ●●
The SQL response is slow. What are your troubleshooting ideas?
PVL EDI project case
NPDP认证|产品经理如何跨职能/跨团队沟通?
GNN, please deepen your network layer~
About the professional ethics of programmers, let's talk about it from the way of craftsmanship and neatness
随机推荐
二叉(搜索)树的最近公共祖先 ●●
MySQL数据库基本操作-DML
That's why you can't understand recursion
雅思口语的具体步骤和时间安排是什么样的?
Applet system update prompt, and force the applet to restart and use the new version
Unity3D学习笔记6——GPU实例化(1)
解决项目跨域问题
How do I write Flask's excellent debug log message to a file in production?
Web APIs DOM 时间对象
Hardware development notes (10): basic process of hardware development, making a USB to RS232 module (9): create ch340g/max232 package library sop-16 and associate principle primitive devices
Netxpert xg2 helps you solve the problem of "Cabling installation and maintenance"
硬件开发笔记(十): 硬件开发基本流程,制作一个USB转RS232的模块(九):创建CH340G/MAX232封装库sop-16并关联原理图元器件
Management background --2 Classification list
微信红包封面小程序源码-后台独立版-带测评积分功能源码
QT | UDP broadcast communication, simple use case
Daily question 1: force deduction: 225: realize stack with queue
The nearest common ancestor of binary (search) tree ●●
做接口测试都测什么?有哪些通用测试点?
LeetCode刷题(十一)——顺序刷题51至55
C # réalise la liaison des données du rapport Crystal et l'impression du Code à barres 4