Compare commits
199 Commits
Author | SHA1 | Date | |
---|---|---|---|
547abf0cf2 | |||
06b21b6d82 | |||
|
ad1868f8d4 | ||
|
c712a54cbc | ||
|
a51d90ba2d | ||
|
f67a4e421d | ||
|
8fc7a559b2 | ||
|
c9a0be19cb | ||
|
2ca08f8511 | ||
|
3ae3095499 | ||
|
2a792399ca | ||
|
576f575871 | ||
|
e43b07172b | ||
|
e0f1d29d41 | ||
|
2a00dd88ec | ||
|
c121da06c8 | ||
|
542c157955 | ||
|
d4dd288426 | ||
|
b096e95488 | ||
|
7bd7c3d0f5 | ||
|
82673b5e7b | ||
|
9542cd1cfb | ||
|
328be18288 | ||
|
03331b3fff | ||
|
ca1c0acb27 | ||
|
b4af0f5145 | ||
|
e174c5b503 | ||
|
c91322e38e | ||
|
85fc728293 | ||
|
6727e74daf | ||
|
d7bf91d039 | ||
|
878dc379b9 | ||
|
4f97627b02 | ||
|
56858650cb | ||
|
dcbb1657b4 | ||
|
9dc79becc2 | ||
|
9ec6693e4d | ||
|
a2f6776bf8 | ||
|
cb1ef7d616 | ||
|
def176b240 | ||
|
d5a8717bb0 | ||
|
8acda14170 | ||
|
c1e34792f4 | ||
|
c5b6f066b8 | ||
|
f109bc2e98 | ||
|
d36213b7d0 | ||
|
389bb03fc0 | ||
|
78837173a4 | ||
|
4328e8a4c1 | ||
|
646fbcb21f | ||
|
9da2d298c3 | ||
|
95a4ebf836 | ||
|
3024cc1bfe | ||
|
7340b0065d | ||
|
dd01fe9ad3 | ||
|
336797363b | ||
|
046cc359ba | ||
|
9e02c5f0cd | ||
|
c73329f7d4 | ||
|
d90c207c50 | ||
|
b87091a59b | ||
|
f8aff4bf4b | ||
|
50b9a4ceb6 | ||
|
93cf62d944 | ||
|
09e45cea5b | ||
|
65c95fb413 | ||
|
c643726c9d | ||
|
eda19bc28d | ||
|
9b145c8398 | ||
|
53c6821734 | ||
|
842a0b4193 | ||
|
8a37449f8a | ||
|
21989d4142 | ||
|
63449912e2 | ||
|
1661396951 | ||
|
fd6610bdae | ||
|
19e01abf70 | ||
|
a89b2ead47 | ||
|
81cfa0a380 | ||
|
41449370b4 | ||
|
73285885b3 | ||
|
b71213522a | ||
|
c0c5255103 | ||
|
a2cdb32f14 | ||
|
1930380e16 | ||
|
5509264a2b | ||
|
6f902bcfe7 | ||
|
fdce017311 | ||
|
96a980b682 | ||
|
cedcd1a832 | ||
|
1737788a92 | ||
|
f65793582d | ||
|
90a7ecaaf1 | ||
|
b6896898c2 | ||
|
81bb75bba6 | ||
|
6661871707 | ||
|
885fdcc354 | ||
|
16261813ca | ||
|
fcf5b74542 | ||
|
539fba02ac | ||
|
4a2a121e89 | ||
|
16b827e4e4 | ||
|
a9197e67ea | ||
|
ab63700a80 | ||
|
0993a8ae28 | ||
|
a7c4a0c108 | ||
|
bb97e35f82 | ||
|
cbed6c911f | ||
|
272b461b3e | ||
|
a29d53cb31 | ||
|
4947f0f747 | ||
|
a6f8944afe | ||
|
33c0319263 | ||
|
93cad1ca5a | ||
|
9a9fac2e83 | ||
|
a285b2ac17 | ||
|
4b4d0fcfcf | ||
|
6b2b1aa4c3 | ||
|
fce7dd2957 | ||
|
6b2f0aeb63 | ||
|
4cae565ef3 | ||
|
d76fd844c9 | ||
|
27a099a94b | ||
|
9c33ce7979 | ||
|
1612eacab2 | ||
|
f1f59d3c1d | ||
|
a42fc8904d | ||
|
f62c9db5af | ||
|
1ba83f3283 | ||
|
c33a447210 | ||
|
81fafae68d | ||
|
447bdc50a0 | ||
|
b91712214f | ||
|
5574a14aee | ||
|
a82ab6a45d | ||
|
40ea78d57b | ||
|
eab16ef39f | ||
|
da701aff6d | ||
|
aece87bf3e | ||
|
2931169dd1 | ||
|
95655b838e | ||
|
1846795844 | ||
|
76c2f5e39c | ||
|
51f2b79437 | ||
|
02eafe9883 | ||
|
05a42576c2 | ||
|
39949eefe2 | ||
|
d7afc92b5f | ||
|
44b5eed7ca | ||
|
4346fb2405 | ||
|
9c95dfb712 | ||
|
f99fe59ce8 | ||
|
5cd430647e | ||
|
fc55400aad | ||
|
d2370f780f | ||
|
f254e86511 | ||
|
3cc6aa1236 | ||
|
65ac074410 | ||
|
c6d1bcb352 | ||
|
eb9d9893f8 | ||
|
8db1d30852 | ||
|
1f22c72634 | ||
|
7322bb3ffa | ||
|
17ba28c44b | ||
|
47c84fac85 | ||
|
a6f9701368 | ||
|
237d6b89f6 | ||
|
2b89a07dae | ||
|
a01642e480 | ||
|
6b9b502354 | ||
|
8606b78b9e | ||
|
cd325dfe52 | ||
|
c1b3d0c629 | ||
|
94238fd95b | ||
|
5c835bc0f6 | ||
|
100fc2e7d4 | ||
|
880e977fb6 | ||
|
3a9b0eee7a | ||
|
6baf90ac4c | ||
|
77064754ad | ||
|
92ed79e68e | ||
|
b91a975d56 | ||
|
84b6818982 | ||
|
4aee9fe2a3 | ||
|
4847e0d1e6 | ||
|
a599b989cf | ||
|
50658a5c0a | ||
|
f828fc1ac1 | ||
|
bd71ca2a3c | ||
|
2d38c9614e | ||
|
7ce265f2cf | ||
|
638299534b | ||
|
919a005b65 | ||
|
58865ca5ec | ||
|
d62d82bb2f | ||
|
f1ecd66283 | ||
|
fd2cb4b8d2 | ||
|
1cc3e05c11 | ||
|
d5b6d4ab12 |
5
.gitignore
vendored
5
.gitignore
vendored
@ -16,7 +16,10 @@ tags
|
|||||||
*.b#*
|
*.b#*
|
||||||
blackmagic_upgrade
|
blackmagic_upgrade
|
||||||
*.exe
|
*.exe
|
||||||
|
.DS_Store
|
||||||
*.elf
|
*.elf
|
||||||
.vscode
|
.vscode
|
||||||
|
cscope.out
|
||||||
|
cscope.files
|
||||||
.gdb_history
|
.gdb_history
|
||||||
src/artifacts/
|
src/artifacts/
|
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -1,3 +1,3 @@
|
|||||||
[submodule "libopencm3"]
|
[submodule "libopencm3"]
|
||||||
path = libopencm3
|
path = libopencm3
|
||||||
url = https://github.com/libopencm3/libopencm3.git
|
url = https://github.com/flirc/libopencm3.git
|
||||||
|
12
Makefile
12
Makefile
@ -17,13 +17,23 @@ ifndef NO_LIBOPENCM3
|
|||||||
git submodule init ;\
|
git submodule init ;\
|
||||||
git submodule update ;\
|
git submodule update ;\
|
||||||
fi
|
fi
|
||||||
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib/stm32/f1 lib/stm32/f4 lib/lm4f
|
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib/sam/d
|
||||||
endif
|
endif
|
||||||
$(Q)$(MAKE) $(MFLAGS) -C src
|
$(Q)$(MAKE) $(MFLAGS) -C src
|
||||||
|
|
||||||
|
all_platforms:
|
||||||
|
$(Q)$(MAKE) $(MFLAGS) -C src $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
ifndef NO_LIBOPENCM3
|
ifndef NO_LIBOPENCM3
|
||||||
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 $@
|
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 $@
|
||||||
endif
|
endif
|
||||||
$(Q)$(MAKE) $(MFLAGS) -C src $@
|
$(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
153
README.md
@ -1,113 +1,54 @@
|
|||||||
Black Magic Probe
|
Jeff Probe
|
||||||
=================
|
|
||||||
|
|
||||||
[](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
|
|
||||||
==========
|
==========
|
||||||
|
|
||||||
You can also build blackmagic as a PC hosted application
|
This is a fork of the [original Black Magic Probe](https://github.com/blacksphere/blackmagic).
|
||||||
"make PROBE_HOST=hosted"
|
|
||||||
|
|
||||||
This builds the same GDB server, that is running on the Black Magic Probe.
|
The original is arguably better, faster and wider supported. However, this
|
||||||
While connection to the Black Magic Probe GDB server is via serial line,
|
project was a way to offer an affordable version and I'll rely on community
|
||||||
connection to the PC-Hosted GDB server is via TCP port 2000 for the first
|
support and pull requests.
|
||||||
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.
|
|
||||||
|
|
||||||
When connected to a single BMP supported probe, starting "blackmagic" w/o any
|
One urguably better funncton is the ability to do DEBUG and Serial communication
|
||||||
arguments starts the server. When several BMP supported probes are connected,
|
over a single JTAG cable when paired with a device that uses single wire JTAG.
|
||||||
their types, position and serial number is displayed and the program exits.
|
|
||||||
Add "-P (position)" to the next invocation to select one.
|
Normally, the serial header can be used on a target for the serial port, and
|
||||||
For the setup from the sample session above:
|
shows up as the second serial device on the system, however, we can dynamically
|
||||||
In another terminal:
|
change the pins to use the ones on the JTAG cable with the following command:
|
||||||
```console
|
|
||||||
> blackmagic
|
``` bash
|
||||||
Using 1d50:6018 E2E489E7 Black Sphere Technologies Black Magic Probe (STLINK), (Firmware v1.6.1-477-g70bb131-dirty)
|
$ mon convert_tdio enable
|
||||||
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
|
|
||||||
...
|
|
||||||
```
|
```
|
||||||
|
|
||||||
PC hosted BMP also allows to flash, read and verify a binary file, by default
|
Compilation
|
||||||
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.
|
||||||
|
271
UsingRTT.md
Normal file
271
UsingRTT.md
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
# 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)
|
@ -1,6 +1,7 @@
|
|||||||
# Black Magic Probe
|
# Black Magic Probe
|
||||||
# there are two connections, one for GDB and one for UART debugging
|
# there are two connections, one for GDB and one for UART debugging
|
||||||
# copy this to /etc/udev/rules.d/99-blackmagic.rules
|
# 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 GDB Server", SYMLINK+="ttyBmpGdb"
|
||||||
SUBSYSTEM=="tty", ACTION=="add", ATTRS{interface}=="Black Magic UART Port", SYMLINK+="ttyBmpTarg"
|
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"
|
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="1d50", ATTR{idProduct}=="6017", MODE="0666"
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 8435287300e5ca9af9f889c529e7b1fa019c42fb
|
Subproject commit 63573143ef7e1b037d1f0c5baedc5264e12562b8
|
BIN
schematic/bm-sam-a04.pdf
Normal file
BIN
schematic/bm-sam-a04.pdf
Normal file
Binary file not shown.
68
src/Makefile
68
src/Makefile
@ -9,7 +9,7 @@ Q := @
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
CFLAGS += -Wall -Wextra -Werror -Wno-char-subscripts \
|
CFLAGS += -Wall -Wextra -Werror -Wno-char-subscripts \
|
||||||
-std=gnu99 -g3 -MD -I./target \
|
-std=gnu99 -MD -I./target \
|
||||||
-I. -Iinclude -I$(PLATFORM_DIR)
|
-I. -Iinclude -I$(PLATFORM_DIR)
|
||||||
|
|
||||||
ifeq ($(ENABLE_DEBUG), 1)
|
ifeq ($(ENABLE_DEBUG), 1)
|
||||||
@ -65,11 +65,6 @@ SRC = \
|
|||||||
|
|
||||||
include $(PLATFORM_DIR)/Makefile.inc
|
include $(PLATFORM_DIR)/Makefile.inc
|
||||||
|
|
||||||
ifneq ($(PC_HOSTED),1)
|
|
||||||
# Output memory usage information
|
|
||||||
LDFLAGS += -Wl,--print-memory-usage
|
|
||||||
endif
|
|
||||||
|
|
||||||
OPT_FLAGS ?= -Os
|
OPT_FLAGS ?= -Os
|
||||||
CFLAGS += $(OPT_FLAGS)
|
CFLAGS += $(OPT_FLAGS)
|
||||||
LDFLAGS += $(OPT_FLAGS)
|
LDFLAGS += $(OPT_FLAGS)
|
||||||
@ -95,8 +90,28 @@ VPATH += platforms/common
|
|||||||
CFLAGS += -Iplatforms/common
|
CFLAGS += -Iplatforms/common
|
||||||
endif
|
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)))
|
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)
|
$(TARGET): include/version.h $(OBJ)
|
||||||
@echo " LD $@"
|
@echo " LD $@"
|
||||||
$(Q)$(CC) -o $@ $(OBJ) $(LDFLAGS)
|
$(Q)$(CC) -o $@ $(OBJ) $(LDFLAGS)
|
||||||
@ -112,14 +127,14 @@ $(TARGET): include/version.h $(OBJ)
|
|||||||
ifndef PC_HOSTED
|
ifndef PC_HOSTED
|
||||||
%.bin: %.elf
|
%.bin: %.elf
|
||||||
@echo " OBJCOPY $@"
|
@echo " OBJCOPY $@"
|
||||||
$(Q)$(OBJCOPY) -O binary $^ $@
|
$(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) -O binary $^ $@
|
||||||
|
|
||||||
%.hex: %.elf
|
%.hex: %.elf
|
||||||
@echo " OBJCOPY $@"
|
@echo " OBJCOPY $@"
|
||||||
$(Q)$(OBJCOPY) -O ihex $^ $@
|
$(Q)$(OBJCOPY) -O ihex $^ $@
|
||||||
endif
|
endif
|
||||||
|
|
||||||
.PHONY: clean host_clean all_platforms FORCE
|
.PHONY: clean host_clean all_platforms clang-format FORCE
|
||||||
|
|
||||||
clean: host_clean
|
clean: host_clean
|
||||||
$(Q)echo " CLEAN"
|
$(Q)echo " CLEAN"
|
||||||
@ -127,16 +142,27 @@ clean: host_clean
|
|||||||
-$(Q)$(RM) platforms/*/*.o platforms/*/*.d mapfile include/version.h
|
-$(Q)$(RM) platforms/*/*.o platforms/*/*.d mapfile include/version.h
|
||||||
|
|
||||||
all_platforms:
|
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 ;\
|
$(Q)set -e ;\
|
||||||
mkdir -p artifacts/$(shell git describe --always --dirty --tags) ;\
|
mkdir -p artifacts/$(shell git describe --always --dirty --tags) ;\
|
||||||
echo "<html><body><ul>" > artifacts/index.html ;\
|
echo "<html><body><ul>" > artifacts/index.html ;\
|
||||||
|
$(MAKE) clean ;\
|
||||||
for i in platforms/*/Makefile.inc ; do \
|
for i in platforms/*/Makefile.inc ; do \
|
||||||
export DIRNAME=`dirname $$i` ;\
|
export DIRNAME=`dirname $$i` ;\
|
||||||
export PROBE_HOST=`basename $$DIRNAME` ;\
|
export PROBE_HOST=`basename $$DIRNAME` ;\
|
||||||
export CFLAGS=-Werror ;\
|
export CFLAGS=-Werror ;\
|
||||||
echo "Building for hardware platform: $$PROBE_HOST" ;\
|
echo "Building for hardware platform: $$PROBE_HOST" ;\
|
||||||
$(MAKE) clean ;\
|
|
||||||
$(MAKE);\
|
$(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 \
|
if [ -f blackmagic.bin ]; then \
|
||||||
mv blackmagic.bin artifacts/blackmagic-$$PROBE_HOST.bin ;\
|
mv blackmagic.bin artifacts/blackmagic-$$PROBE_HOST.bin ;\
|
||||||
echo "<li><a href='blackmagic-$$PROBE_HOST.bin'>$$PROBE_HOST</a></li>"\
|
echo "<li><a href='blackmagic-$$PROBE_HOST.bin'>$$PROBE_HOST</a></li>"\
|
||||||
@ -147,13 +173,31 @@ all_platforms:
|
|||||||
echo "<li><a href='blackmagic_dfu-$$PROBE_HOST.bin'>$$PROBE_HOST DFU</a></li>"\
|
echo "<li><a href='blackmagic_dfu-$$PROBE_HOST.bin'>$$PROBE_HOST DFU</a></li>"\
|
||||||
>> artifacts/index.html ;\
|
>> artifacts/index.html ;\
|
||||||
fi ;\
|
fi ;\
|
||||||
|
$(MAKE) clean ;\
|
||||||
done ;\
|
done ;\
|
||||||
echo "</ul></body></html>" >> artifacts/index.html ;\
|
echo "</ul></body></html>" >> artifacts/index.html ;\
|
||||||
cp artifacts/*.bin artifacts/$(shell git describe --always --dirty --tags)
|
cp artifacts/blackmagic* artifacts/$(shell git describe --always --dirty --tags)
|
||||||
|
|
||||||
command.c: include/version.h
|
command.c: include/version.h
|
||||||
|
|
||||||
|
GIT_VERSION := $(shell git describe --always --dirty --tags)
|
||||||
|
VERSION_HEADER := \#define FIRMWARE_VERSION "$(GIT_VERSION)"
|
||||||
|
|
||||||
include/version.h: FORCE
|
include/version.h: FORCE
|
||||||
$(Q)echo " GIT include/version.h"
|
@# If git isn't found then GIT_VERSION will be an empty string.
|
||||||
$(Q)echo "#define FIRMWARE_VERSION \"$(shell git describe --always --dirty --tags)\"" > $@
|
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
|
||||||
|
|
||||||
-include *.d
|
-include *.d
|
||||||
|
166
src/command.c
166
src/command.c
@ -34,11 +34,18 @@
|
|||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "serialno.h"
|
#include "serialno.h"
|
||||||
|
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
#include "rtt.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef PLATFORM_HAS_TRACESWO
|
#ifdef PLATFORM_HAS_TRACESWO
|
||||||
# include "traceswo.h"
|
# include "traceswo.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool cmd_version(target *t, int argc, char **argv);
|
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_help(target *t, int argc, char **argv);
|
||||||
|
|
||||||
static bool cmd_jtag_scan(target *t, int argc, char **argv);
|
static bool cmd_jtag_scan(target *t, int argc, char **argv);
|
||||||
@ -56,12 +63,25 @@ static bool cmd_target_power(target *t, int argc, const char **argv);
|
|||||||
static bool cmd_traceswo(target *t, int argc, const char **argv);
|
static bool cmd_traceswo(target *t, int argc, const char **argv);
|
||||||
#endif
|
#endif
|
||||||
static bool cmd_heapinfo(target *t, int argc, const char **argv);
|
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)
|
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
|
||||||
static bool cmd_debug_bmp(target *t, int argc, const char **argv);
|
static bool cmd_debug_bmp(target *t, int argc, const char **argv);
|
||||||
#endif
|
#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[] = {
|
const struct command_s cmd_list[] = {
|
||||||
{"version", (cmd_handler)cmd_version, "Display firmware version info"},
|
{"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"},
|
{"help", (cmd_handler)cmd_help, "Display help for monitor commands"},
|
||||||
{"jtag_scan", (cmd_handler)cmd_jtag_scan, "Scan JTAG chain for devices" },
|
{"jtag_scan", (cmd_handler)cmd_jtag_scan, "Scan JTAG chain for devices" },
|
||||||
{"swdp_scan", (cmd_handler)cmd_swdp_scan, "Scan SW-DP for devices" },
|
{"swdp_scan", (cmd_handler)cmd_swdp_scan, "Scan SW-DP for devices" },
|
||||||
@ -74,6 +94,9 @@ const struct command_s cmd_list[] = {
|
|||||||
#ifdef PLATFORM_HAS_POWER_SWITCH
|
#ifdef PLATFORM_HAS_POWER_SWITCH
|
||||||
{"tpwr", (cmd_handler)cmd_target_power, "Supplies power to the target: (enable|disable)"},
|
{"tpwr", (cmd_handler)cmd_target_power, "Supplies power to the target: (enable|disable)"},
|
||||||
#endif
|
#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
|
#ifdef PLATFORM_HAS_TRACESWO
|
||||||
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2
|
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2
|
||||||
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, NRZ mode: (baudrate) (decode channel ...)" },
|
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, NRZ mode: (baudrate) (decode channel ...)" },
|
||||||
@ -84,6 +107,13 @@ const struct command_s cmd_list[] = {
|
|||||||
{"heapinfo", (cmd_handler)cmd_heapinfo, "Set semihosting heapinfo" },
|
{"heapinfo", (cmd_handler)cmd_heapinfo, "Set semihosting heapinfo" },
|
||||||
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
|
#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)"},
|
{"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
|
#endif
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
@ -410,6 +440,82 @@ static bool cmd_target_power(target *t, int argc, const char **argv)
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
#ifdef PLATFORM_HAS_TRACESWO
|
||||||
static bool cmd_traceswo(target *t, int argc, const char **argv)
|
static bool cmd_traceswo(target *t, int argc, const char **argv)
|
||||||
{
|
{
|
||||||
@ -487,6 +593,66 @@ static bool cmd_debug_bmp(target *t, int argc, const char **argv)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#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)
|
static bool cmd_heapinfo(target *t, int argc, const char **argv)
|
||||||
{
|
{
|
||||||
if (t == NULL) gdb_out("not attached\n");
|
if (t == NULL) gdb_out("not attached\n");
|
||||||
|
@ -130,4 +130,3 @@ int hostio_system(struct target_controller *tc,
|
|||||||
gdb_putpacket_f("Fsystem,%08X/%X", cmd, cmd_len);
|
gdb_putpacket_f("Fsystem,%08X/%X", cmd, cmd_len);
|
||||||
return gdb_main_loop(tc, true);
|
return gdb_main_loop(tc, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
247
src/gdb_main.c
247
src/gdb_main.c
@ -35,6 +35,9 @@
|
|||||||
#include "command.h"
|
#include "command.h"
|
||||||
#include "crc32.h"
|
#include "crc32.h"
|
||||||
#include "morse.h"
|
#include "morse.h"
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
#include "rtt.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
enum gdb_signal {
|
enum gdb_signal {
|
||||||
GDB_SIGINT = 2,
|
GDB_SIGINT = 2,
|
||||||
@ -43,7 +46,7 @@ enum gdb_signal {
|
|||||||
GDB_SIGLOST = 29,
|
GDB_SIGLOST = 29,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BUF_SIZE 1024
|
#define BUF_SIZE 1024U
|
||||||
|
|
||||||
#define ERROR_IF_NO_TARGET() \
|
#define ERROR_IF_NO_TARGET() \
|
||||||
if(!cur_target) { gdb_putpacketz("EFF"); break; }
|
if(!cur_target) { gdb_putpacketz("EFF"); break; }
|
||||||
@ -51,23 +54,29 @@ enum gdb_signal {
|
|||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
const char *cmd_prefix;
|
const char *cmd_prefix;
|
||||||
void (*func)(const char *packet, int len);
|
void (*func)(const char *packet, size_t len);
|
||||||
} cmd_executer;
|
} cmd_executer;
|
||||||
|
|
||||||
static char pbuf[BUF_SIZE + 1];
|
static char pbuf[BUF_SIZE + 1U];
|
||||||
|
|
||||||
static target *cur_target;
|
static target *cur_target;
|
||||||
static target *last_target;
|
static target *last_target;
|
||||||
|
static bool gdb_needs_detach_notify = false;
|
||||||
|
|
||||||
static void handle_q_packet(char *packet, int len);
|
static void handle_q_packet(char *packet, size_t len);
|
||||||
static void handle_v_packet(char *packet, int len);
|
static void handle_v_packet(char *packet, size_t len);
|
||||||
static void handle_z_packet(char *packet, int len);
|
static void handle_z_packet(char *packet, size_t len);
|
||||||
|
static void handle_kill_target(void);
|
||||||
|
|
||||||
static void gdb_target_destroy_callback(struct target_controller *tc, target *t)
|
static void gdb_target_destroy_callback(struct target_controller *tc, target *t)
|
||||||
{
|
{
|
||||||
(void)tc;
|
(void)tc;
|
||||||
if (cur_target == t)
|
if (cur_target == t) {
|
||||||
|
gdb_put_notificationz("%Stop:W00");
|
||||||
|
gdb_out("You are now detached from the previous target.\n");
|
||||||
cur_target = NULL;
|
cur_target = NULL;
|
||||||
|
gdb_needs_detach_notify = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (last_target == t)
|
if (last_target == t)
|
||||||
last_target = NULL;
|
last_target = NULL;
|
||||||
@ -100,22 +109,20 @@ static struct target_controller gdb_controller = {
|
|||||||
|
|
||||||
int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
||||||
{
|
{
|
||||||
int size;
|
|
||||||
bool single_step = false;
|
bool single_step = false;
|
||||||
|
|
||||||
/* GDB protocol main loop */
|
/* GDB protocol main loop */
|
||||||
while(1) {
|
while (1) {
|
||||||
SET_IDLE_STATE(1);
|
SET_IDLE_STATE(1);
|
||||||
size = gdb_getpacket(pbuf, BUF_SIZE);
|
size_t size = gdb_getpacket(pbuf, BUF_SIZE);
|
||||||
SET_IDLE_STATE(0);
|
SET_IDLE_STATE(0);
|
||||||
switch(pbuf[0]) {
|
switch (pbuf[0]) {
|
||||||
/* Implementation of these is mandatory! */
|
/* Implementation of these is mandatory! */
|
||||||
case 'g': { /* 'g': Read general registers */
|
case 'g': { /* 'g': Read general registers */
|
||||||
ERROR_IF_NO_TARGET();
|
ERROR_IF_NO_TARGET();
|
||||||
uint8_t arm_regs[target_regs_size(cur_target)];
|
uint8_t gp_regs[target_regs_size(cur_target)];
|
||||||
target_regs_read(cur_target, arm_regs);
|
target_regs_read(cur_target, gp_regs);
|
||||||
gdb_putpacket(hexify(pbuf, arm_regs, sizeof(arm_regs)),
|
gdb_putpacket(hexify(pbuf, gp_regs, sizeof(gp_regs)), sizeof(gp_regs) * 2U);
|
||||||
sizeof(arm_regs) * 2);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'm': { /* 'm addr,len': Read len bytes from addr */
|
case 'm': { /* 'm addr,len': Read len bytes from addr */
|
||||||
@ -132,19 +139,20 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
if (target_mem_read(cur_target, mem, addr, len))
|
if (target_mem_read(cur_target, mem, addr, len))
|
||||||
gdb_putpacketz("E01");
|
gdb_putpacketz("E01");
|
||||||
else
|
else
|
||||||
gdb_putpacket(hexify(pbuf, mem, len), len * 2);
|
gdb_putpacket(hexify(pbuf, mem, len), len * 2U);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'G': { /* 'G XX': Write general registers */
|
case 'G': { /* 'G XX': Write general registers */
|
||||||
ERROR_IF_NO_TARGET();
|
ERROR_IF_NO_TARGET();
|
||||||
uint8_t arm_regs[target_regs_size(cur_target)];
|
uint8_t gp_regs[target_regs_size(cur_target)];
|
||||||
unhexify(arm_regs, &pbuf[1], sizeof(arm_regs));
|
unhexify(gp_regs, &pbuf[1], sizeof(gp_regs));
|
||||||
target_regs_write(cur_target, arm_regs);
|
target_regs_write(cur_target, gp_regs);
|
||||||
gdb_putpacketz("OK");
|
gdb_putpacketz("OK");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'M': { /* 'M addr,len:XX': Write len bytes to addr */
|
case 'M': { /* 'M addr,len:XX': Write len bytes to addr */
|
||||||
uint32_t addr, len;
|
uint32_t addr = 0;
|
||||||
|
uint32_t len = 0;
|
||||||
int hex;
|
int hex;
|
||||||
ERROR_IF_NO_TARGET();
|
ERROR_IF_NO_TARGET();
|
||||||
sscanf(pbuf, "M%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &hex);
|
sscanf(pbuf, "M%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &hex);
|
||||||
@ -162,11 +170,24 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
gdb_putpacketz("OK");
|
gdb_putpacketz("OK");
|
||||||
break;
|
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] */
|
case 's': /* 's [addr]': Single step [start at addr] */
|
||||||
single_step = true;
|
single_step = true;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case 'c': /* 'c [addr]': Continue [at addr] */
|
case 'c': /* 'c [addr]': Continue [at addr] */
|
||||||
if(!cur_target) {
|
if (!cur_target) {
|
||||||
gdb_putpacketz("X1D");
|
gdb_putpacketz("X1D");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -181,7 +202,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
target_addr watch;
|
target_addr watch;
|
||||||
enum target_halt_reason reason;
|
enum target_halt_reason reason;
|
||||||
|
|
||||||
if(!cur_target) {
|
if (!cur_target) {
|
||||||
/* Report "target exited" if no target */
|
/* Report "target exited" if no target */
|
||||||
gdb_putpacketz("W00");
|
gdb_putpacketz("W00");
|
||||||
break;
|
break;
|
||||||
@ -189,10 +210,13 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
|
|
||||||
/* Wait for target halt */
|
/* Wait for target halt */
|
||||||
while(!(reason = target_halt_poll(cur_target, &watch))) {
|
while(!(reason = target_halt_poll(cur_target, &watch))) {
|
||||||
unsigned char c = gdb_if_getchar_to(0);
|
char c = (char)gdb_if_getchar_to(0);
|
||||||
if((c == '\x03') || (c == '\x04')) {
|
if(c == '\x03' || c == '\x04') {
|
||||||
target_halt_request(cur_target);
|
target_halt_request(cur_target);
|
||||||
}
|
}
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
if (rtt_enabled) poll_rtt(cur_target);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
SET_RUN_STATE(0);
|
SET_RUN_STATE(0);
|
||||||
|
|
||||||
@ -274,12 +298,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'k': /* Kill the target */
|
case 'k': /* Kill the target */
|
||||||
if(cur_target) {
|
handle_kill_target();
|
||||||
target_reset(cur_target);
|
|
||||||
target_detach(cur_target);
|
|
||||||
last_target = cur_target;
|
|
||||||
cur_target = NULL;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'r': /* Reset the target system */
|
case 'r': /* Reset the target system */
|
||||||
@ -317,7 +336,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
handle_q_packet(pbuf, size);
|
handle_q_packet(pbuf, size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'v': /* General query packet */
|
case 'v': /* Verbose command packet */
|
||||||
handle_v_packet(pbuf, size);
|
handle_v_packet(pbuf, size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -335,12 +354,12 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool exec_command(char *packet, int len, const cmd_executer *exec)
|
static bool exec_command(char *packet, const size_t length, const cmd_executer *exec)
|
||||||
{
|
{
|
||||||
while (exec->cmd_prefix) {
|
while (exec->cmd_prefix) {
|
||||||
const int l = strlen(exec->cmd_prefix);
|
const size_t prefix_length = strlen(exec->cmd_prefix);
|
||||||
if (!strncmp(packet, exec->cmd_prefix, l)) {
|
if (!strncmp(packet, exec->cmd_prefix, prefix_length)) {
|
||||||
exec->func(packet + l, len - l);
|
exec->func(packet + prefix_length, length - prefix_length);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
++exec;
|
++exec;
|
||||||
@ -348,19 +367,16 @@ static bool exec_command(char *packet, int len, const cmd_executer *exec)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exec_q_rcmd(const char *packet,int len)
|
static void exec_q_rcmd(const char *packet, const size_t length)
|
||||||
{
|
{
|
||||||
char *data;
|
|
||||||
int datalen;
|
|
||||||
|
|
||||||
/* calculate size and allocate buffer for command */
|
/* calculate size and allocate buffer for command */
|
||||||
datalen = len / 2;
|
const size_t datalen = length / 2U;
|
||||||
data = alloca(datalen + 1);
|
char *data = alloca(datalen + 1);
|
||||||
/* dehexify command */
|
/* dehexify command */
|
||||||
unhexify(data, packet, datalen);
|
unhexify(data, packet, datalen);
|
||||||
data[datalen] = 0; /* add terminating null */
|
data[datalen] = 0; /* add terminating null */
|
||||||
|
|
||||||
int c = command_process(cur_target, data);
|
const int c = command_process(cur_target, data);
|
||||||
if (c < 0)
|
if (c < 0)
|
||||||
gdb_putpacketz("");
|
gdb_putpacketz("");
|
||||||
else if (c == 0)
|
else if (c == 0)
|
||||||
@ -370,41 +386,41 @@ static void exec_q_rcmd(const char *packet,int len)
|
|||||||
2 * strlen("Failed\n"));
|
2 * strlen("Failed\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void handle_q_string_reply(const char *reply, const char *param)
|
||||||
handle_q_string_reply(const char *str, const char *param)
|
|
||||||
{
|
{
|
||||||
unsigned long addr, len;
|
const size_t reply_length = strlen(reply);
|
||||||
const size_t str_len = strlen(str);
|
uint32_t addr = 0;
|
||||||
|
uint32_t len = 0;
|
||||||
|
|
||||||
if (sscanf(param, "%08lx,%08lx", &addr, &len) != 2) {
|
if (sscanf(param, "%08" PRIx32 ",%08" PRIx32, &addr, &len) != 2) {
|
||||||
gdb_putpacketz("E01");
|
gdb_putpacketz("E01");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (addr > str_len) {
|
if (addr > reply_length) {
|
||||||
gdb_putpacketz("E01");
|
gdb_putpacketz("E01");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (addr == str_len) {
|
if (addr == reply_length) {
|
||||||
gdb_putpacketz("l");
|
gdb_putpacketz("l");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unsigned long output_len = str_len - addr;
|
size_t output_len = reply_length - addr;
|
||||||
if (output_len > len)
|
if (output_len > len)
|
||||||
output_len = len;
|
output_len = len;
|
||||||
gdb_putpacket2("m", 1, str + addr, output_len);
|
gdb_putpacket2("m", 1U, reply + addr, output_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exec_q_supported(const char *packet, int len)
|
static void exec_q_supported(const char *packet, const size_t length)
|
||||||
{
|
{
|
||||||
(void)packet;
|
(void)packet;
|
||||||
(void)len;
|
(void)length;
|
||||||
gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+;qXfer:features:read+", BUF_SIZE);
|
gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+;qXfer:features:read+", BUF_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exec_q_memory_map(const char *packet, int len)
|
static void exec_q_memory_map(const char *packet, const size_t length)
|
||||||
{
|
{
|
||||||
(void)packet;
|
(void)packet;
|
||||||
(void)len;
|
(void)length;
|
||||||
/* Read target XML memory map */
|
/* Read target XML memory map */
|
||||||
if ((!cur_target) && last_target) {
|
if ((!cur_target) && last_target) {
|
||||||
/* Attach to last target if detached. */
|
/* Attach to last target if detached. */
|
||||||
@ -420,9 +436,9 @@ static void exec_q_memory_map(const char *packet, int len)
|
|||||||
handle_q_string_reply(buf, packet);
|
handle_q_string_reply(buf, packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exec_q_feature_read(const char *packet, int len)
|
static void exec_q_feature_read(const char *packet, const size_t length)
|
||||||
{
|
{
|
||||||
(void)len;
|
(void)length;
|
||||||
/* Read target description */
|
/* Read target description */
|
||||||
if ((!cur_target) && last_target) {
|
if ((!cur_target) && last_target) {
|
||||||
/* Attach to last target if detached. */
|
/* Attach to last target if detached. */
|
||||||
@ -435,24 +451,51 @@ static void exec_q_feature_read(const char *packet, int len)
|
|||||||
handle_q_string_reply(target_tdesc(cur_target), packet);
|
handle_q_string_reply(target_tdesc(cur_target), packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void exec_q_crc(const char *packet, int len)
|
static void exec_q_crc(const char *packet, const size_t length)
|
||||||
{
|
{
|
||||||
(void)len;
|
(void)length;
|
||||||
uint32_t addr, alen;
|
uint32_t addr;
|
||||||
if (sscanf(packet, "%" PRIx32 ",%" PRIx32, &addr, &alen) == 2) {
|
uint32_t addr_length;
|
||||||
|
if (sscanf(packet, "%" PRIx32 ",%" PRIx32, &addr, &addr_length) == 2) {
|
||||||
if (!cur_target) {
|
if (!cur_target) {
|
||||||
gdb_putpacketz("E01");
|
gdb_putpacketz("E01");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uint32_t crc;
|
uint32_t crc;
|
||||||
int res = generic_crc32(cur_target, &crc, addr, alen);
|
if (generic_crc32(cur_target, &crc, addr, addr_length))
|
||||||
if (res)
|
|
||||||
gdb_putpacketz("E03");
|
gdb_putpacketz("E03");
|
||||||
else
|
else
|
||||||
gdb_putpacket_f("C%lx", crc);
|
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[]=
|
static const cmd_executer q_commands[]=
|
||||||
{
|
{
|
||||||
{"qRcmd,", exec_q_rcmd},
|
{"qRcmd,", exec_q_rcmd},
|
||||||
@ -460,34 +503,60 @@ static const cmd_executer q_commands[]=
|
|||||||
{"qXfer:memory-map:read::", exec_q_memory_map},
|
{"qXfer:memory-map:read::", exec_q_memory_map},
|
||||||
{"qXfer:features:read:target.xml:",exec_q_feature_read},
|
{"qXfer:features:read:target.xml:",exec_q_feature_read},
|
||||||
{"qCRC:", exec_q_crc},
|
{"qCRC:", exec_q_crc},
|
||||||
|
{"qC", exec_q_c},
|
||||||
|
{"qfThreadInfo", exec_q_thread_info},
|
||||||
|
{"qsThreadInfo", exec_q_thread_info},
|
||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void handle_kill_target(void)
|
||||||
handle_q_packet(char *packet, int len)
|
|
||||||
{
|
{
|
||||||
if (exec_command(packet, len, q_commands))
|
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))
|
||||||
return;
|
return;
|
||||||
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
|
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
|
||||||
gdb_putpacket("", 0);
|
gdb_putpacket("", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void handle_v_packet(char *packet, const size_t plen)
|
||||||
handle_v_packet(char *packet, int plen)
|
|
||||||
{
|
{
|
||||||
unsigned long addr, len;
|
uint32_t addr = 0;
|
||||||
|
uint32_t len = 0;
|
||||||
int bin;
|
int bin;
|
||||||
static uint8_t flash_mode = 0;
|
static uint8_t flash_mode = 0;
|
||||||
|
|
||||||
if (sscanf(packet, "vAttach;%08lx", &addr) == 1) {
|
if (sscanf(packet, "vAttach;%08" PRIx32, &addr) == 1) {
|
||||||
/* Attach to remote target processor */
|
/* Attach to remote target processor */
|
||||||
cur_target = target_attach_n(addr, &gdb_controller);
|
cur_target = target_attach_n(addr, &gdb_controller);
|
||||||
if(cur_target) {
|
if(cur_target) {
|
||||||
morse(NULL, false);
|
morse(NULL, false);
|
||||||
gdb_putpacketz("T05");
|
/*
|
||||||
|
* 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;");
|
||||||
} else
|
} else
|
||||||
gdb_putpacketz("E01");
|
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)) {
|
} else if (!strncmp(packet, "vRun", 4)) {
|
||||||
/* Parse command line for get_cmdline semihosting call */
|
/* Parse command line for get_cmdline semihosting call */
|
||||||
char cmdline[83];
|
char cmdline[83];
|
||||||
@ -518,6 +587,10 @@ handle_v_packet(char *packet, int plen)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
/* force searching rtt control block */
|
||||||
|
rtt_found = false;
|
||||||
|
#endif
|
||||||
/* Run target program. For us (embedded) this means reset. */
|
/* Run target program. For us (embedded) this means reset. */
|
||||||
if (cur_target) {
|
if (cur_target) {
|
||||||
target_set_cmdline(cur_target, cmdline);
|
target_set_cmdline(cur_target, cmdline);
|
||||||
@ -539,9 +612,9 @@ handle_v_packet(char *packet, int plen)
|
|||||||
} else
|
} else
|
||||||
gdb_putpacketz("E01");
|
gdb_putpacketz("E01");
|
||||||
|
|
||||||
} else if (sscanf(packet, "vFlashErase:%08lx,%08lx", &addr, &len) == 2) {
|
} else if (sscanf(packet, "vFlashErase:%08" PRIx32 ",%08" PRIx32, &addr, &len) == 2) {
|
||||||
/* Erase Flash Memory */
|
/* Erase Flash Memory */
|
||||||
DEBUG_GDB("Flash Erase %08lX %08lX\n", addr, len);
|
DEBUG_GDB("Flash Erase %08" PRIX32 " %08" PRIX32 "\n", addr, len);
|
||||||
if (!cur_target) {
|
if (!cur_target) {
|
||||||
gdb_putpacketz("EFF");
|
gdb_putpacketz("EFF");
|
||||||
return;
|
return;
|
||||||
@ -560,11 +633,11 @@ handle_v_packet(char *packet, int plen)
|
|||||||
gdb_putpacketz("EFF");
|
gdb_putpacketz("EFF");
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (sscanf(packet, "vFlashWrite:%08lx:%n", &addr, &bin) == 1) {
|
} else if (sscanf(packet, "vFlashWrite:%08" PRIx32 ":%n", &addr, &bin) == 1) {
|
||||||
/* Write Flash Memory */
|
/* Write Flash Memory */
|
||||||
len = plen - bin;
|
const uint32_t count = plen - bin;
|
||||||
DEBUG_GDB("Flash Write %08lX %08lX\n", addr, len);
|
DEBUG_GDB("Flash Write %08" PRIX32 " %08" PRIX32 "\n", addr, count);
|
||||||
if (cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, len) == 0)
|
if (cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, count) == 0)
|
||||||
gdb_putpacketz("OK");
|
gdb_putpacketz("OK");
|
||||||
else {
|
else {
|
||||||
flash_mode = 0;
|
flash_mode = 0;
|
||||||
@ -576,24 +649,30 @@ handle_v_packet(char *packet, int plen)
|
|||||||
gdb_putpacketz(target_flash_done(cur_target) ? "EFF" : "OK");
|
gdb_putpacketz(target_flash_done(cur_target) ? "EFF" : "OK");
|
||||||
flash_mode = 0;
|
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 {
|
} else {
|
||||||
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
|
DEBUG_GDB("*** Unsupported packet: %s\n", packet);
|
||||||
gdb_putpacket("", 0);
|
gdb_putpacket("", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void handle_z_packet(char *packet, const size_t plen)
|
||||||
handle_z_packet(char *packet, int plen)
|
|
||||||
{
|
{
|
||||||
(void)plen;
|
(void)plen;
|
||||||
|
|
||||||
uint8_t set = (packet[0] == 'Z') ? 1 : 0;
|
uint32_t type;
|
||||||
int type, len;
|
uint32_t len;
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
int ret;
|
sscanf(packet, "%*[zZ]%" PRIu32 ",%08" PRIx32 ",%" PRIu32, &type, &addr, &len);
|
||||||
|
|
||||||
sscanf(packet, "%*[zZ]%d,%08" PRIx32 ",%d", &type, &addr, &len);
|
int ret = 0;
|
||||||
if(set)
|
if (packet[0] == 'Z')
|
||||||
ret = target_breakwatch_set(cur_target, type, addr, len);
|
ret = target_breakwatch_set(cur_target, type, addr, len);
|
||||||
else
|
else
|
||||||
ret = target_breakwatch_clear(cur_target, type, addr, len);
|
ret = target_breakwatch_clear(cur_target, type, addr, len);
|
||||||
|
@ -30,12 +30,11 @@
|
|||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
int gdb_getpacket(char *packet, int size)
|
size_t gdb_getpacket(char *packet, size_t size)
|
||||||
{
|
{
|
||||||
unsigned char c;
|
|
||||||
unsigned char csum;
|
unsigned char csum;
|
||||||
char recv_csum[3];
|
char recv_csum[3];
|
||||||
int i;
|
size_t offset = 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
/* Wait for packet start */
|
/* Wait for packet start */
|
||||||
@ -44,7 +43,8 @@ int gdb_getpacket(char *packet, int size)
|
|||||||
* start ('$') or a BMP remote packet start ('!').
|
* start ('$') or a BMP remote packet start ('!').
|
||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
packet[0] = gdb_if_getchar();
|
/* Smells like bad code */
|
||||||
|
packet[0] = (char)gdb_if_getchar();
|
||||||
if (packet[0] == 0x04)
|
if (packet[0] == 0x04)
|
||||||
return 1;
|
return 1;
|
||||||
} while ((packet[0] != '$') && (packet[0] != REMOTE_SOM));
|
} while ((packet[0] != '$') && (packet[0] != REMOTE_SOM));
|
||||||
@ -52,18 +52,19 @@ int gdb_getpacket(char *packet, int size)
|
|||||||
if (packet[0] == REMOTE_SOM) {
|
if (packet[0] == REMOTE_SOM) {
|
||||||
/* This is probably a remote control packet
|
/* This is probably a remote control packet
|
||||||
* - get and handle it */
|
* - get and handle it */
|
||||||
i = 0;
|
offset = 0;
|
||||||
bool gettingRemotePacket = true;
|
bool gettingRemotePacket = true;
|
||||||
while (gettingRemotePacket) {
|
while (gettingRemotePacket) {
|
||||||
c = gdb_if_getchar();
|
/* Smells like bad code */
|
||||||
|
const char c = (char)gdb_if_getchar();
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case REMOTE_SOM: /* Oh dear, packet restarts */
|
case REMOTE_SOM: /* Oh dear, packet restarts */
|
||||||
i = 0;
|
offset = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case REMOTE_EOM: /* Complete packet for processing */
|
case REMOTE_EOM: /* Complete packet for processing */
|
||||||
packet[i] = 0;
|
packet[offset] = 0;
|
||||||
remotePacketProcess(i, packet);
|
remotePacketProcess(offset, packet);
|
||||||
gettingRemotePacket = false;
|
gettingRemotePacket = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -73,8 +74,8 @@ int gdb_getpacket(char *packet, int size)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (i < size) {
|
if (offset < size) {
|
||||||
packet[i++] = c;
|
packet[offset++] = c;
|
||||||
} else {
|
} else {
|
||||||
/* Who knows what is going on...return to normality */
|
/* Who knows what is going on...return to normality */
|
||||||
gettingRemotePacket = false;
|
gettingRemotePacket = false;
|
||||||
@ -92,30 +93,32 @@ int gdb_getpacket(char *packet, int size)
|
|||||||
#endif
|
#endif
|
||||||
} while (packet[0] != '$');
|
} while (packet[0] != '$');
|
||||||
|
|
||||||
i = 0;
|
offset = 0;
|
||||||
csum = 0;
|
csum = 0;
|
||||||
|
char c;
|
||||||
/* Capture packet data into buffer */
|
/* Capture packet data into buffer */
|
||||||
while ((c = gdb_if_getchar()) != '#') {
|
while ((c = (char)gdb_if_getchar()) != '#') {
|
||||||
|
|
||||||
if (i == size) /* Oh shit */
|
/* If we run out of buffer space, exit early */
|
||||||
|
if (offset == size)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (c == '$') { /* Restart capture */
|
if (c == '$') { /* Restart capture */
|
||||||
i = 0;
|
offset = 0;
|
||||||
csum = 0;
|
csum = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c == '}') { /* escaped char */
|
if (c == '}') { /* escaped char */
|
||||||
c = gdb_if_getchar();
|
c = gdb_if_getchar();
|
||||||
csum += c + '}';
|
csum += c + '}';
|
||||||
packet[i++] = c ^ 0x20;
|
packet[offset++] = c ^ 0x20;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
csum += c;
|
csum += c;
|
||||||
packet[i++] = c;
|
packet[offset++] = c;
|
||||||
}
|
}
|
||||||
recv_csum[0] = gdb_if_getchar();
|
recv_csum[0] = (char)gdb_if_getchar();
|
||||||
recv_csum[1] = gdb_if_getchar();
|
recv_csum[1] = (char)gdb_if_getchar();
|
||||||
recv_csum[2] = 0;
|
recv_csum[2] = 0;
|
||||||
|
|
||||||
/* return packet if checksum matches */
|
/* return packet if checksum matches */
|
||||||
@ -126,20 +129,20 @@ int gdb_getpacket(char *packet, int size)
|
|||||||
gdb_if_putchar('-', 1); /* send nack */
|
gdb_if_putchar('-', 1); /* send nack */
|
||||||
}
|
}
|
||||||
gdb_if_putchar('+', 1); /* send ack */
|
gdb_if_putchar('+', 1); /* send ack */
|
||||||
packet[i] = 0;
|
packet[offset] = 0;
|
||||||
|
|
||||||
#if PC_HOSTED == 1
|
#if PC_HOSTED == 1
|
||||||
DEBUG_GDB_WIRE("%s : ", __func__);
|
DEBUG_GDB_WIRE("%s : ", __func__);
|
||||||
for(int j = 0; j < i; j++) {
|
for (size_t j = 0; j < offset; j++) {
|
||||||
c = packet[j];
|
const char c = packet[j];
|
||||||
if ((c >= 32) && (c < 127))
|
if (c >= ' ' && c < 0x7F)
|
||||||
DEBUG_GDB_WIRE("%c", c);
|
DEBUG_GDB_WIRE("%c", c);
|
||||||
else
|
else
|
||||||
DEBUG_GDB_WIRE("\\x%02X", c);
|
DEBUG_GDB_WIRE("\\x%02X", c);
|
||||||
}
|
}
|
||||||
DEBUG_GDB_WIRE("\n");
|
DEBUG_GDB_WIRE("\n");
|
||||||
#endif
|
#endif
|
||||||
return i;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gdb_next_char(char c, unsigned char *csum)
|
static void gdb_next_char(char c, unsigned char *csum)
|
||||||
@ -161,21 +164,19 @@ static void gdb_next_char(char c, unsigned char *csum)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdb_putpacket2(const char *packet1, int size1, const char *packet2, int size2)
|
void gdb_putpacket2(const char *packet1, size_t size1, const char *packet2, size_t size2)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
unsigned char csum;
|
|
||||||
char xmit_csum[3];
|
char xmit_csum[3];
|
||||||
int tries = 0;
|
size_t tries = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
DEBUG_GDB_WIRE("%s : ", __func__);
|
DEBUG_GDB_WIRE("%s: ", __func__);
|
||||||
csum = 0;
|
unsigned char csum = 0;
|
||||||
gdb_if_putchar('$', 0);
|
gdb_if_putchar('$', 0);
|
||||||
|
|
||||||
for (i = 0; i < size1; ++i)
|
for (size_t i = 0; i < size1; ++i)
|
||||||
gdb_next_char(packet1[i], &csum);
|
gdb_next_char(packet1[i], &csum);
|
||||||
for (i = 0; i < size2; ++i)
|
for (size_t i = 0; i < size2; ++i)
|
||||||
gdb_next_char(packet2[i], &csum);
|
gdb_next_char(packet2[i], &csum);
|
||||||
|
|
||||||
gdb_if_putchar('#', 0);
|
gdb_if_putchar('#', 0);
|
||||||
@ -183,28 +184,42 @@ void gdb_putpacket2(const char *packet1, int size1, const char *packet2, int siz
|
|||||||
gdb_if_putchar(xmit_csum[0], 0);
|
gdb_if_putchar(xmit_csum[0], 0);
|
||||||
gdb_if_putchar(xmit_csum[1], 1);
|
gdb_if_putchar(xmit_csum[1], 1);
|
||||||
DEBUG_GDB_WIRE("\n");
|
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, int size)
|
void gdb_putpacket(const char *packet, size_t size)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
unsigned char csum;
|
|
||||||
char xmit_csum[3];
|
char xmit_csum[3];
|
||||||
int tries = 0;
|
size_t tries = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
DEBUG_GDB_WIRE("%s : ", __func__);
|
DEBUG_GDB_WIRE("%s: ", __func__);
|
||||||
csum = 0;
|
unsigned char csum = 0;
|
||||||
gdb_if_putchar('$', 0);
|
gdb_if_putchar('$', 0);
|
||||||
for (i = 0; i < size; ++i)
|
for (size_t i = 0; i < size; ++i)
|
||||||
gdb_next_char(packet[i], &csum);
|
gdb_next_char(packet[i], &csum);
|
||||||
gdb_if_putchar('#', 0);
|
gdb_if_putchar('#', 0);
|
||||||
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
|
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
|
||||||
gdb_if_putchar(xmit_csum[0], 0);
|
gdb_if_putchar(xmit_csum[0], 0);
|
||||||
gdb_if_putchar(xmit_csum[1], 1);
|
gdb_if_putchar(xmit_csum[1], 1);
|
||||||
DEBUG_GDB_WIRE("\n");
|
DEBUG_GDB_WIRE("\n");
|
||||||
} while ((gdb_if_getchar_to(2000) != '+') && (tries++ < 3));
|
} 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)
|
||||||
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
void gdb_putpacket_f(const char *fmt, ...)
|
void gdb_putpacket_f(const char *fmt, ...)
|
||||||
|
@ -26,16 +26,16 @@
|
|||||||
|
|
||||||
static const char hexdigits[] = "0123456789abcdef";
|
static const char hexdigits[] = "0123456789abcdef";
|
||||||
|
|
||||||
char * hexify(char *hex, const void *buf, size_t size)
|
char *hexify(char *hex, const void *buf, const size_t size)
|
||||||
{
|
{
|
||||||
char *tmp = hex;
|
char *dst = hex;
|
||||||
const uint8_t *b = buf;
|
const uint8_t *const src = buf;
|
||||||
|
|
||||||
while (size--) {
|
for (size_t idx = 0; idx < size; ++idx) {
|
||||||
*tmp++ = hexdigits[*b >> 4];
|
*dst++ = hexdigits[src[idx] >> 4];
|
||||||
*tmp++ = hexdigits[*b++ & 0xF];
|
*dst++ = hexdigits[src[idx] & 0xF];
|
||||||
}
|
}
|
||||||
*tmp++ = 0;
|
*dst++ = 0;
|
||||||
|
|
||||||
return hex;
|
return hex;
|
||||||
}
|
}
|
||||||
@ -43,20 +43,18 @@ char * hexify(char *hex, const void *buf, size_t size)
|
|||||||
static uint8_t unhex_digit(char hex)
|
static uint8_t unhex_digit(char hex)
|
||||||
{
|
{
|
||||||
uint8_t tmp = hex - '0';
|
uint8_t tmp = hex - '0';
|
||||||
if(tmp > 9)
|
if (tmp > 9)
|
||||||
tmp -= 'A' - '0' - 10;
|
tmp -= 'A' - '0' - 10;
|
||||||
if(tmp > 16)
|
if (tmp > 16)
|
||||||
tmp -= 'a' - 'A';
|
tmp -= 'a' - 'A';
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
char * unhexify(void *buf, const char *hex, size_t size)
|
char *unhexify(void *buf, const char *hex, const size_t size)
|
||||||
{
|
{
|
||||||
uint8_t *b = buf;
|
uint8_t *const dst = buf;
|
||||||
while (size--) {
|
for (size_t idx = 0; idx < size; ++idx, hex += 2) {
|
||||||
*b = unhex_digit(*hex++) << 4;
|
dst[idx] = (unhex_digit(hex[0]) << 4) | unhex_digit(hex[1]);
|
||||||
*b++ |= unhex_digit(*hex++);
|
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,18 +21,19 @@
|
|||||||
#ifndef __GDB_PACKET_H
|
#ifndef __GDB_PACKET_H
|
||||||
#define __GDB_PACKET_H
|
#define __GDB_PACKET_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
int gdb_getpacket(char *packet, int size);
|
size_t gdb_getpacket(char *packet, size_t size);
|
||||||
void gdb_putpacket(const char *packet, int size);
|
void gdb_putpacket(const char *packet, size_t size);
|
||||||
void gdb_putpacket2(const char *packet1, int size1, const char *packet2, int size2);
|
void gdb_putpacket2(const char *packet1, size_t size1, const char *packet2, size_t size2);
|
||||||
#define gdb_putpacketz(packet) gdb_putpacket((packet), strlen(packet))
|
#define gdb_putpacketz(packet) gdb_putpacket((packet), strlen(packet))
|
||||||
void gdb_putpacket_f(const char *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_out(const char *buf);
|
||||||
void gdb_voutf(const char *fmt, va_list);
|
void gdb_voutf(const char *fmt, va_list);
|
||||||
void gdb_outf(const char *fmt, ...);
|
void gdb_outf(const char *fmt, ...);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
85
src/include/queue.h
Normal file
85
src/include/queue.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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__ */
|
34
src/include/rtt.h
Normal file
34
src/include/rtt.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#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
|
36
src/include/rtt_if.h
Normal file
36
src/include/rtt_if.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#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
|
@ -78,7 +78,7 @@ static const struct usb_device_descriptor dev_desc = {
|
|||||||
.bDeviceClass = 0xEF, /* Miscellaneous Device */
|
.bDeviceClass = 0xEF, /* Miscellaneous Device */
|
||||||
.bDeviceSubClass = 2, /* Common Class */
|
.bDeviceSubClass = 2, /* Common Class */
|
||||||
.bDeviceProtocol = 1, /* Interface Association */
|
.bDeviceProtocol = 1, /* Interface Association */
|
||||||
#ifdef LM4F
|
#if defined(SAMD21E17) || defined(LM4F)
|
||||||
.bMaxPacketSize0 = 64, /*Fixed for icdi*/
|
.bMaxPacketSize0 = 64, /*Fixed for icdi*/
|
||||||
#else
|
#else
|
||||||
.bMaxPacketSize0 = 32,
|
.bMaxPacketSize0 = 32,
|
||||||
@ -435,6 +435,8 @@ static void dfu_detach_complete(usbd_device *dev, struct usb_setup_data *req)
|
|||||||
/* Reset core to enter bootloader */
|
/* Reset core to enter bootloader */
|
||||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||||
scb_reset_core();
|
scb_reset_core();
|
||||||
|
#else
|
||||||
|
scb_reset_system();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,7 +526,7 @@ static void cdcacm_set_config(usbd_device *dev, uint16_t wValue)
|
|||||||
configured = wValue;
|
configured = wValue;
|
||||||
|
|
||||||
/* GDB interface */
|
/* GDB interface */
|
||||||
#if defined(STM32F4) || defined(LM4F)
|
#if defined(STM32F4) || defined(LM4F) || defined(SAMD)
|
||||||
usbd_ep_setup(dev, CDCACM_GDB_ENDPOINT, USB_ENDPOINT_ATTR_BULK,
|
usbd_ep_setup(dev, CDCACM_GDB_ENDPOINT, USB_ENDPOINT_ATTR_BULK,
|
||||||
CDCACM_PACKET_SIZE, gdb_usb_out_cb);
|
CDCACM_PACKET_SIZE, gdb_usb_out_cb);
|
||||||
#else
|
#else
|
||||||
@ -580,6 +582,7 @@ void cdcacm_init(void)
|
|||||||
|
|
||||||
nvic_set_priority(USB_IRQ, IRQ_PRI_USB);
|
nvic_set_priority(USB_IRQ, IRQ_PRI_USB);
|
||||||
nvic_enable_irq(USB_IRQ);
|
nvic_enable_irq(USB_IRQ);
|
||||||
|
usbd_disconnect(usbdev, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void USB_ISR(void)
|
void USB_ISR(void)
|
||||||
|
@ -30,6 +30,10 @@
|
|||||||
#include "gdb_if.h"
|
#include "gdb_if.h"
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
#include "rtt_if.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "bmp_remote.h"
|
#include "bmp_remote.h"
|
||||||
#include "bmp_hosted.h"
|
#include "bmp_hosted.h"
|
||||||
#include "stlinkv2.h"
|
#include "stlinkv2.h"
|
||||||
@ -58,6 +62,9 @@ static void exit_function(void)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
rtt_if_exit();
|
||||||
|
#endif
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,6 +117,9 @@ void platform_init(int argc, char **argv)
|
|||||||
exit(cl_execute(&cl_opts));
|
exit(cl_execute(&cl_opts));
|
||||||
else {
|
else {
|
||||||
gdb_if_init();
|
gdb_if_init();
|
||||||
|
#ifdef ENABLE_RTT
|
||||||
|
rtt_if_init();
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
127
src/platforms/hosted/rtt_if.c
Normal file
127
src/platforms/hosted/rtt_if.c
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
61
src/platforms/jeff/Makefile.inc
Normal file
61
src/platforms/jeff/Makefile.inc
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
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
|
346
src/platforms/jeff/platform.c
Normal file
346
src/platforms/jeff/platform.c
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
227
src/platforms/jeff/platform.h
Normal file
227
src/platforms/jeff/platform.h
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
351
src/platforms/jeff/usbdfu.c
Normal file
351
src/platforms/jeff/usbdfu.c
Normal file
@ -0,0 +1,351 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
103
src/platforms/samd/gdb_if.c
Normal file
103
src/platforms/samd/gdb_if.c
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
134
src/platforms/samd/rtt_if.c
Normal file
134
src/platforms/samd/rtt_if.c
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
28
src/platforms/samd/samd.ld
Normal file
28
src/platforms/samd/samd.ld
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
28
src/platforms/samd/samd_boot.ld
Normal file
28
src/platforms/samd/samd_boot.ld
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
57
src/platforms/samd/traceswo.c
Normal file
57
src/platforms/samd/traceswo.c
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
}
|
251
src/platforms/samd/usbuart.c
Normal file
251
src/platforms/samd/usbuart.c
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
* 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();
|
||||||
|
}
|
134
src/platforms/stm32/rtt_if.c
Normal file
134
src/platforms/stm32/rtt_if.c
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
@ -259,6 +259,7 @@ static void usbuart_change_dma_tx_buf(void)
|
|||||||
buf_tx_act_idx ^= 1;
|
buf_tx_act_idx ^= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef ENABLE_RTT
|
||||||
void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
|
void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
|
||||||
{
|
{
|
||||||
(void)ep;
|
(void)ep;
|
||||||
@ -301,6 +302,7 @@ void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
|
|||||||
if (TX_BUF_SIZE - buf_tx_act_sz >= CDCACM_PACKET_SIZE)
|
if (TX_BUF_SIZE - buf_tx_act_sz >= CDCACM_PACKET_SIZE)
|
||||||
usbd_ep_nak_set(dev, CDCACM_UART_ENDPOINT, 0);
|
usbd_ep_nak_set(dev, CDCACM_UART_ENDPOINT, 0);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USBUART_DEBUG
|
#ifdef USBUART_DEBUG
|
||||||
int usbuart_debug_write(const char *buf, size_t len)
|
int usbuart_debug_write(const char *buf, size_t len)
|
||||||
|
@ -99,6 +99,7 @@ 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 usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
|
||||||
{
|
{
|
||||||
(void)ep;
|
(void)ep;
|
||||||
@ -110,7 +111,7 @@ void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
|
|||||||
for(int i = 0; i < len; i++)
|
for(int i = 0; i < len; i++)
|
||||||
uart_send_blocking(USBUART, buf[i]);
|
uart_send_blocking(USBUART, buf[i]);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep)
|
void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep)
|
||||||
{
|
{
|
||||||
|
456
src/rtt.c
Normal file
456
src/rtt.c
Normal file
@ -0,0 +1,456 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
@ -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)
|
int adiv5_swdp_scan(uint32_t targetid)
|
||||||
{
|
{
|
||||||
volatile struct exception e;
|
volatile struct exception e;
|
||||||
target_list_free();
|
static bool scan_multidrop = true;
|
||||||
ADIv5_DP_t idp = {
|
ADIv5_DP_t idp = {
|
||||||
.dp_low_write = firmware_dp_low_write,
|
.dp_low_write = firmware_dp_low_write,
|
||||||
.error = firmware_swdp_error,
|
.error = firmware_swdp_error,
|
||||||
@ -77,6 +77,7 @@ int adiv5_swdp_scan(uint32_t targetid)
|
|||||||
.abort = firmware_swdp_abort,
|
.abort = firmware_swdp_abort,
|
||||||
};
|
};
|
||||||
ADIv5_DP_t *initial_dp = &idp;
|
ADIv5_DP_t *initial_dp = &idp;
|
||||||
|
target_list_free();
|
||||||
if (swdptap_init(initial_dp))
|
if (swdptap_init(initial_dp))
|
||||||
return -1;
|
return -1;
|
||||||
/* DORMANT-> SWD sequence*/
|
/* DORMANT-> SWD sequence*/
|
||||||
@ -93,7 +94,6 @@ int adiv5_swdp_scan(uint32_t targetid)
|
|||||||
initial_dp->seq_out(0x1a0, 12);
|
initial_dp->seq_out(0x1a0, 12);
|
||||||
uint32_t idcode = 0;
|
uint32_t idcode = 0;
|
||||||
volatile uint32_t target_id = 0;
|
volatile uint32_t target_id = 0;
|
||||||
bool scan_multidrop = true;
|
|
||||||
if (!targetid || !initial_dp->dp_low_write) {
|
if (!targetid || !initial_dp->dp_low_write) {
|
||||||
/* No targetID given on the command line or probe can not
|
/* No targetID given on the command line or probe can not
|
||||||
* handle multi-drop. Try to read ID */
|
* handle multi-drop. Try to read ID */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user