当前位置:网站首页>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 .
 Insert picture description here
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
 Insert picture description here
This article is for reference only , Not for commercial use , In case of infringement, please contact to delete .

原网站

版权声明
本文为[fangye945a]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/187/202207061429346158.html