Skip to content

Commit

Permalink
msp432e4: add msp432e target
Browse files Browse the repository at this point in the history
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
neutered committed Nov 18, 2022
1 parent bdc90e4 commit 970c52f
Show file tree
Hide file tree
Showing 4 changed files with 357 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ SRC = \
kinetis.c \
main.c \
morse.c \
msp432e4.c \
msp432p4.c \
nrf51.c \
nxpke04.c \
Expand Down
1 change: 1 addition & 0 deletions src/target/cortexm.c
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,7 @@ bool cortexm_probe(ADIv5_AP_t *ap)
PROBE(lpc43xx_probe);
PROBE(kinetis_probe); /* Older K-series */
PROBE(at32fxx_probe);
PROBE(msp432e4_probe);
} else if (t->part_id == 0x4cb) { /* Cortex-M23 ROM */
PROBE(gd32f1_probe); /* GD32E23x uses GD32F1 peripherals */
}
Expand Down
354 changes: 354 additions & 0 deletions src/target/msp432e4.c
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;
}
1 change: 1 addition & 0 deletions src/target/target_probe.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ bool samd_probe(target *t);
bool samx5x_probe(target *t);
bool kinetis_probe(target *t);
bool efm32_probe(target *t);
bool msp432e4_probe(target *t);
bool msp432p4_probe(target *t);
bool ke04_probe(target *t);
bool rp_probe(target *t);
Expand Down

0 comments on commit 970c52f

Please sign in to comment.