C语言实现ARM MCUJTAG离线调试器

以下是一个使用C语言实现ARM MCU JTAG离线调试器的示例代码,该代码可以读取目标设备的寄存器和内存:

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#define TCK_PIN 0
#define TMS_PIN 1
#define TDI_PIN 2
#define TDO_PIN 3

#define TCK_H() GPIO_SetBits(GPIOA, GPIO_Pin_0)
#define TCK_L() GPIO_ResetBits(GPIOA, GPIO_Pin_0)
#define TMS_H() GPIO_SetBits(GPIOA, GPIO_Pin_1)
#define TMS_L() GPIO_ResetBits(GPIOA, GPIO_Pin_1)
#define TDI_H() GPIO_SetBits(GPIOA, GPIO_Pin_2)
#define TDI_L() GPIO_ResetBits(GPIOA, GPIO_Pin_2)

#define TDO_IN() GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING
#define TDO_OUT() GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP

GPIO_InitTypeDef GPIO_InitStructure;

void JTAG_Init(void);
void JTAG_SendData(uint8_t *data, uint32_t len);
void JTAG_ReceiveData(uint8_t *data, uint32_t len);
void JTAG_ReadReg(uint32_t addr, uint32_t *data);
void JTAG_WriteReg(uint32_t addr, uint32_t data);
void JTAG_ReadMem(uint32_t addr, uint8_t *data, uint32_t len);
void JTAG_WriteMem(uint32_t addr, uint8_t *data, uint32_t len);

int main(void)
{
    uint32_t reg_value;
    uint8_t mem_data[256];

    // 初始化GPIO
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // 初始化JTAG接口
    JTAG_Init();

    // 读取寄存器
    JTAG_ReadReg(0xE000EDFC, &reg_value);
    printf("SP: 0x%08X\n", reg_value);
    JTAG_ReadReg(0xE000EDF0, &reg_value);
    printf("PC: 0x%08X\n", reg_value);

    // 读取内存
    JTAG_ReadMem(0x08000000, mem_data, sizeof(mem_data));
    for (int i = 0; i < sizeof(mem_data); i += 4) {
        printf("0x%08X: %02X %02X %02X %02X\n",
            0x08000000 + i,
            mem_data[i], mem_data[i+1], mem_data[i+2], mem_data[i+3]);
    }

    return 0;
}

void JTAG_Init(void)
{
    // 发送复位序列
    TCK_L();
    TMS_H();
    TDI_L();
    for (int i = 0; i < 5; i++) {
        TCK_H();
        TCK_L();
    }

    // 发送Test-Logic-Reset序列
    TCK_L();
    TMS_H();
    TCK_H();
    TCK_L();
    TCK_H();
    TCK_L();
    TCK_H();
    TCK_L();
    TMS_L();
    TCK_H();
    TCK_L();

    // 发送Run-Test/Idle序列
    for (int i = 0; i < 10; i++) {
        TCK_H();
        TCK_L();
    }
}

void JTAG_SendData(uint8_t *data, uint32_t len)
{
    for (int i = 0; i < len; i++) {
        for (int j = 0; j < 8; j++) {
            if (data[i] & (1 << j)) {
                TDI_H();
            } else {
                TDI_L();
            }

            TCK_H();
            TCK_L();
        }
    }
}

void JTAG_ReceiveData(uint8_t *data, uint32_t len)
{
    for (int i = 0; i < len; i++) {
        data[i] = 0;

        for (int j = 0; j < 8; j++) {
            TCK_H();
            data[i] |= GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3) << j;
            TCK_L();
        }
    }
}

void JTAG_ReadReg(uint32_t addr, uint32_t *data)
{
    uint8_t req[5];
    uint8_t res[4];

    req[0] = 0x8E;
    req[1] = (addr >> 16) & 0xFF;
    req[2] = (addr >> 8) & 0xFF;
    req[3] = (addr >> 0) & 0xFF;
    req[4] = 0x00;

    JTAG_SendData(req, sizeof(req));
    JTAG_ReceiveData(res, sizeof(res));

    *data = (res[0] << 0) | (res[1] << 8) | (res[2] << 16) | (res[3] << 24);
}

void JTAG_WriteReg(uint32_t addr, uint32_t data)
{
    uint8_t req[9];

    req[0] = 0xAE;
    req[1] = (addr >> 16) & 0xFF;
    req[2] = (addr >> 8) & 0xFF;
    req[3] = (addr >> 0) & 0xFF;
    req[4] = (data >> 24) & 0xFF;
    req[5] = (data >> 16) & 0xFF;
    req[6] = (data >> 8) & 0xFF;
    req[7] = (data >> 0) & 0xFF;
    req[8] = 0x00;

    JTAG_SendData(req, sizeof(req));
}

void JTAG_ReadMem(uint32_t addr, uint8_t *data, uint32_t len)
{
    uint8_t req[7];

    req[0] = 0x9E;
    req[1] = (addr >> 16) & 0xFF;
    req[2] = (addr >> 8) & 0xFF;
    req[3] = (addr >> 0) & 0xFF;
    req[4] = (len >> 16) & 0xFF;
    req[5] = (len >> 8) & 0xFF;
    req[6] = (len >> 0) & 0xFF;

    JTAG_SendData(req, sizeof(req));
    JTAG_ReceiveData(data, len);
}

void JTAG_WriteMem(uint32_t addr, uint8_t *data, uint32_t len)
{
    uint8_t req[7];

    req[0] = 0xBE;
    req[1] = (addr >> 16) & 0xFF;
    req[2] = (addr >> 8) & 0xFF;
    req[3] = (addr >> 0) & 0xFF;
    req[4] = (len >> 16) & 0xFF;
    req[5] = (len >> 8) & 0xFF;
    req[6] = (len >> 0) & 0xFF;

    JTAG_SendData(req, sizeof(req));
    JTAG_SendData(data, len);
}

该代码使用STM32F103C8T6作为调试器,通过JTAG接口连接目标设备。调试器通过GPIO控制JTAG接口的时钟和数据线,实现JTAG协议的相关功能。该代码实现了读取寄存器和读取内存的功能,可以用于基本的ARM MCU离线调试。需要注意的是,该代码仅供参考,实际应用需要根据具体的需求进行修改和优化。

相关推荐
eng八戒19 分钟前
【RA-Eco-RA2L1开发板评测】基于 FSP 实现串口打印功能
单片机·嵌入式硬件
坚果派·白晓明25 分钟前
[鸿蒙PC三方库移植适配] 使用 AtomCode + Skills 自动完成Protobuf鸿蒙化适配
c语言·c++·华为·harmonyos
嵌入式ZYXC1 小时前
第2篇:《面试题:LDO和DC-DC的区别?分别用在什么场景?》
stm32·单片机·嵌入式硬件·面试·职场和发展
SoftLipaRZC1 小时前
C语言预处理详解:从宏定义到条件编译
c语言·开发语言
HAPPY酷1 小时前
单片机OLED进阶:打造赛博朋克风“碎片化消散”文字特效
单片机·嵌入式硬件·microsoft
czhaii1 小时前
GB2312简体中文编码表
单片机·算法
玩转单片机与嵌入式1 小时前
AI 推理会不会堵住实时任务?MCU 上跑模型时,RTOS 和 DMA 该怎么配合?
人工智能·单片机·嵌入式硬件
xiangw@GZ2 小时前
ARM TCM 紧耦合内存与 Cache 架构区别
arm开发·架构
Legendary_0082 小时前
18-30W 便携照明设备 USB-C PD 升级:选型与设计要点
c语言·开发语言
清风6666662 小时前
基于单片机的超声波人体感应PWM自动调光灯设计与实现
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业