-
-
Notifications
You must be signed in to change notification settings - Fork 770
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tested against the MSP432E401YTPDTR that we're using at work. testing w/ attach/detach, manually erasing flash all/sectors, and loading elf files via the gdb 'load' command.
- Loading branch information
Showing
4 changed files
with
357 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -44,6 +44,7 @@ SRC = \ | |
kinetis.c \ | ||
main.c \ | ||
morse.c \ | ||
msp432e4.c \ | ||
msp432p4.c \ | ||
nrf51.c \ | ||
nxpke04.c \ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,354 @@ | ||
/* | ||
* This file is part of the Black Magic Debug project. | ||
* | ||
* Copyright (C) 2022 | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 3 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
/* This file implements MSP432 target specific functions for detecting | ||
* the device, providing the XML memory map and Flash memory programming. | ||
* | ||
* Refereces: | ||
* TI doc - SLAU723a | ||
* MSP423e4xx Technical Reference Manual | ||
*/ | ||
|
||
#include "general.h" | ||
#include "target.h" | ||
#include "target_internal.h" | ||
#include "cortexm.h" | ||
|
||
#define REG_BASE_EEPROM 0x400af000 | ||
#define REG_BASE_FLASH 0x400fd000u | ||
#define REG_BASE_SYSTEM_CONTROL 0x400fe000u | ||
|
||
/* devid 0 | ||
* [31] - 0 - reserved | ||
* [30:28] - 001 - version | ||
* [27:24] - 1000 - reserved | ||
* [23:16] - 0c - device class == msp432e4 | ||
* [15:8] - xx - major | ||
* [7:0] - xx - minor | ||
* devid 1 | ||
* [31:28] - 0001 - version | ||
* [27:24] - 0000 - device family == msp432e4 | ||
* [23:16] - xx - part number w/in family | ||
* [15:13] - bbb - pin count | ||
* [12:8] - 00000 - reserved | ||
* [7:5] - bbb - temperature range | ||
* [4:3] - bb - package type | ||
* [2] - b - rohs | ||
* [1:0] - bb - qualification status | ||
*/ | ||
#define REG_DEVID0 (REG_BASE_SYSTEM_CONTROL + 0x0000u) | ||
#define REG_DEVID0_MASK 0xffff0000u | ||
#define REG_DEVID0_MSP432E4 0x180c0000u | ||
|
||
#define REG_DEVID1 (REG_BASE_SYSTEM_CONTROL + 0x0004u) | ||
#define REG_DEVID1_MASK 0xff000000u | ||
#define REG_DEVID1_MSP432E4 0x10000000u | ||
|
||
/* boot config | ||
* [31] - b - lock register | ||
* [30:16] - 7fff - reserved | ||
* [15:13] - x - gpio port | ||
* [12:10] - x - gpio pin | ||
* [9] - b - gpio polarity | ||
* [8] - b - gpio enable | ||
* [7:5] - 111 - reserved | ||
* [4] - b - key select | ||
* [3:2] - 11 - reserved | ||
* [1:0] - bb - debug control | ||
*/ | ||
#define REG_BOOTCFG (REG_BASE_SYSTEM_CONTROL + 0x01d0u) | ||
|
||
/* flash peripheral properties | ||
* [31] - 0 - reserved | ||
* [30] - b - prefetch buffer mode | ||
* [29] - b - flash mirror mode | ||
* [28] - b - dma flash access | ||
* [27:23] - 00000 - reserved | ||
* [22:19] - bbbb - eeprom sector size | ||
* [18:16] - bbb - flash sector size | ||
* [15:0] - xxxx - flash size | ||
*/ | ||
#define REG_FLASH_PERIPHERAL_PROPERTIES (REG_BASE_FLASH + 0x0fc0u) | ||
|
||
/* sram size | ||
* [31:16] - 0000 - reserved | ||
* [15:0] - xxxx - sram size | ||
*/ | ||
#define REG_FLASH_SRAM_SIZE (REG_BASE_FLASH + 0x0fc4u) | ||
|
||
/* control | ||
* [31:16] - xxxx - write key | ||
* [15:4] - 000 - reserved | ||
* [3] - b - commit | ||
* [2] - b - mass erase | ||
* [1] - b - erase sector | ||
* [0] - b - write | ||
* control 2 | ||
* [31:16] - xxxx - write key | ||
* [15:1] - 0000 - reserved | ||
* [0] - b - buffered flash memory write | ||
*/ | ||
#define REG_FLASH_FMC (REG_BASE_FLASH + 0x0008u) | ||
#define REG_FLASH_FMC2 (REG_BASE_FLASH + 0x0020u) | ||
|
||
/* raw interrupt status | ||
* [31:14] - 00000 - reserved | ||
* [13] - b - program verify | ||
* [12] - 0 - reserved | ||
* [11] - b - erase verify | ||
* [10] - b - invalid data | ||
* [9] - b - pump voltage | ||
* [8:3] - 00 - reserved | ||
* [2] - b - eeprom status | ||
* [1] - b - program status | ||
* [0] - b - access status | ||
*/ | ||
#define REG_FLASH_FCRIS (REG_BASE_FLASH + 0x000cu) | ||
|
||
/* flash write key | ||
* [31:16] - 0000 - reserved | ||
* [15:0] - xxxx - key | ||
*/ | ||
#define REG_FLASH_PEKEY (REG_BASE_FLASH + 0x003cu) | ||
|
||
/* flash access address | ||
* [31:20] - 000 - reserved | ||
* [19:0] - xxxxx - operation aligned address | ||
*/ | ||
#define REG_FLASH_ADDR (REG_BASE_FLASH + 0x0000u) | ||
|
||
/* flash data */ | ||
#define REG_FLASH_DATA (REG_BASE_FLASH + 0x0004u) | ||
|
||
/* eeprom size | ||
* [31:16] - xxxx - # 16bit words | ||
* [15:0] - xxxx - # 32bit words | ||
*/ | ||
#define REG_EEPROM_SIZE (REG_BASE_EEPROM + 0x0000u) | ||
|
||
#define BASE_ADDR_SRAM 0x20000000u | ||
#define BASE_ADDR_FLASH 0x00000000u | ||
|
||
/* Flash operations */ | ||
|
||
/* FixMe - the flash block size might be nice to use, but the part i | ||
* have has a 16k sector which is too big w/ the current build setup. | ||
*/ | ||
#define BUFFERED_WRITE_SIZE 0x100 | ||
|
||
/* Erase from addr for len bytes */ | ||
static bool msp432e4_flash_erase_sectors(struct target_flash* f, | ||
target_addr_t addr, size_t len) | ||
{ | ||
target *t = f->t; | ||
uint32_t fmc = | ||
(((target_mem_read32(t, REG_BOOTCFG) & (1 << 4)) | ||
? 0xa442u | ||
: target_mem_read32(t, REG_FLASH_PEKEY)) << 16) | | ||
(1 << 1); | ||
|
||
for (target_addr_t end = addr + len; addr < end; addr += f->blocksize) { | ||
target_mem_write32(t, REG_FLASH_ADDR, addr); | ||
target_mem_write32(t, REG_FLASH_FMC, fmc); | ||
/* FixMe - verify/timeout bit? */ | ||
while (target_mem_read32(t, REG_FLASH_FMC) & (1 << 1)); | ||
} | ||
return true; | ||
} | ||
|
||
/* special case command for erase all flash */ | ||
static bool msp432e4_flash_erase_all(target* t) | ||
{ | ||
uint32_t fmc = | ||
(((target_mem_read32(t, REG_BOOTCFG) & (1 << 4)) | ||
? 0xa442u | ||
: target_mem_read32(t, REG_FLASH_PEKEY)) << 16) | | ||
(1 << 2); | ||
target_mem_write32(t, REG_FLASH_FMC, fmc); | ||
/* FixMe - timeout/verify bit? */ | ||
while (target_mem_read32(t, REG_FLASH_FMC) & (1 << 2)); | ||
return true; | ||
} | ||
|
||
/* Program flash */ | ||
static bool msp432e4_flash_write(struct target_flash* f, | ||
target_addr_t dst, | ||
const void* src, size_t len) | ||
{ | ||
target* t = f->t; | ||
|
||
uint32_t fmc = | ||
(( 1 || (target_mem_read32(t, REG_BOOTCFG) & (1 << 4)) | ||
? 0xa442u | ||
: target_mem_read32(t, REG_FLASH_PEKEY)) << 16) | | ||
(1 << 0); | ||
|
||
/* copy out the aligned part */ | ||
const uint32_t* s = src; | ||
const uint32_t* const e = src + (len / 4); | ||
for (/**/; s < e; dst += sizeof(uint32_t), s++) { | ||
target_mem_write32(t, REG_FLASH_ADDR, dst); | ||
target_mem_write32(t, REG_FLASH_DATA, *s); | ||
target_mem_write32(t, REG_FLASH_FMC, fmc); | ||
while (target_mem_read32(t, REG_FLASH_FMC) & (1 << 0)); | ||
} | ||
|
||
/* endian little hate i */ | ||
if (len & 3) { | ||
const uint8_t* rem = (const uint8_t*)s; | ||
uint32_t val = 0; | ||
switch (len & 3) { | ||
case 3: val |= rem[2] << 16; /* fallthrough */ | ||
case 2: val |= rem[1] << 8; /* fallthrough */ | ||
case 1: val |= rem[0] << 0; /* fallthrough */ | ||
} | ||
|
||
target_mem_write32(t, REG_FLASH_ADDR, dst); | ||
target_mem_write32(t, REG_FLASH_DATA, val); | ||
target_mem_write32(t, REG_FLASH_FMC, fmc); | ||
while (target_mem_read32(t, REG_FLASH_FMC) & (1 << 0)); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/* Optional commands handlers */ | ||
static bool msp432e4_cmd_erase(target* t, int argc, const char** argv) | ||
{ | ||
if (argc != 2 && argc != 3) | ||
goto err_usage; | ||
|
||
uint32_t addr; | ||
if (strcmp(argv[1], "all") == 0) { | ||
if (argc != 2) | ||
goto err_usage; | ||
return msp432e4_flash_erase_all(t); | ||
} | ||
|
||
char* end; | ||
addr = strtoul(argv[1], &end, 0); | ||
if (end == argv[1]) | ||
goto err_usage; | ||
struct target_flash* f = t->flash; | ||
while (f != NULL) { | ||
if ((f->start <= addr) && (addr < f->start + f->length)) | ||
break; | ||
f = f->next; | ||
} | ||
if (f == NULL) | ||
goto err_usage; | ||
|
||
uint32_t n = 1; | ||
if (argc == 3) { | ||
n = strtoul(argv[2], &end, 0); | ||
if (end == argv[2]) | ||
goto err_usage; | ||
} | ||
n *= f->blocksize; | ||
if (n == 0 || addr + n > f->start + f->length) | ||
goto err_usage; | ||
|
||
return msp432e4_flash_erase_sectors(f, addr, n); | ||
|
||
err_usage: | ||
tc_printf(t, "usage: monitor erase (all | <addr> <n>?)\n"); | ||
return false; | ||
} | ||
|
||
/* Optional commands structure*/ | ||
static const struct command_s msp432e4_cmd_list[] = { | ||
{ "erase", msp432e4_cmd_erase, "Erase flash: all | <sector> <n sectors>?" }, | ||
{ NULL, NULL, NULL }, | ||
}; | ||
|
||
static void msp432e4_add_flash(target* t, uint32_t sector, uint32_t addr, size_t length) | ||
{ | ||
struct target_flash* f = calloc(1, sizeof(*f)); | ||
if (f == NULL) { | ||
DEBUG_WARN("calloc: failed in %s\n", __func__); | ||
return; | ||
} | ||
|
||
f->start = addr; | ||
f->length = length; | ||
f->blocksize = sector; | ||
f->erase = msp432e4_flash_erase_sectors; | ||
f->write = msp432e4_flash_write; | ||
f->writesize = BUFFERED_WRITE_SIZE; | ||
f->erased = 0xff; | ||
target_add_flash(t, f); | ||
} | ||
|
||
bool msp432e4_probe(target* t) | ||
{ | ||
uint32_t devid0 = target_mem_read32(t, REG_DEVID0); | ||
uint32_t devid1 = target_mem_read32(t, REG_DEVID1); | ||
DEBUG_INFO("%s:%d: devid:%x:%x\n", | ||
__func__, __LINE__, | ||
devid0, devid1); | ||
|
||
/* does it look like an msp432e4 variant? */ | ||
if (((devid0 & REG_DEVID0_MASK) != REG_DEVID0_MSP432E4) || | ||
((devid1 & REG_DEVID1_MASK) != REG_DEVID1_MSP432E4)) | ||
return false; | ||
DEBUG_INFO("%s:%d: ver:%x:%x part:%x pin:%x temp:%x package:%x\n", | ||
__func__, __LINE__, | ||
(devid0 >> 8) & 0xff, (devid0 >> 0) & 0xff, | ||
(devid1 >> 16) & 0xff, | ||
(devid1 >> 13) & 0x7, | ||
(devid1 >> 5) & 0x7, | ||
(devid1 >> 3) & 0x3); | ||
|
||
/* eeprom size as # of 32bit words but not directly accessible */ | ||
uint32_t size_eeprom = (target_mem_read32(t, REG_EEPROM_SIZE) & 0xffffu) * 4; | ||
|
||
/* sram is banked but interleaved into one logical bank */ | ||
uint32_t size_sram = ((target_mem_read32(t, REG_FLASH_SRAM_SIZE) & 0xffffu) + 1) * 0x100u; | ||
|
||
/* flash is in four banks but two-way interleaved */ | ||
uint32_t flash_props = target_mem_read32(t, REG_FLASH_PERIPHERAL_PROPERTIES); | ||
uint32_t flash_size = ((flash_props & 0xffffu) + 1) * 0x800; | ||
uint32_t flash_sector = (1 << ((flash_props >> 16) & 0x07)) * 1024; | ||
|
||
#define FORMAT "MSP432E4 %"PRIu32"k eeprom / %"PRIu32"k sram / %"PRIu32"k flash" | ||
size_t nb = snprintf(NULL, 0, | ||
FORMAT, | ||
size_eeprom / 1024, size_sram / 1024, flash_size / 1024); | ||
void* p = malloc(nb + 1); | ||
if (p == NULL) | ||
return false; | ||
snprintf(p, nb + 1, | ||
FORMAT, | ||
size_eeprom / 1024, size_sram / 1024, flash_size / 1024); | ||
t->driver = p; | ||
t->target_storage = p; | ||
#undef FORMAT | ||
|
||
target_add_ram(t, BASE_ADDR_SRAM, size_sram); | ||
|
||
/* the flash is physically 4x but is 2x banked and 2x interleaved. */ | ||
msp432e4_add_flash(t, flash_sector, BASE_ADDR_FLASH, flash_size / 2); | ||
msp432e4_add_flash(t, flash_sector, BASE_ADDR_FLASH + flash_size / 2, flash_size / 2); | ||
|
||
/* Connect the optional commands */ | ||
target_add_commands(t, msp432e4_cmd_list, "MSP432E4"); | ||
|
||
/* All done */ | ||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters