Compare commits
186 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 | ||
|
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 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -16,7 +16,10 @@ tags
|
||||
*.b#*
|
||||
blackmagic_upgrade
|
||||
*.exe
|
||||
.DS_Store
|
||||
*.elf
|
||||
.vscode
|
||||
cscope.out
|
||||
cscope.files
|
||||
.gdb_history
|
||||
src/artifacts/
|
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -1,3 +1,3 @@
|
||||
[submodule "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 update ;\
|
||||
fi
|
||||
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib/stm32/f1 lib/stm32/f4 lib/lm4f
|
||||
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib/sam/d
|
||||
endif
|
||||
$(Q)$(MAKE) $(MFLAGS) -C src
|
||||
|
||||
all_platforms:
|
||||
$(Q)$(MAKE) $(MFLAGS) -C src $@
|
||||
|
||||
clean:
|
||||
ifndef NO_LIBOPENCM3
|
||||
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 $@
|
||||
endif
|
||||
$(Q)$(MAKE) $(MFLAGS) -C src $@
|
||||
|
||||
clang-tidy:
|
||||
$(Q)scripts/run-clang-tidy.py -s "$(PWD)"
|
||||
|
||||
clang-format:
|
||||
$(Q)$(MAKE) $(MFLAGS) -C src $@
|
||||
|
||||
.PHONY: clean all_platforms clang-tidy clang-format
|
||||
|
153
README.md
153
README.md
@ -1,113 +1,54 @@
|
||||
Black Magic 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
|
||||
Jeff Probe
|
||||
==========
|
||||
|
||||
You can also build blackmagic as a PC hosted application
|
||||
"make PROBE_HOST=hosted"
|
||||
This is a fork of the [original Black Magic Probe](https://github.com/blacksphere/blackmagic).
|
||||
|
||||
This builds the same GDB server, that is running on the Black Magic Probe.
|
||||
While connection to the Black Magic Probe GDB server is via serial line,
|
||||
connection to the PC-Hosted GDB server is via TCP port 2000 for the first
|
||||
GDB server and higher for more invokations. Use "tar(get) ext(ented) :2000"
|
||||
to connect.
|
||||
PC-hosted BMP GDB server can talk to
|
||||
- Black Magic Probe firmware probes via the USB-serial port
|
||||
- ST-LinkV2 and V3 with recent firmware
|
||||
- CMSIS-DAP compatible probes
|
||||
- JLINK probes
|
||||
- FTDI MPSSE based probe.
|
||||
The original is arguably better, faster and wider supported. However, this
|
||||
project was a way to offer an affordable version and I'll rely on community
|
||||
support and pull requests.
|
||||
|
||||
When connected to a single BMP supported probe, starting "blackmagic" w/o any
|
||||
arguments starts the server. When several BMP supported probes are connected,
|
||||
their types, position and serial number is displayed and the program exits.
|
||||
Add "-P (position)" to the next invocation to select one.
|
||||
For the setup from the sample session above:
|
||||
In another terminal:
|
||||
```console
|
||||
> blackmagic
|
||||
Using 1d50:6018 E2E489E7 Black Sphere Technologies Black Magic Probe (STLINK), (Firmware v1.6.1-477-g70bb131-dirty)
|
||||
Remote is Black Magic Probe (STLINK), (Firmware v1.6.1-477-g70bb131-dirty) v1.6.1-477-g70bb131-dirty
|
||||
Listening on TCP: 2000
|
||||
And in the GDB terminal:
|
||||
(gdb) target ext :2000
|
||||
Remote debugging using :2000
|
||||
(gdb) mon s
|
||||
...
|
||||
One urguably better funncton is the ability to do DEBUG and Serial communication
|
||||
over a single JTAG cable when paired with a device that uses single wire JTAG.
|
||||
|
||||
Normally, the serial header can be used on a target for the serial port, and
|
||||
shows up as the second serial device on the system, however, we can dynamically
|
||||
change the pins to use the ones on the JTAG cable with the following command:
|
||||
|
||||
``` bash
|
||||
$ mon convert_tdio enable
|
||||
```
|
||||
|
||||
PC hosted BMP also allows to flash, read and verify a binary file, by default
|
||||
starting at lowest flash address. The "-t" argument displays information about the
|
||||
connected target. Use "-h " to get a list of supported options.
|
||||
Compilation
|
||||
---
|
||||
|
||||
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
|
||||
# there are two connections, one for GDB and one for UART debugging
|
||||
# copy this to /etc/udev/rules.d/99-blackmagic.rules
|
||||
# and run /usr/sbin/udevadm control --reload-rules
|
||||
SUBSYSTEM=="tty", ACTION=="add", ATTRS{interface}=="Black Magic GDB Server", SYMLINK+="ttyBmpGdb"
|
||||
SUBSYSTEM=="tty", ACTION=="add", ATTRS{interface}=="Black Magic UART Port", SYMLINK+="ttyBmpTarg"
|
||||
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTR{idVendor}=="1d50", ATTR{idProduct}=="6017", MODE="0666"
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 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
|
||||
|
||||
CFLAGS += -Wall -Wextra -Werror -Wno-char-subscripts \
|
||||
-std=gnu99 -g3 -MD -I./target \
|
||||
-std=gnu99 -MD -I./target \
|
||||
-I. -Iinclude -I$(PLATFORM_DIR)
|
||||
|
||||
ifeq ($(ENABLE_DEBUG), 1)
|
||||
@ -65,11 +65,6 @@ SRC = \
|
||||
|
||||
include $(PLATFORM_DIR)/Makefile.inc
|
||||
|
||||
ifneq ($(PC_HOSTED),1)
|
||||
# Output memory usage information
|
||||
LDFLAGS += -Wl,--print-memory-usage
|
||||
endif
|
||||
|
||||
OPT_FLAGS ?= -Os
|
||||
CFLAGS += $(OPT_FLAGS)
|
||||
LDFLAGS += $(OPT_FLAGS)
|
||||
@ -95,8 +90,28 @@ VPATH += platforms/common
|
||||
CFLAGS += -Iplatforms/common
|
||||
endif
|
||||
|
||||
ifeq ($(ENABLE_RTT), 1)
|
||||
CFLAGS += -DENABLE_RTT
|
||||
SRC += rtt.c rtt_if.c
|
||||
endif
|
||||
|
||||
ifdef RTT_IDENT
|
||||
CFLAGS += -DRTT_IDENT=$(RTT_IDENT)
|
||||
endif
|
||||
|
||||
OBJ = $(patsubst %.S,%.o,$(patsubst %.c,%.o,$(SRC)))
|
||||
|
||||
OPTIMIZE := swdptap.o jtagtap.o \
|
||||
adiv5_jtagdp.o adiv5_swdp.o adiv5.o \
|
||||
cortexa.o cortexm.o \
|
||||
gdb_if.o gdb_main.o gdb_hostio.o gdb_packet.o \
|
||||
jtag_devs.o jtag_scan.o \
|
||||
crc32.o main.o \
|
||||
cdcacm.o jeff.o timing.o traceswo.o usbuart.o \
|
||||
|
||||
$(OPTIMIZE):: CFLAGS := $(filter-out -Os, $(CFLAGS))
|
||||
$(OPTIMIZE):: CFLAGS += -O3
|
||||
|
||||
$(TARGET): include/version.h $(OBJ)
|
||||
@echo " LD $@"
|
||||
$(Q)$(CC) -o $@ $(OBJ) $(LDFLAGS)
|
||||
@ -112,14 +127,14 @@ $(TARGET): include/version.h $(OBJ)
|
||||
ifndef PC_HOSTED
|
||||
%.bin: %.elf
|
||||
@echo " OBJCOPY $@"
|
||||
$(Q)$(OBJCOPY) -O binary $^ $@
|
||||
$(Q)$(OBJCOPY) $(OBJCOPY_FLAGS) -O binary $^ $@
|
||||
|
||||
%.hex: %.elf
|
||||
@echo " OBJCOPY $@"
|
||||
$(Q)$(OBJCOPY) -O ihex $^ $@
|
||||
endif
|
||||
|
||||
.PHONY: clean host_clean all_platforms FORCE
|
||||
.PHONY: clean host_clean all_platforms clang-format FORCE
|
||||
|
||||
clean: host_clean
|
||||
$(Q)echo " CLEAN"
|
||||
@ -127,16 +142,27 @@ clean: host_clean
|
||||
-$(Q)$(RM) platforms/*/*.o platforms/*/*.d mapfile include/version.h
|
||||
|
||||
all_platforms:
|
||||
$(Q)if [ ! -f ../libopencm3/Makefile ]; then \
|
||||
echo "Initialising git submodules..." ;\
|
||||
git submodule init ;\
|
||||
git submodule update ;\
|
||||
fi
|
||||
$(Q)$(MAKE) $(MFLAGS) -C ../libopencm3 lib/stm32/f1 lib/stm32/f4 lib/lm4f
|
||||
$(Q)set -e ;\
|
||||
mkdir -p artifacts/$(shell git describe --always --dirty --tags) ;\
|
||||
echo "<html><body><ul>" > artifacts/index.html ;\
|
||||
$(MAKE) clean ;\
|
||||
for i in platforms/*/Makefile.inc ; do \
|
||||
export DIRNAME=`dirname $$i` ;\
|
||||
export PROBE_HOST=`basename $$DIRNAME` ;\
|
||||
export CFLAGS=-Werror ;\
|
||||
echo "Building for hardware platform: $$PROBE_HOST" ;\
|
||||
$(MAKE) clean ;\
|
||||
$(MAKE);\
|
||||
if [ -f blackmagic ]; then \
|
||||
mv blackmagic artifacts/blackmagic-$$PROBE_HOST ;\
|
||||
echo "<li><a href='blackmagic-$$PROBE_HOST'>$$PROBE_HOST</a></li>"\
|
||||
>> artifacts/index.html ;\
|
||||
fi ;\
|
||||
if [ -f blackmagic.bin ]; then \
|
||||
mv blackmagic.bin artifacts/blackmagic-$$PROBE_HOST.bin ;\
|
||||
echo "<li><a href='blackmagic-$$PROBE_HOST.bin'>$$PROBE_HOST</a></li>"\
|
||||
@ -147,13 +173,31 @@ all_platforms:
|
||||
echo "<li><a href='blackmagic_dfu-$$PROBE_HOST.bin'>$$PROBE_HOST DFU</a></li>"\
|
||||
>> artifacts/index.html ;\
|
||||
fi ;\
|
||||
$(MAKE) clean ;\
|
||||
done ;\
|
||||
echo "</ul></body></html>" >> artifacts/index.html ;\
|
||||
cp artifacts/*.bin artifacts/$(shell git describe --always --dirty --tags)
|
||||
cp artifacts/blackmagic* artifacts/$(shell git describe --always --dirty --tags)
|
||||
|
||||
command.c: include/version.h
|
||||
|
||||
GIT_VERSION := $(shell git describe --always --dirty --tags)
|
||||
VERSION_HEADER := \#define FIRMWARE_VERSION "$(GIT_VERSION)"
|
||||
|
||||
include/version.h: FORCE
|
||||
$(Q)echo " GIT include/version.h"
|
||||
$(Q)echo "#define FIRMWARE_VERSION \"$(shell git describe --always --dirty --tags)\"" > $@
|
||||
@# If git isn't found then GIT_VERSION will be an empty string.
|
||||
ifeq ($(GIT_VERSION),)
|
||||
@echo Git not found, assuming up to date include/version.h
|
||||
else
|
||||
@# Note that when we echo the version to the header file, echo writes a final newline
|
||||
@# to the file. This is fine and probably makes the file more human-readable, but
|
||||
@# also means we have to account for that newline in this comparison.
|
||||
$(Q)if [ ! -f $@ ] || [ "$$(cat $@)" != "$$(echo '$(VERSION_HEADER)\n')" ]; then \
|
||||
echo " GEN $@"; \
|
||||
echo '$(VERSION_HEADER)' > $@; \
|
||||
fi
|
||||
endif
|
||||
|
||||
clang-format:
|
||||
$(Q)clang-format -i *.c */*.c */*/*.c *.h */*.h */*/*.h
|
||||
|
||||
-include *.d
|
||||
|
166
src/command.c
166
src/command.c
@ -34,11 +34,18 @@
|
||||
#include "version.h"
|
||||
#include "serialno.h"
|
||||
|
||||
#ifdef ENABLE_RTT
|
||||
#include "rtt.h"
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_HAS_TRACESWO
|
||||
# include "traceswo.h"
|
||||
#endif
|
||||
|
||||
static bool cmd_version(target *t, int argc, char **argv);
|
||||
#ifdef PLATFORM_HAS_PRINTSERIAL
|
||||
static bool cmd_serial(target *t, int argc, char **argv);
|
||||
#endif
|
||||
static bool cmd_help(target *t, int argc, char **argv);
|
||||
|
||||
static bool cmd_jtag_scan(target *t, int argc, char **argv);
|
||||
@ -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);
|
||||
#endif
|
||||
static bool cmd_heapinfo(target *t, int argc, const char **argv);
|
||||
#ifdef ENABLE_RTT
|
||||
static bool cmd_rtt(target *t, int argc, const char **argv);
|
||||
#endif
|
||||
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
|
||||
static bool cmd_debug_bmp(target *t, int argc, const char **argv);
|
||||
#endif
|
||||
#ifdef PLATFORM_HAS_UART_WHEN_SWDP
|
||||
static bool cmd_convert_tdio(target *t, int argc, const char **argv);
|
||||
static bool cmd_set_srst(target *t, int argc, const char **argv);
|
||||
#endif
|
||||
#ifdef PLATFORM_HAS_BOOTLOADER
|
||||
static bool cmd_enter_bootldr(target *t, int argc, const char **argv);
|
||||
#endif
|
||||
|
||||
const struct command_s cmd_list[] = {
|
||||
{"version", (cmd_handler)cmd_version, "Display firmware version info"},
|
||||
#ifdef PLATFORM_HAS_PRINTSERIAL
|
||||
{"serial", (cmd_handler)cmd_serial, "Display firmware serial number"},
|
||||
#endif
|
||||
{"help", (cmd_handler)cmd_help, "Display help for monitor commands"},
|
||||
{"jtag_scan", (cmd_handler)cmd_jtag_scan, "Scan JTAG chain for devices" },
|
||||
{"swdp_scan", (cmd_handler)cmd_swdp_scan, "Scan SW-DP for devices" },
|
||||
@ -74,6 +94,9 @@ const struct command_s cmd_list[] = {
|
||||
#ifdef PLATFORM_HAS_POWER_SWITCH
|
||||
{"tpwr", (cmd_handler)cmd_target_power, "Supplies power to the target: (enable|disable)"},
|
||||
#endif
|
||||
#ifdef ENABLE_RTT
|
||||
{"rtt", (cmd_handler)cmd_rtt, "enable|disable|status|channel 0..15|ident (str)|cblock|poll maxms minms maxerr" },
|
||||
#endif
|
||||
#ifdef PLATFORM_HAS_TRACESWO
|
||||
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2
|
||||
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, NRZ mode: (baudrate) (decode channel ...)" },
|
||||
@ -84,6 +107,13 @@ const struct command_s cmd_list[] = {
|
||||
{"heapinfo", (cmd_handler)cmd_heapinfo, "Set semihosting heapinfo" },
|
||||
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
|
||||
{"debug_bmp", (cmd_handler)cmd_debug_bmp, "Output BMP \"debug\" strings to the second vcom: (enable|disable)"},
|
||||
#endif
|
||||
#ifdef PLATFORM_HAS_UART_WHEN_SWDP
|
||||
{"convert_tdio", (cmd_handler)cmd_convert_tdio,"Switch TDI/O pins to UART TX/RX functions"},
|
||||
{"set_srst", (cmd_handler)cmd_set_srst,"Set output state of SRST pin (enable|disable)"},
|
||||
#endif
|
||||
#ifdef PLATFORM_HAS_BOOTLOADER
|
||||
{"enter_bootldr", (cmd_handler)cmd_enter_bootldr,"Force BMP into bootloader mode"},
|
||||
#endif
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
@ -410,6 +440,82 @@ static bool cmd_target_power(target *t, int argc, const char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_RTT
|
||||
static const char *on_or_off(const bool value)
|
||||
{
|
||||
return value ? "on" : "off";
|
||||
}
|
||||
|
||||
static bool cmd_rtt(target *t, int argc, const char **argv)
|
||||
{
|
||||
(void)t;
|
||||
const size_t command_len = strlen(argv[1]);
|
||||
if (argc == 1 || (argc == 2 && !strncmp(argv[1], "enabled", command_len))) {
|
||||
rtt_enabled = true;
|
||||
rtt_found = false;
|
||||
} else if ((argc == 2) && !strncmp(argv[1], "disabled", command_len)) {
|
||||
rtt_enabled = false;
|
||||
rtt_found = false;
|
||||
} else if ((argc == 2) && !strncmp(argv[1], "status", command_len)) {
|
||||
gdb_outf("rtt: %s found: %s ident: \"%s\"", on_or_off(rtt_enabled), rtt_found ? "yes" : "no",
|
||||
rtt_ident[0] == '\0' ? "off" : rtt_ident);
|
||||
gdb_outf(" halt: %s", on_or_off(target_no_background_memory_access(t)));
|
||||
gdb_out(" channels: ");
|
||||
if (rtt_auto_channel)
|
||||
gdb_out("auto ");
|
||||
for (size_t i = 0; i < MAX_RTT_CHAN; i++) {
|
||||
if (rtt_channel[i].is_enabled)
|
||||
gdb_outf("%d ", i);
|
||||
}
|
||||
gdb_outf(
|
||||
"\nmax poll ms: %u min poll ms: %u max errs: %u\n", rtt_max_poll_ms, rtt_min_poll_ms, rtt_max_poll_errs);
|
||||
} else if (argc >= 2 && !strncmp(argv[1], "channel", command_len)) {
|
||||
/* mon rtt channel switches to auto rtt channel selection
|
||||
mon rtt channel number... selects channels given */
|
||||
for (size_t i = 0; i < MAX_RTT_CHAN; i++)
|
||||
rtt_channel[i].is_enabled = false;
|
||||
|
||||
if (argc == 2)
|
||||
rtt_auto_channel = true;
|
||||
else {
|
||||
rtt_auto_channel = false;
|
||||
for (size_t i = 2; i < (size_t)argc; ++i) {
|
||||
const uint32_t channel = strtoul(argv[i], NULL, 0);
|
||||
if (channel < MAX_RTT_CHAN)
|
||||
rtt_channel[channel].is_enabled = true;
|
||||
}
|
||||
}
|
||||
} else if (argc == 2 && !strncmp(argv[1], "ident", command_len))
|
||||
rtt_ident[0] = '\0';
|
||||
else if (argc == 2 && !strncmp(argv[1], "poll", command_len))
|
||||
gdb_outf("%u %u %u\n", rtt_max_poll_ms, rtt_min_poll_ms, rtt_max_poll_errs);
|
||||
else if (argc == 2 && !strncmp(argv[1], "cblock", command_len)) {
|
||||
gdb_outf("cbaddr: 0x%x\n", rtt_cbaddr);
|
||||
gdb_out("ch ena cfg i/o buf@ size head@ tail@ flg\n");
|
||||
for (size_t i = 0; i < MAX_RTT_CHAN; ++i) {
|
||||
gdb_outf("%2zu %c %c %s 0x%08x %5d 0x%08x 0x%08x %d\n", i, rtt_channel[i].is_enabled ? 'y' : 'n',
|
||||
rtt_channel[i].is_configured ? 'y' : 'n', rtt_channel[i].is_output ? "out" : "in ",
|
||||
rtt_channel[i].buf_addr, rtt_channel[i].buf_size, rtt_channel[i].head_addr, rtt_channel[i].tail_addr,
|
||||
rtt_channel[i].flag);
|
||||
}
|
||||
} else if (argc == 3 && !strncmp(argv[1], "ident", command_len)) {
|
||||
strncpy(rtt_ident, argv[2], sizeof(rtt_ident));
|
||||
rtt_ident[sizeof(rtt_ident) - 1] = '\0';
|
||||
for (size_t i = 0; i < sizeof(rtt_ident); i++) {
|
||||
if (rtt_ident[i] == '_')
|
||||
rtt_ident[i] = ' ';
|
||||
}
|
||||
} else if (argc == 5 && !strncmp(argv[1], "poll", command_len)) {
|
||||
/* set polling params */
|
||||
rtt_max_poll_ms = strtoul(argv[2], NULL, 0);
|
||||
rtt_min_poll_ms = strtoul(argv[3], NULL, 0);
|
||||
rtt_max_poll_errs = strtoul(argv[4], NULL, 0);
|
||||
} else
|
||||
gdb_out("what?\n");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_HAS_TRACESWO
|
||||
static bool cmd_traceswo(target *t, int argc, const char **argv)
|
||||
{
|
||||
@ -487,6 +593,66 @@ static bool cmd_debug_bmp(target *t, int argc, const char **argv)
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_HAS_UART_WHEN_SWDP
|
||||
static bool cmd_convert_tdio(target *t, int argc, const char **argv)
|
||||
{
|
||||
(void)t;
|
||||
|
||||
uint8_t val;
|
||||
if (argc > 1) {
|
||||
val = (!strcmp(argv[1], "enable")) ? true : false;
|
||||
usbuart_convert_tdio(val);
|
||||
} else {
|
||||
gdb_outf("Convert_tdio: %s\n",(usbuart_convert_tdio_enabled()) ?
|
||||
"enabled" : "disabled");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool cmd_set_srst(target *t, int argc, const char **argv)
|
||||
{
|
||||
(void) t;
|
||||
|
||||
uint8_t val;
|
||||
if (argc > 1) {
|
||||
val = (!strcmp(argv[1], "enable")) ? true : false;
|
||||
platform_srst_set_val(val);
|
||||
} else {
|
||||
gdb_outf("SRST: %s\n",(platform_srst_get_val()) ?
|
||||
"enabled" : "disabled");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_HAS_BOOTLOADER
|
||||
static bool cmd_enter_bootldr(target *t, int argc, const char **argv)
|
||||
{
|
||||
(void) t;
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
scb_reset_system();
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PLATFORM_HAS_PRINTSERIAL
|
||||
bool cmd_serial(target *t, int argc, char **argv)
|
||||
{
|
||||
(void) t;
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
print_serial();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool cmd_heapinfo(target *t, int argc, const char **argv)
|
||||
{
|
||||
if (t == NULL) gdb_out("not attached\n");
|
||||
|
@ -35,6 +35,9 @@
|
||||
#include "command.h"
|
||||
#include "crc32.h"
|
||||
#include "morse.h"
|
||||
#ifdef ENABLE_RTT
|
||||
#include "rtt.h"
|
||||
#endif
|
||||
|
||||
enum gdb_signal {
|
||||
GDB_SIGINT = 2,
|
||||
@ -208,8 +211,12 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
|
||||
/* Wait for target halt */
|
||||
while(!(reason = target_halt_poll(cur_target, &watch))) {
|
||||
char c = (char)gdb_if_getchar_to(0);
|
||||
if(c == '\x03' || c == '\x04')
|
||||
if(c == '\x03' || c == '\x04') {
|
||||
target_halt_request(cur_target);
|
||||
}
|
||||
#ifdef ENABLE_RTT
|
||||
if (rtt_enabled) poll_rtt(cur_target);
|
||||
#endif
|
||||
}
|
||||
SET_RUN_STATE(0);
|
||||
|
||||
@ -580,6 +587,10 @@ static void handle_v_packet(char *packet, const size_t plen)
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifdef ENABLE_RTT
|
||||
/* force searching rtt control block */
|
||||
rtt_found = false;
|
||||
#endif
|
||||
/* Run target program. For us (embedded) this means reset. */
|
||||
if (cur_target) {
|
||||
target_set_cmdline(cur_target, cmdline);
|
||||
|
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 */
|
||||
.bDeviceSubClass = 2, /* Common Class */
|
||||
.bDeviceProtocol = 1, /* Interface Association */
|
||||
#ifdef LM4F
|
||||
#if defined(SAMD21E17) || defined(LM4F)
|
||||
.bMaxPacketSize0 = 64, /*Fixed for icdi*/
|
||||
#else
|
||||
.bMaxPacketSize0 = 32,
|
||||
@ -435,6 +435,8 @@ static void dfu_detach_complete(usbd_device *dev, struct usb_setup_data *req)
|
||||
/* Reset core to enter bootloader */
|
||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||
scb_reset_core();
|
||||
#else
|
||||
scb_reset_system();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -524,7 +526,7 @@ static void cdcacm_set_config(usbd_device *dev, uint16_t wValue)
|
||||
configured = wValue;
|
||||
|
||||
/* 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,
|
||||
CDCACM_PACKET_SIZE, gdb_usb_out_cb);
|
||||
#else
|
||||
@ -580,6 +582,7 @@ void cdcacm_init(void)
|
||||
|
||||
nvic_set_priority(USB_IRQ, IRQ_PRI_USB);
|
||||
nvic_enable_irq(USB_IRQ);
|
||||
usbd_disconnect(usbdev, false);
|
||||
}
|
||||
|
||||
void USB_ISR(void)
|
||||
|
@ -30,6 +30,10 @@
|
||||
#include "gdb_if.h"
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef ENABLE_RTT
|
||||
#include "rtt_if.h"
|
||||
#endif
|
||||
|
||||
#include "bmp_remote.h"
|
||||
#include "bmp_hosted.h"
|
||||
#include "stlinkv2.h"
|
||||
@ -58,6 +62,9 @@ static void exit_function(void)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#ifdef ENABLE_RTT
|
||||
rtt_if_exit();
|
||||
#endif
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
@ -110,6 +117,9 @@ void platform_init(int argc, char **argv)
|
||||
exit(cl_execute(&cl_opts));
|
||||
else {
|
||||
gdb_if_init();
|
||||
#ifdef ENABLE_RTT
|
||||
rtt_if_init();
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
#ifndef ENABLE_RTT
|
||||
void usbuart_usb_out_cb(usbd_device *dev, uint8_t 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)
|
||||
usbd_ep_nak_set(dev, CDCACM_UART_ENDPOINT, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USBUART_DEBUG
|
||||
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)ep;
|
||||
@ -110,7 +111,7 @@ void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
|
||||
for(int i = 0; i < len; i++)
|
||||
uart_send_blocking(USBUART, buf[i]);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep)
|
||||
{
|
||||
|
456
src/rtt.c
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)
|
||||
{
|
||||
volatile struct exception e;
|
||||
target_list_free();
|
||||
static bool scan_multidrop = true;
|
||||
ADIv5_DP_t idp = {
|
||||
.dp_low_write = firmware_dp_low_write,
|
||||
.error = firmware_swdp_error,
|
||||
@ -77,6 +77,7 @@ int adiv5_swdp_scan(uint32_t targetid)
|
||||
.abort = firmware_swdp_abort,
|
||||
};
|
||||
ADIv5_DP_t *initial_dp = &idp;
|
||||
target_list_free();
|
||||
if (swdptap_init(initial_dp))
|
||||
return -1;
|
||||
/* DORMANT-> SWD sequence*/
|
||||
@ -93,7 +94,6 @@ int adiv5_swdp_scan(uint32_t targetid)
|
||||
initial_dp->seq_out(0x1a0, 12);
|
||||
uint32_t idcode = 0;
|
||||
volatile uint32_t target_id = 0;
|
||||
bool scan_multidrop = true;
|
||||
if (!targetid || !initial_dp->dp_low_write) {
|
||||
/* No targetID given on the command line or probe can not
|
||||
* handle multi-drop. Try to read ID */
|
||||
|
Loading…
x
Reference in New Issue
Block a user