Compare commits

..

No commits in common. "stable" and "v1.8.0" have entirely different histories.

43 changed files with 715 additions and 3727 deletions

3
.gitignore vendored
View File

@ -16,10 +16,7 @@ tags
*.b#*
blackmagic_upgrade
*.exe
.DS_Store
*.elf
.vscode
cscope.out
cscope.files
.gdb_history
src/artifacts/

2
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "libopencm3"]
path = libopencm3
url = https://github.com/flirc/libopencm3.git
url = https://github.com/libopencm3/libopencm3.git

View File

@ -17,23 +17,13 @@ ifndef NO_LIBOPENCM3
git submodule init ;\
git submodule update ;\
fi
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib/sam/d
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib/stm32/f1 lib/stm32/f4 lib/lm4f
endif
$(Q)$(MAKE) $(MFLAGS) -C src
all_platforms:
$(Q)$(MAKE) $(MFLAGS) -C src $@
clean:
ifndef NO_LIBOPENCM3
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 $@
endif
$(Q)$(MAKE) $(MFLAGS) -C src $@
clang-tidy:
$(Q)scripts/run-clang-tidy.py -s "$(PWD)"
clang-format:
$(Q)$(MAKE) $(MFLAGS) -C src $@
.PHONY: clean all_platforms clang-tidy clang-format

153
README.md
View File

@ -1,54 +1,113 @@
Jeff Probe
Black Magic Probe
=================
[![Discord](https://img.shields.io/discord/613131135903596547?logo=discord)](https://discord.gg/P7FYThy)
Firmware for the Black Magic Debug Probe.
The Black Magic Probe is a modern, in-application debugging tool for
embedded microprocessors. It allows you see what is going on 'inside' an
application running on an embedded microprocessor while it executes. It is
able to control and examine the state of the target microprocessor using a
JTAG or Serial Wire Debugging (SWD) port and on-chip debug logic provided
by the microprocessor. The probe connects to a host computer using a
standard USB interface. The user is able to control exactly what happens
using the GNU source level debugging software, GDB.
Serial Wire Output (SWO) allows the target to write tracing and logging to the host
without using usb or serial port. Decoding SWO in the probe itself
makes [SWO viewing as simple as connecting to a serial port](https://github.com/blackmagic-debug/blackmagic/wiki/Serial-Wire-Output).
Resources
=========
* [Documentation](https://github.com/blackmagic-debug/blackmagic/wiki)
* [Binary builds](http://builds.blacksphere.co.nz/blackmagic)
Toolchain specific remarks
==========================
Most firmware building is done with the most recent suite from https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm.
If you have a toolchain from other sources and find problems, check if it is a failure of your toolchain and if not open an issue or better provide a pull request with a fix.
OS specific remarks for BMP-Hosted
==================================
Most hosted building is done on and for Linux. BMP-hosted for windows can also be build with Mingw on Linux.<br>
Building hosted for BMP firmware probes only with "make PROBE_HOST HOSTED_BMP_ONLY=1" does not require libusb, libftdi and evt. libhidapi development headers and libraries for running.<br>
On BSD/Macos, using dev/tty.usbmodemXXX should work but unresolved discussions indicate a hanging open() call on the second invocation. If that happens, try with cu.usbmodemXXX.<br>
Reporting problems
==================
Before reporting issues, check against the latest git version. If possible, test against another target /and/or debug probe. Consider broken USB cables and connectors. Try to reproduce with bmp-hosted with at least debug bit 1 set (blackmagic -v 1 ...), as debug messages will be dumped to the starting console. When reporting issues, be as specific as possible!
Sample Session
=============
```console
> arm-none-eabi-gdb gpio.elf
...<GDB Copyright message>
(gdb) tar ext /dev/ttyACM0
Remote debugging using /dev/ttyACM0
(gdb) mon s
Target voltage: 2.94V
Available Targets:
No. Att Driver
1 STM32F40x M3/M4
(gdb) att 1
Attaching to program: /devel/en_apps/gpio/f4_discovery/gpio.elf, Remote target
0x08002298 in UsartIOCtl ()
(gdb) load
Loading section .text, size 0x5868 lma 0x8000000
Loading section .data, size 0x9e0 lma 0x8005868
Loading section .rodata, size 0x254 lma 0x8006248
Start address 0x800007c, load size 25756
Transfer rate: 31 KB/sec, 919 bytes/write.
(gdb) b main
Breakpoint 1 at 0x80000e8: file /devel/en_apps/gpio/f4_discovery/../gpio.c, line 70.
(gdb) r
Starting program: /devel/en_apps/gpio/f4_discovery/gpio.elf
Note: automatically using hardware breakpoints for read-only addresses.
Breakpoint 1, main () at /devel/en_apps/gpio/f4_discovery/../gpio.c:70
70 {
```
BLACKMAGIC
==========
This is a fork of the [original Black Magic Probe](https://github.com/blacksphere/blackmagic).
You can also build blackmagic as a PC hosted application
"make PROBE_HOST=hosted"
The original is arguably better, faster and wider supported. However, this
project was a way to offer an affordable version and I'll rely on community
support and pull requests.
This builds the same GDB server, that is running on the Black Magic Probe.
While connection to the Black Magic Probe GDB server is via serial line,
connection to the PC-Hosted GDB server is via TCP port 2000 for the first
GDB server and higher for more invokations. Use "tar(get) ext(ented) :2000"
to connect.
PC-hosted BMP GDB server can talk to
- Black Magic Probe firmware probes via the USB-serial port
- ST-LinkV2 and V3 with recent firmware
- CMSIS-DAP compatible probes
- JLINK probes
- FTDI MPSSE based probe.
One urguably better funncton is the ability to do DEBUG and Serial communication
over a single JTAG cable when paired with a device that uses single wire JTAG.
Normally, the serial header can be used on a target for the serial port, and
shows up as the second serial device on the system, however, we can dynamically
change the pins to use the ones on the JTAG cable with the following command:
``` bash
$ mon convert_tdio enable
When connected to a single BMP supported probe, starting "blackmagic" w/o any
arguments starts the server. When several BMP supported probes are connected,
their types, position and serial number is displayed and the program exits.
Add "-P (position)" to the next invocation to select one.
For the setup from the sample session above:
In another terminal:
```console
> blackmagic
Using 1d50:6018 E2E489E7 Black Sphere Technologies Black Magic Probe (STLINK), (Firmware v1.6.1-477-g70bb131-dirty)
Remote is Black Magic Probe (STLINK), (Firmware v1.6.1-477-g70bb131-dirty) v1.6.1-477-g70bb131-dirty
Listening on TCP: 2000
And in the GDB terminal:
(gdb) target ext :2000
Remote debugging using :2000
(gdb) mon s
...
```
Compilation
---
PC hosted BMP also allows to flash, read and verify a binary file, by default
starting at lowest flash address. The "-t" argument displays information about the
connected target. Use "-h " to get a list of supported options.
Newer toolchains can cause issues. I usually work 4_9-2014q4-20141203 found [here.](https://launchpad.net/gcc-arm-embedded/4.9/4.9-2014-q4-major/+download/gcc-arm-none-eabi-4_9-2014q4-20141203-mac.tar.bz2)
the versionfollowing version
```bash
$ make clean
$ make PROBE_HOST=jeff CUSTOM_SER=1
$ dfu-util --device ,1d50:6017 -s 0x00002000:leave -D src/blackmagic.bin
```
CUSTOM OPTIONS
---
On mac, our device shows up with a serial number /dev/tty.cuJEFF123HDC
This can be annoy if we want to autocnnect with a gith script. We can override
the use of a serial number by doing a custom compliation such that our device
shows up with the following: /dev/cu.usbmodemJEFF1 and /dev/cu.usbmodemJEFF3
```bash
$ make PROBE_HOST=jeff CUSTOM_SER=1
```
More
---
More helpful information can be found on the black magic probe [readme](https://github.com/blacksphere/blackmagic/blob/master/README.md#black-magic-probe), which is relevant.
See online documentation at https://github.com/blacksphere/blackmagic/wiki
Binaries from the latest automated build can be found on the release page.

View File

@ -1,271 +0,0 @@
# Using RTT
When debugging arm processors, there are three ways for the target to print debug messages on the host: Semihosting, Serial Wire Output SWO, and Real-Time Transfer RTT.
[Black Magic Probe](https://github.com/blacksphere/blackmagic) (BMP) is an open source debugger probe that already implements Semihosting and Single Wire Output. This patch adds Real-Time Transfer RTT output to usb serial port.
- RTT is implemented, not as a user program, but as a serial port device. To read RTT output, use a terminal emulator and connect to the serial port.
- A novel way to detect RTT automatically, fast and convenient.
## Use
This example uses linux as operating system. For Windows and MacOS see the *Operating Systems* section.
In one window open a terminal emulator (minicom, putty) and connect to the usb uart:
```
$ minicom -c on -D /dev/ttyBmpTarg
```
In another window open a debugger:
```
$ gdb
(gdb) target extended-remote /dev/ttyBmpGdb
(gdb) monitor swdp_scan
(gdb) attach 1
(gdb) monitor rtt
(gdb) run
^C
(gdb) monitor rtt status
rtt: on found: yes ident: off halt: off channels: auto 0 1 3
max poll ms: 256 min poll ms: 8 max errs: 10
```
The terminal emulator displays RTT output from the target,
and characters typed in the terminal emulator are sent via RTT to the target.
## gdb commands
The following new gdb commands are available:
- ``monitor rtt``
switch rtt on
- ``monitor rtt enable``
switch rtt on
- ``monitor rtt disable``
switch rtt off
- ``monitor rtt poll `` max_poll_ms min_poll_ms max_errs
sets maximum time between polls, minimum time between polls, and the maximum number of errors before RTT disconnects from the target. Times in milliseconds. It is best if max_poll_ms/min_poll_ms is a power of two. As an example, if you wish to check for RTT output between once per second to eight times per second: ``monitor rtt poll 1000 125 10``.
- ``monitor rtt status``
show status.
rtt|found|state
---|---|---
rtt: off|found: no|rtt inactive
rtt: on|found: no|searching for rtt control block
rtt: on|found: yes|rtt active
rtt: off|found: yes|corrupt rtt control block, or target memory access error
A status of `rtt: on found: no` indicates bmp is still searching for the rtt control block in target ram, but has not found anything yet. A status of `rtt: on found: yes` indicates the control block has been found and rtt is active.
- ``monitor rtt channel``
enables the first two output channels, and the first input channel. (default)
- ``monitor rtt channel number...``
enables the given RTT channel numbers. Channels are numbers from 0 to 15, inclusive. Eg. ``monitor rtt channel 0 1 4`` to enable channels 0, 1, and 4.
- ``monitor rtt ident string``
sets RTT ident to *string*. If *string* contains a space, replace the space with an underscore _. Setting ident string is optional, RTT works fine without.
- ``monitor rtt ident``
clears ident string. (default)
- ``monitor rtt cblock``
shows rtt control block data, and which channels are enabled. This is an example control block:
```
(gdb) mon rtt cb
cbaddr: 0x200000a0
ch ena cfg i/o buf@ size head@ tail@ flg
0 y y out 0x20000148 1024 0x200000c4 0x200000c8 2
1 y n out 0x00000000 0 0x200000dc 0x200000e0 0
2 n n out 0x00000000 0 0x200000f4 0x200000f8 0
3 y y in 0x20000548 16 0x2000010c 0x20000110 0
4 n n in 0x00000000 0 0x20000124 0x20000128 0
5 n n in 0x00000000 0 0x2000013c 0x20000140 0
6 n n in 0x00000000 0 0x00000000 0x00000000 0
7 n n in 0x00000000 0 0x00000000 0x00000000 0
8 n n in 0x00000000 0 0x00000000 0x00000000 0
9 n n in 0x00000000 0 0x00000000 0x00000000 0
10 n n in 0x00000000 0 0x00000000 0x00000000 0
11 n n in 0x00000000 0 0x00000000 0x00000000 0
12 n n in 0x00000000 0 0x00000000 0x00000000 0
13 n n in 0x00000000 0 0x00000000 0x00000000 0
14 n n in 0x00000000 0 0x00000000 0x00000000 0
15 n n in 0x00000000 0 0x00000000 0x00000000 0
```
Channels are listed, one channel per line. The columns are: channel, enabled, configured, input/output, buffer address, buffer size, address of head pointer, address of tail pointer, flag. Each channel is a circular buffer with head and tail pointer.
Note the columns `ena` for enabled, `cfg` for configured.
Configured channels have a non-zero buffer address and non-zero size. Configured channels are marked yes `y` in the column `cfg` . What channels are configured depends upon target software.
Channels the user wants to see are marked yes `y` in the column enabled `ena`. The user can change which channels are shown with the `monitor rtt channel` command.
Output channels are displayed, and Input channels receive keyboard input, if they are marked yes in both *enabled* and *configured*.
The control block is cached for speed. In an interrupted program, `monitor rtt` will force a reload of the control block when the program continues.
## Identifier string
It is possible to set an RTT identifier string.
As an example, if the RTT identifier is "IDENT STR":
```
$ gdb
(gdb) target extended-remote /dev/ttyBmpGdb
(gdb) monitor swdp_scan
(gdb) attach 1
(gdb) monitor rtt ident IDENT_STR
(gdb) monitor rtt
(gdb) run
^C
(gdb) monitor rtt status
rtt: on found: yes ident: "IDENT STR" halt: off channels: auto 0 1 3
max poll ms: 256 min poll ms: 8 max errs: 10
```
Note replacing space with underscore _ in *monitor rtt ident*.
Setting an identifier string is optional. RTT gives the same output at the same speed, with or without specifying identifier string.
## Operating systems
[Configuration](https://github.com/blacksphere/blackmagic/wiki/Getting-Started) instructions for windows, linux and macos.
### Windows
After configuration, Black Magic Probe shows up in Windows as two _USB Serial (CDC)_ ports.
Connect arm-none-eabi-gdb, the gnu debugger for arm processors, to the lower numbered of the two COM ports. Connect an ansi terminal emulator to the higher numbered of the two COM ports.
Sample gdb session:
```
(gdb) target extended-remote COM3
(gdb) monitor swdp_scan
(gdb) attach 1
(gdb) monitor rtt
(gdb) run
```
For COM port COM10 and higher, add the prefix `\\.\`, e.g.
```
target extended-remote \\.\COM10
```
Target RTT output will appear in the terminal, and what you type in the terminal will be sent to the RTT input of the target.
### linux
On linux, install [udev rules](https://github.com/blacksphere/blackmagic/blob/master/driver/99-blackmagic.rules). Disconnect and re-connect the BMP. Check the device shows up in /dev/ :
```
$ ls -l /dev/ttyBmp*
lrwxrwxrwx 1 root root 7 Dec 13 07:29 /dev/ttyBmpGdb -> ttyACM0
lrwxrwxrwx 1 root root 7 Dec 13 07:29 /dev/ttyBmpTarg -> ttyACM2
```
Connect terminal emulator to /dev/ttyBmpTarg and gdb to /dev/ttyBmpGdb .
In one window:
```
minicom -c on -D /dev/ttyBmpTarg
```
In another window :
```
gdb
(gdb) target extended-remote /dev/ttyBmpGdb
(gdb) monitor swdp_scan
(gdb) attach 1
(gdb) monitor rtt
(gdb) run
```
### MacOS
On MacOS the tty devices have different names than on linux. On connecting blackmagic to the computer 4 devices are created, 2 'tty' and 2 'cu' devices. Gdb connects to the first cu device (e.g.: `target extended-remote /dev/cu.usbmodemDDCEC9EC1`), while RTT is connected to the second tty device (`minicom -c on -D /dev/tty.usbmodemDDCEC9EC3`). In full:
In one Terminal window, connect a terminal emulator to /dev/tty.usbmodemDDCEC9EC3 :
```
minicom -c on -D /dev/tty.usbmodemDDCEC9EC3
```
In another Terminal window, connect gdb to /dev/cu.usbmodemDDCEC9EC1 :
```
gdb
(gdb) target extended-remote /dev/cu.usbmodemDDCEC9EC1
(gdb) monitor swdp_scan
(gdb) attach 1
(gdb) monitor rtt
(gdb) run
```
RTT input/output is in the window running _minicom_.
## Notes
- Design goal was smallest, simplest implementation that has good practical use.
- RTT code size is 3.5 kbyte - the whole debugger 110 kbyte.
- Because RTT is implemented as a serial port device, there is no need to write and maintain software for different host operating systems. A serial port works everywhere - linux, windows and mac. You can even use an Android mobile phone as RTT terminal.
- Because polling occurs between debugger probe and target, the load on the host is small. There is no constant usb traffic, there are no real-time requirements on the host.
- RTT polling frequency is adaptive and goes up and down with RTT activity. Use *monitor rtt poll* to balance response speed and target load for your use.
- Detects RTT automatically, very convenient.
- When using RTT as a terminal, sending data from host to target, you may need to change local echo, carriage return and/or line feed settings in your terminal emulator.
- Architectures such as risc-v may not allow the debugger access to target memory while the target is running. As a workaround, on these architectures RTT briefly halts the target during polling. If the target is halted during polling, `monitor rtt status` shows `halt: on`.
- Measured RTT speed.
| debugger | char/s |
| ------------------------- | ------ |
| bmp stm32f723 stlinkv3 | 49811 |
| bmp stm32f411 black pill | 50073 |
| bmp stm32f103 blue pill | 50142 |
This is the speed at which characters can be sent from target to debugger probe, in reasonable circumstances. Test target is an stm32f103 blue pill running an [Arduino sketch](https://github.com/koendv/Arduino-RTTStream/blob/main/examples/SpeedTest/SpeedTest.ino). Default *monitor rtt poll* settings on debugger. Default RTT buffer size in target and debugger. Overhead for printf() calls included.
## Compiling firmware
To compile with RTT support, add *ENABLE_RTT=1*.
Eg. for STM32F103 blue pill:
```
make clean
make PROBE_HOST=stlink ENABLE_RTT=1
```
or for the STM32F411 *[Black Pill](https://www.aliexpress.com/item/1005001456186625.html)*:
```
make clean
make PROBE_HOST=f4discovery BLACKPILL=1 ENABLE_RTT=1
```
Setting an ident string is optional. But if you wish, you can set the default RTT ident at compile time.
For STM32F103 *Blue Pill*:
```
make clean
make PROBE_HOST=stlink ENABLE_RTT=1 "RTT_IDENT=IDENT\ STR"
```
or for STM32F411 *Black Pill*:
```
make clean
make PROBE_HOST=f4discovery BLACKPILL=1 ENABLE_RTT=1 "RTT_IDENT=IDENT\ STR"
```
Note the backslash \\ before the space.
## Links
- [OpenOCD](https://openocd.org/doc/html/General-Commands.html#Real-Time-Transfer-_0028RTT_0029)
- [probe-rs](https://probe.rs/) and [rtt-target](https://github.com/mvirkkunen/rtt-target) for the _rust_ programming language.
- [RTT Stream](https://github.com/koendv/Arduino-RTTStream) for Arduino on arm processors
- [\[WIP\] RTT support - PR from katyo](https://github.com/blacksphere/blackmagic/pull/833)

View File

@ -1,7 +1,6 @@
# Black Magic Probe
# there are two connections, one for GDB and one for UART debugging
# copy this to /etc/udev/rules.d/99-blackmagic.rules
# and run /usr/sbin/udevadm control --reload-rules
SUBSYSTEM=="tty", ACTION=="add", ATTRS{interface}=="Black Magic GDB Server", SYMLINK+="ttyBmpGdb"
SUBSYSTEM=="tty", ACTION=="add", ATTRS{interface}=="Black Magic UART Port", SYMLINK+="ttyBmpTarg"
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="1d50", ATTR{idProduct}=="6017", MODE="0666"

@ -1 +1 @@
Subproject commit 63573143ef7e1b037d1f0c5baedc5264e12562b8
Subproject commit 8435287300e5ca9af9f889c529e7b1fa019c42fb

Binary file not shown.

View File

@ -9,7 +9,7 @@ Q := @
endif
CFLAGS += -Wall -Wextra -Werror -Wno-char-subscripts \
-std=gnu99 -MD -I./target \
-std=gnu99 -g3 -MD -I./target \
-I. -Iinclude -I$(PLATFORM_DIR)
ifeq ($(ENABLE_DEBUG), 1)
@ -65,6 +65,11 @@ SRC = \
include $(PLATFORM_DIR)/Makefile.inc
ifneq ($(PC_HOSTED),1)
# Output memory usage information
LDFLAGS += -Wl,--print-memory-usage
endif
OPT_FLAGS ?= -Os
CFLAGS += $(OPT_FLAGS)
LDFLAGS += $(OPT_FLAGS)
@ -90,28 +95,8 @@ VPATH += platforms/common
CFLAGS += -Iplatforms/common
endif
ifeq ($(ENABLE_RTT), 1)
CFLAGS += -DENABLE_RTT
SRC += rtt.c rtt_if.c
endif
ifdef RTT_IDENT
CFLAGS += -DRTT_IDENT=$(RTT_IDENT)
endif
OBJ = $(patsubst %.S,%.o,$(patsubst %.c,%.o,$(SRC)))
OPTIMIZE := swdptap.o jtagtap.o \
adiv5_jtagdp.o adiv5_swdp.o adiv5.o \
cortexa.o cortexm.o \
gdb_if.o gdb_main.o gdb_hostio.o gdb_packet.o \
jtag_devs.o jtag_scan.o \
crc32.o main.o \
cdcacm.o jeff.o timing.o traceswo.o usbuart.o \
$(OPTIMIZE):: CFLAGS := $(filter-out -Os, $(CFLAGS))
$(OPTIMIZE):: CFLAGS += -O3
$(TARGET): include/version.h $(OBJ)
@echo " LD $@"
$(Q)$(CC) -o $@ $(OBJ) $(LDFLAGS)
@ -127,14 +112,14 @@ $(TARGET): include/version.h $(OBJ)
ifndef PC_HOSTED
%.bin: %.elf
@echo " OBJCOPY $@"
$(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) -O binary $^ $@
$(Q)$(OBJCOPY) -O binary $^ $@
%.hex: %.elf
@echo " OBJCOPY $@"
$(Q)$(OBJCOPY) -O ihex $^ $@
endif
.PHONY: clean host_clean all_platforms clang-format FORCE
.PHONY: clean host_clean all_platforms FORCE
clean: host_clean
$(Q)echo " CLEAN"
@ -142,27 +127,16 @@ clean: host_clean
-$(Q)$(RM) platforms/*/*.o platforms/*/*.d mapfile include/version.h
all_platforms:
$(Q)if [ ! -f ../libopencm3/Makefile ]; then \
echo "Initialising git submodules..." ;\
git submodule init ;\
git submodule update ;\
fi
$(Q)$(MAKE) $(MFLAGS) -C ../libopencm3 lib/stm32/f1 lib/stm32/f4 lib/lm4f
$(Q)set -e ;\
mkdir -p artifacts/$(shell git describe --always --dirty --tags) ;\
echo "<html><body><ul>" > artifacts/index.html ;\
$(MAKE) clean ;\
for i in platforms/*/Makefile.inc ; do \
export DIRNAME=`dirname $$i` ;\
export PROBE_HOST=`basename $$DIRNAME` ;\
export CFLAGS=-Werror ;\
echo "Building for hardware platform: $$PROBE_HOST" ;\
$(MAKE) clean ;\
$(MAKE);\
if [ -f blackmagic ]; then \
mv blackmagic artifacts/blackmagic-$$PROBE_HOST ;\
echo "<li><a href='blackmagic-$$PROBE_HOST'>$$PROBE_HOST</a></li>"\
>> artifacts/index.html ;\
fi ;\
if [ -f blackmagic.bin ]; then \
mv blackmagic.bin artifacts/blackmagic-$$PROBE_HOST.bin ;\
echo "<li><a href='blackmagic-$$PROBE_HOST.bin'>$$PROBE_HOST</a></li>"\
@ -173,31 +147,13 @@ all_platforms:
echo "<li><a href='blackmagic_dfu-$$PROBE_HOST.bin'>$$PROBE_HOST DFU</a></li>"\
>> artifacts/index.html ;\
fi ;\
$(MAKE) clean ;\
done ;\
echo "</ul></body></html>" >> artifacts/index.html ;\
cp artifacts/blackmagic* artifacts/$(shell git describe --always --dirty --tags)
cp artifacts/*.bin artifacts/$(shell git describe --always --dirty --tags)
command.c: include/version.h
GIT_VERSION := $(shell git describe --always --dirty --tags)
VERSION_HEADER := \#define FIRMWARE_VERSION "$(GIT_VERSION)"
include/version.h: FORCE
@# If git isn't found then GIT_VERSION will be an empty string.
ifeq ($(GIT_VERSION),)
@echo Git not found, assuming up to date include/version.h
else
@# Note that when we echo the version to the header file, echo writes a final newline
@# to the file. This is fine and probably makes the file more human-readable, but
@# also means we have to account for that newline in this comparison.
$(Q)if [ ! -f $@ ] || [ "$$(cat $@)" != "$$(echo '$(VERSION_HEADER)\n')" ]; then \
echo " GEN $@"; \
echo '$(VERSION_HEADER)' > $@; \
fi
endif
clang-format:
$(Q)clang-format -i *.c */*.c */*/*.c *.h */*.h */*/*.h
$(Q)echo " GIT include/version.h"
$(Q)echo "#define FIRMWARE_VERSION \"$(shell git describe --always --dirty --tags)\"" > $@
-include *.d

View File

@ -34,18 +34,11 @@
#include "version.h"
#include "serialno.h"
#ifdef ENABLE_RTT
#include "rtt.h"
#endif
#ifdef PLATFORM_HAS_TRACESWO
# include "traceswo.h"
#endif
static bool cmd_version(target *t, int argc, char **argv);
#ifdef PLATFORM_HAS_PRINTSERIAL
static bool cmd_serial(target *t, int argc, char **argv);
#endif
static bool cmd_help(target *t, int argc, char **argv);
static bool cmd_jtag_scan(target *t, int argc, char **argv);
@ -63,25 +56,12 @@ static bool cmd_target_power(target *t, int argc, const char **argv);
static bool cmd_traceswo(target *t, int argc, const char **argv);
#endif
static bool cmd_heapinfo(target *t, int argc, const char **argv);
#ifdef ENABLE_RTT
static bool cmd_rtt(target *t, int argc, const char **argv);
#endif
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
static bool cmd_debug_bmp(target *t, int argc, const char **argv);
#endif
#ifdef PLATFORM_HAS_UART_WHEN_SWDP
static bool cmd_convert_tdio(target *t, int argc, const char **argv);
static bool cmd_set_srst(target *t, int argc, const char **argv);
#endif
#ifdef PLATFORM_HAS_BOOTLOADER
static bool cmd_enter_bootldr(target *t, int argc, const char **argv);
#endif
const struct command_s cmd_list[] = {
{"version", (cmd_handler)cmd_version, "Display firmware version info"},
#ifdef PLATFORM_HAS_PRINTSERIAL
{"serial", (cmd_handler)cmd_serial, "Display firmware serial number"},
#endif
{"help", (cmd_handler)cmd_help, "Display help for monitor commands"},
{"jtag_scan", (cmd_handler)cmd_jtag_scan, "Scan JTAG chain for devices" },
{"swdp_scan", (cmd_handler)cmd_swdp_scan, "Scan SW-DP for devices" },
@ -94,9 +74,6 @@ const struct command_s cmd_list[] = {
#ifdef PLATFORM_HAS_POWER_SWITCH
{"tpwr", (cmd_handler)cmd_target_power, "Supplies power to the target: (enable|disable)"},
#endif
#ifdef ENABLE_RTT
{"rtt", (cmd_handler)cmd_rtt, "enable|disable|status|channel 0..15|ident (str)|cblock|poll maxms minms maxerr" },
#endif
#ifdef PLATFORM_HAS_TRACESWO
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, NRZ mode: (baudrate) (decode channel ...)" },
@ -107,13 +84,6 @@ const struct command_s cmd_list[] = {
{"heapinfo", (cmd_handler)cmd_heapinfo, "Set semihosting heapinfo" },
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
{"debug_bmp", (cmd_handler)cmd_debug_bmp, "Output BMP \"debug\" strings to the second vcom: (enable|disable)"},
#endif
#ifdef PLATFORM_HAS_UART_WHEN_SWDP
{"convert_tdio", (cmd_handler)cmd_convert_tdio,"Switch TDI/O pins to UART TX/RX functions"},
{"set_srst", (cmd_handler)cmd_set_srst,"Set output state of SRST pin (enable|disable)"},
#endif
#ifdef PLATFORM_HAS_BOOTLOADER
{"enter_bootldr", (cmd_handler)cmd_enter_bootldr,"Force BMP into bootloader mode"},
#endif
{NULL, NULL, NULL}
};
@ -440,82 +410,6 @@ static bool cmd_target_power(target *t, int argc, const char **argv)
}
#endif
#ifdef ENABLE_RTT
static const char *on_or_off(const bool value)
{
return value ? "on" : "off";
}
static bool cmd_rtt(target *t, int argc, const char **argv)
{
(void)t;
const size_t command_len = strlen(argv[1]);
if (argc == 1 || (argc == 2 && !strncmp(argv[1], "enabled", command_len))) {
rtt_enabled = true;
rtt_found = false;
} else if ((argc == 2) && !strncmp(argv[1], "disabled", command_len)) {
rtt_enabled = false;
rtt_found = false;
} else if ((argc == 2) && !strncmp(argv[1], "status", command_len)) {
gdb_outf("rtt: %s found: %s ident: \"%s\"", on_or_off(rtt_enabled), rtt_found ? "yes" : "no",
rtt_ident[0] == '\0' ? "off" : rtt_ident);
gdb_outf(" halt: %s", on_or_off(target_no_background_memory_access(t)));
gdb_out(" channels: ");
if (rtt_auto_channel)
gdb_out("auto ");
for (size_t i = 0; i < MAX_RTT_CHAN; i++) {
if (rtt_channel[i].is_enabled)
gdb_outf("%d ", i);
}
gdb_outf(
"\nmax poll ms: %u min poll ms: %u max errs: %u\n", rtt_max_poll_ms, rtt_min_poll_ms, rtt_max_poll_errs);
} else if (argc >= 2 && !strncmp(argv[1], "channel", command_len)) {
/* mon rtt channel switches to auto rtt channel selection
mon rtt channel number... selects channels given */
for (size_t i = 0; i < MAX_RTT_CHAN; i++)
rtt_channel[i].is_enabled = false;
if (argc == 2)
rtt_auto_channel = true;
else {
rtt_auto_channel = false;
for (size_t i = 2; i < (size_t)argc; ++i) {
const uint32_t channel = strtoul(argv[i], NULL, 0);
if (channel < MAX_RTT_CHAN)
rtt_channel[channel].is_enabled = true;
}
}
} else if (argc == 2 && !strncmp(argv[1], "ident", command_len))
rtt_ident[0] = '\0';
else if (argc == 2 && !strncmp(argv[1], "poll", command_len))
gdb_outf("%u %u %u\n", rtt_max_poll_ms, rtt_min_poll_ms, rtt_max_poll_errs);
else if (argc == 2 && !strncmp(argv[1], "cblock", command_len)) {
gdb_outf("cbaddr: 0x%x\n", rtt_cbaddr);
gdb_out("ch ena cfg i/o buf@ size head@ tail@ flg\n");
for (size_t i = 0; i < MAX_RTT_CHAN; ++i) {
gdb_outf("%2zu %c %c %s 0x%08x %5d 0x%08x 0x%08x %d\n", i, rtt_channel[i].is_enabled ? 'y' : 'n',
rtt_channel[i].is_configured ? 'y' : 'n', rtt_channel[i].is_output ? "out" : "in ",
rtt_channel[i].buf_addr, rtt_channel[i].buf_size, rtt_channel[i].head_addr, rtt_channel[i].tail_addr,
rtt_channel[i].flag);
}
} else if (argc == 3 && !strncmp(argv[1], "ident", command_len)) {
strncpy(rtt_ident, argv[2], sizeof(rtt_ident));
rtt_ident[sizeof(rtt_ident) - 1] = '\0';
for (size_t i = 0; i < sizeof(rtt_ident); i++) {
if (rtt_ident[i] == '_')
rtt_ident[i] = ' ';
}
} else if (argc == 5 && !strncmp(argv[1], "poll", command_len)) {
/* set polling params */
rtt_max_poll_ms = strtoul(argv[2], NULL, 0);
rtt_min_poll_ms = strtoul(argv[3], NULL, 0);
rtt_max_poll_errs = strtoul(argv[4], NULL, 0);
} else
gdb_out("what?\n");
return true;
}
#endif
#ifdef PLATFORM_HAS_TRACESWO
static bool cmd_traceswo(target *t, int argc, const char **argv)
{
@ -593,66 +487,6 @@ static bool cmd_debug_bmp(target *t, int argc, const char **argv)
return true;
}
#endif
#ifdef PLATFORM_HAS_UART_WHEN_SWDP
static bool cmd_convert_tdio(target *t, int argc, const char **argv)
{
(void)t;
uint8_t val;
if (argc > 1) {
val = (!strcmp(argv[1], "enable")) ? true : false;
usbuart_convert_tdio(val);
} else {
gdb_outf("Convert_tdio: %s\n",(usbuart_convert_tdio_enabled()) ?
"enabled" : "disabled");
}
return true;
}
static bool cmd_set_srst(target *t, int argc, const char **argv)
{
(void) t;
uint8_t val;
if (argc > 1) {
val = (!strcmp(argv[1], "enable")) ? true : false;
platform_srst_set_val(val);
} else {
gdb_outf("SRST: %s\n",(platform_srst_get_val()) ?
"enabled" : "disabled");
}
return true;
}
#endif
#ifdef PLATFORM_HAS_BOOTLOADER
static bool cmd_enter_bootldr(target *t, int argc, const char **argv)
{
(void) t;
(void) argc;
(void) argv;
scb_reset_system();
return true;
}
#endif
#ifdef PLATFORM_HAS_PRINTSERIAL
bool cmd_serial(target *t, int argc, char **argv)
{
(void) t;
(void) argc;
(void) argv;
print_serial();
return true;
}
#endif
static bool cmd_heapinfo(target *t, int argc, const char **argv)
{
if (t == NULL) gdb_out("not attached\n");

View File

@ -130,3 +130,4 @@ int hostio_system(struct target_controller *tc,
gdb_putpacket_f("Fsystem,%08X/%X", cmd, cmd_len);
return gdb_main_loop(tc, true);
}

View File

@ -35,9 +35,6 @@
#include "command.h"
#include "crc32.h"
#include "morse.h"
#ifdef ENABLE_RTT
#include "rtt.h"
#endif
enum gdb_signal {
GDB_SIGINT = 2,
@ -46,7 +43,7 @@ enum gdb_signal {
GDB_SIGLOST = 29,
};
#define BUF_SIZE 1024U
#define BUF_SIZE 1024
#define ERROR_IF_NO_TARGET() \
if(!cur_target) { gdb_putpacketz("EFF"); break; }
@ -54,29 +51,23 @@ enum gdb_signal {
typedef struct
{
const char *cmd_prefix;
void (*func)(const char *packet, size_t len);
void (*func)(const char *packet, int len);
} cmd_executer;
static char pbuf[BUF_SIZE + 1U];
static char pbuf[BUF_SIZE + 1];
static target *cur_target;
static target *last_target;
static bool gdb_needs_detach_notify = false;
static void handle_q_packet(char *packet, size_t len);
static void handle_v_packet(char *packet, size_t len);
static void handle_z_packet(char *packet, size_t len);
static void handle_kill_target(void);
static void handle_q_packet(char *packet, int len);
static void handle_v_packet(char *packet, int len);
static void handle_z_packet(char *packet, int len);
static void gdb_target_destroy_callback(struct target_controller *tc, target *t)
{
(void)tc;
if (cur_target == t) {
gdb_put_notificationz("%Stop:W00");
gdb_out("You are now detached from the previous target.\n");
if (cur_target == t)
cur_target = NULL;
gdb_needs_detach_notify = true;
}
if (last_target == t)
last_target = NULL;
@ -109,20 +100,22 @@ static struct target_controller gdb_controller = {
int gdb_main_loop(struct target_controller *tc, bool in_syscall)
{
int size;
bool single_step = false;
/* GDB protocol main loop */
while (1) {
while(1) {
SET_IDLE_STATE(1);
size_t size = gdb_getpacket(pbuf, BUF_SIZE);
size = gdb_getpacket(pbuf, BUF_SIZE);
SET_IDLE_STATE(0);
switch (pbuf[0]) {
switch(pbuf[0]) {
/* Implementation of these is mandatory! */
case 'g': { /* 'g': Read general registers */
ERROR_IF_NO_TARGET();
uint8_t gp_regs[target_regs_size(cur_target)];
target_regs_read(cur_target, gp_regs);
gdb_putpacket(hexify(pbuf, gp_regs, sizeof(gp_regs)), sizeof(gp_regs) * 2U);
uint8_t arm_regs[target_regs_size(cur_target)];
target_regs_read(cur_target, arm_regs);
gdb_putpacket(hexify(pbuf, arm_regs, sizeof(arm_regs)),
sizeof(arm_regs) * 2);
break;
}
case 'm': { /* 'm addr,len': Read len bytes from addr */
@ -139,20 +132,19 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
if (target_mem_read(cur_target, mem, addr, len))
gdb_putpacketz("E01");
else
gdb_putpacket(hexify(pbuf, mem, len), len * 2U);
gdb_putpacket(hexify(pbuf, mem, len), len * 2);
break;
}
case 'G': { /* 'G XX': Write general registers */
ERROR_IF_NO_TARGET();
uint8_t gp_regs[target_regs_size(cur_target)];
unhexify(gp_regs, &pbuf[1], sizeof(gp_regs));
target_regs_write(cur_target, gp_regs);
uint8_t arm_regs[target_regs_size(cur_target)];
unhexify(arm_regs, &pbuf[1], sizeof(arm_regs));
target_regs_write(cur_target, arm_regs);
gdb_putpacketz("OK");
break;
}
case 'M': { /* 'M addr,len:XX': Write len bytes to addr */
uint32_t addr = 0;
uint32_t len = 0;
uint32_t addr, len;
int hex;
ERROR_IF_NO_TARGET();
sscanf(pbuf, "M%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &hex);
@ -170,24 +162,11 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
gdb_putpacketz("OK");
break;
}
/* '[m|M|g|G|c][thread-id]' : Set the thread ID for the given subsequent operation
* (we don't actually care which as we only care about the TID for whether to send OK or an error)
*/
case 'H': {
char operation = 0;
uint32_t thread_id = 0;
sscanf(pbuf, "H%c%" SCNx32, &operation, &thread_id);
if (thread_id <= 1)
gdb_putpacketz("OK");
else
gdb_putpacketz("E01");
break;
}
case 's': /* 's [addr]': Single step [start at addr] */
single_step = true;
/* fall through */
case 'c': /* 'c [addr]': Continue [at addr] */
if (!cur_target) {
if(!cur_target) {
gdb_putpacketz("X1D");
break;
}
@ -202,7 +181,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
target_addr watch;
enum target_halt_reason reason;
if (!cur_target) {
if(!cur_target) {
/* Report "target exited" if no target */
gdb_putpacketz("W00");
break;
@ -210,13 +189,10 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
/* Wait for target halt */
while(!(reason = target_halt_poll(cur_target, &watch))) {
char c = (char)gdb_if_getchar_to(0);
if(c == '\x03' || c == '\x04') {
unsigned char c = gdb_if_getchar_to(0);
if((c == '\x03') || (c == '\x04')) {
target_halt_request(cur_target);
}
#ifdef ENABLE_RTT
if (rtt_enabled) poll_rtt(cur_target);
#endif
}
SET_RUN_STATE(0);
@ -298,7 +274,12 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
break;
case 'k': /* Kill the target */
handle_kill_target();
if(cur_target) {
target_reset(cur_target);
target_detach(cur_target);
last_target = cur_target;
cur_target = NULL;
}
break;
case 'r': /* Reset the target system */
@ -336,7 +317,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
handle_q_packet(pbuf, size);
break;
case 'v': /* Verbose command packet */
case 'v': /* General query packet */
handle_v_packet(pbuf, size);
break;
@ -354,12 +335,12 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
}
}
static bool exec_command(char *packet, const size_t length, const cmd_executer *exec)
static bool exec_command(char *packet, int len, const cmd_executer *exec)
{
while (exec->cmd_prefix) {
const size_t prefix_length = strlen(exec->cmd_prefix);
if (!strncmp(packet, exec->cmd_prefix, prefix_length)) {
exec->func(packet + prefix_length, length - prefix_length);
const int l = strlen(exec->cmd_prefix);
if (!strncmp(packet, exec->cmd_prefix, l)) {
exec->func(packet + l, len - l);
return true;
}
++exec;
@ -367,16 +348,19 @@ static bool exec_command(char *packet, const size_t length, const cmd_executer *
return false;
}
static void exec_q_rcmd(const char *packet, const size_t length)
static void exec_q_rcmd(const char *packet,int len)
{
char *data;
int datalen;
/* calculate size and allocate buffer for command */
const size_t datalen = length / 2U;
char *data = alloca(datalen + 1);
datalen = len / 2;
data = alloca(datalen + 1);
/* dehexify command */
unhexify(data, packet, datalen);
data[datalen] = 0; /* add terminating null */
const int c = command_process(cur_target, data);
int c = command_process(cur_target, data);
if (c < 0)
gdb_putpacketz("");
else if (c == 0)
@ -386,41 +370,41 @@ static void exec_q_rcmd(const char *packet, const size_t length)
2 * strlen("Failed\n"));
}
static void handle_q_string_reply(const char *reply, const char *param)
static void
handle_q_string_reply(const char *str, const char *param)
{
const size_t reply_length = strlen(reply);
uint32_t addr = 0;
uint32_t len = 0;
unsigned long addr, len;
const size_t str_len = strlen(str);
if (sscanf(param, "%08" PRIx32 ",%08" PRIx32, &addr, &len) != 2) {
if (sscanf(param, "%08lx,%08lx", &addr, &len) != 2) {
gdb_putpacketz("E01");
return;
}
if (addr > reply_length) {
else if (addr > str_len) {
gdb_putpacketz("E01");
return;
}
if (addr == reply_length) {
else if (addr == str_len) {
gdb_putpacketz("l");
return;
}
size_t output_len = reply_length - addr;
unsigned long output_len = str_len - addr;
if (output_len > len)
output_len = len;
gdb_putpacket2("m", 1U, reply + addr, output_len);
gdb_putpacket2("m", 1, str + addr, output_len);
}
static void exec_q_supported(const char *packet, const size_t length)
static void exec_q_supported(const char *packet, int len)
{
(void)packet;
(void)length;
(void)len;
gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+;qXfer:features:read+", BUF_SIZE);
}
static void exec_q_memory_map(const char *packet, const size_t length)
static void exec_q_memory_map(const char *packet, int len)
{
(void)packet;
(void)length;
(void)len;
/* Read target XML memory map */
if ((!cur_target) && last_target) {
/* Attach to last target if detached. */
@ -436,9 +420,9 @@ static void exec_q_memory_map(const char *packet, const size_t length)
handle_q_string_reply(buf, packet);
}
static void exec_q_feature_read(const char *packet, const size_t length)
static void exec_q_feature_read(const char *packet, int len)
{
(void)length;
(void)len;
/* Read target description */
if ((!cur_target) && last_target) {
/* Attach to last target if detached. */
@ -451,51 +435,24 @@ static void exec_q_feature_read(const char *packet, const size_t length)
handle_q_string_reply(target_tdesc(cur_target), packet);
}
static void exec_q_crc(const char *packet, const size_t length)
static void exec_q_crc(const char *packet, int len)
{
(void)length;
uint32_t addr;
uint32_t addr_length;
if (sscanf(packet, "%" PRIx32 ",%" PRIx32, &addr, &addr_length) == 2) {
(void)len;
uint32_t addr, alen;
if (sscanf(packet, "%" PRIx32 ",%" PRIx32, &addr, &alen) == 2) {
if (!cur_target) {
gdb_putpacketz("E01");
return;
}
uint32_t crc;
if (generic_crc32(cur_target, &crc, addr, addr_length))
int res = generic_crc32(cur_target, &crc, addr, alen);
if (res)
gdb_putpacketz("E03");
else
gdb_putpacket_f("C%lx", crc);
}
}
/*
* qC queries are for the current thread. We don't support threads but GDB 11 and 12 require this,
* so we always answer that the current thread is thread 1.
*/
static void exec_q_c(const char *packet, const size_t length)
{
(void)packet;
(void)length;
gdb_putpacketz("QC1");
}
/*
* qfThreadInfo queries are required in GDB 11 and 12 as these GDBs require the server to support
* threading even when there's only the possiblity for one thread to exist. In this instance,
* we have to tell GDB that there is a single active thread so it doesn't think the "thread" died.
* qsThreadInfo will always follow qfThreadInfo when we reply as we have to specify 'l' at the
* end to terminate the list.. GDB doesn't like this not happening.
*/
static void exec_q_thread_info(const char *packet, const size_t length)
{
(void)length;
if (packet[-11] == 'f')
gdb_putpacketz("m1");
else
gdb_putpacketz("l");
}
static const cmd_executer q_commands[]=
{
{"qRcmd,", exec_q_rcmd},
@ -503,60 +460,34 @@ static const cmd_executer q_commands[]=
{"qXfer:memory-map:read::", exec_q_memory_map},
{"qXfer:features:read:target.xml:",exec_q_feature_read},
{"qCRC:", exec_q_crc},
{"qC", exec_q_c},
{"qfThreadInfo", exec_q_thread_info},
{"qsThreadInfo", exec_q_thread_info},
{NULL, NULL},
};
static void handle_kill_target(void)
static void
handle_q_packet(char *packet, int len)
{
if (cur_target) {
target_reset(cur_target);
target_detach(cur_target);
last_target = cur_target;
cur_target = NULL;
}
}
static void handle_q_packet(char *packet, const size_t length)
{
if (exec_command(packet, length, q_commands))
if (exec_command(packet, len, q_commands))
return;
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
gdb_putpacket("", 0);
}
static void handle_v_packet(char *packet, const size_t plen)
static void
handle_v_packet(char *packet, int plen)
{
uint32_t addr = 0;
uint32_t len = 0;
unsigned long addr, len;
int bin;
static uint8_t flash_mode = 0;
if (sscanf(packet, "vAttach;%08" PRIx32, &addr) == 1) {
if (sscanf(packet, "vAttach;%08lx", &addr) == 1) {
/* Attach to remote target processor */
cur_target = target_attach_n(addr, &gdb_controller);
if(cur_target) {
morse(NULL, false);
/*
* We don't actually support threads, but GDB 11 and 12 can't work without
* us saying we attached to thread 1.. see the following for the low-down of this:
* https://sourceware.org/bugzilla/show_bug.cgi?id=28405
* https://sourceware.org/bugzilla/show_bug.cgi?id=28874
* https://sourceware.org/pipermail/gdb-patches/2021-December/184171.html
* https://sourceware.org/pipermail/gdb-patches/2022-April/188058.html
* https://sourceware.org/pipermail/gdb-patches/2022-July/190869.html
*/
gdb_putpacketz("T05thread:1;");
gdb_putpacketz("T05");
} else
gdb_putpacketz("E01");
} else if (!strncmp(packet, "vKill;", 6)) {
/* Kill the target - we don't actually care about the PID that follows "vKill;" */
handle_kill_target();
gdb_putpacketz("OK");
} else if (!strncmp(packet, "vRun", 4)) {
/* Parse command line for get_cmdline semihosting call */
char cmdline[83];
@ -587,10 +518,6 @@ static void handle_v_packet(char *packet, const size_t plen)
}
break;
}
#ifdef ENABLE_RTT
/* force searching rtt control block */
rtt_found = false;
#endif
/* Run target program. For us (embedded) this means reset. */
if (cur_target) {
target_set_cmdline(cur_target, cmdline);
@ -612,9 +539,9 @@ static void handle_v_packet(char *packet, const size_t plen)
} else
gdb_putpacketz("E01");
} else if (sscanf(packet, "vFlashErase:%08" PRIx32 ",%08" PRIx32, &addr, &len) == 2) {
} else if (sscanf(packet, "vFlashErase:%08lx,%08lx", &addr, &len) == 2) {
/* Erase Flash Memory */
DEBUG_GDB("Flash Erase %08" PRIX32 " %08" PRIX32 "\n", addr, len);
DEBUG_GDB("Flash Erase %08lX %08lX\n", addr, len);
if (!cur_target) {
gdb_putpacketz("EFF");
return;
@ -633,11 +560,11 @@ static void handle_v_packet(char *packet, const size_t plen)
gdb_putpacketz("EFF");
}
} else if (sscanf(packet, "vFlashWrite:%08" PRIx32 ":%n", &addr, &bin) == 1) {
} else if (sscanf(packet, "vFlashWrite:%08lx:%n", &addr, &bin) == 1) {
/* Write Flash Memory */
const uint32_t count = plen - bin;
DEBUG_GDB("Flash Write %08" PRIX32 " %08" PRIX32 "\n", addr, count);
if (cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, count) == 0)
len = plen - bin;
DEBUG_GDB("Flash Write %08lX %08lX\n", addr, len);
if (cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, len) == 0)
gdb_putpacketz("OK");
else {
flash_mode = 0;
@ -649,30 +576,24 @@ static void handle_v_packet(char *packet, const size_t plen)
gdb_putpacketz(target_flash_done(cur_target) ? "EFF" : "OK");
flash_mode = 0;
} else if (!strcmp(packet, "vStopped")) {
if (gdb_needs_detach_notify) {
gdb_putpacketz("W00");
gdb_needs_detach_notify = false;
} else
gdb_putpacketz("OK");
} else {
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
gdb_putpacket("", 0);
}
}
static void handle_z_packet(char *packet, const size_t plen)
static void
handle_z_packet(char *packet, int plen)
{
(void)plen;
uint32_t type;
uint32_t len;
uint8_t set = (packet[0] == 'Z') ? 1 : 0;
int type, len;
uint32_t addr;
sscanf(packet, "%*[zZ]%" PRIu32 ",%08" PRIx32 ",%" PRIu32, &type, &addr, &len);
int ret;
int ret = 0;
if (packet[0] == 'Z')
sscanf(packet, "%*[zZ]%d,%08" PRIX32 ",%d", &type, &addr, &len);
if(set)
ret = target_breakwatch_set(cur_target, type, addr, len);
else
ret = target_breakwatch_clear(cur_target, type, addr, len);

View File

@ -30,11 +30,12 @@
#include <stdarg.h>
size_t gdb_getpacket(char *packet, size_t size)
int gdb_getpacket(char *packet, int size)
{
unsigned char c;
unsigned char csum;
char recv_csum[3];
size_t offset = 0;
int i;
while (1) {
/* Wait for packet start */
@ -43,8 +44,7 @@ size_t gdb_getpacket(char *packet, size_t size)
* start ('$') or a BMP remote packet start ('!').
*/
do {
/* Smells like bad code */
packet[0] = (char)gdb_if_getchar();
packet[0] = gdb_if_getchar();
if (packet[0] == 0x04)
return 1;
} while ((packet[0] != '$') && (packet[0] != REMOTE_SOM));
@ -52,19 +52,18 @@ size_t gdb_getpacket(char *packet, size_t size)
if (packet[0] == REMOTE_SOM) {
/* This is probably a remote control packet
* - get and handle it */
offset = 0;
i = 0;
bool gettingRemotePacket = true;
while (gettingRemotePacket) {
/* Smells like bad code */
const char c = (char)gdb_if_getchar();
c = gdb_if_getchar();
switch (c) {
case REMOTE_SOM: /* Oh dear, packet restarts */
offset = 0;
i = 0;
break;
case REMOTE_EOM: /* Complete packet for processing */
packet[offset] = 0;
remotePacketProcess(offset, packet);
packet[i] = 0;
remotePacketProcess(i, packet);
gettingRemotePacket = false;
break;
@ -74,8 +73,8 @@ size_t gdb_getpacket(char *packet, size_t size)
break;
default:
if (offset < size) {
packet[offset++] = c;
if (i < size) {
packet[i++] = c;
} else {
/* Who knows what is going on...return to normality */
gettingRemotePacket = false;
@ -93,32 +92,30 @@ size_t gdb_getpacket(char *packet, size_t size)
#endif
} while (packet[0] != '$');
offset = 0;
i = 0;
csum = 0;
char c;
/* Capture packet data into buffer */
while ((c = (char)gdb_if_getchar()) != '#') {
while ((c = gdb_if_getchar()) != '#') {
/* If we run out of buffer space, exit early */
if (offset == size)
if (i == size) /* Oh shit */
break;
if (c == '$') { /* Restart capture */
offset = 0;
i = 0;
csum = 0;
continue;
}
if (c == '}') { /* escaped char */
c = gdb_if_getchar();
csum += c + '}';
packet[offset++] = c ^ 0x20;
packet[i++] = c ^ 0x20;
continue;
}
csum += c;
packet[offset++] = c;
packet[i++] = c;
}
recv_csum[0] = (char)gdb_if_getchar();
recv_csum[1] = (char)gdb_if_getchar();
recv_csum[0] = gdb_if_getchar();
recv_csum[1] = gdb_if_getchar();
recv_csum[2] = 0;
/* return packet if checksum matches */
@ -129,20 +126,20 @@ size_t gdb_getpacket(char *packet, size_t size)
gdb_if_putchar('-', 1); /* send nack */
}
gdb_if_putchar('+', 1); /* send ack */
packet[offset] = 0;
packet[i] = 0;
#if PC_HOSTED == 1
DEBUG_GDB_WIRE("%s : ", __func__);
for (size_t j = 0; j < offset; j++) {
const char c = packet[j];
if (c >= ' ' && c < 0x7F)
for(int j = 0; j < i; j++) {
c = packet[j];
if ((c >= 32) && (c < 127))
DEBUG_GDB_WIRE("%c", c);
else
DEBUG_GDB_WIRE("\\x%02X", c);
}
DEBUG_GDB_WIRE("\n");
#endif
return offset;
return i;
}
static void gdb_next_char(char c, unsigned char *csum)
@ -164,19 +161,21 @@ static void gdb_next_char(char c, unsigned char *csum)
}
}
void gdb_putpacket2(const char *packet1, size_t size1, const char *packet2, size_t size2)
void gdb_putpacket2(const char *packet1, int size1, const char *packet2, int size2)
{
int i;
unsigned char csum;
char xmit_csum[3];
size_t tries = 0;
int tries = 0;
do {
DEBUG_GDB_WIRE("%s: ", __func__);
unsigned char csum = 0;
DEBUG_GDB_WIRE("%s : ", __func__);
csum = 0;
gdb_if_putchar('$', 0);
for (size_t i = 0; i < size1; ++i)
for (i = 0; i < size1; ++i)
gdb_next_char(packet1[i], &csum);
for (size_t i = 0; i < size2; ++i)
for (i = 0; i < size2; ++i)
gdb_next_char(packet2[i], &csum);
gdb_if_putchar('#', 0);
@ -184,42 +183,28 @@ void gdb_putpacket2(const char *packet1, size_t size1, const char *packet2, size
gdb_if_putchar(xmit_csum[0], 0);
gdb_if_putchar(xmit_csum[1], 1);
DEBUG_GDB_WIRE("\n");
} while (gdb_if_getchar_to(2000) != '+' && tries++ < 3);
} while ((gdb_if_getchar_to(2000) != '+') && (tries++ < 3));
}
void gdb_putpacket(const char *packet, size_t size)
void gdb_putpacket(const char *packet, int size)
{
int i;
unsigned char csum;
char xmit_csum[3];
size_t tries = 0;
int tries = 0;
do {
DEBUG_GDB_WIRE("%s: ", __func__);
unsigned char csum = 0;
DEBUG_GDB_WIRE("%s : ", __func__);
csum = 0;
gdb_if_putchar('$', 0);
for (size_t i = 0; i < size; ++i)
gdb_next_char(packet[i], &csum);
gdb_if_putchar('#', 0);
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
gdb_if_putchar(xmit_csum[0], 0);
gdb_if_putchar(xmit_csum[1], 1);
DEBUG_GDB_WIRE("\n");
} while (gdb_if_getchar_to(2000) != '+' && tries++ < 3);
}
void gdb_put_notification(const char *const packet, const size_t size)
{
char xmit_csum[3];
DEBUG_GDB_WIRE("%s: ", __func__);
uint8_t csum = 0;
gdb_if_putchar('%', 0);
for (size_t i = 0; i < size; ++i)
for (i = 0; i < size; ++i)
gdb_next_char(packet[i], &csum);
gdb_if_putchar('#', 0);
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
gdb_if_putchar(xmit_csum[0], 0);
gdb_if_putchar(xmit_csum[1], 1);
DEBUG_GDB_WIRE("\n");
} while ((gdb_if_getchar_to(2000) != '+') && (tries++ < 3));
}
void gdb_putpacket_f(const char *fmt, ...)

View File

@ -26,16 +26,16 @@
static const char hexdigits[] = "0123456789abcdef";
char *hexify(char *hex, const void *buf, const size_t size)
char * hexify(char *hex, const void *buf, size_t size)
{
char *dst = hex;
const uint8_t *const src = buf;
char *tmp = hex;
const uint8_t *b = buf;
for (size_t idx = 0; idx < size; ++idx) {
*dst++ = hexdigits[src[idx] >> 4];
*dst++ = hexdigits[src[idx] & 0xF];
while (size--) {
*tmp++ = hexdigits[*b >> 4];
*tmp++ = hexdigits[*b++ & 0xF];
}
*dst++ = 0;
*tmp++ = 0;
return hex;
}
@ -43,18 +43,20 @@ char *hexify(char *hex, const void *buf, const size_t size)
static uint8_t unhex_digit(char hex)
{
uint8_t tmp = hex - '0';
if (tmp > 9)
if(tmp > 9)
tmp -= 'A' - '0' - 10;
if (tmp > 16)
if(tmp > 16)
tmp -= 'a' - 'A';
return tmp;
}
char *unhexify(void *buf, const char *hex, const size_t size)
char * unhexify(void *buf, const char *hex, size_t size)
{
uint8_t *const dst = buf;
for (size_t idx = 0; idx < size; ++idx, hex += 2) {
dst[idx] = (unhex_digit(hex[0]) << 4) | unhex_digit(hex[1]);
uint8_t *b = buf;
while (size--) {
*b = unhex_digit(*hex++) << 4;
*b++ |= unhex_digit(*hex++);
}
return buf;
}

View File

@ -21,19 +21,18 @@
#ifndef __GDB_PACKET_H
#define __GDB_PACKET_H
#include <stddef.h>
#include <stdarg.h>
size_t gdb_getpacket(char *packet, size_t size);
void gdb_putpacket(const char *packet, size_t size);
void gdb_putpacket2(const char *packet1, size_t size1, const char *packet2, size_t size2);
int gdb_getpacket(char *packet, int size);
void gdb_putpacket(const char *packet, int size);
void gdb_putpacket2(const char *packet1, int size1, const char *packet2, int size2);
#define gdb_putpacketz(packet) gdb_putpacket((packet), strlen(packet))
void gdb_putpacket_f(const char *packet, ...);
void gdb_put_notification(const char *packet, size_t size);
#define gdb_put_notificationz(packet) gdb_put_notification((packet), strlen(packet))
void gdb_out(const char *buf);
void gdb_voutf(const char *fmt, va_list);
void gdb_outf(const char *fmt, ...);
#endif

View File

@ -1,85 +0,0 @@
/*
* Copyright 2018 Robert C. Curtis. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY ROBERT C. CURTIS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ROBERT C. CURTIS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* official policies, either expressed or implied, of Robert C. Curtis.
*/
/** @file util/queue.h
* Static queue primitives.
*
* This file contains a set of static queue primitives that are common among
* all of the low level queue implementations. The primitives are inline
* functions, and will be optimal if size is a constant power of 2.
*/
#ifndef I__QUEUE_H__
#define I__QUEUE_H__
/** Increment a queue index.
* @param[in] idx Queue index
* @param[in] size Queue size
* @returns The new queue index value
*/
static inline size_t qinc(size_t idx, size_t size)
{
return ((idx + 1) % size);
}
/** Decrement a queue index.
* @param[in] idx Queue index
* @param[in] size Queue size
* @returns The new queue index value
*/
static inline size_t qdec(size_t idx, size_t size)
{
return ((idx - 1) % size);
}
/** Tests if a queue is full.
* @param[in] head Head index
* @param[in] tail Tail index
* @param[in] size Queue size
*/
static inline int qfull(size_t head, size_t tail, size_t size)
{
size_t next_head = qinc(head, size);
return (next_head == tail);
}
/** Tests if a queue is empty.
* @param[in] head Head index
* @param[in] tail Tail index
*/
static inline int qempty(size_t head, size_t tail)
{
return (head == tail);
}
#endif /* I__QUEUE_H__ */

View File

@ -1,34 +0,0 @@
#ifndef RTT_H
#define RTT_H
#include <target.h>
#define MAX_RTT_CHAN 16
extern char rtt_ident[16]; // string
extern bool rtt_enabled; // rtt on/off
extern bool rtt_found; // control block found
extern uint32_t rtt_cbaddr; // control block address
extern uint32_t rtt_min_poll_ms; // min time between polls (ms)
extern uint32_t rtt_max_poll_ms; // max time between polls (ms)
extern uint32_t rtt_max_poll_errs; // max number of errors before disconnect
extern bool rtt_auto_channel; // manual or auto channel selection
extern bool rtt_flag_skip; // skip if host-to-target fifo full
extern bool rtt_flag_block; // block if host-to-target fifo full
struct rtt_channel_struct {
bool is_enabled; // does user want to see this channel?
bool is_configured; // is channel configured in control block?
bool is_output;
uint32_t buf_addr;
uint32_t buf_size;
uint32_t head_addr;
uint32_t tail_addr;
uint32_t flag;
};
extern struct rtt_channel_struct rtt_channel[MAX_RTT_CHAN];
// true if target memory access does not work when target running
extern bool target_no_background_memory_access(target *cur_target);
extern void poll_rtt(target *cur_target);
#endif

View File

@ -1,36 +0,0 @@
#ifndef RTT_IF_H
#define RTT_IF_H
/* rtt i/o to terminal */
/* default buffer sizes, 8 bytes added to up buffer for alignment and padding */
/* override RTT_UP_BUF_SIZE and RTT_DOWN_BUF_SIZE in platform.h if needed */
#if !defined(RTT_UP_BUF_SIZE) || !defined(RTT_DOWN_BUF_SIZE)
#if (PC_HOSTED == 1)
#define RTT_UP_BUF_SIZE (4096 + 8)
#define RTT_DOWN_BUF_SIZE (512)
#elif defined(STM32F7)
#define RTT_UP_BUF_SIZE (4096 + 8)
#define RTT_DOWN_BUF_SIZE (2048)
#elif defined(STM32F4)
#define RTT_UP_BUF_SIZE (2048 + 8)
#define RTT_DOWN_BUF_SIZE (256)
#else /* stm32f103 */
#define RTT_UP_BUF_SIZE (1024 + 8)
#define RTT_DOWN_BUF_SIZE (256)
#endif
#endif
/* hosted initialisation */
extern int rtt_if_init(void);
/* hosted teardown */
extern int rtt_if_exit(void);
/* target to host: write len bytes from the buffer starting at buf. return number bytes written */
extern uint32_t rtt_write(const char *buf, uint32_t len);
/* host to target: read one character, non-blocking. return character, -1 if no character */
extern int32_t rtt_getchar();
/* host to target: true if no characters available for reading */
extern bool rtt_nodata();
#endif

View File

@ -78,7 +78,7 @@ static const struct usb_device_descriptor dev_desc = {
.bDeviceClass = 0xEF, /* Miscellaneous Device */
.bDeviceSubClass = 2, /* Common Class */
.bDeviceProtocol = 1, /* Interface Association */
#if defined(SAMD21E17) || defined(LM4F)
#ifdef LM4F
.bMaxPacketSize0 = 64, /*Fixed for icdi*/
#else
.bMaxPacketSize0 = 32,
@ -435,8 +435,6 @@ static void dfu_detach_complete(usbd_device *dev, struct usb_setup_data *req)
/* Reset core to enter bootloader */
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
scb_reset_core();
#else
scb_reset_system();
#endif
}
@ -526,7 +524,7 @@ static void cdcacm_set_config(usbd_device *dev, uint16_t wValue)
configured = wValue;
/* GDB interface */
#if defined(STM32F4) || defined(LM4F) || defined(SAMD)
#if defined(STM32F4) || defined(LM4F)
usbd_ep_setup(dev, CDCACM_GDB_ENDPOINT, USB_ENDPOINT_ATTR_BULK,
CDCACM_PACKET_SIZE, gdb_usb_out_cb);
#else
@ -582,7 +580,6 @@ void cdcacm_init(void)
nvic_set_priority(USB_IRQ, IRQ_PRI_USB);
nvic_enable_irq(USB_IRQ);
usbd_disconnect(usbdev, false);
}
void USB_ISR(void)

View File

@ -233,9 +233,7 @@ int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
struct dirent *dp;
int i = 0;
while ((dp = readdir(dir)) != NULL) {
if ((strstr(dp->d_name, BMP_IDSTRING_BLACKMAGIC) ||
strstr(dp->d_name, BMP_IDSTRING_BLACKSPHERE) ||
strstr(dp->d_name, BMP_IDSTRING_1BITSQUARED)) &&
if ((strstr(dp->d_name, BMP_IDSTRING)) &&
(strstr(dp->d_name, "-if00"))) {
i++;
char type[256], version[256], serial[256];
@ -268,9 +266,7 @@ int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
dir = opendir(DEVICE_BY_ID);
i = 0;
while ((dp = readdir(dir)) != NULL) {
if ((strstr(dp->d_name, BMP_IDSTRING_BLACKMAGIC) ||
strstr(dp->d_name, BMP_IDSTRING_BLACKSPHERE) ||
strstr(dp->d_name, BMP_IDSTRING_1BITSQUARED)) &&
if ((strstr(dp->d_name, BMP_IDSTRING)) &&
(strstr(dp->d_name, "-if00"))) {
i++;
char type[256], version[256], serial[256];

View File

@ -30,10 +30,6 @@
#include "gdb_if.h"
#include <signal.h>
#ifdef ENABLE_RTT
#include "rtt_if.h"
#endif
#include "bmp_remote.h"
#include "bmp_hosted.h"
#include "stlinkv2.h"
@ -62,9 +58,6 @@ static void exit_function(void)
default:
break;
}
#ifdef ENABLE_RTT
rtt_if_exit();
#endif
fflush(stdout);
}
@ -117,9 +110,6 @@ void platform_init(int argc, char **argv)
exit(cl_execute(&cl_opts));
else {
gdb_if_init();
#ifdef ENABLE_RTT
rtt_if_init();
#endif
return;
}
}

View File

@ -1,127 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* MIT License
*
* Copyright (c) 2021 Koen De Vleeschauwer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <general.h>
#include <unistd.h>
#include <fcntl.h>
#include <rtt_if.h>
/* maybe rewrite this as tcp server */
#ifndef WIN32
#include <termios.h>
/* linux */
static struct termios saved_ttystate;
static bool tty_saved = false;
/* set up and tear down */
int rtt_if_init()
{
struct termios ttystate;
tcgetattr(STDIN_FILENO, &saved_ttystate);
tty_saved = true;
tcgetattr(STDIN_FILENO, &ttystate);
ttystate.c_lflag &= ~ICANON;
ttystate.c_lflag &= ~ECHO;
ttystate.c_cc[VMIN] = 1;
tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
int flags = fcntl(0, F_GETFL, 0);
fcntl(0, F_SETFL, flags | O_NONBLOCK);
return 0;
}
int rtt_if_exit()
{
if (tty_saved)
tcsetattr(STDIN_FILENO, TCSANOW, &saved_ttystate);
return 0;
}
/* write buffer to terminal */
uint32_t rtt_write(const char *buf, uint32_t len)
{
write(1, buf, len);
return len;
}
/* read character from terminal */
int32_t rtt_getchar()
{
char ch;
int len;
len = read(0, &ch, 1);
if (len == 1) return ch;
return -1;
}
/* true if no characters available */
bool rtt_nodata()
{
return false;
}
#else
/* windows, output only */
int rtt_if_init()
{
return 0;
}
int rtt_if_exit()
{
return 0;
}
/* write buffer to terminal */
uint32_t rtt_write(const char *buf, uint32_t len)
{
write(1, buf, len);
return len;
}
/* read character from terminal */
int32_t rtt_getchar()
{
return -1;
}
/* true if no characters available */
bool rtt_nodata()
{
return false;
}
#endif

View File

@ -1,61 +0,0 @@
CROSS_COMPILE ?= arm-none-eabi-
CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy
OPT_FLAGS := -Os
ifeq ($(ENABLE_DEBUG), 1)
CFLAGS += -DDEBUG_ME
CFLAGS += -DENABLE_DEBUG
endif
ifeq ($(CUSTOM_SER), 1)
CFLAGS += -DCUSTOM_SER
endif
ifeq ($(CONSOLE_NO_AUTO_CRLF), 1)
CFLAGS += -DCONSOLE_NO_AUTO_CRLF
endif
ifeq ($(ENABLE_DEBUG), 1)
CFLAGS += -g3 -ggdb
endif
CFLAGS += -mthumb -mcpu=cortex-m0plus -DDFU_SERIAL_LENGTH=9 \
-DSAMD -DSAMD21E17 -DBLACKMAGIC -I../libopencm3/include \
-Iplatforms/samd -msoft-float -ffunction-sections -fdata-sections -MD
LINKER_SCRIPT="platforms/samd/samd.ld"
LDFLAGS = -mthumb -mcpu=cortex-m0plus -msoft-float -nostartfiles -lc \
$(CPU_FLAGS) -T$(LINKER_SCRIPT) -Wl,--gc-sections \
-L../libopencm3/lib -lopencm3_samd -lnosys -lm -lgcc
ifeq ($(ENABLE_DEBUG), 1)
LDFLAGS += --specs=rdimon.specs
else
LDFLAGS += --specs=nano.specs
endif
VPATH += platforms/samd
SRC += cdcacm.c \
timing.c \
traceswo.o \
usbuart.c \
all: blackmagic_full.bin blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex
blackmagic_dfu.bin : OBJCOPY_FLAGS := --pad-to 0x00002000 --gap-fill 0xFF -j .text -j .data
blackmagic_dfu.bin : LINKER_SCRIPT := "platforms/samd/samd_boot.ld"
blackmagic_dfu.elf: usbdfu.o
@echo " LD $@"
$(Q)$(CC) $^ -o $@ $(LDFLAGS)
blackmagic_full.bin: blackmagic_dfu.bin blackmagic.bin
@echo " CAT $@"
$(Q)cp blackmagic.bin jeff-$(shell git describe --tags --always --dirty).bin
$(Q)cat $^ > $@
host_clean:
$(Q)$(RM) -f blackmagic.bin blackmagic_full.bin blackmagic_dfu blackmagic_dfu.bin blackmagic_dfu.hex jeff*.bin

View File

@ -1,346 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2018 Flirc Inc.
* Written by Jason Kotzin <jasonkotzin@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "general.h"
#include "gdb_if.h"
#include "cdcacm.h"
#include "usbuart.h"
#include "gdb_packet.h"
#include <libopencm3/sam/d/nvic.h>
#include <libopencm3/sam/d/port.h>
#include <libopencm3/sam/d/gclk.h>
#include <libopencm3/sam/d/pm.h>
#include <libopencm3/sam/d/uart.h>
#include <libopencm3/sam/d/adc.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/sam/d/tc.h>
#include <libopencm3/sam/d/eic.h>
static struct gclk_hw clock = {
.gclk0 = SRC_DFLL48M,
.gclk1 = SRC_OSC8M,
.gclk1_div = 30, /* divide clock for ADC */
.gclk2 = SRC_OSC8M,
.gclk2_div = 100, /* divide clock for TC */
.gclk3 = SRC_DFLL48M,
.gclk4 = SRC_DFLL48M,
.gclk5 = SRC_DFLL48M,
.gclk6 = SRC_DFLL48M,
.gclk7 = SRC_DFLL48M,
};
extern void trace_tick(void);
uint8_t running_status;
static volatile uint32_t time_ms;
uint8_t button_pressed;
uint8_t tpwr_enabled;
void sys_tick_handler(void)
{
if(running_status)
gpio_toggle(LED_PORT, LED_IDLE_RUN);
time_ms += 10;
uart_pop();
}
uint32_t platform_time_ms(void)
{
return time_ms;
}
static void usb_setup(void)
{
/* Enable USB */
INSERTBF(PM_APBBMASK_USB, 1, PM->apbbmask);
/* enable clocking to usb */
set_periph_clk(GCLK0, GCLK_ID_USB);
periph_clk_en(GCLK_ID_USB, 1);
gpio_config_special(PORTA, GPIO24, SOC_GPIO_PERIPH_G);
gpio_config_special(PORTA, GPIO25, SOC_GPIO_PERIPH_G);
}
static uint32_t timing_init(void)
{
uint32_t cal = 0;
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
systick_set_reload(4800); /* Interrupt us at 10 Hz */
systick_interrupt_enable();
systick_counter_enable();
return cal;
}
static void adc_init(void)
{
gpio_config_special(ADC_PORT, ADC_POS_PIN, SOC_GPIO_PERIPH_B); /* +input */
gpio_config_special(ADC_PORT, ADC_REF_PIN, SOC_GPIO_PERIPH_B); /* reference */
set_periph_clk(GCLK1, GCLK_ID_ADC);
periph_clk_en(GCLK_ID_ADC, 1);
adc_enable(ADC_REFCTRL_VREFA,0,ADC_INPUTCTRL_GND,ADC_MUXPOS);
}
static void counter_init(void)
{
/* enable bus and clock */
INSERTBF(PM_APBCMASK_TC3, 1, PM->apbcmask);
set_periph_clk(GCLK2, GCLK_ID_TC3);
periph_clk_en(GCLK_ID_TC3, 1);
/* reset */
tc_reset(3);
/* set CTRLA.PRESCALER and CTRLA.PRESYNC */
tc_config_ctrla(3,1,(7<<8));
/* set CC0 (approx. 5 seconds delay) */
tc_set_cc(3,0,1000);
/* enable MC0 interrupt */
tc_enable_interrupt(3,(1<<4));
nvic_enable_irq(NVIC_TC3_IRQ);
}
static void button_init(void)
{
gpio_config_special(BUTTON_PORT, BUTTON_PIN, SOC_GPIO_PERIPH_A);
/* enable bus and clock */
INSERTBF(PM_APBAMASK_EIC, 1, PM->apbamask);
set_periph_clk(GCLK0, GCLK_ID_EIC);
periph_clk_en(GCLK_ID_EIC, 1);
/* configure r/f edge, enable filtering */
eic_set_config(15, 1, EIC_FALL);
/* enable the IEC */
eic_enable(1);
/* enable interrupts */
eic_enable_interrupt((1<<15));
nvic_enable_irq(NVIC_EIC_IRQ);
}
void platform_init(void)
{
gclk_init(&clock);
usb_setup();
gpio_config_output(LED_PORT, LED_IDLE_RUN, 0);
gpio_config_output(TMS_PORT, TMS_PIN, 0);
gpio_config_output(TCK_PORT, TCK_PIN, 0);
gpio_config_output(TDI_PORT, TDI_PIN, 0);
gpio_config_output(TMS_PORT, TMS_DIR_PIN, 0);
gpio_set(TMS_PORT, TMS_DIR_PIN);
/* enable both input and output with pullup disabled by default */
PORT_DIRSET(SWDIO_PORT) = SWDIO_PIN;
PORT_PINCFG(SWDIO_PORT, SWDIO_PIN_NUM) |= GPIO_PINCFG_INEN | GPIO_PINCFG_PULLEN;
gpio_clear(SWDIO_PORT, SWDIO_PIN);
/* configure swclk_pin as output */
gpio_config_output(SWCLK_PORT, SWCLK_PIN, 0);
gpio_clear(SWCLK_PORT, SWCLK_PIN);
gpio_config_input(TDO_PORT, TDO_PIN, 0);
gpio_config_output(SRST_PORT, SRST_PIN, GPIO_OUT_FLAG_DEFAULT_HIGH);
gpio_clear(SRST_PORT, SRST_PIN);
/* setup uart led, disable by default*/
gpio_config_output(LED_PORT_UART, LED_UART, 0);//GPIO_OUT_FLAG_DEFAULT_HIGH);
gpio_clear(LED_PORT_UART, LED_UART);
/* set up TPWR */
gpio_set(PWR_BR_PORT, PWR_BR_PIN);
gpio_config_output(PWR_BR_PORT, PWR_BR_PIN, GPIO_OUT_FLAG_DEFAULT_HIGH);
timing_init();
usbuart_init();
cdcacm_init();
adc_init();
counter_init();
button_init();
}
uint8_t srst_state;
void platform_srst_set_val(bool assert)
{
volatile int i;
if (!assert) {
gpio_clear(SRST_PORT, SRST_PIN);
for(i = 0; i < 10000; i++) asm("nop");
srst_state = 0;
} else {
gpio_set(SRST_PORT, SRST_PIN);
srst_state = 1;
}
}
bool platform_srst_get_val(void)
{
//return gpio_get(SRST_PORT, SRST_PIN) != 0;
return srst_state;
}
bool platform_target_get_power(void)
{
//return !gpio_get(PWR_BR_PORT, PWR_BR_PIN);
return tpwr_enabled;
}
void platform_target_set_power(bool power)
{
gpio_set_val(PWR_BR_PORT, PWR_BR_PIN, !power);
tpwr_enabled = power;
}
void platform_delay(uint32_t ms)
{
platform_timeout timeout;
platform_timeout_set(&timeout, ms);
while (!platform_timeout_is_expired(&timeout));
}
uint32_t platform_target_voltage_sense(void)
{
uint32_t val;
adc_start();
while (!(1&(ADC->intflag)));
val = ((485*adc_result())>>12); /* 330 without divider, 485 with it */
return val;
}
const char *platform_target_voltage(void)
{
uint32_t voltage;
static char out[] = "0.0V";
adc_start();
voltage = platform_target_voltage_sense();
out[0] = '0' + (char)(voltage/100);
out[2] = '0' + (char)((voltage/10) % 10);
return out;
}
char *serial_no_read(char *s)
{
#ifdef CUSTOM_SER
s[0] = 'J';
s[1] = 'E';
s[2] = 'F';
s[3] = 'F';
return s;
#else
int i;
volatile uint32_t unique_id = *(volatile uint32_t *)0x0080A00C +
*(volatile uint32_t *)0x0080A040 +
*(volatile uint32_t *)0x0080A044 +
*(volatile uint32_t *)0x0080A048;
/* Fetch serial number from chip's unique ID */
for(i = 0; i < 8; i++) {
s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';
}
for(i = 0; i < 8; i++)
if(s[i] > '9')
s[i] += 'A' - '9' - 1;
s[8] = 0;
return s;
#endif
}
void print_serial(void)
{
gdb_outf("0x%08X%08X%08X%08X\n", *(volatile uint32_t *)0x0080A048,
*(volatile uint32_t *)0x0080A044,
*(volatile uint32_t *)0x0080A040,
*(volatile uint32_t *)0x0080A00C);
}
void platform_request_boot(void)
{
}
void eic_isr(void)
{
if (!button_pressed){
/* set to rising-edge detection */
eic_set_config(15, 1, EIC_RISE);
/* enable counter */
tc_enable(3,1);
button_pressed = 1;
} else {
/* set to falling-edge detection */
eic_set_config(15, 1, EIC_FALL);
/* disable and reset counter */
tc_enable(3,0);
button_pressed = 0;
}
/* clear the interrupt */
eic_clr_interrupt((1<<15));
}
void tc3_isr(void)
{
if (tc_interrupt_flag(3) & 16)
scb_reset_system();
}
uint32_t swd_delay_cnt = 0;
void platform_max_frequency_set(uint32_t freq)
{
(void)freq;
}
uint32_t platform_max_frequency_get(void)
{
return 0;
}

View File

@ -1,227 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2018 Flirc Inc.
* Written by Jason Kotzin <jasonkotzin@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __PLATFORM_H
#define __PLATFORM_H
#include <libopencm3/sam/d/port.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/sam/d/nvmctrl.h>
#include "timing.h"
#include "version.h"
//#define PLATFORM_HAS_DEBUG
//#define USBUART_DEBUG
#define PLATFORM_HAS_UART_WHEN_SWDP
#define PLATFORM_HAS_POWER_SWITCH
#define PLATFORM_HAS_BOOTLOADER
#define PLATFORM_HAS_PRINTSERIAL
//#define BOARD_IDENT "Black Magic Probe (SAMD), (Firmware " FIRMWARE_VERSION ")"
#define BOARD_IDENT_DFU "Black Magic (Upgrade) for Launchpad, (Firmware " FIRMWARE_VERSION ")"
//#define DFU_IDENT "Black Magic Firmware Upgrade (SAMD)"
#define DFU_IFACE_STRING "hid"
#define BOARD_IDENT_UPD "Black Magic (DFU Upgrade), SAMD21, (Firmware " FIRMWARE_VERSION ")"
#define UPD_IFACE_STRING "@Internal Flash /0x00000000/1*008Ka,15*8Kg"
#define PLATFORM_IDENT " "
extern uint8_t running_status;
extern uint32_t swd_delay_cnt;
#ifdef DEBUG_ME
#define LED_PORT PORTA
#define LED_IDLE_RUN GPIO11
#define LED_ERROR GPIO10
#define TMS_PORT PORTA
#define TMS_PIN GPIO1
#define TMS_DIR_PIN GPIO5
#define TCK_PORT PORTA
#define TCK_PIN GPIO2
#define TDI_PORT PORTA
#define TDI_PIN GPIO16
#define TDO_PORT PORTA
#define TDO_PIN GPIO19
#define SWO_PORT PORTA
#define SWO_PIN GPIO6
#define SWDIO_PORT PORTA
#define SWDIO_PIN TMS_PIN
#define SWDIO_PIN_NUM 1
#define SWCLK_PORT PORTA
#define SWCLK_PIN TCK_PIN
#define SRST_PORT PORTA
#define SRST_PIN GPIO7
#define LED_PORT_UART PORTA
#define LED_UART GPIO12
#define UART_TX_PIN GPIO8
#define UART_RX_PIN GPIO9
#define UART_PERIPH SOC_GPIO_PERIPH_C
#define UART_PERIPH_2 SOC_GPIO_PERIPH_C
#define ADC_PORT PORTA
#define ADC_REF_PIN GPIO3
#define ADC_POS_PIN GPIO4
#define ADC_MUXPOS 4
#define BUTTON_PORT PORTA
#define BUTTON_PIN GPIO27
#else
/* Hardware definitions... */
#define JTAG_PORT PORTA
#define TDI_PORT JTAG_PORT
#define TMS_DIR_PORT JTAG_PORT
#define TMS_PORT JTAG_PORT
#define TCK_PORT JTAG_PORT
#define TDO_PORT JTAG_PORT
#define TMS_DIR_PIN GPIO15
#define TMS_PIN GPIO0
#define TCK_PIN GPIO6
#define TDI_PIN GPIO16
#define TDO_PIN GPIO19
#define SWDIO_DIR_PORT JTAG_PORT
#define SWDIO_PORT JTAG_PORT
#define SWCLK_PORT JTAG_PORT
#define SWDIO_DIR_PIN TMS_DIR_PIN
#define SWDIO_PIN TMS_PIN
#define SWDIO_PIN_NUM 0
#define SWCLK_PIN TCK_PIN
#define TRST_PORT PORTA
#define TRST_PIN GPIO27
#define PWR_BR_PORT PORTA
#define PWR_BR_PIN GPIO28
#define SRST_PORT PORTA
#define SRST_PIN GPIO8
#define SRST_SENSE_PORT GPIOA
#define SRST_SENSE_PIN GPIO9
#define TRGT_SENSE GPIO2
#define LED_PORT PORTA
#define LED_PORT_UART PORTA
#define LED_0 GPIO10
#define LED_1 GPIO11
#define LED_2 GPIO14
//#define LED_2 GPIO13
#define LED_UART LED_1 /* Orange */
#define LED_IDLE_RUN LED_0 /* Yellow */
#define LED_ERROR LED_2 /* Red */
#define UART_TX_PIN GPIO4
#define UART_RX_PIN GPIO7
#define UART_PERIPH SOC_GPIO_PERIPH_D
#define UART_PERIPH_2 SOC_GPIO_PERIPH_C
#define SWO_PORT JTAG_PORT
#define SWO_PIN SWD_PIN
#define ADC_PORT PORTA
#define ADC_REF_PIN GPIO3
#define ADC_POS_PIN GPIO2
#define ADC_MUXPOS 0
#define BUTTON_PORT PORTA
#define BUTTON_PIN GPIO27
#endif
#define TMS_SET_MODE() { \
gpio_config_output(TMS_PORT, TMS_PIN, 0); \
gpio_set(TMS_PORT, TMS_DIR_PIN); \
}
#define SWDIO_MODE_FLOAT() do { \
PORT_DIRCLR(SWDIO_PORT) = SWDIO_PIN; \
gpio_set(SWDIO_PORT, SWDIO_PIN); \
gpio_clear(TMS_PORT, TMS_DIR_PIN); \
} while(0)
#define SWDIO_MODE_DRIVE() do { \
PORT_DIRSET(SWDIO_PORT) = SWDIO_PIN; \
gpio_set(TMS_PORT, TMS_DIR_PIN); \
} while(0)
/* extern usbd_driver samd21_usb_driver; */
#define USB_DRIVER samd21_usb_driver
#define USB_IRQ NVIC_USB_IRQ
#define USB_ISR usb_isr
#define IRQ_PRI_USB (2 << 4)
#define INLINE_GPIO
#define gpio_set_val(port, pin, val) do { \
if(val) \
_gpio_set((port), (pin)); \
else \
_gpio_clear((port), (pin)); \
} while(0)
#ifdef INLINE_GPIO
static inline void _gpio_set(uint32_t gpioport, uint32_t gpios)
{
PORT_OUTSET(gpioport) = gpios;
}
#define gpio_set _gpio_set
static inline void _gpio_clear(uint32_t gpioport, uint32_t gpios)
{
PORT_OUTCLR(gpioport) = gpios;
}
#define gpio_clear _gpio_clear
static inline uint16_t _gpio_get(uint32_t gpioport, uint32_t gpios)
{
return (uint32_t)PORT_IN(gpioport) & gpios;
}
#define gpio_get _gpio_get
#endif
#define DEBUG(...)
#define SET_RUN_STATE(state) {running_status = (state);}
#define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, LED_IDLE_RUN, state);}
#define SET_ERROR_STATE(state) {gpio_set_val(LED_PORT, LED_ERROR, state);}
static inline int platform_hwversion(void)
{
return 0;
}
void uart_pop(void);
int usbuart_convert_tdio(uint32_t arg);
int usbuart_convert_tdio_enabled(void);
void print_serial(void);
#endif

View File

@ -1,351 +0,0 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <libopencm3/sam/d/gclk.h>
#include <libopencm3/sam/d/port.h>
#include <libopencm3/sam/d/nvmctrl.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/dfu.h>
#include <libopencm3/sam/d/nvic.h>
#include <libopencm3/sam/d/pm.h>
#include <libopencm3/sam/d/bitfield.h>
#include <libopencm3/sam/d/usb.h>
//#define APP_ADDRESS 0x08002000
//#define APP_ADDRESS 0x00002000
#define APP_ADDRESS 0x00002000
//#define APP_ADDRESS 0x00004000
/* Commands sent with wBlockNum == 0 as per ST implementation. */
#define CMD_SETADDR 0x21
#define CMD_ERASE 0x41
#define BUTTON_PORT PORTA
#define BUTTON_PIN GPIO27
#define BUF_SIZE 4096
static struct gclk_hw clock = {
.gclk0 = SRC_DFLL48M,
.gclk1 = SRC_OSC8M,
/* clock 1 has 8 divider, clock should be over 1khz for 1ms timer */
.gclk1_div = 100,
.gclk2 = SRC_DFLL48M,
.gclk3 = SRC_DFLL48M,
.gclk3_div = 1,
.gclk4 = SRC_OSC8M,
.gclk4_div = 1,
.gclk5 = SRC_DFLL48M,
.gclk6 = SRC_DFLL48M,
.gclk7 = SRC_DFLL48M,
};
/* We need a special large control buffer for this device: */
uint8_t usbd_control_buffer[BUF_SIZE];
static enum dfu_state usbdfu_state = STATE_DFU_IDLE;
static struct {
uint8_t buf[sizeof(usbd_control_buffer)];
uint16_t len;
uint32_t addr;
uint16_t blocknum;
} prog;
const struct usb_device_descriptor dev = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = 0,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = 64,
.idVendor = 0x1D50,
.idProduct = 0x6017,
.bcdDevice = 0x0200,
.iManufacturer = 1,
.iProduct = 2,
.iSerialNumber = 3,
.bNumConfigurations = 1,
};
const struct usb_dfu_descriptor dfu_function = {
.bLength = sizeof(struct usb_dfu_descriptor),
.bDescriptorType = DFU_FUNCTIONAL,
.bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
.wDetachTimeout = 255,
.wTransferSize = BUF_SIZE,
.bcdDFUVersion = 0x011A,
};
const struct usb_interface_descriptor iface = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 0,
.bInterfaceClass = 0xFE, /* Device Firmware Upgrade */
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 2,
/* The ST Microelectronics DfuSe application needs this string.
* The format isn't documented... */
.iInterface = 4,
.extra = &dfu_function,
.extralen = sizeof(dfu_function),
};
const struct usb_interface ifaces[] = {{
.num_altsetting = 1,
.altsetting = &iface,
}};
const struct usb_config_descriptor config = {
.bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = 0,
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = 0,
.bmAttributes = 0xC0,
.bMaxPower = 0x32,
.interface = ifaces,
};
static const char *usb_strings[] = {
"Black Sphere Technologies",
"DFU Demo",
"DEMO",
/* This string is used by ST Microelectronics' DfuSe utility. */
//"@Internal Flash /0x08000000/8*001Ka,56*001Kg",
"@Internal Flash /0x00000000/1*008Ka,15*008Kg",
//"@Internal Flash /0x00000000/1*0016Ka,15*0016Kg",
};
static uint8_t usbdfu_getstatus(uint32_t *bwPollTimeout)
{
switch (usbdfu_state) {
case STATE_DFU_DNLOAD_SYNC:
usbdfu_state = STATE_DFU_DNBUSY;
*bwPollTimeout = 100;
return DFU_STATUS_OK;
case STATE_DFU_MANIFEST_SYNC:
/* Device will reset when read is complete. */
usbdfu_state = STATE_DFU_MANIFEST;
return DFU_STATUS_OK;
default:
return DFU_STATUS_OK;
}
}
static void usbdfu_getstatus_complete(usbd_device *usbd_dev, struct usb_setup_data *req)
{
int i;
(void)req;
(void)usbd_dev;
switch (usbdfu_state) {
case STATE_DFU_DNBUSY:
//flash_unlock();
if (prog.blocknum == 0) {
switch (prog.buf[0]) {
case CMD_ERASE:
{
uint32_t *dat = (uint32_t *)(prog.buf + 1);
nvmctrl_erase_row(*dat); //flash_erase_page(*dat);
}
break;
case CMD_SETADDR:
{
uint32_t *dat = (uint32_t *)(prog.buf + 1);
prog.addr = *dat;
}
break;
}
} else {
//uint32_t baseaddr = prog.addr + ((prog.blocknum - 2) *
// dfu_function.wTransferSize);
uint32_t baseaddr = prog.addr;
//for (i = 0; i < prog.len; i += 2) {
//uint16_t *dat = (uint16_t *)(prog.buf + i);
//flash_program_half_word(baseaddr + i,
// *dat);
for (i = 0; i < BUF_SIZE; i += 256){
nvmctrl_erase_row(baseaddr+i);
nvmctrl_write_row(baseaddr+i, prog.buf+i);
}
//}
}
//flash_lock();
/* Jump straight to dfuDNLOAD-IDLE, skipping dfuDNLOAD-SYNC. */
usbdfu_state = STATE_DFU_DNLOAD_IDLE;
return;
case STATE_DFU_MANIFEST:
/* reset USB */
INSERTBF(USB_CTRLA_SWRST, 1, USB->ctrla);
/* jump to app */
if ((*(volatile uint32_t *)APP_ADDRESS & 0x2FFE0000) == 0x20000000) {
/* Set vector table base address. */
//SCB_VTOR = APP_ADDRESS & 0xFFFF;
SCB_VTOR = APP_ADDRESS;
/* Initialise master stack pointer. */
asm volatile("msr msp, %0"::"g"
(*(volatile uint32_t *)APP_ADDRESS));
/* Jump to application. */
(*(void (**)())(APP_ADDRESS + 4))();
}
//scb_reset_system();
return; /* Will never return. */
default:
return;
}
}
static enum usbd_request_return_codes usbdfu_control_request(usbd_device *dev,
struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
void (**complete)(usbd_device *dev, struct usb_setup_data *req))
{
(void)dev;
if ((req->bmRequestType & 0x7F) != 0x21)
return 0; /* Only accept class request. */
switch (req->bRequest) {
case DFU_DNLOAD:
if ((len == NULL) || (*len == 0)) {
usbdfu_state = STATE_DFU_MANIFEST_SYNC;
return 1;
} else {
/* Copy download data for use on GET_STATUS. */
prog.blocknum = req->wValue;
prog.len = *len;
memcpy(prog.buf, *buf, *len);
usbdfu_state = STATE_DFU_DNLOAD_SYNC;
return 1;
}
case DFU_CLRSTATUS:
/* Clear error and return to dfuIDLE. */
if (usbdfu_state == STATE_DFU_ERROR)
usbdfu_state = STATE_DFU_IDLE;
return 1;
case DFU_ABORT:
/* Abort returns to dfuIDLE state. */
usbdfu_state = STATE_DFU_IDLE;
return 1;
case DFU_UPLOAD:
/* Upload not supported for now. */
return 0;
case DFU_GETSTATUS: {
uint32_t bwPollTimeout = 0; /* 24-bit integer in DFU class spec */
(*buf)[0] = usbdfu_getstatus(&bwPollTimeout);
(*buf)[1] = bwPollTimeout & 0xFF;
(*buf)[2] = (bwPollTimeout >> 8) & 0xFF;
(*buf)[3] = (bwPollTimeout >> 16) & 0xFF;
(*buf)[4] = usbdfu_state;
(*buf)[5] = 0; /* iString not used here */
*len = 6;
*complete = usbdfu_getstatus_complete;
return 1;
}
case DFU_GETSTATE:
/* Return state with no state transision. */
*buf[0] = usbdfu_state;
*len = 1;
return 1;
}
return 0;
}
static void usbdfu_set_config(usbd_device *usbd_dev, uint16_t wValue)
{
(void)wValue;
usbd_register_control_callback(
usbd_dev,
USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
usbdfu_control_request);
}
static void usb_setup(void)
{
/* Enable USB */
INSERTBF(PM_APBBMASK_USB, 1, PM->apbbmask);
/* enable clocking to usb */
set_periph_clk(GCLK0, GCLK_ID_USB);
periph_clk_en(GCLK_ID_USB, 1);
gpio_config_special(PORTA, GPIO24, SOC_GPIO_PERIPH_G);
gpio_config_special(PORTA, GPIO25, SOC_GPIO_PERIPH_G);
}
int main(void)
{
usbd_device *usbd_dev;
gclk_init(&clock);
//rcc_periph_clock_enable(RCC_GPIOA);
//gpio_config_input(BUTTON_PORT,BUTTON_PIN,GPIO_IN_FLAG_PULLUP);
gpio_config_input(BUTTON_PORT,BUTTON_PIN,0);
nvmctrl_init(0,0);
usb_setup();
if (PM->rcause != (1<<6))
if (gpio_get(BUTTON_PORT, BUTTON_PIN)) {
//if (gpio_get(PORTA, GPIO27)) {
/* Boot the application if it's valid. */
if ((*(volatile uint32_t *)APP_ADDRESS & 0x2FFE0000) == 0x20000000) {
/* Set vector table base address. */
//SCB_VTOR = APP_ADDRESS & 0xFFFF;
SCB_VTOR = APP_ADDRESS;
/* Initialise master stack pointer. */
asm volatile("msr msp, %0"::"g"
(*(volatile uint32_t *)APP_ADDRESS));
/* Jump to application. */
(*(void (**)())(APP_ADDRESS + 4))();
}
}
usbd_dev = usbd_init(&samd21_usb_driver, &dev, &config, usb_strings, 4, usbd_control_buffer, sizeof(usbd_control_buffer));
usbd_register_set_config_callback(usbd_dev, usbdfu_set_config);
//nvic_enable_irq(NVIC_USB_IRQ);
/* Connect USB cable */
usbd_disconnect(usbd_dev, false);
//gpio_clear(GPIOC, GPIO11);
while (1)
usbd_poll(usbd_dev);
}

View File

@ -285,7 +285,7 @@ static void adc_init(void)
adc_set_single_conversion_mode(ADC1);
adc_disable_external_trigger_regular(ADC1);
adc_set_right_aligned(ADC1);
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_239DOT5CYC);
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_28DOT5CYC);
adc_power_on(ADC1);
@ -316,8 +316,6 @@ uint32_t platform_target_voltage_sense(void)
while (!adc_eoc(ADC1));
uint32_t val = adc_read_regular(ADC1); /* 0-4095 */
/* Clear EOC bit. The GD32F103 does not automatically reset it on ADC read. */
ADC_SR(ADC1) &= ~ADC_SR_EOC;
return (val * 99) / 8191;
}

View File

@ -1,103 +0,0 @@
/*
* 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>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* This file implements a transparent channel over which the GDB Remote
* Serial Debugging protocol is implemented. This implementation for STM32
* uses the USB CDC-ACM device bulk endpoints to implement the channel.
*/
#include "general.h"
#include "gdb_if.h"
#include "cdcacm.h"
#include <libopencm3/usb/usbd.h>
static volatile uint32_t head_out, tail_out;
static volatile uint32_t count_in;
static volatile uint8_t buffer_out[16*CDCACM_PACKET_SIZE];
static volatile uint8_t buffer_in[CDCACM_PACKET_SIZE];
void gdb_if_putchar(unsigned char c, int flush)
{
buffer_in[count_in++] = c;
if(flush || (count_in == CDCACM_PACKET_SIZE)) {
/* Refuse to send if USB isn't configured, and
* don't bother if nobody's listening */
if((cdcacm_get_config() != 1) || !cdcacm_get_dtr()) {
count_in = 0;
return;
}
while(usbd_ep_write_packet(usbdev, CDCACM_GDB_ENDPOINT,
(uint8_t *)buffer_in, count_in) <= 0);
count_in = 0;
}
}
void gdb_usb_out_cb(usbd_device *dev, uint8_t ep)
{
(void)ep;
static uint8_t buf[CDCACM_PACKET_SIZE];
usbd_ep_nak_set(dev, CDCACM_GDB_ENDPOINT, 1);
uint32_t count = usbd_ep_read_packet(dev, CDCACM_GDB_ENDPOINT,
(uint8_t *)buf, CDCACM_PACKET_SIZE);
uint32_t idx;
for (idx=0; idx<count; idx++) {
buffer_out[head_out++ % sizeof(buffer_out)] = buf[idx];
}
usbd_ep_nak_set(dev, CDCACM_GDB_ENDPOINT, 0);
}
unsigned char gdb_if_getchar(void)
{
while(tail_out == head_out) {
/* Detach if port closed */
if(!cdcacm_get_dtr())
return 0x04;
while(cdcacm_get_config() != 1);
}
return buffer_out[tail_out++ % sizeof(buffer_out)];
}
unsigned char gdb_if_getchar_to(int timeout)
{
platform_timeout t;
platform_timeout_set(&t, timeout);
if(head_out == tail_out) do {
/* Detach if port closed */
if(!cdcacm_get_dtr())
return 0x04;
while(cdcacm_get_config() != 1);
} while(!platform_timeout_is_expired(&t) && head_out == tail_out);
if(head_out != tail_out)
return gdb_if_getchar();
return -1;
}

View File

@ -1,134 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* MIT License
*
* Copyright (c) 2021 Koen De Vleeschauwer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "general.h"
#include "platform.h"
#include <assert.h>
#include "cdcacm.h"
#include "rtt.h"
#include "rtt_if.h"
/*********************************************************************
*
* rtt terminal i/o
*
**********************************************************************
*/
/* usb uart receive buffer */
static char recv_buf[RTT_DOWN_BUF_SIZE];
static uint32_t recv_head = 0;
static uint32_t recv_tail = 0;
/* data from host to target: number of free bytes in usb receive buffer */
inline static uint32_t recv_bytes_free()
{
if (recv_tail <= recv_head)
return sizeof(recv_buf) - recv_head + recv_tail - 1;
else
return recv_tail - recv_head - 1;
}
/* data from host to target: true if not enough free buffer space and we need to close flow control */
inline static bool recv_set_nak()
{
assert(sizeof(recv_buf) > 2 * CDCACM_PACKET_SIZE);
return recv_bytes_free() < 2 * CDCACM_PACKET_SIZE;
}
/* usbuart_usb_out_cb is called when usb uart has received new data for target.
this routine has to be fast */
void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
{
(void)dev;
(void)ep;
char usb_buf[CDCACM_PACKET_SIZE];
/* close flow control while processing packet */
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 1);
const uint16_t len = usbd_ep_read_packet(usbdev, CDCACM_UART_ENDPOINT, usb_buf, CDCACM_PACKET_SIZE);
/* skip flag: drop packet if not enough free buffer space */
if (rtt_flag_skip && len > recv_bytes_free()) {
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 0);
return;
}
/* copy data to recv_buf */
for (int i = 0; i < len; i++) {
uint32_t next_recv_head = (recv_head + 1) % sizeof(recv_buf);
if (next_recv_head == recv_tail)
break; /* overflow */
recv_buf[recv_head] = usb_buf[i];
recv_head = next_recv_head;
}
/* block flag: flow control closed if not enough free buffer space */
if (!(rtt_flag_block && recv_set_nak()))
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 0);
return;
}
/* rtt host to target: read one character */
int32_t rtt_getchar()
{
int retval;
if (recv_head == recv_tail)
return -1;
retval = recv_buf[recv_tail];
recv_tail = (recv_tail + 1) % sizeof(recv_buf);
/* open flow control if enough free buffer space */
if (!recv_set_nak())
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 0);
return retval;
}
/* rtt host to target: true if no characters available for reading */
bool rtt_nodata()
{
return recv_head == recv_tail;
}
/* rtt target to host: write string */
uint32_t rtt_write(const char *buf, uint32_t len)
{
if (len != 0 && usbdev && cdcacm_get_config() && cdcacm_get_dtr()) {
for (uint32_t p = 0; p < len; p += CDCACM_PACKET_SIZE) {
uint32_t plen = MIN(CDCACM_PACKET_SIZE, len - p);
while(usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, buf + p, plen) <= 0);
}
/* flush 64-byte packet on full-speed */
if (CDCACM_PACKET_SIZE == 64 && (len % CDCACM_PACKET_SIZE) == 0)
while(usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, NULL, 0) <= 0);
}
return len;
}

View File

@ -1,28 +0,0 @@
/*
* This file is part of the libopenstm32 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
*
* 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/>.
*/
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x00002000, LENGTH = 120K /* 128k - 8k for bootloader */
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
}
/* Include the common ld script from libopenstm32. */
INCLUDE cortex-m-generic.ld

View File

@ -1,28 +0,0 @@
/*
* This file is part of the libopenstm32 project.
*
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
*
* 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/>.
*/
/* Define memory regions. */
MEMORY
{
rom (rx) : ORIGIN = 0x00000000, LENGTH = 128K /* 128k - 8k for bootloader */
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K
}
/* Include the common ld script from libopenstm32. */
INCLUDE cortex-m-generic.ld

View File

@ -1,57 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2018 Flirc Inc.
* Written by Jason Kotzin <jasonkotzin@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/* This file implements capture of the TRACESWO output.
*
* ARM DDI 0403D - ARMv7M Architecture Reference Manual
* ARM DDI 0337I - Cortex-M3 Technical Reference Manual
* ARM DDI 0314H - CoreSight Components Technical Reference Manual
*/
#include "general.h"
#include "cdcacm.h"
void traceswo_init(void)
{
}
void traceswo_baud(unsigned int baud)
{
baud++;
}
void trace_buf_push(void)
{
}
void trace_buf_drain(usbd_device *dev, uint8_t ep)
{
ep ++;
if (dev == NULL)
return;
}
void trace_tick(void)
{
}
void TRACEUART_ISR(void)
{
}

View File

@ -1,251 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2018 Flirc Inc.
* Written by Jason Kotzin <jasonkotzin@gmail.com>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "general.h"
#include "cdcacm.h"
#include <libopencm3/sam/d/bitfield.h>
#include <libopencm3/sam/d/gclk.h>
#include <libopencm3/sam/d/pm.h>
#include <libopencm3/sam/d/port.h>
#include <libopencm3/sam/d/nvic.h>
#include <libopencm3/sam/d/uart.h>
#include <libopencm3/cm3/cortex.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/scs.h>
#include <libopencm3/cm3/systick.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/cdc.h>
#include "queue.h"
#define Q_SIZE 1024
/* Active USART number */
static uint8_t USART_NUM = 0;
/* Current Baud Rate setting */
static uint32_t current_baud = 115200;
usbd_device * usbdev;
/* input and output ring buffer */
struct {
char buf[Q_SIZE];
volatile size_t head, tail;
} rx, tx;
#ifndef ENABLE_RTT
/* non blocking putc function */
static void usart_putc(char c)
{
#ifdef CONSOLE_NO_AUTO_CRLF
if (c == '\n')
usart_putc('\r');
#endif
if (qfull(tx.head, tx.tail, Q_SIZE))
return;
cm_disable_interrupts();
tx.buf[tx.head] = c;
tx.head = qinc(tx.head, Q_SIZE);
cm_enable_interrupts();
/* kick the transmitter to restart interrupts */
usart_enable_tx_interrupt(USART_NUM);
}
#endif
void usbuart_init(void)
{
/* enable gpios */
gpio_config_special(PORTA, UART_TX_PIN, UART_PERIPH); /* tx pin */
gpio_config_special(PORTA, UART_RX_PIN, UART_PERIPH); /* rx pin */
/* enable clocking to sercom0 */
set_periph_clk(GCLK0, GCLK_ID_SERCOM0_CORE);
periph_clk_en(GCLK_ID_SERCOM0_CORE, 1);
//usart_enable(USART_NUM, current_baud);
usart_setup(USART_NUM, current_baud);
#ifndef DEBUG_ME
usart_set_pads(USART_NUM, 3, 0); /* bm-sam uses different pads */
#endif
usart_enable(USART_NUM, 0); /* baud==0 so setup is skipped */
usart_enable_rx_interrupt(USART_NUM);
usart_enable_tx_interrupt(USART_NUM);
}
static uint8_t convert_tdio_enabled;
int usbuart_convert_tdio(uint32_t arg)
{
(void) arg;
convert_tdio_enabled = arg;
if (!convert_tdio_enabled) {
usart_disable(1);
USART_NUM = 0;
usbuart_init();
return current_baud;
}
gpio_config_special(PORTA, TDI_PIN, UART_PERIPH_2); /* TX */
gpio_config_special(PORTA, TDO_PIN, UART_PERIPH_2); /* RX */
/* disable USART0 (we will be using USART1 now) */
usart_disable(0);
USART_NUM = 1;
/* Select and Enable system clock */
set_periph_clk(GCLK0, GCLK_ID_SERCOM1_CORE);
periph_clk_en(GCLK_ID_SERCOM1_CORE, 1);
usart_setup(1, current_baud);
usart_set_pads(1, 3, 0); /* uses different pads than the default */
usart_enable(1, 0); /* baud==0 so setup is skipped */
usart_enable_rx_interrupt(1);
usart_enable_tx_interrupt(1);
return current_baud;
}
int usbuart_convert_tdio_enabled(void)
{
return convert_tdio_enabled;
}
void usbuart_set_line_coding(struct usb_cdc_line_coding *coding)
{
uint8_t sbmode = (coding->bCharFormat == 2) ? 1 : 0;
uint8_t parity = (coding->bParityType == 1) ? 0 : 1;
uint8_t form = (coding->bParityType) ? 1 : 0;
uint8_t chsize = (form) ? coding->bDataBits + 1 : coding->bDataBits;
usart_disable(USART_NUM);
/* set baud rate */
usart_set_baudrate(USART_NUM, coding->dwDTERate);
/* set data size, stop mode, and parity */
usart_set_chsize(USART_NUM, chsize);
usart_set_sbmode(USART_NUM, sbmode);
usart_set_parity(USART_NUM, parity, form);
usart_enable(USART_NUM, 0);
current_baud = coding->dwDTERate;
}
#ifndef ENABLE_RTT
void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
{
(void)ep;
char buf[CDCACM_PACKET_SIZE];
int len = usbd_ep_read_packet(dev, CDCACM_UART_ENDPOINT,
buf, CDCACM_PACKET_SIZE);
gpio_set(LED_PORT_UART, LED_UART);
for(int i = 0; i < len; i++) {
usart_putc(buf[i]);
}
gpio_clear(LED_PORT_UART, LED_UART);
}
#endif
/* run by our systick timer */
void uart_pop(void)
{
if (cdcacm_get_config() != 1) {
return;
}
if (!qempty(rx.head, rx.tail)) {
if (usbd_ep_write_packet(usbdev, 0x83, &rx.buf[rx.tail], 1) == 0) {
return;
}
rx.tail = qinc(rx.tail, Q_SIZE);
}
}
void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep)
{
(void) dev;
(void) ep;
}
/************************** UART Interrupt Handlers *************************/
static void uart_rx_irq(void)
{
char c = UART(USART_NUM)->data;
/* bug?, need to re-enable rx complete interrupt */
INSERTBF(UART_INTENSET_RXC, 1, UART(USART_NUM)->intenset);
if (!qfull(rx.head, rx.tail, Q_SIZE)) {
rx.buf[rx.head] = c;
rx.head = qinc(rx.head, Q_SIZE);
}
}
static void uart_tx_irq(void)
{
if (!qempty(tx.head, tx.tail)) {
usart_send(USART_NUM, tx.buf[tx.tail]);
tx.tail = qinc(tx.tail, Q_SIZE);
} else {
usart_disable_tx_interrupt(USART_NUM);
}
}
void sercom0_isr(void)
{
/* Turn on LED */
gpio_set(LED_PORT_UART, LED_UART);
if (GETBF(UART_INTFLAG_RXC, UART(USART_NUM)->intflag))
uart_rx_irq();
if (GETBF(UART_INTFLAG_DRE, UART(USART_NUM)->intflag))
uart_tx_irq();
}
void sercom1_isr(void)
{
/* Turn on LED */
gpio_set(LED_PORT_UART, LED_UART);
if (GETBF(UART_INTFLAG_RXC, UART(USART_NUM)->intflag))
uart_rx_irq();
if (GETBF(UART_INTFLAG_DRE, UART(USART_NUM)->intflag))
uart_tx_irq();
}

View File

@ -1,134 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* MIT License
*
* Copyright (c) 2021 Koen De Vleeschauwer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "general.h"
#include "platform.h"
#include <assert.h>
#include "cdcacm.h"
#include "rtt.h"
#include "rtt_if.h"
/*********************************************************************
*
* rtt terminal i/o
*
**********************************************************************
*/
/* usb uart receive buffer */
static char recv_buf[RTT_DOWN_BUF_SIZE];
static uint32_t recv_head = 0;
static uint32_t recv_tail = 0;
/* data from host to target: number of free bytes in usb receive buffer */
inline static uint32_t recv_bytes_free()
{
if (recv_tail <= recv_head)
return sizeof(recv_buf) - recv_head + recv_tail - 1;
else
return recv_tail - recv_head - 1;
}
/* data from host to target: true if not enough free buffer space and we need to close flow control */
inline static bool recv_set_nak()
{
assert(sizeof(recv_buf) > 2 * CDCACM_PACKET_SIZE);
return recv_bytes_free() < 2 * CDCACM_PACKET_SIZE;
}
/* usbuart_usb_out_cb is called when usb uart has received new data for target.
this routine has to be fast */
void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
{
(void)dev;
(void)ep;
char usb_buf[CDCACM_PACKET_SIZE];
/* close flow control while processing packet */
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 1);
const uint16_t len = usbd_ep_read_packet(usbdev, CDCACM_UART_ENDPOINT, usb_buf, CDCACM_PACKET_SIZE);
/* skip flag: drop packet if not enough free buffer space */
if (rtt_flag_skip && len > recv_bytes_free()) {
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 0);
return;
}
/* copy data to recv_buf */
for (int i = 0; i < len; i++) {
uint32_t next_recv_head = (recv_head + 1) % sizeof(recv_buf);
if (next_recv_head == recv_tail)
break; /* overflow */
recv_buf[recv_head] = usb_buf[i];
recv_head = next_recv_head;
}
/* block flag: flow control closed if not enough free buffer space */
if (!(rtt_flag_block && recv_set_nak()))
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 0);
return;
}
/* rtt host to target: read one character */
int32_t rtt_getchar()
{
int retval;
if (recv_head == recv_tail)
return -1;
retval = recv_buf[recv_tail];
recv_tail = (recv_tail + 1) % sizeof(recv_buf);
/* open flow control if enough free buffer space */
if (!recv_set_nak())
usbd_ep_nak_set(usbdev, CDCACM_UART_ENDPOINT, 0);
return retval;
}
/* rtt host to target: true if no characters available for reading */
bool rtt_nodata()
{
return recv_head == recv_tail;
}
/* rtt target to host: write string */
uint32_t rtt_write(const char *buf, uint32_t len)
{
if (len != 0 && usbdev && cdcacm_get_config() && cdcacm_get_dtr()) {
for (uint32_t p = 0; p < len; p += CDCACM_PACKET_SIZE) {
uint32_t plen = MIN(CDCACM_PACKET_SIZE, len - p);
while(usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, buf + p, plen) <= 0);
}
/* flush 64-byte packet on full-speed */
if (CDCACM_PACKET_SIZE == 64 && (len % CDCACM_PACKET_SIZE) == 0)
while(usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, NULL, 0) <= 0);
}
return len;
}

View File

@ -259,7 +259,6 @@ static void usbuart_change_dma_tx_buf(void)
buf_tx_act_idx ^= 1;
}
#ifndef ENABLE_RTT
void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
{
(void)ep;
@ -302,7 +301,6 @@ void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
if (TX_BUF_SIZE - buf_tx_act_sz >= CDCACM_PACKET_SIZE)
usbd_ep_nak_set(dev, CDCACM_UART_ENDPOINT, 0);
}
#endif
#ifdef USBUART_DEBUG
int usbuart_debug_write(const char *buf, size_t len)

View File

@ -99,7 +99,6 @@ void usbuart_set_line_coding(struct usb_cdc_line_coding *coding)
}
}
#ifndef ENABLE_RTT
void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
{
(void)ep;
@ -111,7 +110,7 @@ void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
for(int i = 0; i < len; i++)
uart_send_blocking(USBUART, buf[i]);
}
#endif
void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep)
{

456
src/rtt.c
View File

@ -1,456 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* MIT License
*
* Copyright (c) 2021 Koen De Vleeschauwer
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "general.h"
#include "platform.h"
#include "gdb_packet.h"
#include "target.h"
#include "target/target_internal.h"
#include "rtt.h"
#include "rtt_if.h"
bool rtt_enabled = false;
bool rtt_found = false;
static bool rtt_halt = false; // true if rtt needs to halt target to access memory
uint32_t rtt_cbaddr = 0;
bool rtt_auto_channel = true;
struct rtt_channel_struct rtt_channel[MAX_RTT_CHAN];
uint32_t rtt_min_poll_ms = 8; /* 8 ms */
uint32_t rtt_max_poll_ms = 256; /* 0.256 s */
uint32_t rtt_max_poll_errs = 10;
static uint32_t poll_ms;
static uint32_t poll_errs;
static uint32_t last_poll_ms;
/* flags for data from host to target */
bool rtt_flag_skip = false;
bool rtt_flag_block = false;
typedef enum rtt_retval {
RTT_OK,
RTT_IDLE,
RTT_ERR
} rtt_retval;
#ifdef RTT_IDENT
#define Q(x) #x
#define QUOTE(x) Q(x)
char rtt_ident[16] = QUOTE(RTT_IDENT);
#else
char rtt_ident[16] = {0};
#endif
/* usb uart transmit buffer */
static char xmit_buf[RTT_UP_BUF_SIZE];
/*********************************************************************
*
* rtt control block
*
**********************************************************************
*/
uint32_t fastsrch(target *cur_target)
{
const uint32_t m = 16;
const uint64_t q = 0x797a9691; /* prime */
const uint64_t rm = 0x73b07d01;
const uint64_t p = 0x444110cd;
const uint32_t stride = 128;
uint64_t t = 0;
uint8_t srch_buf[m+stride];
for (struct target_ram *r = cur_target->ram; r; r = r->next) {
const uint32_t ram_start = r->start;
const uint32_t ram_end = r->start + r->length;
t = 0;
memset(srch_buf, 0, sizeof(srch_buf));
for (uint32_t addr = ram_start; addr < ram_end; addr += stride) {
uint32_t buf_siz = MIN(stride, ram_end - addr);
memcpy(srch_buf, srch_buf + stride, m);
if (target_mem_read(cur_target, srch_buf + m, addr, buf_siz)) {
gdb_outf("rtt: read fail at 0x%" PRIx32 "\r\n", addr);
return 0;
}
for (uint32_t i = 0; i < buf_siz; i++) {
t = (t + q - rm * srch_buf[i] % q) % q;
t = ((t << 8) + srch_buf[i + m]) % q;
if (p == t) {
uint32_t offset = i - m + 1;
return addr + offset;
}
}
}
}
/* no match */
return 0;
}
uint32_t memsrch(target *cur_target)
{
char *srch_str = rtt_ident;
uint32_t srch_str_len = strlen(srch_str);
uint8_t srch_buf[128];
if (srch_str_len == 0 || srch_str_len > sizeof(srch_buf) / 2)
return 0;
if (rtt_cbaddr && !target_mem_read(cur_target, srch_buf, rtt_cbaddr, srch_str_len)
&& strncmp((const char *)(srch_buf), srch_str, srch_str_len) == 0)
/* still at same place */
return rtt_cbaddr;
for (struct target_ram *r = cur_target->ram; r; r = r->next) {
uint32_t ram_end = r->start + r->length;
for (uint32_t addr = r->start; addr < ram_end; addr += sizeof(srch_buf) - srch_str_len - 1) {
uint32_t buf_siz = MIN(ram_end - addr, sizeof(srch_buf));
if (target_mem_read(cur_target, srch_buf, addr, buf_siz)) {
gdb_outf("rtt: read fail at 0x%" PRIx32 "\r\n", addr);
continue;
}
for (uint32_t offset = 0; offset + srch_str_len + 1 < buf_siz; offset++) {
if (strncmp((const char *)(srch_buf + offset), srch_str, srch_str_len) == 0) {
uint32_t cb_addr = addr + offset;
return cb_addr;
}
}
}
}
return 0;
}
static void find_rtt(target *cur_target)
{
rtt_found = false;
poll_ms = rtt_max_poll_ms;
poll_errs = 0;
last_poll_ms = 0;
if (!cur_target || !rtt_enabled)
return;
if (rtt_ident[0] == 0)
rtt_cbaddr = fastsrch(cur_target);
else
rtt_cbaddr = memsrch(cur_target);
DEBUG_INFO("rtt: match at 0x%" PRIx32 "\r\n", rtt_cbaddr);
if (rtt_cbaddr) {
uint32_t num_buf[2];
int32_t num_up_buf;
int32_t num_down_buf;
if (target_mem_read(cur_target, num_buf, rtt_cbaddr + 16, sizeof(num_buf)))
return;
num_up_buf = num_buf[0];
num_down_buf = num_buf[1];
if (num_up_buf > 255 || num_down_buf > 255) {
gdb_out("rtt: bad cblock\r\n");
rtt_enabled = false;
return;
} else if (num_up_buf == 0 && num_down_buf == 0)
gdb_out("rtt: empty cblock\r\n");
for (int32_t i = 0; i < MAX_RTT_CHAN; i++) {
uint32_t buf_desc[6];
rtt_channel[i].is_configured = false;
rtt_channel[i].is_output = false;
rtt_channel[i].buf_addr = 0;
rtt_channel[i].buf_size = 0;
rtt_channel[i].head_addr = 0;
rtt_channel[i].tail_addr = 0;
rtt_channel[i].flag = 0;
if (i >= num_up_buf + num_down_buf)
continue;
if (target_mem_read(cur_target, buf_desc, rtt_cbaddr + 24 + i * 24, sizeof(buf_desc)))
return;
rtt_channel[i].is_output = i < num_up_buf;
rtt_channel[i].buf_addr = buf_desc[1];
rtt_channel[i].buf_size = buf_desc[2];
rtt_channel[i].head_addr = rtt_cbaddr + 24 + i * 24 + 12;
rtt_channel[i].tail_addr = rtt_cbaddr + 24 + i * 24 + 16;
rtt_channel[i].flag = buf_desc[5];
rtt_channel[i].is_configured = (rtt_channel[i].buf_addr != 0) && (rtt_channel[i].buf_size != 0);
}
/* auto channel: enable output channels 0 and 1 and first input channel */
if (rtt_auto_channel) {
for (uint32_t i = 0; i < MAX_RTT_CHAN; i++)
rtt_channel[i].is_enabled = false;
rtt_channel[0].is_enabled = num_up_buf > 0;
rtt_channel[1].is_enabled = num_up_buf > 1;
if ((num_up_buf < MAX_RTT_CHAN) && (num_down_buf > 0))
rtt_channel[num_up_buf].is_enabled = true;
}
/* get flags for data from host to target */
rtt_flag_skip = false;
rtt_flag_block = false;
for (uint32_t i = 0; i < MAX_RTT_CHAN; i++)
if (rtt_channel[i].is_enabled && rtt_channel[i].is_configured && !rtt_channel[i].is_output) {
rtt_flag_skip = rtt_channel[i].flag == 0;
rtt_flag_block = rtt_channel[i].flag == 2;
break;
}
rtt_found = true;
DEBUG_INFO("rtt found\n");
}
return;
}
/*********************************************************************
*
* rtt from host to target
*
**********************************************************************
*/
/* poll if host has new data for target */
static rtt_retval read_rtt(target *cur_target, uint32_t i)
{
uint32_t head_tail[2];
uint32_t buf_head;
uint32_t buf_tail;
uint32_t next_head;
int ch;
/* copy data from recv_buf to target rtt 'down' buffer */
if (rtt_nodata())
return RTT_IDLE;
if (cur_target == NULL || rtt_channel[i].is_output || rtt_channel[i].buf_addr == 0 || rtt_channel[i].buf_size == 0)
return RTT_IDLE;
/* read down buffer head and tail from target */
if (target_mem_read(cur_target, head_tail, rtt_channel[i].head_addr, sizeof(head_tail)))
return RTT_ERR;
buf_head = head_tail[0];
buf_tail = head_tail[1];
if (buf_head >= rtt_channel[i].buf_size || buf_tail >= rtt_channel[i].buf_size)
return RTT_ERR;
/* write recv_buf to target rtt 'down' buf */
while ((next_head = ((buf_head + 1) % rtt_channel[i].buf_size)) != buf_tail && (ch = rtt_getchar()) != -1) {
if (target_mem_write(cur_target, rtt_channel[i].buf_addr + buf_head, &ch, 1))
return RTT_ERR;
/* advance pointers */
buf_head = next_head;
}
/* update head of target 'down' buffer */
if (target_mem_write(cur_target, rtt_channel[i].head_addr, &buf_head, sizeof(buf_head)))
return RTT_ERR;
return RTT_OK;
}
/*********************************************************************
*
* rtt from target to host
*
**********************************************************************
*/
/* target_mem_read, word aligned for speed.
note: dest has to be len + 8 bytes, to allow for alignment and padding.
*/
int target_aligned_mem_read(target *t, void *dest, target_addr src, size_t len)
{
uint32_t src0 = src;
uint32_t len0 = len;
uint32_t offset = src & 0x3;
src0 -= offset;
len0 += offset;
if ((len0 & 0x3) != 0)
len0 = (len0 + 4) & ~0x3;
if (src0 == src && len0 == len)
return target_mem_read(t, dest, src, len);
else {
uint32_t retval = target_mem_read(t, dest, src0, len0);
memmove(dest, dest + offset, len);
return retval;
}
}
/* poll if target has new data for host */
static rtt_retval print_rtt(target *cur_target, uint32_t i)
{
uint32_t head;
uint32_t tail;
if (!cur_target || !rtt_channel[i].is_output || rtt_channel[i].buf_addr == 0 || rtt_channel[i].head_addr == 0)
return RTT_IDLE;
uint32_t head_tail[2];
if (target_mem_read(cur_target, head_tail, rtt_channel[i].head_addr, sizeof(head_tail)))
return RTT_ERR;
head = head_tail[0];
tail = head_tail[1];
if (head >= rtt_channel[i].buf_size || tail >= rtt_channel[i].buf_size)
return RTT_ERR;
else if (head == tail)
return RTT_IDLE;
uint32_t bytes_free = sizeof(xmit_buf) - 8; /* need 8 bytes for alignment and padding */
uint32_t bytes_read = 0;
if (tail > head) {
uint32_t len = rtt_channel[i].buf_size - tail;
if (len > bytes_free)
len = bytes_free;
if (target_aligned_mem_read(cur_target, xmit_buf + bytes_read, rtt_channel[i].buf_addr + tail, len))
return RTT_ERR;
bytes_free -= len;
bytes_read += len;
tail = (tail + len) % rtt_channel[i].buf_size;
}
if (head > tail && bytes_free > 0) {
uint32_t len = head - tail;
if (len > bytes_free)
len = bytes_free;
if (target_aligned_mem_read(cur_target, xmit_buf + bytes_read, rtt_channel[i].buf_addr + tail, len))
return RTT_ERR;
bytes_read += len;
tail = (tail + len) % rtt_channel[i].buf_size;
}
/* update tail on target */
if (target_mem_write(cur_target, rtt_channel[i].tail_addr, &tail, sizeof(tail)))
return RTT_ERR;
/* write buffer to usb */
rtt_write(xmit_buf, bytes_read);
return RTT_OK;
}
/*********************************************************************
*
* target background memory access
*
**********************************************************************
*/
/* target_no_background_memory_access() is true if the target needs to be halted during jtag memory access
target_no_background_memory_access() is false if the target allows jtag memory access while running */
bool target_no_background_memory_access(target *cur_target)
{
/* if error message is 'rtt: read fail at' add target to expression below.
As a first approximation, assume all arm processors allow memory access while running, and no riscv does. */
bool riscv_core = cur_target && target_core_name(cur_target) && strstr(target_core_name(cur_target), "RVDBG");
return riscv_core;
}
/*********************************************************************
*
* rtt top level
*
**********************************************************************
*/
void poll_rtt(target *cur_target)
{
/* rtt off */
if (!cur_target || !rtt_enabled)
return;
/* target present and rtt enabled */
uint32_t now = platform_time_ms();
bool rtt_err = false;
bool rtt_busy = false;
if (last_poll_ms + poll_ms <= now || now < last_poll_ms) {
target_addr watch;
enum target_halt_reason reason;
bool resume_target = false;
if (!rtt_found)
/* check if target needs to be halted during memory access */
rtt_halt = target_no_background_memory_access(cur_target);
if (rtt_halt && target_halt_poll(cur_target, &watch) == TARGET_HALT_RUNNING) {
/* briefly halt target during target memory access */
target_halt_request(cur_target);
while((reason = target_halt_poll(cur_target, &watch)) == TARGET_HALT_RUNNING)
continue;
resume_target = reason == TARGET_HALT_REQUEST;
}
if (!rtt_found)
/* find rtt control block in target memory */
find_rtt(cur_target);
/* do rtt i/o if control block found */
if (rtt_found) {
for (uint32_t i = 0; i < MAX_RTT_CHAN; i++) {
rtt_retval v;
if (rtt_channel[i].is_enabled && rtt_channel[i].is_configured) {
if (rtt_channel[i].is_output)
v = print_rtt(cur_target, i);
else
v = read_rtt(cur_target, i);
if (v == RTT_OK) rtt_busy = true;
else if (v == RTT_ERR) rtt_err = true;
}
}
}
/* continue target if halted */
if (resume_target)
target_halt_resume(cur_target, false);
/* update last poll time */
last_poll_ms = now;
/* rtt polling frequency goes up and down with rtt activity */
if (rtt_busy && !rtt_err)
poll_ms /= 2;
else
poll_ms *= 2;
if (poll_ms > rtt_max_poll_ms)
poll_ms = rtt_max_poll_ms;
else if (poll_ms < rtt_min_poll_ms)
poll_ms = rtt_min_poll_ms;
if (rtt_err) {
gdb_out("rtt: err\r\n");
poll_errs++;
if (rtt_max_poll_errs != 0 && poll_errs > rtt_max_poll_errs) {
gdb_out("\r\nrtt lost\r\n");
rtt_enabled = false;
}
}
}
return;
}

View File

@ -68,7 +68,7 @@ bool firmware_dp_low_write(ADIv5_DP_t *dp, uint16_t addr, const uint32_t data)
int adiv5_swdp_scan(uint32_t targetid)
{
volatile struct exception e;
static bool scan_multidrop = true;
target_list_free();
ADIv5_DP_t idp = {
.dp_low_write = firmware_dp_low_write,
.error = firmware_swdp_error,
@ -77,7 +77,6 @@ int adiv5_swdp_scan(uint32_t targetid)
.abort = firmware_swdp_abort,
};
ADIv5_DP_t *initial_dp = &idp;
target_list_free();
if (swdptap_init(initial_dp))
return -1;
/* DORMANT-> SWD sequence*/
@ -94,6 +93,7 @@ int adiv5_swdp_scan(uint32_t targetid)
initial_dp->seq_out(0x1a0, 12);
uint32_t idcode = 0;
volatile uint32_t target_id = 0;
bool scan_multidrop = true;
if (!targetid || !initial_dp->dp_low_write) {
/* No targetID given on the command line or probe can not
* handle multi-drop. Try to read ID */

View File

@ -32,20 +32,29 @@
#include "target_internal.h"
#include "cortexm.h"
#if PC_HOSTED == 1
#define DEBUG_CH DEBUG_INFO
#define ERROR_CH DEBUG_WARN
#else
#define DEBUG_CH(...) {} //DEBUG_WARN //(...) {}
#define ERROR_CH DEBUG_WARN //DEBUG_WARN
#endif
extern const struct command_s stm32f1_cmd_list[]; // Reuse stm32f1 stuff
static int ch32f1_flash_erase(struct target_flash *f,
static int ch32f1_flash_erase(struct target_flash *f,
target_addr addr, size_t len);
static int ch32f1_flash_write(struct target_flash *f,
static int ch32f1_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);
// these are common with stm32f1/gd32f1/...
#define FPEC_BASE 0x40022000
#define FLASH_ACR (FPEC_BASE + 0x00)
#define FLASH_KEYR (FPEC_BASE + 0x04)
#define FLASH_SR (FPEC_BASE + 0x0C)
#define FLASH_CR (FPEC_BASE + 0x10)
#define FLASH_AR (FPEC_BASE + 0x14)
#define FLASH_ACR (FPEC_BASE+0x00)
#define FLASH_KEYR (FPEC_BASE+0x04)
#define FLASH_SR (FPEC_BASE+0x0C)
#define FLASH_CR (FPEC_BASE+0x10)
#define FLASH_AR (FPEC_BASE+0x14)
#define FLASH_CR_LOCK (1 << 7)
#define FLASH_CR_STRT (1 << 6)
#define FLASH_SR_BSY (1 << 0)
@ -57,16 +66,19 @@ static int ch32f1_flash_write(struct target_flash *f,
#define FLASHSIZE 0x1FFFF7E0
// these are specific to ch32f1
#define FLASH_MAGIC (FPEC_BASE + 0x34)
#define FLASH_MODEKEYR_CH32 (FPEC_BASE + 0x24) // Fast mode for CH32F10x
#define FLASH_CR_FLOCK_CH32 (1 << 15) // fast unlock
#define FLASH_CR_FTPG_CH32 (1 << 16) // fast page program
#define FLASH_CR_FTER_CH32 (1 << 17) // fast page erase
#define FLASH_CR_BUF_LOAD_CH32 (1 << 18) // Buffer load
#define FLASH_CR_BUF_RESET_CH32 (1 << 19) // Buffer reset
#define FLASH_SR_EOP (1 << 5) // End of programming
#define FLASH_MAGIC (FPEC_BASE+0x34)
#define FLASH_MODEKEYR_CH32 (FPEC_BASE+0x24) // Fast mode for CH32F10x
#define FLASH_CR_FLOCK_CH32 (1<<15) // fast unlock
#define FLASH_CR_FTPG_CH32 (1<<16) // fast page program
#define FLASH_CR_FTER_CH32 (1<<17) // fast page erase
#define FLASH_CR_BUF_LOAD_CH32 (1<<18) // Buffer load
#define FLASH_CR_BUF_RESET_CH32 (1<<19) // Buffer reset
#define FLASH_SR_EOP (1<<5) // End of programming
#define FLASH_BEGIN_ADDRESS_CH32 0x8000000
/**
\fn ch32f1_add_flash
\brief "fast" flash driver for CH32F10x chips
@ -91,39 +103,36 @@ static void ch32f1_add_flash(target *t, uint32_t addr, size_t length, size_t era
#define WAIT_BUSY() do { \
sr = target_mem_read32(t, FLASH_SR); \
if (target_check_error(t)) { \
DEBUG_WARN("ch32f1 flash write: comm error\n"); \
if(target_check_error(t)) { \
ERROR_CH("ch32f1 flash write: comm error\n"); \
return -1; \
} \
} while (sr & FLASH_SR_BSY);
} while (sr & FLASH_SR_BSY);
#define WAIT_EOP() do { \
sr = target_mem_read32(t, FLASH_SR); \
if (target_check_error(t)) { \
DEBUG_WARN("ch32f1 flash write: comm error\n"); \
if(target_check_error(t)) { \
ERROR_CH("ch32f1 flash write: comm error\n"); \
return -1; \
} \
} while (!(sr & FLASH_SR_EOP));
} while (!(sr & FLASH_SR_EOP));
#define CLEAR_EOP() target_mem_write32(t, FLASH_SR,FLASH_SR_EOP)
#define SET_CR(bit) do { \
const uint32_t cr = target_mem_read32(t, FLASH_CR) | (bit); \
target_mem_write32(t, FLASH_CR, cr); \
} while(0)
#define SET_CR(bit) { ct = target_mem_read32(t, FLASH_CR); \
ct|=(bit); \
target_mem_write32(t, FLASH_CR, ct);}
#define CLEAR_CR(bit) do { \
const uint32_t cr = target_mem_read32(t, FLASH_CR) & (~(bit)); \
target_mem_write32(t, FLASH_CR, cr); \
} while(0)
#define CLEAR_CR(bit) {ct = target_mem_read32(t, FLASH_CR); \
ct&=~(bit); \
target_mem_write32(t, FLASH_CR, ct);}
// Which one is the right value ?
#define MAGIC_WORD 0x100
// #define MAGIC_WORD 0x1000
#define MAGIC(addr) do { \
magic = target_mem_read32(t, (addr) ^ MAGIC_WORD); \
target_mem_write32(t, FLASH_MAGIC , magic); \
} while(0)
#define MAGIC(adr) { magic=target_mem_read32(t,(adr) ^ MAGIC_WORD); \
target_mem_write32(t, FLASH_MAGIC , magic); }
/**
\fn ch32f1_flash_unlock
@ -131,24 +140,24 @@ static void ch32f1_add_flash(target *t, uint32_t addr, size_t length, size_t era
*/
static int ch32f1_flash_unlock(target *t)
{
DEBUG_INFO("CH32: flash unlock \n");
DEBUG_CH("CH32: flash unlock \n");
target_mem_write32(t, FLASH_KEYR, KEY1);
target_mem_write32(t, FLASH_KEYR, KEY2);
target_mem_write32(t, FLASH_KEYR , KEY1);
target_mem_write32(t, FLASH_KEYR , KEY2);
// fast mode
target_mem_write32(t, FLASH_MODEKEYR_CH32, KEY1);
target_mem_write32(t, FLASH_MODEKEYR_CH32, KEY2);
target_mem_write32(t, FLASH_MODEKEYR_CH32 , KEY1);
target_mem_write32(t, FLASH_MODEKEYR_CH32 , KEY2);
uint32_t cr = target_mem_read32(t, FLASH_CR);
if (cr & FLASH_CR_FLOCK_CH32) {
DEBUG_WARN("Fast unlock failed, cr: 0x%08" PRIx32 "\n", cr);
if (cr & FLASH_CR_FLOCK_CH32){
ERROR_CH("Fast unlock failed, cr: 0x%08" PRIx32 "\n", cr);
return -1;
}
return 0;
}
static int ch32f1_flash_lock(target *t)
{
DEBUG_INFO("CH32: flash lock \n");
volatile uint32_t ct;
DEBUG_CH("CH32: flash lock \n");
SET_CR(FLASH_CR_LOCK);
return 0;
}
@ -157,55 +166,56 @@ static int ch32f1_flash_lock(target *t)
\brief identify the ch32f1 chip
Actually grab all cortex m3 with designer = arm not caught earlier...
*/
bool ch32f1_probe(target *t)
{
t->idcode = target_mem_read32(t, DBGMCU_IDCODE) & 0xfff;
if ((t->cpuid & CPUID_PARTNO_MASK) != CORTEX_M3)
return false;
const uint32_t idcode = target_mem_read32(t, DBGMCU_IDCODE) & 0x00000fffU;
if (idcode != 0x410) // only ch32f103
if(t->idcode !=0x410) { // only ch32f103
return false;
}
// try to flock
ch32f1_flash_lock(t);
// if this fails it is not a CH32 chip
if (ch32f1_flash_unlock(t))
if(ch32f1_flash_unlock(t)) {
return false;
}
t->idcode = idcode;
uint32_t signature = target_mem_read32(t, FLASHSIZE);
uint32_t flashSize = signature & 0xFFFF;
target_add_ram(t, 0x20000000, 0x5000);
ch32f1_add_flash(t, FLASH_BEGIN_ADDRESS_CH32, flashSize * 1024, 128);
ch32f1_add_flash(t, FLASH_BEGIN_ADDRESS_CH32, flashSize*1024, 128);
target_add_commands(t, stm32f1_cmd_list, "STM32 LD/MD/VL-LD/VL-MD");
t->driver = "CH32F1 medium density (stm32f1 clone)";
return true;
}
/**
\fn ch32f1_flash_erase
\brief fast erase of CH32
*/
int ch32f1_flash_erase(struct target_flash *f, target_addr addr, size_t len)
int ch32f1_flash_erase (struct target_flash *f, target_addr addr, size_t len)
{
volatile uint32_t sr, magic;
volatile uint32_t ct, sr, magic;
target *t = f->t;
DEBUG_INFO("CH32: flash erase \n");
DEBUG_CH("CH32: flash erase \n");
if (ch32f1_flash_unlock(t)) {
DEBUG_WARN("CH32: Unlock failed\n");
ERROR_CH("CH32: Unlock failed\n");
return -1;
}
// Fast Erase 128 bytes pages (ch32 mode)
while (len) {
while(len) {
SET_CR(FLASH_CR_FTER_CH32);// CH32 PAGE_ER
/* write address to FMA */
target_mem_write32(t, FLASH_AR, addr);
target_mem_write32(t, FLASH_AR , addr);
/* Flash page erase start instruction */
SET_CR(FLASH_CR_STRT);
SET_CR( FLASH_CR_STRT );
WAIT_EOP();
CLEAR_EOP();
CLEAR_CR(FLASH_CR_STRT);
CLEAR_CR( FLASH_CR_STRT );
// Magic
MAGIC(addr);
if (len > 128)
@ -216,8 +226,8 @@ int ch32f1_flash_erase(struct target_flash *f, target_addr addr, size_t len)
}
sr = target_mem_read32(t, FLASH_SR);
ch32f1_flash_lock(t);
if (sr & SR_ERROR_MASK) {
DEBUG_WARN("ch32f1 flash erase error 0x%" PRIx32 "\n", sr);
if ((sr & SR_ERROR_MASK)) {
ERROR_CH("ch32f1 flash erase error 0x%" PRIx32 "\n", sr);
return -1;
}
return 0;
@ -231,13 +241,14 @@ int ch32f1_flash_erase(struct target_flash *f, target_addr addr, size_t len)
NB: Just reading fff is not enough as it could be a transient previous operation value
*/
static bool ch32f1_wait_flash_ready(target *t, uint32_t addr)
static bool ch32f1_wait_flash_ready(target *t,uint32_t adr)
{
uint32_t ff = 0;
for (size_t i = 0; i < 32; i++)
ff = target_mem_read32(t, addr);
if (ff != 0xffffffffUL) {
DEBUG_WARN("ch32f1 Not erased properly at %" PRIx32 " or flash access issue\n", addr);
uint32_t ff;
for(int i = 0; i < 32; i++) {
ff = target_mem_read32(t,adr);
}
if(ff != 0xffffffffUL) {
ERROR_CH("ch32f1 Not erased properly at %x or flash access issue\n",adr);
return false;
}
return true;
@ -249,20 +260,20 @@ static bool ch32f1_wait_flash_ready(target *t, uint32_t addr)
static int ch32f1_upload(target *t, uint32_t dest, const void *src, uint32_t offset)
{
volatile uint32_t sr, magic;
volatile uint32_t ct, sr, magic;
const uint32_t *ss = (const uint32_t *)(src+offset);
uint32_t dd = dest + offset;
uint32_t dd = dest+offset;
SET_CR(FLASH_CR_FTPG_CH32);
target_mem_write32(t, dd + 0, ss[0]);
target_mem_write32(t, dd + 4, ss[1]);
target_mem_write32(t, dd + 8, ss[2]);
target_mem_write32(t, dd + 12, ss[3]);
target_mem_write32(t, dd+0,ss[0]);
target_mem_write32(t, dd+4,ss[1]);
target_mem_write32(t, dd+8,ss[2]);
target_mem_write32(t, dd+12,ss[3]);
SET_CR(FLASH_CR_BUF_LOAD_CH32); /* BUF LOAD */
WAIT_EOP();
CLEAR_EOP();
CLEAR_CR(FLASH_CR_FTPG_CH32);
MAGIC(dest + offset);
MAGIC((dest+offset));
return 0;
}
/**
@ -271,7 +282,7 @@ static int ch32f1_upload(target *t, uint32_t dest, const void *src, uint32_t off
*/
int ch32f1_buffer_clear(target *t)
{
volatile uint32_t sr;
volatile uint32_t ct,sr;
SET_CR(FLASH_CR_FTPG_CH32); // Fast page program 4-
SET_CR(FLASH_CR_BUF_RESET_CH32); // BUF_RESET 5-
WAIT_BUSY(); // 6-
@ -286,19 +297,19 @@ int ch32f1_buffer_clear(target *t)
static int ch32f1_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len)
{
volatile uint32_t sr, magic;
volatile uint32_t ct, sr, magic;
target *t = f->t;
size_t length = len;
#ifdef CH32_VERIFY
target_addr org_dest = dest;
const void *org_src = src;
target_addr orgDest=dest;
const void *orgSrc=src;
#endif
DEBUG_INFO("CH32: flash write 0x%" PRIx32 " ,size=%zu\n", dest, len);
DEBUG_CH("CH32: flash write 0x%x ,size=%d\n",dest,len);
while (length > 0)
while(length > 0)
{
if (ch32f1_flash_unlock(t)) {
DEBUG_WARN("ch32f1 cannot fast unlock\n");
if(ch32f1_flash_unlock(t)) {
ERROR_CH("ch32f1 cannot fast unlock\n");
return -1;
}
WAIT_BUSY();
@ -306,12 +317,12 @@ static int ch32f1_flash_write(struct target_flash *f,
// Buffer reset...
ch32f1_buffer_clear(t);
// Load 128 bytes to buffer
if (!ch32f1_wait_flash_ready(t,dest))
if(!ch32f1_wait_flash_ready(t,dest)) {
return -1;
for (size_t i = 0; i < 8; i++) {
if (ch32f1_upload(t, dest, src, i * 16U)) {
DEBUG_WARN("Cannot upload to buffer\n");
}
for(int i = 0; i < 8; i++) {
if(ch32f1_upload(t,dest,src, 16*i)) {
ERROR_CH("Cannot upload to buffer\n");
return -1;
}
}
@ -323,10 +334,10 @@ static int ch32f1_flash_write(struct target_flash *f,
CLEAR_EOP();
CLEAR_CR(FLASH_CR_FTPG_CH32);
MAGIC(dest);
MAGIC((dest));
// next
if (length > 128)
if(length > 128)
length -=128;
else
length = 0;
@ -335,23 +346,24 @@ static int ch32f1_flash_write(struct target_flash *f,
sr = target_mem_read32(t, FLASH_SR); // 13
ch32f1_flash_lock(t);
if (sr & SR_ERROR_MASK) {
DEBUG_WARN("ch32f1 flash write error 0x%" PRIx32 "\n", sr);
if ((sr & SR_ERROR_MASK) ) {
ERROR_CH("ch32f1 flash write error 0x%" PRIx32 "\n", sr);
return -1;
}
}
}
#ifdef CH32_VERIFY
DEBUG_INFO("Verifying\n");
for (size_t i = 0; i < len; i += 4)
DEBUG_CH("Verifying\n");
size_t i = 0;
for(i = 0; i < len; i+= 4)
{
const uint32_t expected = *(uint32_t *)(org_src + i);
const uint32_t actual = target_mem_read32(t, org_dest + i);
if (expected != actual)
uint32_t mem=target_mem_read32(t, orgDest+i);
uint32_t mem2=*(uint32_t *)(orgSrc+i);
if(mem!=mem2)
{
DEBUG_WARN(">>>>write mistmatch at address 0x%x\n", org_dest + i);
DEBUG_WARN(">>>>expected: 0x%x\n", expected);
DEBUG_WARN(">>>> actual: 0x%x\n", actual);
ERROR_CH(">>>>write mistmatch at address 0x%x\n",orgDest+i);
ERROR_CH(">>>>expected 0x%x\n",mem2);
ERROR_CH(">>>>flash 0x%x\n",mem);
return -1;
}
}
@ -359,3 +371,4 @@ static int ch32f1_flash_write(struct target_flash *f,
return 0;
}
// EOF

View File

@ -378,25 +378,8 @@ bool cortexm_probe(ADIv5_AP_t *ap)
} else {
target_check_error(t);
}
#if PC_HOSTED
#define STRINGIFY(x) #x
#define PROBE(x) \
do { \
DEBUG_INFO("Calling " STRINGIFY(x) "\n"); \
if ((x)(t)) \
return true; \
else \
target_check_error(t); \
} while (0)
#else
#define PROBE(x) \
do { \
if ((x)(t)) \
return true; \
else \
target_check_error(t); \
} while (0)
#endif
do { if ((x)(t)) {return true;} else target_check_error(t); } while (0)
switch (ap->ap_designer) {
case AP_DESIGNER_FREESCALE:
@ -519,7 +502,7 @@ bool cortexm_attach(target *t)
priv->flash_patch_revision = (r >> 28);
priv->hw_watchpoint_max = CORTEXM_MAX_WATCHPOINTS;
r = target_mem_read32(t, CORTEXM_DWT_CTRL);
if ((r >> 28) < priv->hw_watchpoint_max)
if ((r >> 28) > priv->hw_watchpoint_max)
priv->hw_watchpoint_max = r >> 28;
/* Clear any stale breakpoints */
@ -692,7 +675,7 @@ static int dcrsr_regnum(target *t, unsigned reg)
return regnum_cortex_m[reg];
} else if ((t->target_options & TOPT_FLAVOUR_V7MF) &&
(reg < (sizeof(regnum_cortex_m) +
sizeof(regnum_cortex_mf)) / 4)) {
sizeof(regnum_cortex_mf) / 4))) {
return regnum_cortex_mf[reg - sizeof(regnum_cortex_m)/4];
} else {
return -1;

View File

@ -37,91 +37,72 @@
#include "general.h"
#include "target.h"
#include "target_internal.h"
#include "adiv5.h"
#define KINETIS_MDM_IDR_K22F 0x1c0000
#define KINETIS_MDM_IDR_KZ03 0x1c0020
#define MDM_STATUS ADIV5_AP_REG(0x00)
#define MDM_CONTROL ADIV5_AP_REG(0x04)
#define MDM_STATUS_MASS_ERASE_ACK (1 << 0)
#define MDM_STATUS_FLASH_READY (1 << 1)
#define MDM_STATUS_MASS_ERASE_ENABLED (1 << 5)
#define MDM_STATUS_BACK_KEY_ENABLED (1 << 6)
#define MDM_CONTROL_MASS_ERASE (1 << 0)
#define MDM_CONTROL_SYS_RESET (1 << 3)
#define SIM_SDID 0x40048024
#define SIM_FCFG1 0x4004804C
#define FLASH_SECURITY_BYTE_ADDRESS 0x40C
#define FLASH_SECURITY_BYTE_UNSECURED 0xFE
#define FTFA_BASE 0x40020000
#define FTFA_FSTAT (FTFA_BASE + 0x00)
#define FTFA_FCNFG (FTFA_BASE + 0x01)
#define FTFA_FSEC (FTFA_BASE + 0x02)
#define FTFA_FOPT (FTFA_BASE + 0x03)
#define FTFA_FCCOB_0 (FTFA_BASE + 0x04)
#define FTFA_FCCOB_1 (FTFA_BASE + 0x08)
#define FTFA_FCCOB_2 (FTFA_BASE + 0x0C)
#define FTFx_BASE 0x40020000
#define FTFx_FSTAT (FTFx_BASE + 0x00)
#define FTFx_FCNFG (FTFx_BASE + 0x01)
#define FTFx_FSEC (FTFx_BASE + 0x02)
#define FTFx_FOPT (FTFx_BASE + 0x03)
#define FTFx_FCCOB0 (FTFx_BASE + 0x04)
#define FTFx_FCCOB4 (FTFx_BASE + 0x08)
#define FTFx_FCCOB8 (FTFx_BASE + 0x0C)
#define FTFA_FSTAT_CCIF (1 << 7)
#define FTFA_FSTAT_RDCOLERR (1 << 6)
#define FTFA_FSTAT_ACCERR (1 << 5)
#define FTFA_FSTAT_FPVIOL (1 << 4)
#define FTFA_FSTAT_MGSTAT0 (1 << 0)
#define FTFx_FSTAT_CCIF (1 << 7)
#define FTFx_FSTAT_RDCOLERR (1 << 6)
#define FTFx_FSTAT_ACCERR (1 << 5)
#define FTFx_FSTAT_FPVIOL (1 << 4)
#define FTFx_FSTAT_MGSTAT0 (1 << 0)
#define FTFx_FSEC_KEYEN_MSK (0b11 << 6)
#define FTFx_FSEC_KEYEN (0b10 << 6)
#define FTFx_CMD_CHECK_ERASE 0x01
#define FTFx_CMD_PROGRAM_CHECK 0x02
#define FTFx_CMD_READ_RESOURCE 0x03
#define FTFx_CMD_PROGRAM_LONGWORD 0x06
#define FTFA_CMD_CHECK_ERASE 0x01
#define FTFA_CMD_PROGRAM_CHECK 0x02
#define FTFA_CMD_READ_RESOURCE 0x03
#define FTFA_CMD_PROGRAM_LONGWORD 0x06
/* Part of the FTFE module for K64 */
#define FTFx_CMD_PROGRAM_PHRASE 0x07
#define FTFx_CMD_ERASE_SECTOR 0x09
#define FTFx_CMD_CHECK_ERASE_ALL 0x40
#define FTFx_CMD_READ_ONCE 0x41
#define FTFx_CMD_PROGRAM_ONCE 0x43
#define FTFx_CMD_ERASE_ALL 0x44
#define FTFx_CMD_BACKDOOR_ACCESS 0x45
#define FTFE_CMD_PROGRAM_PHRASE 0x07
#define FTFA_CMD_ERASE_SECTOR 0x09
#define FTFA_CMD_CHECK_ERASE_ALL 0x40
#define FTFA_CMD_READ_ONCE 0x41
#define FTFA_CMD_PROGRAM_ONCE 0x43
#define FTFA_CMD_ERASE_ALL 0x44
#define FTFA_CMD_BACKDOOR_ACCESS 0x45
#define KL_WRITE_LEN 4
/* 8 byte phrases need to be written to the k64 flash */
#define K64_WRITE_LEN 8
static bool kinetis_cmd_unsafe(target *t, int argc, char **argv);
static bool kinetis_cmd_unsafe(target *t, int argc, char *argv[]);
const struct command_s kinetis_cmd_list[] = {
{"unsafe", (cmd_handler)kinetis_cmd_unsafe, "Allow programming security byte (enable|disable)"},
{NULL, NULL, NULL},
{NULL, NULL, NULL}
};
static bool kinetis_cmd_unsafe(target *t, int argc, char **argv)
static bool kinetis_cmd_unsafe(target *t, int argc, char *argv[])
{
if (argc == 1) {
tc_printf(t, "Allow programming security byte: %s\n", t->unsafe_enabled ? "enabled" : "disabled");
tc_printf(t, "Allow programming security byte: %s\n",
t->unsafe_enabled ? "enabled" : "disabled");
} else {
parse_enable_or_disable(argv[1], &t->unsafe_enabled);
}
return true;
}
static int kinetis_flash_cmd_erase(struct target_flash *f, target_addr addr, size_t len);
static int kinetis_flash_cmd_write(struct target_flash *f, target_addr dest, const void *src, size_t len);
static int kinetis_flash_done(struct target_flash *f);
static int kl_gen_flash_erase(struct target_flash *f, target_addr addr, size_t len);
static int kl_gen_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);
static int kl_gen_flash_done(struct target_flash *f);
struct kinetis_flash {
struct target_flash f;
uint8_t write_len;
};
static void kinetis_add_flash(
target *const t, const uint32_t addr, const size_t length, const size_t erasesize, const size_t write_len)
static void kl_gen_add_flash(target *t, uint32_t addr, size_t length,
size_t erasesize, size_t write_len)
{
struct kinetis_flash *kf = calloc(1, sizeof(*kf));
struct target_flash *f;
@ -135,26 +116,15 @@ static void kinetis_add_flash(
f->start = addr;
f->length = length;
f->blocksize = erasesize;
f->erase = kinetis_flash_cmd_erase;
f->write = kinetis_flash_cmd_write;
f->done = kinetis_flash_done;
f->erase = kl_gen_flash_erase;
f->write = kl_gen_flash_write;
f->done = kl_gen_flash_done;
f->erased = 0xff;
kf->write_len = write_len;
target_add_flash(t, f);
}
static void kl_s32k14_setup(
target *const t, const uint32_t sram_l, const uint32_t sram_h, const size_t flash_size, const size_t flexmem_size)
{
t->driver = "S32K14x";
target_add_ram(t, sram_l, 0x20000000 - sram_l);
target_add_ram(t, 0x20000000, sram_h);
kinetis_add_flash(t, 0x00000000, flash_size, 0x1000, K64_WRITE_LEN); /* P-Flash, 4 KB Sectors */
kinetis_add_flash(t, 0x10000000, flexmem_size, 0x1000, K64_WRITE_LEN); /* FlexNVM, 4 KB Sectors */
}
bool kinetis_probe(target *const t)
bool kinetis_probe(target *t)
{
uint32_t sdid = target_mem_read32(t, SIM_SDID);
uint32_t fcfg1 = target_mem_read32(t, SIM_FCFG1);
@ -162,20 +132,20 @@ bool kinetis_probe(target *const t)
switch (sdid >> 20) {
case 0x161:
/* sram memory size */
switch ((sdid >> 16) & 0x0f) {
case 0x03: /* 4 KB */
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 */
case 0x04:/* 8 KB */
target_add_ram(t, 0x1ffff800, 0x0800);
target_add_ram(t, 0x20000000, 0x1800);
break;
case 0x05: /* 16 KB */
case 0x05:/* 16 KB */
target_add_ram(t, 0x1ffff000, 0x1000);
target_add_ram(t, 0x20000000, 0x3000);
break;
case 0x06: /* 32 KB */
case 0x06:/* 32 KB */
target_add_ram(t, 0x1fffe000, 0x2000);
target_add_ram(t, 0x20000000, 0x6000);
break;
@ -185,25 +155,25 @@ bool kinetis_probe(target *const t)
}
/* flash memory size */
switch ((fcfg1 >> 24) & 0x0f) {
switch((fcfg1 >> 24) & 0x0f) {
case 0x03: /* 32 KB */
t->driver = "KL16Z32Vxxx";
kinetis_add_flash(t, 0x00000000, 0x08000, 0x400, KL_WRITE_LEN);
kl_gen_add_flash(t, 0x00000000, 0x08000, 0x400, KL_WRITE_LEN);
break;
case 0x05: /* 64 KB */
t->driver = "KL16Z64Vxxx";
kinetis_add_flash(t, 0x00000000, 0x10000, 0x400, KL_WRITE_LEN);
kl_gen_add_flash(t, 0x00000000, 0x10000, 0x400, KL_WRITE_LEN);
break;
case 0x07: /* 128 KB */
t->driver = "KL16Z128Vxxx";
kinetis_add_flash(t, 0x00000000, 0x20000, 0x400, KL_WRITE_LEN);
kl_gen_add_flash(t, 0x00000000, 0x20000, 0x400, KL_WRITE_LEN);
break;
case 0x09: /* 256 KB */
t->driver = "KL16Z256Vxxx";
kinetis_add_flash(t, 0x00000000, 0x40000, 0x400, KL_WRITE_LEN);
kl_gen_add_flash(t, 0x00000000, 0x40000, 0x400, KL_WRITE_LEN);
break;
default:
return false;
@ -216,51 +186,51 @@ bool kinetis_probe(target *const t)
t->driver = "KL25";
target_add_ram(t, 0x1ffff000, 0x1000);
target_add_ram(t, 0x20000000, 0x3000);
kinetis_add_flash(t, 0x00000000, 0x20000, 0x400, KL_WRITE_LEN);
kl_gen_add_flash(t, 0x00000000, 0x20000, 0x400, KL_WRITE_LEN);
break;
case 0x231:
t->driver = "KL27x128"; // MKL27 >=128kb
target_add_ram(t, 0x1fffe000, 0x2000);
target_add_ram(t, 0x20000000, 0x6000);
kinetis_add_flash(t, 0x00000000, 0x40000, 0x400, KL_WRITE_LEN);
kl_gen_add_flash(t, 0x00000000, 0x40000, 0x400, KL_WRITE_LEN);
break;
case 0x271:
switch ((sdid >> 16) & 0x0f) {
switch((sdid >> 16) & 0x0f) {
case 4:
t->driver = "KL27x32";
target_add_ram(t, 0x1ffff800, 0x0800);
target_add_ram(t, 0x20000000, 0x1800);
kinetis_add_flash(t, 0x00000000, 0x8000, 0x400, KL_WRITE_LEN);
kl_gen_add_flash(t, 0x00000000, 0x8000, 0x400, KL_WRITE_LEN);
break;
case 5:
t->driver = "KL27x64";
target_add_ram(t, 0x1ffff000, 0x1000);
target_add_ram(t, 0x20000000, 0x3000);
kinetis_add_flash(t, 0x00000000, 0x10000, 0x400, KL_WRITE_LEN);
kl_gen_add_flash(t, 0x00000000, 0x10000, 0x400, KL_WRITE_LEN);
break;
default:
return false;
}
break;
case 0x021: /* KL02 family */
switch ((sdid >> 16) & 0x0f) {
switch((sdid >> 16) & 0x0f) {
case 3:
t->driver = "KL02x32";
target_add_ram(t, 0x1FFFFC00, 0x400);
target_add_ram(t, 0x20000000, 0xc00);
kinetis_add_flash(t, 0x00000000, 0x7FFF, 0x400, KL_WRITE_LEN);
kl_gen_add_flash(t, 0x00000000, 0x7FFF, 0x400, KL_WRITE_LEN);
break;
case 2:
t->driver = "KL02x16";
target_add_ram(t, 0x1FFFFE00, 0x200);
target_add_ram(t, 0x20000000, 0x600);
kinetis_add_flash(t, 0x00000000, 0x3FFF, 0x400, KL_WRITE_LEN);
kl_gen_add_flash(t, 0x00000000, 0x3FFF, 0x400, KL_WRITE_LEN);
break;
case 1:
t->driver = "KL02x8";
target_add_ram(t, 0x1FFFFF00, 0x100);
target_add_ram(t, 0x20000000, 0x300);
kinetis_add_flash(t, 0x00000000, 0x1FFF, 0x400, KL_WRITE_LEN);
kl_gen_add_flash(t, 0x00000000, 0x1FFF, 0x400, KL_WRITE_LEN);
break;
default:
return false;
@ -270,14 +240,14 @@ bool kinetis_probe(target *const t)
t->driver = "KL03";
target_add_ram(t, 0x1ffffe00, 0x200);
target_add_ram(t, 0x20000000, 0x600);
kinetis_add_flash(t, 0, 0x8000, 0x400, KL_WRITE_LEN);
kl_gen_add_flash(t, 0, 0x8000, 0x400, KL_WRITE_LEN);
break;
case 0x220: /* K22F family */
t->driver = "K22F";
target_add_ram(t, 0x1c000000, 0x4000000);
target_add_ram(t, 0x20000000, 0x100000);
kinetis_add_flash(t, 0, 0x40000, 0x800, KL_WRITE_LEN);
kinetis_add_flash(t, 0x40000, 0x40000, 0x800, KL_WRITE_LEN);
kl_gen_add_flash(t, 0, 0x40000, 0x800, KL_WRITE_LEN);
kl_gen_add_flash(t, 0x40000, 0x40000, 0x800, KL_WRITE_LEN);
break;
case 0x620: /* K64F family. */
/* This should be 0x640, but according to the errata sheet
@ -287,11 +257,11 @@ bool kinetis_probe(target *const t)
t->driver = "K64";
target_add_ram(t, 0x1FFF0000, 0x10000);
target_add_ram(t, 0x20000000, 0x30000);
kinetis_add_flash(t, 0, 0x80000, 0x1000, K64_WRITE_LEN);
kinetis_add_flash(t, 0x80000, 0x80000, 0x1000, K64_WRITE_LEN);
kl_gen_add_flash(t, 0, 0x80000, 0x1000, K64_WRITE_LEN);
kl_gen_add_flash(t, 0x80000, 0x80000, 0x1000, K64_WRITE_LEN);
break;
case 0x000: /* Older K-series */
switch (sdid & 0xff0) {
switch(sdid & 0xff0) {
case 0x000: /* K10 Family, DIEID=0x0 */
case 0x080: /* K10 Family, DIEID=0x1 */
case 0x100: /* K10 Family, DIEID=0x2 */
@ -299,28 +269,28 @@ bool kinetis_probe(target *const t)
case 0x220: /* K11 Family, DIEID=0x4 */
return false;
case 0x200: /* K12 Family, DIEID=0x4 */
switch ((fcfg1 >> 24) & 0x0f) {
switch((fcfg1 >> 24) & 0x0f) {
/* K12 Sub-Family Reference Manual, K12P80M50SF4RM, Rev. 4, February 2013 */
case 0x7:
t->driver = "MK12DX128Vxx5";
target_add_ram(t, 0x1fffc000, 0x00004000); /* SRAM_L, 16 KB */
target_add_ram(t, 0x20000000, 0x00004000); /* SRAM_H, 16 KB */
kinetis_add_flash(t, 0x00000000, 0x00020000, 0x800, KL_WRITE_LEN); /* P-Flash, 128 KB, 2 KB Sectors */
kinetis_add_flash(t, 0x10000000, 0x00010000, 0x800, KL_WRITE_LEN); /* FlexNVM, 64 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x00000000, 0x00020000, 0x800, KL_WRITE_LEN); /* P-Flash, 128 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x10000000, 0x00010000, 0x800, KL_WRITE_LEN); /* FlexNVM, 64 KB, 2 KB Sectors */
break;
case 0x9:
t->driver = "MK12DX256Vxx5";
target_add_ram(t, 0x1fffc000, 0x00004000); /* SRAM_L, 16 KB */
target_add_ram(t, 0x20000000, 0x00004000); /* SRAM_H, 16 KB */
kinetis_add_flash(t, 0x00000000, 0x00040000, 0x800, KL_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kinetis_add_flash(t, 0x10000000, 0x00010000, 0x800, KL_WRITE_LEN); /* FlexNVM, 64 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x00000000, 0x00040000, 0x800, KL_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x10000000, 0x00010000, 0x800, KL_WRITE_LEN); /* FlexNVM, 64 KB, 2 KB Sectors */
break;
case 0xb:
t->driver = "MK12DN512Vxx5";
target_add_ram(t, 0x1fff8000, 0x00008000); /* SRAM_L, 32 KB */
target_add_ram(t, 0x20000000, 0x00008000); /* SRAM_H, 32 KB */
kinetis_add_flash(t, 0x00000000, 0x00040000, 0x800, KL_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kinetis_add_flash(t, 0x00040000, 0x00040000, 0x800, KL_WRITE_LEN); /* FlexNVM, 256 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x00000000, 0x00040000, 0x800, KL_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x00040000, 0x00040000, 0x800, KL_WRITE_LEN); /* FlexNVM, 256 KB, 2 KB Sectors */
break;
default:
return false;
@ -352,40 +322,48 @@ bool kinetis_probe(target *const t)
t->driver = "S32K118";
target_add_ram(t, 0x1ffffc00, 0x00000400); /* SRAM_L, 1 KB */
target_add_ram(t, 0x20000000, 0x00005800); /* SRAM_H, 22 KB */
kinetis_add_flash(t, 0x00000000, 0x00040000, 0x800, K64_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kinetis_add_flash(t, 0x10000000, 0x00008000, 0x800, K64_WRITE_LEN); /* FlexNVM, 32 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x00000000, 0x00040000, 0x800, K64_WRITE_LEN); /* P-Flash, 256 KB, 2 KB Sectors */
kl_gen_add_flash(t, 0x10000000, 0x00008000, 0x800, K64_WRITE_LEN); /* FlexNVM, 32 KB, 2 KB Sectors */
break;
/* gen1 s32k14x */
case 0x142: /* S32K142 */
case 0x143: /* S32K142W */
/* SRAM_L = 16KiB */
/* SRAM_H = 12KiB */
/* Flash = 256 KiB */
/* FlexNVM = 64 KiB */
kl_s32k14_setup(t, 0x1FFFC000, 0x03000, 0x00040000, 0x10000);
break;
case 0x144: /* S32K144 */
case 0x145: /* S32K144W */
/* SRAM_L = 32KiB */
/* SRAM_H = 28KiB */
/* Flash = 512 KiB */
/* FlexNVM = 64 KiB */
kl_s32k14_setup(t, 0x1FFF8000, 0x07000, 0x00080000, 0x10000);
break;
case 0x146: /* S32K146 */
/* SRAM_L = 64KiB */
/* SRAM_H = 60KiB */
/* Flash = 1024 KiB */
/* FlexNVM = 64 KiB */
kl_s32k14_setup(t, 0x1fff0000, 0x0f000, 0x00100000, 0x10000);
break;
{
uint32_t sram_l, sram_h;
uint32_t flash, flexmem;
case 0x142: /* s32k142 */
case 0x143: /* s32k142w */
sram_l = 0x1FFFC000; /* SRAM_L, 16k */
sram_h = 0x03000; /* SRAM_H, 12k */
flash = 0x00040000; /* flash 256 KB */
flexmem = 0x10000; /* FlexNVM 64 KB */
goto do_common_s32k14x;
case 0x144: /* s32k144 */
case 0x145: /* s32k144w */
sram_l = 0x1FFF8000; /* SRAM_L, 32k */
sram_h = 0x07000; /* SRAM_H, 28k */
flash = 0x00080000; /* flash 512 KB */
flexmem = 0x10000; /* FlexNVM 64 KB */
goto do_common_s32k14x;
case 0x146: /* s32k146 */
sram_l = 0x1fff0000; /* SRAM_L, 64k */
sram_h = 0x0f000; /* SRAM_H, 60k */
flash = 0x00100000; /* flash 1024 KB */
flexmem = 0x10000; /* FlexNVM 64 KB */
goto do_common_s32k14x;
case 0x148: /* S32K148 */
/* SRAM_L = 128 KiB */
/* SRAM_H = 124 KiB */
/* Flash = 1536 KiB */
/* FlexNVM = 512 KiB */
kl_s32k14_setup(t, 0x1ffe0000, 0x1f000, 0x00180000, 0x80000);
sram_l = 0x1ffe0000; /* SRAM_L, 128 KB */
sram_h = 0x1f000; /* SRAM_H, 124 KB */
flash = 0x00180000; /* flash 1536 KB */
flexmem = 0x80000; /* FlexNVM 512 KB */
goto do_common_s32k14x;
do_common_s32k14x:
t->driver = "S32K14x";
target_add_ram(t, sram_l, 0x20000000 - sram_l);
target_add_ram(t, 0x20000000, sram_h);
kl_gen_add_flash(t, 0x00000000, flash, 0x1000, K64_WRITE_LEN); /* P-Flash, 4 KB Sectors */
kl_gen_add_flash(t, 0x10000000, flexmem, 0x1000, K64_WRITE_LEN); /* FlexNVM, 4 KB Sectors */
break;
}
default:
return false;
}
@ -394,48 +372,47 @@ bool kinetis_probe(target *const t)
return true;
}
static bool kinetis_fccob_cmd(target *t, uint8_t cmd, uint32_t addr, const uint32_t *data, int n_items)
static bool
kl_gen_command(target *t, uint8_t cmd, uint32_t addr, const uint32_t *data, int n_items)
{
uint8_t fstat;
/* clear errors unconditionally, so we can start a new operation */
target_mem_write8(t, FTFx_FSTAT, (FTFx_FSTAT_ACCERR | FTFx_FSTAT_FPVIOL));
target_mem_write8(t,FTFA_FSTAT,(FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL));
/* Wait for CCIF to be high */
do {
fstat = target_mem_read8(t, FTFx_FSTAT);
} while (!(fstat & FTFx_FSTAT_CCIF));
fstat = target_mem_read8(t, FTFA_FSTAT);
} while (!(fstat & FTFA_FSTAT_CCIF));
/* Write command to FCCOB */
addr &= 0x00ffffffU;
addr |= cmd << 24U;
target_mem_write32(t, FTFx_FCCOB0, addr);
if (data && n_items) {
target_mem_write32(t, FTFx_FCCOB4, data[0]);
addr &= 0xffffff;
addr |= (uint32_t)cmd << 24;
target_mem_write32(t, FTFA_FCCOB_0, addr);
if (data) {
target_mem_write32(t, FTFA_FCCOB_1, data[0]);
if (n_items > 1)
target_mem_write32(t, FTFx_FCCOB8, data[1]);
else
target_mem_write32(t, FTFx_FCCOB8, 0);
target_mem_write32(t, FTFA_FCCOB_2, data[1]);
}
/* Enable execution by clearing CCIF */
target_mem_write8(t, FTFx_FSTAT, FTFx_FSTAT_CCIF);
target_mem_write8(t, FTFA_FSTAT, FTFA_FSTAT_CCIF);
/* Wait for execution to complete */
do {
fstat = target_mem_read8(t, FTFx_FSTAT);
fstat = target_mem_read8(t, FTFA_FSTAT);
/* Check ACCERR and FPVIOL are zero in FSTAT */
if (fstat & (FTFx_FSTAT_ACCERR | FTFx_FSTAT_FPVIOL))
if (fstat & (FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL))
return false;
} while (!(fstat & FTFx_FSTAT_CCIF));
} while (!(fstat & FTFA_FSTAT_CCIF));
return true;
}
static int kinetis_flash_cmd_erase(struct target_flash *const f, target_addr addr, size_t len)
static int kl_gen_flash_erase(struct target_flash *f, target_addr addr, size_t len)
{
while (len) {
if (kinetis_fccob_cmd(f->t, FTFx_CMD_ERASE_SECTOR, addr, NULL, 0)) {
if (kl_gen_command(f->t, FTFA_CMD_ERASE_SECTOR, addr, NULL, 0)) {
/* Different targets have different flash erase sizes */
if (len > f->blocksize)
len -= f->blocksize;
@ -449,60 +426,72 @@ static int kinetis_flash_cmd_erase(struct target_flash *const f, target_addr add
return 0;
}
static int kinetis_flash_cmd_write(struct target_flash *f, target_addr dest, const void *src, size_t len)
#define FLASH_SECURITY_BYTE_ADDRESS 0x40C
#define FLASH_SECURITY_BYTE_UNSECURED 0xFE
static int kl_gen_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len)
{
struct kinetis_flash *const kf = (struct kinetis_flash *)f;
struct kinetis_flash *kf = (struct kinetis_flash *)f;
/* Ensure we don't write something horrible over the security byte */
if (!f->t->unsafe_enabled && dest <= FLASH_SECURITY_BYTE_ADDRESS && dest + len > FLASH_SECURITY_BYTE_ADDRESS) {
((uint8_t *)src)[FLASH_SECURITY_BYTE_ADDRESS - dest] = FLASH_SECURITY_BYTE_UNSECURED;
if (!f->t->unsafe_enabled &&
(dest <= FLASH_SECURITY_BYTE_ADDRESS) &&
((dest + len) > FLASH_SECURITY_BYTE_ADDRESS)) {
((uint8_t*)src)[FLASH_SECURITY_BYTE_ADDRESS - dest] =
FLASH_SECURITY_BYTE_UNSECURED;
}
/* Determine write command based on the alignment. */
uint8_t write_cmd;
if (kf->write_len == K64_WRITE_LEN)
write_cmd = FTFx_CMD_PROGRAM_PHRASE;
else
write_cmd = FTFx_CMD_PROGRAM_LONGWORD;
if (kf->write_len == K64_WRITE_LEN) {
write_cmd = FTFE_CMD_PROGRAM_PHRASE;
} else {
write_cmd = FTFA_CMD_PROGRAM_LONGWORD;
}
while (len) {
if (kinetis_fccob_cmd(f->t, write_cmd, dest, src, kf->write_len >> 2U)) {
if (kl_gen_command(f->t, write_cmd, dest, src, 1)) {
if (len > kf->write_len)
len -= kf->write_len;
else
len = 0;
dest += kf->write_len;
src += kf->write_len;
} else
} else {
return 1;
}
}
return 0;
}
static int kinetis_flash_done(struct target_flash *const f)
static int kl_gen_flash_done(struct target_flash *f)
{
struct kinetis_flash *const kf = (struct kinetis_flash *)f;
struct kinetis_flash *kf = (struct kinetis_flash *)f;
if (f->t->unsafe_enabled)
return 0;
if (target_mem_read8(f->t, FLASH_SECURITY_BYTE_ADDRESS) == FLASH_SECURITY_BYTE_UNSECURED)
if (target_mem_read8(f->t, FLASH_SECURITY_BYTE_ADDRESS) ==
FLASH_SECURITY_BYTE_UNSECURED)
return 0;
/* Load the security byte based on the alignment (determine 8 byte phrases
* vs 4 byte phrases).
*/
if (kf->write_len == K64_WRITE_LEN) {
uint32_t vals[2] = {
target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS - 4),
target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS)
};
vals[1] = (vals[1] & 0xffffff00U) | FLASH_SECURITY_BYTE_UNSECURED;
kinetis_fccob_cmd(f->t, FTFx_CMD_PROGRAM_PHRASE, FLASH_SECURITY_BYTE_ADDRESS - 4, vals, 2);
if (kf->write_len == 8) {
uint32_t vals[2];
vals[0] = target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS-4);
vals[1] = target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS);
vals[1] = (vals[1] & 0xffffff00) | FLASH_SECURITY_BYTE_UNSECURED;
kl_gen_command(f->t, FTFE_CMD_PROGRAM_PHRASE,
FLASH_SECURITY_BYTE_ADDRESS - 4, vals, 2);
} else {
uint32_t val = target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS);
val = (val & 0xffffff00U) | FLASH_SECURITY_BYTE_UNSECURED;
kinetis_fccob_cmd(f->t, FTFx_CMD_PROGRAM_LONGWORD, FLASH_SECURITY_BYTE_ADDRESS, &val, 1);
uint32_t vals[1];
vals[0] = target_mem_read32(f->t, FLASH_SECURITY_BYTE_ADDRESS);
vals[0] = (vals[0] & 0xffffff00) | FLASH_SECURITY_BYTE_UNSECURED;
kl_gen_command(f->t, FTFA_CMD_PROGRAM_LONGWORD,
FLASH_SECURITY_BYTE_ADDRESS, vals, 1);
}
return 0;
@ -515,6 +504,10 @@ static int kinetis_flash_done(struct target_flash *const f)
* a backdoor AP is provided which may allow a mass erase to recover the
* device. This provides a fake target to allow a monitor command interface
*/
#include "adiv5.h"
#define KINETIS_MDM_IDR_K22F 0x1c0000
#define KINETIS_MDM_IDR_KZ03 0x1c0020
static bool kinetis_mdm_cmd_erase_mass(target *t, int argc, const char **argv);
static bool kinetis_mdm_cmd_ke04_mode(target *t, int argc, const char **argv);
@ -522,19 +515,18 @@ static bool kinetis_mdm_cmd_ke04_mode(target *t, int argc, const char **argv);
const struct command_s kinetis_mdm_cmd_list[] = {
{"erase_mass", (cmd_handler)kinetis_mdm_cmd_erase_mass, "Erase entire flash memory"},
{"ke04_mode", (cmd_handler)kinetis_mdm_cmd_ke04_mode, "Allow erase for KE04"},
{NULL, NULL, NULL},
{NULL, NULL, NULL}
};
enum target_halt_reason mdm_halt_poll(target *t, const target_addr *const watch)
enum target_halt_reason mdm_halt_poll(target *t, target_addr *watch)
{
(void)t;
(void)watch;
(void)t; (void)watch;
return TARGET_HALT_REQUEST;
}
void kinetis_mdm_probe(ADIv5_AP_t *ap)
{
switch (ap->idr) {
switch(ap->idr) {
case KINETIS_MDM_IDR_KZ03: /* Also valid for KE04, no way to check! */
case KINETIS_MDM_IDR_K22F:
break;
@ -549,13 +541,23 @@ void kinetis_mdm_probe(ADIv5_AP_t *ap)
adiv5_ap_ref(ap);
t->priv = ap;
t->priv_free = (void *)adiv5_ap_unref;
t->priv_free = (void*)adiv5_ap_unref;
t->driver = "Kinetis Recovery (MDM-AP)";
t->regs_size = 4;
target_add_commands(t, kinetis_mdm_cmd_list, t->driver);
}
#define MDM_STATUS ADIV5_AP_REG(0x00)
#define MDM_CONTROL ADIV5_AP_REG(0x04)
#define MDM_STATUS_MASS_ERASE_ACK (1 << 0)
#define MDM_STATUS_FLASH_READY (1 << 1)
#define MDM_STATUS_MASS_ERASE_ENABLED (1 << 5)
#define MDM_CONTROL_MASS_ERASE (1 << 0)
#define MDM_CONTROL_SYS_RESET (1 << 3)
/* This is needed as a separate command, as there's no way to *
* tell a KE04 from other kinetis in kinetis_mdm_probe() */
static bool kinetis_mdm_cmd_ke04_mode(target *t, int argc, const char **argv)
@ -567,7 +569,6 @@ static bool kinetis_mdm_cmd_ke04_mode(target *t, int argc, const char **argv)
tc_printf(t, "Mass erase for KE04 now allowed\n");
return true;
}
static bool kinetis_mdm_cmd_erase_mass(target *t, int argc, const char **argv)
{
(void)argc;
@ -575,12 +576,13 @@ static bool kinetis_mdm_cmd_erase_mass(target *t, int argc, const char **argv)
ADIv5_AP_t *ap = t->priv;
/* Keep the MCU in reset as stated in KL25PxxM48SF0RM */
if (t->ke04_mode)
if(t->ke04_mode)
adiv5_ap_write(ap, MDM_CONTROL, MDM_CONTROL_SYS_RESET);
uint32_t status = adiv5_ap_read(ap, MDM_STATUS);
uint32_t control = adiv5_ap_read(ap, MDM_CONTROL);
tc_printf(t, "Requesting mass erase (status = 0x%" PRIx32 ")\n", status);
uint32_t status, control;
status = adiv5_ap_read(ap, MDM_STATUS);
control = adiv5_ap_read(ap, MDM_CONTROL);
tc_printf(t, "Requesting mass erase (status = 0x%"PRIx32")\n", status);
/* This flag does not exist on KE04 */
if (!(status & MDM_STATUS_MASS_ERASE_ENABLED) && !t->ke04_mode) {

View File

@ -56,7 +56,7 @@ static int stm32f4_flash_erase(struct target_flash *f, target_addr addr,
static int stm32f4_flash_write(struct target_flash *f,
target_addr dest, const void *src, size_t len);
/* Flash Program and Erase Controller Register Map */
/* Flash Program ad Erase Controller Register Map */
#define FPEC_BASE 0x40023C00
#define FLASH_ACR (FPEC_BASE+0x00)
#define FLASH_KEYR (FPEC_BASE+0x04)
@ -503,8 +503,11 @@ static bool stm32f4_cmd_erase_mass(target *t, int argc, const char **argv)
tc_printf(t, "\n");
/* Check for error */
const uint32_t result = target_mem_read32(t, FLASH_SR);
return !(result & SR_ERROR_MASK);
uint32_t sr = target_mem_read32(t, FLASH_SR);
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP))
return false;
return true;
}
/* Dev | DOC |Rev|ID |OPTCR |OPTCR |OPTCR1 |OPTCR1 | OPTCR2

View File

@ -271,11 +271,6 @@ int target_flash_write(target *t,
dest += tmplen;
src += tmplen;
len -= tmplen;
/* If the current chunk of Flash is now full from this operation
* then finish operations on the Flash chunk and free the internal buffer.
*/
if (dest == f->start + f->length)
ret |= target_flash_done_buffered(f);
}
return ret;
}