Merge commit 'f89542c79f6edb0d64e7dfa483501718113f45b5' into sam-update

This commit is contained in:
Jason Kotzin 2022-08-02 09:28:24 -07:00
commit fdce017311
37 changed files with 2736 additions and 98 deletions

View File

@ -13,6 +13,10 @@ ifeq ($(PROBE_HOST), pc-stlinkv2)
PC_HOSTED = true
NO_LIBOPENCM3 = true
endif
ifeq ($(PROBE_HOST), pc-hosted)
PC_HOSTED = true
NO_LIBOPENCM3 = true
endif
all:
ifndef NO_LIBOPENCM3

View File

@ -46,8 +46,9 @@ SRC = \
nxpke04.c \
platform.c \
sam3x.c \
sam4l.c \
sam4l.c \
samd.c \
samx5x.c \
stm32f1.c \
stm32f4.c \
stm32h7.c \
@ -71,6 +72,9 @@ endif
ifndef OWN_HL
SRC += jtag_scan.c jtagtap.c swdptap.c
SRC += remote.c
else
CFLAGS += -DOWN_HL
endif
OBJ = $(patsubst %.S,%.o,$(patsubst %.c,%.o,$(SRC)))
@ -118,6 +122,11 @@ all_platforms:
echo "<li><a href='blackmagic-$$PROBE_HOST.bin'>$$PROBE_HOST</a></li>"\
>> artifacts/index.html ;\
fi ;\
if [ -f blackmagic_dfu.bin ]; then \
mv blackmagic_dfu.bin artifacts/blackmagic_dfu-$$PROBE_HOST.bin ;\
echo "<li><a href='blackmagic_dfu-$$PROBE_HOST.bin'>$$PROBE_HOST DFU</a></li>"\
>> artifacts/index.html ;\
fi ;\
done ;\
echo "</ul></body></html>" >> artifacts/index.html ;\
cp artifacts/*.bin artifacts/$(shell git describe --tags --always)

View File

@ -88,7 +88,11 @@ const struct command_s cmd_list[] = {
{"tpwr", (cmd_handler)cmd_target_power, "Supplies power to the target: (enable|disable)"},
#endif
#ifdef PLATFORM_HAS_TRACESWO
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture [(baudrate) for async swo]" },
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, NRZ mode: (baudrate)" },
#else
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, Manchester mode" },
#endif
#endif
#if defined(PLATFORM_HAS_DEBUG) && !defined(PC_HOSTED)
{"debug_bmp", (cmd_handler)cmd_debug_bmp, "Output BMP \"debug\" strings to the second vcom: (enable|disable)"},
@ -112,8 +116,9 @@ long cortexm_wait_timeout = 2000; /* Timeout to wait for Cortex to react on halt
int command_process(target *t, char *cmd)
{
const struct command_s *c;
int argc = 0;
int argc = 1;
const char **argv;
const char *part;
/* Initial estimate for argc */
for(char *s = cmd; *s; s++)
@ -122,8 +127,9 @@ int command_process(target *t, char *cmd)
argv = alloca(sizeof(const char *) * argc);
/* Tokenize cmd to find argv */
for(argc = 0, argv[argc] = strtok(cmd, " \t");
argv[argc]; argv[++argc] = strtok(NULL, " \t"));
argc = 0;
for (part = strtok(cmd, " \t"); part; part = strtok(NULL, " \t"))
argv[argc++] = part;
/* Look for match and call handler */
for(c = cmd_list; c->cmd; c++) {
@ -372,13 +378,21 @@ static bool cmd_traceswo(target *t, int argc, const char **argv)
#else
extern char serial_no[9];
#endif
uint32_t baudrate = 0;
(void)t;
if (argc > 1)
baudrate = atoi(argv[1]);
traceswo_init(baudrate);
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2
if (argc > 1) {
uint32_t baudrate = atoi(argv[1]);
traceswo_init(baudrate);
} else {
gdb_outf("Missing baudrate parameter in command\n");
}
#else
(void)argv;
traceswo_init();
if (argc > 1) {
gdb_outf("Superfluous parameter(s) ignored\n");
}
#endif
gdb_outf("%s:%02X:%02X\n", serial_no, 5, 0x85);
return true;
}

View File

@ -21,7 +21,10 @@
#include "general.h"
#include "target.h"
#if !defined(STM32F1) && !defined(STM32F4)
#if !defined(STM32F0) && !defined(STM32F1) && !defined(STM32F2) && \
!defined(STM32F3) && !defined(STM32F4) && !defined(STM32F7) && \
!defined(STM32L0) && !defined(STM32L1) && !defined(STM32F4) && \
!defined(STM32G0) && !defined(STM32G4)
static const uint32_t crc32_table[] = {
0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9,
0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005,

View File

@ -26,6 +26,7 @@
#include "gdb_if.h"
#include "gdb_packet.h"
#include "hex_utils.h"
#include "remote.h"
#include <stdarg.h>
@ -37,9 +38,52 @@ int gdb_getpacket(char *packet, int size)
int i;
while(1) {
/* Wait for packet start */
while((packet[0] = gdb_if_getchar()) != '$')
if(packet[0] == 0x04) return 1;
/* Wait for packet start */
do {
/* Spin waiting for a start of packet character - either a gdb
* start ('$') or a BMP remote packet start ('!').
*/
do {
packet[0] = gdb_if_getchar();
if (packet[0]==0x04) return 1;
} while ((packet[0] != '$') && (packet[0] != REMOTE_SOM));
#ifndef OWN_HL
if (packet[0]==REMOTE_SOM) {
/* This is probably a remote control packet
* - get and handle it */
i=0;
bool gettingRemotePacket=true;
while (gettingRemotePacket) {
c=gdb_if_getchar();
switch (c) {
case REMOTE_SOM: /* Oh dear, packet restarts */
i=0;
break;
case REMOTE_EOM: /* Complete packet for processing */
packet[i]=0;
remotePacketProcess(i,packet);
gettingRemotePacket=false;
break;
case '$': /* A 'real' gdb packet, best stop squatting now */
packet[0]='$';
gettingRemotePacket=false;
break;
default:
if (i<size) {
packet[i++]=c;
} else {
/* Who knows what is going on...return to normality */
gettingRemotePacket=false;
}
break;
}
}
}
#endif
} while (packet[0] != '$');
i = 0; csum = 0;
/* Capture packet data into buffer */

View File

@ -22,7 +22,12 @@
#include <libopencm3/usb/usbd.h>
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2
void traceswo_init(uint32_t baudrate);
#else
void traceswo_init(void);
#endif
void trace_buf_drain(usbd_device *dev, uint8_t ep);
#endif

View File

@ -38,11 +38,11 @@
#include <libopencm3/cm3/cortex.h>
jmp_buf fatal_error_jmpbuf;
extern uint32_t _ebss;
extern char _ebss[];
void platform_init(void)
{
volatile uint32_t *magic = (uint32_t *) &_ebss;
volatile uint32_t *magic = (uint32_t *)_ebss;
/* Check the USER button*/
rcc_periph_clock_enable(RCC_GPIOA);
if (gpio_get(GPIOA, GPIO0) ||

View File

@ -1,6 +1,7 @@
SYS = $(shell $(CC) -dumpmachine)
CFLAGS += -DPC_HOSTED -DNO_LIBOPENCM3 -DENABLE_DEBUG
LDFLAGS += -lftdi1
CFLAGS += $(shell pkg-config --cflags libftdi1)
LDFLAGS += $(shell pkg-config --libs libftdi1)
ifneq (, $(findstring mingw, $(SYS)))
LDFLAGS += -lusb-1.0 -lws2_32
else ifneq (, $(findstring cygwin, $(SYS)))

View File

@ -0,0 +1,13 @@
TARGET=blackmagic_hosted
SYS = $(shell $(CC) -dumpmachine)
CFLAGS += -DPC_HOSTED -DNO_LIBOPENCM3 -DENABLE_DEBUG
CFLAGS += $(shell pkg-config --cflags libftdi1)
LDFLAGS += $(shell pkg-config --libs libftdi1)
ifneq (, $(findstring mingw, $(SYS)))
LDFLAGS += -lusb-1.0 -lws2_32
CFLAGS += -Wno-cast-function-type
else ifneq (, $(findstring cygwin, $(SYS)))
LDFLAGS += -lusb-1.0 -lws2_32
endif
VPATH += platforms/pc
SRC += timing.c \

View File

@ -0,0 +1,40 @@
PC Hosted variant
THIS IS INCOMPLETE - ONLY SUPPORTS SWD AT THE MOMENT
This variant will use any BMP probe with recent firmware as a remote
actuator, with the actual probe code running on the PC. The BMP itself
is 'dumb' and doesn't do anything (although any secondary serial port
remains available).
To use it, compile for the pc-hosted target and then connect to your normal
BMP GDB port;
src/blackmagic -s /dev/ttyACM0
...you can then connect your gdb session to localhost:2000 for all your
debugging goodness;
$arm-eabi-none-gdb
(gdb) monitor swdp_scan
Target voltage: not supported
Available Targets:
No. Att Driver
1 STM32F1 medium density M3/M4
(gdb) attach 1
Attaching to program: Builds/blackmagic/src/blackmagic, Remote target
0x08001978 in ?? ()
(gdb) file src/blackmagic
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Load new symbol table from "src/blackmagic"? (y or n) y
Reading symbols from src/blackmagic...
(gdb) load
Loading section .text, size 0x1201c lma 0x8002000
Loading section .data, size 0xd8 lma 0x801401c
Start address 0x800d9fc, load size 73972
Transfer rate: 2 KB/sec, 960 bytes/write.
(gdb)
...note that the speed of the probe in this way is about 10 times less than
running native. This build is intended for debug and development only.

View File

@ -0,0 +1,144 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2008 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
* Modified by Dave Marples <dave@marples.net>
*
* 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/>.
*/
/* Low level JTAG implementation using FT2232 with libftdi.
*
* Issues:
* Should share interface with swdptap.c or at least clean up...
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include "general.h"
#include "remote.h"
#include "jtagtap.h"
/* See remote.c/.h for protocol information */
int jtagtap_init(void)
{
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_JTAG_INIT_STR);
platform_buffer_write(construct,s);
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
{
fprintf(stderr,"jtagtap_init failed, error %s\n",s?(char *)&(construct[1]):"unknown");
exit(-1);
}
return 0;
}
void jtagtap_reset(void)
{
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_JTAG_RESET_STR);
platform_buffer_write(construct,s);
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
{
fprintf(stderr,"jtagtap_reset failed, error %s\n",s?(char *)&(construct[1]):"unknown");
exit(-1);
}
}
void jtagtap_tms_seq(uint32_t MS, int ticks)
{
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_JTAG_TMS_STR,ticks,MS);
platform_buffer_write(construct,s);
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
{
fprintf(stderr,"jtagtap_tms_seq failed, error %s\n",s?(char *)&(construct[1]):"unknown");
exit(-1);
}
}
void jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
{
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
uint64_t DIl=*(uint64_t *)DI;
if(!ticks || !DI) return;
/* Reduce the length of DI according to the bits we're transmitting */
DIl&=(1L<<(ticks+1))-1;
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_JTAG_TDIDO_STR,final_tms?REMOTE_TDITDO_TMS:REMOTE_TDITDO_NOTMS,ticks,DIl);
platform_buffer_write(construct,s);
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
{
fprintf(stderr,"jtagtap_tms_seq failed, error %s\n",s?(char *)&(construct[1]):"unknown");
exit(-1);
}
if (DO) {
for (unsigned int i = 1; i*8 <= (unsigned int)ticks; i++)
DO[i - 1] = remotehston(2 , (char *)&construct[s - (i * 2)]);
}
}
void jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks)
{
return jtagtap_tdi_tdo_seq(NULL, final_tms, DI, ticks);
}
uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
{
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_JTAG_NEXT,dTMS?'1':'0',dTDI?'1':'0');
platform_buffer_write(construct,s);
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
{
fprintf(stderr,"jtagtap_next failed, error %s\n",s?(char *)&(construct[1]):"unknown");
exit(-1);
}
return remotehston(-1,(char *)&construct[1]);
}

View File

@ -0,0 +1,352 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
* Additions by Dave Marples <dave@marples.net>
*
* 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/>.
*/
#include "general.h"
#include "gdb_if.h"
#include "version.h"
#include "platform.h"
#include "remote.h"
#include <assert.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
/* Allow 100mS for responses to reach us */
#define RESP_TIMEOUT (100)
/* Define this to see the transactions across the link */
//#define DUMP_TRANSACTIONS
static int f; /* File descriptor for connection to GDB remote */
int set_interface_attribs (int fd, int speed, int parity)
/* A nice routine grabbed from
* https://stackoverflow.com/questions/6947413/how-to-open-read-and-write-from-serial-port-in-c
*/
{
struct termios tty;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0)
{
fprintf(stderr,"error %d from tcgetattr", errno);
return -1;
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0)
{
fprintf(stderr,"error %d from tcsetattr", errno);
return -1;
}
return 0;
}
void platform_init(int argc, char **argv)
{
int c;
char construct[PLATFORM_MAX_MSG_SIZE];
char *serial = NULL;
while((c = getopt(argc, argv, "s:")) != -1) {
switch(c)
{
case 's':
serial = optarg;
break;
}
}
printf("\nBlack Magic Probe (" FIRMWARE_VERSION ")\n");
printf("Copyright (C) 2019 Black Sphere Technologies Ltd.\n");
printf("License GPLv3+: GNU GPL version 3 or later "
"<http://gnu.org/licenses/gpl.html>\n\n");
assert(gdb_if_init() == 0);
f=open(serial,O_RDWR|O_SYNC|O_NOCTTY);
if (f<0)
{
fprintf(stderr,"Couldn't open serial port %s\n",serial);
exit(-1);
}
if (set_interface_attribs (f, 115000, 0)<0)
{
exit(-1);
}
c=snprintf(construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_START_STR);
platform_buffer_write((uint8_t *)construct,c);
c=platform_buffer_read((uint8_t *)construct, PLATFORM_MAX_MSG_SIZE);
if ((!c) || (construct[0]==REMOTE_RESP_ERR))
{
fprintf(stderr,"Remote Start failed, error %s\n",c?(char *)&(construct[1]):"unknown");
exit(-1);
}
printf("Remote is %s\n",&construct[1]);
}
bool platform_target_get_power(void)
{
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_PWR_GET_STR);
platform_buffer_write(construct,s);
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
{
fprintf(stderr,"platform_target_get_power failed, error %s\n",s?(char *)&(construct[1]):"unknown");
exit(-1);
}
return (construct[1]=='1');
}
void platform_target_set_power(bool power)
{
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_PWR_SET_STR,power?'1':'0');
platform_buffer_write(construct,s);
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
{
fprintf(stderr,"platform_target_set_power failed, error %s\n",s?(char *)&(construct[1]):"unknown");
exit(-1);
}
}
void platform_srst_set_val(bool assert)
{
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,REMOTE_SRST_SET_STR,assert?'1':'0');
platform_buffer_write(construct,s);
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
{
fprintf(stderr,"platform_srst_set_val failed, error %s\n",s?(char *)&(construct[1]):"unknown");
exit(-1);
}
}
bool platform_srst_get_val(void)
{
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_SRST_GET_STR);
platform_buffer_write(construct,s);
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
{
fprintf(stderr,"platform_srst_set_val failed, error %s\n",s?(char *)&(construct[1]):"unknown");
exit(-1);
}
return (construct[1]=='1');
}
void platform_buffer_flush(void)
{
}
int platform_buffer_write(const uint8_t *data, int size)
{
int s;
#ifdef DUMP_TRANSACTIONS
printf("%s\n",data);
#endif
s=write(f,data,size);
if (s<0)
{
fprintf(stderr,"Failed to write\n");
exit(-2);
}
return size;
}
int platform_buffer_read(uint8_t *data, int maxsize)
{
uint8_t *c;
int s;
int ret;
uint32_t endTime;
fd_set rset;
struct timeval tv;
c=data;
tv.tv_sec=0;
endTime=platform_time_ms()+RESP_TIMEOUT;
tv.tv_usec=1000*(endTime-platform_time_ms());
/* Look for start of response */
do
{
FD_ZERO(&rset);
FD_SET(f, &rset);
ret = select(f + 1, &rset, NULL, NULL, &tv);
if (ret < 0)
{
fprintf(stderr,"Failed on select\n");
exit(-4);
}
if(ret == 0)
{
fprintf(stderr,"Timeout on read\n");
exit(-3);
}
s=read(f,c,1);
}
while ((s>0) && (*c!=REMOTE_RESP));
/* Now collect the response */
do
{
FD_ZERO(&rset);
FD_SET(f, &rset);
ret = select(f + 1, &rset, NULL, NULL, &tv);
if (ret < 0)
{
fprintf(stderr,"Failed on select\n");
exit(-4);
}
if(ret == 0)
{
fprintf(stderr,"Timeout on read\n");
exit(-3);
}
s=read(f,c,1);
if (*c==REMOTE_EOM)
{
*c=0;
#ifdef DUMP_TRANSACTIONS
printf(" %s\n",data);
#endif
return (c-data);
}
else
c++;
}
while ((s>=0) && (c-data<maxsize));
fprintf(stderr,"Failed to read\n");
exit(-3);
return 0;
}
#if defined(_WIN32) && !defined(__MINGW32__)
#warning "This vasprintf() is dubious!"
int vasprintf(char **strp, const char *fmt, va_list ap)
{
int size = 128, ret = 0;
*strp = malloc(size);
while(*strp && ((ret = vsnprintf(*strp, size, fmt, ap)) == size))
*strp = realloc(*strp, size <<= 1);
return ret;
}
#endif
const char *platform_target_voltage(void)
{
static uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
s=snprintf((char *)construct,PLATFORM_MAX_MSG_SIZE,"%s",REMOTE_VOLTAGE_STR);
platform_buffer_write(construct,s);
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
{
fprintf(stderr,"platform_target_voltage failed, error %s\n",s?(char *)&(construct[1]):"unknown");
exit(-1);
}
return (char *)&construct[1];
}
void platform_delay(uint32_t ms)
{
usleep(ms * 1000);
}
uint32_t platform_time_ms(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
}

View File

@ -0,0 +1,53 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
* Additions by Dave Marples <dave@marples.net>
*
* 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/>.
*/
#ifndef __PLATFORM_H
#define __PLATFORM_H
#include "timing.h"
#ifndef _WIN32
# include <alloca.h>
#else
# ifndef alloca
# define alloca __builtin_alloca
# endif
#endif
#define PLATFORM_HAS_DEBUG
#define PLATFORM_HAS_POWER_SWITCH
#define PLATFORM_MAX_MSG_SIZE (256)
#define PLATFORM_IDENT "PC-HOSTED"
#define BOARD_IDENT PLATFORM_IDENT
#define SET_RUN_STATE(state)
#define SET_IDLE_STATE(state)
#define SET_ERROR_STATE(state)
void platform_buffer_flush(void);
int platform_buffer_write(const uint8_t *data, int size);
int platform_buffer_read(uint8_t *data, int size);
static inline int platform_hwversion(void)
{
return 0;
}
#endif

View File

@ -0,0 +1,123 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2018 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
* Modified by Dave Marples <dave@marples.net>
*
* 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/>.
*/
/* MPSSE bit-banging SW-DP interface over FTDI with loop unrolled.
* Speed is sensible.
*/
#include <stdio.h>
#include <assert.h>
#include "general.h"
#include "swdptap.h"
#include "remote.h"
int swdptap_init(void)
{
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
s=sprintf((char *)construct,"%s",REMOTE_SWDP_INIT_STR);
platform_buffer_write(construct,s);
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
if ((!s) || (construct[0]==REMOTE_RESP_ERR))
{
fprintf(stderr,"swdptap_init failed, error %s\n",s?(char *)&(construct[1]):"unknown");
exit(-1);
}
return 0;
}
bool swdptap_seq_in_parity(uint32_t *res, int ticks)
{
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
s=sprintf((char *)construct,REMOTE_SWDP_IN_PAR_STR,ticks);
platform_buffer_write(construct,s);
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
if ((s<2) || (construct[0]==REMOTE_RESP_ERR))
{
fprintf(stderr,"swdptap_seq_in_parity failed, error %s\n",s?(char *)&(construct[1]):"short response");
exit(-1);
}
*res=remotehston(-1,(char *)&construct[1]);
return (construct[0]!=REMOTE_RESP_OK);
}
uint32_t swdptap_seq_in(int ticks)
{
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
s=sprintf((char *)construct,REMOTE_SWDP_IN_STR,ticks);
platform_buffer_write(construct,s);
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
if ((s<2) || (construct[0]==REMOTE_RESP_ERR))
{
fprintf(stderr,"swdptap_seq_in failed, error %s\n",s?(char *)&(construct[1]):"short response");
exit(-1);
}
return remotehston(-1,(char *)&construct[1]);
}
void swdptap_seq_out(uint32_t MS, int ticks)
{
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
s=sprintf((char *)construct,REMOTE_SWDP_OUT_STR,ticks,MS);
platform_buffer_write(construct,s);
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
if ((s<1) || (construct[0]==REMOTE_RESP_ERR))
{
fprintf(stderr,"swdptap_seq_out failed, error %s\n",s?(char *)&(construct[1]):"short response");
exit(-1);
}
}
void swdptap_seq_out_parity(uint32_t MS, int ticks)
{
uint8_t construct[PLATFORM_MAX_MSG_SIZE];
int s;
s=sprintf((char *)construct,REMOTE_SWDP_OUT_PAR_STR,ticks,MS);
platform_buffer_write(construct,s);
s=platform_buffer_read(construct, PLATFORM_MAX_MSG_SIZE);
if ((s<1) || (construct[1]==REMOTE_RESP_ERR))
{
fprintf(stderr,"swdptap_seq_out_parity failed, error %s\n",s?(char *)&(construct[2]):"short response");
exit(-1);
}
}

View File

@ -654,9 +654,9 @@ void stlink_leave_state(void)
DEBUG("Leaving DEBUG Mode\n");
send_recv(dbg_cmd, 16, NULL, 0);
} else if (data[0] == STLINK_DEV_BOOTLOADER_MODE) {
DEBUG("BOOTLOADER Mode\n");
DEBUG("Leaving BOOTLOADER Mode\n");
} else if (data[0] == STLINK_DEV_MASS_MODE) {
DEBUG("MASS Mode\n");
DEBUG("Leaving MASS Mode\n");
} else {
DEBUG("Unknown Mode %02x\n", data[0]);
}
@ -921,8 +921,8 @@ void stlink_init(int argc, char **argv)
DEBUG("Please update Firmware\n");
goto error_1;
}
stlink_resetsys();
stlink_leave_state();
stlink_resetsys();
assert(gdb_if_init() == 0);
return;
error_1:

View File

@ -98,14 +98,18 @@ unsigned char gdb_if_getchar(void)
{
unsigned char ret;
int i = 0;
#if defined(_WIN32) || defined(__CYGWIN__)
unsigned long opt;
#else
int flags;
#endif
while(i <= 0) {
if(gdb_if_conn <= 0) {
#if defined(_WIN32) || defined(__CYGWIN__)
unsigned long opt = 1;
opt = 1;
ioctlsocket(gdb_if_serv, FIONBIO, &opt);
#else
int flags = fcntl(gdb_if_serv, F_GETFL);
flags = fcntl(gdb_if_serv, F_GETFL);
fcntl(gdb_if_serv, F_SETFL, flags | O_NONBLOCK);
#endif
while(1) {
@ -115,12 +119,12 @@ unsigned char gdb_if_getchar(void)
SET_IDLE_STATE(1);
platform_delay(100);
} else {
DEBUG("error when accepting connection");
DEBUG("error when accepting connection: %s", strerror(errno));
exit(1);
}
} else {
#if defined(_WIN32) || defined(__CYGWIN__)
unsigned long opt = 0;
opt = 0;
ioctlsocket(gdb_if_serv, FIONBIO, &opt);
#else
fcntl(gdb_if_serv, F_SETFL, flags);
@ -129,11 +133,18 @@ unsigned char gdb_if_getchar(void)
}
}
DEBUG("Got connection\n");
#if defined(_WIN32) || defined(__CYGWIN__)
opt = 0;
ioctlsocket(gdb_if_conn, FIONBIO, &opt);
#else
flags = fcntl(gdb_if_conn, F_GETFL);
fcntl(gdb_if_conn, F_SETFL, flags & ~O_NONBLOCK);
#endif
}
i = recv(gdb_if_conn, (void*)&ret, 1, 0);
if(i <= 0) {
gdb_if_conn = -1;
DEBUG("Dropped broken connection\n");
DEBUG("Dropped broken connection: %s\n", strerror(errno));
/* Return '+' in case we were waiting for an ACK */
return '+';
}

View File

@ -1,4 +1,5 @@
CROSS_COMPILE ?= arm-none-eabi-
ST_BOOTLOADER ?=
CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy
@ -10,7 +11,12 @@ LDFLAGS_BOOT := $(LDFLAGS) --specs=nano.specs -lopencm3_stm32f1 \
-Wl,-T,platforms/stm32/stlink.ld -nostartfiles -lc \
-Wl,-Map=mapfile -mthumb -mcpu=cortex-m3 -Wl,-gc-sections \
-L../libopencm3/lib
ifeq ($(ST_BOOTLOADER), 1)
$(info Load address 0x08004000 for original ST-LinkV2 Bootloader)
LDFLAGS = $(LDFLAGS_BOOT) -Wl,-Ttext=0x8004000
else
LDFLAGS = $(LDFLAGS_BOOT) -Wl,-Ttext=0x8002000
endif
ifeq ($(ENABLE_DEBUG), 1)
LDFLAGS += --specs=rdimon.specs

View File

@ -8,10 +8,29 @@ Only if you have a Stlinkv2 with STM32F103C8 versus the STM32F103CB on V2/1
and you want to rewire and use the UART, consider reflashing the the Stlink
firmware.
On StlinkV2, the original ST Bootloader can also be used with
- Compile firmware with "make PROBE_HOST=stlink ST_BOOTLOADER=1"
- Upload firmware with stlink-tool from [stlink-tool](https://github.com/jeanthom/stlink-tool.git).
Before upload, replug the stlink to enter the bootloader.
- After each stlink replug, use call "stlink-tool" without arguments
to enter BMP
Drawback: After each USB replug, DFU needs to be left explicit!
On Linux, add someting like :
`> cat /etc/udev/rules.d/98-stlink.rules`
`SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", ACTION=="add", RUN+="<path-to>/stlink-tool"`
for automatic switch to BMP on replug. However this defeats reflashing further
BMP reflash as long as this rule is active.
## Versions
### [Standalone ST-LINKV2
](https://www.st.com/content/st_com/en/products/development-tools/hardware-development-tools/development-tool-hardware-for-mcus/debug-hardware-for-mcus/debug-hardware-for-stm32-mcus/st-link-v2.html)
### [Standalone ST-LINKV2](https://www.st.com/content/st_com/en/products/development-tools/hardware-development-tools/development-tool-hardware-for-mcus/debug-hardware-for-mcus/debug-hardware-for-stm32-mcus/st-link-v2.html)
Accessible connectors for JTAG/SWD (20-pin) and SWIM.
ST-LINKV2/ISOL).
### ST-LINKV2 clones aka "baite"
@ -21,8 +40,7 @@ board.
JTAG and target SWIM pins are accessible on connector (footprints). They are handled in the swlink branch.
### SWIM-only ST-LINK adapters on STM8 Nucleo-Stm8 boards
As only a SWIM connector is accessible, they are not usefull as BMP target.
### [SWD only ST-LINK adapter
](https://www.st.com/content/ccc/resource/technical/document/technical_note/group0/30/c8/1d/0f/15/62/46/ef/DM00290229/files/DM00290229.pdf/jcr:content/translations/en.DM00290229.pdf)
### [SWD only ST-LINK adapter](https://www.st.com/content/ccc/resource/technical/document/technical_note/group0/30/c8/1d/0f/15/62/46/ef/DM00290229/files/DM00290229.pdf/jcr:content/translations/en.DM00290229.pdf) (Stm32 Nucleo Boards, recent Discovery boards)
SWD, SWO and Reset are accessible on a 6-pin connector row.
Jumper allow to route SWD to on-board target or off-board.
Newer variants have UART TX/RX accessible on a connector
@ -35,8 +53,26 @@ CDCACM USART pins are not accessible. MCO output is used for LED.
#### ST-Link/V2 and ST-Link/V2-A
CDCACM USART pins are not accessible. MCO is connected to on board target.
#### ST-Link/V2-1 and ST-Link/V2-B
### [STLINK-V3SET
](https://www.st.com/content/st_com/en/products/development-tools/hardware-development-tools/development-tool-hardware-for-mcus/debug-hardware-for-mcus/debug-hardware-for-stm32-mcus/stlink-v3set.html)
### [STLINK-V3SET](https://www.st.com/content/st_com/en/products/development-tools/hardware-development-tools/development-tool-hardware-for-mcus/debug-hardware-for-mcus/debug-hardware-for-stm32-mcus/stlink-v3set.html)
## Wiring on Discovery and Nucleo Boards
If there is a 6-pin connector, connect an external target after removing
the 2 jumper shortening the 4-pin connector like this:
1: VCC sense, used only for measurement
2: SWCLK
3: GND
4: SWDIO
5: nSRST (pulled high by on board target. Will reset with on board target
unpowered.
6: SWO
## BMP version detection and handling
All stlink variants
@ -45,3 +81,5 @@ UART RX/TX
PC13 low -> SWIM internal connection
PC13/PC14 both low -> ST-LinkV2 on some F4_Diso boards.

View File

@ -70,6 +70,7 @@
#define PLATFORM_HAS_TRACESWO 1
#define NUM_TRACE_PACKETS (128) /* This is an 8K buffer */
#define TRACESWO_PROTOCOL 2 /* 1 = Manchester, 2 = NRZ / async */
# define SWD_CR GPIO_CRH(SWDIO_PORT)
# define SWD_CR_MULT (1 << ((14 - 8) << 2))

View File

@ -22,13 +22,8 @@
#include <libopencm3/cm3/common.h>
#ifndef STM32F4
# include <libopencm3/stm32/f1/memorymap.h>
# include <libopencm3/stm32/f1/gpio.h>
#else
# include <libopencm3/stm32/f4/memorymap.h>
# include <libopencm3/stm32/f4/gpio.h>
#endif
#include <libopencm3/stm32/memorymap.h>
#include <libopencm3/stm32/gpio.h>
#define INLINE_GPIO

View File

@ -33,6 +33,7 @@
*/
#include "general.h"
#include "cdcacm.h"
#include "traceswo.h"
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/timer.h>

View File

@ -30,7 +30,7 @@
#include "general.h"
#include "cdcacm.h"
#include "platform.h"
#include "traceswo.h"
#include <libopencmsis/core_cm3.h>
#include <libopencm3/cm3/nvic.h>

View File

@ -216,7 +216,10 @@ void USBUSART_ISR(void)
{
uint32_t err = USART_SR(USBUSART);
char c = usart_recv(USBUSART);
if (err & (USART_SR_ORE | USART_SR_FE | USART_SR_NE))
#if !defined(USART_SR_NE) && defined(USART_ISR_NF)
# define USART_SR_NE USART_ISR_NF
#endif
if (err & (USART_FLAG_ORE | USART_FLAG_FE | USART_SR_NE))
return;
/* Turn on LED */

View File

@ -64,6 +64,7 @@
#define PLATFORM_HAS_TRACESWO 1
#define NUM_TRACE_PACKETS (128) /* This is an 8K buffer */
#define TRACESWO_PROTOCOL 2 /* 1 = Manchester, 2 = NRZ / async */
# define SWD_CR GPIO_CRH(SWDIO_PORT)
# define SWD_CR_MULT (1 << ((13 - 8) << 2))

276
src/remote.c Normal file
View File

@ -0,0 +1,276 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2019 Black Sphere Technologies Ltd.
* Written by Dave Marples <dave@marples.net>
*
* 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/>.
*/
#include "general.h"
#include "remote.h"
#include "gdb_packet.h"
#include "swdptap.h"
#include "jtagtap.h"
#include "gdb_if.h"
#include "version.h"
#include <stdarg.h>
#define NTOH(x) ((x<=9)?x+'0':'a'+x-10)
#define HTON(x) ((x<='9')?x-'0':((TOUPPER(x))-'A'+10))
#define TOUPPER(x) ((((x)>='a') && ((x)<='z'))?((x)-('a'-'A')):(x))
#define ISHEX(x) ( \
(((x)>='0') && ((x)<='9')) || \
(((x)>='A') && ((x)<='F')) || \
(((x)>='a') && ((x)<='f')) \
)
uint64_t remotehston(uint32_t limit, char *s)
/* Return numeric version of string, until illegal hex digit, or limit */
{
uint64_t ret=0L;
char c;
while (limit--) {
c=*s++;
if (!ISHEX(c))
return ret;
ret=(ret<<4)|HTON(c);
}
return ret;
}
static void _respond(char respCode, uint64_t param)
/* Send response to far end */
{
char buf[34];
char *p=buf;
gdb_if_putchar(REMOTE_RESP,0);
gdb_if_putchar(respCode,0);
do {
*p++=NTOH((param&0x0f));
param>>=4;
}
while (param);
/* At this point the number to print is the buf, but backwards, so spool it out */
do {
gdb_if_putchar(*--p,0);
} while (p>buf);
gdb_if_putchar(REMOTE_EOM,1);
}
static void _respondS(char respCode, const char *s)
/* Send response to far end */
{
gdb_if_putchar(REMOTE_RESP,0);
gdb_if_putchar(respCode,0);
while (*s) {
/* Just clobber illegal characters so they don't disturb the protocol */
if ((*s=='$') || (*s==REMOTE_SOM) || (*s==REMOTE_EOM))
gdb_if_putchar(' ', 0);
else
gdb_if_putchar(*s, 0);
s++;
}
gdb_if_putchar(REMOTE_EOM,1);
}
void remotePacketProcessSWD(uint8_t i, char *packet)
{
uint8_t ticks;
uint32_t param;
bool badParity;
switch (packet[1]) {
case REMOTE_INIT: /* SS = initialise ================================= */
if (i==2) {
swdptap_init();
_respond(REMOTE_RESP_OK, 0);
} else {
_respond(REMOTE_RESP_ERR,REMOTE_ERROR_WRONGLEN);
}
break;
case REMOTE_IN_PAR: /* = In parity ================================== */
ticks=remotehston(2,&packet[2]);
badParity=swdptap_seq_in_parity(&param, ticks);
_respond(badParity?REMOTE_RESP_PARERR:REMOTE_RESP_OK,param);
break;
case REMOTE_IN: /* = In ========================================= */
ticks=remotehston(2,&packet[2]);
param=swdptap_seq_in(ticks);
_respond(REMOTE_RESP_OK,param);
break;
case REMOTE_OUT: /* = Out ======================================== */
ticks=remotehston(2,&packet[2]);
param=remotehston(-1, &packet[4]);
swdptap_seq_out(param, ticks);
_respond(REMOTE_RESP_OK, 0);
break;
case REMOTE_OUT_PAR: /* = Out parity ================================= */
ticks=remotehston(2,&packet[2]);
param=remotehston(-1, &packet[4]);
swdptap_seq_out_parity(param, ticks);
_respond(REMOTE_RESP_OK, 0);
break;
default:
_respond(REMOTE_RESP_ERR,REMOTE_ERROR_UNRECOGNISED);
break;
}
}
void remotePacketProcessJTAG(uint8_t i, char *packet)
{
uint32_t MS;
uint64_t DO;
uint8_t ticks;
uint64_t DI;
switch (packet[1]) {
case REMOTE_INIT: /* = initialise ================================= */
jtagtap_init();
_respond(REMOTE_RESP_OK, 0);
break;
case REMOTE_RESET: /* = reset ================================= */
jtagtap_reset();
_respond(REMOTE_RESP_OK, 0);
break;
case REMOTE_TMS: /* = TMS Sequence ================================== */
ticks=remotehston(2,&packet[2]);
MS=remotehston(2,&packet[4]);
if (i<4) {
_respond(REMOTE_RESP_ERR,REMOTE_ERROR_WRONGLEN);
} else {
jtagtap_tms_seq( MS, ticks);
_respond(REMOTE_RESP_OK, 0);
}
break;
case REMOTE_TDITDO_TMS: /* = TDI/TDO ========================================= */
case REMOTE_TDITDO_NOTMS:
if (i<5) {
_respond(REMOTE_RESP_ERR,REMOTE_ERROR_WRONGLEN);
} else {
ticks=remotehston(2,&packet[2]);
DI=remotehston(-1,&packet[4]);
jtagtap_tdi_tdo_seq((void *)&DO, (packet[1]==REMOTE_TDITDO_TMS), (void *)&DI, ticks);
/* Mask extra bits on return value... */
DO&=(1<<(ticks+1))-1;
_respond(REMOTE_RESP_OK, DO);
}
break;
case REMOTE_NEXT: /* = NEXT ======================================== */
if (i!=4) {
_respond(REMOTE_RESP_ERR,REMOTE_ERROR_WRONGLEN);
} else {
uint32_t dat=jtagtap_next( (packet[2]=='1'), (packet[3]=='1'));
_respond(REMOTE_RESP_OK,dat);
}
break;
default:
_respond(REMOTE_RESP_ERR,REMOTE_ERROR_UNRECOGNISED);
break;
}
}
void remotePacketProcessGEN(uint8_t i, char *packet)
{
(void)i;
switch (packet[1]) {
case REMOTE_VOLTAGE:
_respondS(REMOTE_RESP_OK,platform_target_voltage());
break;
case REMOTE_SRST_SET:
platform_srst_set_val(packet[2]=='1');
_respond(REMOTE_RESP_OK,0);
break;
case REMOTE_SRST_GET:
_respond(REMOTE_RESP_OK,platform_srst_get_val());
break;
case REMOTE_PWR_SET:
#ifdef PLATFORM_HAS_POWER_SWITCH
platform_target_set_power(packet[2]=='1');
_respond(REMOTE_RESP_OK,0);
#else
_respond(REMOTE_RESP_NOTSUP,0);
#endif
break;
case REMOTE_PWR_GET:
#ifdef PLATFORM_HAS_POWER_SWITCH
_respond(REMOTE_RESP_OK,platform_target_get_power());
#else
_respond(REMOTE_RESP_NOTSUP,0);
#endif
break;
#if !defined(BOARD_IDENT) && defined(PLATFORM_IDENT)
# define BOARD_IDENT PLATFORM_IDENT
#endif
case REMOTE_START:
_respondS(REMOTE_RESP_OK, BOARD_IDENT " " FIRMWARE_VERSION);
break;
default:
_respond(REMOTE_RESP_ERR,REMOTE_ERROR_UNRECOGNISED);
break;
}
}
void remotePacketProcess(uint8_t i, char *packet)
{
switch (packet[0]) {
case REMOTE_SWDP_PACKET:
remotePacketProcessSWD(i,packet);
break;
case REMOTE_JTAG_PACKET:
remotePacketProcessJTAG(i,packet);
break;
case REMOTE_GEN_PACKET:
remotePacketProcessGEN(i,packet);
break;
default: /* Oh dear, unrecognised, return an error */
_respond(REMOTE_RESP_ERR,REMOTE_ERROR_UNRECOGNISED);
break;
}
}

131
src/remote.h Normal file
View File

@ -0,0 +1,131 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2019 Black Sphere Technologies Ltd.
* Written by Dave Marples <dave@marples.net>
*
* 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/>.
*/
#ifndef _REMOTE_
#define _REMOTE_
#include <inttypes.h>
#include "general.h"
/*
* Commands to remote end, and responses
* =====================================
*
* All commands as sent as ASCII and begin with !, ending with #.
* Parameters are hex digits and format is per command.
*
* !<CMD><PARAM>#
* <CMD> - 2 digit ASCII value
* <PARAM> - x digits (according to command) ASCII value
*
* So, for example;
*
* SI - swdptap_seq_in_parity
* tt - Ticks
* e.g. SI21 : Request input with parity, 33 ticks
* resp: K<PARAM> - hex value returned.
* resp: F<PARAM> - hex value returned, bad parity.
* X<err> - error occured
*
* The whole protocol is defined in this header file. Parameters have
* to be marshalled in remote.c, swdptap.c and jtagtap.c, so be
* careful to ensure the parameter handling matches the protocol
* definition when anything is changed.
*/
/* Protocol error messages */
#define REMOTE_ERROR_UNRECOGNISED 1
#define REMOTE_ERROR_WRONGLEN 2
/* Start and end of message identifiers */
#define REMOTE_SOM '!'
#define REMOTE_EOM '#'
#define REMOTE_RESP '&'
/* Generic protocol elements */
#define REMOTE_START 'A'
#define REMOTE_TDITDO_TMS 'D'
#define REMOTE_TDITDO_NOTMS 'd'
#define REMOTE_IN_PAR 'I'
#define REMOTE_IN 'i'
#define REMOTE_NEXT 'N'
#define REMOTE_OUT_PAR 'O'
#define REMOTE_OUT 'o'
#define REMOTE_PWR_SET 'P'
#define REMOTE_PWR_GET 'p'
#define REMOTE_RESET 'R'
#define REMOTE_INIT 'S'
#define REMOTE_TMS 'T'
#define REMOTE_VOLTAGE 'V'
#define REMOTE_SRST_SET 'Z'
#define REMOTE_SRST_GET 'z'
/* Protocol response options */
#define REMOTE_RESP_OK 'K'
#define REMOTE_RESP_PARERR 'P'
#define REMOTE_RESP_ERR 'E'
#define REMOTE_RESP_NOTSUP 'N'
/* Generic protocol elements */
#define REMOTE_GEN_PACKET 'G'
#define REMOTE_START_STR (char []){ '+', REMOTE_EOM, REMOTE_SOM, REMOTE_GEN_PACKET, REMOTE_START, REMOTE_EOM, 0 }
#define REMOTE_VOLTAGE_STR (char []){ REMOTE_SOM, REMOTE_GEN_PACKET, REMOTE_VOLTAGE, REMOTE_EOM, 0 }
#define REMOTE_SRST_SET_STR (char []){ REMOTE_SOM, REMOTE_GEN_PACKET, REMOTE_SRST_SET, '%', 'c', REMOTE_EOM, 0 }
#define REMOTE_SRST_GET_STR (char []){ REMOTE_SOM, REMOTE_GEN_PACKET, REMOTE_SRST_GET, REMOTE_EOM, 0 }
#define REMOTE_PWR_SET_STR (char []){ REMOTE_SOM, REMOTE_GEN_PACKET, REMOTE_PWR_SET, '%', 'c', REMOTE_EOM, 0 }
#define REMOTE_PWR_GET_STR (char []){ REMOTE_SOM, REMOTE_GEN_PACKET, REMOTE_PWR_GET, REMOTE_EOM, 0 }
/* SWDP protocol elements */
#define REMOTE_SWDP_PACKET 'S'
#define REMOTE_SWDP_INIT_STR (char []){ REMOTE_SOM, REMOTE_SWDP_PACKET, REMOTE_INIT, REMOTE_EOM, 0 }
#define REMOTE_SWDP_IN_PAR_STR (char []){ REMOTE_SOM, REMOTE_SWDP_PACKET, REMOTE_IN_PAR, \
'%','0','2','x',REMOTE_EOM, 0 }
#define REMOTE_SWDP_IN_STR (char []){ REMOTE_SOM, REMOTE_SWDP_PACKET, REMOTE_IN, \
'%','0','2','x',REMOTE_EOM, 0 }
#define REMOTE_SWDP_OUT_STR (char []){ REMOTE_SOM, REMOTE_SWDP_PACKET, REMOTE_OUT, \
'%','0','2','x','%','x',REMOTE_EOM, 0 }
#define REMOTE_SWDP_OUT_PAR_STR (char []){ REMOTE_SOM, REMOTE_SWDP_PACKET, REMOTE_OUT_PAR, \
'%','0','2','x','%','x',REMOTE_EOM, 0 }
/* JTAG protocol elements */
#define REMOTE_JTAG_PACKET 'J'
#define REMOTE_JTAG_INIT_STR (char []){ '+',REMOTE_EOM, REMOTE_SOM, REMOTE_JTAG_PACKET, REMOTE_INIT, REMOTE_EOM, 0 }
#define REMOTE_JTAG_RESET_STR (char []){ '+',REMOTE_EOM, REMOTE_SOM, REMOTE_JTAG_PACKET, REMOTE_RESET, REMOTE_EOM, 0 }
#define REMOTE_JTAG_TMS_STR (char []){ REMOTE_SOM, REMOTE_JTAG_PACKET, REMOTE_TMS, \
'%','0','2','x','%','x',REMOTE_EOM, 0 }
#define REMOTE_JTAG_TDIDO_STR (char []){ REMOTE_SOM, REMOTE_JTAG_PACKET, '%', 'c', \
'%','0','2','x','%','l', 'x', REMOTE_EOM, 0 }
#define REMOTE_JTAG_NEXT (char []){ REMOTE_SOM, REMOTE_JTAG_PACKET, REMOTE_NEXT, \
'%','c','%','c',REMOTE_EOM, 0 }
uint64_t remotehston(uint32_t limit, char *s);
void remotePacketProcess(uint8_t i, char *packet);
#endif

View File

@ -30,10 +30,6 @@
#include "cortexm.h"
#include "exception.h"
#ifndef DO_RESET_SEQ
#define DO_RESET_SEQ 0
#endif
/* All this should probably be defined in a dedicated ADIV5 header, so that they
* are consistently named and accessible when needed in the codebase.
*/
@ -263,7 +259,7 @@ static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion,
uint32_t cidr = 0;
bool res = false;
#if defined(ENABLE_DEBUG) && defined(PLATFORM_HAS_DEBUG)
char indent[recursion];
char indent[recursion + 1];
for(int i = 0; i < recursion; i++) indent[i] = ' ';
indent[recursion] = 0;
@ -455,26 +451,33 @@ void adiv5_dp_init(ADIv5_DP_t *dp)
(ADIV5_DP_CTRLSTAT_CSYSPWRUPACK | ADIV5_DP_CTRLSTAT_CDBGPWRUPACK)) !=
(ADIV5_DP_CTRLSTAT_CSYSPWRUPACK | ADIV5_DP_CTRLSTAT_CDBGPWRUPACK));
if(DO_RESET_SEQ) {
/* This AP reset logic is described in ADIv5, but fails to work
* correctly on STM32. CDBGRSTACK is never asserted, and we
* just wait forever.
*/
/* This AP reset logic is described in ADIv5, but fails to work
* correctly on STM32. CDBGRSTACK is never asserted, and we
* just wait forever. This scenario is described in B2.4.1
* so we have a timeout mechanism in addition to the sensing one.
*/
/* Write request for debug reset */
adiv5_dp_write(dp, ADIV5_DP_CTRLSTAT,
ctrlstat |= ADIV5_DP_CTRLSTAT_CDBGRSTREQ);
/* Wait for acknowledge */
while(!((ctrlstat = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT)) &
ADIV5_DP_CTRLSTAT_CDBGRSTACK));
/* Write request for debug reset */
adiv5_dp_write(dp, ADIV5_DP_CTRLSTAT,
ctrlstat |= ADIV5_DP_CTRLSTAT_CDBGRSTREQ);
/* Write request for debug reset release */
adiv5_dp_write(dp, ADIV5_DP_CTRLSTAT,
ctrlstat &= ~ADIV5_DP_CTRLSTAT_CDBGRSTREQ);
/* Wait for acknowledge */
while(adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT) &
ADIV5_DP_CTRLSTAT_CDBGRSTACK);
}
platform_timeout timeout;
platform_timeout_set(&timeout,200);
/* Wait for acknowledge */
while ((!platform_timeout_is_expired(&timeout)) &&
(!((ctrlstat = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT)) & ADIV5_DP_CTRLSTAT_CDBGRSTACK))
);
/* Write request for debug reset release */
adiv5_dp_write(dp, ADIV5_DP_CTRLSTAT,
ctrlstat &= ~ADIV5_DP_CTRLSTAT_CDBGRSTREQ);
platform_timeout_set(&timeout,200);
/* Wait for acknowledge */
while ((!platform_timeout_is_expired(&timeout)) &&
(adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT) & ADIV5_DP_CTRLSTAT_CDBGRSTACK)
);
DEBUG("RESET_SEQ %s\n", (platform_timeout_is_expired(&timeout)) ? "failed": "succeeded");
dp->dp_idcode = adiv5_dp_read(dp, ADIV5_DP_IDCODE);
if ((dp->dp_idcode & ADIV5_DP_VERSION_MASK) == ADIV5_DPv2) {

View File

@ -370,6 +370,7 @@ bool cortexm_probe(ADIv5_AP_t *ap, bool forced)
PROBE(sam4l_probe);
PROBE(nrf51_probe);
PROBE(samd_probe);
PROBE(samx5x_probe);
PROBE(lmi_probe);
PROBE(kinetis_probe);
PROBE(efm32_probe);

View File

@ -39,6 +39,7 @@
#include "target_internal.h"
#define SIM_SDID 0x40048024
#define SIM_FCFG1 0x4004804C
#define FTFA_BASE 0x40020000
#define FTFA_FSTAT (FTFA_BASE + 0x00)
@ -127,7 +128,61 @@ static void kl_gen_add_flash(target *t, uint32_t addr, size_t length,
bool kinetis_probe(target *t)
{
uint32_t sdid = target_mem_read32(t, SIM_SDID);
uint32_t fcfg1 = target_mem_read32(t, SIM_FCFG1);
switch (sdid >> 20) {
case 0x161:
/* sram memory size */
switch((sdid >> 16) & 0x0f) {
case 0x03:/* 4 KB */
target_add_ram(t, 0x1ffffc00, 0x0400);
target_add_ram(t, 0x20000000, 0x0C00);
break;
case 0x04:/* 8 KB */
target_add_ram(t, 0x1ffff800, 0x0800);
target_add_ram(t, 0x20000000, 0x1800);
break;
case 0x05:/* 16 KB */
target_add_ram(t, 0x1ffff000, 0x1000);
target_add_ram(t, 0x20000000, 0x3000);
break;
case 0x06:/* 32 KB */
target_add_ram(t, 0x1fffe000, 0x2000);
target_add_ram(t, 0x20000000, 0x6000);
break;
default:
return false;
break;
}
/* flash memory size */
switch((fcfg1 >> 24) & 0x0f) {
case 0x03: /* 32 KB */
t->driver = "KL16Z32Vxxx";
kl_gen_add_flash(t, 0x00000000, 0x08000, 0x400, KL_WRITE_LEN);
break;
case 0x05: /* 64 KB */
t->driver = "KL16Z64Vxxx";
kl_gen_add_flash(t, 0x00000000, 0x10000, 0x400, KL_WRITE_LEN);
break;
case 0x07: /* 128 KB */
t->driver = "KL16Z128Vxxx";
kl_gen_add_flash(t, 0x00000000, 0x20000, 0x400, KL_WRITE_LEN);
break;
case 0x09: /* 256 KB */
t->driver = "KL16Z256Vxxx";
kl_gen_add_flash(t, 0x00000000, 0x40000, 0x400, KL_WRITE_LEN);
break;
default:
return false;
break;
}
break;
case 0x251:
t->driver = "KL25";
target_add_ram(t, 0x1ffff000, 0x1000);

View File

@ -35,6 +35,26 @@
#define LPC11XX_DEVICE_ID 0x400483F4
#define LPC8XX_DEVICE_ID 0x400483F8
static bool lpc11xx_read_uid(target *t, int argc, const char *argv[])
{
(void)argc;
(void)argv;
struct lpc_flash *f = (struct lpc_flash *)t->flash;
uint8_t uid[16];
if (lpc_iap_call(f, uid, IAP_CMD_READUID))
return false;
tc_printf(t, "UID: 0x");
for (uint32_t i = 0; i < sizeof(uid); ++i)
tc_printf(t, "%02x", uid[i]);
tc_printf(t, "\n");
return true;
}
const struct command_s lpc11xx_cmd_list[] = {
{"readuid", lpc11xx_read_uid, "Read out the 16-byte UID."},
{NULL, NULL, NULL}
};
void lpc11xx_add_flash(target *t, uint32_t addr, size_t len, size_t erasesize)
{
struct lpc_flash *lf = lpc_add_flash(t, addr, len);
@ -89,6 +109,7 @@ lpc11xx_probe(target *t)
t->driver = "LPC11xx";
target_add_ram(t, 0x10000000, 0x2000);
lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000);
target_add_commands(t, lpc11xx_cmd_list, "LPC11xx");
return true;
case 0x0A24902B:
@ -97,8 +118,16 @@ lpc11xx_probe(target *t)
target_add_ram(t, 0x10000000, 0x1000);
lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x1000);
return true;
case 0x3000002B:
case 0x3D00002B:
t->driver = "LPC1343";
target_add_ram(t, 0x10000000, 0x2000);
lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x1000);
return true;
}
if (idcode) {
DEBUG("LPC11xx: Unknown IDCODE 0x%08" PRIx32 "\n", idcode);
}
idcode = target_mem_read32(t, LPC8XX_DEVICE_ID);
switch (idcode) {
case 0x00008100: /* LPC810M021FN8 */
@ -109,6 +138,7 @@ lpc11xx_probe(target *t)
t->driver = "LPC81x";
target_add_ram(t, 0x10000000, 0x1000);
lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400);
target_add_commands(t, lpc11xx_cmd_list, "LPC81x");
return true;
case 0x00008221: /* LPC822M101JHI33 */
case 0x00008222: /* LPC822M101JDH20 */
@ -117,6 +147,23 @@ lpc11xx_probe(target *t)
t->driver = "LPC82x";
target_add_ram(t, 0x10000000, 0x2000);
lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400);
target_add_commands(t, lpc11xx_cmd_list, "LPC82x");
return true;
case 0x00008441:
case 0x00008442:
case 0x00008443: /* UM11029 Rev.1.4 list 8442 */
case 0x00008444:
t->driver = "LPC844";
target_add_ram(t, 0x10000000, 0x2000);
lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x400);
return true;
case 0x00008451:
case 0x00008452:
case 0x00008453:
case 0x00008454:
t->driver = "LPC845";
target_add_ram(t, 0x10000000, 0x4000);
lpc11xx_add_flash(t, 0x00000000, 0x10000, 0x400);
return true;
case 0x0003D440: /* LPC11U34/311 */
case 0x0001cc40: /* LPC11U34/421 */
@ -130,12 +177,16 @@ lpc11xx_probe(target *t)
target_add_ram(t, 0x10000000, 0x2000);
lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000);
return true;
case 0x00040070: /* LPC1114/333 */
case 0x00050080: /* lpc1115XL */
t->driver = "LPC1100XL";
target_add_ram(t, 0x10000000, 0x2000);
lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000);
return true;
}
if (idcode) {
DEBUG("LPC8xx: Unknown IDCODE 0x%08" PRIx32 "\n", idcode);
}
return false;
}

View File

@ -35,6 +35,26 @@
#define LPC15XX_DEVICE_ID 0x400743F8
static bool lpc15xx_read_uid(target *t, int argc, const char *argv[])
{
(void)argc;
(void)argv;
struct lpc_flash *f = (struct lpc_flash *)t->flash;
uint8_t uid[16];
if (lpc_iap_call(f, uid, IAP_CMD_READUID))
return false;
tc_printf(t, "UID: 0x");
for (uint32_t i = 0; i < sizeof(uid); ++i)
tc_printf(t, "%02x", uid[i]);
tc_printf(t, "\n");
return true;
}
const struct command_s lpc15xx_cmd_list[] = {
{"readuid", lpc15xx_read_uid, "Read out the 16-byte UID."},
{NULL, NULL, NULL}
};
void lpc15xx_add_flash(target *t, uint32_t addr, size_t len, size_t erasesize)
{
struct lpc_flash *lf = lpc_add_flash(t, addr, len);
@ -72,6 +92,7 @@ lpc15xx_probe(target *t)
t->driver = "LPC15xx";
target_add_ram(t, 0x02000000, ram_size);
lpc15xx_add_flash(t, 0x00000000, 0x40000, 0x1000);
target_add_commands(t, lpc15xx_cmd_list, "LPC15xx");
return true;
}

View File

@ -164,11 +164,11 @@ static bool lpc43xx_cmd_erase(target *t, int argc, const char *argv[])
for (int bank = 0; bank < FLASH_NUM_BANK; bank++)
{
struct lpc_flash *f = (struct lpc_flash *)t->flash;
if (lpc_iap_call(f, IAP_CMD_PREPARE,
if (lpc_iap_call(f, NULL, IAP_CMD_PREPARE,
0, FLASH_NUM_SECTOR-1, bank))
return false;
if (lpc_iap_call(f, IAP_CMD_ERASE,
if (lpc_iap_call(f, NULL, IAP_CMD_ERASE,
0, FLASH_NUM_SECTOR-1, CPU_CLK_KHZ, bank))
return false;
}
@ -188,7 +188,7 @@ static int lpc43xx_flash_init(target *t)
/* Initialize flash IAP */
struct lpc_flash *f = (struct lpc_flash *)t->flash;
if (lpc_iap_call(f, IAP_CMD_INIT))
if (lpc_iap_call(f, NULL, IAP_CMD_INIT))
return -1;
return 0;
@ -234,7 +234,7 @@ static bool lpc43xx_cmd_mkboot(target *t, int argc, const char *argv[])
/* special command to compute/write magic vector for signature */
struct lpc_flash *f = (struct lpc_flash *)t->flash;
if (lpc_iap_call(f, IAP_CMD_SET_ACTIVE_BANK, bank, CPU_CLK_KHZ)) {
if (lpc_iap_call(f, NULL, IAP_CMD_SET_ACTIVE_BANK, bank, CPU_CLK_KHZ)) {
tc_printf(t, "Set bootable failed.\n");
return false;
}

View File

@ -29,7 +29,8 @@ struct flash_param {
uint16_t pad0;
uint32_t command;
uint32_t words[4];
uint32_t result;
uint32_t status;
uint32_t result[4];
} __attribute__((aligned(4)));
@ -53,7 +54,7 @@ struct lpc_flash *lpc_add_flash(target *t, target_addr addr, size_t length)
return lf;
}
enum iap_status lpc_iap_call(struct lpc_flash *f, enum iap_cmd cmd, ...)
enum iap_status lpc_iap_call(struct lpc_flash *f, void *result, enum iap_cmd cmd, ...)
{
target *t = f->f.t;
struct flash_param param = {
@ -65,6 +66,14 @@ enum iap_status lpc_iap_call(struct lpc_flash *f, enum iap_cmd cmd, ...)
if (f->wdt_kick)
f->wdt_kick(t);
/* save IAP RAM to restore after IAP call */
struct flash_param backup_param;
target_mem_read(t, &backup_param, f->iap_ram, sizeof(backup_param));
/* save registers to restore after IAP call */
uint32_t backup_regs[t->regs_size / sizeof(uint32_t)];
target_regs_read(t, backup_regs);
/* fill out the remainder of the parameters */
va_list ap;
va_start(ap, cmd);
@ -79,7 +88,7 @@ enum iap_status lpc_iap_call(struct lpc_flash *f, enum iap_cmd cmd, ...)
uint32_t regs[t->regs_size / sizeof(uint32_t)];
target_regs_read(t, regs);
regs[0] = f->iap_ram + offsetof(struct flash_param, command);
regs[1] = f->iap_ram + offsetof(struct flash_param, result);
regs[1] = f->iap_ram + offsetof(struct flash_param, status);
regs[REG_MSP] = f->iap_msp;
regs[REG_LR] = f->iap_ram | 1;
regs[REG_PC] = f->iap_entry;
@ -91,7 +100,16 @@ enum iap_status lpc_iap_call(struct lpc_flash *f, enum iap_cmd cmd, ...)
/* copy back just the parameters structure */
target_mem_read(t, &param, f->iap_ram, sizeof(param));
return param.result;
/* restore the original data in RAM and registers */
target_mem_write(t, f->iap_ram, &backup_param, sizeof(param));
target_regs_write(t, backup_regs);
/* if the user expected a result, set the result (16 bytes). */
if (result != NULL)
memcpy(result, param.result, sizeof(param.result));
return param.status;
}
static uint8_t lpc_sector_for_addr(struct lpc_flash *f, uint32_t addr)
@ -105,15 +123,15 @@ int lpc_flash_erase(struct target_flash *tf, target_addr addr, size_t len)
uint32_t start = lpc_sector_for_addr(f, addr);
uint32_t end = lpc_sector_for_addr(f, addr + len - 1);
if (lpc_iap_call(f, IAP_CMD_PREPARE, start, end, f->bank))
if (lpc_iap_call(f, NULL, IAP_CMD_PREPARE, start, end, f->bank))
return -1;
/* and now erase them */
if (lpc_iap_call(f, IAP_CMD_ERASE, start, end, CPU_CLK_KHZ, f->bank))
if (lpc_iap_call(f, NULL, IAP_CMD_ERASE, start, end, CPU_CLK_KHZ, f->bank))
return -2;
/* check erase ok */
if (lpc_iap_call(f, IAP_CMD_BLANKCHECK, start, end, f->bank))
if (lpc_iap_call(f, NULL, IAP_CMD_BLANKCHECK, start, end, f->bank))
return -3;
return 0;
@ -125,7 +143,7 @@ int lpc_flash_write(struct target_flash *tf,
struct lpc_flash *f = (struct lpc_flash *)tf;
/* prepare... */
uint32_t sector = lpc_sector_for_addr(f, dest);
if (lpc_iap_call(f, IAP_CMD_PREPARE, sector, sector, f->bank))
if (lpc_iap_call(f, NULL, IAP_CMD_PREPARE, sector, sector, f->bank))
return -1;
/* Write payload to target ram */
@ -133,7 +151,7 @@ int lpc_flash_write(struct target_flash *tf,
target_mem_write(f->f.t, bufaddr, src, len);
/* set the destination address and program */
if (lpc_iap_call(f, IAP_CMD_PROGRAM, dest, bufaddr, len, CPU_CLK_KHZ))
if (lpc_iap_call(f, NULL, IAP_CMD_PROGRAM, dest, bufaddr, len, CPU_CLK_KHZ))
return -2;
return 0;

View File

@ -27,6 +27,7 @@ enum iap_cmd {
IAP_CMD_ERASE = 52,
IAP_CMD_BLANKCHECK = 53,
IAP_CMD_PARTID = 54,
IAP_CMD_READUID = 58,
IAP_CMD_SET_ACTIVE_BANK = 60,
};
@ -60,7 +61,7 @@ struct lpc_flash {
};
struct lpc_flash *lpc_add_flash(target *t, target_addr addr, size_t length);
enum iap_status lpc_iap_call(struct lpc_flash *f, enum iap_cmd cmd, ...);
enum iap_status lpc_iap_call(struct lpc_flash *f, void *result, enum iap_cmd cmd, ...);
int lpc_flash_erase(struct target_flash *f, target_addr addr, size_t len);
int lpc_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);

View File

@ -25,6 +25,7 @@
* * SAMD20E17A (rev C)
* * SAMD20J18A (rev B)
* * SAMD21J18A (rev B)
* * SAML21J17B (rev B)
* *
*/
/* Refer to the SAM D20 Datasheet:
@ -41,7 +42,7 @@ static int samd_flash_erase(struct target_flash *t, target_addr addr, size_t len
static int samd_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);
static bool samd_cmd_erase_all(target *t, int argc, const char **argv);
bool samd_cmd_erase_all(target *t, int argc, const char **argv);
static bool samd_cmd_lock_flash(target *t, int argc, const char **argv);
static bool samd_cmd_unlock_flash(target *t, int argc, const char **argv);
static bool samd_cmd_unlock_bootprot(target *t, int argc, const char **argv);
@ -129,14 +130,16 @@ const struct command_s samd_cmd_list[] = {
#define SAMD_STATUSB_PROT (1 << 16)
/* Device Identification Register (DID) */
#define SAMD_DID_MASK 0xFFBC0000
#define SAMD_DID_MASK 0xFF3C0000
#define SAMD_DID_CONST_VALUE 0x10000000
#define SAMD_DID_DEVSEL_MASK 0x0F
#define SAMD_DID_DEVSEL_MASK 0xFF
#define SAMD_DID_DEVSEL_POS 0
#define SAMD_DID_REVISION_MASK 0x0F
#define SAMD_DID_REVISION_POS 8
#define SAMD_DID_SERIES_MASK 0x03
#define SAMD_DID_SERIES_MASK 0x1F
#define SAMD_DID_SERIES_POS 16
#define SAMD_DID_FAMILY_MASK 0x1F
#define SAMD_DID_FAMILY_POS 23
/* Peripheral ID */
#define SAMD_PID_MASK 0x00F7FFFF
@ -145,6 +148,79 @@ const struct command_s samd_cmd_list[] = {
/* Component ID */
#define SAMD_CID_VALUE 0xB105100D
/* Family parts */
struct samd_part {
uint8_t devsel;
char pin;
uint8_t mem;
uint8_t variant;
};
static const struct samd_part samd_d21_parts[] = {
{0x00, 'J', 18, 'A'}, /* SAMD21J18A */
{0x01, 'J', 17, 'A'}, /* SAMD21J17A */
{0x02, 'J', 16, 'A'}, /* SAMD21J16A */
{0x03, 'J', 15, 'A'}, /* SAMD21J15A */
{0x05, 'G', 18, 'A'}, /* SAMD21G18A */
{0x06, 'G', 17, 'A'}, /* SAMD21G17A */
{0x07, 'G', 16, 'A'}, /* SAMD21G16A */
{0x08, 'G', 15, 'A'}, /* SAMD21G15A */
{0x0A, 'E', 18, 'A'}, /* SAMD21E18A */
{0x0B, 'E', 17, 'A'}, /* SAMD21E17A */
{0x0C, 'E', 16, 'A'}, /* SAMD21E16A */
{0x0D, 'E', 15, 'A'}, /* SAMD21E15A */
{0x0F, 'G', 18, 'A'}, /* SAMD21G18A (WLCSP) */
{0x10, 'G', 17, 'A'}, /* SAMD21G17A (WLCSP) */
{0x20, 'J', 16, 'B'}, /* SAMD21J16B */
{0x21, 'J', 15, 'B'}, /* SAMD21J15B */
{0x23, 'G', 16, 'B'}, /* SAMD21G16B */
{0x24, 'G', 15, 'B'}, /* SAMD21G15B */
{0x26, 'E', 16, 'B'}, /* SAMD21E16B */
{0x27, 'E', 15, 'B'}, /* SAMD21E15B */
{0x55, 'E', 16, 'B'}, /* SAMD21E16B (WLCSP) */
{0x56, 'E', 15, 'B'}, /* SAMD21E15B (WLCSP) */
{0x62, 'E', 16, 'C'}, /* SAMD21E16C (WLCSP) */
{0x63, 'E', 15, 'C'}, /* SAMD21E15C (WLCSP) */
{0xFF, 0, 0, 0}
};
static const struct samd_part samd_l21_parts[] = {
{0x00, 'J', 18, 'A'}, /* SAML21J18A */
{0x01, 'J', 17, 'A'}, /* SAML21J17A */
{0x02, 'J', 16, 'A'}, /* SAML21J16A */
{0x05, 'G', 18, 'A'}, /* SAML21G18A */
{0x06, 'G', 17, 'A'}, /* SAML21G17A */
{0x07, 'G', 16, 'A'}, /* SAML21G16A */
{0x0A, 'E', 18, 'A'}, /* SAML21E18A */
{0x0B, 'E', 17, 'A'}, /* SAML21E17A */
{0x0C, 'E', 16, 'A'}, /* SAML21E16A */
{0x0D, 'E', 15, 'A'}, /* SAML21E15A */
{0x0F, 'J', 18, 'B'}, /* SAML21J18B */
{0x10, 'J', 17, 'B'}, /* SAML21J17B */
{0x11, 'J', 16, 'B'}, /* SAML21J16B */
{0x14, 'G', 18, 'B'}, /* SAML21G18B */
{0x15, 'G', 17, 'B'}, /* SAML21G17B */
{0x16, 'G', 16, 'B'}, /* SAML21G16B */
{0x19, 'E', 18, 'B'}, /* SAML21E18B */
{0x1A, 'E', 17, 'B'}, /* SAML21E17B */
{0x1B, 'E', 16, 'B'}, /* SAML21E16B */
{0x1C, 'E', 15, 'B'}, /* SAML21E15B */
{0xFF, 0, 0, 0}
};
static const struct samd_part samd_l22_parts[] = {
{0x00, 'N', 18, 'A'}, /* SAML22N18 */
{0x01, 'N', 17, 'A'}, /* SAML22N17 */
{0x02, 'N', 16, 'A'}, /* SAML22N16 */
{0x05, 'J', 18, 'A'}, /* SAML22J18 */
{0x06, 'J', 17, 'A'}, /* SAML22J17 */
{0x07, 'J', 16, 'A'}, /* SAML22J16 */
{0x0A, 'G', 18, 'A'}, /* SAML22G18 */
{0x0B, 'G', 17, 'A'}, /* SAML22G17 */
{0x0C, 'G', 16, 'A'}, /* SAML22G16 */
{0xFF, 0, 0, 0}
};
/**
* Reads the SAM D20 Peripheral ID
*/
@ -178,8 +254,7 @@ uint32_t samd_read_cid(target *t)
* Overloads the default cortexm reset function with a version that
* removes the target from extended reset where required.
*/
static void
samd_reset(target *t)
void samd_reset(target *t)
{
/**
* SRST is not asserted here as it appears to reset the adiv5
@ -273,7 +348,7 @@ samd20_revB_halt_resume(target *t, bool step)
* function allows users to attach on a temporary basis so they can
* rescue the device.
*/
static bool samd_protected_attach(target *t)
bool samd_protected_attach(target *t)
{
/**
* TODO: Notify the user that we're not really attached and
@ -293,17 +368,23 @@ static bool samd_protected_attach(target *t)
* describing the SAM D device.
*/
struct samd_descr {
char family;
uint8_t series;
char revision;
char pin;
uint8_t mem;
char variant;
char package[3];
};
struct samd_descr samd_parse_device_id(uint32_t did)
{
struct samd_descr samd;
uint8_t i = 0;
const struct samd_part *parts = samd_d21_parts;
memset(samd.package, 0, 3);
uint8_t family = (did >> SAMD_DID_FAMILY_POS)
& SAMD_DID_FAMILY_MASK;
uint8_t series = (did >> SAMD_DID_SERIES_POS)
& SAMD_DID_SERIES_MASK;
uint8_t revision = (did >> SAMD_DID_REVISION_POS)
@ -311,11 +392,24 @@ struct samd_descr samd_parse_device_id(uint32_t did)
uint8_t devsel = (did >> SAMD_DID_DEVSEL_POS)
& SAMD_DID_DEVSEL_MASK;
/* Family */
switch (family) {
case 0: samd.family = 'D'; break;
case 1: samd.family = 'L'; parts = samd_l21_parts; break;
case 2: samd.family = 'C'; break;
}
/* Series */
switch (series) {
case 0: samd.series = 20; break;
case 1: samd.series = 21; break;
case 2: samd.series = 10; break;
case 2:
if (family == 1) {
samd.series = 22;
parts = samd_l22_parts;
} else {
samd.series = 10;
}
break;
case 3: samd.series = 11; break;
}
/* Revision */
@ -323,7 +417,6 @@ struct samd_descr samd_parse_device_id(uint32_t did)
switch (samd.series) {
case 20: /* SAM D20 */
case 21: /* SAM D21 */
switch (devsel / 5) {
case 0: samd.pin = 'J'; break;
case 1: samd.pin = 'G'; break;
@ -331,6 +424,20 @@ struct samd_descr samd_parse_device_id(uint32_t did)
default: samd.pin = 'u'; break;
}
samd.mem = 18 - (devsel % 5);
samd.variant = 'A';
break;
case 21: /* SAM D21/L21 */
case 22: /* SAM L22 */
i = 0;
while (parts[i].devsel != 0xFF) {
if (parts[i].devsel == devsel) {
samd.pin = parts[i].pin;
samd.mem = parts[i].mem;
samd.variant = parts[i].variant;
break;
}
i++;
}
break;
case 10: /* SAM D10 */
case 11: /* SAM D11 */
@ -340,6 +447,7 @@ struct samd_descr samd_parse_device_id(uint32_t did)
}
samd.pin = 'D';
samd.mem = 14 - (devsel % 3);
samd.variant = 'A';
break;
}
@ -389,15 +497,19 @@ bool samd_probe(target *t)
/* Part String */
if (protected) {
snprintf(variant_string, sizeof(variant_string),
"Atmel SAMD%d%c%dA%s (rev %c) (PROT=1)",
samd.series, samd.pin, samd.mem,
samd.package, samd.revision);
sprintf(variant_string,
"Atmel SAM%c%d%c%d%c%s (rev %c) (PROT=1)",
samd.family,
samd.series, samd.pin, samd.mem,
samd.variant,
samd.package, samd.revision);
} else {
snprintf(variant_string, sizeof(variant_string),
"Atmel SAMD%d%c%dA%s (rev %c)",
samd.series, samd.pin, samd.mem,
samd.package, samd.revision);
sprintf(variant_string,
"Atmel SAM%c%d%c%d%c%s (rev %c)",
samd.family,
samd.series, samd.pin, samd.mem,
samd.variant,
samd.package, samd.revision);
}
/* Setup Target */
@ -524,7 +636,7 @@ static int samd_flash_write(struct target_flash *f,
/**
* Uses the Device Service Unit to erase the entire flash
*/
static bool samd_cmd_erase_all(target *t, int argc, const char **argv)
bool samd_cmd_erase_all(target *t, int argc, const char **argv)
{
(void)argc;
(void)argv;

1107
src/target/samx5x.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -178,6 +178,7 @@ bool sam3x_probe(target *t);
bool sam4l_probe(target *t);
bool nrf51_probe(target *t);
bool samd_probe(target *t);
bool samx5x_probe(target *t);
bool kinetis_probe(target *t);
bool efm32_probe(target *t);
bool msp432_probe(target *t);