Skip to content

Instantly share code, notes, and snippets.

@GMMan
Last active July 14, 2024 22:00
Show Gist options
  • Save GMMan/a823901763279183a09b9696ec927a49 to your computer and use it in GitHub Desktop.
Save GMMan/a823901763279183a09b9696ec927a49 to your computer and use it in GitHub Desktop.
Dumping ROMs from TI CC2640R2F

Dumping ROMs from TI CC2640R2F

Main flash

Memory address 0x0 to 0x1ffff. Dump over JTAG or built-in bootloader (if enabled).

Boot ROM

Memory address 0x10000000 to 0x1001cbff. Dump over JTAG or built-in bootloader. Note accessing 0x1001cc00 or beyond results in an error.

FCFG1 (ENGR)

Memory address 0x50001000 to 0x500013ff. Dump over JTAG or built-in bootloader.

FCFG2 (OTP?)

Memory address 0x50002000 to 0x500023ff. Dump over JTAG or built-in bootloader.

CCFG

Memory address 0x50003000 to 0x50003fff. Actually mirror of last page of flash.

FCFG0 (Efuse)

#include <ti/devices/DeviceFamily.h>
#include DeviceFamily_constructPath(driverlib/flash.h)

uint32_t buffer[64] = {0};

uint32_t i;
for (i = 0; i < sizeof(buffer) / sizeof(buffer[0]); ++i) {
    FlashEfuseReadRow(&buffer[i], i);
}

FlashProgram(buffer, 0x10000, sizeof(buffer));

Adjust flash destination address, run the code, then dump over JTAG.

CPE_ROM (Cortex-M0 ROM)

Start from the rfEasyLinkRx example to get the RF init done for you, which is required for interfacing with the CPE (Command and Packet Engine, aka Cortex-M0 core).

In easylink/EasyLink_nortos.c (assuming you're using the no RTOS version), remove static from static RF_Handle rfHandle;.

In rfEasyLinkEchoRx_nortos.c, insert the following near the top:

#include DeviceFamily_constructPath(driverlib/cpu.h)
#include DeviceFamily_constructPath(driverlib/flash.h)

uint8_t buf[2048];
extern RF_Handle rfHandle;

typedef signed   char   int8;
typedef unsigned char   uint8;

typedef signed   short  int16;
typedef unsigned short  uint16;

typedef signed   long   int32;
typedef unsigned long   uint32;

// CMD_MEMCPY: Radio Copy Memory
#define CMD_COPY_MEMORY                0x000E  // immediate command
typedef struct __RFC_STRUCT
{
  uint16            cmdNum;            // W:  radio command number
  uint16            nWords;            // W:  num 32 bit words to copy
  uint32           *pDestAddr;         // W:  destination address
  uint32           *pSrcAddr;          // W:  source address
} __RFC_STRUCT_ATTR rfOpImmedCmd_MemCpy_t;

In mainThread(), add the following before the while(1):

uint32_t flashAddr = 0x8000;
uint32_t coprocAddr = 0;

rfOpImmedCmd_MemCpy_t cmd =
{
    .cmdNum = CMD_COPY_MEMORY,
    .nWords = sizeof(buf) / 4,
    .pDestAddr = (uint32*)buf,
};

if (*(uint8_t*)flashAddr == 0xff) {
    for (; flashAddr < 0x1e000; flashAddr += sizeof(buf), coprocAddr += sizeof(buf)) {
        memset(buf, 0x55, sizeof(buf)); // Sanity check for successful read when dumping
        cmd.pSrcAddr = (uint32*)coprocAddr;
        // Required because RF core seems to deactivate itself after an operation
        EasyLink_Status initStat = EasyLink_init(&easyLink_params);
        RF_Stat ret = RF_runImmediateCmd(rfHandle, (uint32_t *)&cmd);
        if (ret != RF_StatCmdDoneSuccess) break;
        CPUcpsid();
        FlashProgram(buf, flashAddr, sizeof(buf));
        CPUcpsie();
    }
}

This will write the ROM to flash address 0x8000 to 0x1dfff. Dump this region over JTAG. Repeat this process with coprocAddr = 0x16000 to dump the rest of the ROM. Stitch the two parts together and truncate to 0x20000 bytes. Remember to erase the full flash between runs if you do not have your flasher configured for a full erase on load.

Alternatively, if you have UART output, you can just write the dumped data to UART instead of writing to flash and grabbing the bytes over JTAG.

MCE_ROM (Modem)

Commands for J-Link Commander, will dump to mce_[0..5].bin. Please set up your connection before running the commands.

connect
reset
// Turn on RFCORE_PD (assume RFC clock is on)
write4 40082130,1
write4 40082188,1
// Set boot command (execute at 0x21000000, which will stop CPE immediately after radio unlock)
write4 400821cc,21000001
// Turn on CPE, MCE and RFE + associated RAM
write4 40040000,7f
// CPE will be stopped now

// Configure MCE for read
write4 40045060,0
// copy address
write4 40045054,0
// bank (note: left shift by 1)
write4 40045048,0
write4 40045060,0
write4 40045000,1
write4 40045004,1
write4 4004504c,7

savebin mce_0.bin,21008000,800

write4 40045048,2
write4 40045004,1
write4 4004504c,7
savebin mce_1.bin,21008000,800

write4 40045048,4
write4 40045004,1
write4 4004504c,7
savebin mce_2.bin,21008000,800

write4 40045048,6
write4 40045004,1
write4 4004504c,7
savebin mce_3.bin,21008000,800

write4 40045048,8
write4 40045004,1
write4 4004504c,7
savebin mce_4.bin,21008000,800

write4 40045048,a
write4 40045004,1
write4 4004504c,7
savebin mce_5.bin,21008000,800

RFE_ROM (RF Engine)

Commands for J-Link Commander, will dump to rfe_[0..5].bin. Please set up your connection before running the commands.

connect
reset
// Turn on RFCORE_PD (assume RFC clock is on)
write4 40082130,1
write4 40082188,1
// Set boot command (execute at 0x21000000, which will stop CPE immediately after radio unlock)
write4 400821cc,21000001
// Turn on CPE, MCE and RFE + associated RAM
write4 40040000,7f
// CPE will be stopped now

// Configure RFE for read
// copy address
write4 40046028,0
// bank (note: left shift by 1)
write4 4004601c,0
write4 40046000,1
write4 40046004,1
write4 40046020,a

savebin rfe_0.bin,2100c000,800

write4 4004601c,2
write4 40046004,1
write4 40046020,a
savebin rfe_1.bin,2100c000,800

write4 4004601c,4
write4 40046004,1
write4 40046020,a
savebin rfe_2.bin,2100c000,800

write4 4004601c,6
write4 40046004,1
write4 40046020,a
savebin rfe_3.bin,2100c000,800

write4 4004601c,8
write4 40046004,1
write4 40046020,a
savebin rfe_4.bin,2100c000,800

write4 4004601c,a
write4 40046004,1
write4 40046020,a
savebin rfe_5.bin,2100c000,800
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment