Merge commit 'f89542c79f6edb0d64e7dfa483501718113f45b5' into sam-update
This commit is contained in:
commit
fdce017311
4
Makefile
4
Makefile
@ -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
|
||||
|
11
src/Makefile
11
src/Makefile
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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) ||
|
||||
|
@ -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)))
|
||||
|
13
src/platforms/pc-hosted/Makefile.inc
Normal file
13
src/platforms/pc-hosted/Makefile.inc
Normal 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 \
|
40
src/platforms/pc-hosted/README.md
Normal file
40
src/platforms/pc-hosted/README.md
Normal 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.
|
144
src/platforms/pc-hosted/jtagtap.c
Normal file
144
src/platforms/pc-hosted/jtagtap.c
Normal 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]);
|
||||
}
|
352
src/platforms/pc-hosted/platform.c
Normal file
352
src/platforms/pc-hosted/platform.c
Normal 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);
|
||||
}
|
53
src/platforms/pc-hosted/platform.h
Normal file
53
src/platforms/pc-hosted/platform.h
Normal 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
|
123
src/platforms/pc-hosted/swdptap.c
Normal file
123
src/platforms/pc-hosted/swdptap.c
Normal 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);
|
||||
}
|
||||
}
|
@ -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:
|
||||
|
@ -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 '+';
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
*/
|
||||
#include "general.h"
|
||||
#include "cdcacm.h"
|
||||
#include "traceswo.h"
|
||||
|
||||
#include <libopencm3/cm3/nvic.h>
|
||||
#include <libopencm3/stm32/timer.h>
|
||||
|
@ -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>
|
||||
|
@ -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 */
|
||||
|
@ -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
276
src/remote.c
Normal 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(¶m, 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
131
src/remote.h
Normal 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
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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, ¶m, 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;
|
||||
|
@ -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);
|
||||
|
@ -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
1107
src/target/samx5x.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user