Compare commits

..

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

174 changed files with 3620 additions and 12175 deletions

40
.gitattributes vendored
View File

@ -1,40 +0,0 @@
# Text for humans
LICENSE text eol=lf
HACKING text eol=lf
COPYING text eol=lf
UsingSWO text eol=lf
README.* text eol=lf
# Source code
Makefile text eol=lf
*.mk text eol=lf
*.mak text eol=lf
*.inc text eol=lf
*.py text eol=lf
*.sh text eol=lf
*.c text eol=lf
*.S text eol=lf
*.s text eol=lf
*.h text eol=lf
*.ld text eol=lf
*.yml text eol=lf
*.rules text eol=lf
# Git control files
.gitattributes eol=lf
.gitignore eol=lf
.gitmodules eol=lf
# Windows source code uses CRLF
*.vcxproj text eol=crlf
*.props text eol=crlf
*.bat text eol=crlf
*.ps1 text eol=crlf
*.inf text eol=crlf
# Other binary files
*.png binary
*.jpg binary
*.bin binary
*.elf binary
*.bin binary

2
.github/FUNDING.yml vendored
View File

@ -1,2 +0,0 @@
github: [esden, dragonmux]
patreon: 1bitsquared

View File

@ -1,36 +0,0 @@
name: build and upload
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ master ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
# Use embedded toolchain
- uses: numworks/setup-arm-toolchain@2020-q4
# Runs a single command using the runners shell
- name: Build
run: make
- name: Archive firmware build artifacts as a zip
uses: actions/upload-artifact@v2.2.4
with:
name: blackmagic-firmware.zip
path: src/blackmagic*
if-no-files-found: error

View File

@ -1,38 +0,0 @@
name: build PR
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the main branch
pull_request:
branches: [ master ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
# Use embedded toolchain
- uses: numworks/setup-arm-toolchain@2020-q4
# Run some of the most common build types
- name: Build native fw
run: make
- name: Clean
run: make clean
- name: Install BMP PC hosted dependencies
run: sudo apt-get -y install libftdi1-dev libhidapi-dev
- name: Build PC hosted binary
run: make PROBE_HOST=hosted

5
.gitignore vendored
View File

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

2
.gitmodules vendored
View File

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

View File

@ -1,11 +1,42 @@
dist: bionic dist: trusty
sudo: required sudo: required
before_install: before_install:
- sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa - sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa
- sudo apt-get update -qq - sudo apt-get update -qq
- pip install --user intelhex - pip install --user intelhex
- sudo apt-get install -y build-essential libboost-all-dev gcc-arm-embedded libusb-1.0-0-dev libhidapi-dev libftdi1 libftdi1-dev - gpg --recv-keys 3CEA9B8868BC3852618EB5B4707F91A424F006F5
- wget http://www.intra2net.com/en/developer/libftdi/download/libftdi1-1.2.tar.bz2
- wget http://www.intra2net.com/en/developer/libftdi/download/libftdi1-1.2.tar.bz2.sig
- gpg --trust-model always --verify libftdi1-1.2.tar.bz2.sig
- tar -xjf libftdi1-1.2.tar.bz2
- sudo apt-get install -y build-essential libboost-all-dev gcc-arm-embedded libusb-1.0-0-dev libhidapi-dev
install:
- cd libftdi1-1.2
- if [ "$TRAVIS_OS_NAME" = "linux" ];
then
sudo apt-get update -qq;
if [ "$ARCH" = "x86_64" ];
then
sudo apt-get install -qq libusb-1.0-0-dev;
elif [ "$ARCH" = "i386" ];
then
sudo apt-get install -qq gcc-multilib libusb-1.0-0-dev:i386 pkg-config:i386;
export CFLAGS="-m32";
fi
fi
- if [ "$TRAVIS_OS_NAME" = "osx" ];
then
brew update;
brew install libusb;
fi
- mkdir build
- cd build
- cmake ../
- make
- sudo make install
- cd ../../
script: script:
- make -C libopencm3 lib - make -C libopencm3 lib

View File

@ -1 +1 @@
See https://github.com/blackmagic-debug/blackmagic/wiki/Hacking See https://github.com/blacksphere/blackmagic/wiki/Hacking

View File

@ -5,6 +5,14 @@ endif
PC_HOSTED = PC_HOSTED =
NO_LIBOPENCM3 = NO_LIBOPENCM3 =
ifeq ($(PROBE_HOST), libftdi)
PC_HOSTED = true
NO_LIBOPENCM3 = true
endif
ifeq ($(PROBE_HOST), pc-stlinkv2)
PC_HOSTED = true
NO_LIBOPENCM3 = true
endif
ifeq ($(PROBE_HOST), hosted) ifeq ($(PROBE_HOST), hosted)
PC_HOSTED = true PC_HOSTED = true
NO_LIBOPENCM3 = true NO_LIBOPENCM3 = true
@ -17,23 +25,13 @@ ifndef NO_LIBOPENCM3
git submodule init ;\ git submodule init ;\
git submodule update ;\ git submodule update ;\
fi fi
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib/sam/d $(Q)$(MAKE) $(MFLAGS) -C libopencm3 lib
endif endif
$(Q)$(MAKE) $(MFLAGS) -C src $(Q)$(MAKE) $(MFLAGS) -C src
all_platforms:
$(Q)$(MAKE) $(MFLAGS) -C src $@
clean: clean:
ifndef NO_LIBOPENCM3 ifndef NO_LIBOPENCM3
$(Q)$(MAKE) $(MFLAGS) -C libopencm3 $@ $(Q)$(MAKE) $(MFLAGS) -C libopencm3 $@
endif endif
$(Q)$(MAKE) $(MFLAGS) -C src $@ $(Q)$(MAKE) $(MFLAGS) -C src $@
clang-tidy:
$(Q)scripts/run-clang-tidy.py -s "$(PWD)"
clang-format:
$(Q)$(MAKE) $(MFLAGS) -C src $@
.PHONY: clean all_platforms clang-tidy clang-format

153
README.md
View File

@ -1,54 +1,111 @@
Jeff Probe Black Magic Probe
========== =================
This is a fork of the [original Black Magic Probe](https://github.com/blacksphere/blackmagic). [![Build Status](https://travis-ci.org/blacksphere/blackmagic.svg?branch=master)](https://travis-ci.org/blacksphere/blackmagic)
[![Discord](https://img.shields.io/discord/613131135903596547?logo=discord)](https://discord.gg/P7FYThy)
[![Donate](https://img.shields.io/badge/paypal-donate-blue.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=N84QYNAM2JJQG)
[![Kickstarter](https://img.shields.io/badge/kickstarter-back%20us-14e16e.svg)](https://www.kickstarter.com/projects/esden/1bitsy-and-black-magic-probe-demystifying-arm-prog)
The original is arguably better, faster and wider supported. However, this Firmware for the Black Magic Debug Probe.
project was a way to offer an affordable version and I'll rely on community
support and pull requests.
One urguably better funncton is the ability to do DEBUG and Serial communication The Black Magic Probe is a modern, in-application debugging tool for
over a single JTAG cable when paired with a device that uses single wire JTAG. embedded microprocessors. It allows you see what is going on 'inside' an
application running on an embedded microprocessor while it executes. It is
Normally, the serial header can be used on a target for the serial port, and able to control and examine the state of the target microprocessor using a
shows up as the second serial device on the system, however, we can dynamically JTAG or Serial Wire Debugging (SWD) port and on-chip debug logic provided
change the pins to use the ones on the JTAG cable with the following command: by the microprocessor. The probe connects to a host computer using a
standard USB interface. The user is able to control exactly what happens
``` bash using the GNU source level debugging software, GDB.
$ mon convert_tdio enable 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/blacksphere/blackmagic/wiki/Serial-Wire-Output).
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 See online documentation at https://github.com/blacksphere/blackmagic/wiki
Binaries from the latest automated build can be found on the release page. Binaries from the latest automated build are at 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.
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.
Reporting problems
==================
Before reporting issues, check against the latest git version. If possible, test against another target /and/or debug probe. Consider broken USB cables and connectors. Try to reproduce with bmp-hosted with at least debug bit 1 set (blackmagic -v 1 ...), as debug messages will be dumped to the starting console. When reporting issues, be as specific as possible!
Sample Session
=============
```console
> arm-none-eabi-gdb gpio.elf
...<GDB Copyright message>
(gdb) tar ext /dev/ttyACM0
Remote debugging using /dev/ttyACM0
(gdb) mon s
Target voltage: 2.94V
Available Targets:
No. Att Driver
1 STM32F40x M3/M4
(gdb) att 1
Attaching to program: /devel/en_apps/gpio/f4_discovery/gpio.elf, Remote target
0x08002298 in UsartIOCtl ()
(gdb) load
Loading section .text, size 0x5868 lma 0x8000000
Loading section .data, size 0x9e0 lma 0x8005868
Loading section .rodata, size 0x254 lma 0x8006248
Start address 0x800007c, load size 25756
Transfer rate: 31 KB/sec, 919 bytes/write.
(gdb) b main
Breakpoint 1 at 0x80000e8: file /devel/en_apps/gpio/f4_discovery/../gpio.c, line 70.
(gdb) r
Starting program: /devel/en_apps/gpio/f4_discovery/gpio.elf
Note: automatically using hardware breakpoints for read-only addresses.
Breakpoint 1, main () at /devel/en_apps/gpio/f4_discovery/../gpio.c:70
70 {
```
BLACKMAGIC
==========
You can also build blackmagic as a PC hosted application
"make PROBE_HOST=hosted"
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.
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
...
```
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.

View File

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

View File

@ -14,28 +14,24 @@ monitor traceswo 115200
We are constrained on maximum input speed by both the capabilities of the We are constrained on maximum input speed by both the capabilities of the
BMP STM32F103 USART and the ability to get the packets back out over the USB BMP STM32F103 USART and the ability to get the packets back out over the USB
link. The UART baudrate is set by b=(72x10^6)/d...with d >= 16 or link. The UART baudrate is set by b=(72x10^6)/(16*d)...so for d=1 that means
a maximum speed of 4.5Mbps UART1 and 2.25 Mbps on UART2. a maximum speed of 4.5Mbps. For continious streaming that turns out to be
For continious streaming that turns out to be_too_ fast for the USB _too_ fast for the USB link, so the next available option is the 2.25Mbps
link, so the next available option is the 2.25Mbps that we use. .... that we use. ....you can safely use the 4.5Mbps setting if your debug data
You can safely use the 4.5Mbps setting if your debug data
is bursty, or if you're using a different CPU to the STM32F103 as your BMP is bursty, or if you're using a different CPU to the STM32F103 as your BMP
host, but you potentially run the risk of losing packets if you have long host, but you potentially run the risk of losing packets if you have long
runs of sending which the usb cannot flush in time (there's a 12K buffer, so runs of sending which the usb cannot flush in time (there's a 12K buffer, so
the it is a pretty long run before it becomes a problem). the it is a pretty long run before it becomes a problem).
Note that the baudrate equation means there are only certain speeds Note that the baudrate equation means there are only certain speeds
available. The highest: available. The highest half dozen are;
BRR USART1(stlink) USART2(swlink) SWO uses USART1(stlink) USART2(swlink)
16 4.50 Mbps 2.25 Mbps 1 4.50 Mbps 2.25 Mbps
17 4.235 Mbps 2.118 Mbps 2 2.25 Mbps 1.125 Mbps
18 4.000 Mbps 2.0 Mbps 3 1.50 Mbps 0.75 Mbps
19 3.789 Mbps 1.895 Mbps 4 1.125 Mbps 0.5635 Mbps
20 3.600 Mbps 1.8 Mbps 5 0.900 Mbps 0.45 Mbps
... 6 0.750 Mbps 0.375 Mbps
24 3.0 Mbps 1.5 Mbps
...
36 2.0 Mbps 1.0 Mbps
...the USART will cope with some timing slip, but it's advisible to stay as ...the USART will cope with some timing slip, but it's advisible to stay as
close to these values as you can. As the speed comes down the spread between close to these values as you can. As the speed comes down the spread between

View File

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

View File

@ -13,17 +13,17 @@
Signature="$Windows NT$" Signature="$Windows NT$"
Class=Ports Class=Ports
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
Provider=%BLACKMAGIC% Provider=%BLACKSPHERE%
DriverVer=28/12/2011,0.0.1.1 DriverVer=28/12/2011,0.0.1.1
[Manufacturer] [Manufacturer]
%VendorName%=DeviceList, NTamd64 %VendorName%=DeviceList, NTamd64
[Strings] [Strings]
VendorName = "Black Magic Debug" VendorName = "Black Sphere Technologies"
BLACKMAGICGDB = "Black Magic GDB Server" BLACKMAGICGDB = "Black Magic GDB Server"
BLACKMAGICUART = "Black Magic UART Port" BLACKMAGICUART = "Black Magic UART Port"
BLACKMAGIC_DISPLAY_NAME = "Black Magic Probe Driver" BLACKSPHERE_DISPLAY_NAME = "Black Magic Probe Driver"
[DeviceList] [DeviceList]
%BLACKMAGICGDB%=DriverInstall, USB\VID_1d50&PID_6018&Rev_0100&MI_00 %BLACKMAGICGDB%=DriverInstall, USB\VID_1d50&PID_6018&Rev_0100&MI_00
@ -55,7 +55,7 @@ HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
AddService = usbser,0x0002,DriverService.nt AddService = usbser,0x0002,DriverService.nt
[DriverService.nt] [DriverService.nt]
DisplayName = %BLACKMAGIC_DISPLAY_NAME% DisplayName = %BLACKSPHERE_DISPLAY_NAME%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL ErrorControl = 1 ; SERVICE_ERROR_NORMAL
@ -80,7 +80,7 @@ HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
AddService = usbser,0x0002,DriverService.NTamd64 AddService = usbser,0x0002,DriverService.NTamd64
[DriverService.NTamd64] [DriverService.NTamd64]
DisplayName = %BLACKMAGIC_DISPLAY_NAME% DisplayName = %BLACKSPHERE_DISPLAY_NAME%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL ErrorControl = 1 ; SERVICE_ERROR_NORMAL

View File

@ -4,7 +4,7 @@
DeviceName = "Black Magic Firmware Upgrade" DeviceName = "Black Magic Firmware Upgrade"
DeviceNameDFU = "Black Magic Probe (Upgrade)" DeviceNameDFU = "Black Magic Probe (Upgrade)"
DeviceNameTPA = "Black Magic Trace Capture" DeviceNameTPA = "Black Magic Trace Capture"
VendorName = "Black Magic Debug" VendorName = "Black Sphere Technologies"
SourceName = "Black Magic Firmware Upgrade Install Disk" SourceName = "Black Magic Firmware Upgrade Install Disk"
DeviceID = "VID_1d50&PID_6018&Rev_0100&MI_04" DeviceID = "VID_1d50&PID_6018&Rev_0100&MI_04"
DeviceIDDFU= "VID_1d50&PID_6017&Rev_0100" DeviceIDDFU= "VID_1d50&PID_6017&Rev_0100"

@ -1 +1 @@
Subproject commit 63573143ef7e1b037d1f0c5baedc5264e12562b8 Subproject commit 89074d6a13ed7febba04d3c421ce7bf2b7972156

Binary file not shown.

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python
# #
# bootprog.py: STM32 SystemMemory Production Programmer -- version 1.1 # bootprog.py: STM32 SystemMemory Production Programmer -- version 1.1
# Copyright (C) 2011 Black Sphere Technologies # Copyright (C) 2011 Black Sphere Technologies
@ -28,100 +28,102 @@ class stm32_boot:
# Turn on target device in SystemMemory boot mode # Turn on target device in SystemMemory boot mode
self.serial.setDTR(1) self.serial.setDTR(1)
sleep(0.1) sleep(0.1);
self._sync() self._sync()
def _sync(self): def _sync(self):
# Send sync byte # Send sync byte
#print("sending sync byte") #print "sending sync byte"
self.serial.write(b"\x7f") self.serial.write("\x7F")
self._checkack() self._checkack()
def _sendcmd(self, cmd): def _sendcmd(self, cmd):
cmd = ord(cmd) if type(cmd) == int:
cmd = bytes((cmd, cmd ^ 0xff)) cmd = chr(cmd)
#print("sendcmd:", repr(cmd)) cmd += chr(ord(cmd) ^ 0xff)
#print "sendcmd:", repr(cmd)
self.serial.write(cmd) self.serial.write(cmd)
def _send(self, data): def _send(self, data):
csum = 0 csum = 0
for c in data: csum ^= c for c in data: csum ^= ord(c)
data = data + bytes((csum,)) data = data + chr(csum)
#print("sending:", repr(data)) #print "sending:", repr(data)
self.serial.write(data) self.serial.write(data)
def _checkack(self): def _checkack(self):
ACK = b"\x79" ACK = "\x79"
b = self.serial.read(1) b = self.serial.read(1)
if b != ACK: raise Exception("Invalid ack: %r" % b) if b != ACK: raise Exception("Invalid ack: %r" % b)
#print("got ack!") #print "got ack!"
def get(self): def get(self):
self._sendcmd(b"\x00") self._sendcmd("\x00")
self._checkack() self._checkack()
num = self.serial.read(1)[0] num = ord(self.serial.read(1))
data = self.serial.read(num+1) data = self.serial.read(num+1)
self._checkack() self._checkack()
return data return data
def eraseall(self): def eraseall(self):
# Send erase cmd # Send erase cmd
self._sendcmd(b"\x43") self._sendcmd("\x43")
self._checkack() self._checkack()
# Global erase # Global erase
self._sendcmd(b"\xff") self._sendcmd("\xff")
self._checkack() self._checkack()
def read(self, addr, len): def read(self, addr, len):
# Send read cmd # Send read cmd
self._sendcmd(b"\x11") self._sendcmd("\x11")
self._checkack() self._checkack()
# Send address # Send address
self._send(struct.pack(">L", addr)) self._send(struct.pack(">L", addr))
self._checkack() self._checkack()
# Send length # Send length
self._sendcmd(bytes((len-1,))) self._sendcmd(chr(len-1))
self._checkack() self._checkack()
return self.serial.read(len) return self.serial.read(len)
def write(self, addr, data): def write(self, addr, data):
# Send write cmd # Send write cmd
self._sendcmd(b"\x31") self._sendcmd("\x31")
self._checkack() self._checkack()
# Send address # Send address
self._send(struct.pack(">L", addr)) self._send(struct.pack(">L", addr))
self._checkack() self._checkack()
# Send data # Send data
self._send(bytes((len(data)-1,)) + data) self._send(chr(len(data)-1) + data)
self._checkack() self._checkack()
def write_protect(self, sectors): def write_protect(self, sectors):
# Send WP cmd # Send WP cmd
self._sendcmd(b"\x63") self._sendcmd("\x63")
self._checkack() self._checkack()
# Send sector list # Send sector list
self._send(bytes((len(sectors)-1,)) + bytes(sectors)) self._send(chr(len(sectors)-1) + "".join(chr(i) for i in sectors))
self._checkack() self._checkack()
# Resync after system reset # Resync after system reset
self._sync() self._sync()
def write_unprotect(self): def write_unprotect(self):
self._sendcmd(b"\x73") self._sendcmd("\x73")
self._checkack() self._checkack()
self._checkack() self._checkack()
self._sync() self._sync()
def read_protect(self): def read_protect(self):
self._sendcmd(b"\x82") self._sendcmd("\x82")
self._checkack() self._checkack()
self._checkack() self._checkack()
self._sync() self._sync()
def read_unprotect(self): def read_unprotect(self):
self._sendcmd(b"\x92") self._sendcmd("\x92")
self._checkack() self._checkack()
self._checkack() self._checkack()
self._sync() self._sync()
@ -131,12 +133,12 @@ if __name__ == "__main__":
from sys import stdout, argv, platform from sys import stdout, argv, platform
from getopt import getopt from getopt import getopt
if platform == "linux": if platform == "linux2":
print("\x1b\x5b\x48\x1b\x5b\x32\x4a") # clear terminal screen print "\x1b\x5b\x48\x1b\x5b\x32\x4a" # clear terminal screen
print("STM32 SystemMemory Production Programmer -- version 1.1") print "STM32 SystemMemory Production Programmer -- version 1.1"
print("Copyright (C) 2011 Black Sphere Technologies") print "Copyright (C) 2011 Black Sphere Technologies"
print("License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>") print "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>"
print() print
dev = "COM1" if platform == "win32" else "/dev/ttyUSB0" dev = "COM1" if platform == "win32" else "/dev/ttyUSB0"
baud = 115200 baud = 115200
@ -150,38 +152,38 @@ if __name__ == "__main__":
progfile = args[0] progfile = args[0]
except: except:
print("Usage %s [-d <dev>] [-b <baudrate>] [-a <address>] <filename>" % argv[0]) print "Usage %s [-d <dev>] [-b <baudrate>] [-a <address>] <filename>" % argv[0]
print("\t-d : Use target on interface <dev> (default: %s)" % dev) print "\t-d : Use target on interface <dev> (default: %s)" % dev
print("\t-b : Set device baudrate (default: %d)" % baud) print "\t-b : Set device baudrate (default: %d)" % baud
print("\t-a : Set programming address (default: 0x%X)" % addr) print "\t-a : Set programming address (default: 0x%X)" % addr
print() print
exit(-1) exit(-1)
prog = open(progfile, "rb").read() prog = open(progfile, "rb").read()
boot = stm32_boot(dev, baud) boot = stm32_boot(dev, baud)
cmds = boot.get() cmds = boot.get()
print("Target bootloader version: %d.%d\n" % (cmds[0] >> 4, cmds[0] % 0xf)) print "Target bootloader version: %d.%d\n" % (ord(cmds[0]) >> 4, ord(cmds[0]) % 0xf)
print("Removing device protection...") print "Removing device protection..."
boot.read_unprotect() boot.read_unprotect()
boot.write_unprotect() boot.write_unprotect()
print("Erasing target device...") print "Erasing target device..."
boot.eraseall() boot.eraseall()
addr = 0x8000000 addr = 0x8000000
while prog: while prog:
print("Programming address 0x%08X..0x%08X...\r" % (addr, addr + min(len(prog), 255)), end=' ') print ("Programming address 0x%08X..0x%08X...\r" % (addr, addr + min(len(prog), 255))),
stdout.flush() stdout.flush();
boot.write(addr, prog[:256]) boot.write(addr, prog[:256])
addr += 256 addr += 256
prog = prog[256:] prog = prog[256:]
print print
print("Enabling device protection...") print "Enabling device protection..."
boot.write_protect(range(0,2)) boot.write_protect(range(0,2))
#boot.read_protect() #boot.read_protect()
print("All operations completed.") print "All operations completed."
print print

53
scripts/dfu-convert.py Executable file → Normal file
View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/python2
# Written by Antonio Galea - 2010/11/18 # Written by Antonio Galea - 2010/11/18
# Distributed under Gnu LGPL 3.0 # Distributed under Gnu LGPL 3.0
@ -16,64 +16,57 @@ def consume(fmt,data,names):
n = struct.calcsize(fmt) n = struct.calcsize(fmt)
return named(struct.unpack(fmt,data[:n]),names),data[n:] return named(struct.unpack(fmt,data[:n]),names),data[n:]
def cstring(string): def cstring(string):
return string.split(b'\0',1)[0] return string.split('\0',1)[0]
def compute_crc(data): def compute_crc(data):
return 0xFFFFFFFF & -zlib.crc32(data) -1 return 0xFFFFFFFF & -zlib.crc32(data) -1
def parse(file,dump_images=False): def parse(file,dump_images=False):
print('File: "%s"' % file) print 'File: "%s"' % file
data = open(file,'rb').read() data = open(file,'rb').read()
crc = compute_crc(data[:-4]) crc = compute_crc(data[:-4])
prefix, data = consume('<5sBIB',data,'signature version size targets') prefix, data = consume('<5sBIB',data,'signature version size targets')
print('%(signature)r v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix) print '%(signature)s v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix
for t in range(prefix['targets']): for t in range(prefix['targets']):
tprefix, data = consume('<6sBI255s2I',data,'signature altsetting named name size elements') tprefix, data = consume('<6sBI255s2I',data,'signature altsetting named name size elements')
tprefix['num'] = t tprefix['num'] = t
if tprefix['named']: if tprefix['named']:
tprefix['name'] = cstring(tprefix['name']) tprefix['name'] = cstring(tprefix['name'])
else: else:
tprefix['name'] = b'' tprefix['name'] = ''
print('%(signature)r %(num)d, alt setting: %(altsetting)r, name: %(name)r, size: %(size)d, elements: %(elements)d' % tprefix) print '%(signature)s %(num)d, alt setting: %(altsetting)s, name: "%(name)s", size: %(size)d, elements: %(elements)d' % tprefix
tsize = tprefix['size'] tsize = tprefix['size']
target, data = data[:tsize], data[tsize:] target, data = data[:tsize], data[tsize:]
for e in range(tprefix['elements']): for e in range(tprefix['elements']):
eprefix, target = consume('<2I',target,'address size') eprefix, target = consume('<2I',target,'address size')
eprefix['num'] = e eprefix['num'] = e
print(' %(num)d, address: 0x%(address)08x, size: %(size)d' % eprefix) print ' %(num)d, address: 0x%(address)08x, size: %(size)d' % eprefix
esize = eprefix['size'] esize = eprefix['size']
image, target = target[:esize], target[esize:] image, target = target[:esize], target[esize:]
if dump_images: if dump_images:
out = '%s.target%d.image%d.bin' % (file,t,e) out = '%s.target%d.image%d.bin' % (file,t,e)
open(out,'wb').write(image) open(out,'wb').write(image)
print(' DUMPED IMAGE TO "%s"' % out) print ' DUMPED IMAGE TO "%s"' % out
if len(target): if len(target):
print("target %d: PARSE ERROR" % t) print "target %d: PARSE ERROR" % t
suffix = named(struct.unpack('<4H3sBI',data[:16]),'device product vendor dfu ufd len crc') suffix = named(struct.unpack('<4H3sBI',data[:16]),'device product vendor dfu ufd len crc')
print('usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)r, %(len)d, 0x%(crc)08x' % suffix) print 'usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x' % suffix
if crc != suffix['crc']: if crc != suffix['crc']:
print("CRC ERROR: computed crc32 is 0x%08x" % crc) print "CRC ERROR: computed crc32 is 0x%08x" % crc
data = data[16:] data = data[16:]
if data: if data:
print("PARSE ERROR") print "PARSE ERROR"
def build(file,targets,device=DEFAULT_DEVICE): def build(file,targets,device=DEFAULT_DEVICE):
data = b'' data = ''
for t,target in enumerate(targets): for t,target in enumerate(targets):
tdata = b'' tdata = ''
for image in target: for image in target:
tdata += struct.pack('<2I',image['address'],len(image['data']))+image['data'] tdata += struct.pack('<2I',image['address'],len(image['data']))+image['data']
tdata = struct.pack('<6sBI255s2I','Target',0,1,'ST...',len(tdata),len(target)) + tdata
trgt = b'Target'
st = b'ST...'
tdata = struct.pack('<6sBI255s2I',trgt,0,1,st,len(tdata),len(target)) + tdata
data += tdata data += tdata
data = struct.pack('<5sBIB','DfuSe',1,len(data)+11,len(targets)) + data
dfu_se = b'DfuSe'
ufd = b'UFD'
data = struct.pack('<5sBIB',dfu_se,1,len(data)+11,len(targets)) + data
v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1)) v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1))
data += struct.pack('<4H3sB',0,d,v,0x011a,ufd,16) data += struct.pack('<4H3sB',0,d,v,0x011a,'UFD',16)
crc = compute_crc(data) crc = compute_crc(data)
data += struct.pack('<I',crc) data += struct.pack('<I',crc)
open(file,'wb').write(data) open(file,'wb').write(data)
@ -103,15 +96,15 @@ if __name__=="__main__":
try: try:
address,binfile = arg.split(':',1) address,binfile = arg.split(':',1)
except ValueError: except ValueError:
print("Address:file couple '%s' invalid." % arg) print "Address:file couple '%s' invalid." % arg
sys.exit(1) sys.exit(1)
try: try:
address = int(address,0) & 0xFFFFFFFF address = int(address,0) & 0xFFFFFFFF
except ValueError: except ValueError:
print("Address %s invalid." % address) print "Address %s invalid." % address
sys.exit(1) sys.exit(1)
if not os.path.isfile(binfile): if not os.path.isfile(binfile):
print("Unreadable file '%s'." % binfile) print "Unreadable file '%s'." % binfile
sys.exit(1) sys.exit(1)
target.append({ 'address': address, 'data': open(binfile,'rb').read() }) target.append({ 'address': address, 'data': open(binfile,'rb').read() })
@ -123,7 +116,7 @@ if __name__=="__main__":
try: try:
address = address & 0xFFFFFFFF address = address & 0xFFFFFFFF
except ValueError: except ValueError:
print("Address %s invalid." % address) print "Address %s invalid." % address
sys.exit(1) sys.exit(1)
target.append({ 'address': address, 'data': data }) target.append({ 'address': address, 'data': data })
@ -134,13 +127,13 @@ if __name__=="__main__":
try: try:
v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1)) v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1))
except: except:
print("Invalid device '%s'." % device) print "Invalid device '%s'." % device
sys.exit(1) sys.exit(1)
build(outfile,[target],device) build(outfile,[target],device)
elif len(args)==1: elif len(args)==1:
infile = args[0] infile = args[0]
if not os.path.isfile(infile): if not os.path.isfile(infile):
print("Unreadable file '%s'." % infile) print "Unreadable file '%s'." % infile
sys.exit(1) sys.exit(1)
parse(infile, dump_images=options.dump_images) parse(infile, dump_images=options.dump_images)
else: else:

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python
# #
# dfu.py: Access USB DFU class devices # dfu.py: Access USB DFU class devices
# Copyright (C) 2009 Black Sphere Technologies # Copyright (C) 2009 Black Sphere Technologies
@ -62,7 +62,7 @@ DFU_STATUS_ERROR_POR = 0x0d
DFU_STATUS_ERROR_UNKNOWN = 0x0e DFU_STATUS_ERROR_UNKNOWN = 0x0e
DFU_STATUS_ERROR_STALLEDPKT = 0x0f DFU_STATUS_ERROR_STALLEDPKT = 0x0f
class dfu_status: class dfu_status(object):
def __init__(self, buf): def __init__(self, buf):
self.bStatus = buf[0] self.bStatus = buf[0]
self.bwPollTimeout = buf[1] + (buf[2]<<8) + (buf[3]<<16) self.bwPollTimeout = buf[1] + (buf[2]<<8) + (buf[3]<<16)
@ -70,7 +70,7 @@ class dfu_status:
self.iString = buf[5] self.iString = buf[5]
class dfu_device: class dfu_device(object):
def __init__(self, dev, conf, iface): def __init__(self, dev, conf, iface):
self.dev = dev self.dev = dev
self.conf = conf self.conf = conf

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python
# #
# gdb.py: Python module for low level GDB protocol implementation # gdb.py: Python module for low level GDB protocol implementation
# Copyright (C) 2009 Black Sphere Technologies # Copyright (C) 2009 Black Sphere Technologies
@ -24,12 +24,18 @@ import struct
import time import time
def hexify(s): def hexify(s):
"""Convert a bytes object into hex bytes representation""" """Convert a binary string into hex representation"""
return s.hex().encode() ret = ''
for c in s:
ret += "%02X" % ord(c)
return ret
def unhexify(s): def unhexify(s):
"""Convert a hex-encoded bytes into bytes object""" """Convert a hex string into binary representation"""
return bytes.fromhex(s.decode()) ret = ''
for i in range(0, len(s), 2):
ret += chr(int(s[i:i+2], 16))
return ret
class FakeSocket: class FakeSocket:
"""Emulate socket functions send and recv on a file object""" """Emulate socket functions send and recv on a file object"""
@ -49,183 +55,145 @@ class Target:
else: else:
self.sock = FakeSocket(sock) self.sock = FakeSocket(sock)
self.PacketSize=0x100 # default
def getpacket(self): def getpacket(self):
"""Return the first correctly received packet from GDB target""" """Return the first correctly received packet from GDB target"""
while True: while True:
while self.sock.recv(1) != b'$': while self.sock.recv(1) != '$': pass
pass
csum = 0 csum = 0
packet = [] # list-of-small-int packet = ''
while True: while True:
c, = self.sock.recv(1) c = self.sock.recv(1)
if c == ord('#'): if c == '#': break
break
if c == ord('$'): if c == '$':
packet = [] packet = ''
csum = 0 csum = 0
continue continue
if c == ord('}'): if c == '}':
c, = self.sock.recv(1) c = self.sock.recv(1)
csum += c + ord('}') csum += ord(c) + ord('}')
packet.append(c ^ 0x20) packet += chr(ord(c) ^ 0x20)
continue continue
packet.append(c) packet += c
csum += c csum += ord(c)
if (csum & 0xFF) == int(self.sock.recv(2),16): if (csum & 0xFF) == int(self.sock.recv(2),16): break
break
self.sock.send(b'-') self.sock.send('-')
self.sock.send('+')
return packet
self.sock.send(b'+')
return bytes(packet)
def putpacket(self, packet): def putpacket(self, packet):
"""Send packet to GDB target and wait for acknowledge """Send packet to GDB target and wait for acknowledge"""
packet is bytes or string"""
if type(packet) == str:
packet = packet.encode()
while True: while True:
out = [] self.sock.send('$')
csum = 0
for c in packet: for c in packet:
if (c in b'$#}'): if (c == '$') or (c == '#') or (c == '}'):
out.append(ord('}')) self.sock.send('}')
out.append(c ^ 0x20) self.sock.send(chr(ord(c) ^ 0x20))
csum += (ord(c) ^ 0x20) + ord('}')
else: else:
out.append(c) self.sock.send(c)
csum += ord(c)
csum = sum(out) self.sock.send('#')
outb = b'$'+bytes(out)+b'#%02X' % (csum & 0xff) self.sock.send("%02X" % (csum & 0xFF))
if self.sock.recv(1) == '+': break
self.sock.send(outb)
if self.sock.recv(1) == b'+':
break
def monitor(self, cmd): def monitor(self, cmd):
"""Send gdb "monitor" command to target""" """Send gdb "monitor" command to target"""
if type(cmd) == str:
cmd = cmd.encode()
ret = [] ret = []
self.putpacket(b"qRcmd," + hexify(cmd)) self.putpacket("qRcmd," + hexify(cmd))
while True: while True:
s = self.getpacket() s = self.getpacket()
if s == '': return None
if s == b'': if s == 'OK': return ret
return None if s.startswith('O'): ret.append(unhexify(s[1:]))
if s == b'OK':
return ret
if s.startswith(b'O'):
ret.append(unhexify(s[1:]))
else: else:
raise Exception('Invalid GDB stub response %r'%s.decode()) raise Exception('Invalid GDB stub response')
def attach(self, pid): def attach(self, pid):
"""Attach to target process (gdb "attach" command)""" """Attach to target process (gdb "attach" command)"""
self.putpacket(b"vAttach;%08X" % pid) self.putpacket("vAttach;%08X" % pid)
reply = self.getpacket() reply = self.getpacket()
if (reply == b'') or (reply[:1] == b'E'): if (len(reply) == 0) or (reply[0] == 'E'):
raise Exception('Failed to attach to remote pid %d' % pid) raise Exception('Failed to attach to remote pid %d' % pid)
def detach(self): def detach(self):
"""Detach from target process (gdb "detach" command)""" """Detach from target process (gdb "detach" command)"""
self.putpacket(b"D") self.putpacket("D")
if self.getpacket() != b'OK': if self.getpacket() != 'OK':
raise Exception("Failed to detach from remote process") raise Exception("Failed to detach from remote process")
def reset(self): def reset(self):
"""Reset the target system""" """Reset the target system"""
self.putpacket(b"r") self.putpacket("r")
def read_mem(self, addr, length): def read_mem(self, addr, length):
"""Read length bytes from target at address addr""" """Read length bytes from target at address addr"""
ret = b'' self.putpacket("m%08X,%08X" % (addr, length))
while length:
# print("Read")
packlen = min(length,self.PacketSize//2)
self.putpacket(b"m%08X,%08X" % (addr, packlen))
reply = self.getpacket() reply = self.getpacket()
if (reply == b'') or (reply[:1] == b'E'): if (len(reply) == 0) or (reply[0] == 'E'):
raise Exception('Error reading memory at 0x%08X' % addr) raise Exception('Error reading memory at 0x%08X' % addr)
try: try:
data = unhexify(reply) data = unhexify(reply)
except Exception: except Excpetion:
raise Exception('Invalid response to memory read packet: %r' % reply) raise Exception('Invalid response to memory read packet: %r' % reply)
ret += data return data
length -= packlen
addr += packlen
return ret
def write_mem(self, addr, data): def write_mem(self, addr, data):
"""Write data to target at address addr""" """Write data to target at address addr"""
data = bytes(data) self.putpacket("X%08X,%08X:%s" % (addr, len(data), data))
if self.getpacket() != 'OK':
while data:
d = data[:self.PacketSize-44]
data = data[len(d):]
#print("Writing %d bytes at 0x%X" % (len(d), addr))
pack = b"X%08X,%08X:%s" % (addr, len(d), d)
self.putpacket(pack)
if self.getpacket() != b'OK':
raise Exception('Error writing to memory at 0x%08X' % addr) raise Exception('Error writing to memory at 0x%08X' % addr)
addr += len(d)
def read_regs(self): def read_regs(self):
"""Read target core registers""" """Read target core registers"""
self.putpacket(b"g") self.putpacket("g")
reply = self.getpacket() reply = self.getpacket()
if (reply == b'') or (reply[:1] == b'E'): if (len(reply) == 0) or (reply[0] == 'E'):
raise Exception('Error reading target core registers') raise Exception('Error reading memory at 0x%08X' % addr)
try: try:
data = unhexify(reply) data = unhexify(reply)
except Exception: except Excpetion:
raise Exception('Invalid response to registers read packet: %r' % reply) raise Exception('Invalid response to memory read packet: %r' % reply)
ret = array.array('I',data) return struct.unpack("=20L", data)
return ret
def write_regs(self, *regs): def write_regs(self, *regs):
"""Write target core registers""" """Write target core registers"""
data = struct.pack("=%dL" % len(regs), *regs) data = struct.pack("=%dL" % len(regs), *regs)
self.putpacket(b"G" + hexify(data)) self.putpacket("G" + hexify(data))
if self.getpacket() != b'OK': if self.getpacket() != 'OK':
raise Exception('Error writing to target core registers') raise Exception('Error writing to target core registers')
def memmap_read(self): def memmap_read(self):
"""Read the XML memory map from target""" """Read the XML memory map from target"""
offset = 0 offset = 0
ret = b'' ret = ''
while True: while True:
self.putpacket(b"qXfer:memory-map:read::%08X,%08X" % (offset, 512)) self.putpacket("qXfer:memory-map:read::%08X,%08X" % (offset, 512))
reply = self.getpacket() reply = self.getpacket()
if (reply[0] in b'ml'): if (reply[0] == 'm') or (reply[0] == 'l'):
offset += len(reply) - 1 offset += len(reply) - 1
ret += reply[1:] ret += reply[1:]
else: else:
raise Exception('Invalid GDB stub response %r'%reply) raise Exception("Invalid GDB stub response")
if reply[:1] == b'l': if reply[0] == 'l': return ret
return ret
def resume(self): def resume(self):
"""Resume target execution""" """Resume target execution"""
self.putpacket(b'c') self.putpacket("c")
def interrupt(self): def interrupt(self):
"""Interrupt target execution""" """Interrupt target execution"""
self.sock.send(b'\x03') self.sock.send("\x03")
def run_stub(self, stub, address, *args): def run_stub(self, stub, address, *args):
"""Execute a binary stub at address, passing args in core registers.""" """Execute a binary stub at address, passing args in core registers."""
@ -237,19 +205,11 @@ class Target:
regs[15] = address regs[15] = address
self.write_regs(*regs) self.write_regs(*regs)
self.resume() self.resume()
reply = None reply = self.getpacket()
while not reply: while not reply:
reply = self.getpacket() reply = self.getpacket()
if not reply.startswith(b"T05"): if not reply.startswith("T05"):
message = "Invalid stop response: %r" % reply raise Exception("Invalid stop response: %r" % reply)
try:
message += {'T02':' (SIGINT)',
'T05':' (SIGTRAP)',
'T0B':' (SIGSEGV)',
'T1D':' (SIGLOST)'}[reply]
except KeyError:
pass
raise Exception(message)
class FlashMemory: class FlashMemory:
def __init__(self, target, offset, length, blocksize): def __init__(self, target, offset, length, blocksize):
@ -257,29 +217,26 @@ class Target:
self.offset = offset self.offset = offset
self.length = length self.length = length
self.blocksize = blocksize self.blocksize = blocksize
self.blocks = list(None for i in range(length // blocksize)) self.blocks = list(None for i in range(length / blocksize))
def prog(self, offset, data): def prog(self, offset, data):
assert type(data)==bytes
assert ((offset >= self.offset) and assert ((offset >= self.offset) and
(offset + len(data) <= self.offset + self.length)) (offset + len(data) <= self.offset + self.length))
while data: while data:
index = (offset - self.offset) // self.blocksize index = (offset - self.offset) / self.blocksize
bloffset = (offset - self.offset) % self.blocksize bloffset = (offset - self.offset) % self.blocksize
bldata = data[:self.blocksize-bloffset] bldata = data[:self.blocksize-bloffset]
data = data[len(bldata):]; offset += len(bldata) data = data[len(bldata):]; offset += len(bldata)
if self.blocks[index] is None: # Initialize a clear block if self.blocks[index] is None: # Initialize a clear block
self.blocks[index] = bytes(0xff for i in range(self.blocksize)) self.blocks[index] = "".join(chr(0xff) for i in range(self.blocksize))
self.blocks[index] = (self.blocks[index][:bloffset] + bldata + self.blocks[index] = (self.blocks[index][:bloffset] + bldata +
self.blocks[index][bloffset+len(bldata):]) self.blocks[index][bloffset+len(bldata):])
def commit(self, progress_cb=None): def commit(self, progress_cb=None):
totalblocks = 0 totalblocks = 0
for b in self.blocks: for b in self.blocks:
if b is not None: if b is not None: totalblocks += 1
totalblocks += 1
block = 0 block = 0
for i in range(len(self.blocks)): for i in range(len(self.blocks)):
@ -290,28 +247,27 @@ class Target:
# Erase the block # Erase the block
data = self.blocks[i] data = self.blocks[i]
addr = self.offset + self.blocksize * i addr = self.offset + self.blocksize * i
if data is None: if data is None: continue
continue #print "Erasing flash at 0x%X" % (self.offset + self.blocksize*i)
#print("Erasing flash at 0x%X" % (self.offset + self.blocksize*i)) self.target.putpacket("vFlashErase:%08X,%08X" %
self.target.putpacket(b"vFlashErase:%08X,%08X" %
(self.offset + self.blocksize*i, self.blocksize)) (self.offset + self.blocksize*i, self.blocksize))
if self.target.getpacket() != b'OK': if self.target.getpacket() != 'OK':
raise Exception("Failed to erase flash") raise Exception("Failed to erase flash")
while data: while data:
d = data[0:980] d = data[0:980]
data = data[len(d):] data = data[len(d):]
#print("Writing %d bytes at 0x%X" % (len(d), addr)) #print "Writing %d bytes at 0x%X" % (len(d), addr)
self.target.putpacket(b"vFlashWrite:%08X:%s" % (addr, d)) self.target.putpacket("vFlashWrite:%08X:%s" % (addr, d))
addr += len(d) addr += len(d)
if self.target.getpacket() != b'OK': if self.target.getpacket() != 'OK':
raise Exception("Failed to write flash") raise Exception("Failed to write flash")
self.target.putpacket(b"vFlashDone") self.target.putpacket("vFlashDone")
if self.target.getpacket() != b'OK': if self.target.getpacket() != 'OK':
raise Exception("Failed to commit") raise Exception("Failed to commit")
self.blocks = list(None for i in range(self.length // self.blocksize)) self.blocks = list(None for i in range(self.length / self.blocksize))
def flash_probe(self): def flash_probe(self):
@ -319,8 +275,7 @@ class Target:
xmldom = parseString(self.memmap_read()) xmldom = parseString(self.memmap_read())
for memrange in xmldom.getElementsByTagName("memory"): for memrange in xmldom.getElementsByTagName("memory"):
if memrange.getAttribute("type") != "flash": if memrange.getAttribute("type") != "flash": continue
continue
offset = eval(memrange.getAttribute("start")) offset = eval(memrange.getAttribute("start"))
length = eval(memrange.getAttribute("length")) length = eval(memrange.getAttribute("length"))
for property in memrange.getElementsByTagName("property"): for property in memrange.getElementsByTagName("property"):
@ -342,3 +297,5 @@ class Target:
def flash_commit(self, progress_cb=None): def flash_commit(self, progress_cb=None):
for m in self.mem: for m in self.mem:
m.commit(progress_cb) m.commit(progress_cb)

View File

@ -1,36 +1,40 @@
#!/usr/bin/env python3 #!/usr/bin/python
"""Pulls nRF51 IDs from openocd's nrf51.c in a form suitable for """Pulls nRF51 IDs from openocd's nrf51.c in a form suitable for
pasting into blackmagic's nrf51.c pasting into blackmagic's nrf51.c
""" """
import subprocess import subprocess,re
import re
import io
cmd = 'git archive --remote=git://git.code.sf.net/p/openocd/code HEAD src/flash/nor/nrf5.c | tar -xO' cmd = 'git archive --remote=git://git.code.sf.net/p/openocd/code HEAD src/flash/nor/nrf51.c | tar -xO'
class Spec(): class Spec():
def __repr__(self): def __repr__(self):
return "0x%04X: /* %s %s %s */"%(self.hwid,self.comment, self.variant,self.build_code) return "0x%04X: /* %s %s %s */"%(self.hwid,self.comment, self.variant,self.build_code)
proc = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE) fd = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE).stdout
specdict={} specdict={}
specs=[] specs=[]
spec=Spec() spec=Spec()
for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"): for line in fd.read().split('\n'):
m = re.search(r'/\*(.*)\*/',line) m=re.search('/\*(.*)\*/',line)
if m: if m:
lastcomment=m.group(1) lastcomment=m.group(1)
m = re.search(r'NRF51_DEVICE_DEF\((0x[0-9A-F]*),\s*"(.*)",\s*"(.*)",\s*"(.*)",\s*([0-9]*)\s*\),', line) m=re.search('.hwid.*=\s*(0x[0-9A-F]*),',line)
if m: if m:
spec.hwid=int(m.group(1),base=0) spec.hwid=int(m.group(1),base=0)
spec.variant = m.group(3) m=re.search('.variant.*=\s*"(.*)",',line)
spec.build_code = m.group(4) if m:
spec.flash_size_kb = int(m.group(5), base=0) spec.variant=m.group(1)
m=re.search('.build_code.*=\s*"(.*)",',line)
if m:
spec.build_code=m.group(1)
m=re.search('.flash_size_kb.*=\s*([0-9]*),',line)
if m:
spec.flash_size_kb=int(m.group(1),base=0)
ram,flash = {'AA':(16,256), ram,flash = {'AA':(16,256),
'AB':(16,128), 'AB':(16,128),
'AC':(32,256)}[spec.variant[-2:]] 'AC':(32,256)}[spec.variant[-2:]]
@ -43,14 +47,14 @@ for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"):
specs.append(spec) specs.append(spec)
spec=Spec() spec=Spec()
for (ram,flash),specs in specdict.items(): for (ram,flash),specs in specdict.iteritems():
specs.sort(key=lambda x:x.hwid) specs.sort(key=lambda x:x.hwid)
for spec in specs: for spec in specs:
print("\tcase",spec) print "\tcase",spec
print('\t\tt->driver = "Nordic nRF51";') print '\t\tt->driver = "Nordic nRF51";'
print('\t\ttarget_add_ram(t, 0x20000000, 0x%X);'%(1024*ram)) print '\t\ttarget_add_ram(t, 0x20000000, 0x%X);'%(1024*ram)
print('\t\tnrf51_add_flash(t, 0x00000000, 0x%X, NRF51_PAGE_SIZE);'%(1024*flash)) print '\t\tnrf51_add_flash(t, 0x00000000, 0x%X, NRF51_PAGE_SIZE);'%(1024*flash)
print('\t\tnrf51_add_flash(t, NRF51_UICR, 0x100, 0x100);') print '\t\tnrf51_add_flash(t, NRF51_UICR, 0x100, 0x100);'
print('\t\ttarget_add_commands(t, nrf51_cmd_list, "nRF51");') print '\t\ttarget_add_commands(t, nrf51_cmd_list, "nRF51");'
print('\t\treturn true;') print '\t\treturn true;'

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python
# hexprog.py: Python application to flash a target with an Intel hex file # hexprog.py: Python application to flash a target with an Intel hex file
# Copyright (C) 2011 Black Sphere Technologies # Copyright (C) 2011 Black Sphere Technologies
@ -18,6 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import gdb import gdb
import struct
import time import time
# Microcode sequence to erase option bytes # Microcode sequence to erase option bytes
@ -30,16 +31,15 @@ def flash_write_hex(target, hexfile, progress_cb=None):
f = open(hexfile) f = open(hexfile)
addrhi = 0 addrhi = 0
for line in f: for line in f:
if line[0] != ':': if line[0] != ':': raise Exception("Error in hex file")
raise Exception("Error in hex file")
reclen = int(line[1:3], 16) reclen = int(line[1:3], 16)
addrlo = int(line[3:7], 16) addrlo = int(line[3:7], 16)
rectype = int(line[7:9], 16) rectype = int(line[7:9], 16);
if sum(x for x in bytes.fromhex(line[1:11+reclen*2])) & 0xff != 0: if sum(ord(x) for x in gdb.unhexify(line[1:11+reclen*2])) & 0xff != 0:
raise Exception("Checksum error in hex file") raise Exception("Checksum error in hex file")
if rectype == 0: # Data record if rectype == 0: # Data record
addr = (addrhi << 16) + addrlo addr = (addrhi << 16) + addrlo
data = bytes.fromhex(line[9:9+reclen*2]) data = gdb.unhexify(line[9:9+reclen*2])
target.flash_write_prepare(addr, data) target.flash_write_prepare(addr, data)
pass pass
elif rectype == 4: # High address record elif rectype == 4: # High address record
@ -55,7 +55,7 @@ def flash_write_hex(target, hexfile, progress_cb=None):
try: try:
target.flash_commit(progress_cb) target.flash_commit(progress_cb)
except: except:
print("Flash write failed! Is device protected?\n") print "Flash write failed! Is device protected?\n"
exit(-1) exit(-1)
@ -64,11 +64,11 @@ if __name__ == "__main__":
from sys import argv, platform, stdout from sys import argv, platform, stdout
from getopt import getopt from getopt import getopt
if platform == "linux": if platform == "linux2":
print ("\x1b\x5b\x48\x1b\x5b\x32\x4a") # clear terminal screen print ("\x1b\x5b\x48\x1b\x5b\x32\x4a") # clear terminal screen
print("Black Magic Probe -- Target Production Programming Tool -- version 1.0") print("Black Magic Probe -- Target Production Programming Tool -- version 1.0")
print("Copyright (C) 2011 Black Sphere Technologies") print "Copyright (C) 2011 Black Sphere Technologies"
print("License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>") print "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>"
print("") print("")
dev = "COM1" if platform == "win32" else "/dev/ttyACM0" dev = "COM1" if platform == "win32" else "/dev/ttyACM0"
@ -80,20 +80,13 @@ if __name__ == "__main__":
try: try:
opts, args = getopt(argv[1:], "sd:b:t:rR") opts, args = getopt(argv[1:], "sd:b:t:rR")
for opt in opts: for opt in opts:
if opt[0] == "-s": if opt[0] == "-s": scan = "swdp_scan"
scan = "swdp_scan" elif opt[0] == "-b": baud = int(opt[1])
elif opt[0] == "-b": elif opt[0] == "-d": dev = opt[1]
baud = int(opt[1]) elif opt[0] == "-t": targetno = int(opt[1])
elif opt[0] == "-d": elif opt[0] == "-r": unprot = True
dev = opt[1] elif opt[0] == "-R": prot = True
elif opt[0] == "-t": else: raise Exception()
targetno = int(opt[1])
elif opt[0] == "-r":
unprot = True
elif opt[0] == "-R":
prot = True
else:
raise Exception()
hexfile = args[0] hexfile = args[0]
except: except:
@ -108,44 +101,39 @@ if __name__ == "__main__":
exit(-1) exit(-1)
try: try:
s = Serial(dev) #, baud, timeout=0.1) s = Serial(dev, baud, timeout=3)
#s.setDTR(1) s.setDTR(1)
#s.flushInput() while s.read(1024):
pass
#while s.read(1024):
# pass
target = gdb.Target(s) target = gdb.Target(s)
except SerialException as e: except SerialException, e:
print("FATAL: Failed to open serial device!\n%s\n" % e[0]) print("FATAL: Failed to open serial device!\n%s\n" % e[0])
exit(-1) exit(-1)
try: try:
r = target.monitor("version") r = target.monitor("version")
for s in r: for s in r: print s,
print(s.decode(), end=' ') except SerialException, e:
except SerialException as e:
print("FATAL: Serial communication failure!\n%s\n" % e[0]) print("FATAL: Serial communication failure!\n%s\n" % e[0])
exit(-1) exit(-1)
#except: pass except: pass
print("Target device scan:") print "Target device scan:"
targetlist = None targetlist = None
r = target.monitor(scan) r = target.monitor(scan)
for s in r: for s in r:
print(s.decode(), end=' ') print s,
print() print
r = target.monitor("targets") r = target.monitor("targets")
for s in r: for s in r:
if s.startswith(b"No. Att Driver"): if s.startswith("No. Att Driver"): targetlist = []
targetlist = []
try: try:
if type(targetlist) is list: if type(targetlist) is list:
targetlist.append(int(s[:2])) targetlist.append(int(s[:2]))
except: except: pass
pass
#if not targetlist: #if not targetlist:
# print("FATAL: No usable targets found!\n") # print("FATAL: No usable targets found!\n")
@ -173,7 +161,7 @@ if __name__ == "__main__":
print("FLASH memory -- Offset: 0x%X BlockSize:0x%X\n" % (m.offset, m.blocksize)) print("FLASH memory -- Offset: 0x%X BlockSize:0x%X\n" % (m.offset, m.blocksize))
def progress(percent): def progress(percent):
print("Progress: %d%%\r" % percent, end=' ') print ("Progress: %d%%\r" % percent),
stdout.flush() stdout.flush()
print("Programming target") print("Programming target")
@ -191,3 +179,4 @@ if __name__ == "__main__":
target.detach() target.detach()
print("\nAll operations complete!\n") print("\nAll operations complete!\n")

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python
# #
# stm32_mem.py: STM32 memory access using USB DFU class # stm32_mem.py: STM32 memory access using USB DFU class
# Copyright (C) 2011 Black Sphere Technologies # Copyright (C) 2011 Black Sphere Technologies
# Copyright (C) 2017, 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) # Copyright (C) 2017 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
# Written by Gareth McMullin <gareth@blacksphere.co.nz> # Written by Gareth McMullin <gareth@blacksphere.co.nz>
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
@ -18,12 +18,14 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from __future__ import print_function
from time import sleep from time import sleep
import struct import struct
import os import os
from sys import stdout from sys import stdout, argv
import argparse import argparse
import usb
import dfu import dfu
CMD_GETCOMMANDS = 0x00 CMD_GETCOMMANDS = 0x00
@ -70,7 +72,7 @@ def stm32_read(dev):
return data return data
def stm32_manifest(dev): def stm32_manifest(dev):
dev.download(0, b"") dev.download(0, "")
while True: while True:
try: try:
status = dev.get_status() status = dev.get_status()
@ -85,7 +87,7 @@ def stm32_scan(args, test):
bmp_devs = [] bmp_devs = []
bmp = 0 bmp = 0
if not devs: if not devs:
if test: if test == True:
return return
print("No DFU devices found!") print("No DFU devices found!")
@ -106,22 +108,22 @@ def stm32_scan(args, test):
bmp_devs.append(dev) bmp_devs.append(dev)
if bmp == 0: if bmp == 0:
if test: if test == True:
return return
print("No compatible device found\n") print("No compatible device found\n")
exit(-1) exit(-1)
if bmp > 1 and not args.serial_target: if bmp > 1 and not args.serial_target:
if test: if test == True:
return return
print("Found multiple devices:\n") print("Found multiple devices:\n")
for dev in bmp_devs: for dev in bmp_devs:
dfudev = dfu.dfu_device(*dev) dfudev = dfu.dfu_device(*dev)
man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30).decode('utf8') man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30)
product = dfudev.handle.getString(dfudev.dev.iProduct, 96).decode('utf8') product = dfudev.handle.getString(dfudev.dev.iProduct, 96)
serial_no = dfudev.handle.getString(dfudev.dev.iSerialNumber, 30).decode('utf8') serial_no = dfudev.handle.getString(dfudev.dev.iSerialNumber, 30)
print("Device ID:\t %04x:%04x" % (dfudev.dev.idVendor, dfudev.dev.idProduct)) print("Device ID:\t %04x:%04x" % (dfudev.dev.idVendor, dfudev.dev.idProduct))
print("Manufacturer:\t %s" % man) print("Manufacturer:\t %s" % man)
print("Product:\t %s" % product) print("Product:\t %s" % product)
@ -132,9 +134,9 @@ def stm32_scan(args, test):
for dev in bmp_devs: for dev in bmp_devs:
dfudev = dfu.dfu_device(*dev) dfudev = dfu.dfu_device(*dev)
man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30).decode('utf8') man = dfudev.handle.getString(dfudev.dev.iManufacturer, 30)
product = dfudev.handle.getString(dfudev.dev.iProduct, 96).decode('utf8') product = dfudev.handle.getString(dfudev.dev.iProduct, 96)
serial_no = dfudev.handle.getString(dfudev.dev.iSerialNumber, 30).decode('utf8') serial_no = dfudev.handle.getString(dfudev.dev.iSerialNumber, 30)
if args.serial_target: if args.serial_target:
if man == "Black Sphere Technologies" and serial_no == args.serial_target: if man == "Black Sphere Technologies" and serial_no == args.serial_target:
break break
@ -148,7 +150,7 @@ def stm32_scan(args, test):
print("Serial:\t\t %s" % serial_no) print("Serial:\t\t %s" % serial_no)
if args.serial_target and serial_no != args.serial_target: if args.serial_target and serial_no != args.serial_target:
print("Serial number doesn't match %s vs %s!\n" % (serial_no, args.serial_target)) print("Serial number doesn't match!\n")
exit(-2) exit(-2)
return dfudev return dfudev
@ -182,7 +184,7 @@ if __name__ == "__main__":
print("Invoking DFU Device") print("Invoking DFU Device")
timeout = 0 timeout = 0
while True : while True :
sleep(1) sleep(0.5)
timeout = timeout + 0.5 timeout = timeout + 0.5
dfudev = stm32_scan(args, True) dfudev = stm32_scan(args, True)
if dfudev: break if dfudev: break
@ -201,11 +203,11 @@ if __name__ == "__main__":
bin = file.read() bin = file.read()
product = dfudev.handle.getString(dfudev.dev.iProduct, 64).decode('utf8') product = dfudev.handle.getString(dfudev.dev.iProduct, 64)
if args.address : if args.address :
start = int(args.address, 0) start = int(args.address, 0)
else : else :
if "F4" in product or "STLINK-V3" in product: if b"F4" in product:
start = 0x8004000 start = 0x8004000
else: else:
start = 0x8002000 start = 0x8002000
@ -234,7 +236,7 @@ if __name__ == "__main__":
bin = file.read() bin = file.read()
len = len(bin) len = len(bin)
addr = start addr = start
print("\n-") print("-")
while bin: while bin:
try: try:
stm32_set_address(dfudev, addr) stm32_set_address(dfudev, addr)
@ -249,8 +251,8 @@ if __name__ == "__main__":
else : else :
size = len size = len
if bin[:size] != bytearray(data[:size]) : if bin[:size] != bytearray(data[:size]) :
print("\nMismatch in block at 0x%08X" % addr) print ("\nMitmatch in block at 0x%08X" % addr)
break break;
bin = bin[1024:] bin = bin[1024:]
addr += 1024 addr += 1024
len -= 1024 len -= 1024

View File

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

View File

@ -3,8 +3,6 @@
* *
* Copyright (C) 2011 Black Sphere Technologies Ltd. * Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz> * Written by Gareth McMullin <gareth@blacksphere.co.nz>
* Copyright (C) 2021 Uwe Bonnes
* (bon@elektron.ikp.physik.tu-darmstadt.de)
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -29,28 +27,28 @@
#include "command.h" #include "command.h"
#include "gdb_packet.h" #include "gdb_packet.h"
#include "target.h" #include "target.h"
#include "target_internal.h"
#include "morse.h" #include "morse.h"
#include "version.h" #include "version.h"
#include "serialno.h" #include "serialno.h"
#ifdef ENABLE_RTT
#include "rtt.h"
#endif
#ifdef PLATFORM_HAS_TRACESWO #ifdef PLATFORM_HAS_TRACESWO
# include "traceswo.h" # include "traceswo.h"
#endif #endif
typedef bool (*cmd_handler)(target *t, int argc, const char **argv);
struct command_s {
const char *cmd;
cmd_handler handler;
const char *help;
};
static bool cmd_version(target *t, int argc, char **argv); static bool cmd_version(target *t, int argc, char **argv);
#ifdef PLATFORM_HAS_PRINTSERIAL
static bool cmd_serial(target *t, int argc, char **argv);
#endif
static bool cmd_help(target *t, int argc, char **argv); static bool cmd_help(target *t, int argc, char **argv);
static bool cmd_jtag_scan(target *t, int argc, char **argv); static bool cmd_jtag_scan(target *t, int argc, char **argv);
static bool cmd_swdp_scan(target *t, int argc, char **argv); static bool cmd_swdp_scan(target *t, int argc, char **argv);
static bool cmd_frequency(target *t, int argc, char **argv);
static bool cmd_targets(target *t, int argc, char **argv); static bool cmd_targets(target *t, int argc, char **argv);
static bool cmd_morse(target *t, int argc, char **argv); static bool cmd_morse(target *t, int argc, char **argv);
static bool cmd_halt_timeout(target *t, int argc, const char **argv); static bool cmd_halt_timeout(target *t, int argc, const char **argv);
@ -63,29 +61,15 @@ static bool cmd_target_power(target *t, int argc, const char **argv);
static bool cmd_traceswo(target *t, int argc, const char **argv); static bool cmd_traceswo(target *t, int argc, const char **argv);
#endif #endif
static bool cmd_heapinfo(target *t, int argc, const char **argv); static bool cmd_heapinfo(target *t, int argc, const char **argv);
#ifdef ENABLE_RTT
static bool cmd_rtt(target *t, int argc, const char **argv);
#endif
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0) #if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
static bool cmd_debug_bmp(target *t, int argc, const char **argv); static bool cmd_debug_bmp(target *t, int argc, const char **argv);
#endif #endif
#ifdef PLATFORM_HAS_UART_WHEN_SWDP
static bool cmd_convert_tdio(target *t, int argc, const char **argv);
static bool cmd_set_srst(target *t, int argc, const char **argv);
#endif
#ifdef PLATFORM_HAS_BOOTLOADER
static bool cmd_enter_bootldr(target *t, int argc, const char **argv);
#endif
const struct command_s cmd_list[] = { const struct command_s cmd_list[] = {
{"version", (cmd_handler)cmd_version, "Display firmware version info"}, {"version", (cmd_handler)cmd_version, "Display firmware version info"},
#ifdef PLATFORM_HAS_PRINTSERIAL
{"serial", (cmd_handler)cmd_serial, "Display firmware serial number"},
#endif
{"help", (cmd_handler)cmd_help, "Display help for monitor commands"}, {"help", (cmd_handler)cmd_help, "Display help for monitor commands"},
{"jtag_scan", (cmd_handler)cmd_jtag_scan, "Scan JTAG chain for devices" }, {"jtag_scan", (cmd_handler)cmd_jtag_scan, "Scan JTAG chain for devices" },
{"swdp_scan", (cmd_handler)cmd_swdp_scan, "Scan SW-DP for devices" }, {"swdp_scan", (cmd_handler)cmd_swdp_scan, "Scan SW-DP for devices" },
{"frequency", (cmd_handler)cmd_frequency, "set minimum high and low times" },
{"targets", (cmd_handler)cmd_targets, "Display list of available targets" }, {"targets", (cmd_handler)cmd_targets, "Display list of available targets" },
{"morse", (cmd_handler)cmd_morse, "Display morse error message" }, {"morse", (cmd_handler)cmd_morse, "Display morse error message" },
{"halt_timeout", (cmd_handler)cmd_halt_timeout, "Timeout (ms) to wait until Cortex-M is halted: (Default 2000)" }, {"halt_timeout", (cmd_handler)cmd_halt_timeout, "Timeout (ms) to wait until Cortex-M is halted: (Default 2000)" },
@ -94,9 +78,6 @@ const struct command_s cmd_list[] = {
#ifdef PLATFORM_HAS_POWER_SWITCH #ifdef PLATFORM_HAS_POWER_SWITCH
{"tpwr", (cmd_handler)cmd_target_power, "Supplies power to the target: (enable|disable)"}, {"tpwr", (cmd_handler)cmd_target_power, "Supplies power to the target: (enable|disable)"},
#endif #endif
#ifdef ENABLE_RTT
{"rtt", (cmd_handler)cmd_rtt, "enable|disable|status|channel 0..15|ident (str)|cblock|poll maxms minms maxerr" },
#endif
#ifdef PLATFORM_HAS_TRACESWO #ifdef PLATFORM_HAS_TRACESWO
#if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2 #if defined TRACESWO_PROTOCOL && TRACESWO_PROTOCOL == 2
{"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, NRZ mode: (baudrate) (decode channel ...)" }, {"traceswo", (cmd_handler)cmd_traceswo, "Start trace capture, NRZ mode: (baudrate) (decode channel ...)" },
@ -107,13 +88,6 @@ const struct command_s cmd_list[] = {
{"heapinfo", (cmd_handler)cmd_heapinfo, "Set semihosting heapinfo" }, {"heapinfo", (cmd_handler)cmd_heapinfo, "Set semihosting heapinfo" },
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0) #if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
{"debug_bmp", (cmd_handler)cmd_debug_bmp, "Output BMP \"debug\" strings to the second vcom: (enable|disable)"}, {"debug_bmp", (cmd_handler)cmd_debug_bmp, "Output BMP \"debug\" strings to the second vcom: (enable|disable)"},
#endif
#ifdef PLATFORM_HAS_UART_WHEN_SWDP
{"convert_tdio", (cmd_handler)cmd_convert_tdio,"Switch TDI/O pins to UART TX/RX functions"},
{"set_srst", (cmd_handler)cmd_set_srst,"Set output state of SRST pin (enable|disable)"},
#endif
#ifdef PLATFORM_HAS_BOOTLOADER
{"enter_bootldr", (cmd_handler)cmd_enter_bootldr,"Force BMP into bootloader mode"},
#endif #endif
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };
@ -122,7 +96,7 @@ bool connect_assert_srst;
#if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0) #if defined(PLATFORM_HAS_DEBUG) && (PC_HOSTED == 0)
bool debug_bmp; bool debug_bmp;
#endif #endif
unsigned cortexm_wait_timeout = 2000; /* Timeout to wait for Cortex to react on halt command. */ long cortexm_wait_timeout = 2000; /* Timeout to wait for Cortex to react on halt command. */
int command_process(target *t, char *cmd) int command_process(target *t, char *cmd)
{ {
@ -157,24 +131,20 @@ int command_process(target *t, char *cmd)
return target_command(t, argc, argv); return target_command(t, argc, argv);
} }
#define BOARD_IDENT "Black Magic Probe" PLATFORM_IDENT FIRMWARE_VERSION
bool cmd_version(target *t, int argc, char **argv) bool cmd_version(target *t, int argc, char **argv)
{ {
(void)t; (void)t;
(void)argc; (void)argc;
(void)argv; (void)argv;
#if PC_HOSTED == 1 #if PC_HOSTED == 1
char ident[256]; gdb_outf("Black Magic Probe, PC-Hosted for " PLATFORM_IDENT()
gdb_ident(ident, sizeof(ident)); ", Version " FIRMWARE_VERSION "\n");
DEBUG_WARN("%s\n", ident);
#else #else
gdb_out(BOARD_IDENT); gdb_outf("Black Magic Probe (Firmware " FIRMWARE_VERSION ") (Hardware Version %d)\n", platform_hwversion());
gdb_outf(", Hardware Version %d\n", platform_hwversion()); #endif
gdb_out("Copyright (C) 2022 Black Magic Debug Project\n"); gdb_out("Copyright (C) 2015 Black Sphere Technologies Ltd.\n");
gdb_out("License GPLv3+: GNU GPL version 3 or later " gdb_out("License GPLv3+: GNU GPL version 3 or later "
"<http://gnu.org/licenses/gpl.html>\n\n"); "<http://gnu.org/licenses/gpl.html>\n\n");
#endif
return true; return true;
} }
@ -185,11 +155,10 @@ bool cmd_help(target *t, int argc, char **argv)
(void)argv; (void)argv;
const struct command_s *c; const struct command_s *c;
if (!t || t->tc->destroy_callback) {
gdb_out("General commands:\n"); gdb_out("General commands:\n");
for(c = cmd_list; c->cmd; c++) for(c = cmd_list; c->cmd; c++)
gdb_outf("\t%s -- %s\n", c->cmd, c->help); gdb_outf("\t%s -- %s\n", c->cmd, c->help);
}
if (!t) if (!t)
return -1; return -1;
@ -247,9 +216,8 @@ static bool cmd_jtag_scan(target *t, int argc, char **argv)
bool cmd_swdp_scan(target *t, int argc, char **argv) bool cmd_swdp_scan(target *t, int argc, char **argv)
{ {
(void)t; (void)t;
volatile uint32_t targetid = 0; (void)argc;
if (argc > 1) (void)argv;
targetid = strtol(argv[1], NULL, 0);
if (platform_target_voltage()) if (platform_target_voltage())
gdb_outf("Target voltage: %s\n", platform_target_voltage()); gdb_outf("Target voltage: %s\n", platform_target_voltage());
@ -260,9 +228,9 @@ bool cmd_swdp_scan(target *t, int argc, char **argv)
volatile struct exception e; volatile struct exception e;
TRY_CATCH (e, EXCEPTION_ALL) { TRY_CATCH (e, EXCEPTION_ALL) {
#if PC_HOSTED == 1 #if PC_HOSTED == 1
devs = platform_adiv5_swdp_scan(targetid); devs = platform_adiv5_swdp_scan();
#else #else
devs = adiv5_swdp_scan(targetid); devs = adiv5_swdp_scan();
#endif #endif
} }
switch (e.type) { switch (e.type) {
@ -286,47 +254,13 @@ bool cmd_swdp_scan(target *t, int argc, char **argv)
} }
bool cmd_frequency(target *t, int argc, char **argv)
{
(void)t;
if (argc == 2) {
char *p;
uint32_t frequency = strtol(argv[1], &p, 10);
switch(*p) {
case 'k':
frequency *= 1000;
break;
case 'M':
frequency *= 1000*1000;
break;
}
platform_max_frequency_set(frequency);
}
uint32_t freq = platform_max_frequency_get();
if (freq == FREQ_FIXED)
gdb_outf("SWJ freq fixed\n");
else
gdb_outf("Max SWJ freq %08" PRIx32 "\n", freq);
return true;
}
static void display_target(int i, target *t, void *context) static void display_target(int i, target *t, void *context)
{ {
(void)context; (void)context;
if (!strcmp(target_driver_name(t), "ARM Cortex-M")) {
gdb_outf("***%2d%sUnknown %s Designer %3x Partno %3x %s\n",
i, target_attached(t)?" * ":" ",
target_driver_name(t),
target_designer(t),
target_idcode(t),
(target_core_name(t)) ? target_core_name(t): "");
} else {
gdb_outf("%2d %c %s %s\n", i, target_attached(t)?'*':' ', gdb_outf("%2d %c %s %s\n", i, target_attached(t)?'*':' ',
target_driver_name(t), target_driver_name(t),
(target_core_name(t)) ? target_core_name(t): ""); (target_core_name(t)) ? target_core_name(t): "");
} }
}
bool cmd_targets(target *t, int argc, char **argv) bool cmd_targets(target *t, int argc, char **argv)
{ {
@ -348,10 +282,8 @@ bool cmd_morse(target *t, int argc, char **argv)
(void)t; (void)t;
(void)argc; (void)argc;
(void)argv; (void)argv;
if(morse_msg) { if(morse_msg)
gdb_outf("%s\n", morse_msg); gdb_outf("%s\n", morse_msg);
DEBUG_WARN("%s\n", morse_msg);
}
return true; return true;
} }
@ -423,16 +355,9 @@ static bool cmd_target_power(target *t, int argc, const char **argv)
} else if (argc == 2) { } else if (argc == 2) {
bool want_enable = false; bool want_enable = false;
if (parse_enable_or_disable(argv[1], &want_enable)) { if (parse_enable_or_disable(argv[1], &want_enable)) {
if (want_enable
&& !platform_target_get_power()
&& platform_target_voltage_sense() > POWER_CONFLICT_THRESHOLD) {
/* want to enable target power, but VREF > 0.5V sensed -> cancel */
gdb_outf("Target already powered (%s)\n", platform_target_voltage());
} else {
platform_target_set_power(want_enable); platform_target_set_power(want_enable);
gdb_outf("%s target power\n", want_enable ? "Enabling" : "Disabling"); gdb_outf("%s target power\n", want_enable ? "Enabling" : "Disabling");
} }
}
} else { } else {
gdb_outf("Unrecognized command format\n"); gdb_outf("Unrecognized command format\n");
} }
@ -440,86 +365,10 @@ static bool cmd_target_power(target *t, int argc, const char **argv)
} }
#endif #endif
#ifdef ENABLE_RTT
static const char *on_or_off(const bool value)
{
return value ? "on" : "off";
}
static bool cmd_rtt(target *t, int argc, const char **argv)
{
(void)t;
const size_t command_len = strlen(argv[1]);
if (argc == 1 || (argc == 2 && !strncmp(argv[1], "enabled", command_len))) {
rtt_enabled = true;
rtt_found = false;
} else if ((argc == 2) && !strncmp(argv[1], "disabled", command_len)) {
rtt_enabled = false;
rtt_found = false;
} else if ((argc == 2) && !strncmp(argv[1], "status", command_len)) {
gdb_outf("rtt: %s found: %s ident: \"%s\"", on_or_off(rtt_enabled), rtt_found ? "yes" : "no",
rtt_ident[0] == '\0' ? "off" : rtt_ident);
gdb_outf(" halt: %s", on_or_off(target_no_background_memory_access(t)));
gdb_out(" channels: ");
if (rtt_auto_channel)
gdb_out("auto ");
for (size_t i = 0; i < MAX_RTT_CHAN; i++) {
if (rtt_channel[i].is_enabled)
gdb_outf("%d ", i);
}
gdb_outf(
"\nmax poll ms: %u min poll ms: %u max errs: %u\n", rtt_max_poll_ms, rtt_min_poll_ms, rtt_max_poll_errs);
} else if (argc >= 2 && !strncmp(argv[1], "channel", command_len)) {
/* mon rtt channel switches to auto rtt channel selection
mon rtt channel number... selects channels given */
for (size_t i = 0; i < MAX_RTT_CHAN; i++)
rtt_channel[i].is_enabled = false;
if (argc == 2)
rtt_auto_channel = true;
else {
rtt_auto_channel = false;
for (size_t i = 2; i < (size_t)argc; ++i) {
const uint32_t channel = strtoul(argv[i], NULL, 0);
if (channel < MAX_RTT_CHAN)
rtt_channel[channel].is_enabled = true;
}
}
} else if (argc == 2 && !strncmp(argv[1], "ident", command_len))
rtt_ident[0] = '\0';
else if (argc == 2 && !strncmp(argv[1], "poll", command_len))
gdb_outf("%u %u %u\n", rtt_max_poll_ms, rtt_min_poll_ms, rtt_max_poll_errs);
else if (argc == 2 && !strncmp(argv[1], "cblock", command_len)) {
gdb_outf("cbaddr: 0x%x\n", rtt_cbaddr);
gdb_out("ch ena cfg i/o buf@ size head@ tail@ flg\n");
for (size_t i = 0; i < MAX_RTT_CHAN; ++i) {
gdb_outf("%2zu %c %c %s 0x%08x %5d 0x%08x 0x%08x %d\n", i, rtt_channel[i].is_enabled ? 'y' : 'n',
rtt_channel[i].is_configured ? 'y' : 'n', rtt_channel[i].is_output ? "out" : "in ",
rtt_channel[i].buf_addr, rtt_channel[i].buf_size, rtt_channel[i].head_addr, rtt_channel[i].tail_addr,
rtt_channel[i].flag);
}
} else if (argc == 3 && !strncmp(argv[1], "ident", command_len)) {
strncpy(rtt_ident, argv[2], sizeof(rtt_ident));
rtt_ident[sizeof(rtt_ident) - 1] = '\0';
for (size_t i = 0; i < sizeof(rtt_ident); i++) {
if (rtt_ident[i] == '_')
rtt_ident[i] = ' ';
}
} else if (argc == 5 && !strncmp(argv[1], "poll", command_len)) {
/* set polling params */
rtt_max_poll_ms = strtoul(argv[2], NULL, 0);
rtt_min_poll_ms = strtoul(argv[3], NULL, 0);
rtt_max_poll_errs = strtoul(argv[4], NULL, 0);
} else
gdb_out("what?\n");
return true;
}
#endif
#ifdef PLATFORM_HAS_TRACESWO #ifdef PLATFORM_HAS_TRACESWO
static bool cmd_traceswo(target *t, int argc, const char **argv) static bool cmd_traceswo(target *t, int argc, const char **argv)
{ {
char serial_no[DFU_SERIAL_LENGTH]; char serial_no[13];
(void)t; (void)t;
#if TRACESWO_PROTOCOL == 2 #if TRACESWO_PROTOCOL == 2
uint32_t baudrate = SWO_DEFAULT_BAUD; uint32_t baudrate = SWO_DEFAULT_BAUD;
@ -565,7 +414,7 @@ static bool cmd_traceswo(target *t, int argc, const char **argv)
#else #else
traceswo_init(swo_channelmask); traceswo_init(swo_channelmask);
#endif #endif
serial_no_read(serial_no); serial_no_read(serial_no, sizeof(serial_no));
gdb_outf("%s:%02X:%02X\n", serial_no, 5, 0x85); gdb_outf("%s:%02X:%02X\n", serial_no, 5, 0x85);
return true; return true;
} }
@ -593,66 +442,6 @@ static bool cmd_debug_bmp(target *t, int argc, const char **argv)
return true; return true;
} }
#endif #endif
#ifdef PLATFORM_HAS_UART_WHEN_SWDP
static bool cmd_convert_tdio(target *t, int argc, const char **argv)
{
(void)t;
uint8_t val;
if (argc > 1) {
val = (!strcmp(argv[1], "enable")) ? true : false;
usbuart_convert_tdio(val);
} else {
gdb_outf("Convert_tdio: %s\n",(usbuart_convert_tdio_enabled()) ?
"enabled" : "disabled");
}
return true;
}
static bool cmd_set_srst(target *t, int argc, const char **argv)
{
(void) t;
uint8_t val;
if (argc > 1) {
val = (!strcmp(argv[1], "enable")) ? true : false;
platform_srst_set_val(val);
} else {
gdb_outf("SRST: %s\n",(platform_srst_get_val()) ?
"enabled" : "disabled");
}
return true;
}
#endif
#ifdef PLATFORM_HAS_BOOTLOADER
static bool cmd_enter_bootldr(target *t, int argc, const char **argv)
{
(void) t;
(void) argc;
(void) argv;
scb_reset_system();
return true;
}
#endif
#ifdef PLATFORM_HAS_PRINTSERIAL
bool cmd_serial(target *t, int argc, char **argv)
{
(void) t;
(void) argc;
(void) argv;
print_serial();
return true;
}
#endif
static bool cmd_heapinfo(target *t, int argc, const char **argv) static bool cmd_heapinfo(target *t, int argc, const char **argv)
{ {
if (t == NULL) gdb_out("not attached\n"); if (t == NULL) gdb_out("not attached\n");

View File

@ -20,7 +20,6 @@
#include "general.h" #include "general.h"
#include "target.h" #include "target.h"
#include "gdb_if.h"
#if !defined(STM32F0) && !defined(STM32F1) && !defined(STM32F2) && \ #if !defined(STM32F0) && !defined(STM32F1) && !defined(STM32F2) && \
!defined(STM32F3) && !defined(STM32F4) && !defined(STM32F7) && \ !defined(STM32F3) && !defined(STM32F4) && !defined(STM32F7) && \
@ -98,33 +97,14 @@ static uint32_t crc32_calc(uint32_t crc, uint8_t data)
return (crc << 8) ^ crc32_table[((crc >> 24) ^ data) & 255]; return (crc << 8) ^ crc32_table[((crc >> 24) ^ data) & 255];
} }
int generic_crc32(target *t, uint32_t *crc_res, uint32_t base, size_t len) uint32_t generic_crc32(target *t, uint32_t base, size_t len)
{ {
uint32_t crc = -1; uint32_t crc = -1;
#if PC_HOSTED == 1
/* Reading a 2 MByte on a H743 takes about 80 s@128, 28s @ 1k,
* 22 s @ 4k and 21 s @ 64k
*/
uint8_t bytes[0x1000];
#else
uint8_t bytes[128]; uint8_t bytes[128];
#endif
#if defined(ENABLE_DEBUG)
uint32_t start_time = platform_time_ms();
#endif
uint32_t last_time = platform_time_ms();
while (len) { while (len) {
uint32_t actual_time = platform_time_ms();
if ( actual_time > last_time + 1000) {
last_time = actual_time;
gdb_if_putchar(0, true);
}
size_t read_len = MIN(sizeof(bytes), len); size_t read_len = MIN(sizeof(bytes), len);
if (target_mem_read(t, bytes, base, read_len)) { target_mem_read(t, bytes, base, read_len);
DEBUG_WARN("generic_crc32 error around address 0x%08" PRIx32 "\n",
base);
return -1;
}
for (unsigned i = 0; i < read_len; i++) for (unsigned i = 0; i < read_len; i++)
crc = crc32_calc(crc, bytes[i]); crc = crc32_calc(crc, bytes[i]);
@ -132,32 +112,20 @@ int generic_crc32(target *t, uint32_t *crc_res, uint32_t base, size_t len)
base += read_len; base += read_len;
len -= read_len; len -= read_len;
} }
DEBUG_WARN("%" PRIu32 " ms\n", platform_time_ms() - start_time); return crc;
*crc_res = crc;
return 0;
} }
#else #else
#include <libopencm3/stm32/crc.h> #include <libopencm3/stm32/crc.h>
int generic_crc32(target *t, uint32_t *crc_res, uint32_t base, size_t len) uint32_t generic_crc32(target *t, uint32_t base, size_t len)
{ {
uint8_t bytes[128]; uint8_t bytes[128];
uint32_t crc; uint32_t crc;
CRC_CR |= CRC_CR_RESET; CRC_CR |= CRC_CR_RESET;
uint32_t last_time = platform_time_ms();
while (len > 3) { while (len > 3) {
uint32_t actual_time = platform_time_ms();
if ( actual_time > last_time + 1000) {
last_time = actual_time;
gdb_if_putchar(0, true);
}
size_t read_len = MIN(sizeof(bytes), len) & ~3; size_t read_len = MIN(sizeof(bytes), len) & ~3;
if (target_mem_read(t, bytes, base, read_len)) { target_mem_read(t, bytes, base, read_len);
DEBUG_WARN("generic_crc32 error around address 0x%08" PRIx32 "\n",
base);
return -1;
}
for (unsigned i = 0; i < read_len; i += 4) for (unsigned i = 0; i < read_len; i += 4)
CRC_DR = __builtin_bswap32(*(uint32_t*)(bytes+i)); CRC_DR = __builtin_bswap32(*(uint32_t*)(bytes+i));
@ -168,11 +136,7 @@ int generic_crc32(target *t, uint32_t *crc_res, uint32_t base, size_t len)
crc = CRC_DR; crc = CRC_DR;
if (target_mem_read(t, bytes, base, len)) { target_mem_read(t, bytes, base, len);
DEBUG_WARN("generic_crc32 error around address 0x%08" PRIx32 "\n",
base);
return -1;
}
uint8_t *data = bytes; uint8_t *data = bytes;
while (len--) { while (len--) {
crc ^= *data++ << 24; crc ^= *data++ << 24;
@ -183,8 +147,7 @@ int generic_crc32(target *t, uint32_t *crc_res, uint32_t base, size_t len)
crc <<= 1; crc <<= 1;
} }
} }
*crc_res = crc; return crc;
return 0;
} }
#endif #endif

View File

@ -26,6 +26,7 @@ struct exception *innermost_exception;
void raise_exception(uint32_t type, const char *msg) void raise_exception(uint32_t type, const char *msg)
{ {
struct exception *e; struct exception *e;
DEBUG_WARN("Exception: %s\n", msg);
for (e = innermost_exception; e; e = e->outer) { for (e = innermost_exception; e; e = e->outer) {
if (e->mask & type) { if (e->mask & type) {
e->type = type; e->type = type;
@ -34,7 +35,6 @@ void raise_exception(uint32_t type, const char *msg)
longjmp(e->jmpbuf, type); longjmp(e->jmpbuf, type);
} }
} }
DEBUG_WARN("Unhandled exception: %s\n", msg);
abort(); abort();
} }

View File

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

View File

@ -35,9 +35,6 @@
#include "command.h" #include "command.h"
#include "crc32.h" #include "crc32.h"
#include "morse.h" #include "morse.h"
#ifdef ENABLE_RTT
#include "rtt.h"
#endif
enum gdb_signal { enum gdb_signal {
GDB_SIGINT = 2, GDB_SIGINT = 2,
@ -46,37 +43,25 @@ enum gdb_signal {
GDB_SIGLOST = 29, GDB_SIGLOST = 29,
}; };
#define BUF_SIZE 1024U #define BUF_SIZE 1024
#define ERROR_IF_NO_TARGET() \ #define ERROR_IF_NO_TARGET() \
if(!cur_target) { gdb_putpacketz("EFF"); break; } if(!cur_target) { gdb_putpacketz("EFF"); break; }
typedef struct static char pbuf[BUF_SIZE+1];
{
const char *cmd_prefix;
void (*func)(const char *packet, size_t len);
} cmd_executer;
static char pbuf[BUF_SIZE + 1U];
static target *cur_target; static target *cur_target;
static target *last_target; static target *last_target;
static bool gdb_needs_detach_notify = false;
static void handle_q_packet(char *packet, size_t len); static void handle_q_packet(char *packet, int len);
static void handle_v_packet(char *packet, size_t len); static void handle_v_packet(char *packet, int len);
static void handle_z_packet(char *packet, size_t len); static void handle_z_packet(char *packet, int len);
static void handle_kill_target(void);
static void gdb_target_destroy_callback(struct target_controller *tc, target *t) static void gdb_target_destroy_callback(struct target_controller *tc, target *t)
{ {
(void)tc; (void)tc;
if (cur_target == t) { if (cur_target == t)
gdb_put_notificationz("%Stop:W00");
gdb_out("You are now detached from the previous target.\n");
cur_target = NULL; cur_target = NULL;
gdb_needs_detach_notify = true;
}
if (last_target == t) if (last_target == t)
last_target = NULL; last_target = NULL;
@ -109,20 +94,22 @@ static struct target_controller gdb_controller = {
int gdb_main_loop(struct target_controller *tc, bool in_syscall) int gdb_main_loop(struct target_controller *tc, bool in_syscall)
{ {
int size;
bool single_step = false; bool single_step = false;
/* GDB protocol main loop */ /* GDB protocol main loop */
while(1) { while(1) {
SET_IDLE_STATE(1); SET_IDLE_STATE(1);
size_t size = gdb_getpacket(pbuf, BUF_SIZE); size = gdb_getpacket(pbuf, BUF_SIZE);
SET_IDLE_STATE(0); SET_IDLE_STATE(0);
switch(pbuf[0]) { switch(pbuf[0]) {
/* Implementation of these is mandatory! */ /* Implementation of these is mandatory! */
case 'g': { /* 'g': Read general registers */ case 'g': { /* 'g': Read general registers */
ERROR_IF_NO_TARGET(); ERROR_IF_NO_TARGET();
uint8_t gp_regs[target_regs_size(cur_target)]; uint8_t arm_regs[target_regs_size(cur_target)];
target_regs_read(cur_target, gp_regs); target_regs_read(cur_target, arm_regs);
gdb_putpacket(hexify(pbuf, gp_regs, sizeof(gp_regs)), sizeof(gp_regs) * 2U); gdb_putpacket(hexify(pbuf, arm_regs, sizeof(arm_regs)),
sizeof(arm_regs) * 2);
break; break;
} }
case 'm': { /* 'm addr,len': Read len bytes from addr */ case 'm': { /* 'm addr,len': Read len bytes from addr */
@ -139,20 +126,19 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
if (target_mem_read(cur_target, mem, addr, len)) if (target_mem_read(cur_target, mem, addr, len))
gdb_putpacketz("E01"); gdb_putpacketz("E01");
else else
gdb_putpacket(hexify(pbuf, mem, len), len * 2U); gdb_putpacket(hexify(pbuf, mem, len), len*2);
break; break;
} }
case 'G': { /* 'G XX': Write general registers */ case 'G': { /* 'G XX': Write general registers */
ERROR_IF_NO_TARGET(); ERROR_IF_NO_TARGET();
uint8_t gp_regs[target_regs_size(cur_target)]; uint8_t arm_regs[target_regs_size(cur_target)];
unhexify(gp_regs, &pbuf[1], sizeof(gp_regs)); unhexify(arm_regs, &pbuf[1], sizeof(arm_regs));
target_regs_write(cur_target, gp_regs); target_regs_write(cur_target, arm_regs);
gdb_putpacketz("OK"); gdb_putpacketz("OK");
break; break;
} }
case 'M': { /* 'M addr,len:XX': Write len bytes to addr */ case 'M': { /* 'M addr,len:XX': Write len bytes to addr */
uint32_t addr = 0; uint32_t addr, len;
uint32_t len = 0;
int hex; int hex;
ERROR_IF_NO_TARGET(); ERROR_IF_NO_TARGET();
sscanf(pbuf, "M%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &hex); sscanf(pbuf, "M%" SCNx32 ",%" SCNx32 ":%n", &addr, &len, &hex);
@ -170,19 +156,6 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
gdb_putpacketz("OK"); gdb_putpacketz("OK");
break; break;
} }
/* '[m|M|g|G|c][thread-id]' : Set the thread ID for the given subsequent operation
* (we don't actually care which as we only care about the TID for whether to send OK or an error)
*/
case 'H': {
char operation = 0;
uint32_t thread_id = 0;
sscanf(pbuf, "H%c%" SCNx32, &operation, &thread_id);
if (thread_id <= 1)
gdb_putpacketz("OK");
else
gdb_putpacketz("E01");
break;
}
case 's': /* 's [addr]': Single step [start at addr] */ case 's': /* 's [addr]': Single step [start at addr] */
single_step = true; single_step = true;
/* fall through */ /* fall through */
@ -210,13 +183,10 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
/* Wait for target halt */ /* Wait for target halt */
while(!(reason = target_halt_poll(cur_target, &watch))) { while(!(reason = target_halt_poll(cur_target, &watch))) {
char c = (char)gdb_if_getchar_to(0); unsigned char c = gdb_if_getchar_to(0);
if(c == '\x03' || c == '\x04') { if((c == '\x03') || (c == '\x04')) {
target_halt_request(cur_target); target_halt_request(cur_target);
} }
#ifdef ENABLE_RTT
if (rtt_enabled) poll_rtt(cur_target);
#endif
} }
SET_RUN_STATE(0); SET_RUN_STATE(0);
@ -248,10 +218,11 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
sscanf(pbuf, "p%" SCNx32, &reg); sscanf(pbuf, "p%" SCNx32, &reg);
uint8_t val[8]; uint8_t val[8];
size_t s = target_reg_read(cur_target, reg, val, sizeof(val)); size_t s = target_reg_read(cur_target, reg, val, sizeof(val));
if (s > 0) if (s > 0) {
gdb_putpacket(hexify(pbuf, val, s), s * 2); gdb_putpacket(hexify(pbuf, val, s), s * 2);
else } else {
gdb_putpacketz("EFF"); gdb_putpacketz("EFF");
}
break; break;
} }
case 'P': { /* Write single register */ case 'P': { /* Write single register */
@ -259,20 +230,20 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
uint32_t reg; uint32_t reg;
int n; int n;
sscanf(pbuf, "P%" SCNx32 "=%n", &reg, &n); sscanf(pbuf, "P%" SCNx32 "=%n", &reg, &n);
// TODO: FIXME, VLAs considered harmful.
uint8_t val[strlen(&pbuf[n])/2]; uint8_t val[strlen(&pbuf[n])/2];
unhexify(val, pbuf + n, sizeof(val)); unhexify(val, pbuf + n, sizeof(val));
if (target_reg_write(cur_target, reg, val, sizeof(val)) > 0) if (target_reg_write(cur_target, reg, val, sizeof(val)) > 0) {
gdb_putpacketz("OK"); gdb_putpacketz("OK");
else } else {
gdb_putpacketz("EFF"); gdb_putpacketz("EFF");
}
break; break;
} }
case 'F': /* Semihosting call finished */ case 'F': /* Semihosting call finished */
if (in_syscall) if (in_syscall) {
return hostio_reply(tc, pbuf, size); return hostio_reply(tc, pbuf, size);
else { } else {
DEBUG_GDB("*** F packet when not in syscall! '%s'\n", pbuf); DEBUG_GDB("*** F packet when not in syscall! '%s'\n", pbuf);
gdb_putpacketz(""); gdb_putpacketz("");
} }
@ -298,7 +269,12 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
break; break;
case 'k': /* Kill the target */ case 'k': /* Kill the target */
handle_kill_target(); if(cur_target) {
target_reset(cur_target);
target_detach(cur_target);
last_target = cur_target;
cur_target = NULL;
}
break; break;
case 'r': /* Reset the target system */ case 'r': /* Reset the target system */
@ -308,8 +284,6 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
else if(last_target) { else if(last_target) {
cur_target = target_attach(last_target, cur_target = target_attach(last_target,
&gdb_controller); &gdb_controller);
if(cur_target)
morse(NULL, false);
target_reset(cur_target); target_reset(cur_target);
} }
break; break;
@ -336,7 +310,7 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
handle_q_packet(pbuf, size); handle_q_packet(pbuf, size);
break; break;
case 'v': /* Verbose command packet */ case 'v': /* General query packet */
handle_v_packet(pbuf, size); handle_v_packet(pbuf, size);
break; break;
@ -354,73 +328,57 @@ int gdb_main_loop(struct target_controller *tc, bool in_syscall)
} }
} }
static bool exec_command(char *packet, const size_t length, const cmd_executer *exec) static void
handle_q_string_reply(const char *str, const char *param)
{ {
while (exec->cmd_prefix) { unsigned long addr, len;
const size_t prefix_length = strlen(exec->cmd_prefix);
if (!strncmp(packet, exec->cmd_prefix, prefix_length)) { if (sscanf(param, "%08lx,%08lx", &addr, &len) != 2) {
exec->func(packet + prefix_length, length - prefix_length); gdb_putpacketz("E01");
return true; return;
} }
++exec; if (addr < strlen (str)) {
} char reply[len+2];
return false; reply[0] = 'm';
strncpy (reply + 1, &str[addr], len);
if(len > strlen(&str[addr]))
len = strlen(&str[addr]);
gdb_putpacket(reply, len + 1);
} else if (addr == strlen (str)) {
gdb_putpacketz("l");
} else
gdb_putpacketz("E01");
} }
static void exec_q_rcmd(const char *packet, const size_t length) static void
handle_q_packet(char *packet, int len)
{ {
uint32_t addr, alen;
if(!strncmp(packet, "qRcmd,", 6)) {
char *data;
int datalen;
/* calculate size and allocate buffer for command */ /* calculate size and allocate buffer for command */
const size_t datalen = length / 2U; datalen = (len - 6) / 2;
char *data = alloca(datalen + 1); data = alloca(datalen+1);
/* dehexify command */ /* dehexify command */
unhexify(data, packet, datalen); unhexify(data, packet+6, datalen);
data[datalen] = 0; /* add terminating null */ data[datalen] = 0; /* add terminating null */
const int c = command_process(cur_target, data); int c = command_process(cur_target, data);
if(c < 0) if(c < 0)
gdb_putpacketz(""); gdb_putpacketz("");
else if(c == 0) else if(c == 0)
gdb_putpacketz("OK"); gdb_putpacketz("OK");
else else
gdb_putpacket(hexify(pbuf, "Failed\n", strlen("Failed\n")), gdb_putpacketz("E");
2 * strlen("Failed\n"));
}
static void handle_q_string_reply(const char *reply, const char *param) } else if (!strncmp (packet, "qSupported", 10)) {
{ /* Query supported protocol features */
const size_t reply_length = strlen(reply);
uint32_t addr = 0;
uint32_t len = 0;
if (sscanf(param, "%08" PRIx32 ",%08" PRIx32, &addr, &len) != 2) {
gdb_putpacketz("E01");
return;
}
if (addr > reply_length) {
gdb_putpacketz("E01");
return;
}
if (addr == reply_length) {
gdb_putpacketz("l");
return;
}
size_t output_len = reply_length - addr;
if (output_len > len)
output_len = len;
gdb_putpacket2("m", 1U, reply + addr, output_len);
}
static void exec_q_supported(const char *packet, const size_t length)
{
(void)packet;
(void)length;
gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+;qXfer:features:read+", BUF_SIZE); gdb_putpacket_f("PacketSize=%X;qXfer:memory-map:read+;qXfer:features:read+", BUF_SIZE);
}
static void exec_q_memory_map(const char *packet, const size_t length) } else if (strncmp (packet, "qXfer:memory-map:read::", 23) == 0) {
{
(void)packet;
(void)length;
/* Read target XML memory map */ /* Read target XML memory map */
if((!cur_target) && last_target) { if((!cur_target) && last_target) {
/* Attach to last target if detached. */ /* Attach to last target if detached. */
@ -433,164 +391,76 @@ static void exec_q_memory_map(const char *packet, const size_t length)
} }
char buf[1024]; char buf[1024];
target_mem_map(cur_target, buf, sizeof(buf)); /* Fixme: Check size!*/ target_mem_map(cur_target, buf, sizeof(buf)); /* Fixme: Check size!*/
handle_q_string_reply(buf, packet); handle_q_string_reply(buf, packet + 23);
}
static void exec_q_feature_read(const char *packet, const size_t length) } else if (strncmp (packet, "qXfer:features:read:target.xml:", 31) == 0) {
{
(void)length;
/* Read target description */ /* Read target description */
if((!cur_target) && last_target) { if((!cur_target) && last_target) {
/* Attach to last target if detached. */ /* Attach to last target if detached. */
cur_target = target_attach(last_target, &gdb_controller); cur_target = target_attach(last_target,
&gdb_controller);
} }
if (!cur_target) { if (!cur_target) {
gdb_putpacketz("E01"); gdb_putpacketz("E01");
return; return;
} }
handle_q_string_reply(target_tdesc(cur_target), packet); handle_q_string_reply(target_tdesc(cur_target), packet + 31);
} } else if (sscanf(packet, "qCRC:%" PRIx32 ",%" PRIx32, &addr, &alen) == 2) {
static void exec_q_crc(const char *packet, const size_t length)
{
(void)length;
uint32_t addr;
uint32_t addr_length;
if (sscanf(packet, "%" PRIx32 ",%" PRIx32, &addr, &addr_length) == 2) {
if(!cur_target) { if(!cur_target) {
gdb_putpacketz("E01"); gdb_putpacketz("E01");
return; return;
} }
uint32_t crc; gdb_putpacket_f("C%lx", generic_crc32(cur_target, addr, alen));
if (generic_crc32(cur_target, &crc, addr, addr_length))
gdb_putpacketz("E03");
else
gdb_putpacket_f("C%lx", crc);
}
}
/* } else {
* qC queries are for the current thread. We don't support threads but GDB 11 and 12 require this,
* so we always answer that the current thread is thread 1.
*/
static void exec_q_c(const char *packet, const size_t length)
{
(void)packet;
(void)length;
gdb_putpacketz("QC1");
}
/*
* qfThreadInfo queries are required in GDB 11 and 12 as these GDBs require the server to support
* threading even when there's only the possiblity for one thread to exist. In this instance,
* we have to tell GDB that there is a single active thread so it doesn't think the "thread" died.
* qsThreadInfo will always follow qfThreadInfo when we reply as we have to specify 'l' at the
* end to terminate the list.. GDB doesn't like this not happening.
*/
static void exec_q_thread_info(const char *packet, const size_t length)
{
(void)length;
if (packet[-11] == 'f')
gdb_putpacketz("m1");
else
gdb_putpacketz("l");
}
static const cmd_executer q_commands[]=
{
{"qRcmd,", exec_q_rcmd},
{"qSupported", exec_q_supported},
{"qXfer:memory-map:read::", exec_q_memory_map},
{"qXfer:features:read:target.xml:",exec_q_feature_read},
{"qCRC:", exec_q_crc},
{"qC", exec_q_c},
{"qfThreadInfo", exec_q_thread_info},
{"qsThreadInfo", exec_q_thread_info},
{NULL, NULL},
};
static void handle_kill_target(void)
{
if (cur_target) {
target_reset(cur_target);
target_detach(cur_target);
last_target = cur_target;
cur_target = NULL;
}
}
static void handle_q_packet(char *packet, const size_t length)
{
if (exec_command(packet, length, q_commands))
return;
DEBUG_GDB("*** Unsupported packet: %s\n", packet); DEBUG_GDB("*** Unsupported packet: %s\n", packet);
gdb_putpacket("", 0); gdb_putpacket("", 0);
} }
}
static void handle_v_packet(char *packet, const size_t plen) static void
handle_v_packet(char *packet, int plen)
{ {
uint32_t addr = 0; unsigned long addr, len;
uint32_t len = 0;
int bin; int bin;
static uint8_t flash_mode = 0; static uint8_t flash_mode = 0;
if (sscanf(packet, "vAttach;%08" PRIx32, &addr) == 1) { if (sscanf(packet, "vAttach;%08lx", &addr) == 1) {
/* Attach to remote target processor */ /* Attach to remote target processor */
cur_target = target_attach_n(addr, &gdb_controller); cur_target = target_attach_n(addr, &gdb_controller);
if(cur_target) { if(cur_target)
morse(NULL, false); gdb_putpacketz("T05");
/* else
* We don't actually support threads, but GDB 11 and 12 can't work without
* us saying we attached to thread 1.. see the following for the low-down of this:
* https://sourceware.org/bugzilla/show_bug.cgi?id=28405
* https://sourceware.org/bugzilla/show_bug.cgi?id=28874
* https://sourceware.org/pipermail/gdb-patches/2021-December/184171.html
* https://sourceware.org/pipermail/gdb-patches/2022-April/188058.html
* https://sourceware.org/pipermail/gdb-patches/2022-July/190869.html
*/
gdb_putpacketz("T05thread:1;");
} else
gdb_putpacketz("E01"); gdb_putpacketz("E01");
} else if (!strncmp(packet, "vKill;", 6)) {
/* Kill the target - we don't actually care about the PID that follows "vKill;" */
handle_kill_target();
gdb_putpacketz("OK");
} else if (!strncmp(packet, "vRun", 4)) { } else if (!strncmp(packet, "vRun", 4)) {
/* Parse command line for get_cmdline semihosting call */ /* Parse command line for get_cmdline semihosting call */
char cmdline[83]; char cmdline[83];
char *pcmdline = cmdline; char *pbuf = cmdline;
char *tok = packet + 4; char *tok = packet + 4;
if (*tok == ';') if (*tok == ';') tok++;
++tok; *cmdline='\0';
cmdline[0] = '\0';
while(*tok != '\0') { while(*tok != '\0') {
if (strlen(cmdline) + 3 >= sizeof(cmdline)) if(strlen(cmdline)+3 >= sizeof(cmdline)) break;
break;
if (*tok == ';') { if (*tok == ';') {
*pcmdline++ = ' '; *pbuf++=' ';
pcmdline[0] = '\0'; *pbuf='\0';
tok++; tok++;
continue; continue;
} }
if (isxdigit(tok[0]) && isxdigit(tok[1])) { if (isxdigit(*tok) && isxdigit(*(tok+1))) {
unhexify(pcmdline, tok, 2); unhexify(pbuf, tok, 2);
if ((*pcmdline == ' ') || (*pcmdline == '\\')) { if ((*pbuf == ' ') || (*pbuf == '\\')) {
pcmdline[1] = *pcmdline; *(pbuf+1)=*pbuf;
*pcmdline++ = '\\'; *pbuf++='\\';
} }
pcmdline++; pbuf++;
tok+=2; tok+=2;
pcmdline[0] = '\0'; *pbuf='\0';
continue; continue;
} }
break; break;
} }
#ifdef ENABLE_RTT
/* force searching rtt control block */
rtt_found = false;
#endif
/* Run target program. For us (embedded) this means reset. */ /* Run target program. For us (embedded) this means reset. */
if(cur_target) { if(cur_target) {
target_set_cmdline(cur_target, cmdline); target_set_cmdline(cur_target, cmdline);
@ -604,21 +474,15 @@ static void handle_v_packet(char *packet, const size_t plen)
if (cur_target) { if (cur_target) {
target_set_cmdline(cur_target, cmdline); target_set_cmdline(cur_target, cmdline);
target_reset(cur_target); target_reset(cur_target);
morse(NULL, false);
gdb_putpacketz("T05"); gdb_putpacketz("T05");
} else } else gdb_putpacketz("E01");
gdb_putpacketz("E01");
} else } else gdb_putpacketz("E01");
gdb_putpacketz("E01");
} else if (sscanf(packet, "vFlashErase:%08" PRIx32 ",%08" PRIx32, &addr, &len) == 2) { } else if (sscanf(packet, "vFlashErase:%08lx,%08lx", &addr, &len) == 2) {
/* Erase Flash Memory */ /* Erase Flash Memory */
DEBUG_GDB("Flash Erase %08" PRIX32 " %08" PRIX32 "\n", addr, len); DEBUG_GDB("Flash Erase %08lX %08lX\n", addr, len);
if (!cur_target) { if(!cur_target) { gdb_putpacketz("EFF"); return; }
gdb_putpacketz("EFF");
return;
}
if(!flash_mode) { if(!flash_mode) {
/* Reset target if first flash command! */ /* Reset target if first flash command! */
@ -626,20 +490,20 @@ static void handle_v_packet(char *packet, const size_t plen)
target_reset(cur_target); target_reset(cur_target);
flash_mode = 1; flash_mode = 1;
} }
if (target_flash_erase(cur_target, addr, len) == 0) if(target_flash_erase(cur_target, addr, len) == 0) {
gdb_putpacketz("OK"); gdb_putpacketz("OK");
else { } else {
flash_mode = 0; flash_mode = 0;
gdb_putpacketz("EFF"); gdb_putpacketz("EFF");
} }
} else if (sscanf(packet, "vFlashWrite:%08" PRIx32 ":%n", &addr, &bin) == 1) { } else if (sscanf(packet, "vFlashWrite:%08lx:%n", &addr, &bin) == 1) {
/* Write Flash Memory */ /* Write Flash Memory */
const uint32_t count = plen - bin; len = plen - bin;
DEBUG_GDB("Flash Write %08" PRIX32 " %08" PRIX32 "\n", addr, count); DEBUG_GDB("Flash Write %08lX %08lX\n", addr, len);
if (cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, count) == 0) if(cur_target && target_flash_write(cur_target, addr, (void*)packet + bin, len) == 0) {
gdb_putpacketz("OK"); gdb_putpacketz("OK");
else { } else {
flash_mode = 0; flash_mode = 0;
gdb_putpacketz("EFF"); gdb_putpacketz("EFF");
} }
@ -649,41 +513,40 @@ static void handle_v_packet(char *packet, const size_t plen)
gdb_putpacketz(target_flash_done(cur_target) ? "EFF" : "OK"); gdb_putpacketz(target_flash_done(cur_target) ? "EFF" : "OK");
flash_mode = 0; flash_mode = 0;
} else if (!strcmp(packet, "vStopped")) {
if (gdb_needs_detach_notify) {
gdb_putpacketz("W00");
gdb_needs_detach_notify = false;
} else
gdb_putpacketz("OK");
} else { } else {
DEBUG_GDB("*** Unsupported packet: %s\n", packet); DEBUG_GDB("*** Unsupported packet: %s\n", packet);
gdb_putpacket("", 0); gdb_putpacket("", 0);
} }
} }
static void handle_z_packet(char *packet, const size_t plen) static void
handle_z_packet(char *packet, int plen)
{ {
(void)plen; (void)plen;
uint32_t type; uint8_t set = (packet[0] == 'Z') ? 1 : 0;
uint32_t len; int type, len;
uint32_t addr; uint32_t addr;
sscanf(packet, "%*[zZ]%" PRIu32 ",%08" PRIx32 ",%" PRIu32, &type, &addr, &len); int ret;
int ret = 0; /* I have no idea why this doesn't work. Seems to work
if (packet[0] == 'Z') * with real sscanf() though... */
//sscanf(packet, "%*[zZ]%hhd,%08lX,%hhd", &type, &addr, &len);
type = packet[1] - '0';
sscanf(packet + 2, ",%" PRIx32 ",%d", &addr, &len);
if(set)
ret = target_breakwatch_set(cur_target, type, addr, len); ret = target_breakwatch_set(cur_target, type, addr, len);
else else
ret = target_breakwatch_clear(cur_target, type, addr, len); ret = target_breakwatch_clear(cur_target, type, addr, len);
if (ret < 0) if (ret < 0) {
gdb_putpacketz("E01"); gdb_putpacketz("E01");
else if (ret > 0) } else if (ret > 0) {
gdb_putpacketz(""); gdb_putpacketz("");
else } else {
gdb_putpacketz("OK"); gdb_putpacketz("OK");
} }
}
void gdb_main(void) void gdb_main(void)
{ {

View File

@ -30,11 +30,12 @@
#include <stdarg.h> #include <stdarg.h>
size_t gdb_getpacket(char *packet, size_t size) int gdb_getpacket(char *packet, int size)
{ {
unsigned char c;
unsigned char csum; unsigned char csum;
char recv_csum[3]; char recv_csum[3];
size_t offset = 0; int i;
while(1) { while(1) {
/* Wait for packet start */ /* Wait for packet start */
@ -43,28 +44,25 @@ size_t gdb_getpacket(char *packet, size_t size)
* start ('$') or a BMP remote packet start ('!'). * start ('$') or a BMP remote packet start ('!').
*/ */
do { do {
/* Smells like bad code */ packet[0] = gdb_if_getchar();
packet[0] = (char)gdb_if_getchar(); if (packet[0]==0x04) return 1;
if (packet[0] == 0x04)
return 1;
} while ((packet[0] != '$') && (packet[0] != REMOTE_SOM)); } while ((packet[0] != '$') && (packet[0] != REMOTE_SOM));
#if PC_HOSTED == 0 #if PC_HOSTED == 0
if (packet[0]==REMOTE_SOM) { if (packet[0]==REMOTE_SOM) {
/* This is probably a remote control packet /* This is probably a remote control packet
* - get and handle it */ * - get and handle it */
offset = 0; i=0;
bool gettingRemotePacket=true; bool gettingRemotePacket=true;
while (gettingRemotePacket) { while (gettingRemotePacket) {
/* Smells like bad code */ c=gdb_if_getchar();
const char c = (char)gdb_if_getchar();
switch (c) { switch (c) {
case REMOTE_SOM: /* Oh dear, packet restarts */ case REMOTE_SOM: /* Oh dear, packet restarts */
offset = 0; i=0;
break; break;
case REMOTE_EOM: /* Complete packet for processing */ case REMOTE_EOM: /* Complete packet for processing */
packet[offset] = 0; packet[i]=0;
remotePacketProcess(offset, packet); remotePacketProcess(i,packet);
gettingRemotePacket=false; gettingRemotePacket=false;
break; break;
@ -74,8 +72,8 @@ size_t gdb_getpacket(char *packet, size_t size)
break; break;
default: default:
if (offset < size) { if (i<size) {
packet[offset++] = c; packet[i++]=c;
} else { } else {
/* Who knows what is going on...return to normality */ /* Who knows what is going on...return to normality */
gettingRemotePacket=false; gettingRemotePacket=false;
@ -83,143 +81,92 @@ size_t gdb_getpacket(char *packet, size_t size)
break; break;
} }
} }
/* Reset the packet buffer start character to zero, because function
* 'remotePacketProcess()' above overwrites this buffer, and
* an arbitrary character may have been placed there. If this is a '$'
* character, this will cause this loop to be terminated, which is wrong.
*/
packet[0] = 0;
} }
#endif #endif
} while (packet[0] != '$'); } while (packet[0] != '$');
offset = 0; i = 0; csum = 0;
csum = 0;
char c;
/* Capture packet data into buffer */ /* Capture packet data into buffer */
while ((c = (char)gdb_if_getchar()) != '#') { while((c = gdb_if_getchar()) != '#') {
/* If we run out of buffer space, exit early */ if(i == size) break; /* Oh shit */
if (offset == size)
break;
if(c == '$') { /* Restart capture */ if(c == '$') { /* Restart capture */
offset = 0; i = 0;
csum = 0; csum = 0;
continue; continue;
} }
if(c == '}') { /* escaped char */ if(c == '}') { /* escaped char */
c = gdb_if_getchar(); c = gdb_if_getchar();
csum += c + '}'; csum += c + '}';
packet[offset++] = c ^ 0x20; packet[i++] = c ^ 0x20;
continue; continue;
} }
csum += c; csum += c;
packet[offset++] = c; packet[i++] = c;
} }
recv_csum[0] = (char)gdb_if_getchar(); recv_csum[0] = gdb_if_getchar();
recv_csum[1] = (char)gdb_if_getchar(); recv_csum[1] = gdb_if_getchar();
recv_csum[2] = 0; recv_csum[2] = 0;
/* return packet if checksum matches */ /* return packet if checksum matches */
if (csum == strtol(recv_csum, NULL, 16)) if(csum == strtol(recv_csum, NULL, 16)) break;
break;
/* get here if checksum fails */ /* get here if checksum fails */
gdb_if_putchar('-', 1); /* send nack */ gdb_if_putchar('-', 1); /* send nack */
} }
gdb_if_putchar('+', 1); /* send ack */ gdb_if_putchar('+', 1); /* send ack */
packet[offset] = 0; packet[i] = 0;
#if PC_HOSTED == 1 #if PC_HOSTED == 1
DEBUG_GDB_WIRE("%s : ", __func__); DEBUG_GDB_WIRE("%s : ", __func__);
for (size_t j = 0; j < offset; j++) { for(int j = 0; j < i; j++) {
const char c = packet[j]; c = packet[j];
if (c >= ' ' && c < 0x7F) if ((c >= 32) && (c < 127))
DEBUG_GDB_WIRE("%c", c); DEBUG_GDB_WIRE("%c", c);
else else
DEBUG_GDB_WIRE("\\x%02X", c); DEBUG_GDB_WIRE("\\x%02X", c);
} }
DEBUG_GDB_WIRE("\n"); DEBUG_GDB_WIRE("\n");
#endif #endif
return offset; return i;
} }
static void gdb_next_char(char c, unsigned char *csum) void gdb_putpacket(const char *packet, int size)
{ {
int i;
unsigned char csum;
unsigned char c;
char xmit_csum[3];
int tries = 0;
do {
DEBUG_GDB_WIRE("%s : ", __func__);
csum = 0;
gdb_if_putchar('$', 0);
for(i = 0; i < size; i++) {
c = packet[i];
#if PC_HOSTED == 1 #if PC_HOSTED == 1
if ((c >= 32) && (c < 127)) if ((c >= 32) && (c < 127))
DEBUG_GDB_WIRE("%c", c); DEBUG_GDB_WIRE("%c", c);
else else
DEBUG_GDB_WIRE("\\x%02X", c); DEBUG_GDB_WIRE("\\x%02X", c);
#endif #endif
if ((c == '$') || (c == '#') || (c == '}') || (c == '*')) { if((c == '$') || (c == '#') || (c == '}')) {
gdb_if_putchar('}', 0); gdb_if_putchar('}', 0);
gdb_if_putchar(c ^ 0x20, 0); gdb_if_putchar(c ^ 0x20, 0);
*csum += '}' + (c ^ 0x20); csum += '}' + (c ^ 0x20);
} } else {
else {
gdb_if_putchar(c, 0); gdb_if_putchar(c, 0);
*csum += c; csum += c;
} }
} }
void gdb_putpacket2(const char *packet1, size_t size1, const char *packet2, size_t size2)
{
char xmit_csum[3];
size_t tries = 0;
do {
DEBUG_GDB_WIRE("%s: ", __func__);
unsigned char csum = 0;
gdb_if_putchar('$', 0);
for (size_t i = 0; i < size1; ++i)
gdb_next_char(packet1[i], &csum);
for (size_t i = 0; i < size2; ++i)
gdb_next_char(packet2[i], &csum);
gdb_if_putchar('#', 0);
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
gdb_if_putchar(xmit_csum[0], 0);
gdb_if_putchar(xmit_csum[1], 1);
DEBUG_GDB_WIRE("\n");
} while (gdb_if_getchar_to(2000) != '+' && tries++ < 3);
}
void gdb_putpacket(const char *packet, size_t size)
{
char xmit_csum[3];
size_t tries = 0;
do {
DEBUG_GDB_WIRE("%s: ", __func__);
unsigned char csum = 0;
gdb_if_putchar('$', 0);
for (size_t i = 0; i < size; ++i)
gdb_next_char(packet[i], &csum);
gdb_if_putchar('#', 0);
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
gdb_if_putchar(xmit_csum[0], 0);
gdb_if_putchar(xmit_csum[1], 1);
DEBUG_GDB_WIRE("\n");
} while (gdb_if_getchar_to(2000) != '+' && tries++ < 3);
}
void gdb_put_notification(const char *const packet, const size_t size)
{
char xmit_csum[3];
DEBUG_GDB_WIRE("%s: ", __func__);
uint8_t csum = 0;
gdb_if_putchar('%', 0);
for (size_t i = 0; i < size; ++i)
gdb_next_char(packet[i], &csum);
gdb_if_putchar('#', 0); gdb_if_putchar('#', 0);
snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum); snprintf(xmit_csum, sizeof(xmit_csum), "%02X", csum);
gdb_if_putchar(xmit_csum[0], 0); gdb_if_putchar(xmit_csum[0], 0);
gdb_if_putchar(xmit_csum[1], 1); gdb_if_putchar(xmit_csum[1], 1);
DEBUG_GDB_WIRE("\n"); DEBUG_GDB_WIRE("\n");
} while((gdb_if_getchar_to(2000) != '+') && (tries++ < 3));
} }
void gdb_putpacket_f(const char *fmt, ...) void gdb_putpacket_f(const char *fmt, ...)
@ -237,13 +184,13 @@ void gdb_putpacket_f(const char *fmt, ...)
void gdb_out(const char *buf) void gdb_out(const char *buf)
{ {
int l = strlen(buf); char *hexdata;
char *hexdata = calloc(1, 2 * l + 1); int i;
if (!hexdata)
return; hexdata = alloca((i = strlen(buf)*2 + 1) + 1);
hexify(hexdata, buf, l); hexdata[0] = 'O';
gdb_putpacket2("O", 1, hexdata, 2 * l); hexify(hexdata+1, buf, strlen(buf));
free(hexdata); gdb_putpacket(hexdata, i);
} }
void gdb_voutf(const char *fmt, va_list ap) void gdb_voutf(const char *fmt, va_list ap)

View File

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

View File

@ -21,6 +21,6 @@
#ifndef __CRC32_H #ifndef __CRC32_H
#define __CRC32_H #define __CRC32_H
int generic_crc32(target *t, uint32_t *crc, uint32_t base, int len); uint32_t generic_crc32(target *t, uint32_t base, int len);
#endif #endif

View File

@ -29,8 +29,6 @@ void gdb_usb_out_cb(usbd_device *dev, uint8_t ep);
int gdb_if_init(void); int gdb_if_init(void);
unsigned char gdb_if_getchar(void); unsigned char gdb_if_getchar(void);
unsigned char gdb_if_getchar_to(int timeout); unsigned char gdb_if_getchar_to(int timeout);
/* sending gdb_if_putchar(0, true) seems to work as keep alive */
void gdb_if_putchar(unsigned char c, int flush); void gdb_if_putchar(unsigned char c, int flush);
#endif #endif

View File

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

View File

@ -21,9 +21,7 @@
#ifndef __GENERAL_H #ifndef __GENERAL_H
#define __GENERAL_H #define __GENERAL_H
#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE #define _GNU_SOURCE
#endif
#if !defined(__USE_MINGW_ANSI_STDIO) #if !defined(__USE_MINGW_ANSI_STDIO)
# define __USE_MINGW_ANSI_STDIO 1 # define __USE_MINGW_ANSI_STDIO 1
#endif #endif
@ -39,8 +37,6 @@
#include "platform.h" #include "platform.h"
#include "platform_support.h" #include "platform_support.h"
extern uint32_t delay_cnt;
enum BMP_DEBUG { enum BMP_DEBUG {
BMP_DEBUG_NONE = 0, BMP_DEBUG_NONE = 0,
BMP_DEBUG_INFO = 1, BMP_DEBUG_INFO = 1,
@ -52,28 +48,23 @@ enum BMP_DEBUG {
BMP_DEBUG_STDOUT = 0x8000, BMP_DEBUG_STDOUT = 0x8000,
}; };
#define FREQ_FIXED 0xffffffff
#if PC_HOSTED == 0 #if PC_HOSTED == 0
/* For BMP debug output on a firmware BMP platform, using /* For BMP debug output on a firmware BMP platform, using
* BMP PC-Hosted is the preferred way. Printing DEBUG_WARN * BMP PC-Hosted is the preferred way. Printing DEBUG_WARN
* and DEBUG_INFO is kept for comptibiluty. * and DEBUG_INFO is kept for comptibiluty.
*/ */
# if !defined(PLATFORM_PRINTF)
# define PLATFORM_PRINTF printf
# endif
# if defined(ENABLE_DEBUG) # if defined(ENABLE_DEBUG)
# define DEBUG_WARN PLATFORM_PRINTF # define DEBUG_WARN printf
# define DEBUG_INFO PLATFORM_PRINTF # define DEBUG_INFO printf
# else # else
# define DEBUG_WARN(...) do {} while(0) # define DEBUG_WARN(...)
# define DEBUG_INFO(...) do {} while(0) # define DEBUG_INFO(...)
# endif # endif
# define DEBUG_GDB(...) do {} while(0) # define DEBUG_GDB(...)
# define DEBUG_TARGET(...) do {} while(0) # define DEBUG_TARGET(...)
# define DEBUG_PROBE(...) do {} while(0) # define DEBUG_PROBE(...)
# define DEBUG_WIRE(...) do {} while(0) # define DEBUG_WIRE(...)
# define DEBUG_GDB_WIRE(...) do {} while(0) # define DEBUG_GDB_WIRE(...)
#else #else
# include <stdarg.h> # include <stdarg.h>
extern int cl_debuglevel; extern int cl_debuglevel;
@ -164,11 +155,5 @@ static inline void DEBUG_WIRE(const char *format, ...)
#undef MAX #undef MAX
#define MAX(x, y) (((x) > (y)) ? (x) : (y)) #define MAX(x, y) (((x) > (y)) ? (x) : (y))
#if !defined(SYSTICKHZ)
# define SYSTICKHZ 100
#endif
#define SYSTICKMS (1000 / SYSTICKHZ)
#define MORSECNT ((SYSTICKHZ / 10) - 1)
#endif #endif

View File

@ -37,9 +37,7 @@ void platform_timeout_set(platform_timeout *t, uint32_t ms);
bool platform_timeout_is_expired(platform_timeout *t); bool platform_timeout_is_expired(platform_timeout *t);
void platform_delay(uint32_t ms); void platform_delay(uint32_t ms);
#define POWER_CONFLICT_THRESHOLD 5 /* in 0.1V, so 5 stands for 0.5V */
extern bool connect_assert_srst; extern bool connect_assert_srst;
uint32_t platform_target_voltage_sense(void);
const char *platform_target_voltage(void); const char *platform_target_voltage(void);
int platform_hwversion(void); int platform_hwversion(void);
void platform_srst_set_val(bool assert); void platform_srst_set_val(bool assert);
@ -47,8 +45,6 @@ bool platform_srst_get_val(void);
bool platform_target_get_power(void); bool platform_target_get_power(void);
void platform_target_set_power(bool power); void platform_target_set_power(bool power);
void platform_request_boot(void); void platform_request_boot(void);
void platform_max_frequency_set(uint32_t frequency);
uint32_t platform_max_frequency_get(void);
#endif #endif

View File

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

View File

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

View File

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

View File

@ -20,7 +20,7 @@
#ifndef __SERIALNO_H #ifndef __SERIALNO_H
#define __SERIALNO_H #define __SERIALNO_H
char *serial_no_read(char *s); char *serial_no_read(char *s, int max);
#endif #endif

View File

@ -1,7 +1,8 @@
/* /*
* This file is part of the libopenstm32 project. * This file is part of the Black Magic Debug project.
* *
* Copyright (C) 2010 Thomas Otto <tommi@viadmin.org> * 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 * 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 * it under the terms of the GNU General Public License as published by
@ -17,12 +18,19 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/* Define memory regions. */ #ifndef __SWDPTAP_H
MEMORY #define __SWDPTAP_H
{ typedef struct swd_proc_s {
rom (rx) : ORIGIN = 0x00002000, LENGTH = 120K /* 128k - 8k for bootloader */ uint32_t (*swdptap_seq_in)(int ticks);
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 16K bool (*swdptap_seq_in_parity)(uint32_t *data, int ticks);
} void (*swdptap_seq_out)(uint32_t MS, int ticks);
void (*swdptap_seq_out_parity)(uint32_t MS, int ticks);
} swd_proc_t;
extern swd_proc_t swd_proc;
/* Include the common ld script from libopenstm32. */ # if PC_HOSTED == 1
INCLUDE cortex-m-generic.ld int platform_swdptap_init(void);
# else
int swdptap_init(void);
# endif
#endif

View File

@ -35,13 +35,13 @@ typedef uint32_t target_addr;
struct target_controller; struct target_controller;
#if PC_HOSTED == 1 #if PC_HOSTED == 1
int platform_adiv5_swdp_scan(uint32_t targetid); int platform_adiv5_swdp_scan(void);
int platform_jtag_scan(const uint8_t *lrlens); int platform_jtag_scan(const uint8_t *lrlens);
#endif #endif
int adiv5_swdp_scan(uint32_t targetid); int adiv5_swdp_scan(void);
int jtag_scan(const uint8_t *lrlens); int jtag_scan(const uint8_t *lrlens);
int target_foreach(void (*cb)(int i, target *t, void *context), void *context); bool target_foreach(void (*cb)(int i, target *t, void *context), void *context);
void target_list_free(void); void target_list_free(void);
/* Attach/detach functions */ /* Attach/detach functions */
@ -51,8 +51,6 @@ void target_detach(target *t);
bool target_attached(target *t); bool target_attached(target *t);
const char *target_driver_name(target *t); const char *target_driver_name(target *t);
const char *target_core_name(target *t); const char *target_core_name(target *t);
unsigned int target_designer(target *t);
unsigned int target_idcode(target *t);
/* Memory access functions */ /* Memory access functions */
bool target_mem_map(target *t, char *buf, size_t len); bool target_mem_map(target *t, char *buf, size_t len);

View File

@ -24,7 +24,6 @@ struct platform_timeout {
uint32_t time; uint32_t time;
}; };
extern int32_t swj_delay_cnt;
uint32_t platform_time_ms(void); uint32_t platform_time_ms(void);
#endif /* __TIMING_H */ #endif /* __TIMING_H */

View File

@ -24,18 +24,6 @@
* field firmware upgrade. * field firmware upgrade.
* *
* The device's unique id is used as the USB serial number string. * The device's unique id is used as the USB serial number string.
*
* Endpoint Usage
*
* 0 Control Endpoint
* IN 1 GDB CDC DATA
* OUT 1 GDB CDC DATA
* IN 2 GDB CDC CTR
* IN 3 UART CDC DATA
* OUT 3 UART CDC DATA
* OUT 4 UART CDC CTRL
* In 5 Trace Capture
*
*/ */
#include "general.h" #include "general.h"
@ -46,23 +34,15 @@
#endif #endif
#include "usbuart.h" #include "usbuart.h"
#include "serialno.h" #include "serialno.h"
#include "version.h"
#include <libopencm3/cm3/nvic.h> #include <libopencm3/cm3/nvic.h>
#include <libopencm3/usb/usbd.h> #include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/cdc.h> #include <libopencm3/usb/cdc.h>
#include <libopencm3/cm3/scb.h> #include <libopencm3/cm3/scb.h>
#include <libopencm3/usb/dfu.h> #include <libopencm3/usb/dfu.h>
#include <stdlib.h>
#define GDB_IF_NO 0
#define UART_IF_NO 2
#define DFU_IF_NO 4 #define DFU_IF_NO 4
#if defined(PLATFORM_HAS_TRACESWO)
# define TRACE_IF_NO 5
# define TOTAL_INTERFACES 6
#else
# define TOTAL_INTERFACES 5
#endif
usbd_device * usbdev; usbd_device * usbdev;
@ -71,18 +51,14 @@ static int cdcacm_gdb_dtr = 1;
static void cdcacm_set_modem_state(usbd_device *dev, int iface, bool dsr, bool dcd); static void cdcacm_set_modem_state(usbd_device *dev, int iface, bool dsr, bool dcd);
static const struct usb_device_descriptor dev_desc = { static const struct usb_device_descriptor dev = {
.bLength = USB_DT_DEVICE_SIZE, .bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE, .bDescriptorType = USB_DT_DEVICE,
.bcdUSB = 0x0200, .bcdUSB = 0x0200,
.bDeviceClass = 0xEF, /* Miscellaneous Device */ .bDeviceClass = 0xEF, /* Miscellaneous Device */
.bDeviceSubClass = 2, /* Common Class */ .bDeviceSubClass = 2, /* Common Class */
.bDeviceProtocol = 1, /* Interface Association */ .bDeviceProtocol = 1, /* Interface Association */
#if defined(SAMD21E17) || defined(LM4F)
.bMaxPacketSize0 = 64, /*Fixed for icdi*/
#else
.bMaxPacketSize0 = 32, .bMaxPacketSize0 = 32,
#endif
.idVendor = 0x1D50, .idVendor = 0x1D50,
.idProduct = 0x6018, .idProduct = 0x6018,
.bcdDevice = 0x0100, .bcdDevice = 0x0100,
@ -98,7 +74,7 @@ static const struct usb_device_descriptor dev_desc = {
static const struct usb_endpoint_descriptor gdb_comm_endp[] = {{ static const struct usb_endpoint_descriptor gdb_comm_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = (CDCACM_GDB_ENDPOINT + 1) | USB_REQ_TYPE_IN, .bEndpointAddress = 0x82,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 16, .wMaxPacketSize = 16,
.bInterval = 255, .bInterval = 255,
@ -107,14 +83,14 @@ static const struct usb_endpoint_descriptor gdb_comm_endp[] = {{
static const struct usb_endpoint_descriptor gdb_data_endp[] = {{ static const struct usb_endpoint_descriptor gdb_data_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = CDCACM_GDB_ENDPOINT, .bEndpointAddress = 0x01,
.bmAttributes = USB_ENDPOINT_ATTR_BULK, .bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = CDCACM_PACKET_SIZE, .wMaxPacketSize = CDCACM_PACKET_SIZE,
.bInterval = 1, .bInterval = 1,
}, { }, {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = CDCACM_GDB_ENDPOINT | USB_REQ_TYPE_IN, .bEndpointAddress = 0x81,
.bmAttributes = USB_ENDPOINT_ATTR_BULK, .bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = CDCACM_PACKET_SIZE, .wMaxPacketSize = CDCACM_PACKET_SIZE,
.bInterval = 1, .bInterval = 1,
@ -138,7 +114,7 @@ static const struct {
.bDescriptorType = CS_INTERFACE, .bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
.bmCapabilities = 0, .bmCapabilities = 0,
.bDataInterface = GDB_IF_NO + 1, .bDataInterface = 1,
}, },
.acm = { .acm = {
.bFunctionLength = sizeof(struct usb_cdc_acm_descriptor), .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
@ -150,8 +126,8 @@ static const struct {
.bFunctionLength = sizeof(struct usb_cdc_union_descriptor), .bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
.bDescriptorType = CS_INTERFACE, .bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_CDC_TYPE_UNION, .bDescriptorSubtype = USB_CDC_TYPE_UNION,
.bControlInterface = GDB_IF_NO, .bControlInterface = 0,
.bSubordinateInterface0 = GDB_IF_NO + 1, .bSubordinateInterface0 = 1,
} }
}; };
@ -163,7 +139,7 @@ static const struct usb_interface_descriptor gdb_comm_iface[] = {{
.bNumEndpoints = 1, .bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_CDC, .bInterfaceClass = USB_CLASS_CDC,
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
.bInterfaceProtocol = USB_CDC_PROTOCOL_NONE, .bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
.iInterface = 4, .iInterface = 4,
.endpoint = gdb_comm_endp, .endpoint = gdb_comm_endp,
@ -175,7 +151,7 @@ static const struct usb_interface_descriptor gdb_comm_iface[] = {{
static const struct usb_interface_descriptor gdb_data_iface[] = {{ static const struct usb_interface_descriptor gdb_data_iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = GDB_IF_NO + 1, .bInterfaceNumber = 1,
.bAlternateSetting = 0, .bAlternateSetting = 0,
.bNumEndpoints = 2, .bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_DATA, .bInterfaceClass = USB_CLASS_DATA,
@ -189,19 +165,19 @@ static const struct usb_interface_descriptor gdb_data_iface[] = {{
static const struct usb_iface_assoc_descriptor gdb_assoc = { static const struct usb_iface_assoc_descriptor gdb_assoc = {
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
.bFirstInterface = GDB_IF_NO, .bFirstInterface = 0,
.bInterfaceCount = 2, .bInterfaceCount = 2,
.bFunctionClass = USB_CLASS_CDC, .bFunctionClass = USB_CLASS_CDC,
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM, .bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
.bFunctionProtocol = USB_CDC_PROTOCOL_NONE, .bFunctionProtocol = USB_CDC_PROTOCOL_AT,
.iFunction = 4, .iFunction = 0,
}; };
/* Serial ACM interface */ /* Serial ACM interface */
static const struct usb_endpoint_descriptor uart_comm_endp[] = {{ static const struct usb_endpoint_descriptor uart_comm_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = (CDCACM_UART_ENDPOINT + 1) | USB_REQ_TYPE_IN, .bEndpointAddress = 0x84,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 16, .wMaxPacketSize = 16,
.bInterval = 255, .bInterval = 255,
@ -210,14 +186,14 @@ static const struct usb_endpoint_descriptor uart_comm_endp[] = {{
static const struct usb_endpoint_descriptor uart_data_endp[] = {{ static const struct usb_endpoint_descriptor uart_data_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = CDCACM_UART_ENDPOINT, .bEndpointAddress = 0x03,
.bmAttributes = USB_ENDPOINT_ATTR_BULK, .bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = CDCACM_PACKET_SIZE / 2, .wMaxPacketSize = CDCACM_PACKET_SIZE / 2,
.bInterval = 1, .bInterval = 1,
}, { }, {
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = CDCACM_UART_ENDPOINT | USB_REQ_TYPE_IN, .bEndpointAddress = 0x83,
.bmAttributes = USB_ENDPOINT_ATTR_BULK, .bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = CDCACM_PACKET_SIZE, .wMaxPacketSize = CDCACM_PACKET_SIZE,
.bInterval = 1, .bInterval = 1,
@ -241,7 +217,7 @@ static const struct {
.bDescriptorType = CS_INTERFACE, .bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT, .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
.bmCapabilities = 0, .bmCapabilities = 0,
.bDataInterface = UART_IF_NO + 1, .bDataInterface = 3,
}, },
.acm = { .acm = {
.bFunctionLength = sizeof(struct usb_cdc_acm_descriptor), .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
@ -253,20 +229,20 @@ static const struct {
.bFunctionLength = sizeof(struct usb_cdc_union_descriptor), .bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
.bDescriptorType = CS_INTERFACE, .bDescriptorType = CS_INTERFACE,
.bDescriptorSubtype = USB_CDC_TYPE_UNION, .bDescriptorSubtype = USB_CDC_TYPE_UNION,
.bControlInterface = UART_IF_NO, .bControlInterface = 2,
.bSubordinateInterface0 = UART_IF_NO + 1, .bSubordinateInterface0 = 3,
} }
}; };
static const struct usb_interface_descriptor uart_comm_iface[] = {{ static const struct usb_interface_descriptor uart_comm_iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = UART_IF_NO, .bInterfaceNumber = 2,
.bAlternateSetting = 0, .bAlternateSetting = 0,
.bNumEndpoints = 1, .bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_CDC, .bInterfaceClass = USB_CLASS_CDC,
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
.bInterfaceProtocol = USB_CDC_PROTOCOL_NONE, .bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
.iInterface = 5, .iInterface = 5,
.endpoint = uart_comm_endp, .endpoint = uart_comm_endp,
@ -278,7 +254,7 @@ static const struct usb_interface_descriptor uart_comm_iface[] = {{
static const struct usb_interface_descriptor uart_data_iface[] = {{ static const struct usb_interface_descriptor uart_data_iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = UART_IF_NO + 1, .bInterfaceNumber = 3,
.bAlternateSetting = 0, .bAlternateSetting = 0,
.bNumEndpoints = 2, .bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_DATA, .bInterfaceClass = USB_CLASS_DATA,
@ -292,12 +268,12 @@ static const struct usb_interface_descriptor uart_data_iface[] = {{
static const struct usb_iface_assoc_descriptor uart_assoc = { static const struct usb_iface_assoc_descriptor uart_assoc = {
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
.bFirstInterface = UART_IF_NO, .bFirstInterface = 2,
.bInterfaceCount = 2, .bInterfaceCount = 2,
.bFunctionClass = USB_CLASS_CDC, .bFunctionClass = USB_CLASS_CDC,
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM, .bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
.bFunctionProtocol = USB_CDC_PROTOCOL_NONE, .bFunctionProtocol = USB_CDC_PROTOCOL_AT,
.iFunction = 5, .iFunction = 0,
}; };
const struct usb_dfu_descriptor dfu_function = { const struct usb_dfu_descriptor dfu_function = {
@ -327,7 +303,7 @@ const struct usb_interface_descriptor dfu_iface = {
static const struct usb_iface_assoc_descriptor dfu_assoc = { static const struct usb_iface_assoc_descriptor dfu_assoc = {
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
.bFirstInterface = DFU_IF_NO, .bFirstInterface = 4,
.bInterfaceCount = 1, .bInterfaceCount = 1,
.bFunctionClass = 0xFE, .bFunctionClass = 0xFE,
.bFunctionSubClass = 1, .bFunctionSubClass = 1,
@ -339,7 +315,7 @@ static const struct usb_iface_assoc_descriptor dfu_assoc = {
static const struct usb_endpoint_descriptor trace_endp[] = {{ static const struct usb_endpoint_descriptor trace_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE, .bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = TRACE_ENDPOINT | USB_REQ_TYPE_IN, .bEndpointAddress = 0x85,
.bmAttributes = USB_ENDPOINT_ATTR_BULK, .bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = 64, .wMaxPacketSize = 64,
.bInterval = 0, .bInterval = 0,
@ -348,7 +324,7 @@ static const struct usb_endpoint_descriptor trace_endp[] = {{
const struct usb_interface_descriptor trace_iface = { const struct usb_interface_descriptor trace_iface = {
.bLength = USB_DT_INTERFACE_SIZE, .bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE, .bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = TRACE_IF_NO, .bInterfaceNumber = 5,
.bAlternateSetting = 0, .bAlternateSetting = 0,
.bNumEndpoints = 1, .bNumEndpoints = 1,
.bInterfaceClass = 0xFF, .bInterfaceClass = 0xFF,
@ -362,7 +338,7 @@ const struct usb_interface_descriptor trace_iface = {
static const struct usb_iface_assoc_descriptor trace_assoc = { static const struct usb_iface_assoc_descriptor trace_assoc = {
.bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE, .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
.bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
.bFirstInterface = TRACE_IF_NO, .bFirstInterface = 5,
.bInterfaceCount = 1, .bInterfaceCount = 1,
.bFunctionClass = 0xFF, .bFunctionClass = 0xFF,
.bFunctionSubClass = 0xFF, .bFunctionSubClass = 0xFF,
@ -401,7 +377,11 @@ static const struct usb_config_descriptor config = {
.bLength = USB_DT_CONFIGURATION_SIZE, .bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION, .bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = 0, .wTotalLength = 0,
.bNumInterfaces = TOTAL_INTERFACES, #if defined(PLATFORM_HAS_TRACESWO)
.bNumInterfaces = 6,
#else
.bNumInterfaces = 5,
#endif
.bConfigurationValue = 1, .bConfigurationValue = 1,
.iConfiguration = 0, .iConfiguration = 0,
.bmAttributes = 0x80, .bmAttributes = 0x80,
@ -409,17 +389,20 @@ static const struct usb_config_descriptor config = {
.interface = ifaces, .interface = ifaces,
}; };
static char serial_no[DFU_SERIAL_LENGTH];
#define BOARD_IDENT "Black Magic Probe " PLATFORM_IDENT FIRMWARE_VERSION #if defined(STM32L0) || defined(STM32F3) || defined(STM32F4)
static char serial_no[13];
#else
static char serial_no[9];
#endif
static const char *usb_strings[] = { static const char *usb_strings[] = {
"Black Magic Debug", "Black Sphere Technologies",
BOARD_IDENT, BOARD_IDENT,
serial_no, serial_no,
"Black Magic GDB Server", "Black Magic GDB Server",
"Black Magic UART Port", "Black Magic UART Port",
"Black Magic DFU", DFU_IDENT,
#if defined(PLATFORM_HAS_TRACESWO) #if defined(PLATFORM_HAS_TRACESWO)
"Black Magic Trace Capture", "Black Magic Trace Capture",
#endif #endif
@ -433,11 +416,7 @@ static void dfu_detach_complete(usbd_device *dev, struct usb_setup_data *req)
platform_request_boot(); platform_request_boot();
/* Reset core to enter bootloader */ /* Reset core to enter bootloader */
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
scb_reset_core(); scb_reset_core();
#else
scb_reset_system();
#endif
} }
static enum usbd_request_return_codes cdcacm_control_request(usbd_device *dev, static enum usbd_request_return_codes cdcacm_control_request(usbd_device *dev,
@ -453,7 +432,7 @@ static enum usbd_request_return_codes cdcacm_control_request(usbd_device *dev,
case USB_CDC_REQ_SET_CONTROL_LINE_STATE: case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
cdcacm_set_modem_state(dev, req->wIndex, true, true); cdcacm_set_modem_state(dev, req->wIndex, true, true);
/* Ignore if not for GDB interface */ /* Ignore if not for GDB interface */
if(req->wIndex != GDB_IF_NO) if(req->wIndex != 0)
return USBD_REQ_HANDLED; return USBD_REQ_HANDLED;
cdcacm_gdb_dtr = req->wValue & 1; cdcacm_gdb_dtr = req->wValue & 1;
@ -464,10 +443,10 @@ static enum usbd_request_return_codes cdcacm_control_request(usbd_device *dev,
return USBD_REQ_NOTSUPP; return USBD_REQ_NOTSUPP;
switch(req->wIndex) { switch(req->wIndex) {
case UART_IF_NO: case 2:
usbuart_set_line_coding((struct usb_cdc_line_coding*)*buf); usbuart_set_line_coding((struct usb_cdc_line_coding*)*buf);
return USBD_REQ_HANDLED; return USBD_REQ_HANDLED;
case GDB_IF_NO: case 0:
return USBD_REQ_HANDLED; /* Ignore on GDB Port */ return USBD_REQ_HANDLED; /* Ignore on GDB Port */
default: default:
return USBD_REQ_NOTSUPP; return USBD_REQ_NOTSUPP;
@ -517,7 +496,6 @@ static void cdcacm_set_modem_state(usbd_device *dev, int iface, bool dsr, bool d
notif->wLength = 2; notif->wLength = 2;
buf[8] = (dsr ? 2 : 0) | (dcd ? 1 : 0); buf[8] = (dsr ? 2 : 0) | (dcd ? 1 : 0);
buf[9] = 0; buf[9] = 0;
/* FIXME: Remove magic numbers */
usbd_ep_write_packet(dev, 0x82 + iface, buf, 10); usbd_ep_write_packet(dev, 0x82 + iface, buf, 10);
} }
@ -526,30 +504,27 @@ static void cdcacm_set_config(usbd_device *dev, uint16_t wValue)
configured = wValue; configured = wValue;
/* GDB interface */ /* GDB interface */
#if defined(STM32F4) || defined(LM4F) || defined(SAMD) #if defined(STM32F4) || defined(LM4F)
usbd_ep_setup(dev, CDCACM_GDB_ENDPOINT, USB_ENDPOINT_ATTR_BULK, usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK,
CDCACM_PACKET_SIZE, gdb_usb_out_cb); CDCACM_PACKET_SIZE, gdb_usb_out_cb);
#else #else
usbd_ep_setup(dev, CDCACM_GDB_ENDPOINT, USB_ENDPOINT_ATTR_BULK, usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK,
CDCACM_PACKET_SIZE, NULL); CDCACM_PACKET_SIZE, NULL);
#endif #endif
usbd_ep_setup(dev, CDCACM_GDB_ENDPOINT | USB_REQ_TYPE_IN, usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_BULK,
USB_ENDPOINT_ATTR_BULK, CDCACM_PACKET_SIZE, NULL); CDCACM_PACKET_SIZE, NULL);
usbd_ep_setup(dev, (CDCACM_GDB_ENDPOINT + 1) | USB_REQ_TYPE_IN, usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
/* Serial interface */ /* Serial interface */
usbd_ep_setup(dev, CDCACM_UART_ENDPOINT, USB_ENDPOINT_ATTR_BULK, usbd_ep_setup(dev, 0x03, USB_ENDPOINT_ATTR_BULK,
CDCACM_PACKET_SIZE / 2, usbuart_usb_out_cb); CDCACM_PACKET_SIZE / 2, usbuart_usb_out_cb);
usbd_ep_setup(dev, CDCACM_UART_ENDPOINT | USB_REQ_TYPE_IN, usbd_ep_setup(dev, 0x83, USB_ENDPOINT_ATTR_BULK,
USB_ENDPOINT_ATTR_BULK,
CDCACM_PACKET_SIZE, usbuart_usb_in_cb); CDCACM_PACKET_SIZE, usbuart_usb_in_cb);
usbd_ep_setup(dev, (CDCACM_UART_ENDPOINT + 1) | USB_REQ_TYPE_IN, usbd_ep_setup(dev, 0x84, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
#if defined(PLATFORM_HAS_TRACESWO) #if defined(PLATFORM_HAS_TRACESWO)
/* Trace interface */ /* Trace interface */
usbd_ep_setup(dev, TRACE_ENDPOINT | USB_REQ_TYPE_IN, USB_ENDPOINT_ATTR_BULK, usbd_ep_setup(dev, 0x85, USB_ENDPOINT_ATTR_BULK,
64, trace_buf_drain); 64, trace_buf_drain);
#endif #endif
@ -561,8 +536,8 @@ static void cdcacm_set_config(usbd_device *dev, uint16_t wValue)
/* Notify the host that DCD is asserted. /* Notify the host that DCD is asserted.
* Allows the use of /dev/tty* devices on *BSD/MacOS * Allows the use of /dev/tty* devices on *BSD/MacOS
*/ */
cdcacm_set_modem_state(dev, GDB_IF_NO, true, true); cdcacm_set_modem_state(dev, 0, true, true);
cdcacm_set_modem_state(dev, UART_IF_NO, true, true); cdcacm_set_modem_state(dev, 2, true, true);
} }
/* We need a special large control buffer for this device: */ /* We need a special large control buffer for this device: */
@ -572,9 +547,9 @@ void cdcacm_init(void)
{ {
void exti15_10_isr(void); void exti15_10_isr(void);
serial_no_read(serial_no); serial_no_read(serial_no, sizeof(serial_no));
usbdev = usbd_init(&USB_DRIVER, &dev_desc, &config, usb_strings, usbdev = usbd_init(&USB_DRIVER, &dev, &config, usb_strings,
sizeof(usb_strings)/sizeof(char *), sizeof(usb_strings)/sizeof(char *),
usbd_control_buffer, sizeof(usbd_control_buffer)); usbd_control_buffer, sizeof(usbd_control_buffer));
@ -582,7 +557,6 @@ void cdcacm_init(void)
nvic_set_priority(USB_IRQ, IRQ_PRI_USB); nvic_set_priority(USB_IRQ, IRQ_PRI_USB);
nvic_enable_irq(USB_IRQ); nvic_enable_irq(USB_IRQ);
usbd_disconnect(usbdev, false);
} }
void USB_ISR(void) void USB_ISR(void)

View File

@ -34,7 +34,6 @@
#define CDCACM_GDB_ENDPOINT 1 #define CDCACM_GDB_ENDPOINT 1
#define CDCACM_UART_ENDPOINT 3 #define CDCACM_UART_ENDPOINT 3
#define TRACE_ENDPOINT 5
extern usbd_device *usbdev; extern usbd_device *usbdev;

View File

@ -70,15 +70,12 @@ static void jtagtap_reset(void)
static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI) static uint8_t jtagtap_next(uint8_t dTMS, uint8_t dTDI)
{ {
uint16_t ret; uint16_t ret;
register volatile int32_t cnt;
gpio_set_val(TMS_PORT, TMS_PIN, dTMS); gpio_set_val(TMS_PORT, TMS_PIN, dTMS);
gpio_set_val(TDI_PORT, TDI_PIN, dTDI); gpio_set_val(TDI_PORT, TDI_PIN, dTDI);
gpio_set(TCK_PORT, TCK_PIN); gpio_set(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
ret = gpio_get(TDO_PORT, TDO_PIN); ret = gpio_get(TDO_PORT, TDO_PIN);
gpio_clear(TCK_PORT, TCK_PIN); gpio_clear(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt - 2; cnt > 0; cnt--);
//DEBUG("jtagtap_next(TMS = %d, TDI = %d) = %d\n", dTMS, dTDI, ret); //DEBUG("jtagtap_next(TMS = %d, TDI = %d) = %d\n", dTMS, dTDI, ret);
@ -89,19 +86,6 @@ static void jtagtap_tms_seq(uint32_t MS, int ticks)
{ {
gpio_set_val(TDI_PORT, TDI_PIN, 1); gpio_set_val(TDI_PORT, TDI_PIN, 1);
int data = MS & 1; int data = MS & 1;
register volatile int32_t cnt;
if (swd_delay_cnt) {
while(ticks) {
gpio_set_val(TMS_PORT, TMS_PIN, data);
gpio_set(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
MS >>= 1;
data = MS & 1;
ticks--;
gpio_clear(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
}
} else {
while(ticks) { while(ticks) {
gpio_set_val(TMS_PORT, TMS_PIN, data); gpio_set_val(TMS_PORT, TMS_PIN, data);
gpio_set(TCK_PORT, TCK_PIN); gpio_set(TCK_PORT, TCK_PIN);
@ -111,7 +95,6 @@ static void jtagtap_tms_seq(uint32_t MS, int ticks)
gpio_clear(TCK_PORT, TCK_PIN); gpio_clear(TCK_PORT, TCK_PIN);
} }
} }
}
static void jtagtap_tdi_tdo_seq( static void jtagtap_tdi_tdo_seq(
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks) uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
@ -119,26 +102,6 @@ static void jtagtap_tdi_tdo_seq(
uint8_t index = 1; uint8_t index = 1;
gpio_set_val(TMS_PORT, TMS_PIN, 0); gpio_set_val(TMS_PORT, TMS_PIN, 0);
uint8_t res = 0; uint8_t res = 0;
register volatile int32_t cnt;
if (swd_delay_cnt) {
while(ticks > 1) {
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
gpio_set(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
if (gpio_get(TDO_PORT, TDO_PIN)) {
res |= index;
}
if(!(index <<= 1)) {
*DO = res;
res = 0;
index = 1;
DI++; DO++;
}
ticks--;
gpio_clear(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
}
} else {
while(ticks > 1) { while(ticks > 1) {
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index); gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
gpio_set(TCK_PORT, TCK_PIN); gpio_set(TCK_PORT, TCK_PIN);
@ -154,37 +117,19 @@ static void jtagtap_tdi_tdo_seq(
ticks--; ticks--;
gpio_clear(TCK_PORT, TCK_PIN); gpio_clear(TCK_PORT, TCK_PIN);
} }
}
gpio_set_val(TMS_PORT, TMS_PIN, final_tms); gpio_set_val(TMS_PORT, TMS_PIN, final_tms);
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index); gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
gpio_set(TCK_PORT, TCK_PIN); gpio_set(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
if (gpio_get(TDO_PORT, TDO_PIN)) { if (gpio_get(TDO_PORT, TDO_PIN)) {
res |= index; res |= index;
} }
*DO = res; *DO = res;
gpio_clear(TCK_PORT, TCK_PIN); gpio_clear(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
} }
static void jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks) static void jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int ticks)
{ {
uint8_t index = 1; uint8_t index = 1;
register volatile int32_t cnt;
if (swd_delay_cnt) {
while(ticks--) {
gpio_set_val(TMS_PORT, TMS_PIN, ticks? 0 : final_tms);
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
gpio_set(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
if(!(index <<= 1)) {
index = 1;
DI++;
}
gpio_clear(TCK_PORT, TCK_PIN);
for(cnt = swd_delay_cnt -2 ; cnt > 0; cnt--);
}
} else {
while(ticks--) { while(ticks--) {
gpio_set_val(TMS_PORT, TMS_PIN, ticks? 0 : final_tms); gpio_set_val(TMS_PORT, TMS_PIN, ticks? 0 : final_tms);
gpio_set_val(TDI_PORT, TDI_PIN, *DI & index); gpio_set_val(TDI_PORT, TDI_PIN, *DI & index);
@ -196,4 +141,3 @@ static void jtagtap_tdi_seq(const uint8_t final_tms, const uint8_t *DI, int tick
gpio_clear(TCK_PORT, TCK_PIN); gpio_clear(TCK_PORT, TCK_PIN);
} }
} }
}

View File

@ -21,8 +21,7 @@
/* This file implements the SW-DP interface. */ /* This file implements the SW-DP interface. */
#include "general.h" #include "general.h"
#include "timing.h" #include "swdptap.h"
#include "adiv5.h"
enum { enum {
SWDIO_STATUS_FLOAT = 0, SWDIO_STATUS_FLOAT = 0,
@ -40,7 +39,6 @@ static void swdptap_seq_out_parity(uint32_t MS, int ticks)
static void swdptap_turnaround(int dir) static void swdptap_turnaround(int dir)
{ {
static int olddir = SWDIO_STATUS_FLOAT; static int olddir = SWDIO_STATUS_FLOAT;
register volatile int32_t cnt;
/* Don't turnaround if direction not changing */ /* Don't turnaround if direction not changing */
if(dir == olddir) return; if(dir == olddir) return;
@ -53,9 +51,10 @@ static void swdptap_turnaround(int dir)
if(dir == SWDIO_STATUS_FLOAT) if(dir == SWDIO_STATUS_FLOAT)
SWDIO_MODE_FLOAT(); SWDIO_MODE_FLOAT();
gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_set(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;); gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_clear(SWCLK_PORT, SWCLK_PIN); gpio_clear(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
if(dir == SWDIO_STATUS_DRIVE) if(dir == SWDIO_STATUS_DRIVE)
SWDIO_MODE_DRIVE(); SWDIO_MODE_DRIVE();
} }
@ -65,30 +64,21 @@ static uint32_t swdptap_seq_in(int ticks)
uint32_t index = 1; uint32_t index = 1;
uint32_t ret = 0; uint32_t ret = 0;
int len = ticks; int len = ticks;
register volatile int32_t cnt;
swdptap_turnaround(SWDIO_STATUS_FLOAT); swdptap_turnaround(SWDIO_STATUS_FLOAT);
if (swd_delay_cnt) {
while (len--) { while (len--) {
int res; int res;
res = gpio_get(SWDIO_PORT, SWDIO_PIN); res = gpio_get(SWDIO_PORT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_set(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
ret |= (res) ? index : 0;
index <<= 1;
gpio_clear(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
}
} else {
volatile int res;
while (len--) {
res = gpio_get(SWDIO_PORT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_set(SWCLK_PORT, SWCLK_PIN);
ret |= (res) ? index : 0; gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
if (res)
ret |= index;
index <<= 1; index <<= 1;
gpio_clear(SWCLK_PORT, SWCLK_PIN); gpio_clear(SWCLK_PORT, SWCLK_PIN);
} }
}
#ifdef DEBUG_SWD_BITS #ifdef DEBUG_SWD_BITS
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
DEBUG("%d", (ret & (1 << i)) ? 1 : 0); DEBUG("%d", (ret & (1 << i)) ? 1 : 0);
@ -102,42 +92,31 @@ static bool swdptap_seq_in_parity(uint32_t *ret, int ticks)
uint32_t res = 0; uint32_t res = 0;
bool bit; bool bit;
int len = ticks; int len = ticks;
register volatile int32_t cnt;
swdptap_turnaround(SWDIO_STATUS_FLOAT); swdptap_turnaround(SWDIO_STATUS_FLOAT);
if (swd_delay_cnt) {
while (len--) { while (len--) {
bit = gpio_get(SWDIO_PORT, SWDIO_PIN); bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_set(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
res |= (bit) ? index : 0;
index <<= 1;
gpio_clear(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
}
} else {
while (len--) {
bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_set(SWCLK_PORT, SWCLK_PIN);
res |= (bit) ? index : 0; gpio_set(SWCLK_PORT, SWCLK_PIN);
if (bit)
res |= index;
index <<= 1; index <<= 1;
gpio_clear(SWCLK_PORT, SWCLK_PIN); gpio_clear(SWCLK_PORT, SWCLK_PIN);
} }
}
int parity = __builtin_popcount(res); int parity = __builtin_popcount(res);
bit = gpio_get(SWDIO_PORT, SWDIO_PIN); bit = gpio_get(SWDIO_PORT, SWDIO_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_set(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;); if (bit)
parity += (bit) ? 1 : 0; parity++;
else
gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_clear(SWCLK_PORT, SWCLK_PIN); gpio_clear(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
#ifdef DEBUG_SWD_BITS #ifdef DEBUG_SWD_BITS
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
DEBUG("%d", (res & (1 << i)) ? 1 : 0); DEBUG("%d", (res & (1 << i)) ? 1 : 0);
#endif #endif
*ret = res; *ret = res;
/* Terminate the read cycle now */
swdptap_turnaround(SWDIO_STATUS_DRIVE);
return (parity & 1); return (parity & 1);
} }
@ -147,25 +126,14 @@ static void swdptap_seq_out(uint32_t MS, int ticks)
for (int i = 0; i < ticks; i++) for (int i = 0; i < ticks; i++)
DEBUG("%d", (MS & (1 << i)) ? 1 : 0); DEBUG("%d", (MS & (1 << i)) ? 1 : 0);
#endif #endif
register volatile int32_t cnt;
swdptap_turnaround(SWDIO_STATUS_DRIVE); swdptap_turnaround(SWDIO_STATUS_DRIVE);
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1); gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
if (swd_delay_cnt) {
while (ticks--) {
gpio_set(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
MS >>= 1;
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
gpio_clear(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
}
} else {
while (ticks--) { while (ticks--) {
gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_set(SWCLK_PORT, SWCLK_PIN);
MS >>= 1; MS >>= 1;
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1); gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
gpio_clear(SWCLK_PORT, SWCLK_PIN); gpio_clear(SWCLK_PORT, SWCLK_PIN);
} gpio_clear(SWCLK_PORT, SWCLK_PIN);
} }
} }
@ -176,40 +144,30 @@ static void swdptap_seq_out_parity(uint32_t MS, int ticks)
for (int i = 0; i < ticks; i++) for (int i = 0; i < ticks; i++)
DEBUG("%d", (MS & (1 << i)) ? 1 : 0); DEBUG("%d", (MS & (1 << i)) ? 1 : 0);
#endif #endif
register volatile int32_t cnt;
swdptap_turnaround(SWDIO_STATUS_DRIVE); swdptap_turnaround(SWDIO_STATUS_DRIVE);
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1); gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
MS >>= 1; MS >>= 1;
if (swd_delay_cnt) {
while (ticks--) {
gpio_set(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
MS >>= 1;
gpio_clear(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
}
} else {
while (ticks--) { while (ticks--) {
gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1); gpio_set_val(SWDIO_PORT, SWDIO_PIN, MS & 1);
MS >>= 1; MS >>= 1;
gpio_clear(SWCLK_PORT, SWCLK_PIN); gpio_clear(SWCLK_PORT, SWCLK_PIN);
} }
}
gpio_set_val(SWDIO_PORT, SWDIO_PIN, parity & 1); gpio_set_val(SWDIO_PORT, SWDIO_PIN, parity & 1);
gpio_set(SWCLK_PORT, SWCLK_PIN); gpio_set(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;); gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_set(SWCLK_PORT, SWCLK_PIN);
gpio_clear(SWCLK_PORT, SWCLK_PIN); gpio_clear(SWCLK_PORT, SWCLK_PIN);
for(cnt = swd_delay_cnt; --cnt > 0;);
} }
int swdptap_init(ADIv5_DP_t *dp) swd_proc_t swd_proc;
int swdptap_init(void)
{ {
dp->seq_in = swdptap_seq_in; swd_proc.swdptap_seq_in = swdptap_seq_in;
dp->seq_in_parity = swdptap_seq_in_parity; swd_proc.swdptap_seq_in_parity = swdptap_seq_in_parity;
dp->seq_out = swdptap_seq_out; swd_proc.swdptap_seq_out = swdptap_seq_out;
dp->seq_out_parity = swdptap_seq_out_parity; swd_proc.swdptap_seq_out_parity = swdptap_seq_out_parity;
return 0; return 0;
} }

View File

@ -1,35 +1,18 @@
CROSS_COMPILE ?= arm-none-eabi- CROSS_COMPILE ?= arm-none-eabi-
BMP_BOOTLOADER ?=
CC = $(CROSS_COMPILE)gcc CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy OBJCOPY = $(CROSS_COMPILE)objcopy
CFLAGS += -Istm32/include -mcpu=cortex-m4 -mthumb \ CFLAGS += -Istm32/include -mcpu=cortex-m4 -mthumb \
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \ -mfloat-abi=hard -mfpu=fpv4-sp-d16 \
-DSTM32F4 -I../libopencm3/include \ -DSTM32F4 -DF4DISCOVERY -I../libopencm3/include \
-Iplatforms/stm32 -Iplatforms/stm32
ifeq ($(BLACKPILL), 1) LDFLAGS = -lopencm3_stm32f4 \
LINKER_SCRIPT=platforms/stm32/blackpillv2.ld -Wl,-T,platforms/stm32/f4discovery.ld -nostartfiles -lc -lnosys \
CFLAGS += -DBLACKPILL=1
else
LINKER_SCRIPT=platforms/stm32/f4discovery.ld
endif
LDFLAGS_BOOT = -lopencm3_stm32f4 \
-Wl,-T,$(LINKER_SCRIPT) -nostartfiles -lc -lnosys \
-Wl,-Map=mapfile -mthumb -mcpu=cortex-m4 -Wl,-gc-sections \ -Wl,-Map=mapfile -mthumb -mcpu=cortex-m4 -Wl,-gc-sections \
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \ -mfloat-abi=hard -mfpu=fpv4-sp-d16 \
-L../libopencm3/lib -L../libopencm3/lib
ifeq ($(BMP_BOOTLOADER), 1)
$(info Load address 0x08004000 for BMPBootloader)
LDFLAGS = $(LDFLAGS_BOOT) -Wl,-Ttext=0x8004000
CFLAGS += -DDFU_SERIAL_LENGTH=9
else
LDFLAGS += $(LDFLAGS_BOOT)
CFLAGS += -DDFU_SERIAL_LENGTH=13
endif
VPATH += platforms/stm32 VPATH += platforms/stm32
SRC += cdcacm.c \ SRC += cdcacm.c \
@ -40,18 +23,7 @@ SRC += cdcacm.c \
timing.c \ timing.c \
timing_stm32.c \ timing_stm32.c \
ifneq ($(BMP_BOOTLOADER), 1)
all: blackmagic.bin all: blackmagic.bin
else
all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex
blackmagic_dfu: usbdfu.o dfucore.o dfu_f4.o serialno.o
$(CC) $^ -o $@ $(LDFLAGS_BOOT)
blackmagic_dfu.bin: blackmagic_dfu
$(OBJCOPY) -O binary $^ $@
blackmagic_dfu.hex: blackmagic_dfu
$(OBJCOPY) -O ihex $^ $@
endif
host_clean: host_clean:
-$(Q)$(RM) blackmagic.bin -$(Q)$(RM) blackmagic.bin

View File

@ -11,55 +11,3 @@ PC6: TDO/TRACESWO<br>
PC1: TRST<br> PC1: TRST<br>
PC8: SRST<br> PC8: SRST<br>
# Alternate build for stm32f401 stm32f411 MiniF4 aka BlackPillV2 boards.
https://github.com/WeActTC/MiniSTM32F4x1
## Connections:
* JTAG/SWD
* PA1: TDI
* PA13: TMS/SWDIO
* PA14: TCK/SWCLK
* PB3: TDO/TRACESWO
* PB5: TRST
* PB4: SRST
* USB USART
* PB6: USART1 TX (usbuart_xxx)
* PB7: USART1 RX (usbuart_xxx)
* +3V3.
* PB8 - turn on IRLML5103 transistor
How to Build
========================================
```
cd blackmagic
make clean
make PROBE_HOST=f4discovery BLACKPILL=1
```
How to Flash with dfu
========================================
* After build:
* 1) `apt install dfu-util`
* 2) Force the F4 into system bootloader mode by jumpering "BOOT0" to "3V3" and "PB2/BOOT1" to "GND" and reset (RESET button). System bootloader should appear.
* 3) `dfu-util -a 0 --dfuse-address 0x08000000 -D blackmagic.bin`
To exit from dfu mode press a "key" and "reset", release reset. BMP firmware should appear
10 pin male from pins
========================================
| PB3/TDO | PB7/RX | PB6/TX | X | PA1/TDI |
| -------- | ----------- | ---------- | ---------- | ------- |
| PB4/SRST | +3V3/PB8 SW | PA13/SWDIO | PA14/SWCLK | GND |
SWJ frequency setting
====================================
https://github.com/blackmagic-debug/blackmagic/pull/783#issue-529197718
`mon freq 900k` helps at most

View File

@ -27,7 +27,7 @@
#include "usbuart.h" #include "usbuart.h"
#include "morse.h" #include "morse.h"
#include <libopencm3/stm32/rcc.h> #include <libopencm3/stm32/f4/rcc.h>
#include <libopencm3/cm3/scb.h> #include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/nvic.h> #include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/exti.h> #include <libopencm3/stm32/exti.h>
@ -37,32 +37,20 @@
#include <libopencm3/cm3/systick.h> #include <libopencm3/cm3/systick.h>
#include <libopencm3/cm3/cortex.h> #include <libopencm3/cm3/cortex.h>
#ifdef BLACKPILL
#include <libopencm3/usb/dwc/otg_fs.h>
#endif
jmp_buf fatal_error_jmpbuf; jmp_buf fatal_error_jmpbuf;
extern char _ebss[]; extern char _ebss[];
void platform_init(void) void platform_init(void)
{ {
volatile uint32_t *magic = (uint32_t *)_ebss; volatile uint32_t *magic = (uint32_t *)_ebss;
/* Enable GPIO peripherals */
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_GPIOC);
#ifdef BLACKPILL
rcc_periph_clock_enable(RCC_GPIOB);
#else
rcc_periph_clock_enable(RCC_GPIOD);
#endif
/* Check the USER button*/ /* Check the USER button*/
rcc_periph_clock_enable(RCC_GPIOA);
if (gpio_get(GPIOA, GPIO0) || if (gpio_get(GPIOA, GPIO0) ||
((magic[0] == BOOTMAGIC0) && (magic[1] == BOOTMAGIC1))) ((magic[0] == BOOTMAGIC0) && (magic[1] == BOOTMAGIC1))) {
{
magic[0] = 0; magic[0] = 0;
magic[1] = 0; magic[1] = 0;
/* Assert blue LED as indicator we are in the bootloader */ /* Assert blue LED as indicator we are in the bootloader */
rcc_periph_clock_enable(RCC_GPIOD);
gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT, gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE, LED_BOOTLOADER); GPIO_PUPD_NONE, LED_BOOTLOADER);
gpio_set(LED_PORT, LED_BOOTLOADER); gpio_set(LED_PORT, LED_BOOTLOADER);
@ -73,62 +61,38 @@ void platform_init(void)
SYSCFG_MEMRM |= 1; SYSCFG_MEMRM |= 1;
scb_reset_core(); scb_reset_core();
} }
#ifdef BLACKPILL
rcc_clock_setup_pll(&rcc_hse_25mhz_3v3[RCC_CLOCK_3V3_84MHZ]);
#else
rcc_clock_setup_pll(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]); rcc_clock_setup_pll(&rcc_hse_8mhz_3v3[RCC_CLOCK_3V3_168MHZ]);
#endif
/* Enable peripherals */ /* Enable peripherals */
rcc_periph_clock_enable(RCC_OTGFS); rcc_periph_clock_enable(RCC_OTGFS);
rcc_periph_clock_enable(RCC_GPIOC);
rcc_periph_clock_enable(RCC_GPIOD);
rcc_periph_clock_enable(RCC_CRC); rcc_periph_clock_enable(RCC_CRC);
/* Set up USB Pins and alternate function*/ /* Set up USB Pins and alternate function*/
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9 | GPIO11 | GPIO12); gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO11 | GPIO12);
gpio_set_af(GPIOA, GPIO_AF10, GPIO9 | GPIO10 | GPIO11 | GPIO12); gpio_set_af(GPIOA, GPIO_AF10, GPIO11 | GPIO12);
#ifdef BLACKPILL
GPIOA_OSPEEDR &= 0x3C00000C;
GPIOA_OSPEEDR |= 0x28000008;
#else
GPIOC_OSPEEDR &=~0xF30; GPIOC_OSPEEDR &=~0xF30;
GPIOC_OSPEEDR |= 0xA20; GPIOC_OSPEEDR |= 0xA20;
#endif
gpio_mode_setup(JTAG_PORT, GPIO_MODE_OUTPUT, gpio_mode_setup(JTAG_PORT, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE, GPIO_PUPD_NONE,
TCK_PIN | TDI_PIN); TCK_PIN | TDI_PIN);
gpio_mode_setup(JTAG_PORT, GPIO_MODE_INPUT, gpio_mode_setup(JTAG_PORT, GPIO_MODE_INPUT,
GPIO_PUPD_NONE, TMS_PIN); GPIO_PUPD_NONE, TMS_PIN);
gpio_set_output_options(JTAG_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ,
TCK_PIN | TDI_PIN | TMS_PIN);
gpio_mode_setup(TDO_PORT, GPIO_MODE_INPUT, gpio_mode_setup(TDO_PORT, GPIO_MODE_INPUT,
GPIO_PUPD_NONE, GPIO_PUPD_NONE,
TDO_PIN); TDO_PIN);
gpio_set_output_options(TDO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ,
TDO_PIN | TMS_PIN);
gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT, gpio_mode_setup(LED_PORT, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE, GPIO_PUPD_NONE,
LED_IDLE_RUN | LED_ERROR | LED_BOOTLOADER); LED_UART | LED_IDLE_RUN | LED_ERROR | LED_BOOTLOADER);
gpio_mode_setup(LED_PORT_UART, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, LED_UART);
#ifdef PLATFORM_HAS_POWER_SWITCH
gpio_set(PWR_BR_PORT, PWR_BR_PIN);
gpio_mode_setup(PWR_BR_PORT, GPIO_MODE_OUTPUT,
GPIO_PUPD_NONE,
PWR_BR_PIN);
#endif
platform_timing_init(); platform_timing_init();
usbuart_init(); usbuart_init();
cdcacm_init(); cdcacm_init();
#ifdef BLACKPILL
// https://github.com/libopencm3/libopencm3/pull/1256#issuecomment-779424001
OTG_FS_GCCFG |= OTG_GCCFG_NOVBUSSENS | OTG_GCCFG_PWRDWN;
OTG_FS_GCCFG &= ~(OTG_GCCFG_VBUSBSEN | OTG_GCCFG_VBUSASEN);
#endif
} }
void platform_srst_set_val(bool assert) { (void)assert; } void platform_srst_set_val(bool assert) { (void)assert; }
@ -146,15 +110,3 @@ void platform_request_boot(void)
magic[1] = BOOTMAGIC1; magic[1] = BOOTMAGIC1;
scb_reset_system(); scb_reset_system();
} }
#ifdef PLATFORM_HAS_POWER_SWITCH
bool platform_target_get_power(void)
{
return !gpio_get(PWR_BR_PORT, PWR_BR_PIN);
}
void platform_target_set_power(bool power)
{
gpio_set_val(PWR_BR_PORT, PWR_BR_PIN, !power);
}
#endif

View File

@ -27,80 +27,13 @@
#include "gpio.h" #include "gpio.h"
#include "timing.h" #include "timing.h"
#include "timing_stm32.h" #include "timing_stm32.h"
#include "version.h"
#include <setjmp.h> #include <setjmp.h>
#define PLATFORM_HAS_TRACESWO #define PLATFORM_HAS_TRACESWO
#ifdef BLACKPILL #define BOARD_IDENT "Black Magic Probe (F4Discovery), (Firmware " FIRMWARE_VERSION ")"
#define PLATFORM_IDENT "(F4Discovery/BlackPillV2) " #define DFU_IDENT "Black Magic Firmware Upgrade (F4Discovery)"
/* Important pin mappings for STM32 implementation:
* JTAG/SWD
* PA1: TDI<br>
* PA13: TMS/SWDIO<br>
* PA14: TCK/SWCLK<br>
* PB3: TDO/TRACESWO<br>
* PB5: TRST<br>
* PB4: SRST<br>
* USB USART
* PB6: USART1 TX
* PB7: USART1 RX
* +3V3
* PB8 - turn on IRLML5103 transistor
* Force DFU mode button: PA0
*/
/* Hardware definitions... */
#define JTAG_PORT GPIOA
#define TDI_PORT JTAG_PORT
#define TMS_PORT JTAG_PORT
#define TCK_PORT JTAG_PORT
#define TDO_PORT GPIOB
#define TDI_PIN GPIO1
#define TMS_PIN GPIO13
#define TCK_PIN GPIO14
#define TDO_PIN GPIO3
#define SWDIO_PORT JTAG_PORT
#define SWCLK_PORT JTAG_PORT
#define SWDIO_PIN TMS_PIN
#define SWCLK_PIN TCK_PIN
#define TRST_PORT GPIOB
#define TRST_PIN GPIO5
#define SRST_PORT GPIOB
#define SRST_PIN GPIO4
#define PWR_BR_PORT GPIOB
#define PWR_BR_PIN GPIO8
#define LED_PORT GPIOC
#define LED_PORT_UART GPIOA
#define LED_UART GPIO1
#define LED_IDLE_RUN GPIO15
#define LED_ERROR GPIO14
#define LED_BOOTLOADER GPIO13
#define USBUSART USART1
#define USBUSART_CR1 USART1_CR1
#define USBUSART_DR USART1_DR
#define USBUSART_IRQ NVIC_USART1_IRQ
#define USBUSART_CLK RCC_USART1
#define USBUSART_PORT GPIOB
#define USBUSART_TX_PIN GPIO6
#define USBUSART_RX_PIN GPIO7
#define USBUSART_ISR(x) usart1_isr(x)
#define USBUSART_DMA_BUS DMA2
#define USBUSART_DMA_CLK RCC_DMA2
#define USBUSART_DMA_TX_CHAN DMA_STREAM7
#define USBUSART_DMA_TX_IRQ NVIC_DMA2_STREAM7_IRQ
#define USBUSART_DMA_TX_ISR(x) dma2_stream7_isr(x)
#define USBUSART_DMA_RX_CHAN DMA_STREAM5
#define USBUSART_DMA_RX_IRQ NVIC_DMA2_STREAM5_IRQ
#define USBUSART_DMA_RX_ISR(x) dma2_stream5_isr(x)
/* For STM32F4 DMA trigger source must be specified */
#define USBUSART_DMA_TRG DMA_SxCR_CHSEL_4
#else
#define PLATFORM_IDENT "(F4Discovery) "
/* Important pin mappings for STM32 implementation: /* Important pin mappings for STM32 implementation:
* *
@ -147,28 +80,6 @@
#define LED_IDLE_RUN GPIO13 #define LED_IDLE_RUN GPIO13
#define LED_ERROR GPIO14 #define LED_ERROR GPIO14
#define LED_BOOTLOADER GPIO15 #define LED_BOOTLOADER GPIO15
#define USBUSART USART3
#define USBUSART_CR1 USART3_CR1
#define USBUSART_DR USART3_DR
#define USBUSART_IRQ NVIC_USART3_IRQ
#define USBUSART_CLK RCC_USART3
#define USBUSART_PORT GPIOD
#define USBUSART_TX_PIN GPIO8
#define USBUSART_RX_PIN GPIO9
#define USBUSART_ISR(x) usart3_isr(x)
#define USBUSART_DMA_BUS DMA1
#define USBUSART_DMA_CLK RCC_DMA1
#define USBUSART_DMA_TX_CHAN DMA_STREAM3
#define USBUSART_DMA_TX_IRQ NVIC_DMA1_STREAM3_IRQ
#define USBUSART_DMA_TX_ISR(x) dma1_stream3_isr(x)
#define USBUSART_DMA_RX_CHAN DMA_STREAM1
#define USBUSART_DMA_RX_IRQ NVIC_DMA1_STREAM1_IRQ
#define USBUSART_DMA_RX_ISR(x) dma1_stream1_isr(x)
/* For STM32F4 DMA trigger source must be specified */
#define USBUSART_DMA_TRG DMA_SxCR_CHSEL_4
#endif
#define BOOTMAGIC0 0xb007da7a #define BOOTMAGIC0 0xb007da7a
#define BOOTMAGIC1 0xbaadfeed #define BOOTMAGIC1 0xbaadfeed
@ -182,35 +93,47 @@
#define SWDIO_MODE_DRIVE() \ #define SWDIO_MODE_DRIVE() \
gpio_mode_setup(SWDIO_PORT, GPIO_MODE_OUTPUT, \ gpio_mode_setup(SWDIO_PORT, GPIO_MODE_OUTPUT, \
GPIO_PUPD_NONE, SWDIO_PIN); GPIO_PUPD_NONE, SWDIO_PIN);
#define UART_PIN_SETUP() do { \
gpio_mode_setup(USBUSART_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
USBUSART_TX_PIN); \
gpio_set_output_options(USBUSART_PORT, GPIO_OTYPE_PP, \
GPIO_OSPEED_100MHZ, USBUSART_TX_PIN); \
gpio_set_af(USBUSART_PORT, GPIO_AF7, USBUSART_TX_PIN); \
gpio_mode_setup(USBUSART_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, \
USBUSART_RX_PIN); \
gpio_set_output_options(USBUSART_PORT, GPIO_OTYPE_OD, \
GPIO_OSPEED_100MHZ, USBUSART_RX_PIN); \
gpio_set_af(USBUSART_PORT, GPIO_AF7, USBUSART_RX_PIN); \
} while(0)
#define USB_DRIVER stm32f107_usb_driver #define USB_DRIVER stm32f107_usb_driver
#define USB_IRQ NVIC_OTG_FS_IRQ #define USB_IRQ NVIC_OTG_FS_IRQ
#define USB_ISR(x) otg_fs_isr(x) #define USB_ISR otg_fs_isr
/* Interrupt priorities. Low numbers are high priority. /* Interrupt priorities. Low numbers are high priority.
* For now USART1 preempts USB which may spin while buffer is drained.
* TIM3 is used for traceswo capture and must be highest priority. * TIM3 is used for traceswo capture and must be highest priority.
*/ */
#define IRQ_PRI_USB (1 << 4) #define IRQ_PRI_USB (2 << 4)
#define IRQ_PRI_USBUSART (2 << 4) #define IRQ_PRI_USBUSART (1 << 4)
#define IRQ_PRI_USBUSART_DMA (2 << 4) #define IRQ_PRI_USBUSART_TIM (3 << 4)
#define IRQ_PRI_TRACE (0 << 4) #define IRQ_PRI_TRACE (0 << 4)
#define USBUSART USART3
#define USBUSART_CR1 USART3_CR1
#define USBUSART_IRQ NVIC_USART3_IRQ
#define USBUSART_CLK RCC_USART3
#define USBUSART_TX_PORT GPIOD
#define USBUSART_TX_PIN GPIO8
#define USBUSART_RX_PORT GPIOD
#define USBUSART_RX_PIN GPIO9
#define USBUSART_ISR usart3_isr
#define USBUSART_TIM TIM4
#define USBUSART_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM4)
#define USBUSART_TIM_IRQ NVIC_TIM4_IRQ
#define USBUSART_TIM_ISR tim4_isr
#define UART_PIN_SETUP() do { \
gpio_mode_setup(USBUSART_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
USBUSART_TX_PIN); \
gpio_mode_setup(USBUSART_RX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
USBUSART_RX_PIN); \
gpio_set_af(USBUSART_TX_PORT, GPIO_AF7, USBUSART_TX_PIN); \
gpio_set_af(USBUSART_RX_PORT, GPIO_AF7, USBUSART_RX_PIN); \
} while(0)
#define TRACE_TIM TIM3 #define TRACE_TIM TIM3
#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) #define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3)
#define TRACE_IRQ NVIC_TIM3_IRQ #define TRACE_IRQ NVIC_TIM3_IRQ
#define TRACE_ISR(x) tim3_isr(x) #define TRACE_ISR tim3_isr
#define gpio_set_val(port, pin, val) do { \ #define gpio_set_val(port, pin, val) do { \
if(val) \ if(val) \

View File

@ -1,39 +1,18 @@
CC ?= gcc
SYS = $(shell $(CC) -dumpmachine) SYS = $(shell $(CC) -dumpmachine)
CFLAGS += -DENABLE_DEBUG -DPLATFORM_HAS_DEBUG CFLAGS += -DENABLE_DEBUG -DPLATFORM_HAS_DEBUG
CFLAGS +=-I ./target -I./platforms/pc CFLAGS +=-I ./target -I./platforms/pc
# Define HOSTED_BMP_ONLY to '0' in order to build the hosted blackmagic
# executable with support for other probes beside BMP. Default HOSTED_BMP_ONLY
# == 1 on Windows makes linking against the libftdi and libusb libraries
# unnecessary.
# This can be useful to minimize external dependencies, and make building on
# windows systems easier and is default now.
ifneq (, $(findstring linux, $(SYS)))
HOSTED_BMP_ONLY ?= 0
else
HOSTED_BMP_ONLY ?= 1
endif
CFLAGS += -DHOSTED_BMP_ONLY=$(HOSTED_BMP_ONLY)
ifneq (, $(findstring linux, $(SYS))) ifneq (, $(findstring linux, $(SYS)))
SRC += serial_unix.c SRC += serial_unix.c
HIDAPILIB = hidapi-hidraw
ifeq ($(ASAN), 1) ifeq ($(ASAN), 1)
CFLAGS += -fsanitize=address -Wno-format-truncation CFLAGS += -fsanitize=address
LDFLAGS += -lasan LDFLAGS += -lasan
endif endif
else ifneq (, $(findstring mingw, $(SYS))) else ifneq (, $(findstring mingw, $(SYS)))
# Build for windows versions Vista, and above, where the
# 'SetupDiGetDevicePropertyW()' function is available
CFLAGS += -D_WIN32_WINNT=0x600
SRC += serial_win.c SRC += serial_win.c
LDFLAGS += -lws2_32 LDFLAGS += -lws2_32
LDFLAGS += -lsetupapi LDFLAGS += -lsetupapi
else ifneq (, $(findstring cygwin, $(SYS))) else ifneq (, $(findstring cygwin, $(SYS)))
# Build for windows versions Vista, and above, where the
# 'SetupDiGetDevicePropertyW()' function is available
CFLAGS += -D_WIN32_WINNT=0x600
SRC += serial_win.c SRC += serial_win.c
LDFLAGS += -lws2_32 LDFLAGS += -lws2_32
LDFLAGS += -lsetupapi LDFLAGS += -lsetupapi
@ -43,43 +22,29 @@ SRC += serial_unix.c
LDFLAGS += -lhidapi LDFLAGS += -lhidapi
LDFLAGS += -framework CoreFoundation LDFLAGS += -framework CoreFoundation
CFLAGS += -Ihidapi/hidapi CFLAGS += -Ihidapi/hidapi
HIDAPILIB = hidapi
endif endif
ifneq ($(HOSTED_BMP_ONLY), 1)
$(shell pkg-config --exists libftdi1)
ifneq ($(.SHELLSTATUS), 0)
$(error Please install libftdi1 dependency or set HOSTED_BMP_ONLY to 1)
endif
LDFLAGS += -lusb-1.0 LDFLAGS += -lusb-1.0
CFLAGS += $(shell pkg-config --cflags libftdi1) CFLAGS += $(shell pkg-config --cflags libftdi1)
LDFLAGS += $(shell pkg-config --libs libftdi1) LDFLAGS += $(shell pkg-config --libs libftdi1)
CFLAGS += -Wno-missing-field-initializers CFLAGS += -Wno-missing-field-initializers
endif
ifneq ($(HOSTED_BMP_ONLY), 1) ifneq (, $(findstring mingw, $(SYS)))
SRC += cmsis_dap.c dap.c hid.c
CFLAGS += -DCMSIS_DAP
else
ifeq ($(shell pkg-config --exists hidapi-libusb && echo 0), 0)
CFLAGS += $(shell pkg-config --cflags hidapi-libusb)
LDFLAGS += $(shell pkg-config --libs hidapi-libusb)
CFLAGS += -DCMSIS_DAP CFLAGS += -DCMSIS_DAP
SRC += cmsis_dap.c dap.c SRC += cmsis_dap.c dap.c
ifneq (, $(findstring mingw, $(SYS)))
SRC += hid.c
else
$(shell pkg-config --exists $(HIDAPILIB))
ifneq ($(.SHELLSTATUS), 0)
$(error Please install $(HIDAPILIB) dependency or set HOSTED_BMP_ONLY to 1)
endif
CFLAGS += $(shell pkg-config --cflags $(HIDAPILIB))
LDFLAGS += $(shell pkg-config --libs $(HIDAPILIB))
endif endif
endif endif
VPATH += platforms/pc VPATH += platforms/pc
SRC += timing.c cl_utils.c utils.c SRC += timing.c cl_utils.c utils.c libusb_utils.c
SRC += stlinkv2.c
SRC += bmp_remote.c remote_swdptap.c remote_jtagtap.c SRC += bmp_remote.c remote_swdptap.c remote_jtagtap.c
ifneq ($(HOSTED_BMP_ONLY), 1)
SRC += bmp_libusb.c stlinkv2.c
SRC += ftdi_bmp.c libftdi_swdptap.c libftdi_jtagtap.c SRC += ftdi_bmp.c libftdi_swdptap.c libftdi_jtagtap.c
SRC += jlink.c jlink_adiv5_swdp.c jlink_jtagtap.c SRC += jlink.c jlink_adiv5_swdp.c jlink_jtagtap.c
else
SRC += bmp_serial.c
endif
PC_HOSTED = 1 PC_HOSTED = 1

View File

@ -1,7 +1,5 @@
# PC-Hosted BMP # PC-Hosted BMP
Compile in src with "make PROBE_HOST=hosted". This needs minimal external Compile in src with "make PROBE_HOST=hosted"
support. "make PROBE_HOST=hosted HOSTED_BMP_ONLY=0" will compile support for FTDI,
STLink, CMSIS-DAP and JLINK probes, but requires external libraries.
## Description ## Description
PC-hosted BMP run on the PC and compiles as "blackmagic". When started, PC-hosted BMP run on the PC and compiles as "blackmagic". When started,
@ -10,7 +8,7 @@ if either only one probe is attached to the PC or enough information is
given on the command line to select one of several probes. given on the command line to select one of several probes.
When started without any other argument beside the probe selection, a When started without any other argument beside the probe selection, a
GDB server is started on port 2000 and up. Connect to the server as you would GDB server is started as port 2000 and up. Connect to the server as you would
connect to the BMP with the CDCACM GDB serial server. GDB functionality connect to the BMP with the CDCACM GDB serial server. GDB functionality
is the same, monitor option may vary. is the same, monitor option may vary.
@ -38,51 +36,23 @@ blackmagic -V <file>.bin
``` ```
### Show more options ### Show more options
``` ```
blackmagic -h blackmagic -h"
``` ```
### Show available monitor commands ## Used libraries:
```
blackmagic -M help
```
### Show available monitor commands on second target
```
blackmagic -n 2 -M help
```
### Monitor commands with multiple arguments, e.g.Stm32F1:
```
blackmagic -M "option help"
```
## Used shared libraries:
### libusb ### libusb
### libftdi, for FTDI support ### libftdi, for FTDI support
## Other used libraries:
### hidapi-libusb, for CMSIS-DAP support ### hidapi-libusb, for CMSIS-DAP support
## Compiling on windows ## Compiling on windows
You can crosscompile blackmagic for windows with mingw or on windows You can crosscompile blackmagic for windows with mingw or on windows
with cygwin. For suppport of other probes beside BMP, headers for libftdi1 and with cygwin. For compilation, headers for libftdi1 and libusb-1.0 are
libusb-1.0 are needed. For running, libftdi1.dll and libusb-1.0.dll are needed needed. For running, libftdi1.dll and libusb-1.0.dll are needed and
and the executable must be able to find them. Mingw on cygwin does not provide the executable must be able to find them. Mingw on cygwin does not provide
a libftdi package yet. a libftdi package yet.
PC-hosted BMP for windows can also be built with [MSYS2](https://www.msys2.org/), To prepare libusb access to the ftdi device, run zadig https://zadig.akeo.ie/.
in windows. Make sure to use the `mingw64` shell from msys2, otherwise, Choose WinUSB(libusb-1.0) for the BMP Ftdi device.
you may get compilation errors. You will need to install the libusb
and libftdi libraries, and have the correct mingw compiler.
You can use these commands to install dependencies, and build PC-hosted BMP
from a mingw64 shell, from within the `src` directory:
```
pacman -S mingw-w64-x86_64-libusb --needed
pacman -S mingw-w64-x86_64-libftdi --needed
pacman -S mingw-w64-x86_64-gcc --needed
PROBE_HOST=hosted make
```
For suppport of other probes beside BMP, libusb access is needed. To prepare
libusb access to the ftdi/stlink/jlink/cmsis-dap devices, run zadig
https://zadig.akeo.ie/. Choose WinUSB(libusb-1.0).
Running cygwin/blackmagic in a cygwin console, the program does not react Running cygwin/blackmagic in a cygwin console, the program does not react
on ^C. In another console, run "ps ax" to find the WINPID of the process on ^C. In another console, run "ps ax" to find the WINPID of the process
@ -94,7 +64,6 @@ REMOTE_BMP is a "normal" BMP usb connected
| Debugger | Speed | Remarks | Debugger | Speed | Remarks
| ------------ | ----- | ------ | ------------ | ----- | ------
| REMOTE_BMP | +++ | Requires recent firmware for decent speed | REMOTE_BMP | +++ | Requires recent firmware for decent speed
Probes below only when compiled with HOSTED_BMP_ONLY=0
| ST-Link V3 | ++++ | Requires recent firmware, Only STM32 devices supported! | ST-Link V3 | ++++ | Requires recent firmware, Only STM32 devices supported!
| ST-Link V2 | +++ | Requires recent firmware, No CDCACM uart! Cortex only! | ST-Link V2 | +++ | Requires recent firmware, No CDCACM uart! Cortex only!
| ST-Link V2/1 | +++ | Requires recent firmware, Cortex only! | ST-Link V2/1 | +++ | Requires recent firmware, Cortex only!
@ -171,7 +140,7 @@ cables already listed and propose other cable. A link to the schematics
is welcome. is welcome.
## Feedback ## Feedback
### Issues and Pull request on https://github.com/blackmagic-debug/blackmagic/ ### Issues and Pull request on https://github.com/blacksphere/blackmagic/
### Discussions on Discord. ### Discussions on Discord.
You can find the Discord link here: https://1bitsquared.com/pages/chat You can find the Discord link here: https://1bitsquared.com/pages/chat
### Blackmagic mailing list http://sourceforge.net/mail/?group_id=407419 ### Blackmagic mailing list http://sourceforge.net/mail/?group_id=407419

View File

@ -1,52 +0,0 @@
#if !defined(__BMP_LIBUSB_H)
#define __BMP_LIBUSB_H
#include "cl_utils.h"
#if HOSTED_BMP_ONLY != 1
# include <libusb-1.0/libusb.h>
struct trans_ctx {
#define TRANS_FLAGS_IS_DONE (1 << 0)
#define TRANS_FLAGS_HAS_ERROR (1 << 1)
volatile unsigned long flags;
};
typedef struct usb_link_s {
libusb_context *ul_libusb_ctx;
libusb_device_handle *ul_libusb_device_handle;
unsigned char ep_tx;
unsigned char ep_rx;
struct libusb_transfer* req_trans;
struct libusb_transfer* rep_trans;
void *priv;
} usb_link_t;
int send_recv(usb_link_t *link, uint8_t *txbuf, size_t txsize,
uint8_t *rxbuf, size_t rxsize);
#endif
typedef struct bmp_info_s {
bmp_type_t bmp_type;
char dev;
char serial[64];
char manufacturer[512];
char product[256];
char version[256];
bool is_jtag;
#if HOSTED_BMP_ONLY != 1
libusb_context *libusb_ctx;
struct ftdi_context *ftdic;
usb_link_t *usb_link;
unsigned int vid;
unsigned int pid;
uint8_t interface_num;
uint8_t in_ep;
uint8_t out_ep;
#endif
} bmp_info_t;
extern bmp_info_t info;
void bmp_ident(bmp_info_t *info);
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info);
void libusb_exit_function(bmp_info_t *info);
#endif

View File

@ -1,473 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright(C) 2020 - 2022 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
*
* 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/>.
*/
/* Find all known usb connected debuggers */
#include "general.h"
#include "libusb-1.0/libusb.h"
#include "cl_utils.h"
#include "ftdi_bmp.h"
#include "version.h"
#define NO_SERIAL_NUMBER "<no serial number>"
void bmp_ident(bmp_info_t *info)
{
DEBUG_INFO("BMP hosted %s\n for ST-Link V2/3, CMSIS_DAP, JLINK and "
"LIBFTDI/MPSSE\n", FIRMWARE_VERSION);
if (info && info->vid && info->pid)
DEBUG_INFO("Using %04x:%04x %s %s\n %s\n", info->vid, info->pid,
(info->serial[0]) ? info->serial : NO_SERIAL_NUMBER,
info->manufacturer,
info->product);
}
void libusb_exit_function(bmp_info_t *info)
{
if (!info->usb_link)
return;
libusb_free_transfer(info->usb_link->req_trans);
libusb_free_transfer(info->usb_link->rep_trans);
if (info->usb_link->ul_libusb_device_handle) {
libusb_release_interface (
info->usb_link->ul_libusb_device_handle, 0);
libusb_close(info->usb_link->ul_libusb_device_handle);
}
}
static bmp_type_t find_cmsis_dap_interface(libusb_device *dev,bmp_info_t *info) {
bmp_type_t type = BMP_TYPE_NONE;
struct libusb_config_descriptor *conf;
char interface_string[128];
int res = libusb_get_active_config_descriptor(dev, &conf);
if (res < 0) {
DEBUG_WARN( "WARN: libusb_get_active_config_descriptor() failed: %s",
libusb_strerror(res));
return type;
}
libusb_device_handle *handle;
res = libusb_open(dev, &handle);
if (res != LIBUSB_SUCCESS) {
DEBUG_INFO("INFO: libusb_open() failed: %s\n",
libusb_strerror(res));
libusb_free_config_descriptor(conf);
return type;
}
for (int i = 0; i < conf->bNumInterfaces; i++) {
const struct libusb_interface_descriptor *interface = &conf->interface[i].altsetting[0];
if (!interface->iInterface) {
continue;
}
res = libusb_get_string_descriptor_ascii(
handle, interface->iInterface, (uint8_t*)interface_string,
sizeof(interface_string));
if (res < 0) {
DEBUG_WARN( "WARN: libusb_get_string_descriptor_ascii() failed: %s\n",
libusb_strerror(res));
continue;
}
if (!strstr(interface_string, "CMSIS")) {
continue;
}
type = BMP_TYPE_CMSIS_DAP;
if (interface->bInterfaceClass == 0xff && interface->bNumEndpoints == 2) {
info->interface_num = interface->bInterfaceNumber;
for (int j = 0; j < interface->bNumEndpoints; j++) {
uint8_t n = interface->endpoint[j].bEndpointAddress;
if (n & 0x80) {
info->in_ep = n;
} else {
info->out_ep = n;
}
}
/* V2 is preferred, return early. */
break;
}
}
libusb_free_config_descriptor(conf);
return type;
}
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
{
libusb_device **devs;
int res = libusb_init(&info->libusb_ctx);
if (res) {
DEBUG_WARN( "Fatal: Failed to get USB context: %s\n",
libusb_strerror(res));
exit(-1);
}
if (cl_opts->opt_cable) {
if (!strcmp(cl_opts->opt_cable, "list") ||
!strcmp(cl_opts->opt_cable, "l")) {
cable_desc_t *cable = cable_desc;
DEBUG_WARN("Available cables:\n");
for (; cable->name; ++cable) {
DEBUG_WARN("\t%s\n", cable->name);
}
exit(0);
}
info->bmp_type = BMP_TYPE_LIBFTDI;
}
int n_devs = libusb_get_device_list(info->libusb_ctx, &devs);
if (n_devs < 0) {
DEBUG_WARN( "WARN:libusb_get_device_list() failed");
return -1;
}
bool report = false;
int found_debuggers;
struct libusb_device_descriptor desc;
char serial[64];
char manufacturer[128];
char product[128];
bool access_problems = false;
char *active_cable = NULL;
bool ftdi_unknown = false;
rescan:
found_debuggers = 0;
serial[0] = 0;
manufacturer[0] = 0;
product[0] = 0;
access_problems = false;
active_cable = NULL;
ftdi_unknown = false;
for (size_t i = 0; devs[i]; ++i) {
bmp_type_t type = BMP_TYPE_NONE;
libusb_device *dev = devs[i];
int res = libusb_get_device_descriptor(dev, &desc);
if (res < 0) {
DEBUG_WARN( "WARN: libusb_get_device_descriptor() failed: %s",
libusb_strerror(res));
libusb_free_device_list(devs, 1);
continue;
}
/* Exclude hubs from testing. Probably more classes could be excluded here!*/
switch (desc.bDeviceClass) {
case LIBUSB_CLASS_HUB:
case LIBUSB_CLASS_WIRELESS:
continue;
}
libusb_device_handle *handle = NULL;
res = libusb_open(dev, &handle);
if (res != LIBUSB_SUCCESS) {
if (!access_problems) {
DEBUG_INFO("INFO: Open USB %04x:%04x class %2x failed\n",
desc.idVendor, desc.idProduct, desc.bDeviceClass);
access_problems = true;
}
continue;
}
/* If the device even has a serial number string, fetch it */
if (desc.iSerialNumber) {
res = libusb_get_string_descriptor_ascii(handle, desc.iSerialNumber,
(uint8_t *)serial, sizeof(serial));
/* If the call fails and it's not because the device gave us STALL, continue to the next one */
if (res < 0 && res != LIBUSB_ERROR_PIPE) {
libusb_close(handle);
continue;
}
/* Device has no serial and that's ok. */
else if (res <= 0)
serial[0] = '\0';
}
else
serial[0] = '\0';
if (cl_opts->opt_serial && !strstr(serial, cl_opts->opt_serial)) {
libusb_close(handle);
continue;
}
/* Attempt to get the manufacturer string */
if (desc.iManufacturer) {
res = libusb_get_string_descriptor_ascii(handle, desc.iManufacturer,
(uint8_t *)manufacturer, sizeof(manufacturer));
/* If the call fails and it's not because the device gave us STALL, continue to the next one */
if (res < 0 && res != LIBUSB_ERROR_PIPE) {
DEBUG_WARN("WARN: libusb_get_string_descriptor_ascii() call to fetch manufacturer string failed: %s\n",
libusb_strerror(res));
libusb_close(handle);
continue;
}
/* Device has no manufacturer string and that's ok. */
else if (res <= 0)
manufacturer[0] = '\0';
}
else
manufacturer[0] = '\0';
/* Attempt to get the product string */
if (desc.iProduct) {
res = libusb_get_string_descriptor_ascii(handle, desc.iProduct,
(uint8_t *)product, sizeof(product));
/* If the call fails and it's not because the device gave us STALL, continue to the next one */
if (res < 0 && res != LIBUSB_ERROR_PIPE) {
DEBUG_WARN("WARN: libusb_get_string_descriptor_ascii() call to fetch product string failed: %s\n",
libusb_strerror(res));
libusb_close(handle);
continue;
}
/* Device has no product string and that's ok. */
else if (res <= 0)
product[0] = '\0';
}
else
product[0] = '\0';
libusb_close(handle);
if (cl_opts->opt_ident_string) {
char *match_manu = NULL;
char *match_product = NULL;
match_manu = strstr(manufacturer, cl_opts->opt_ident_string);
match_product = strstr(product, cl_opts->opt_ident_string);
if (!match_manu && !match_product)
continue;
}
/* Either serial and/or ident_string match or are not given.
* Check type.*/
if (desc.idVendor == VENDOR_ID_BMP) {
if (desc.idProduct == PRODUCT_ID_BMP)
type = BMP_TYPE_BMP;
else {
if (desc.idProduct == PRODUCT_ID_BMP_BL)
DEBUG_WARN("BMP in bootloader mode found. Restart or reflash!\n");
continue;
}
} else if (type == BMP_TYPE_NONE &&
(type = find_cmsis_dap_interface(dev, info)) != BMP_TYPE_NONE) {
/* find_cmsis_dap_interface has set valid type*/
} else if (strstr(manufacturer, "CMSIS") || strstr(product, "CMSIS"))
type = BMP_TYPE_CMSIS_DAP;
else if (desc.idVendor == VENDOR_ID_STLINK) {
if (desc.idProduct == PRODUCT_ID_STLINKV2 ||
desc.idProduct == PRODUCT_ID_STLINKV21 ||
desc.idProduct == PRODUCT_ID_STLINKV21_MSD ||
desc.idProduct == PRODUCT_ID_STLINKV3_NO_MSD ||
desc.idProduct == PRODUCT_ID_STLINKV3_BL ||
desc.idProduct == PRODUCT_ID_STLINKV3 ||
desc.idProduct == PRODUCT_ID_STLINKV3E)
type = BMP_TYPE_STLINKV2;
else {
if (desc.idProduct == PRODUCT_ID_STLINKV1)
DEBUG_WARN( "INFO: STLINKV1 not supported\n");
continue;
}
} else if (desc.idVendor == VENDOR_ID_SEGGER)
type = BMP_TYPE_JLINK;
else {
cable_desc_t *cable = cable_desc;
for (; cable->name; ++cable) {
bool found = false;
if (cable->vendor != desc.idVendor || cable->product != desc.idProduct)
continue; /* VID/PID do not match*/
if (cl_opts->opt_cable) {
if (strncmp(cable->name, cl_opts->opt_cable, strlen(cable->name)))
continue; /* cable names do not match*/
else
found = true;
}
if (cable->description) {
if (strncmp(cable->description, product, strlen(cable->description)))
continue; /* discriptions do not match*/
else
found = true;
} else { /* VID/PID fits, but no cl_opts->opt_cable and no description*/
if (cable->vendor == 0x0403 && /* FTDI*/
(cable->product == 0x6010 || /* FT2232C/D/H*/
cable->product == 0x6011 || /* FT4232H Quad HS USB-UART/FIFO IC */
cable->product == 0x6014)) { /* FT232H Single HS USB-UART/FIFO IC */
ftdi_unknown = true;
continue; /* Cable name is needed */
}
}
if (found) {
active_cable = cable->name;
type = BMP_TYPE_LIBFTDI;
break;
}
}
if (!cable->name)
continue;
}
if (report) {
DEBUG_WARN("%2d: %s, %s, %s\n", found_debuggers + 1,
serial[0] ? serial : NO_SERIAL_NUMBER,
manufacturer,product);
}
info->vid = desc.idVendor;
info->pid = desc.idProduct;
info->bmp_type = type;
strncpy(info->serial, serial, sizeof(info->serial));
strncpy(info->product, product, sizeof(info->product));
strncpy(info->manufacturer, manufacturer, sizeof(info->manufacturer));
if (cl_opts->opt_position &&
cl_opts->opt_position == found_debuggers + 1) {
found_debuggers = 1;
break;
} else
++found_debuggers;
}
if (found_debuggers == 0 && ftdi_unknown)
DEBUG_WARN("Generic FTDI MPSSE VID/PID found. Please specify exact type with \"-c <cable>\" !\n");
if (found_debuggers == 1 && !cl_opts->opt_cable && info->bmp_type == BMP_TYPE_LIBFTDI)
cl_opts->opt_cable = active_cable;
if (!found_debuggers && cl_opts->opt_list_only)
DEBUG_WARN("No usable debugger found\n");
if (found_debuggers > 1 ||
(found_debuggers == 1 && cl_opts->opt_list_only)) {
if (!report) {
if (found_debuggers > 1)
DEBUG_WARN("%d debuggers found!\nSelect with -P <pos> "
"or -s <(partial)serial no.>\n",
found_debuggers);
report = true;
goto rescan;
} else {
if (found_debuggers > 0)
access_problems = false;
found_debuggers = 0;
}
}
if (!found_debuggers && access_problems)
DEBUG_WARN(
"No debugger found. Please check access rights to USB devices!\n");
libusb_free_device_list(devs, 1);
return found_debuggers == 1 ? 0 : -1;
}
static void LIBUSB_CALL on_trans_done(struct libusb_transfer *trans)
{
struct trans_ctx * const ctx = trans->user_data;
if (trans->status != LIBUSB_TRANSFER_COMPLETED)
{
DEBUG_WARN("on_trans_done: ");
if (trans->status == LIBUSB_TRANSFER_TIMED_OUT)
DEBUG_WARN(" Timeout\n");
else if (trans->status == LIBUSB_TRANSFER_CANCELLED)
DEBUG_WARN(" cancelled\n");
else if (trans->status == LIBUSB_TRANSFER_NO_DEVICE)
DEBUG_WARN(" no device\n");
else
DEBUG_WARN(" unknown\n");
ctx->flags |= TRANS_FLAGS_HAS_ERROR;
}
ctx->flags |= TRANS_FLAGS_IS_DONE;
}
static int submit_wait(usb_link_t *link, struct libusb_transfer *trans) {
struct trans_ctx trans_ctx;
enum libusb_error error;
trans_ctx.flags = 0;
/* brief intrusion inside the libusb interface */
trans->callback = on_trans_done;
trans->user_data = &trans_ctx;
if ((error = libusb_submit_transfer(trans))) {
DEBUG_WARN("libusb_submit_transfer(%d): %s\n", error,
libusb_strerror(error));
exit(-1);
}
uint32_t start_time = platform_time_ms();
while (trans_ctx.flags == 0) {
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
if (libusb_handle_events_timeout(link->ul_libusb_ctx, &timeout)) {
DEBUG_WARN("libusb_handle_events()\n");
return -1;
}
uint32_t now = platform_time_ms();
if (now - start_time > 1000) {
libusb_cancel_transfer(trans);
DEBUG_WARN("libusb_handle_events() timeout\n");
return -1;
}
}
if (trans_ctx.flags & TRANS_FLAGS_HAS_ERROR) {
DEBUG_WARN("libusb_handle_events() | has_error\n");
return -1;
}
return 0;
}
/* One USB transaction */
int send_recv(usb_link_t *link,
uint8_t *txbuf, size_t txsize,
uint8_t *rxbuf, size_t rxsize)
{
int res = 0;
if (txsize) {
libusb_fill_bulk_transfer(link->req_trans,
link->ul_libusb_device_handle,
link->ep_tx | LIBUSB_ENDPOINT_OUT,
txbuf, txsize,
NULL, NULL, 0);
size_t i = 0;
DEBUG_WIRE(" Send (%3zu): ", txsize);
for (; i < txsize; ++i) {
DEBUG_WIRE("%02x", txbuf[i]);
if ((i & 7U) == 7U)
DEBUG_WIRE(".");
if ((i & 31U) == 31U)
DEBUG_WIRE("\n ");
}
if (!(i & 31U))
DEBUG_WIRE("\n");
if (submit_wait(link, link->req_trans)) {
libusb_clear_halt(link->ul_libusb_device_handle, link->ep_tx);
return -1;
}
}
/* send_only */
if (rxsize != 0) {
/* read the response */
libusb_fill_bulk_transfer(link->rep_trans, link->ul_libusb_device_handle,
link->ep_rx | LIBUSB_ENDPOINT_IN,
rxbuf, rxsize, NULL, NULL, 0);
if (submit_wait(link, link->rep_trans)) {
DEBUG_WARN("clear 1\n");
libusb_clear_halt(link->ul_libusb_device_handle, link->ep_rx);
return -1;
}
res = link->rep_trans->actual_length;
if (res > 0) {
const size_t rxlen = (size_t)res;
DEBUG_WIRE(" Rec (%zu/%zu)", rxsize, rxlen);
for (size_t i = 0; i < rxlen && i < 32 ; ++i) {
if (i && ((i & 7U) == 0U))
DEBUG_WIRE(".");
DEBUG_WIRE("%02x", rxbuf[i]);
}
}
}
DEBUG_WIRE("\n");
return res;
}

View File

@ -22,6 +22,7 @@
#include "general.h" #include "general.h"
#include "gdb_if.h" #include "gdb_if.h"
#include "version.h" #include "version.h"
#include "platform.h"
#include "remote.h" #include "remote.h"
#include "target.h" #include "target.h"
#include "bmp_remote.h" #include "bmp_remote.h"
@ -32,22 +33,24 @@
#include <sys/time.h> #include <sys/time.h>
#include <sys/time.h> #include <sys/time.h>
#include <errno.h> #include <errno.h>
#include <string.h>
#include "adiv5.h" #include "adiv5.h"
int remote_init(void) int remote_init(bool verbose)
{ {
char construct[REMOTE_MAX_MSG_SIZE]; char construct[REMOTE_MAX_MSG_SIZE];
int c = snprintf(construct, REMOTE_MAX_MSG_SIZE, "%s", REMOTE_START_STR); int c = snprintf(construct, REMOTE_MAX_MSG_SIZE, "%s", REMOTE_START_STR);
platform_buffer_write((uint8_t *)construct, c); platform_buffer_write((uint8_t *)construct, c);
c = platform_buffer_read((uint8_t *)construct, REMOTE_MAX_MSG_SIZE); c = platform_buffer_read((uint8_t *)construct, REMOTE_MAX_MSG_SIZE);
if ((c < 1) || (construct[0] == REMOTE_RESP_ERR)) { if ((!c) || (construct[0] == REMOTE_RESP_ERR)) {
DEBUG_WARN("Remote Start failed, error %s\n", DEBUG_WARN("Remote Start failed, error %s\n",
c ? (char *)&(construct[1]) : "unknown"); c ? (char *)&(construct[1]) : "unknown");
return -1; return -1;
} }
DEBUG_PROBE("Remote is %s\n", &construct[1]); if (verbose)
DEBUG_WARN("Remote is %s\n", &construct[1]);
return 0; return 0;
} }
@ -62,7 +65,7 @@ bool remote_target_get_power(void)
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) { if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
DEBUG_WARN(" platform_target_get_power failed, error %s\n", DEBUG_WARN(" platform_target_get_power failed, error %s\n",
s ? (char *)&(construct[1]) : "unknown"); s ? (char *)&(construct[1]) : "unknown");
exit (-1); exit (-1);
@ -71,7 +74,7 @@ bool remote_target_get_power(void)
return (construct[1] == '1'); return (construct[1] == '1');
} }
bool remote_target_set_power(bool power) void remote_target_set_power(bool power)
{ {
uint8_t construct[REMOTE_MAX_MSG_SIZE]; uint8_t construct[REMOTE_MAX_MSG_SIZE];
int s; int s;
@ -82,12 +85,11 @@ bool remote_target_set_power(bool power)
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) { if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
DEBUG_WARN("platform_target_set_power failed, error %s\n", DEBUG_WARN("platform_target_set_power failed, error %s\n",
s ? (char *)&(construct[1]) : "unknown"); s ? (char *)&(construct[1]) : "unknown");
return false; exit(-1);
} }
return true;
} }
void remote_srst_set_val(bool assert) void remote_srst_set_val(bool assert)
@ -101,7 +103,7 @@ void remote_srst_set_val(bool assert)
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) { if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
DEBUG_WARN("platform_srst_set_val failed, error %s\n", DEBUG_WARN("platform_srst_set_val failed, error %s\n",
s ? (char *)&(construct[1]) : "unknown"); s ? (char *)&(construct[1]) : "unknown");
exit(-1); exit(-1);
@ -119,7 +121,7 @@ bool remote_srst_get_val(void)
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) { if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
DEBUG_WARN("platform_srst_set_val failed, error %s\n", DEBUG_WARN("platform_srst_set_val failed, error %s\n",
s ? (char *)&(construct[1]) : "unknown"); s ? (char *)&(construct[1]) : "unknown");
exit(-1); exit(-1);
@ -127,40 +129,6 @@ bool remote_srst_get_val(void)
return (construct[1] == '1'); return (construct[1] == '1');
} }
void remote_max_frequency_set(uint32_t freq)
{
uint8_t construct[REMOTE_MAX_MSG_SIZE];
int s;
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, REMOTE_FREQ_SET_STR,
freq);
platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) {
DEBUG_WARN("Update Firmware to allow to set max SWJ frequency\n");
}
}
uint32_t remote_max_frequency_get(void)
{
uint8_t construct[REMOTE_MAX_MSG_SIZE];
int s;
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,"%s",
REMOTE_FREQ_GET_STR);
platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR))
return FREQ_FIXED;
uint32_t freq[1];
unhexify(freq, (const char*)&construct[1], 4);
return freq[0];
}
const char *remote_target_voltage(void) const char *remote_target_voltage(void)
{ {
static uint8_t construct[REMOTE_MAX_MSG_SIZE]; static uint8_t construct[REMOTE_MAX_MSG_SIZE];
@ -172,7 +140,7 @@ const char *remote_target_voltage(void)
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) { if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
DEBUG_WARN("platform_target_voltage failed, error %s\n", DEBUG_WARN("platform_target_voltage failed, error %s\n",
s ? (char *)&(construct[1]) : "unknown"); s ? (char *)&(construct[1]) : "unknown");
exit(- 1); exit(- 1);
@ -185,10 +153,10 @@ static uint32_t remote_adiv5_dp_read(ADIv5_DP_t *dp, uint16_t addr)
(void)dp; (void)dp;
uint8_t construct[REMOTE_MAX_MSG_SIZE]; uint8_t construct[REMOTE_MAX_MSG_SIZE];
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, REMOTE_DP_READ_STR, int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, REMOTE_DP_READ_STR,
dp->dp_jd_index, addr); addr);
platform_buffer_write(construct, s); platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) { if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
DEBUG_WARN("%s error %d\n", __func__, s); DEBUG_WARN("%s error %d\n", __func__, s);
} }
uint32_t dest[1]; uint32_t dest[1];
@ -203,10 +171,10 @@ static uint32_t remote_adiv5_low_access(
(void)dp; (void)dp;
uint8_t construct[REMOTE_MAX_MSG_SIZE]; uint8_t construct[REMOTE_MAX_MSG_SIZE];
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,
REMOTE_LOW_ACCESS_STR, dp->dp_jd_index, RnW, addr, value); REMOTE_LOW_ACCESS_STR, RnW, addr, value);
platform_buffer_write(construct, s); platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) { if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
DEBUG_WARN("%s error %d\n", __func__, s); DEBUG_WARN("%s error %d\n", __func__, s);
} }
uint32_t dest[1]; uint32_t dest[1];
@ -218,10 +186,10 @@ static uint32_t remote_adiv5_ap_read(ADIv5_AP_t *ap, uint16_t addr)
{ {
uint8_t construct[REMOTE_MAX_MSG_SIZE]; uint8_t construct[REMOTE_MAX_MSG_SIZE];
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,REMOTE_AP_READ_STR, int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,REMOTE_AP_READ_STR,
ap->dp->dp_jd_index, ap->apsel, addr); ap->apsel, addr);
platform_buffer_write(construct, s); platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) { if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
DEBUG_WARN("%s error %d\n", __func__, s); DEBUG_WARN("%s error %d\n", __func__, s);
} }
uint32_t dest[1]; uint32_t dest[1];
@ -233,10 +201,10 @@ static void remote_adiv5_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value)
{ {
uint8_t construct[REMOTE_MAX_MSG_SIZE]; uint8_t construct[REMOTE_MAX_MSG_SIZE];
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,REMOTE_AP_WRITE_STR, int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,REMOTE_AP_WRITE_STR,
ap->dp->dp_jd_index, ap->apsel, addr, value); ap->apsel, addr, value);
platform_buffer_write(construct, s); platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR)) { if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
DEBUG_WARN("%s error %d\n", __func__, s); DEBUG_WARN("%s error %d\n", __func__, s);
} }
return; return;
@ -299,7 +267,7 @@ static void remote_ap_mem_read(
if (count > batchsize) if (count > batchsize)
count = batchsize; count = batchsize;
s = snprintf(construct, REMOTE_MAX_MSG_SIZE, s = snprintf(construct, REMOTE_MAX_MSG_SIZE,
REMOTE_AP_MEM_READ_STR, ap->dp->dp_jd_index, ap->apsel, ap->csw, src, count); REMOTE_AP_MEM_READ_STR, ap->apsel, ap->csw, src, count);
platform_buffer_write((uint8_t*)construct, s); platform_buffer_write((uint8_t*)construct, s);
s = platform_buffer_read((uint8_t*)construct, REMOTE_MAX_MSG_SIZE); s = platform_buffer_read((uint8_t*)construct, REMOTE_MAX_MSG_SIZE);
if ((s > 0) && (construct[0] == REMOTE_RESP_OK)) { if ((s > 0) && (construct[0] == REMOTE_RESP_OK)) {
@ -339,7 +307,7 @@ static void remote_ap_mem_write_sized(
count = batchsize; count = batchsize;
int s = snprintf(construct, REMOTE_MAX_MSG_SIZE, int s = snprintf(construct, REMOTE_MAX_MSG_SIZE,
REMOTE_AP_MEM_WRITE_SIZED_STR, REMOTE_AP_MEM_WRITE_SIZED_STR,
ap->dp->dp_jd_index, ap->apsel, ap->csw, align, dest, count); ap->apsel, ap->csw, align, dest, count);
char *p = construct + s; char *p = construct + s;
hexify(p, src, count); hexify(p, src, count);
p += 2 * count; p += 2 * count;
@ -372,8 +340,7 @@ void remote_adiv5_dp_defaults(ADIv5_DP_t *dp)
REMOTE_HL_CHECK_STR); REMOTE_HL_CHECK_STR);
platform_buffer_write(construct, s); platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
if ((s < 1) || (construct[0] == REMOTE_RESP_ERR) || if ((!s) || (construct[0] == REMOTE_RESP_ERR)) {
((construct[1] - '0') < REMOTE_HL_VERSION)) {
DEBUG_WARN( DEBUG_WARN(
"Please update BMP firmware for substantial speed increase!\n"); "Please update BMP firmware for substantial speed increase!\n");
return; return;
@ -385,20 +352,3 @@ void remote_adiv5_dp_defaults(ADIv5_DP_t *dp)
dp->mem_read = remote_ap_mem_read; dp->mem_read = remote_ap_mem_read;
dp->mem_write_sized = remote_ap_mem_write_sized; dp->mem_write_sized = remote_ap_mem_write_sized;
} }
void remote_add_jtag_dev(int i, const jtag_dev_t *jtag_dev)
{
uint8_t construct[REMOTE_MAX_MSG_SIZE];
int s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,
REMOTE_JTAG_ADD_DEV_STR,
i,
jtag_dev->dr_prescan,
jtag_dev->dr_postscan,
jtag_dev->ir_len,
jtag_dev->ir_prescan,
jtag_dev->ir_postscan,
jtag_dev->current_ir);
platform_buffer_write(construct, s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
/* No check for error here. Done in remote_adiv5_dp_defaults!*/
}

View File

@ -18,6 +18,7 @@
*/ */
#if !defined(__BMP_REMOTE_H_) #if !defined(__BMP_REMOTE_H_)
#define __BMP_REMOTE_H_ #define __BMP_REMOTE_H_
#include "swdptap.h"
#include "jtagtap.h" #include "jtagtap.h"
#include "adiv5.h" #include "adiv5.h"
#include "target.h" #include "target.h"
@ -28,18 +29,15 @@
int platform_buffer_write(const uint8_t *data, int size); int platform_buffer_write(const uint8_t *data, int size);
int platform_buffer_read(uint8_t *data, int size); int platform_buffer_read(uint8_t *data, int size);
int remote_init(void); int remote_init(bool verbose);
int remote_swdptap_init(ADIv5_DP_t *dp); int remote_swdptap_init(swd_proc_t *swd_proc);
int remote_jtagtap_init(jtag_proc_t *jtag_proc); int remote_jtagtap_init(jtag_proc_t *jtag_proc);
bool remote_target_get_power(void); bool remote_target_get_power(void);
const char *remote_target_voltage(void); const char *remote_target_voltage(void);
bool remote_target_set_power(bool power); void remote_target_set_power(bool power);
void remote_srst_set_val(bool assert); void remote_srst_set_val(bool assert);
bool remote_srst_get_val(void); bool remote_srst_get_val(void);
void remote_max_frequency_set(uint32_t freq);
uint32_t remote_max_frequency_get(void);
const char *platform_target_voltage(void); const char *platform_target_voltage(void);
void remote_adiv5_dp_defaults(ADIv5_DP_t *dp); void remote_adiv5_dp_defaults(ADIv5_DP_t *dp);
void remote_add_jtag_dev(int i, const jtag_dev_t *jtag_dev);
#define __BMP_REMOTE_H_ #define __BMP_REMOTE_H_
#endif #endif

View File

@ -1,296 +0,0 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
*
* 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/>.
*/
/* Find all known serial connected debuggers */
#include "general.h"
#include <dirent.h>
#include <errno.h>
#include "bmp_hosted.h"
#include "version.h"
void bmp_ident(bmp_info_t *info)
{
if (!info)
return;
DEBUG_INFO("BMP hosted (BMP Only) %s\n", FIRMWARE_VERSION);
DEBUG_INFO("Using:\n %s %s %s\n", info->manufacturer, info->version, info->serial);
}
void libusb_exit_function(bmp_info_t *info) {(void)info;};
#ifdef __APPLE__
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
{
DEBUG_WARN("Please implement find_debuggers for MACOS!\n");
(void)cl_opts;
(void)info;
return -1;
}
#elif defined(__WIN32__) || defined(__CYGWIN__)
/* This source has been used as an example:
* https://stackoverflow.com/questions/3438366/setupdigetdeviceproperty-usage-example */
#include <windows.h>
#include <setupapi.h>
#include <cfgmgr32.h> // for MAX_DEVICE_ID_LEN, CM_Get_Parent and CM_Get_Device_ID
#include <tchar.h>
#include <stdio.h>
/* include DEVPKEY_Device_BusReportedDeviceDesc from WinDDK\7600.16385.1\inc\api\devpropdef.h */
#ifdef DEFINE_DEVPROPKEY
#undef DEFINE_DEVPROPKEY
#endif
#define DEFINE_DEVPROPKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) const DEVPROPKEY DECLSPEC_SELECTANY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid }
/* include DEVPKEY_Device_BusReportedDeviceDesc from WinDDK\7600.16385.1\inc\api\devpkey.h */
DEFINE_DEVPROPKEY(DEVPKEY_Device_BusReportedDeviceDesc, 0x540b947e, 0x8b40, 0x45bc, 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2, 4); // DEVPROP_TYPE_STRING
/* List all USB devices with some additional information.
* Unfortunately, this code is quite ugly. */
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
{
unsigned i;
DWORD dwSize;
DEVPROPTYPE ulPropertyType;
CONFIGRET status;
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
TCHAR szDeviceInstanceID [MAX_DEVICE_ID_LEN];
WCHAR busReportedDeviceSesc[4096];
int probes_found = 0;
bool is_printing_probes_info = cl_opts->opt_list_only != 0;
info->bmp_type = BMP_TYPE_BMP;
hDevInfo = SetupDiGetClassDevs (0, "USB", NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE)
return -1;
print_probes_info:
for (i = 0; ; i++) {
char serial_number[sizeof info->serial];
DeviceInfoData.cbSize = sizeof (DeviceInfoData);
if (!SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData))
break;
status = CM_Get_Device_ID(DeviceInfoData.DevInst, szDeviceInstanceID , MAX_PATH, 0);
if (status != CR_SUCCESS)
continue;
if (!sscanf(szDeviceInstanceID, "USB\\VID_1D50&PID_6018\\%s", serial_number))
continue;
if (SetupDiGetDevicePropertyW (hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc,
&ulPropertyType, (BYTE*)busReportedDeviceSesc, sizeof busReportedDeviceSesc, &dwSize, 0))
{
probes_found ++;
if (is_printing_probes_info)
{
DEBUG_WARN("%2d: %s, %ls\n", probes_found,
serial_number, busReportedDeviceSesc);
}
else
{
bool probe_identified = true;
if ((cl_opts->opt_serial && strstr(serial_number, cl_opts->opt_serial)) ||
(cl_opts->opt_position && cl_opts->opt_position == probes_found) ||
/* Special case for the very first probe found. */
(probe_identified = false, probes_found == 1)) {
strncpy(info->serial, serial_number, sizeof info->serial);
strncpy(info->manufacturer, "BMP", sizeof info->manufacturer);
snprintf(info->product, sizeof info->product, "%ls", busReportedDeviceSesc);
/* Don't bother to parse the version string. It is a part of the
* product description string. It seems that at the moment it
* is only being used to print a version string in response
* to the 'monitor version' command, so it doesn't really matter
* if the version string is printed as a part of the product string,
* or as a separate string, the result is pretty much the same. */
info->version[0] = 0;
if (probe_identified)
return 0;
}
}
}
}
if (is_printing_probes_info)
return 1;
if (probes_found == 1)
/* Exactly one probe found. Its information has already been filled
* in the detection loop, so use this probe. */
return 0;
if (probes_found < 1) {
DEBUG_WARN("No BMP probe found\n");
return -1;
}
/* Otherwise, if this line is reached, then more than one probe has been found,
* and no probe was identified as selected by the user.
* Restart the identification loop, this time printing the probe information,
* and then return. */
DEBUG_WARN("%d debuggers found!\nSelect with -P <pos>, or "
"-s <(partial)serial no.>\n",
probes_found);
probes_found = 0;
is_printing_probes_info = true;
goto print_probes_info;
}
#else
/* Old ID: Black_Sphere_Technologies_Black_Magic_Probe_BFE4D6EC-if00
* Recent: Black_Sphere_Technologies_Black_Magic_Probe_v1.7.1-212-g212292ab_7BAE7AB8-if00
* usb-Black_Sphere_Technologies_Black_Magic_Probe__SWLINK__v1.7.1-155-gf55ad67b-dirty_DECB8811-if00
*/
#define BMP_IDSTRING_BLACKSPHERE "usb-Black_Sphere_Technologies_Black_Magic_Probe"
#define BMP_IDSTRING_BLACKMAGIC "usb-Black_Magic_Debug_Black_Magic_Probe"
#define BMP_IDSTRING_1BITSQUARED "usb-1BitSquared_Black_Magic_Probe"
#define DEVICE_BY_ID "/dev/serial/by-id/"
/*
* Extract type, version and serial from /dev/serial/by_id
* Return 0 on success
*
* Old versions have different strings. Try to cope!
*/
static int scan_linux_id(char *name, char *type, char *version, char *serial)
{
name += strlen(BMP_IDSTRING_BLACKSPHERE) + 1;
while (*name == '_')
name++;
if (!*name) {
DEBUG_WARN("Unexpected end\n");
return -1;
}
char *p = name;
char *delims[4] = {0,0,0,0};
int underscores = 0;
while (*p) {
if (*p == '_') {
while (p[1] == '_')
p++; /* remove multiple underscores */
if (underscores > 2)
return -1;
delims[underscores] = p;
underscores ++;
}
p++;
}
if (underscores == 0) { /* Old BMP native */
int res;
res = sscanf(name, "%8s-if00", serial);
if (res != 1)
return -1;
strcpy(type, "Native");
strcpy(version, "Unknown");
} else if (underscores == 2) {
strncpy(type, name, delims[0] - name - 1);
strncpy(version, delims[0] + 1, delims[1] - delims[0] - 1);
int res = sscanf(delims[1] + 1, "%8s-if00", serial);
if (!res)
return -1;
} else {
int res = sscanf(delims[0] + 1, "%8s-if00", serial);
if (!res)
return -1;
if (name[0] == 'v') {
strcpy(type, "Unknown");
strncpy(version, name, delims[0] - name - 1);
} else {
strncpy(type, name, delims[0] - name);
strcpy(type, "Unknown");
}
}
return 0;
}
int find_debuggers(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
{
if (cl_opts->opt_device)
return 1;
info->bmp_type = BMP_TYPE_BMP;
DIR *dir = opendir(DEVICE_BY_ID);
if (!dir) /* No serial device connected!*/
return 0;
int found_bmps = 0;
struct dirent *dp;
int i = 0;
while ((dp = readdir(dir)) != NULL) {
if ((strstr(dp->d_name, BMP_IDSTRING_BLACKMAGIC) ||
strstr(dp->d_name, BMP_IDSTRING_BLACKSPHERE) ||
strstr(dp->d_name, BMP_IDSTRING_1BITSQUARED)) &&
(strstr(dp->d_name, "-if00"))) {
i++;
char type[256], version[256], serial[256];
if (scan_linux_id(dp->d_name, type, version, serial)) {
DEBUG_WARN("Unexpected device name found \"%s\"\n",
dp->d_name);
}
if ((cl_opts->opt_serial && strstr(serial, cl_opts->opt_serial)) ||
(cl_opts->opt_position && cl_opts->opt_position == i)) {
/* With serial number given and partial match, we are done!*/
strncpy(info->serial, serial, sizeof(info->serial));
int res = snprintf(info->manufacturer, sizeof(info->manufacturer), "Black Magic Probe (%s)", type);
if (res)
DEBUG_WARN("Overflow\n");
strncpy(info->version, version, sizeof(info->version));
found_bmps = 1;
break;
} else {
found_bmps++;
}
}
}
closedir(dir);
if (found_bmps < 1) {
DEBUG_WARN("No BMP probe found\n");
return -1;
} else if ((found_bmps > 1) || cl_opts->opt_list_only) {
DEBUG_WARN("Available Probes:\n");
}
dir = opendir(DEVICE_BY_ID);
i = 0;
while ((dp = readdir(dir)) != NULL) {
if ((strstr(dp->d_name, BMP_IDSTRING_BLACKMAGIC) ||
strstr(dp->d_name, BMP_IDSTRING_BLACKSPHERE) ||
strstr(dp->d_name, BMP_IDSTRING_1BITSQUARED)) &&
(strstr(dp->d_name, "-if00"))) {
i++;
char type[256], version[256], serial[256];
if (scan_linux_id(dp->d_name, type, version, serial)) {
DEBUG_WARN("Unexpected device name found \"%s\"\n",
dp->d_name);
} else if ((found_bmps == 1) && (!cl_opts->opt_list_only)) {
strncpy(info->serial, serial, sizeof(info->serial));
found_bmps = 1;
strncpy(info->serial, serial, sizeof(info->serial));
snprintf(info->manufacturer, sizeof(info->manufacturer), "Black Magic Probe (%s)", type);
strncpy(info->version, version, sizeof(info->version));
break;
} else if (found_bmps > 0) {
DEBUG_WARN("%2d: %s, Black Magic Debug, Black Magic "
"Probe (%s), %s\n", i, serial, type, version);
}
}
}
closedir(dir);
return (found_bmps == 1 && !cl_opts->opt_list_only) ? 0 : 1;
}
#endif

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the Black Magic Debug project. * This file is part of the Black Magic Debug project.
* *
* Copyright (C) 2019-2021 Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de> * Copyright (C) 2019-20 Uwe Bonnes <bon@elektron,ikp.physik.tu-darmstadt.de>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -34,7 +34,6 @@
#include <hidapi.h> #include <hidapi.h>
#include <wchar.h> #include <wchar.h>
#include "bmp_hosted.h"
#include "dap.h" #include "dap.h"
#include "cmsis_dap.h" #include "cmsis_dap.h"
@ -45,101 +44,48 @@
uint8_t dap_caps; uint8_t dap_caps;
uint8_t mode; uint8_t mode;
typedef enum cmsis_type_s {
CMSIS_TYPE_NONE = 0,
CMSIS_TYPE_HID,
CMSIS_TYPE_BULK
} cmsis_type_t;
/*- Variables ---------------------------------------------------------------*/ /*- Variables ---------------------------------------------------------------*/
static cmsis_type_t type;
static libusb_device_handle *usb_handle = NULL;
static uint8_t in_ep;
static uint8_t out_ep;
static hid_device *handle = NULL; static hid_device *handle = NULL;
static uint8_t buffer[1024 + 1]; static uint8_t hid_buffer[1024 + 1];
static int report_size = 64 + 1; // TODO: read actual report size static int report_size = 512 + 1; // TODO: read actual report size
static bool has_swd_sequence = false;
/* LPC845 Breakout Board Rev. 0 report invalid response with > 65 bytes */ /* LPC845 Breakout Board Rev. 0 report invalid response with > 65 bytes */
int dap_init(bmp_info_t *info) int dap_init(bmp_info_t *info)
{ {
type = (info->in_ep && info->out_ep) ? CMSIS_TYPE_BULK : CMSIS_TYPE_HID; printf("dap_init\n");
int size;
if (type == CMSIS_TYPE_HID) {
DEBUG_INFO("Using hid transfer\n");
if (hid_init()) if (hid_init())
return -1; return -1;
size = strlen(info->serial); int size = strlen(info->serial);
wchar_t serial[64] = {0}, *wc = serial; wchar_t serial[size + 1], *wc = serial;
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
*wc++ = info->serial[i]; *wc++ = info->serial[i];
*wc = 0; *wc = 0;
/* Blacklist devices that do not work with 513 byte report length /* Blacklist devices that do not wirk with 513 byte report length
* FIXME: Find a solution to decipher from the device. * FIXME: Find a solution to decipher from the device.
*/ */
if ((info->vid == 0x1fc9) && (info->pid == 0x0132)) { if ((info->vid == 0x1fc9) && (info->pid == 0x0132)) {
DEBUG_WARN("Blacklist\n"); DEBUG_WARN("Blacklist\n");
report_size = 64 + 1; report_size = 64 + 1;
} }
handle = hid_open(info->vid, info->pid, (serial[0]) ? serial : NULL); handle = hid_open(info->vid, info->pid, serial);
if (!handle) { if (!handle)
DEBUG_WARN("hid_open failed\n");
return -1; return -1;
}
} else if (type == CMSIS_TYPE_BULK) {
DEBUG_INFO("Using bulk transfer\n");
usb_handle = libusb_open_device_with_vid_pid(info->libusb_ctx, info->vid, info->pid);
if (!usb_handle) {
DEBUG_WARN("WARN: libusb_open_device_with_vid_pid() failed\n");
return -1;
}
if (libusb_claim_interface(usb_handle, info->interface_num) < 0) {
DEBUG_WARN("WARN: libusb_claim_interface() failed\n");
return -1;
}
in_ep = info->in_ep;
out_ep = info->out_ep;
}
dap_disconnect(); dap_disconnect();
size = dap_info(DAP_INFO_FW_VER, buffer, sizeof(buffer)); size = dap_info(DAP_INFO_CAPABILITIES, hid_buffer, sizeof(hid_buffer));
if (size) { dap_caps = hid_buffer[0];
DEBUG_INFO("Ver %s, ", buffer); DEBUG_INFO(" Cap (0x%2x): %s%s%s", hid_buffer[0],
int major = -1, minor = -1, sub = -1; (hid_buffer[0] & 1)? "SWD" : "",
if (sscanf((const char *)buffer, "%d.%d.%d", ((hid_buffer[0] & 3) == 3) ? "/" : "",
&major, &minor, &sub)) { (hid_buffer[0] & 2)? "JTAG" : "");
if (sub == -1) { if (hid_buffer[0] & 4)
if (minor >= 10) {
minor /= 10;
sub = 0;
}
}
has_swd_sequence = ((major > 1 ) || ((major > 0 ) && (minor > 1)));
}
}
size = dap_info(DAP_INFO_CAPABILITIES, buffer, sizeof(buffer));
dap_caps = buffer[0];
DEBUG_INFO("Cap (0x%2x): %s%s%s", dap_caps,
(dap_caps & 1)? "SWD" : "",
((dap_caps & 3) == 3) ? "/" : "",
(dap_caps & 2)? "JTAG" : "");
if (dap_caps & 4)
DEBUG_INFO(", SWO_UART"); DEBUG_INFO(", SWO_UART");
if (dap_caps & 8) if (hid_buffer[0] & 8)
DEBUG_INFO(", SWO_MANCHESTER"); DEBUG_INFO(", SWO_MANCHESTER");
if (dap_caps & 0x10) if (hid_buffer[0] & 0x10)
DEBUG_INFO(", Atomic Cmds"); DEBUG_INFO(", Atomic Cmds");
if (has_swd_sequence)
DEBUG_INFO(", DAP_SWD_Sequence");
DEBUG_INFO("\n"); DEBUG_INFO("\n");
return 0; return 0;
} }
void dap_srst_set_val(bool assert)
{
dap_reset_pin(!assert);
}
static void dap_dp_abort(ADIv5_DP_t *dp, uint32_t abort) static void dap_dp_abort(ADIv5_DP_t *dp, uint32_t abort)
{ {
/* DP Write to Reg 0.*/ /* DP Write to Reg 0.*/
@ -148,7 +94,6 @@ static void dap_dp_abort(ADIv5_DP_t *dp, uint32_t abort)
static uint32_t dap_dp_error(ADIv5_DP_t *dp) static uint32_t dap_dp_error(ADIv5_DP_t *dp)
{ {
/* Not used for SWD debugging, so no TARGETID switch needed!*/
uint32_t ctrlstat = dap_read_reg(dp, ADIV5_DP_CTRLSTAT); uint32_t ctrlstat = dap_read_reg(dp, ADIV5_DP_CTRLSTAT);
uint32_t err = ctrlstat & uint32_t err = ctrlstat &
(ADIV5_DP_CTRLSTAT_STICKYORUN | ADIV5_DP_CTRLSTAT_STICKYCMP | (ADIV5_DP_CTRLSTAT_STICKYORUN | ADIV5_DP_CTRLSTAT_STICKYCMP |
@ -184,24 +129,24 @@ static uint32_t dap_dp_low_access(struct ADIv5_DP_s *dp, uint8_t RnW,
static uint32_t dap_dp_read_reg(ADIv5_DP_t *dp, uint16_t addr) static uint32_t dap_dp_read_reg(ADIv5_DP_t *dp, uint16_t addr)
{ {
uint32_t res = dap_dp_low_access(dp, ADIV5_LOW_READ, addr, 0); uint32_t res;
if (addr & ADIV5_APnDP) {
dap_dp_low_access(dp, ADIV5_LOW_READ, addr, 0);
res = dap_dp_low_access(dp, ADIV5_LOW_READ,
ADIV5_DP_RDBUFF, 0);
} else {
res = dap_dp_low_access(dp, ADIV5_LOW_READ, addr, 0);
}
DEBUG_PROBE("dp_read %04x %08" PRIx32 "\n", addr, res); DEBUG_PROBE("dp_read %04x %08" PRIx32 "\n", addr, res);
return res; return res;
} }
void dap_exit_function(void) void dap_exit_function(void)
{ {
if (type == CMSIS_TYPE_HID) {
if (handle) { if (handle) {
dap_disconnect(); dap_disconnect();
hid_close(handle); hid_close(handle);
} }
} else if (type == CMSIS_TYPE_BULK) {
if (usb_handle) {
dap_disconnect();
libusb_close(usb_handle);
}
}
} }
int dbg_get_report_size(void) int dbg_get_report_size(void)
@ -213,56 +158,40 @@ int dbg_dap_cmd(uint8_t *data, int size, int rsize)
{ {
char cmd = data[0]; char cmd = data[0];
int res = -1; int res;
memset(buffer, 0xff, report_size + 1); memset(hid_buffer, 0xff, report_size + 1);
buffer[0] = 0x00; // Report ID?? hid_buffer[0] = 0x00; // Report ID??
memcpy(&buffer[1], data, rsize); memcpy(&hid_buffer[1], data, rsize);
DEBUG_WIRE("cmd : "); DEBUG_WIRE("cmd : ");
for(int i = 0; (i < 32) && (i < rsize + 1); i++) for(int i = 0; (i < 16) && (i < rsize + 1); i++)
DEBUG_WIRE("%02x.", buffer[i]); DEBUG_WIRE("%02x.", hid_buffer[i]);
DEBUG_WIRE("\n"); DEBUG_WIRE("\n");
if (type == CMSIS_TYPE_HID) { res = hid_write(handle, hid_buffer, rsize + 1);
res = hid_write(handle, buffer, 65);
if (res < 0) { if (res < 0) {
DEBUG_WARN( "Error: %ls\n", hid_error(handle)); DEBUG_WARN( "Error: %ls\n", hid_error(handle));
exit(-1); exit(-1);
} }
res = hid_read_timeout(handle, buffer, 65, 1000); if (size) {
res = hid_read(handle, hid_buffer, report_size + 1);
if (res < 0) { if (res < 0) {
DEBUG_WARN( "debugger read(): %ls\n", hid_error(handle)); DEBUG_WARN( "debugger read(): %ls\n", hid_error(handle));
exit(-1); exit(-1);
} else if (res == 0) {
DEBUG_WARN( "timeout\n");
exit(-1);
} }
} else if (type == CMSIS_TYPE_BULK) { if (size && hid_buffer[0] != cmd) {
int transferred = 0; DEBUG_WARN("cmd %02x invalid response received %02x\n",
cmd, hid_buffer[0]);
res = libusb_bulk_transfer(usb_handle, out_ep, data, rsize, &transferred, 500);
if (res < 0) {
DEBUG_WARN("OUT error: %d\n", res);
return res;
}
res = libusb_bulk_transfer(usb_handle, in_ep, buffer, report_size, &transferred, 500);
if (res < 0) {
DEBUG_WARN("IN error: %d\n", res);
return res;
}
res = transferred;
} }
res--;
memcpy(data, &hid_buffer[1], (size < res) ? size : res);
DEBUG_WIRE("cmd res:"); DEBUG_WIRE("cmd res:");
for(int i = 0; (i < 16) && (i < size + 1); i++) for(int i = 0; (i < 16) && (i < size + 4); i++)
DEBUG_WIRE("%02x.", buffer[i]); DEBUG_WIRE("%02x.", hid_buffer[i]);
DEBUG_WIRE("\n"); DEBUG_WIRE("\n");
if (buffer[0] != cmd) {
DEBUG_WARN("cmd %02x not implemented\n", cmd);
buffer[1] = 0xff /*DAP_ERROR*/;
} }
if (size)
memcpy(data, &buffer[1], (size < res) ? size : res);
return res; return res;
} }
#define ALIGNOF(x) (((x) & 3) == 0 ? ALIGN_WORD : \ #define ALIGNOF(x) (((x) & 3) == 0 ? ALIGN_WORD : \
@ -279,7 +208,7 @@ static void dap_mem_read(ADIv5_AP_t *ap, void *dest, uint32_t src, size_t len)
return dap_read_single(ap, dest, src, align); return dap_read_single(ap, dest, src, align);
/* One word transfer for every byte/halfword/word /* One word transfer for every byte/halfword/word
* Total number of bytes in transfer*/ * Total number of bytes in transfer*/
unsigned int max_size = ((dbg_get_report_size() - 6) >> (2 - align)) & ~3; unsigned int max_size = (dbg_get_report_size() - 5) >> (2 - align);
while (len) { while (len) {
dap_ap_mem_access_setup(ap, src, align); dap_ap_mem_access_setup(ap, src, align);
/* Calculate length until next access setup is needed */ /* Calculate length until next access setup is needed */
@ -316,7 +245,7 @@ static void dap_mem_write_sized(
dest, len, align, *(uint32_t *)src); dest, len, align, *(uint32_t *)src);
if (((unsigned)(1 << align)) == len) if (((unsigned)(1 << align)) == len)
return dap_write_single(ap, dest, src, align); return dap_write_single(ap, dest, src, align);
unsigned int max_size = ((dbg_get_report_size() - 6) >> (2 - align) & ~3); unsigned int max_size = (dbg_get_report_size() - 5) >> (2 - align);
while (len) { while (len) {
dap_ap_mem_access_setup(ap, dest, align); dap_ap_mem_access_setup(ap, dest, align);
unsigned int blocksize = (dest | 0x3ff) - dest + 1; unsigned int blocksize = (dest | 0x3ff) - dest + 1;
@ -342,6 +271,27 @@ static void dap_mem_write_sized(
DEBUG_WIRE("memwrite done\n"); DEBUG_WIRE("memwrite done\n");
} }
int dap_enter_debug_swd(ADIv5_DP_t *dp)
{
target_list_free();
if (!(dap_caps & DAP_CAP_SWD))
return -1;
mode = DAP_CAP_SWD;
dap_swj_clock(2000000);
dap_transfer_configure(2, 128, 128);
dap_swd_configure(0);
dap_connect(false);
dap_led(0, 1);
dap_reset_link(false);
dp->idcode = dap_read_idcode(dp);
dp->dp_read = dap_dp_read_reg;
dp->error = dap_dp_error;
dp->low_access = dap_dp_low_access;
dp->abort = dap_dp_abort; /* DP Write to Reg 0.*/
return 0;
}
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp) void dap_adiv5_dp_defaults(ADIv5_DP_t *dp)
{ {
if ((mode == DAP_CAP_JTAG) && dap_jtag_configure()) if ((mode == DAP_CAP_JTAG) && dap_jtag_configure())
@ -370,7 +320,7 @@ static void cmsis_dap_jtagtap_tdi_tdo_seq(uint8_t *DO, const uint8_t final_tms,
const uint8_t *DI, int ticks) const uint8_t *DI, int ticks)
{ {
dap_jtagtap_tdi_tdo_seq(DO, (final_tms), NULL, DI, ticks); dap_jtagtap_tdi_tdo_seq(DO, (final_tms), NULL, DI, ticks);
DEBUG_PROBE("jtagtap_tdi_tdo_seq %d, %02x-> %02x\n", ticks, DI[0], (DO)? DO[0] : 0); DEBUG_PROBE("jtagtap_tdi_tdo_seq %d, %02x-> %02x\n", ticks, DI[0], DO[0]);
} }
static void cmsis_dap_jtagtap_tdi_seq(const uint8_t final_tms, static void cmsis_dap_jtagtap_tdi_seq(const uint8_t final_tms,
@ -396,12 +346,13 @@ int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc)
mode = DAP_CAP_JTAG; mode = DAP_CAP_JTAG;
dap_disconnect(); dap_disconnect();
dap_connect(true); dap_connect(true);
dap_reset_link(true); dap_swj_clock(2000000);
jtag_proc->jtagtap_reset = cmsis_dap_jtagtap_reset; jtag_proc->jtagtap_reset = cmsis_dap_jtagtap_reset;
jtag_proc->jtagtap_next = cmsis_dap_jtagtap_next; jtag_proc->jtagtap_next = cmsis_dap_jtagtap_next;
jtag_proc->jtagtap_tms_seq = cmsis_dap_jtagtap_tms_seq; jtag_proc->jtagtap_tms_seq = cmsis_dap_jtagtap_tms_seq;
jtag_proc->jtagtap_tdi_tdo_seq = cmsis_dap_jtagtap_tdi_tdo_seq; jtag_proc->jtagtap_tdi_tdo_seq = cmsis_dap_jtagtap_tdi_tdo_seq;
jtag_proc->jtagtap_tdi_seq = cmsis_dap_jtagtap_tdi_seq; jtag_proc->jtagtap_tdi_seq = cmsis_dap_jtagtap_tdi_seq;
dap_reset_link(true);
return 0; return 0;
} }
@ -414,57 +365,3 @@ int dap_jtag_dp_init(ADIv5_DP_t *dp)
return true; return true;
} }
#define SWD_SEQUENCE_IN 0x80
#define DAP_SWD_SEQUENCE 0x1d
static bool dap_dp_low_write(ADIv5_DP_t *dp, uint16_t addr, const uint32_t data)
{
DEBUG_PROBE("dap_dp_low_write %08" PRIx32 "\n", data);
(void)dp;
unsigned int paket_request = make_packet_request(ADIV5_LOW_WRITE, addr);
uint8_t buf[32] = {
DAP_SWD_SEQUENCE,
5,
8,
paket_request,
4 + SWD_SEQUENCE_IN, /* one turn-around + read 3 bit ACK */
1, /* one bit turn around to drive SWDIO */
0,
32, /* write 32 bit data */
(data >> 0) & 0xff,
(data >> 8) & 0xff,
(data >> 16) & 0xff,
(data >> 24) & 0xff,
1, /* write parity biT */
__builtin_parity(data)
};
dbg_dap_cmd(buf, sizeof(buf), 14);
if (buf[0])
DEBUG_WARN("dap_dp_low_write failed\n");
uint32_t ack = (buf[1] >> 1) & 7;
return (ack != SWDP_ACK_OK);
}
int dap_swdptap_init(ADIv5_DP_t *dp)
{
if (!(dap_caps & DAP_CAP_SWD))
return 1;
mode = DAP_CAP_SWD;
dap_transfer_configure(2, 128, 128);
dap_swd_configure(0);
dap_connect(false);
dap_led(0, 1);
dap_reset_link(false);
if ((has_swd_sequence) && dap_sequence_test()) {
/* DAP_SWD_SEQUENCE does not do auto turnaround, use own!*/
dp->dp_low_write = dap_dp_low_write;
} else {
dp->dp_low_write = NULL;
}
dp->seq_out = dap_swdptap_seq_out;
dp->dp_read = dap_dp_read_reg;
/* For error() use the TARGETID switching firmware_swdp_error */
dp->low_access = dap_dp_low_access;
dp->abort = dap_dp_abort;
return 0;
}

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the Black Magic Debug project. * This file is part of the Black Magic Debug project.
* *
* Copyright (C) 2019 - 2021 Uwe Bonnes(bon@elektron.ikp.physik.tu-darmstadt.de) * Copyright (C) 2019 Uwe Bonnes
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -24,14 +24,11 @@
#if defined(CMSIS_DAP) #if defined(CMSIS_DAP)
int dap_init(bmp_info_t *info); int dap_init(bmp_info_t *info);
int dap_enter_debug_swd(ADIv5_DP_t *dp);
void dap_exit_function(void); void dap_exit_function(void);
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp); void dap_adiv5_dp_defaults(ADIv5_DP_t *dp);
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc); int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc);
int dap_swdptap_init(ADIv5_DP_t *dp);
int dap_jtag_dp_init(ADIv5_DP_t *dp); int dap_jtag_dp_init(ADIv5_DP_t *dp);
uint32_t dap_swj_clock(uint32_t clock);
void dap_swd_configure(uint8_t cfg);
void dap_srst_set_val(bool assert);
#else #else
int dap_init(bmp_info_t *info) int dap_init(bmp_info_t *info)
{ {
@ -39,17 +36,19 @@ int dap_init(bmp_info_t *info)
(void)info; (void)info;
return -1; return -1;
} }
# pragma GCC diagnostic push int dap_enter_debug_swd(ADIv5_DP_t *dp) {(void)dp; return -1;}
# pragma GCC diagnostic ignored "-Wunused-parameter" void dap_exit_function(void) {return;};
uint32_t dap_swj_clock(uint32_t clock) {return 0;} void dap_adiv5_dp_defaults(ADIv5_DP_t *dp) {(void)dp; return; }
void dap_exit_function(void) {}; int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc)
void dap_adiv5_dp_defaults(ADIv5_DP_t *dp) {}; {
int cmsis_dap_jtagtap_init(jtag_proc_t *jtag_proc) {return -1;} (void)jtag_proc;
int dap_swdptap_init(ADIv5_DP_t *dp) {return -1;} return -1;
int dap_jtag_dp_init(ADIv5_DP_t *dp) {return -1;} }
void dap_swd_configure(uint8_t cfg) {}; int dap_jtag_dp_init(ADIv5_DP_t *dp)
void dap_srst_set_val(bool assert) {}; {
# pragma GCC diagnostic pop (void)dp;
return -1;
}
#endif #endif

View File

@ -27,12 +27,12 @@
*/ */
/* Modified for Blackmagic Probe /* Modified for Blackmagic Probe
* Copyright (c) 2020-21 Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de * Copyright (c) 2020 Uwe Bonnes bon@elektron.ikp.physik.tu-darmstadt.de
*/ */
/*- Includes ----------------------------------------------------------------*/ /*- Includes ----------------------------------------------------------------*/
#include <general.h> #include <general.h>
#include "exception.h" #include <stdlib.h>
#include "dap.h" #include "dap.h"
#include "jtag_scan.h" #include "jtag_scan.h"
@ -57,7 +57,6 @@ enum
ID_DAP_JTAG_SEQUENCE = 0x14, ID_DAP_JTAG_SEQUENCE = 0x14,
ID_DAP_JTAG_CONFIGURE = 0x15, ID_DAP_JTAG_CONFIGURE = 0x15,
ID_DAP_JTAG_IDCODE = 0x16, ID_DAP_JTAG_IDCODE = 0x16,
ID_DAP_SWD_SEQUENCE = 0x1D,
}; };
enum enum
@ -198,33 +197,24 @@ void dap_connect(bool jtag)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void dap_disconnect(void) void dap_disconnect(void)
{ {
uint8_t buf[65]; uint8_t buf[1];
buf[0] = ID_DAP_DISCONNECT; buf[0] = ID_DAP_DISCONNECT;
dbg_dap_cmd(buf, sizeof(buf), 1); dbg_dap_cmd(buf, sizeof(buf), 1);
} }
static uint32_t swj_clock; //-----------------------------------------------------------------------------
/* Set/Get JTAG/SWD clock frequency void dap_swj_clock(uint32_t clock)
*
* With clock == 0, return last set value.
*/
uint32_t dap_swj_clock(uint32_t clock)
{ {
if (clock == 0)
return swj_clock;
uint8_t buf[5]; uint8_t buf[5];
buf[0] = ID_DAP_SWJ_CLOCK; buf[0] = ID_DAP_SWJ_CLOCK;
buf[1] = clock & 0xff; buf[1] = clock & 0xff;
buf[2] = (clock >> 8) & 0xff; buf[2] = (clock >> 8) & 0xff;
buf[3] = (clock >> 16) & 0xff; buf[3] = (clock >> 16) & 0xff;
buf[4] = (clock >> 24) & 0xff; buf[4] = (clock >> 24) & 0xff;
dbg_dap_cmd(buf, sizeof(buf), 5); dbg_dap_cmd(buf, sizeof(buf), 5);
if (buf[0])
DEBUG_WARN("dap_swj_clock failed\n");
else
swj_clock = clock;
return swj_clock;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -278,9 +268,9 @@ void dap_reset_pin(int state)
buf[1] = state ? DAP_SWJ_nRESET : 0; // Value buf[1] = state ? DAP_SWJ_nRESET : 0; // Value
buf[2] = DAP_SWJ_nRESET; // Select buf[2] = DAP_SWJ_nRESET; // Select
buf[3] = 0; // Wait buf[3] = 0; // Wait
buf[4] = 0; // Wait buf[4] = 0;
buf[5] = 0; // Wait buf[5] = 0;
buf[6] = 0; // Wait buf[6] = 0;
dbg_dap_cmd(buf, sizeof(buf), 7); dbg_dap_cmd(buf, sizeof(buf), 7);
} }
@ -324,22 +314,20 @@ static void dap_line_reset(void)
static uint32_t wait_word(uint8_t *buf, int size, int len, uint8_t *dp_fault) static uint32_t wait_word(uint8_t *buf, int size, int len, uint8_t *dp_fault)
{ {
uint8_t cmd_copy[len];
memcpy(cmd_copy, buf, len);
do { do {
memcpy(buf, cmd_copy, len);
dbg_dap_cmd(buf, size, len); dbg_dap_cmd(buf, size, len);
if (buf[1] < DAP_TRANSFER_WAIT) if (buf[1] < DAP_TRANSFER_WAIT)
break; break;
} while (buf[1] == DAP_TRANSFER_WAIT); } while (buf[1] == DAP_TRANSFER_WAIT);
if(buf[1] == SWDP_ACK_FAULT) { if (buf[1] > DAP_TRANSFER_WAIT) {
// DEBUG_WARN("dap_read_reg fault\n");
*dp_fault = 1; *dp_fault = 1;
return 0;
} }
if (buf[1] == DAP_TRANSFER_ERROR) {
if(buf[1] != SWDP_ACK_OK) DEBUG_WARN("dap_read_reg, protocoll error\n");
raise_exception(EXCEPTION_ERROR, "SWDP invalid ACK"); dap_line_reset();
}
uint32_t res = uint32_t res =
((uint32_t)buf[5] << 24) | ((uint32_t)buf[4] << 16) | ((uint32_t)buf[5] << 24) | ((uint32_t)buf[4] << 16) |
((uint32_t)buf[3] << 8) | (uint32_t)buf[2]; ((uint32_t)buf[3] << 8) | (uint32_t)buf[2];
@ -351,7 +339,8 @@ uint32_t dap_read_reg(ADIv5_DP_t *dp, uint8_t reg)
{ {
uint8_t buf[8]; uint8_t buf[8];
uint8_t dap_index = 0; uint8_t dap_index = 0;
dap_index = dp->dp_jd_index; if (dp->dev)
dap_index = dp->dev->dev;
buf[0] = ID_DAP_TRANSFER; buf[0] = ID_DAP_TRANSFER;
buf[1] = dap_index; buf[1] = dap_index;
buf[2] = 0x01; // Request size buf[2] = 0x01; // Request size
@ -369,7 +358,8 @@ void dap_write_reg(ADIv5_DP_t *dp, uint8_t reg, uint32_t data)
buf[0] = ID_DAP_TRANSFER; buf[0] = ID_DAP_TRANSFER;
uint8_t dap_index = 0; uint8_t dap_index = 0;
dap_index = dp->dp_jd_index; if (dp->dev)
dap_index = dp->dev->dev;
buf[1] = dap_index; buf[1] = dap_index;
buf[2] = 0x01; // Request size buf[2] = 0x01; // Request size
buf[3] = reg & ~DAP_TRANSFER_RnW;; buf[3] = reg & ~DAP_TRANSFER_RnW;;
@ -377,10 +367,7 @@ void dap_write_reg(ADIv5_DP_t *dp, uint8_t reg, uint32_t data)
buf[5] = (data >> 8) & 0xff; buf[5] = (data >> 8) & 0xff;
buf[6] = (data >> 16) & 0xff; buf[6] = (data >> 16) & 0xff;
buf[7] = (data >> 24) & 0xff; buf[7] = (data >> 24) & 0xff;
uint8_t cmd_copy[8];
memcpy(cmd_copy, buf, 8);
do { do {
memcpy(buf, cmd_copy, 8);
dbg_dap_cmd(buf, sizeof(buf), 8); dbg_dap_cmd(buf, sizeof(buf), 8);
if (buf[1] < DAP_TRANSFER_WAIT) if (buf[1] < DAP_TRANSFER_WAIT)
break; break;
@ -403,13 +390,14 @@ unsigned int dap_read_block(ADIv5_AP_t *ap, void *dest, uint32_t src,
uint8_t buf[1024]; uint8_t buf[1024];
unsigned int sz = len >> align; unsigned int sz = len >> align;
uint8_t dap_index = 0; uint8_t dap_index = 0;
dap_index = ap->dp->dp_jd_index; if (ap->dp->dev)
dap_index = ap->dp->dev->dev;
buf[0] = ID_DAP_TRANSFER_BLOCK; buf[0] = ID_DAP_TRANSFER_BLOCK;
buf[1] = dap_index; buf[1] = dap_index;
buf[2] = sz & 0xff; buf[2] = sz & 0xff;
buf[3] = (sz >> 8) & 0xff; buf[3] = (sz >> 8) & 0xff;
buf[4] = SWD_AP_DRW | DAP_TRANSFER_RnW; buf[4] = SWD_AP_DRW | DAP_TRANSFER_RnW;
dbg_dap_cmd(buf, 1023, 5); dbg_dap_cmd(buf, 1023, 5 + 1);
unsigned int transferred = buf[0] + (buf[1] << 8); unsigned int transferred = buf[0] + (buf[1] << 8);
if (buf[2] >= DAP_TRANSFER_FAULT) { if (buf[2] >= DAP_TRANSFER_FAULT) {
DEBUG_WARN("dap_read_block @ %08 "PRIx32 " fault -> line reset\n", src); DEBUG_WARN("dap_read_block @ %08 "PRIx32 " fault -> line reset\n", src);
@ -425,6 +413,7 @@ unsigned int dap_read_block(ADIv5_AP_t *ap, void *dest, uint32_t src,
dest = extract(dest, src, *p, align); dest = extract(dest, src, *p, align);
p++; p++;
src += (1 << align); src += (1 << align);
dest += (1 << align);
sz--; sz--;
} }
} }
@ -437,7 +426,8 @@ unsigned int dap_write_block(ADIv5_AP_t *ap, uint32_t dest, const void *src,
uint8_t buf[1024]; uint8_t buf[1024];
unsigned int sz = len >> align; unsigned int sz = len >> align;
uint8_t dap_index = 0; uint8_t dap_index = 0;
dap_index = ap->dp->dp_jd_index; if (ap->dp->dev)
dap_index = ap->dp->dev->dev;
buf[0] = ID_DAP_TRANSFER_BLOCK; buf[0] = ID_DAP_TRANSFER_BLOCK;
buf[1] = dap_index; buf[1] = dap_index;
buf[2] = sz & 0xff; buf[2] = sz & 0xff;
@ -537,7 +527,8 @@ static uint8_t *mem_access_setup(ADIv5_AP_t *ap, uint8_t *p,
break; break;
} }
uint8_t dap_index = 0; uint8_t dap_index = 0;
dap_index = ap->dp->dp_jd_index; if (ap->dp->dev)
dap_index = ap->dp->dev->dev;
*p++ = ID_DAP_TRANSFER; *p++ = ID_DAP_TRANSFER;
*p++ = dap_index; *p++ = dap_index;
*p++ = 3; /* Nr transfers */ *p++ = 3; /* Nr transfers */
@ -568,11 +559,12 @@ void dap_ap_mem_access_setup(ADIv5_AP_t *ap, uint32_t addr, enum align align)
uint32_t dap_ap_read(ADIv5_AP_t *ap, uint16_t addr) uint32_t dap_ap_read(ADIv5_AP_t *ap, uint16_t addr)
{ {
DEBUG_PROBE("dap_ap_read_start addr %x\n", addr); DEBUG_PROBE("dap_ap_read_start\n");
uint8_t buf[63], *p = buf; uint8_t buf[63], *p = buf;
buf[0] = ID_DAP_TRANSFER; buf[0] = ID_DAP_TRANSFER;
uint8_t dap_index = 0; uint8_t dap_index = 0;
dap_index = ap->dp->dp_jd_index; if (ap->dp->dev)
dap_index = ap->dp->dev->dev;
*p++ = ID_DAP_TRANSFER; *p++ = ID_DAP_TRANSFER;
*p++ = dap_index; *p++ = dap_index;
*p++ = 2; /* Nr transfers */ *p++ = 2; /* Nr transfers */
@ -584,9 +576,6 @@ uint32_t dap_ap_read(ADIv5_AP_t *ap, uint16_t addr)
*p++ = (addr & 0x0c) | DAP_TRANSFER_RnW | *p++ = (addr & 0x0c) | DAP_TRANSFER_RnW |
((addr & 0x100) ? DAP_TRANSFER_APnDP : 0); ((addr & 0x100) ? DAP_TRANSFER_APnDP : 0);
uint32_t res = wait_word(buf, 63, p - buf, &ap->dp->fault); uint32_t res = wait_word(buf, 63, p - buf, &ap->dp->fault);
if ((buf[0] != 2) || (buf[1] != 1)) {
DEBUG_WARN("dap_ap_read error %x\n", buf[1]);
}
return res; return res;
} }
@ -595,7 +584,8 @@ void dap_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value)
DEBUG_PROBE("dap_ap_write addr %04x value %08x\n", addr, value); DEBUG_PROBE("dap_ap_write addr %04x value %08x\n", addr, value);
uint8_t buf[63], *p = buf; uint8_t buf[63], *p = buf;
uint8_t dap_index = 0; uint8_t dap_index = 0;
dap_index = ap->dp->dp_jd_index; if (ap->dp->dev)
dap_index = ap->dp->dev->dev;
*p++ = ID_DAP_TRANSFER; *p++ = ID_DAP_TRANSFER;
*p++ = dap_index; *p++ = dap_index;
*p++ = 2; /* Nr transfers */ *p++ = 2; /* Nr transfers */
@ -610,9 +600,6 @@ void dap_ap_write(ADIv5_AP_t *ap, uint16_t addr, uint32_t value)
*p++ = (value >> 16) & 0xff; *p++ = (value >> 16) & 0xff;
*p++ = (value >> 24) & 0xff; *p++ = (value >> 24) & 0xff;
dbg_dap_cmd(buf, sizeof(buf), p - buf); dbg_dap_cmd(buf, sizeof(buf), p - buf);
if ((buf[0] != 2) || (buf[1] != 1)) {
DEBUG_WARN("dap_ap_write error %x\n", buf[1]);
}
} }
void dap_read_single(ADIv5_AP_t *ap, void *dest, uint32_t src, enum align align) void dap_read_single(ADIv5_AP_t *ap, void *dest, uint32_t src, enum align align)
@ -620,8 +607,7 @@ void dap_read_single(ADIv5_AP_t *ap, void *dest, uint32_t src, enum align align)
uint8_t buf[63]; uint8_t buf[63];
uint8_t *p = mem_access_setup(ap, buf, src, align); uint8_t *p = mem_access_setup(ap, buf, src, align);
*p++ = SWD_AP_DRW | DAP_TRANSFER_RnW; *p++ = SWD_AP_DRW | DAP_TRANSFER_RnW;
*p++ = SWD_DP_R_RDBUFF | DAP_TRANSFER_RnW; buf[2] = 4;
buf[2] = 5;
uint32_t tmp = wait_word(buf, 63, p - buf, &ap->dp->fault); uint32_t tmp = wait_word(buf, 63, p - buf, &ap->dp->fault);
dest = extract(dest, src, tmp, align); dest = extract(dest, src, tmp, align);
} }
@ -657,16 +643,15 @@ void dap_write_single(ADIv5_AP_t *ap, uint32_t dest, const void *src,
void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS, void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
const uint8_t *DI, int ticks) const uint8_t *DI, int ticks)
{ {
DEBUG_PROBE("dap_jtagtap_tdi_tdo_seq %s %d ticks\n",
(final_tms) ? "final" : "", ticks);
uint8_t buf[64]; uint8_t buf[64];
const uint8_t *din = DI;
uint8_t *dout = DO;
if (!TMS) { if (!TMS) {
int last_byte = last_byte = (ticks - 1) >> 3; int last_byte = 0;
int last_bit = (ticks - 1) & 7; int last_bit = 0;
if (final_tms) if (final_tms) {
last_byte = ticks >> 3;
last_bit = ticks & 7;
ticks --; ticks --;
}
while (ticks) { while (ticks) {
int transfers = ticks; int transfers = ticks;
if (transfers > 64) if (transfers > 64)
@ -674,12 +659,11 @@ void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
uint8_t *p = buf; uint8_t *p = buf;
*p++ = ID_DAP_JTAG_SEQUENCE; *p++ = ID_DAP_JTAG_SEQUENCE;
*p++ = 1; *p++ = 1;
*p++ = ((transfers == 64) ? 0 : transfers) | *p++ = transfers | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0);
((DO) ? DAP_JTAG_TDO_CAPTURE : 0);
int n_di_bytes = (transfers + 7) >> 3; int n_di_bytes = (transfers + 7) >> 3;
if (din) { if (DI) {
p = memcpy(p, din, n_di_bytes); p = memcpy(p, DI, n_di_bytes);
din += n_di_bytes; DI += n_di_bytes;
} else { } else {
p = memset(p, 0xff, n_di_bytes); p = memset(p, 0xff, n_di_bytes);
} }
@ -687,9 +671,9 @@ void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
dbg_dap_cmd(buf, sizeof(buf), p - buf); dbg_dap_cmd(buf, sizeof(buf), p - buf);
if (buf[0] != DAP_OK) if (buf[0] != DAP_OK)
DEBUG_WARN("dap_jtagtap_tdi_tdo_seq failed %02x\n", buf[0]); DEBUG_WARN("dap_jtagtap_tdi_tdo_seq failed %02x\n", buf[0]);
if (dout) { if (DO) {
memcpy(dout, &buf[1], (transfers + 7) >> 3); memcpy(DO, &buf[1], (transfers + 7) >> 3);
dout += (transfers + 7) >> 3; DO += (transfers + 7) >> 3;
} }
ticks -= transfers; ticks -= transfers;
} }
@ -697,8 +681,8 @@ void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
uint8_t *p = buf; uint8_t *p = buf;
*p++ = ID_DAP_JTAG_SEQUENCE; *p++ = ID_DAP_JTAG_SEQUENCE;
*p++ = 1; *p++ = 1;
*p++ = 1 | ((dout) ? DAP_JTAG_TDO_CAPTURE : 0) | DAP_JTAG_TMS; *p++ = 1 | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0) | DAP_JTAG_TMS;
if (din) { if (DI) {
*p++ = ((DI[last_byte] & (1 << last_bit)) ? 1 : 0); *p++ = ((DI[last_byte] & (1 << last_bit)) ? 1 : 0);
} else { } else {
*p++ = 0; *p++ = 0;
@ -706,7 +690,7 @@ void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
dbg_dap_cmd(buf, sizeof(buf), p - buf); dbg_dap_cmd(buf, sizeof(buf), p - buf);
if (buf[0] == DAP_ERROR) if (buf[0] == DAP_ERROR)
DEBUG_WARN("dap_jtagtap_tdi_tdo_seq failed %02x\n", buf[0]); DEBUG_WARN("dap_jtagtap_tdi_tdo_seq failed %02x\n", buf[0]);
if (dout) { if (DO) {
if (buf[1] & 1) if (buf[1] & 1)
DO[last_byte] |= (1 << last_bit); DO[last_byte] |= (1 << last_bit);
else else
@ -724,11 +708,11 @@ void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
*p++ = transfers; *p++ = transfers;
for (int i = 0; i < transfers; i++) { for (int i = 0; i < transfers; i++) {
*p++ = 1 | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0) | *p++ = 1 | ((DO) ? DAP_JTAG_TDO_CAPTURE : 0) |
((TMS[i >> 3] & (1 << (i & 7))) ? DAP_JTAG_TMS : 0); ((TMS[i >> 8] & (1 << (i & 7))) ? DAP_JTAG_TMS : 0);
if (DI) if (DI)
*p++ = (DI[i >> 3] & (1 << (i & 7))) ? 1 : 0; *p++ = (DI[i >> 8] & (1 << (i & 7))) ? 1 : 0;
else else
*p++ = 1; *p++ = 0x55;
} }
dbg_dap_cmd(buf, sizeof(buf), p - buf); dbg_dap_cmd(buf, sizeof(buf), p - buf);
if (buf[0] == DAP_ERROR) if (buf[0] == DAP_ERROR)
@ -736,9 +720,9 @@ void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
if (DO) { if (DO) {
for (int i = 0; i < transfers; i++) { for (int i = 0; i < transfers; i++) {
if (buf[i + 1]) if (buf[i + 1])
DO[i >> 3] |= (1 << (i & 7)); DO[i >> 8] |= (1 << (i & 7));
else else
DO[i >> 3] &= ~(1 << (i & 7)); DO[i >> 8] &= ~(1 << (i & 7));
} }
} }
ticks -= transfers; ticks -= transfers;
@ -764,86 +748,3 @@ int dap_jtag_configure(void)
DEBUG_WARN("dap_jtag_configure Failed %02x\n", buf[0]); DEBUG_WARN("dap_jtag_configure Failed %02x\n", buf[0]);
return 0; return 0;
} }
void dap_swdptap_seq_out(uint32_t MS, int ticks)
{
uint8_t buf[64] = {
ID_DAP_SWJ_SEQUENCE,
ticks,
(MS >> 0) & 0xff,
(MS >> 8) & 0xff,
(MS >> 16) & 0xff,
(MS >> 24) & 0xff
};
dbg_dap_cmd(buf, 64, 2 + ((ticks +7) >> 3));
if (buf[0])
DEBUG_WARN("dap_swdptap_seq_out error\n");
}
void dap_swdptap_seq_out_parity(uint32_t MS, int ticks)
{
uint8_t buf[] = {
ID_DAP_SWJ_SEQUENCE,
ticks + 1,
(MS >> 0) & 0xff,
(MS >> 8) & 0xff,
(MS >> 16) & 0xff,
(MS >> 24) & 0xff,
__builtin_parity(MS) & 1
};
dbg_dap_cmd(buf, 1, sizeof(buf));
if (buf[0])
DEBUG_WARN("dap_swdptap_seq_out error\n");
}
bool dap_sequence_test(void)
{
uint8_t buf[4] = {
ID_DAP_SWD_SEQUENCE,
0x1,
0x81, /* Read one bit */
0 /* one idle cycle */
};
dbg_dap_cmd(buf, sizeof(buf), 3);
return (buf[0] == DAP_OK);
}
#define SWD_SEQUENCE_IN 0x80
uint32_t dap_swdptap_seq_in(int ticks)
{
uint8_t buf[5] = {
ID_DAP_SWD_SEQUENCE,
1,
ticks + SWD_SEQUENCE_IN
};
dbg_dap_cmd(buf, 2 + ((ticks + 7) >> 3), 3);
uint32_t res = 0;
int len = (ticks + 7) >> 3;
while (len--) {
res <<= 8;
res += buf[len + 1];
}
return res;
}
bool dap_swdptap_seq_in_parity(uint32_t *ret, int ticks)
{
(void)ticks;
uint8_t buf[8] = {
ID_DAP_SWD_SEQUENCE,
1,
33 + SWD_SEQUENCE_IN,
};
dbg_dap_cmd(buf, 7, 4);
uint32_t res = 0;
int len = 4;
while (len--) {
res <<= 8;
res += buf[len + 1];
}
*ret = res;
unsigned int parity = __builtin_parity(res) & 1;
parity ^= (buf[5] % 1);
DEBUG_WARN("Res %08" PRIx32" %d\n", *ret, parity & 1);
return (!(parity & 1));
}

View File

@ -65,11 +65,11 @@ enum
void dap_led(int index, int state); void dap_led(int index, int state);
void dap_connect(bool jtag); void dap_connect(bool jtag);
void dap_disconnect(void); void dap_disconnect(void);
void dap_swj_clock(uint32_t clock);
void dap_transfer_configure(uint8_t idle, uint16_t count, uint16_t retry); void dap_transfer_configure(uint8_t idle, uint16_t count, uint16_t retry);
void dap_swd_configure(uint8_t cfg); void dap_swd_configure(uint8_t cfg);
int dap_info(int info, uint8_t *data, int size); int dap_info(int info, uint8_t *data, int size);
void dap_reset_target(void); void dap_reset_target(void);
void dap_srst_set_val(bool assert);
void dap_trst_reset(void); void dap_trst_reset(void);
void dap_reset_target_hw(int state); void dap_reset_target_hw(int state);
void dap_reset_pin(int state); void dap_reset_pin(int state);
@ -91,7 +91,4 @@ int dbg_dap_cmd(uint8_t *data, int size, int rsize);
void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS, void dap_jtagtap_tdi_tdo_seq(uint8_t *DO, bool final_tms, const uint8_t *TMS,
const uint8_t *DI, int ticks); const uint8_t *DI, int ticks);
int dap_jtag_configure(void); int dap_jtag_configure(void);
void dap_swdptap_seq_out(uint32_t MS, int ticks);
void dap_swdptap_seq_out_parity(uint32_t MS, int ticks);
bool dap_sequence_test(void);
#endif // _DAP_H_ #endif // _DAP_H_

View File

@ -20,6 +20,8 @@
*/ */
#include "general.h" #include "general.h"
#include "gdb_if.h" #include "gdb_if.h"
#include "version.h"
#include "platform.h"
#include "target.h" #include "target.h"
#include <assert.h> #include <assert.h>
@ -27,7 +29,6 @@
#include <sys/time.h> #include <sys/time.h>
#include "ftdi_bmp.h" #include "ftdi_bmp.h"
#include <ftdi.h>
struct ftdi_context *ftdic; struct ftdi_context *ftdic;
@ -123,8 +124,8 @@ cable_desc_t cable_desc[] = {
.init.ddr_low = PIN4, .init.ddr_low = PIN4,
.init.data_high = PIN4 | PIN3 | PIN2, .init.data_high = PIN4 | PIN3 | PIN2,
.init.ddr_high = PIN4 | PIN3 | PIN2 | PIN1 | PIN0, .init.ddr_high = PIN4 | PIN3 | PIN2 | PIN1 | PIN0,
.assert_srst.data_high = ~PIN3, .assert_srst.data_high = ~PIN2,
.deassert_srst.data_high = PIN3, .deassert_srst.data_high = PIN2,
.srst_get_port_cmd = GET_BITS_LOW, .srst_get_port_cmd = GET_BITS_LOW,
.srst_get_pin = PIN6, .srst_get_pin = PIN6,
.description = "FTDIJTAG", .description = "FTDIJTAG",
@ -269,7 +270,7 @@ int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
int err; int err;
cable_desc_t *cable = &cable_desc[0]; cable_desc_t *cable = &cable_desc[0];
for(; cable->name; cable++) { for(; cable->name; cable++) {
if (strncmp(cable->name, cl_opts->opt_cable, strlen(cable->name)) == 0) if (strcmp(cable->name, cl_opts->opt_cable) == 0)
break; break;
} }
@ -281,7 +282,7 @@ int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
active_cable = cable; active_cable = cable;
memcpy(&active_state, &active_cable->init, sizeof(data_desc_t)); memcpy(&active_state, &active_cable->init, sizeof(data_desc_t));
/* If swd_(read|write) is not given for the selected cable and /* If swd_(read|write) is not given for the selected cable and
the 'e' command line argument is give, assume resistor SWD the 'r' command line argument is give, assume resistor SWD
connection.*/ connection.*/
if (cl_opts->external_resistor_swd && if (cl_opts->external_resistor_swd &&
(active_cable->mpsse_swd_read.set_data_low == 0) && (active_cable->mpsse_swd_read.set_data_low == 0) &&
@ -340,27 +341,23 @@ int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
goto error_2; goto error_2;
} }
assert(ftdic != NULL); assert(ftdic != NULL);
#ifdef _Ftdi_Pragma
err = ftdi_tcioflush(ftdic);
#else
err = ftdi_usb_purge_buffers(ftdic); err = ftdi_usb_purge_buffers(ftdic);
#endif
if (err != 0) { if (err != 0) {
DEBUG_WARN("ftdi_tcioflush(ftdi_usb_purge_buffer): %d: %s\n", fprintf(stderr, "ftdi_usb_purge_buffer: %d: %s\n",
err, ftdi_get_error_string(ftdic)); err, ftdi_get_error_string(ftdic));
goto error_2; goto error_2;
} }
/* Reset MPSSE controller. */ /* Reset MPSSE controller. */
err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET); err = ftdi_set_bitmode(ftdic, 0, BITMODE_RESET);
if (err != 0) { if (err != 0) {
DEBUG_WARN("ftdi_set_bitmode: %d: %s\n", fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
err, ftdi_get_error_string(ftdic)); err, ftdi_get_error_string(ftdic));
goto error_2; goto error_2;
} }
/* Enable MPSSE controller. Pin directions are set later.*/ /* Enable MPSSE controller. Pin directions are set later.*/
err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE); err = ftdi_set_bitmode(ftdic, 0, BITMODE_MPSSE);
if (err != 0) { if (err != 0) {
DEBUG_WARN("ftdi_set_bitmode: %d: %s\n", fprintf(stderr, "ftdi_set_bitmode: %d: %s\n",
err, ftdi_get_error_string(ftdic)); err, ftdi_get_error_string(ftdic));
goto error_2; goto error_2;
} }
@ -375,18 +372,6 @@ int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info)
} }
int index = 0; int index = 0;
ftdi_init[index++]= LOOPBACK_END; /* FT2232D gets upset otherwise*/ ftdi_init[index++]= LOOPBACK_END; /* FT2232D gets upset otherwise*/
switch(ftdic->type) {
case TYPE_2232H:
case TYPE_4232H:
case TYPE_232H:
ftdi_init[index++] = DIS_DIV_5;
break;
case TYPE_2232C:
break;
default:
DEBUG_WARN("FTDI Chip has no MPSSE\n");
goto error_2;
}
ftdi_init[index++]= TCK_DIVISOR; ftdi_init[index++]= TCK_DIVISOR;
/* Use CLK/2 for about 50 % SWDCLK duty cycle on FT2232c.*/ /* Use CLK/2 for about 50 % SWDCLK duty cycle on FT2232c.*/
ftdi_init[index++]= 1; ftdi_init[index++]= 1;
@ -421,11 +406,11 @@ static void libftdi_set_data(data_desc_t* data)
if ((data->data_low) || (data->ddr_low)) { if ((data->data_low) || (data->ddr_low)) {
if (data->data_low > 0) if (data->data_low > 0)
active_state.data_low |= (data->data_low & 0xff); active_state.data_low |= (data->data_low & 0xff);
else if (data->data_low < 0) else
active_state.data_low &= (data->data_low & 0xff); active_state.data_low &= (data->data_low & 0xff);
if (data->ddr_low > 0) if (data->ddr_low > 0)
active_state.ddr_low |= (data->ddr_low & 0xff); active_state.ddr_low |= (data->ddr_low & 0xff);
else if (data->ddr_low < 0) else
active_state.ddr_low &= (data->ddr_low & 0xff); active_state.ddr_low &= (data->ddr_low & 0xff);
cmd[index++] = SET_BITS_LOW; cmd[index++] = SET_BITS_LOW;
cmd[index++] = active_state.data_low; cmd[index++] = active_state.data_low;
@ -434,11 +419,11 @@ static void libftdi_set_data(data_desc_t* data)
if ((data->data_high) || (data->ddr_high)) { if ((data->data_high) || (data->ddr_high)) {
if (data->data_high > 0) if (data->data_high > 0)
active_state.data_high |= (data->data_high & 0xff); active_state.data_high |= (data->data_high & 0xff);
else if (data->data_high < 0) else
active_state.data_high &= (data->data_high & 0xff); active_state.data_high &= (data->data_high & 0xff);
if (data->ddr_high > 0) if (data->ddr_high > 0)
active_state.ddr_high |= (data->ddr_high & 0xff); active_state.ddr_high |= (data->ddr_high & 0xff);
else if (data->ddr_high < 0) else
active_state.ddr_high &= (data->ddr_high & 0xff); active_state.ddr_high &= (data->ddr_high & 0xff);
cmd[index++] = SET_BITS_HIGH; cmd[index++] = SET_BITS_HIGH;
cmd[index++] = active_state.data_high; cmd[index++] = active_state.data_high;
@ -552,8 +537,7 @@ void libftdi_jtagtap_tdi_tdo_seq(
if(!ticks) return; if(!ticks) return;
if (!DI && !DO) return; if (!DI && !DO) return;
DEBUG_WIRE("libftdi_jtagtap_tdi_tdo_seq %s ticks: %d\n", // printf("ticks: %d\n", ticks);
(DI && DO) ? "read/write" : ((DI) ? "write" : "read"), ticks);
if(final_tms) ticks--; if(final_tms) ticks--;
rticks = ticks & 7; rticks = ticks & 7;
ticks >>= 3; ticks >>= 3;
@ -583,7 +567,7 @@ void libftdi_jtagtap_tdi_tdo_seq(
MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG; MPSSE_LSB | MPSSE_BITMODE | MPSSE_WRITE_NEG;
data[index++] = 0; data[index++] = 0;
if (DI) if (DI)
data[index++] = (DI[ticks] & (1 << rticks)) ? 0x81 : 0x01; data[index++] = (DI[ticks]) >> rticks?0x81 : 0x01;
} }
if (index) if (index)
libftdi_buffer_write(data, index); libftdi_buffer_write(data, index);
@ -594,6 +578,7 @@ void libftdi_jtagtap_tdi_tdo_seq(
if(final_tms) rsize--; if(final_tms) rsize--;
while(rsize--) { while(rsize--) {
/*if(rsize) printf("%02X ", tmp[index]);*/
*DO++ = tmp[index++]; *DO++ = tmp[index++];
} }
if (rticks == 0) if (rticks == 0)
@ -606,6 +591,7 @@ void libftdi_jtagtap_tdi_tdo_seq(
if(rticks) { if(rticks) {
*DO >>= (8-rticks); *DO >>= (8-rticks);
} }
/*printf("%02X\n", *DO);*/
} }
} }
@ -628,34 +614,3 @@ const char *libftdi_target_voltage(void)
} }
return NULL; return NULL;
} }
static uint16_t divisor;
void libftdi_max_frequency_set(uint32_t freq)
{
uint32_t clock;
if (ftdic->type == TYPE_2232C)
clock = 12 * 1000 * 1000;
else
/* Undivided clock set during startup*/
clock = 60 * 1000 * 1000;
uint32_t div = (clock + 2 * freq - 1)/ freq;
if ((div < 4) && (ftdic->type = TYPE_2232C))
div = 4; /* Avoid bad unsymetrict FT2232C clock at 6 MHz*/
divisor = div / 2 - 1;
uint8_t buf[3];
buf[0] = TCK_DIVISOR;
buf[1] = divisor & 0xff;
buf[2] = (divisor >> 8) & 0xff;
libftdi_buffer_write(buf, 3);
}
uint32_t libftdi_max_frequency_get(void)
{
uint32_t clock;
if (ftdic->type == TYPE_2232C)
clock = 12 * 1000 * 1000;
else
/* Undivided clock set during startup*/
clock = 60 * 1000 * 1000;
return clock/ ( 2 *(divisor + 1));
}

View File

@ -23,10 +23,9 @@
#define __FTDI_BMP_H #define __FTDI_BMP_H
#include "cl_utils.h" #include "cl_utils.h"
#include "swdptap.h"
#include "jtagtap.h" #include "jtagtap.h"
#include "bmp_hosted.h"
typedef struct data_desc_s { typedef struct data_desc_s {
int16_t data_low; int16_t data_low;
int16_t ddr_low; int16_t ddr_low;
@ -99,33 +98,14 @@ typedef struct cable_desc_s {
char * name; char * name;
}cable_desc_t; }cable_desc_t;
#if HOSTED_BMP_ONLY == 1
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info) {return -1;};
int libftdi_swdptap_init(ADIv5_DP_t *dp) {return -1;};
int libftdi_jtagtap_init(jtag_proc_t *jtag_proc) {return 0;};
void libftdi_buffer_flush(void) {};
int libftdi_buffer_write(const uint8_t *data, int size) {return size;};
int libftdi_buffer_read(uint8_t *data, int size) {return size;};
const char *libftdi_target_voltage(void) {return "ERROR";};
void libftdi_jtagtap_tdi_tdo_seq(
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks) {};
bool libftdi_swd_possible(bool *do_mpsse, bool *direct_bb_swd) {return false;};
void libftdi_max_frequency_set(uint32_t freq) {};
uint32_t libftdi_max_frequency_get(void) {return 0;};
void libftdi_srst_set_val(bool assert){};
bool libftdi_srst_get_val(void) { return false;};
# pragma GCC diagnostic pop
#else
#include <ftdi.h>
extern cable_desc_t cable_desc[]; extern cable_desc_t cable_desc[];
extern cable_desc_t *active_cable; extern cable_desc_t *active_cable;
extern struct ftdi_context *ftdic; extern struct ftdi_context *ftdic;
extern data_desc_t active_state; extern data_desc_t active_state;
int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info); int ftdi_bmp_init(BMP_CL_OPTIONS_t *cl_opts, bmp_info_t *info);
int libftdi_swdptap_init(ADIv5_DP_t *dp);
int libftdi_swdptap_init(swd_proc_t *swd_proc);
int libftdi_jtagtap_init(jtag_proc_t *jtag_proc); int libftdi_jtagtap_init(jtag_proc_t *jtag_proc);
void libftdi_buffer_flush(void); void libftdi_buffer_flush(void);
int libftdi_buffer_write(const uint8_t *data, int size); int libftdi_buffer_write(const uint8_t *data, int size);
@ -134,11 +114,6 @@ const char *libftdi_target_voltage(void);
void libftdi_jtagtap_tdi_tdo_seq( void libftdi_jtagtap_tdi_tdo_seq(
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks); uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks);
bool libftdi_swd_possible(bool *do_mpsse, bool *direct_bb_swd); bool libftdi_swd_possible(bool *do_mpsse, bool *direct_bb_swd);
void libftdi_max_frequency_set(uint32_t freq);
uint32_t libftdi_max_frequency_get(void);
void libftdi_srst_set_val(bool assert);
bool libftdi_srst_get_val(void);
#endif
#define MPSSE_SK 1 #define MPSSE_SK 1
#define PIN0 1 #define PIN0 1

View File

@ -38,21 +38,15 @@
/* Only two devices PIDS tested so long */ /* Only two devices PIDS tested so long */
#define USB_VID_SEGGER_0101 0x0101 #define USB_VID_SEGGER_0101 0x0101
#define USB_VID_SEGGER_0105 0x0105 #define USB_VID_SEGGER_0105 0x0105
#define USB_VID_SEGGER_1020 0x1020
static uint32_t emu_caps;
static uint32_t emu_speed_kHz;
static uint16_t emu_min_divisor;
static uint16_t emu_current_divisor;
static void jlink_print_caps(bmp_info_t *info) static void jlink_print_caps(bmp_info_t *info)
{ {
uint8_t cmd[1] = {CMD_GET_CAPS}; uint8_t cmd[1] = {CMD_GET_CAPS};
uint8_t res[4]; uint8_t res[4];
send_recv(info->usb_link, cmd, 1, res, sizeof(res)); send_recv(info->usb_link, cmd, 1, res, sizeof(res));
emu_caps = res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24); uint32_t caps = res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24);
DEBUG_INFO("Caps %" PRIx32 "\n", emu_caps); DEBUG_INFO("Caps %" PRIx32 "\n", caps);
if (emu_caps & JLINK_CAP_GET_HW_VERSION) { if (caps & JLINK_CAP_GET_HW_VERSION) {
uint8_t cmd[1] = {CMD_GET_HW_VERSION}; uint8_t cmd[1] = {CMD_GET_HW_VERSION};
send_recv(info->usb_link, cmd, 1, NULL, 0); send_recv(info->usb_link, cmd, 1, NULL, 0);
send_recv(info->usb_link, NULL, 0, res, sizeof(res)); send_recv(info->usb_link, NULL, 0, res, sizeof(res));
@ -62,15 +56,13 @@ static void jlink_print_caps(bmp_info_t *info)
} }
static void jlink_print_speed(bmp_info_t *info) static void jlink_print_speed(bmp_info_t *info)
{ {
uint8_t cmd[1] = {CMD_GET_SPEEDS}; uint8_t cmd[1] = {CMD_GET_SPEED};
uint8_t res[6]; uint8_t res[6];
send_recv(info->usb_link, cmd, 1, res, sizeof(res)); send_recv(info->usb_link, cmd, 1, res, sizeof(res));
emu_speed_kHz = (res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24)) / uint32_t speed = res[0] | (res[1] << 8) | (res[2] << 16) | (res[3] << 24);
1000; double freq_mhz = speed / 1000000.0;
emu_min_divisor = res[4] | (res[5] << 8); uint16_t divisor = res[4] | (res[5] << 8);
DEBUG_INFO("Emulator speed %d kHz, Mindiv %d%s\n", emu_speed_kHz, DEBUG_INFO("Emulator speed %3.1f MHz, Mindiv %d\n", freq_mhz, divisor);
emu_min_divisor,
(emu_caps & JLINK_CAP_GET_SPEEDS) ? "" : ", fixed");
} }
static void jlink_print_version(bmp_info_t *info) static void jlink_print_version(bmp_info_t *info)
@ -98,15 +90,15 @@ static void jlink_print_interfaces(bmp_info_t *info)
DEBUG_INFO(", %s available\n", DEBUG_INFO(", %s available\n",
(other_interface == JLINK_IF_SWD) ? "SWD": "JTAG"); (other_interface == JLINK_IF_SWD) ? "SWD": "JTAG");
else else
DEBUG_INFO(", %s not available\n", DEBUG_WARN(", %s not available\n",
((res[0] + 1) == JLINK_IF_SWD) ? "JTAG": "SWD"); ((res[0] + 1) == JLINK_IF_SWD) ? "JTAG": "SWD");
} }
static void jlink_info(bmp_info_t *info) static void jlink_info(bmp_info_t *info)
{ {
jlink_print_version(info); jlink_print_version(info);
jlink_print_caps(info);
jlink_print_speed(info); jlink_print_speed(info);
jlink_print_caps(info);
jlink_print_interfaces(info); jlink_print_interfaces(info);
} }
@ -183,8 +175,7 @@ int jlink_init(bmp_info_t *info)
if (desc.idVendor != USB_PID_SEGGER) if (desc.idVendor != USB_PID_SEGGER)
continue; continue;
if ((desc.idProduct != USB_VID_SEGGER_0101) && if ((desc.idProduct != USB_VID_SEGGER_0101) &&
(desc.idProduct != USB_VID_SEGGER_0105) && (desc.idProduct != USB_VID_SEGGER_0105))
(desc.idProduct != USB_VID_SEGGER_1020))
continue; continue;
int res = libusb_open(dev, &jl->ul_libusb_device_handle); int res = libusb_open(dev, &jl->ul_libusb_device_handle);
if (res != LIBUSB_SUCCESS) if (res != LIBUSB_SUCCESS)
@ -245,27 +236,3 @@ bool jlink_srst_get_val(bmp_info_t *info) {
send_recv(info->usb_link, cmd, 1, res, sizeof(res)); send_recv(info->usb_link, cmd, 1, res, sizeof(res));
return !(res[6]); return !(res[6]);
} }
void jlink_max_frequency_set(bmp_info_t *info, uint32_t freq)
{
if (!(emu_caps & JLINK_CAP_GET_SPEEDS))
return;
if (!info->is_jtag)
return;
uint16_t freq_kHz = freq /1000;
uint16_t divisor = (emu_speed_kHz + freq_kHz - 1) / freq_kHz;
if (divisor < emu_min_divisor)
divisor = emu_min_divisor;
emu_current_divisor = divisor;
uint16_t speed_kHz = emu_speed_kHz / divisor;
uint8_t cmd[3] = {CMD_SET_SPEED, speed_kHz & 0xff, speed_kHz >> 8};
DEBUG_WARN("Set Speed %d\n", speed_kHz);
send_recv(info->usb_link, cmd, 3, NULL, 0);
}
uint32_t jlink_max_frequency_get(bmp_info_t *info)
{
if ((emu_caps & JLINK_CAP_GET_SPEEDS) && (info->is_jtag))
return (emu_speed_kHz * 1000L)/ emu_current_divisor;
return FREQ_FIXED;
}

View File

@ -19,14 +19,12 @@
#if !defined(__JLINK_H_) #if !defined(__JLINK_H_)
#define __JLINK_H_ #define __JLINK_H_
#include "bmp_hosted.h"
#include "jtagtap.h" #include "jtagtap.h"
/** @cond PRIVATE */ /** @cond PRIVATE */
#define CMD_GET_VERSION 0x01 #define CMD_GET_VERSION 0x01
#define CMD_SET_SPEED 0x05
#define CMD_GET_HW_STATUS 0x07 #define CMD_GET_HW_STATUS 0x07
#define CMD_GET_SPEEDS 0xc0 #define CMD_GET_SPEED 0xc0
#define CMD_GET_SELECT_IF 0xc7 #define CMD_GET_SELECT_IF 0xc7
#define CMD_HW_JTAG3 0xcf #define CMD_HW_JTAG3 0xcf
#define CMD_HW_RESET0 0xdc #define CMD_HW_RESET0 0xdc
@ -38,63 +36,13 @@
#define JLINK_IF_GET_ACTIVE 0xfe #define JLINK_IF_GET_ACTIVE 0xfe
#define JLINK_IF_GET_AVAILABLE 0xff #define JLINK_IF_GET_AVAILABLE 0xff
#define JLINK_CAP_GET_SPEEDS (1 << 9) #define JLINK_CAP_GET_HW_VERSION 2
#define JLINK_CAP_GET_HW_VERSION (1 << 1)
#define JLINK_IF_JTAG 1 #define JLINK_IF_JTAG 1
#define JLINK_IF_SWD 2 #define JLINK_IF_SWD 2
#define SELECT_IF_JTAG 0 #define SELECT_IF_JTAG 0
#define SELECT_IF_SWD 1 #define SELECT_IF_SWD 1
#if HOSTED_BMP_ONLY == 1
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
int jlink_init(bmp_info_t *info) {return -1;};
int jlink_swdp_scan(bmp_info_t *info) {return 0;};
int jlink_jtagtap_init(bmp_info_t *info, jtag_proc_t *jtag_proc) {return 0;};
const char *jlink_target_voltage(bmp_info_t *info) {return "ERROR";};
void jlink_srst_set_val(bmp_info_t *info, bool assert) {};
bool jlink_srst_get_val(bmp_info_t *info) {return true;};
void jlink_max_frequency_set(bmp_info_t *info, uint32_t freq) {};
uint32_t jlink_max_frequency_get(bmp_info_t *info) {return 0;};
# pragma GCC diagnostic pop
#else
/** Device capabilities. (from openocd*/
enum jaylink_device_capability {
/** Device supports retrieval of the hardware version. */
JAYLINK_DEV_CAP_GET_HW_VERSION = 1,
/** Device supports adaptive clocking. */
JAYLINK_DEV_CAP_ADAPTIVE_CLOCKING = 3,
/** Device supports reading configuration data. */
JAYLINK_DEV_CAP_READ_CONFIG = 4,
/** Device supports writing configuration data. */
JAYLINK_DEV_CAP_WRITE_CONFIG = 5,
/** Device supports retrieval of target interface speeds. */
JAYLINK_DEV_CAP_GET_SPEEDS = 9,
/** Device supports retrieval of free memory size. */
JAYLINK_DEV_CAP_GET_FREE_MEMORY = 11,
/** Device supports retrieval of hardware information. */
JAYLINK_DEV_CAP_GET_HW_INFO = 12,
/** Device supports the setting of the target power supply. */
JAYLINK_DEV_CAP_SET_TARGET_POWER = 13,
/** Device supports target interface selection. */
JAYLINK_DEV_CAP_SELECT_TIF = 17,
/** Device supports retrieval of counter values. */
JAYLINK_DEV_CAP_GET_COUNTERS = 19,
/** Device supports capturing of SWO trace data. */
JAYLINK_DEV_CAP_SWO = 23,
/** Device supports file I/O operations. */
JAYLINK_DEV_CAP_FILE_IO = 26,
/** Device supports registration of connections. */
JAYLINK_DEV_CAP_REGISTER = 27,
/** Device supports retrieval of extended capabilities. */
JAYLINK_DEV_CAP_GET_EXT_CAPS = 31,
/** Device supports EMUCOM. */
JAYLINK_DEV_CAP_EMUCOM = 33,
/** Device supports ethernet connectivity. */
JAYLINK_DEV_CAP_ETHERNET = 38
};
int jlink_init(bmp_info_t *info); int jlink_init(bmp_info_t *info);
int jlink_swdp_scan(bmp_info_t *info); int jlink_swdp_scan(bmp_info_t *info);
@ -102,7 +50,4 @@ int jlink_jtagtap_init(bmp_info_t *info, jtag_proc_t *jtag_proc);
const char *jlink_target_voltage(bmp_info_t *info); const char *jlink_target_voltage(bmp_info_t *info);
void jlink_srst_set_val(bmp_info_t *info, bool assert); void jlink_srst_set_val(bmp_info_t *info, bool assert);
bool jlink_srst_get_val(bmp_info_t *info); bool jlink_srst_get_val(bmp_info_t *info);
void jlink_max_frequency_set(bmp_info_t *info, uint32_t freq);
uint32_t jlink_max_frequency_get(bmp_info_t *info);
#endif
#endif #endif

View File

@ -3,7 +3,7 @@
* *
* Copyright (C) 2011 Black Sphere Technologies Ltd. * Copyright (C) 2011 Black Sphere Technologies Ltd.
* Written by Gareth McMullin <gareth@blacksphere.co.nz> * Written by Gareth McMullin <gareth@blacksphere.co.nz>
* Copyright (C) 2019 - 2021 Uwe Bonnes * Copyright (C) 2019 - 2020 Uwe Bonnes
* (bon@elektron.ikp.physik.tu-darmstadt.de) * (bon@elektron.ikp.physik.tu-darmstadt.de)
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -103,7 +103,7 @@ static int line_reset(bmp_info_t *info)
return 0; return 0;
} }
static int jlink_swdptap_init(bmp_info_t *info) static int swdptap_init(bmp_info_t *info)
{ {
uint8_t cmd[2] = {CMD_GET_SELECT_IF, JLINK_IF_GET_AVAILABLE}; uint8_t cmd[2] = {CMD_GET_SELECT_IF, JLINK_IF_GET_AVAILABLE};
uint8_t res[4]; uint8_t res[4];
@ -113,14 +113,20 @@ static int jlink_swdptap_init(bmp_info_t *info)
cmd[1] = SELECT_IF_SWD; cmd[1] = SELECT_IF_SWD;
send_recv(info->usb_link, cmd, 2, res, sizeof(res)); send_recv(info->usb_link, cmd, 2, res, sizeof(res));
platform_delay(10); platform_delay(10);
/* SWD speed is fixed. Do not set it here*/ /* Set speed 256 kHz*/
unsigned int speed = 2000;
uint8_t jtag_speed[3] = {5, speed & 0xff, speed >> 8};
send_recv(info->usb_link, jtag_speed, 3, NULL, 0);
return 0; return 0;
} }
int jlink_swdp_scan(bmp_info_t *info) int jlink_swdp_scan(bmp_info_t *info)
{ {
jlink_swdptap_init(info); swdptap_init(info);
target_list_free(); target_list_free();
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
if (!dp) /* calloc failed: heap exhaustion */
return 0;
uint8_t cmd[44]; uint8_t cmd[44];
cmd[0] = CMD_HW_JTAG3; cmd[0] = CMD_HW_JTAG3;
cmd[1] = 0; cmd[1] = 0;
@ -172,18 +178,7 @@ int jlink_swdp_scan(bmp_info_t *info)
DEBUG_WARN( "Line reset failed\n"); DEBUG_WARN( "Line reset failed\n");
return 0; return 0;
} }
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
if (!dp) /* calloc failed: heap exhaustion */
return 0;
volatile struct exception e;
TRY_CATCH (e, EXCEPTION_ALL) {
dp->idcode = jlink_adiv5_swdp_low_access(dp, 1, ADIV5_DP_IDCODE, 0); dp->idcode = jlink_adiv5_swdp_low_access(dp, 1, ADIV5_DP_IDCODE, 0);
}
if (e.type) {
DEBUG_WARN("DP not responding for IDCODE! Reset stuck low?\n");
free(dp);
return 0;
}
dp->dp_read = jlink_adiv5_swdp_read; dp->dp_read = jlink_adiv5_swdp_read;
dp->error = jlink_adiv5_swdp_error; dp->error = jlink_adiv5_swdp_error;
dp->low_access = jlink_adiv5_swdp_low_access; dp->low_access = jlink_adiv5_swdp_low_access;
@ -252,26 +247,20 @@ static uint32_t jlink_adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
uint8_t res[8]; uint8_t res[8];
cmd[0] = CMD_HW_JTAG3; cmd[0] = CMD_HW_JTAG3;
cmd[1] = 0; cmd[1] = 0;
/* It seems, JLINK samples read data at end of previous clock. cmd[2] = 13;
* So target data read must start at the 12'th clock, while
* write starts as expected at the 14'th clock (8 cmd, 3 response,
* 2 turn around.
*/
cmd[2] = (RnW) ? 11 : 13;
cmd[3] = 0; cmd[3] = 0;
cmd[4] = 0xff; /* 8 bits command OUT */ cmd[4] = 0xff;
cmd[5] = 0xf0; /* one IN bit to turn around to read, read 2 cmd[5] = 0xe3;
(read) or 3 (write) IN bits for response and cmd[6] = request << 2;
and one OUT bit to turn around to write on write*/ cmd[7] = request >> 6;
cmd[6] = request;
cmd[7] = 0x00;
platform_timeout_set(&timeout, 2000); platform_timeout_set(&timeout, 2000);
do { do {
send_recv(info.usb_link, cmd, 8, res, 2); send_recv(info.usb_link, cmd, 8, res, 2);
send_recv(info.usb_link, NULL, 0, res + 2 , 1); send_recv(info.usb_link, NULL, 0, res, 1);
if (res[2] != 0) if (res[0] != 0)
raise_exception(EXCEPTION_ERROR, "Low access setup failed"); raise_exception(EXCEPTION_ERROR, "Low access setup failed");
ack = res[1] & 7; ack = res[1] >> 2;
ack &= 7;
} while (ack == SWDP_ACK_WAIT && !platform_timeout_is_expired(&timeout)); } while (ack == SWDP_ACK_WAIT && !platform_timeout_is_expired(&timeout));
if (ack == SWDP_ACK_WAIT) if (ack == SWDP_ACK_WAIT)
raise_exception(EXCEPTION_TIMEOUT, "SWDP ACK timeout"); raise_exception(EXCEPTION_TIMEOUT, "SWDP ACK timeout");
@ -285,15 +274,17 @@ static uint32_t jlink_adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
if(ack != SWDP_ACK_OK) { if(ack != SWDP_ACK_OK) {
if (cl_debuglevel & BMP_DEBUG_TARGET) if (cl_debuglevel & BMP_DEBUG_TARGET)
DEBUG_WARN( "Protocol %d\n", ack); DEBUG_WARN( "Protocol\n");
line_reset(&info); line_reset(&info);
return 0; return 0;
} }
/* Always append 8 idle cycle (SWDIO = 0)!*/ cmd[3] = 0;
/* Always prepend an idle cycle (SWDIO = 0)!*/
if(RnW) { if(RnW) {
memset(cmd + 4, 0, 10); memset(cmd + 4, 0, 10);
cmd[2] = 33 + 2; /* 2 idle cycles */ cmd[2] = 34;
cmd[8] = 0xfe; cmd[8] = 0xfe;
cmd[13] = 0;
send_recv(info.usb_link, cmd, 14, res, 5); send_recv(info.usb_link, cmd, 14, res, 5);
send_recv(info.usb_link, NULL, 0, res + 5, 1); send_recv(info.usb_link, NULL, 0, res + 5, 1);
if (res[5] != 0) if (res[5] != 0)
@ -304,16 +295,16 @@ static uint32_t jlink_adiv5_swdp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
if (bit_count & 1) /* Give up on parity error */ if (bit_count & 1) /* Give up on parity error */
raise_exception(EXCEPTION_ERROR, "SWDP Parity error"); raise_exception(EXCEPTION_ERROR, "SWDP Parity error");
} else { } else {
cmd[2] = 33 + 8; /* 8 idle cycle to move data through SW-DP */ cmd[2] = 35;
memset(cmd + 4, 0xff, 6); memset(cmd + 4, 0xff, 5);
cmd[10] = ((value >> 0) & 0xff); cmd[ 9] = ((value << 2) & 0xfc);
cmd[11] = ((value >> 8) & 0xff); cmd[10] = ((value >> 6) & 0xff);
cmd[12] = ((value >> 16) & 0xff); cmd[11] = ((value >> 14) & 0xff);
cmd[13] = ((value >> 24) & 0xff); cmd[12] = ((value >> 22) & 0xff);
cmd[13] = ((value >> 30) & 0x03);
int bit_count = __builtin_popcount(value); int bit_count = __builtin_popcount(value);
cmd[14] = bit_count & 1; cmd[13] |= ((bit_count & 1) ? 4 : 0);
cmd[15] = 0; send_recv(info.usb_link, cmd, 14, res, 5);
send_recv(info.usb_link, cmd, 16, res, 6);
send_recv(info.usb_link, NULL, 0, res, 1); send_recv(info.usb_link, NULL, 0, res, 1);
if (res[0] != 0) if (res[0] != 0)
raise_exception(EXCEPTION_ERROR, "Low access write failed"); raise_exception(EXCEPTION_ERROR, "Low access write failed");

View File

@ -21,10 +21,13 @@
* *
*/ */
#include "general.h" #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <string.h>
#include <assert.h> #include <assert.h>
#include "general.h"
#include "exception.h" #include "exception.h"
#include "jlink.h" #include "jlink.h"

View File

View File

@ -22,12 +22,14 @@
* *
*/ */
#include "general.h" #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <assert.h> #include <string.h>
#include <ftdi.h>
#include "ftdi_bmp.h"
#include <assert.h>
#include "general.h"
#include "ftdi_bmp.h"
extern cable_desc_t *active_cable; extern cable_desc_t *active_cable;
extern struct ftdi_context *ftdic; extern struct ftdi_context *ftdic;

View File

@ -1,7 +1,8 @@
/* /*
* This file is part of the Black Magic Debug project. * This file is part of the Black Magic Debug project.
* *
* Copyright(C) 2018 - 2021 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) * Copyright (C) 2018 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
* Written by Gareth McMullin <gareth@blacksphere.co.nz>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -21,10 +22,10 @@
* Speed is sensible. * Speed is sensible.
*/ */
#include "general.h" #include <stdio.h>
#include <assert.h> #include <assert.h>
#include <ftdi.h> #include "general.h"
#include "ftdi_bmp.h" #include "ftdi_bmp.h"
enum swdio_status{ enum swdio_status{
@ -165,7 +166,7 @@ bool libftdi_swd_possible(bool *do_mpsse, bool *direct_bb_swd)
return true; return true;
} }
int libftdi_swdptap_init(ADIv5_DP_t *dp) int libftdi_swdptap_init(swd_proc_t *swd_proc)
{ {
if (!libftdi_swd_possible(&do_mpsse, &direct_bb_swd)) { if (!libftdi_swd_possible(&do_mpsse, &direct_bb_swd)) {
DEBUG_WARN("SWD not possible or missing item in cable description.\n"); DEBUG_WARN("SWD not possible or missing item in cable description.\n");
@ -205,14 +206,11 @@ int libftdi_swdptap_init(ADIv5_DP_t *dp)
libftdi_buffer_flush(); libftdi_buffer_flush();
olddir = SWDIO_STATUS_FLOAT; olddir = SWDIO_STATUS_FLOAT;
dp->seq_in = swdptap_seq_in; swd_proc->swdptap_seq_in = swdptap_seq_in;
dp->seq_in_parity = swdptap_seq_in_parity; swd_proc->swdptap_seq_in_parity = swdptap_seq_in_parity;
dp->seq_out = swdptap_seq_out; swd_proc->swdptap_seq_out = swdptap_seq_out;
dp->seq_out_parity = swdptap_seq_out_parity; swd_proc->swdptap_seq_out_parity = swdptap_seq_out_parity;
dp->dp_read = firmware_swdp_read;
dp->error = firmware_swdp_error;
dp->low_access = firmware_swdp_low_access;
dp->abort = firmware_swdp_abort;
return 0; return 0;
} }
@ -305,10 +303,7 @@ static uint32_t swdptap_seq_in(int ticks)
if (do_mpsse) { if (do_mpsse) {
uint8_t DO[4]; uint8_t DO[4];
libftdi_jtagtap_tdi_tdo_seq(DO, 0, NULL, ticks); libftdi_jtagtap_tdi_tdo_seq(DO, 0, NULL, ticks);
int bytes = ticks >> 3; for (int i = 0; i < (ticks >> 3) + (ticks & 7)? 1: 0; i++) {
if (ticks & 7)
bytes++;
for (int i = 0; i < bytes; i++) {
result |= DO[i] << (8 * i); result |= DO[i] << (8 * i);
} }
} else { } else {
@ -366,19 +361,9 @@ static void swdptap_seq_out(uint32_t MS, int ticks)
} }
} }
/* ARM Debug Interface Architecture Specification ADIv5.0 to ADIv5.2
* tells to clock the data through SW-DP to either :
* - immediate start a new transaction
* - continue to drive idle cycles
* - or clock at least 8 idle cycles
*
* Implement last option to favour correctness over
* slight speed decrease
*/
static void swdptap_seq_out_parity(uint32_t MS, int ticks) static void swdptap_seq_out_parity(uint32_t MS, int ticks)
{ {
(void) ticks; int parity = __builtin_parity(MS & ((1LL << ticks) - 1)) & 1;
int parity = __builtin_parity(MS) & 1;
unsigned int index = 0; unsigned int index = 0;
swdptap_turnaround(SWDIO_STATUS_DRIVE); swdptap_turnaround(SWDIO_STATUS_DRIVE);
if (do_mpsse) { if (do_mpsse) {
@ -388,26 +373,26 @@ static void swdptap_seq_out_parity(uint32_t MS, int ticks)
DI[2] = (MS >> 16) & 0xff; DI[2] = (MS >> 16) & 0xff;
DI[3] = (MS >> 24) & 0xff; DI[3] = (MS >> 24) & 0xff;
DI[4] = parity; DI[4] = parity;
DI[5] = 0; libftdi_jtagtap_tdi_tdo_seq(NULL, 0, DI, ticks + 1);
libftdi_jtagtap_tdi_tdo_seq(NULL, 0, DI, 32 + 1 + 8);
} else { } else {
uint8_t cmd[32]; uint8_t cmd[32];
int steps = ticks; int steps = ticks;
while (steps) { while (steps) {
cmd[index++] = MPSSE_TMS_SHIFT; cmd[index++] = MPSSE_TMS_SHIFT;
cmd[index++] = 6;
if (steps >= 7) { if (steps >= 7) {
cmd[index++] = 6;
cmd[index++] = MS & 0x7f; cmd[index++] = MS & 0x7f;
MS >>= 7; MS >>= 7;
steps -= 7; steps -= 7;
} else { } else {
cmd[index++] = (MS & 0x7f) | (parity << 4); cmd[index++] = steps - 1;
cmd[index++] = MS & 0x7f;
steps = 0; steps = 0;
} }
} }
cmd[index++] = MPSSE_TMS_SHIFT; cmd[index++] = MPSSE_TMS_SHIFT;
cmd[index++] = 4;
cmd[index++] = 0; cmd[index++] = 0;
cmd[index++] = parity;
libftdi_buffer_write(cmd, index); libftdi_buffer_write(cmd, index);
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the Black Magic Debug project. * This file is part of the Black Magic Debug project.
* *
* Copyright (C) 2020- 2021 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) * Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -21,6 +21,7 @@
*/ */
#include "general.h" #include "general.h"
#include "swdptap.h"
#include "jtagtap.h" #include "jtagtap.h"
#include "target.h" #include "target.h"
#include "target_internal.h" #include "target_internal.h"
@ -30,31 +31,40 @@
#include "gdb_if.h" #include "gdb_if.h"
#include <signal.h> #include <signal.h>
#ifdef ENABLE_RTT
#include "rtt_if.h"
#endif
#include "bmp_remote.h" #include "bmp_remote.h"
#include "bmp_hosted.h"
#include "stlinkv2.h" #include "stlinkv2.h"
#include "ftdi_bmp.h" #include "ftdi_bmp.h"
#include "jlink.h" #include "jlink.h"
#include "cmsis_dap.h" #include "cmsis_dap.h"
#include "cl_utils.h"
#define VENDOR_ID_STLINK 0x0483
#define PRODUCT_ID_STLINK_MASK 0xffe0
#define PRODUCT_ID_STLINK_GROUP 0x3740
#define PRODUCT_ID_STLINKV1 0x3744
#define PRODUCT_ID_STLINKV2 0x3748
#define PRODUCT_ID_STLINKV21 0x374b
#define PRODUCT_ID_STLINKV21_MSD 0x3752
#define PRODUCT_ID_STLINKV3 0x374f
#define PRODUCT_ID_STLINKV3E 0x374e
#define VENDOR_ID_SEGGER 0x1366
bmp_info_t info; bmp_info_t info;
swd_proc_t swd_proc;
jtag_proc_t jtag_proc; jtag_proc_t jtag_proc;
void gdb_ident(char *p, int count)
{
snprintf(p, count, "%s (%s), %s", info.manufacturer, info.product,
info.version);
}
static void exit_function(void) static void exit_function(void)
{ {
libusb_exit_function(&info); if(info.usb_link) {
libusb_free_transfer(info.usb_link->req_trans);
libusb_free_transfer(info.usb_link->rep_trans);
if (info.usb_link->ul_libusb_device_handle) {
libusb_release_interface (
info.usb_link->ul_libusb_device_handle, 0);
libusb_close(info.usb_link->ul_libusb_device_handle);
}
}
switch (info.bmp_type) { switch (info.bmp_type) {
case BMP_TYPE_CMSIS_DAP: case BMP_TYPE_CMSIS_DAP:
dap_exit_function(); dap_exit_function();
@ -62,9 +72,6 @@ static void exit_function(void)
default: default:
break; break;
} }
#ifdef ENABLE_RTT
rtt_if_exit();
#endif
fflush(stdout); fflush(stdout);
} }
@ -75,24 +82,225 @@ static void sigterm_handler(int sig)
exit(0); exit(0);
} }
static BMP_CL_OPTIONS_t cl_opts; static int find_debuggers( BMP_CL_OPTIONS_t *cl_opts,bmp_info_t *info)
{
libusb_device **devs;
int n_devs = libusb_get_device_list(info->libusb_ctx, &devs);
if (n_devs < 0) {
DEBUG_WARN( "WARN:libusb_get_device_list() failed");
return -1;
}
bool report = false;
int found_debuggers;
struct libusb_device_descriptor desc;
char serial[64];
char manufacturer[128];
char product[128];
bmp_type_t type = BMP_TYPE_NONE;
bool access_problems = false;
char *active_cable = NULL;
bool ftdi_unknown = false;
rescan:
found_debuggers = 0;
for (int i = 0; devs[i]; i++) {
libusb_device *dev = devs[i];
int res = libusb_get_device_descriptor(dev, &desc);
if (res < 0) {
DEBUG_WARN( "WARN: libusb_get_device_descriptor() failed: %s",
libusb_strerror(res));
libusb_free_device_list(devs, 1);
continue;
}
libusb_device_handle *handle;
res = libusb_open(dev, &handle);
if (res != LIBUSB_SUCCESS) {
if (!access_problems) {
DEBUG_INFO("INFO: Open USB %04x:%04x failed\n",
desc.idVendor, desc.idProduct);
access_problems = true;
}
continue;
}
res = libusb_get_string_descriptor_ascii(
handle, desc.iSerialNumber, (uint8_t*)serial,
sizeof(serial));
if (res <= 0) {
/* This can fail for many devices. Continue silent!*/
libusb_close(handle);
continue;
}
if (cl_opts->opt_serial && !strstr(serial, cl_opts->opt_serial)) {
libusb_close(handle);
continue;
}
res = libusb_get_string_descriptor_ascii(
handle, desc.iManufacturer, (uint8_t*)manufacturer,
sizeof(manufacturer));
if (res > 0) {
res = libusb_get_string_descriptor_ascii(
handle, desc.iProduct, (uint8_t*)product,
sizeof(product));
if (res <= 0) {
DEBUG_WARN( "WARN:"
"libusb_get_string_descriptor_ascii "
"for ident_string failed: %s\n",
libusb_strerror(res));
libusb_close(handle);
continue;
}
}
libusb_close(handle);
if (cl_opts->opt_ident_string) {
char *match_manu = NULL;
char *match_product = NULL;
match_manu = strstr(manufacturer, cl_opts->opt_ident_string);
match_product = strstr(product, cl_opts->opt_ident_string);
if (!match_manu && !match_product) {
continue;
}
}
/* Either serial and/or ident_string match or are not given.
* Check type.*/
if ((desc.idVendor == VENDOR_ID_BMP) &&
(desc.idProduct == PRODUCT_ID_BMP)) {
type = BMP_TYPE_BMP;
} else if ((strstr(manufacturer, "CMSIS")) || (strstr(product, "CMSIS"))) {
type = BMP_TYPE_CMSIS_DAP;
} else if (desc.idVendor == VENDOR_ID_STLINK) {
if ((desc.idProduct == PRODUCT_ID_STLINKV2) ||
(desc.idProduct == PRODUCT_ID_STLINKV21) ||
(desc.idProduct == PRODUCT_ID_STLINKV21_MSD) ||
(desc.idProduct == PRODUCT_ID_STLINKV3) ||
(desc.idProduct == PRODUCT_ID_STLINKV3E)) {
type = BMP_TYPE_STLINKV2;
} else {
if (desc.idProduct == PRODUCT_ID_STLINKV1)
DEBUG_WARN( "INFO: STLINKV1 not supported\n");
continue;
}
} else if (desc.idVendor == VENDOR_ID_SEGGER) {
type = BMP_TYPE_JLINK;
} else {
cable_desc_t *cable = &cable_desc[0];
for (; cable->name; cable++) {
bool found = false;
if ((cable->vendor != desc.idVendor) || (cable->product != desc.idProduct))
continue; /* VID/PID do not match*/
if (cl_opts->opt_cable) {
if (strcmp(cable->name, cl_opts->opt_cable))
continue; /* cable names do not match*/
else
found = true;
}
if (cable->description) {
if (strcmp(cable->description, product))
continue; /* discriptions do not match*/
else
found = true;
} else { /* VID/PID fits, but no cl_opts->opt_cable and no description*/
if ((cable->vendor == 0x0403) && /* FTDI*/
((cable->product == 0x6010) || /* FT2232C/D/H*/
(cable->product == 0x6011) || /* FT4232H Quad HS USB-UART/FIFO IC */
(cable->product == 0x6014))) { /* FT232H Single HS USB-UART/FIFO IC */
ftdi_unknown = true;
continue; /* Cable name is needed */
}
}
if (found) {
active_cable = cable->name;
type = BMP_TYPE_LIBFTDI;
break;
}
}
if (!cable->name)
continue;
}
if (report) {
DEBUG_WARN("%2d: %s, %s, %s\n", found_debuggers + 1,
serial,
manufacturer,product);
}
info->vid = desc.idVendor;
info->pid = desc.idProduct;
info->bmp_type = type;
strncpy(info->serial, serial, sizeof(info->serial));
strncpy(info->product, product, sizeof(info->product));
strncpy(info->manufacturer, manufacturer, sizeof(info->manufacturer));
if (cl_opts->opt_position &&
(cl_opts->opt_position == (found_debuggers + 1))) {
found_debuggers = 1;
break;
} else {
found_debuggers++;
}
}
if ((found_debuggers == 0) && ftdi_unknown)
DEBUG_WARN("Generic FTDI MPSSE VID/PID found. Please specify exact type with \"-c <cable>\" !\n");
if ((found_debuggers == 1) && !cl_opts->opt_cable && (type == BMP_TYPE_LIBFTDI))
cl_opts->opt_cable = active_cable;
if (!found_debuggers && cl_opts->opt_list_only)
DEBUG_WARN("No usable debugger found\n");
if ((found_debuggers > 1) ||
((found_debuggers == 1) && (cl_opts->opt_list_only))) {
if (!report) {
if (found_debuggers > 1)
DEBUG_WARN("%d debuggers found!\nSelect with -P <pos>, "
"-s <(partial)serial no.> "
"and/or -S <(partial)description>\n",
found_debuggers);
report = true;
goto rescan;
} else {
if (found_debuggers > 0)
access_problems = false;
found_debuggers = 0;
}
}
if (!found_debuggers && access_problems)
DEBUG_WARN(
"No debugger found. Please check access rights to USB devices!\n");
libusb_free_device_list(devs, 1);
return (found_debuggers == 1) ? 0 : -1;
}
void platform_init(int argc, char **argv) void platform_init(int argc, char **argv)
{ {
BMP_CL_OPTIONS_t cl_opts = {0};
cl_opts.opt_idstring = "Blackmagic PC-Hosted";
cl_init(&cl_opts, argc, argv); cl_init(&cl_opts, argc, argv);
atexit(exit_function); atexit(exit_function);
signal(SIGTERM, sigterm_handler); signal(SIGTERM, sigterm_handler);
signal(SIGINT, sigterm_handler); signal(SIGINT, sigterm_handler);
if (cl_opts.opt_device) int res = libusb_init(&info.libusb_ctx);
info.bmp_type = BMP_TYPE_BMP; if (res) {
else if (find_debuggers(&cl_opts, &info)) DEBUG_WARN( "Fatal: Failed to get USB context: %s\n",
libusb_strerror(res));
exit(-1); exit(-1);
bmp_ident(&info); }
if (cl_opts.opt_device) {
info.bmp_type = BMP_TYPE_BMP;
} else if (cl_opts.opt_cable) {
if ((!strcmp(cl_opts.opt_cable, "list")) ||
(!strcmp(cl_opts.opt_cable, "l"))) {
cable_desc_t *cable = &cable_desc[0];
DEBUG_WARN("Available cables:\n");
for (; cable->name; cable++) {
DEBUG_WARN("\t%s\n", cable->name);
}
exit(0);
}
info.bmp_type = BMP_TYPE_LIBFTDI;
} else if (find_debuggers(&cl_opts, &info)) {
exit(-1);
}
DEBUG_WARN("Using %04x:%04x %s %s %s\n", info.vid, info.pid, info.serial,
info.manufacturer,
info.product);
switch (info.bmp_type) { switch (info.bmp_type) {
case BMP_TYPE_BMP: case BMP_TYPE_BMP:
if (serial_open(&cl_opts, info.serial)) if (serial_open(&cl_opts, info.serial))
exit(-1); exit(-1);
remote_init(); remote_init(true);
break; break;
case BMP_TYPE_STLINKV2: case BMP_TYPE_STLINKV2:
if (stlink_init( &info)) if (stlink_init( &info))
@ -113,38 +321,45 @@ void platform_init(int argc, char **argv)
default: default:
exit(-1); exit(-1);
} }
if (cl_opts.opt_mode != BMP_MODE_DEBUG) int ret = -1;
exit(cl_execute(&cl_opts)); if (cl_opts.opt_mode != BMP_MODE_DEBUG) {
else { ret = cl_execute(&cl_opts);
} else {
gdb_if_init(); gdb_if_init();
#ifdef ENABLE_RTT
rtt_if_init();
#endif
return; return;
} }
exit(ret);
} }
int platform_adiv5_swdp_scan(uint32_t targetid) int platform_adiv5_swdp_scan(void)
{ {
info.is_jtag = false;
platform_max_frequency_set(cl_opts.opt_max_swj_frequency);
switch (info.bmp_type) { switch (info.bmp_type) {
case BMP_TYPE_BMP: case BMP_TYPE_BMP:
case BMP_TYPE_LIBFTDI: case BMP_TYPE_LIBFTDI:
case BMP_TYPE_CMSIS_DAP: return adiv5_swdp_scan();
return adiv5_swdp_scan(targetid);
break; break;
case BMP_TYPE_STLINKV2: case BMP_TYPE_STLINKV2:
{ {
target_list_free(); target_list_free();
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp)); ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
if (stlink_enter_debug_swd(&info, dp)) { if (!stlink_enter_debug_swd(&info, dp)) {
free(dp);
} else {
adiv5_dp_init(dp); adiv5_dp_init(dp);
if (target_list) if (target_list)
return 1; return 1;
} }
free(dp);
break;
}
case BMP_TYPE_CMSIS_DAP:
{
target_list_free();
ADIv5_DP_t *dp = (void*)calloc(1, sizeof(*dp));
if (!dap_enter_debug_swd(dp)) {
adiv5_dp_init(dp);
if (target_list)
return 1;
}
free(dp);
break; break;
} }
case BMP_TYPE_JLINK: case BMP_TYPE_JLINK:
@ -155,34 +370,25 @@ int platform_adiv5_swdp_scan(uint32_t targetid)
return 0; return 0;
} }
int swdptap_init(ADIv5_DP_t *dp) int platform_swdptap_init(void)
{ {
switch (info.bmp_type) { switch (info.bmp_type) {
case BMP_TYPE_BMP: case BMP_TYPE_BMP:
return remote_swdptap_init(dp); return remote_swdptap_init(&swd_proc);
case BMP_TYPE_CMSIS_DAP:
return dap_swdptap_init(dp);
case BMP_TYPE_STLINKV2: case BMP_TYPE_STLINKV2:
case BMP_TYPE_CMSIS_DAP:
case BMP_TYPE_JLINK: case BMP_TYPE_JLINK:
return 0; return 0;
case BMP_TYPE_LIBFTDI: case BMP_TYPE_LIBFTDI:
return libftdi_swdptap_init(dp); return libftdi_swdptap_init(&swd_proc);
default: default:
return -1; return -1;
} }
return -1; return -1;
} }
void platform_add_jtag_dev(int i, const jtag_dev_t *jtag_dev)
{
if (info.bmp_type == BMP_TYPE_BMP)
remote_add_jtag_dev(i, jtag_dev);
}
int platform_jtag_scan(const uint8_t *lrlens) int platform_jtag_scan(const uint8_t *lrlens)
{ {
info.is_jtag = true;
platform_max_frequency_set(cl_opts.opt_max_swj_frequency);
switch (info.bmp_type) { switch (info.bmp_type) {
case BMP_TYPE_BMP: case BMP_TYPE_BMP:
case BMP_TYPE_LIBFTDI: case BMP_TYPE_LIBFTDI:
@ -218,13 +424,8 @@ int platform_jtagtap_init(void)
void platform_adiv5_dp_defaults(ADIv5_DP_t *dp) void platform_adiv5_dp_defaults(ADIv5_DP_t *dp)
{ {
dp->dp_bmp_type = info.bmp_type;
switch (info.bmp_type) { switch (info.bmp_type) {
case BMP_TYPE_BMP: case BMP_TYPE_BMP:
if (cl_opts.opt_no_hl) {
DEBUG_WARN("Not using HL commands\n");
return;
}
return remote_adiv5_dp_defaults(dp); return remote_adiv5_dp_defaults(dp);
case BMP_TYPE_STLINKV2: case BMP_TYPE_STLINKV2:
return stlink_adiv5_dp_defaults(dp); return stlink_adiv5_dp_defaults(dp);
@ -297,10 +498,6 @@ void platform_srst_set_val(bool assert)
return remote_srst_set_val(assert); return remote_srst_set_val(assert);
case BMP_TYPE_JLINK: case BMP_TYPE_JLINK:
return jlink_srst_set_val(&info, assert); return jlink_srst_set_val(&info, assert);
case BMP_TYPE_LIBFTDI:
return libftdi_srst_set_val(assert);
case BMP_TYPE_CMSIS_DAP:
return dap_srst_set_val(assert);
default: default:
break; break;
} }
@ -315,83 +512,12 @@ bool platform_srst_get_val(void)
return stlink_srst_get_val(); return stlink_srst_get_val();
case BMP_TYPE_JLINK: case BMP_TYPE_JLINK:
return jlink_srst_get_val(&info); return jlink_srst_get_val(&info);
case BMP_TYPE_LIBFTDI:
return libftdi_srst_get_val();
default: default:
break; break;
} }
return false; return false;
} }
void platform_max_frequency_set(uint32_t freq)
{
if (!freq)
return;
switch (info.bmp_type) {
case BMP_TYPE_BMP:
remote_max_frequency_set(freq);
break;
case BMP_TYPE_CMSIS_DAP:
dap_swj_clock(freq);
break;
case BMP_TYPE_LIBFTDI:
libftdi_max_frequency_set(freq);
break;
case BMP_TYPE_STLINKV2:
stlink_max_frequency_set(&info, freq);
break;
case BMP_TYPE_JLINK:
jlink_max_frequency_set(&info, freq);
break;
default:
DEBUG_WARN("Setting max SWJ frequency not yet implemented\n");
break;
}
uint32_t max_freq = platform_max_frequency_get();
if (max_freq == FREQ_FIXED)
DEBUG_INFO("Device has fixed frequency for %s\n",
(info.is_jtag) ? "JTAG" : "SWD" );
else
DEBUG_INFO("Speed set to %7.4f MHz for %s\n",
platform_max_frequency_get() / 1000000.0,
(info.is_jtag) ? "JTAG" : "SWD" );
}
uint32_t platform_max_frequency_get(void)
{
switch (info.bmp_type) {
case BMP_TYPE_BMP:
return remote_max_frequency_get();
case BMP_TYPE_CMSIS_DAP:
return dap_swj_clock(0);
break;
case BMP_TYPE_LIBFTDI:
return libftdi_max_frequency_get();
case BMP_TYPE_STLINKV2:
return stlink_max_frequency_get(&info);
case BMP_TYPE_JLINK:
return jlink_max_frequency_get(&info);
default:
DEBUG_WARN("Reading max SWJ frequency not yet implemented\n");
break;
}
return false;
}
void platform_target_set_power(bool power)
{
switch (info.bmp_type) {
case BMP_TYPE_BMP:
if (remote_target_set_power(power))
DEBUG_INFO("Powering up device!\n");
else
DEBUG_WARN("Powering up device unimplemented or failed\n");
break;
default:
break;
}
}
void platform_buffer_flush(void) void platform_buffer_flush(void)
{ {
switch (info.bmp_type) { switch (info.bmp_type) {

View File

@ -1,35 +1,22 @@
#ifndef __PLATFORM_H #ifndef __PLATFORM_H
#define __PLATFORM_H #define __PLATFORM_H
#include <libusb-1.0/libusb.h>
#include "libusb_utils.h"
#include <libftdi1/ftdi.h>
#include "timing.h" #include "timing.h"
char *platform_ident(void); char *platform_ident(void);
void platform_buffer_flush(void); void platform_buffer_flush(void);
#define PLATFORM_IDENT "(PC-Hosted) " #define PLATFORM_IDENT() "NONE"
#define SET_IDLE_STATE(x) #define SET_IDLE_STATE(x)
#define SET_RUN_STATE(x) #define SET_RUN_STATE(x)
#define SYSTICKHZ 1000
#define VENDOR_ID_BMP 0x1d50 #define VENDOR_ID_BMP 0x1d50
#define PRODUCT_ID_BMP_BL 0x6017
#define PRODUCT_ID_BMP 0x6018 #define PRODUCT_ID_BMP 0x6018
#define VENDOR_ID_STLINK 0x0483
#define PRODUCT_ID_STLINK_MASK 0xffe0
#define PRODUCT_ID_STLINK_GROUP 0x3740
#define PRODUCT_ID_STLINKV1 0x3744
#define PRODUCT_ID_STLINKV2 0x3748
#define PRODUCT_ID_STLINKV21 0x374b
#define PRODUCT_ID_STLINKV21_MSD 0x3752
#define PRODUCT_ID_STLINKV3_NO_MSD 0x3754
#define PRODUCT_ID_STLINKV3_BL 0x374d
#define PRODUCT_ID_STLINKV3 0x374f
#define PRODUCT_ID_STLINKV3E 0x374e
#define VENDOR_ID_SEGGER 0x1366
typedef enum bmp_type_s { typedef enum bmp_type_s {
BMP_TYPE_NONE = 0, BMP_TYPE_NONE = 0,
BMP_TYPE_BMP, BMP_TYPE_BMP,
@ -39,5 +26,19 @@ typedef enum bmp_type_s {
BMP_TYPE_JLINK BMP_TYPE_JLINK
} bmp_type_t; } bmp_type_t;
void gdb_ident(char *p, int count); typedef struct bmp_info_s {
bmp_type_t bmp_type;
libusb_context *libusb_ctx;
struct ftdi_context *ftdic;
usb_link_t *usb_link;
unsigned int vid;
unsigned int pid;
char dev;
char serial[64];
char manufacturer[128];
char product[128];
} bmp_info_t;
extern bmp_info_t info;
#endif #endif

View File

@ -26,11 +26,13 @@
* Should share interface with swdptap.c or at least clean up... * Should share interface with swdptap.c or at least clean up...
*/ */
#include "general.h" #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <string.h>
#include <assert.h> #include <assert.h>
#include "general.h"
#include "remote.h" #include "remote.h"
#include "jtagtap.h" #include "jtagtap.h"
#include "bmp_remote.h" #include "bmp_remote.h"
@ -104,43 +106,23 @@ static void jtagtap_tms_seq(uint32_t MS, int ticks)
} }
} }
/* At least up to v1.7.1-233, remote handles only up to 32 ticks in one
* call. Break up large calls.
*
* FIXME: Provide and test faster call and keep fallback
* for old firmware
*/
static void jtagtap_tdi_tdo_seq( static void jtagtap_tdi_tdo_seq(
uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks) uint8_t *DO, const uint8_t final_tms, const uint8_t *DI, int ticks)
{ {
uint8_t construct[REMOTE_MAX_MSG_SIZE]; uint8_t construct[REMOTE_MAX_MSG_SIZE];
int s; int s;
if(!ticks || (!DI && !DO)) uint64_t DIl=*(uint64_t *)DI;
return;
while (ticks) { if(!ticks || !DI) return;
int chunk;
if (ticks < 65) /* Reduce the length of DI according to the bits we're transmitting */
chunk = ticks; DIl &= (1LL << (ticks + 1))-1;
else {
chunk = 64;
}
ticks -= chunk;
uint64_t di = 0;
int bytes = (chunk + 7) >> 3;
int i = 0;
if (DI) {
for (; i < bytes; i++) {
di |= *DI << (i * 8);
DI++;
}
}
/* PRIx64 differs with system. Use it explicit in the format string*/
s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE, s = snprintf((char *)construct, REMOTE_MAX_MSG_SIZE,
"!J%c%02x%" PRIx64 "%c", REMOTE_JTAG_TDIDO_STR,
(!ticks && final_tms) ? final_tms ? REMOTE_TDITDO_TMS : REMOTE_TDITDO_NOTMS,
REMOTE_TDITDO_TMS : REMOTE_TDITDO_NOTMS, ticks, DIl);
chunk, di, REMOTE_EOM);
platform_buffer_write(construct,s); platform_buffer_write(construct,s);
s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE); s = platform_buffer_read(construct, REMOTE_MAX_MSG_SIZE);
@ -149,13 +131,10 @@ static void jtagtap_tdi_tdo_seq(
s ? (char *)&(construct[1]) : "unknown"); s ? (char *)&(construct[1]) : "unknown");
exit(-1); exit(-1);
} }
if (DO) { if (DO) {
uint64_t res = remotehston(-1, (char *)&construct[1]); uint64_t DOl = remotehston(-1, (char *)&construct[1]);
for (i = bytes; i > 0; i--) { *(uint64_t *)DO = DOl;
*DO++ = res & 0xff;
res >>= 8;
}
}
} }
} }

View File

@ -3,7 +3,7 @@
* *
* Written by Gareth McMullin <gareth@blacksphere.co.nz> * Written by Gareth McMullin <gareth@blacksphere.co.nz>
* Modified by Dave Marples <dave@marples.net> * Modified by Dave Marples <dave@marples.net>
* Modified 2020 - 2021 by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) * Modification (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -35,7 +35,7 @@ static uint32_t swdptap_seq_in(int ticks);
static void swdptap_seq_out(uint32_t MS, int ticks); static void swdptap_seq_out(uint32_t MS, int ticks);
static void swdptap_seq_out_parity(uint32_t MS, int ticks); static void swdptap_seq_out_parity(uint32_t MS, int ticks);
int remote_swdptap_init(ADIv5_DP_t *dp) int remote_swdptap_init(swd_proc_t *swd_proc)
{ {
DEBUG_WIRE("remote_swdptap_init\n"); DEBUG_WIRE("remote_swdptap_init\n");
uint8_t construct[REMOTE_MAX_MSG_SIZE]; uint8_t construct[REMOTE_MAX_MSG_SIZE];
@ -50,14 +50,11 @@ int remote_swdptap_init(ADIv5_DP_t *dp)
exit(-1); exit(-1);
} }
dp->seq_in = swdptap_seq_in; swd_proc->swdptap_seq_in = swdptap_seq_in;
dp->seq_in_parity = swdptap_seq_in_parity; swd_proc->swdptap_seq_in_parity = swdptap_seq_in_parity;
dp->seq_out = swdptap_seq_out; swd_proc->swdptap_seq_out = swdptap_seq_out;
dp->seq_out_parity = swdptap_seq_out_parity; swd_proc->swdptap_seq_out_parity = swdptap_seq_out_parity;
dp->dp_read = firmware_swdp_read;
dp->error = firmware_swdp_error;
dp->low_access = firmware_swdp_low_access;
dp->abort = firmware_swdp_abort;
return 0; return 0;
} }

View File

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

View File

@ -27,12 +27,10 @@
#include "general.h" #include "general.h"
#include "gdb_if.h" #include "gdb_if.h"
#include "adiv5.h" #include "adiv5.h"
#include "bmp_hosted.h"
#include "stlinkv2.h" #include "stlinkv2.h"
#include "exception.h" #include "exception.h"
#include "jtag_devs.h" #include "jtag_devs.h"
#include "target.h" #include "target.h"
#include "cortexm.h"
#include <assert.h> #include <assert.h>
#include <unistd.h> #include <unistd.h>
@ -42,6 +40,16 @@
#include "cl_utils.h" #include "cl_utils.h"
#define VENDOR_ID_STLINK 0x483
#define PRODUCT_ID_STLINK_MASK 0xffe0
#define PRODUCT_ID_STLINK_GROUP 0x3740
#define PRODUCT_ID_STLINKV1 0x3744
#define PRODUCT_ID_STLINKV2 0x3748
#define PRODUCT_ID_STLINKV21 0x374b
#define PRODUCT_ID_STLINKV21_MSD 0x3752
#define PRODUCT_ID_STLINKV3 0x374f
#define PRODUCT_ID_STLINKV3E 0x374e
#define STLINK_SWIM_ERR_OK 0x00 #define STLINK_SWIM_ERR_OK 0x00
#define STLINK_SWIM_BUSY 0x01 #define STLINK_SWIM_BUSY 0x01
#define STLINK_DEBUG_ERR_OK 0x80 #define STLINK_DEBUG_ERR_OK 0x80
@ -190,6 +198,7 @@ typedef struct {
libusb_context* libusb_ctx; libusb_context* libusb_ctx;
uint16_t vid; uint16_t vid;
uint16_t pid; uint16_t pid;
uint8_t transport_mode;
bool srst; bool srst;
uint8_t dap_select; uint8_t dap_select;
uint8_t ep_tx; uint8_t ep_tx;
@ -339,8 +348,7 @@ static int stlink_send_recv_retry(uint8_t *txbuf, size_t txsize,
if (res == STLINK_ERROR_OK) if (res == STLINK_ERROR_OK)
return res; return res;
uint32_t now = platform_time_ms(); uint32_t now = platform_time_ms();
if (((now - start) > cortexm_wait_timeout) || if (((now - start) > 1000) || (res != STLINK_ERROR_WAIT)) {
(res != STLINK_ERROR_WAIT)) {
DEBUG_WARN("write_retry failed. "); DEBUG_WARN("write_retry failed. ");
return res; return res;
} }
@ -389,9 +397,6 @@ static int write_retry(uint8_t *cmdbuf, size_t cmdsize,
return res; return res;
} }
/* Version data is at 0x080103f8 with STLINKV3 bootloader flashed with
* STLinkUpgrade_v3[3|5].jar
*/
static void stlink_version(bmp_info_t *info) static void stlink_version(bmp_info_t *info)
{ {
if (Stlink.ver_hw == 30) { if (Stlink.ver_hw == 30) {
@ -429,8 +434,7 @@ static void stlink_version(bmp_info_t *info)
Stlink.ver_swim = (version >> 0) & 0x3f; Stlink.ver_swim = (version >> 0) & 0x3f;
} }
} }
DEBUG_INFO("STLink firmware version: V%dJ%d",Stlink.ver_stlink, DEBUG_INFO("V%dJ%d",Stlink.ver_stlink, Stlink.ver_jtag);
Stlink.ver_jtag);
if (Stlink.ver_hw == 30) { if (Stlink.ver_hw == 30) {
DEBUG_INFO("M%dB%dS%d", Stlink.ver_mass, Stlink.ver_bridge, Stlink.ver_swim); DEBUG_INFO("M%dB%dS%d", Stlink.ver_mass, Stlink.ver_bridge, Stlink.ver_swim);
} else if (Stlink.ver_hw == 20) { } else if (Stlink.ver_hw == 20) {
@ -510,39 +514,23 @@ int stlink_init(bmp_info_t *info)
bool found = false; bool found = false;
while ((dev = devs[i++]) != NULL) { while ((dev = devs[i++]) != NULL) {
struct libusb_device_descriptor desc; struct libusb_device_descriptor desc;
int result = libusb_get_device_descriptor(dev, &desc); int r = libusb_get_device_descriptor(dev, &desc);
if (result != LIBUSB_SUCCESS) { if (r < 0) {
DEBUG_WARN("libusb_get_device_descriptor failed %s", DEBUG_WARN("libusb_get_device_descriptor failed %s",
libusb_strerror(result)); libusb_strerror(r));
return -1; return -1;
} }
if (desc.idVendor != info->vid || if ((desc.idVendor != info->vid) ||
desc.idProduct != info->pid) { (desc.idProduct != info->pid) ||
continue; (libusb_open(dev, &sl->ul_libusb_device_handle)
} != LIBUSB_SUCCESS)) {
if ((result = libusb_open(dev, &sl->ul_libusb_device_handle)) != LIBUSB_SUCCESS)
{
DEBUG_WARN("Failed to open STLink device %04x:%04x - %s\n",
desc.idVendor, desc.idProduct, libusb_strerror(result));
DEBUG_WARN("Are you sure the permissions on the device are set correctly?\n");
continue; continue;
} }
char serial[64]; char serial[64];
if (desc.iSerialNumber) { r = libusb_get_string_descriptor_ascii(
int result = libusb_get_string_descriptor_ascii(sl->ul_libusb_device_handle, sl->ul_libusb_device_handle, desc.iSerialNumber,
desc.iSerialNumber, (uint8_t *)serial, sizeof(serial)); (uint8_t*)serial,sizeof(serial));
/* If the call fails and it's not because the device gave us STALL, continue to the next one */ if (r <= 0 || !strstr(serial, info->serial)) {
if (result < 0 && result != LIBUSB_ERROR_PIPE) {
libusb_close(sl->ul_libusb_device_handle);
continue;
}
else if (result <= 0)
serial[0] = '\0';
}
else
serial[0] = '\0';
/* Likewise, if the serial number returned doesn't match the one in info, go to next */
if (!strstr(serial, info->serial)) {
libusb_close(sl->ul_libusb_device_handle); libusb_close(sl->ul_libusb_device_handle);
continue; continue;
} }
@ -551,31 +539,21 @@ int stlink_init(bmp_info_t *info)
} }
libusb_free_device_list(devs, 1); libusb_free_device_list(devs, 1);
if (!found) if (!found)
return 1;
if (info->vid != VENDOR_ID_STLINK)
return 0; return 0;
switch (info->pid) { if (info->pid == PRODUCT_ID_STLINKV2) {
case PRODUCT_ID_STLINKV2:
Stlink.ver_hw = 20; Stlink.ver_hw = 20;
info->usb_link->ep_tx = 2; info->usb_link->ep_tx = 2;
Stlink.ep_tx = 2; Stlink.ep_tx = 2;
break; } else if ((info->pid == PRODUCT_ID_STLINKV21)||
case PRODUCT_ID_STLINKV21 : (info->pid == PRODUCT_ID_STLINKV21_MSD)) {
case PRODUCT_ID_STLINKV21_MSD:
Stlink.ver_hw = 21; Stlink.ver_hw = 21;
info->usb_link->ep_tx = 1; info->usb_link->ep_tx = 1;
Stlink.ep_tx = 1; Stlink.ep_tx = 1;
break; } else if ((info->pid == PRODUCT_ID_STLINKV3) ||
case PRODUCT_ID_STLINKV3_BL: (info->pid == PRODUCT_ID_STLINKV3E)) {
case PRODUCT_ID_STLINKV3:
case PRODUCT_ID_STLINKV3E:
case PRODUCT_ID_STLINKV3_NO_MSD:
Stlink.ver_hw = 30; Stlink.ver_hw = 30;
info->usb_link->ep_tx = 1; info->usb_link->ep_tx = 1;
Stlink.ep_tx = 1; Stlink.ep_tx = 1;
break;
default:
DEBUG_INFO("Unhandled STM32 device\n");
} }
info->usb_link->ep_rx = 1; info->usb_link->ep_rx = 1;
int config; int config;
@ -647,6 +625,44 @@ bool stlink_srst_get_val(void)
return Stlink.srst; return Stlink.srst;
} }
static bool stlink_set_freq_divisor(bmp_info_t *info, uint16_t divisor)
{
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
STLINK_DEBUG_APIV2_SWD_SET_FREQ,
divisor & 0xff, divisor >> 8};
uint8_t data[2];
send_recv(info->usb_link, cmd, 16, data, 2);
if (stlink_usb_error_check(data, false))
return false;
return true;
}
static bool stlink3_set_freq_divisor(bmp_info_t *info, uint16_t divisor)
{
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
STLINK_APIV3_GET_COM_FREQ,
Stlink.transport_mode};
uint8_t data[52];
send_recv(info->usb_link, cmd, 16, data, 52);
stlink_usb_error_check(data, true);
int size = data[8];
if (divisor > size)
divisor = size;
uint8_t *p = data + 12 + divisor * sizeof(uint32_t);
uint32_t freq = p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
DEBUG_INFO("Selected %" PRId32 " khz\n", freq);
cmd[1] = STLINK_APIV3_SET_COM_FREQ;
cmd[2] = Stlink.transport_mode;
cmd[3] = 0;
p = data + 12 + divisor * sizeof(uint32_t);
cmd[4] = p[0];
cmd[5] = p[1];
cmd[6] = p[2];
cmd[7] = p[3];
send_recv(info->usb_link, cmd, 16, data, 8);
return true;
}
int stlink_hwversion(void) int stlink_hwversion(void)
{ {
return Stlink.ver_stlink; return Stlink.ver_stlink;
@ -655,10 +671,16 @@ int stlink_hwversion(void)
static int stlink_enter_debug_jtag(bmp_info_t *info) static int stlink_enter_debug_jtag(bmp_info_t *info)
{ {
stlink_leave_state(info); stlink_leave_state(info);
Stlink.transport_mode = STLINK_MODE_JTAG;
if (Stlink.ver_stlink == 3)
stlink3_set_freq_divisor(info, 4);
else
stlink_set_freq_divisor(info, 1);
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
STLINK_DEBUG_APIV2_ENTER, STLINK_DEBUG_APIV2_ENTER,
STLINK_DEBUG_ENTER_JTAG_NO_RESET}; STLINK_DEBUG_ENTER_JTAG_NO_RESET};
uint8_t data[2]; uint8_t data[2];
DEBUG_INFO("Enter JTAG\n");
send_recv(info->usb_link, cmd, 16, data, 2); send_recv(info->usb_link, cmd, 16, data, 2);
return stlink_usb_error_check(data, true); return stlink_usb_error_check(data, true);
} }
@ -780,10 +802,9 @@ uint32_t stlink_dp_low_access(ADIv5_DP_t *dp, uint8_t RnW,
int res; int res;
if (RnW) { if (RnW) {
res = stlink_read_dp_register( res = stlink_read_dp_register(
(addr < 0x100) ? STLINK_DEBUG_PORT_ACCESS : 0, addr, &response); STLINK_DEBUG_PORT_ACCESS, addr, &response);
} else { } else {
res = stlink_write_dp_register( res = stlink_write_dp_register(STLINK_DEBUG_PORT_ACCESS, addr, value);
(addr < 0x100) ? STLINK_DEBUG_PORT_ACCESS : 0, addr, value);
} }
if (res == STLINK_ERROR_WAIT) if (res == STLINK_ERROR_WAIT)
raise_exception(EXCEPTION_TIMEOUT, "DP ACK timeout"); raise_exception(EXCEPTION_TIMEOUT, "DP ACK timeout");
@ -808,8 +829,8 @@ static bool stlink_ap_setup(int ap)
ap, ap,
}; };
uint8_t data[2]; uint8_t data[2];
send_recv(info.usb_link, cmd, 16, data, 2);
DEBUG_PROBE("Open AP %d\n", ap); DEBUG_PROBE("Open AP %d\n", ap);
stlink_send_recv_retry(cmd, 16, data, 2);
int res = stlink_usb_error_check(data, true); int res = stlink_usb_error_check(data, true);
if (res) { if (res) {
if (Stlink.ver_hw == 30) { if (Stlink.ver_hw == 30) {
@ -1020,13 +1041,13 @@ int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens)
jtag_dev_count = stlink_read_idcodes(info, idcodes); jtag_dev_count = stlink_read_idcodes(info, idcodes);
/* Check for known devices and handle accordingly */ /* Check for known devices and handle accordingly */
for(int i = 0; i < jtag_dev_count; i++) for(int i = 0; i < jtag_dev_count; i++)
jtag_devs[i].jd_idcode = idcodes[i]; jtag_devs[i].idcode = idcodes[i];
for(int i = 0; i < jtag_dev_count; i++) for(int i = 0; i < jtag_dev_count; i++)
for(int j = 0; dev_descr[j].idcode; j++) for(int j = 0; dev_descr[j].idcode; j++)
if((jtag_devs[i].jd_idcode & dev_descr[j].idmask) == if((jtag_devs[i].idcode & dev_descr[j].idmask) ==
dev_descr[j].idcode) { dev_descr[j].idcode) {
if(dev_descr[j].handler) if(dev_descr[j].handler)
dev_descr[j].handler(i); dev_descr[j].handler(&jtag_devs[i]);
break; break;
} }
@ -1060,13 +1081,19 @@ void stlink_adiv5_dp_defaults(ADIv5_DP_t *dp)
int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp) int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp)
{ {
stlink_leave_state(info); stlink_leave_state(info);
Stlink.transport_mode = STLINK_MODE_SWD;
if (Stlink.ver_stlink == 3)
stlink3_set_freq_divisor(info, 2);
else
stlink_set_freq_divisor(info, 1);
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND, uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
STLINK_DEBUG_APIV2_ENTER, STLINK_DEBUG_APIV2_ENTER,
STLINK_DEBUG_ENTER_SWD_NO_RESET}; STLINK_DEBUG_ENTER_SWD_NO_RESET};
uint8_t data[2]; uint8_t data[2];
DEBUG_INFO("Enter SWD\n");
stlink_send_recv_retry(cmd, 16, data, 2); stlink_send_recv_retry(cmd, 16, data, 2);
if (stlink_usb_error_check(data, true)) if (stlink_usb_error_check(data, true))
exit( -1); return -1;
dp->idcode = stlink_read_coreid(); dp->idcode = stlink_read_coreid();
dp->dp_read = stlink_dp_read; dp->dp_read = stlink_dp_read;
dp->error = stlink_dp_error; dp->error = stlink_dp_error;
@ -1074,117 +1101,5 @@ int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp)
dp->abort = stlink_dp_abort; dp->abort = stlink_dp_abort;
stlink_dp_error(dp); stlink_dp_error(dp);
if ((dp->idcode & ADIV5_DP_VERSION_MASK) == ADIV5_DPv2) {
adiv5_dp_write(dp, ADIV5_DP_SELECT, 2);
dp->targetid = adiv5_dp_read(dp, ADIV5_DP_CTRLSTAT);
adiv5_dp_write(dp, ADIV5_DP_SELECT, 0);
DEBUG_INFO("TARGETID 0x%08" PRIx32 "\n", dp->targetid);
}
return 0; return 0;
} }
#define V2_USED_SWD_CYCLES 20
#define V2_CYCLES_PER_CNT 20
#define V2_CLOCK_RATE (72*1000*1000)
/* Above values reproduce the known values for V2
#include <stdio.h>
int main(void)
{
int divs[] = {0, 1,2,3,7,15,31,40,79,158,265,798};
for (int i = 0; i < (sizeof(divs) /sizeof(divs[0])); i++) {
float ret = 72.0 * 1000 * 1000 / (20 + 20 * divs[i]);
printf("%3d: %6.4f MHz\n", divs[i], ret/ 1000000);
}
return 0;
}
*/
static int divisor;
static unsigned int v3_freq[2];
void stlink_max_frequency_set(bmp_info_t *info, uint32_t freq)
{
if (Stlink.ver_hw == 30) {
uint8_t cmd[16] = {STLINK_DEBUG_COMMAND,
STLINK_APIV3_GET_COM_FREQ,
info->is_jtag ? STLINK_MODE_JTAG : STLINK_MODE_SWD};
uint8_t data[52];
send_recv(info->usb_link, cmd, 16, data, 52);
stlink_usb_error_check(data, true);
volatile uint8_t *p = data + 12;
int i;
unsigned int last_freq = 0;
DEBUG_INFO("Available speed settings: ");
for (i = 0; i < STLINK_V3_MAX_FREQ_NB; i++) {
unsigned int new_freq = *p++;
new_freq |= *p++ << 8;
new_freq |= *p++ << 16;
new_freq |= *p++ << 24;
if (!new_freq)
break;
else
last_freq = new_freq;
DEBUG_INFO("%s%d", (i)? "/": "", last_freq);
if ((freq / 1000) >= last_freq)
break;
}
DEBUG_INFO(" kHz for %s\n", (info->is_jtag) ? "JTAG" : "SWD");
cmd[1] = STLINK_APIV3_SET_COM_FREQ;
cmd[3] = 0;
cmd[4] = (last_freq >> 0) & 0xff;
cmd[5] = (last_freq >> 8) & 0xff;
cmd[6] = (last_freq >> 16) & 0xff;
cmd[7] = (last_freq >> 24) & 0xff;
send_recv(info->usb_link, cmd, 16, data, 8);
stlink_usb_error_check(data, true);
v3_freq[(info->is_jtag) ? 1 : 0] = last_freq * 1000;
} else {
uint8_t cmd[16];
cmd[0] = STLINK_DEBUG_COMMAND;
if (info->is_jtag) {
cmd[1] = STLINK_DEBUG_APIV2_JTAG_SET_FREQ;
/* V2_CLOCK_RATE / (4, 8, 16, ... 256)*/
int div = (V2_CLOCK_RATE + (2 * freq) - 1) / (2 * freq);
if (div & (div -1)) {/* Round up */
int clz = __builtin_clz(div);
divisor = 1 << (32 - clz);
} else
divisor = div;
if (divisor < 4)
divisor = 4;
else if (divisor > 256)
divisor = 256;
} else {
cmd[1] = STLINK_DEBUG_APIV2_SWD_SET_FREQ;
divisor = V2_CLOCK_RATE + freq - 1;
divisor /= freq;
divisor -= V2_USED_SWD_CYCLES;
if (divisor < 0)
divisor = 0;
divisor /= V2_CYCLES_PER_CNT;
}
DEBUG_WARN("Divisor for %6.4f MHz is %" PRIu32 "\n",
freq/1000000.0, divisor);
cmd[2] = divisor & 0xff;
cmd[3] = (divisor >> 8) & 0xff;
uint8_t data[2];
send_recv(info->usb_link, cmd, 16, data, 2);
if (stlink_usb_error_check(data, false))
DEBUG_WARN("Set frequency failed!\n");
}
}
uint32_t stlink_max_frequency_get(bmp_info_t *info)
{
uint32_t ret = 0;
if (Stlink.ver_hw == 30) {
ret = v3_freq[(info->is_jtag) ? STLINK_MODE_JTAG : STLINK_MODE_SWD];
} else {
ret = V2_CLOCK_RATE;
if (info->is_jtag)
ret /= (2 * divisor);
else
ret /= (V2_USED_SWD_CYCLES + (V2_CYCLES_PER_CNT * divisor));
}
return ret;
}

View File

@ -24,34 +24,16 @@
#define STLINK_DEBUG_PORT_ACCESS 0xffff #define STLINK_DEBUG_PORT_ACCESS 0xffff
#if HOSTED_BMP_ONLY == 1
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
int stlink_init(bmp_info_t *info) {return -1;};
int stlink_hwversion(void) {return -1;};
const char *stlink_target_voltage(bmp_info_t *info) {return "ERROR";};
void stlink_srst_set_val(bmp_info_t *info, bool assert) {};
bool stlink_srst_get_val(void) {return true;};
int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp) {return -1;};
void stlink_adiv5_dp_defaults(ADIv5_DP_t *dp) {};
int stlink_jtag_dp_init(ADIv5_DP_t *dp) {return false;};
int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens) {return 0;};
void stlink_exit_function(bmp_info_t *info) {};
void stlink_max_frequency_set(bmp_info_t *info, uint32_t freq) {};
uint32_t stlink_max_frequency_get(bmp_info_t *info) {return 0;};
# pragma GCC diagnostic pop
#else
int stlink_init(bmp_info_t *info); int stlink_init(bmp_info_t *info);
int stlink_hwversion(void); int stlink_hwversion(void);
const char *stlink_target_voltage(bmp_info_t *info); const char *stlink_target_voltage(bmp_info_t *info);
void stlink_srst_set_val(bmp_info_t *info, bool assert); void stlink_srst_set_val(bmp_info_t *info, bool assert);
bool stlink_srst_get_val(void); bool stlink_srst_get_val(void);
int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp); int stlink_enter_debug_swd(bmp_info_t *info, ADIv5_DP_t *dp);
const char *stlink_target_voltage(bmp_info_t *info);
void stlink_adiv5_dp_defaults(ADIv5_DP_t *dp); void stlink_adiv5_dp_defaults(ADIv5_DP_t *dp);
int stlink_jtag_dp_init(ADIv5_DP_t *dp); int stlink_jtag_dp_init(ADIv5_DP_t *dp);
int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens); int jtag_scan_stlinkv2(bmp_info_t *info, const uint8_t *irlens);
void stlink_exit_function(bmp_info_t *info); void stlink_exit_function(bmp_info_t *info);
void stlink_max_frequency_set(bmp_info_t *info, uint32_t freq);
uint32_t stlink_max_frequency_get(bmp_info_t *info);
#endif
#endif #endif

View File

View File

@ -4,8 +4,8 @@ OBJCOPY = $(CROSS_COMPILE)objcopy
CFLAGS += -Istm32/include -mcpu=cortex-m4 -mthumb \ CFLAGS += -Istm32/include -mcpu=cortex-m4 -mthumb \
-mfloat-abi=hard -mfpu=fpv4-sp-d16 \ -mfloat-abi=hard -mfpu=fpv4-sp-d16 \
-DSTM32F4 -I../libopencm3/include \ -DSTM32F4 -DHYDRABUS -I../libopencm3/include \
-Iplatforms/stm32 -DDFU_SERIAL_LENGTH=9 -Iplatforms/stm32
LDFLAGS = -lopencm3_stm32f4 \ LDFLAGS = -lopencm3_stm32f4 \
-Wl,-T,platforms/stm32/f4discovery.ld -nostartfiles -lc -lnosys \ -Wl,-T,platforms/stm32/f4discovery.ld -nostartfiles -lc -lnosys \
@ -27,7 +27,7 @@ all: blackmagic.bin blackmagic.hex
blackmagic.dfu: blackmagic.hex blackmagic.dfu: blackmagic.hex
@echo Creating $@ @echo Creating $@
@python3 ../scripts/dfu-convert.py -i $< $@ @python ../scripts/dfu-convert.py -i $< $@
host_clean: host_clean:
-$(Q)$(RM) blackmagic.bin blackmagic.hex blackmagic.dfu -$(Q)$(RM) blackmagic.bin blackmagic.hex blackmagic.dfu

View File

@ -27,7 +27,7 @@
#include "usbuart.h" #include "usbuart.h"
#include "morse.h" #include "morse.h"
#include <libopencm3/stm32/rcc.h> #include <libopencm3/stm32/f4/rcc.h>
#include <libopencm3/cm3/scb.h> #include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/nvic.h> #include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/exti.h> #include <libopencm3/stm32/exti.h>

View File

@ -28,11 +28,14 @@
#include "gpio.h" #include "gpio.h"
#include "timing.h" #include "timing.h"
#include "timing_stm32.h" #include "timing_stm32.h"
#include "version.h"
#include <setjmp.h> #include <setjmp.h>
#define PLATFORM_HAS_TRACESWO #define PLATFORM_HAS_TRACESWO
#define PLATFORM_IDENT " (HydraBus))" #define BOARD_IDENT "Black Magic Probe (HydraBus), (Firmware " FIRMWARE_VERSION ")"
#define BOARD_IDENT_DFU "Black Magic (Upgrade) for HydraBus, (Firmware " FIRMWARE_VERSION ")"
#define DFU_IDENT "Black Magic Firmware Upgrade (HydraBus)"
/* Important pin mappings for STM32 implementation: /* Important pin mappings for STM32 implementation:
* *
@ -90,54 +93,47 @@
#define SWDIO_MODE_DRIVE() \ #define SWDIO_MODE_DRIVE() \
gpio_mode_setup(SWDIO_PORT, GPIO_MODE_OUTPUT, \ gpio_mode_setup(SWDIO_PORT, GPIO_MODE_OUTPUT, \
GPIO_PUPD_NONE, SWDIO_PIN); GPIO_PUPD_NONE, SWDIO_PIN);
#define UART_PIN_SETUP() do { \
gpio_mode_setup(USBUSART_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
USBUSART_TX_PIN); \
gpio_set_output_options(USBUSART_PORT, GPIO_OTYPE_PP, \
GPIO_OSPEED_100MHZ, USBUSART_TX_PIN); \
gpio_set_af(USBUSART_PORT, GPIO_AF7, USBUSART_TX_PIN); \
gpio_mode_setup(USBUSART_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, \
USBUSART_RX_PIN); \
gpio_set_output_options(USBUSART_PORT, GPIO_OTYPE_OD, \
GPIO_OSPEED_100MHZ, USBUSART_RX_PIN); \
gpio_set_af(USBUSART_PORT, GPIO_AF7, USBUSART_RX_PIN); \
} while(0)
#define USB_DRIVER stm32f107_usb_driver #define USB_DRIVER stm32f107_usb_driver
#define USB_IRQ NVIC_OTG_FS_IRQ #define USB_IRQ NVIC_OTG_FS_IRQ
#define USB_ISR(x) otg_fs_isr(x) #define USB_ISR otg_fs_isr
/* Interrupt priorities. Low numbers are high priority. /* Interrupt priorities. Low numbers are high priority.
* For now USART1 preempts USB which may spin while buffer is drained.
* TIM3 is used for traceswo capture and must be highest priority. * TIM3 is used for traceswo capture and must be highest priority.
*/ */
#define IRQ_PRI_USB (1 << 4) #define IRQ_PRI_USB (2 << 4)
#define IRQ_PRI_USBUSART (2 << 4) #define IRQ_PRI_USBUSART (1 << 4)
#define IRQ_PRI_USBUSART_DMA (2 << 4) #define IRQ_PRI_USBUSART_TIM (3 << 4)
#define IRQ_PRI_TRACE (0 << 4) #define IRQ_PRI_TRACE (0 << 4)
#define USBUSART USART1 #define USBUSART USART1
#define USBUSART_CR1 USART1_CR1 #define USBUSART_CR1 USART1_CR1
#define USBUSART_DR USART1_DR
#define USBUSART_IRQ NVIC_USART1_IRQ #define USBUSART_IRQ NVIC_USART1_IRQ
#define USBUSART_CLK RCC_USART1 #define USBUSART_CLK RCC_USART1
#define USBUSART_PORT GPIOA #define USBUSART_TX_PORT GPIOA
#define USBUSART_TX_PIN GPIO9 #define USBUSART_TX_PIN GPIO9
#define USBUSART_RX_PORT GPIOA
#define USBUSART_RX_PIN GPIO10 #define USBUSART_RX_PIN GPIO10
#define USBUSART_ISR(x) usart1_isr(x) #define USBUSART_ISR usart1_isr
#define USBUSART_DMA_BUS DMA2 #define USBUSART_TIM TIM4
#define USBUSART_DMA_CLK RCC_DMA2 #define USBUSART_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM4)
#define USBUSART_DMA_TX_CHAN DMA_STREAM7 #define USBUSART_TIM_IRQ NVIC_TIM4_IRQ
#define USBUSART_DMA_TX_IRQ NVIC_DMA2_STREAM7_IRQ #define USBUSART_TIM_ISR tim4_isr
#define USBUSART_DMA_TX_ISR(x) dma2_stream7_isr(x)
#define USBUSART_DMA_RX_CHAN DMA_STREAM5 #define UART_PIN_SETUP() do { \
#define USBUSART_DMA_RX_IRQ NVIC_DMA2_STREAM5_IRQ gpio_mode_setup(USBUSART_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
#define USBUSART_DMA_RX_ISR(x) dma2_stream5_isr(x) USBUSART_TX_PIN); \
/* For STM32F4 DMA trigger source must be specified */ gpio_mode_setup(USBUSART_RX_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, \
#define USBUSART_DMA_TRG DMA_SxCR_CHSEL_4 USBUSART_RX_PIN); \
gpio_set_af(USBUSART_TX_PORT, GPIO_AF7, USBUSART_TX_PIN); \
gpio_set_af(USBUSART_RX_PORT, GPIO_AF7, USBUSART_RX_PIN); \
} while(0)
#define TRACE_TIM TIM3 #define TRACE_TIM TIM3
#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) #define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3)
#define TRACE_IRQ NVIC_TIM3_IRQ #define TRACE_IRQ NVIC_TIM3_IRQ
#define TRACE_ISR(x) tim3_isr(x) #define TRACE_ISR tim3_isr
#define gpio_set_val(port, pin, val) do { \ #define gpio_set_val(port, pin, val) do { \
if(val) \ if(val) \
@ -189,3 +185,4 @@ static inline int platform_hwversion(void)
#endif #endif
#endif #endif

View File

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

View File

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

View File

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

View File

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

View File

@ -7,7 +7,6 @@ INCLUDES = -I../libopencm3/include
CPU_FLAGS = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard CPU_FLAGS = -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard
CFLAGS += $(INCLUDES) $(CPU_FLAGS) -DSERIAL_NO=$(SERIAL_NO) -DTARGET_IS_BLIZZARD_RB1 -DLM4F -DPART_TM4C123GH6PM CFLAGS += $(INCLUDES) $(CPU_FLAGS) -DSERIAL_NO=$(SERIAL_NO) -DTARGET_IS_BLIZZARD_RB1 -DLM4F -DPART_TM4C123GH6PM
CFLAGS += -DDFU_SERIAL_LENGTH=9
LINKER_SCRIPT="platforms/tm4c/tm4c.ld" LINKER_SCRIPT="platforms/tm4c/tm4c.ld"
LDFLAGS = -nostartfiles -lc $(CPU_FLAGS) -nodefaultlibs -T$(LINKER_SCRIPT) -Wl,--gc-sections \ LDFLAGS = -nostartfiles -lc $(CPU_FLAGS) -nodefaultlibs -T$(LINKER_SCRIPT) -Wl,--gc-sections \

View File

@ -25,6 +25,9 @@
#include <libopencm3/cm3/systick.h> #include <libopencm3/cm3/systick.h>
#include <libopencm3/lm4f/usb.h> #include <libopencm3/lm4f/usb.h>
#define SYSTICKHZ 100
#define SYSTICKMS (1000 / SYSTICKHZ)
#define PLL_DIV_80MHZ 5 #define PLL_DIV_80MHZ 5
#define PLL_DIV_25MHZ 16 #define PLL_DIV_25MHZ 16
@ -34,8 +37,6 @@ volatile platform_timeout * volatile head_timeout;
uint8_t running_status; uint8_t running_status;
static volatile uint32_t time_ms; static volatile uint32_t time_ms;
uint32_t swd_delay_cnt = 0;
void sys_tick_handler(void) void sys_tick_handler(void)
{ {
trace_tick(); trace_tick();
@ -117,7 +118,7 @@ const char *platform_target_voltage(void)
return NULL; return NULL;
} }
char *serial_no_read(char *s) char *serial_no_read(char *s, int max)
{ {
/* FIXME: Store a unique serial number somewhere and retreive here */ /* FIXME: Store a unique serial number somewhere and retreive here */
uint32_t unique_id = SERIAL_NO; uint32_t unique_id = SERIAL_NO;
@ -127,10 +128,10 @@ char *serial_no_read(char *s)
for(i = 0; i < 8; i++) { for(i = 0; i < 8; i++) {
s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0'; s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';
} }
for(i = 0; i < DFU_SERIAL_LENGTH - 1; i++) for(i = 0; i < max - 1; i++)
if(s[i] > '9') if(s[i] > '9')
s[i] += 'A' - '9' - 1; s[i] += 'A' - '9' - 1;
s[DFU_SERIAL_LENGTH - 1] = 0; s[max] = 0;
return s; return s;
} }
@ -139,12 +140,3 @@ void platform_request_boot(void)
{ {
} }
void platform_max_frequency_set(uint32_t freq)
{
(void)freq;
}
uint32_t platform_max_frequency_get(void)
{
return 0;
}

View File

@ -21,11 +21,14 @@
#include <libopencm3/usb/usbd.h> #include <libopencm3/usb/usbd.h>
#include "timing.h" #include "timing.h"
#include "version.h"
#define PLATFORM_IDENT "(Launchpad ICDI) " #define BOARD_IDENT "Black Magic Probe (Launchpad ICDI), (Firmware " FIRMWARE_VERSION ")"
#define BOARD_IDENT_DFU "Black Magic (Upgrade) for Launchpad, (Firmware " FIRMWARE_VERSION ")"
#define DFU_IDENT "Black Magic Firmware Upgrade (Launchpad)"
#define DFU_IFACE_STRING "lolwut"
extern uint8_t running_status; extern uint8_t running_status;
extern uint32_t swd_delay_cnt;
#define TMS_PORT GPIOA_BASE #define TMS_PORT GPIOA_BASE
#define TMS_PIN GPIO3 #define TMS_PIN GPIO3

View File

@ -4,7 +4,7 @@ OBJCOPY = $(CROSS_COMPILE)objcopy
CFLAGS += -Istm32/include -mcpu=cortex-m3 -mthumb \ CFLAGS += -Istm32/include -mcpu=cortex-m3 -mthumb \
-DSTM32F1 -DBLACKMAGIC -I../libopencm3/include \ -DSTM32F1 -DBLACKMAGIC -I../libopencm3/include \
-Iplatforms/stm32 -DDFU_SERIAL_LENGTH=9 -Iplatforms/stm32
LDFLAGS_BOOT := $(LDFLAGS) --specs=nano.specs -lopencm3_stm32f1 \ LDFLAGS_BOOT := $(LDFLAGS) --specs=nano.specs -lopencm3_stm32f1 \
-Wl,-T,platforms/stm32/blackmagic.ld -nostartfiles -lc \ -Wl,-T,platforms/stm32/blackmagic.ld -nostartfiles -lc \
@ -30,7 +30,7 @@ SRC += cdcacm.c \
all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex all: blackmagic.bin blackmagic_dfu.bin blackmagic_dfu.hex
blackmagic_dfu.elf: usbdfu.o dfucore.o dfu_f1.o serialno.o blackmagic_dfu.elf: usbdfu.o dfucore.o dfu_f1.o
@echo " LD $@" @echo " LD $@"
$(Q)$(CC) $^ -o $@ $(LDFLAGS_BOOT) $(Q)$(CC) $^ -o $@ $(LDFLAGS_BOOT)

View File

@ -27,50 +27,23 @@
#include "usbuart.h" #include "usbuart.h"
#include "morse.h" #include "morse.h"
#include <libopencm3/stm32/rcc.h> #include <libopencm3/stm32/f1/rcc.h>
#include <libopencm3/cm3/scb.h> #include <libopencm3/cm3/scb.h>
#include <libopencm3/cm3/scs.h> #include <libopencm3/cm3/scs.h>
#include <libopencm3/cm3/nvic.h> #include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/exti.h> #include <libopencm3/stm32/exti.h>
#include <libopencm3/stm32/usart.h> #include <libopencm3/stm32/usart.h>
#include <libopencm3/usb/usbd.h> #include <libopencm3/usb/usbd.h>
#include <libopencm3/stm32/adc.h> #include <libopencm3/stm32/f1/adc.h>
#include <libopencm3/stm32/flash.h>
static void adc_init(void); static void adc_init(void);
static void setup_vbus_irq(void); static void setup_vbus_irq(void);
/* Starting with hardware version 4 we are storing the hardware version in the
* flash option user Data1 byte.
* The hardware version 4 was the transition version that had it's hardware
* pins strapped to 3 but contains version 4 in the Data1 byte.
* The hardware 4 is backward compatible with V3 but provides the new jumper
* connecting STRACE target pin to the UART1 pin.
* Hardware version 5 does not have the physically strapped version encoding
* any more and the hardware version has to be read out of the option bytes.
* This means that older firmware versions that don't do the detection won't
* work on the newer hardware.
*/
#define BMP_HWVERSION_BYTE FLASH_OPTION_BYTE_2
/* Pins PB[7:5] are used to detect hardware revision. /* Pins PB[7:5] are used to detect hardware revision.
* User option byte Data1 is used starting with hardware revision 4. * 000 - Original production build.
* Pin - OByte - Rev - Description * 001 - Mini production build.
* 000 - 0xFFFF - 0 - Original production build. * 010 - Mini V2.0e and later.
* 001 - 0xFFFF - 1 - Mini production build. * 011 - Mini V2.1e and later.
* 010 - 0xFFFF - 2 - Mini V2.0e and later.
* 011 - 0xFFFF - 3 - Mini V2.1a and later.
* 011 - 0xFB04 - 4 - Mini V2.1d and later.
* xxx - 0xFB05 - 5 - Mini V2.2a and later.
* xxx - 0xFB06 - 6 - Mini V2.3a and later.
*
* This function will return -2 if the version number does not make sense.
* This can happen when the Data1 byte contains "garbage". For example a
* hardware revision that is <4 or the high byte is not the binary inverse of
* the lower byte.
* Note: The high byte of the Data1 option byte should always be the binary
* inverse of the lower byte unless the byte is not set, then all bits in both
* high and low byte are 0xFF.
*/ */
int platform_hwversion(void) int platform_hwversion(void)
{ {
@ -78,26 +51,7 @@ int platform_hwversion(void)
uint16_t hwversion_pins = GPIO7 | GPIO6 | GPIO5; uint16_t hwversion_pins = GPIO7 | GPIO6 | GPIO5;
uint16_t unused_pins = hwversion_pins ^ 0xFFFF; uint16_t unused_pins = hwversion_pins ^ 0xFFFF;
/* Check if the hwversion is set in the user option byte. */ /* Only check for version if this is the first time. */
if (hwversion == -1) {
if ((BMP_HWVERSION_BYTE != 0xFFFF) &&
(BMP_HWVERSION_BYTE != 0x00FF)) {
/* Check if the data is valid.
* When valid it should only have values 4 and higher.
*/
if (((BMP_HWVERSION_BYTE >> 8) !=
(~BMP_HWVERSION_BYTE & 0xFF)) ||
((BMP_HWVERSION_BYTE & 0xFF) < 4)) {
return -2;
} else {
hwversion = BMP_HWVERSION_BYTE & 0xFF;
}
}
}
/* If the hwversion is not set in option bytes check
* the hw pin strapping.
*/
if (hwversion == -1) { if (hwversion == -1) {
/* Configure the hardware version pins as input pull-up/down */ /* Configure the hardware version pins as input pull-up/down */
gpio_set_mode(GPIOB, GPIO_MODE_INPUT, gpio_set_mode(GPIOB, GPIO_MODE_INPUT,
@ -143,7 +97,7 @@ void platform_init(void)
initialise_monitor_handles(); initialise_monitor_handles();
#endif #endif
rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE8_72MHZ]); rcc_clock_setup_in_hse_8mhz_out_72mhz();
/* Enable peripherals */ /* Enable peripherals */
rcc_periph_clock_enable(RCC_USB); rcc_periph_clock_enable(RCC_USB);
@ -177,6 +131,10 @@ void platform_init(void)
GPIO_CNF_OUTPUT_PUSHPULL, GPIO_CNF_OUTPUT_PUSHPULL,
LED_UART | LED_IDLE_RUN | LED_ERROR); LED_UART | LED_IDLE_RUN | LED_ERROR);
/* FIXME: This pin in intended to be input, but the TXS0108 fails
* to release the device from reset if this floats. */
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, GPIO7);
/* Enable SRST output. Original uses a NPN to pull down, so setting the /* Enable SRST output. Original uses a NPN to pull down, so setting the
* output HIGH asserts. Mini is directly connected so use open drain output * output HIGH asserts. Mini is directly connected so use open drain output
* and set LOW to assert. * and set LOW to assert.
@ -188,17 +146,7 @@ void platform_init(void)
? GPIO_CNF_OUTPUT_PUSHPULL ? GPIO_CNF_OUTPUT_PUSHPULL
: GPIO_CNF_OUTPUT_OPENDRAIN), : GPIO_CNF_OUTPUT_OPENDRAIN),
SRST_PIN); SRST_PIN);
/* FIXME: Gareth, Esden, what versions need this fix? */
if (platform_hwversion() < 3) {
/* FIXME: This pin in intended to be input, but the TXS0108 fails
* to release the device from reset if this floats. */
gpio_set_mode(SRST_SENSE_PORT, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, SRST_SENSE_PIN);
} else {
gpio_set(SRST_SENSE_PORT, SRST_SENSE_PIN);
gpio_set_mode(SRST_SENSE_PORT, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_PULL_UPDOWN, SRST_SENSE_PIN);
}
/* Enable internal pull-up on PWR_BR so that we don't drive /* Enable internal pull-up on PWR_BR so that we don't drive
TPWR locally or inadvertently supply power to the target. */ TPWR locally or inadvertently supply power to the target. */
if (platform_hwversion () == 1) { if (platform_hwversion () == 1) {
@ -285,7 +233,7 @@ static void adc_init(void)
adc_set_single_conversion_mode(ADC1); adc_set_single_conversion_mode(ADC1);
adc_disable_external_trigger_regular(ADC1); adc_disable_external_trigger_regular(ADC1);
adc_set_right_aligned(ADC1); adc_set_right_aligned(ADC1);
adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_239DOT5CYC); adc_set_sample_time_on_all_channels(ADC1, ADC_SMPR_SMP_28DOT5CYC);
adc_power_on(ADC1); adc_power_on(ADC1);
@ -297,16 +245,12 @@ static void adc_init(void)
adc_calibrate(ADC1); adc_calibrate(ADC1);
} }
uint32_t platform_target_voltage_sense(void) const char *platform_target_voltage(void)
{ {
/* returns the voltage in volt scaled by 10 (so 33 means 3.3V), except
* for hardware version 1
* this function is only needed for implementations that allow the
* target to be powered from the debug probe
*/
if (platform_hwversion() == 0) if (platform_hwversion() == 0)
return 0; return gpio_get(GPIOB, GPIO0) ? "OK" : "ABSENT!";
static char ret[] = "0.0V";
const uint8_t channel = 8; const uint8_t channel = 8;
adc_set_regular_sequence(ADC1, 1, (uint8_t*)&channel); adc_set_regular_sequence(ADC1, 1, (uint8_t*)&channel);
@ -315,21 +259,9 @@ uint32_t platform_target_voltage_sense(void)
/* Wait for end of conversion. */ /* Wait for end of conversion. */
while (!adc_eoc(ADC1)); while (!adc_eoc(ADC1));
uint32_t val = adc_read_regular(ADC1); /* 0-4095 */ uint32_t val = adc_read_regular(ADC1) * 99; /* 0-4095 */
/* Clear EOC bit. The GD32F103 does not automatically reset it on ADC read. */ ret[0] = '0' + val / 81910;
ADC_SR(ADC1) &= ~ADC_SR_EOC; ret[2] = '0' + (val / 8191) % 10;
return (val * 99) / 8191;
}
const char *platform_target_voltage(void)
{
if (platform_hwversion() == 0)
return gpio_get(GPIOB, GPIO0) ? "OK" : "ABSENT!";
static char ret[] = "0.0V";
uint32_t val = platform_target_voltage_sense();
ret[0] = '0' + val / 10;
ret[2] = '0' + val % 10;
return ret; return ret;
} }
@ -347,18 +279,7 @@ void platform_request_boot(void)
void exti15_10_isr(void) void exti15_10_isr(void)
{ {
uint32_t usb_vbus_port; if (gpio_get(USB_VBUS_PORT, USB_VBUS_PIN)) {
uint16_t usb_vbus_pin;
if (platform_hwversion() < 5) {
usb_vbus_port = USB_VBUS_PORT;
usb_vbus_pin = USB_VBUS_PIN;
} else {
usb_vbus_port = USB_VBUS5_PORT;
usb_vbus_pin = USB_VBUS5_PIN;
}
if (gpio_get(usb_vbus_port, usb_vbus_pin)) {
/* Drive pull-up high if VBUS connected */ /* Drive pull-up high if VBUS connected */
gpio_set_mode(USB_PU_PORT, GPIO_MODE_OUTPUT_10_MHZ, gpio_set_mode(USB_PU_PORT, GPIO_MODE_OUTPUT_10_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, USB_PU_PIN); GPIO_CNF_OUTPUT_PUSHPULL, USB_PU_PIN);
@ -368,35 +289,24 @@ void exti15_10_isr(void)
GPIO_CNF_INPUT_FLOAT, USB_PU_PIN); GPIO_CNF_INPUT_FLOAT, USB_PU_PIN);
} }
exti_reset_request(usb_vbus_pin); exti_reset_request(USB_VBUS_PIN);
} }
static void setup_vbus_irq(void) static void setup_vbus_irq(void)
{ {
uint32_t usb_vbus_port;
uint16_t usb_vbus_pin;
if (platform_hwversion() < 5) {
usb_vbus_port = USB_VBUS_PORT;
usb_vbus_pin = USB_VBUS_PIN;
} else {
usb_vbus_port = USB_VBUS5_PORT;
usb_vbus_pin = USB_VBUS5_PIN;
}
nvic_set_priority(USB_VBUS_IRQ, IRQ_PRI_USB_VBUS); nvic_set_priority(USB_VBUS_IRQ, IRQ_PRI_USB_VBUS);
nvic_enable_irq(USB_VBUS_IRQ); nvic_enable_irq(USB_VBUS_IRQ);
gpio_set(usb_vbus_port, usb_vbus_pin); gpio_set(USB_VBUS_PORT, USB_VBUS_PIN);
gpio_set(USB_PU_PORT, USB_PU_PIN); gpio_set(USB_PU_PORT, USB_PU_PIN);
gpio_set_mode(usb_vbus_port, GPIO_MODE_INPUT, gpio_set_mode(USB_VBUS_PORT, GPIO_MODE_INPUT,
GPIO_CNF_INPUT_PULL_UPDOWN, usb_vbus_pin); GPIO_CNF_INPUT_PULL_UPDOWN, USB_VBUS_PIN);
/* Configure EXTI for USB VBUS monitor */ /* Configure EXTI for USB VBUS monitor */
exti_select_source(usb_vbus_pin, usb_vbus_port); exti_select_source(USB_VBUS_PIN, USB_VBUS_PORT);
exti_set_trigger(usb_vbus_pin, EXTI_TRIGGER_BOTH); exti_set_trigger(USB_VBUS_PIN, EXTI_TRIGGER_BOTH);
exti_enable_request(usb_vbus_pin); exti_enable_request(USB_VBUS_PIN);
exti15_10_isr(); exti15_10_isr();
} }

View File

@ -38,69 +38,33 @@ extern bool debug_bmp;
int usbuart_debug_write(const char *buf, size_t len); int usbuart_debug_write(const char *buf, size_t len);
#endif #endif
#define PLATFORM_IDENT " " #define BOARD_IDENT "Black Magic Probe"
#define BOARD_IDENT_DFU "Black Magic Probe (Upgrade)"
#define BOARD_IDENT_UPD "Black Magic Probe (DFU Upgrade)"
#define DFU_IDENT "Black Magic Firmware Upgrade"
#define UPD_IFACE_STRING "@Internal Flash /0x08000000/8*001Kg" #define UPD_IFACE_STRING "@Internal Flash /0x08000000/8*001Kg"
/* Hardware version switcher helper
* when the hardware version is smaller than ver
* it outputs opt1, otherwise opt2 */
#define HW_SWITCH(ver, opt1, opt2) \
((platform_hwversion() < (ver))?(opt1):(opt2))
/* Important pin mappings for STM32 implementation: /* Important pin mappings for STM32 implementation:
* *
* LED0 = PB2 (Yellow LED : Running) * LED0 = PB2 (Yellow LED : Running)
* LED1 = PB10 (Orange LED : Idle) * LED1 = PB10 (Yellow LED : Idle)
* LED2 = PB11 (Red LED : Error) * LED2 = PB11 (Red LED : Error)
* *
* TPWR = PB0 (input) -- analogue on mini design ADC1, CH8 * TPWR = PB0 (input) -- analogue on mini design ADC1, ch8
* nTRST = PB1 (output) [blackmagic] * nTRST = PB1 (output) [blackmagic]
* PWR_BR = PB1 (output) [blackmagic_mini] -- supply power to the target, active low * PWR_BR = PB1 (output) [blackmagic_mini] -- supply power to the target, active low
* TMS_DIR = PA1 (output) [blackmagic_mini v2.1] -- choose direction of the TCK pin, input low, output high * TMS_DIR = PA1 (output) [blackmagic_mini v2.1] -- choose direction of the TCK pin, input low, output high
* SRST_OUT = PA2 (output) -- Hardware 5 and older * SRST_OUT = PA2 (output)
* = PA9 (output) -- Hardware 6 and newer * TDI = PA3 (output)
* TDI = PA3 (output) -- Hardware 5 and older
* = PA7 (output) -- Hardware 6 and newer
* TMS = PA4 (input/output for SWDIO) * TMS = PA4 (input/output for SWDIO)
* TCK = PA5 (output SWCLK) * TCK = PA5 (output SWCLK)
* TDO = PA6 (input) * TDO = PA6 (input)
* TRACESWO = PB7 (input) -- To allow trace decoding using USART1 * nSRST = PA7 (input)
* Hardware 4 has a normally open jumper between TDO and TRACESWO
* Hardware 5 has hardwired connection between TDO and TRACESWO
* = PA10 (input) -- Hardware 6 and newer
* nSRST = PA7 (input) -- Hardware 5 and older
* = PC13 (input) -- Hardware 6 and newer
* *
* USB_PU = PA8 (output) * USB cable pull-up: PA8
* USB_VBUS = PB13 (input) -- New on mini design. * USB VBUS detect: PB13 -- New on mini design.
* Enable pull up for compatibility. * Enable pull up for compatibility.
* Hardware 4 and older. (we needed the pin for SPI on 5) * Force DFU mode button: PB12
* = PA15 (input) -- Hardware 5 and newer.
* BTN1 = PB12 (input) -- Force DFU bootloader when pressed during powerup.
*
* UART_TX = PA9 (output) -- USART1 Hardware 5 and older
* = PA2 (output) -- USART2 Hardware 6 and newer
* UART_RX = PA10 (input) -- USART1 Hardware 5 and older
* = PA3 (input) -- USART2 Hardware 6 and newer
*
* On Board OTG Flash: -- Optional on Hardware 5 and newer, since Hardware 6 can be on the main board
* FLASH_CS = PB5 (output)
* SCLK = PB13 (output)
* COPI = PB15 (output)
* CIPO = PB14 (input)
*
* AUX Interface: -- Hardware 5 and newer
* SCLK = PB13 (output)
* COPI = PB15 (output)
* CIPO = PB14 (input)
* FLASH_CS = PB5 (output) -- Only Hardware 5
* SD_CS = PB6 (output) -- Hardware 6 and newer
* DISPLAY_CS = PB6 (output) -- OnlyHardware 5
* = PB7 (output) -- Hardware 6 and newer
* DISPLAY_DC = PB8 (output)
* BTN1 = PB12 (input) -- Shared with the DFU bootloader button
* BTN2 = PB9 (input)
* VBAT = PA0 (input) -- Battery voltage sense ADC2, CH0
*/ */
/* Hardware definitions... */ /* Hardware definitions... */
@ -110,7 +74,7 @@ int usbuart_debug_write(const char *buf, size_t len);
#define TMS_PORT JTAG_PORT #define TMS_PORT JTAG_PORT
#define TCK_PORT JTAG_PORT #define TCK_PORT JTAG_PORT
#define TDO_PORT JTAG_PORT #define TDO_PORT JTAG_PORT
#define TDI_PIN HW_SWITCH(6, GPIO3, GPIO7) #define TDI_PIN GPIO3
#define TMS_DIR_PIN GPIO1 #define TMS_DIR_PIN GPIO1
#define TMS_PIN GPIO4 #define TMS_PIN GPIO4
#define TCK_PIN GPIO5 #define TCK_PIN GPIO5
@ -128,23 +92,17 @@ int usbuart_debug_write(const char *buf, size_t len);
#define PWR_BR_PORT GPIOB #define PWR_BR_PORT GPIOB
#define PWR_BR_PIN GPIO1 #define PWR_BR_PIN GPIO1
#define SRST_PORT GPIOA #define SRST_PORT GPIOA
#define SRST_PIN HW_SWITCH(6, GPIO2, GPIO9) #define SRST_PIN GPIO2
#define SRST_SENSE_PORT GPIOA #define SRST_SENSE_PORT GPIOA
#define SRST_SENSE_PIN HW_SWITCH(6, GPIO7, GPIO13) #define SRST_SENSE_PIN GPIO7
#define USB_PU_PORT GPIOA #define USB_PU_PORT GPIOA
#define USB_PU_PIN GPIO8 #define USB_PU_PIN GPIO8
/* For HW Rev 4 and older */
#define USB_VBUS_PORT GPIOB #define USB_VBUS_PORT GPIOB
#define USB_VBUS_PIN GPIO13 #define USB_VBUS_PIN GPIO13
/* IRQ stays the same for all hw revisions. */
#define USB_VBUS_IRQ NVIC_EXTI15_10_IRQ #define USB_VBUS_IRQ NVIC_EXTI15_10_IRQ
/* For HW Rev 5 and newer */
#define USB_VBUS5_PORT GPIOA
#define USB_VBUS5_PIN GPIO15
#define LED_PORT GPIOB #define LED_PORT GPIOB
#define LED_PORT_UART GPIOB #define LED_PORT_UART GPIOB
#define LED_0 GPIO2 #define LED_0 GPIO2
@ -154,37 +112,6 @@ int usbuart_debug_write(const char *buf, size_t len);
#define LED_IDLE_RUN LED_1 #define LED_IDLE_RUN LED_1
#define LED_ERROR LED_2 #define LED_ERROR LED_2
/* OTG Flash HW Rev 5 and newer */
#define OTG_PORT GPIOB
#define OTG_CS GPIO5
#define OTG_SCLK GPIO13
#define OTG_COPI GPIO15
#define OTG_CIPO GPIO14
/* AUX Port HW Rev 5 and newer */
#define AUX_PORT GPIOB
#define AUX_SCLK_PORT AUX_PORT
#define AUX_COPI_PORT AUX_PORT
#define AUX_CIPO_PORT AUX_PORT
#define AUX_FCS_PORT AUX_PORT
#define AUX_SDCS_PORT AUX_PORT
#define AUX_DCS_PORT AUX_PORT
#define AUX_DDC_PORT AUX_PORT
#define AUX_BTN1_PORT AUX_PORT
#define AUX_BTN2_PORT AUX_PORT
#define AUX_VBAT_PORT GPIOA
#define AUX_SCLK GPIO13
#define AUX_COPI GPIO15
#define AUX_CIPO GPIO14
#define AUX_FCS GPIO5
#define AUX_SDCS GPIO6
#define AUX_DCS GPIO6
#define AUX_DCS6 GPIO7
#define AUX_DDC GPIO8
#define AUX_BTN1 GPIO12
#define AUX_BTN2 GPIO9
#define AUX_VBAT GPIO0
# define SWD_CR GPIO_CRL(SWDIO_PORT) # define SWD_CR GPIO_CRL(SWDIO_PORT)
# define SWD_CR_MULT (1 << (4 << 2)) # define SWD_CR_MULT (1 << (4 << 2))
@ -208,63 +135,39 @@ int usbuart_debug_write(const char *buf, size_t len);
SWD_CR = cr; \ SWD_CR = cr; \
} while(0) } while(0)
#define UART_PIN_SETUP() do { \ #define UART_PIN_SETUP() do { \
gpio_set_mode(USBUSART_PORT, GPIO_MODE_OUTPUT_50_MHZ, \ gpio_set_mode(USBUSART_PORT, GPIO_MODE_OUTPUT_2_MHZ, \
GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, USBUSART_TX_PIN); \ GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, USBUSART_TX_PIN); \
gpio_set_mode(USBUSART_PORT, GPIO_MODE_INPUT, \
GPIO_CNF_INPUT_PULL_UPDOWN, USBUSART_RX_PIN); \
gpio_set(USBUSART_PORT, USBUSART_RX_PIN); \
} while(0) } while(0)
#define USB_DRIVER st_usbfs_v1_usb_driver #define USB_DRIVER st_usbfs_v1_usb_driver
#define USB_IRQ NVIC_USB_LP_CAN_RX0_IRQ #define USB_IRQ NVIC_USB_LP_CAN_RX0_IRQ
#define USB_ISR(x) usb_lp_can_rx0_isr(x) #define USB_ISR usb_lp_can_rx0_isr
/* Interrupt priorities. Low numbers are high priority. /* Interrupt priorities. Low numbers are high priority.
* For now USART1 preempts USB which may spin while buffer is drained.
* TIM3 is used for traceswo capture and must be highest priority. * TIM3 is used for traceswo capture and must be highest priority.
*/ */
#define IRQ_PRI_USB (1 << 4) #define IRQ_PRI_USB (2 << 4)
#define IRQ_PRI_USBUSART (2 << 4) #define IRQ_PRI_USBUSART (1 << 4)
#define IRQ_PRI_USBUSART_DMA (2 << 4) #define IRQ_PRI_USBUSART_TIM (3 << 4)
#define IRQ_PRI_USB_VBUS (14 << 4) #define IRQ_PRI_USB_VBUS (14 << 4)
#define IRQ_PRI_TRACE (0 << 4) #define IRQ_PRI_TRACE (0 << 4)
#define USBUSART HW_SWITCH(6, USBUSART1, USBUSART2) #define USBUSART USART1
#define USBUSART_IRQ HW_SWITCH(6, NVIC_USART1_IRQ, NVIC_USART2_IRQ) #define USBUSART_CR1 USART1_CR1
#define USBUSART_CLK HW_SWITCH(6, RCC_USART1, RCC_USART2) #define USBUSART_IRQ NVIC_USART1_IRQ
#define USBUSART_CLK RCC_USART1
#define USBUSART_PORT GPIOA #define USBUSART_PORT GPIOA
#define USBUSART_TX_PIN HW_SWITCH(6, GPIO9, GPIO2) #define USBUSART_TX_PIN GPIO9
#define USBUSART_RX_PIN HW_SWITCH(6, GPIO10, GPIO3) #define USBUSART_ISR usart1_isr
#define USBUSART_TIM TIM4
#define USBUSART_DMA_BUS DMA1 #define USBUSART_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM4)
#define USBUSART_DMA_CLK RCC_DMA1 #define USBUSART_TIM_IRQ NVIC_TIM4_IRQ
#define USBUSART_DMA_TX_CHAN HW_SWITCH(6, USBUSART1_DMA_TX_CHAN, USBUSART2_DMA_TX_CHAN) #define USBUSART_TIM_ISR tim4_isr
#define USBUSART_DMA_RX_CHAN HW_SWITCH(6, USBUSART1_DMA_RX_CHAN, USBUSART2_DMA_RX_CHAN)
#define USBUSART_DMA_TX_IRQ HW_SWITCH(6, USBUSART1_DMA_TX_IRQ, USBUSART2_DMA_TX_IRQ)
#define USBUSART_DMA_RX_IRQ HW_SWITCH(6, USBUSART1_DMA_RX_IRQ, USBUSART2_DMA_RX_IRQ)
#define USBUSART1 USART1
#define USBUSART1_IRQ NVIC_USART1_IRQ
#define USBUSART1_ISR(x) usart1_isr(x)
#define USBUSART1_DMA_TX_CHAN DMA_CHANNEL4
#define USBUSART1_DMA_TX_IRQ NVIC_DMA1_CHANNEL4_IRQ
#define USBUSART1_DMA_TX_ISR(x) dma1_channel4_isr(x)
#define USBUSART1_DMA_RX_CHAN DMA_CHANNEL5
#define USBUSART1_DMA_RX_IRQ NVIC_DMA1_CHANNEL5_IRQ
#define USBUSART1_DMA_RX_ISR(x) dma1_channel5_isr(x)
#define USBUSART2 USART2
#define USBUSART2_IRQ NVIC_USART2_IRQ
#define USBUSART2_ISR(x) usart2_isr(x)
#define USBUSART2_DMA_TX_CHAN DMA_CHANNEL7
#define USBUSART2_DMA_TX_IRQ NVIC_DMA1_CHANNEL7_IRQ
#define USBUSART2_DMA_TX_ISR(x) dma1_channel7_isr(x)
#define USBUSART2_DMA_RX_CHAN DMA_CHANNEL6
#define USBUSART2_DMA_RX_IRQ NVIC_DMA1_CHANNEL6_IRQ
#define USBUSART2_DMA_RX_ISR(x) dma1_channel6_isr(x)
#define TRACE_TIM TIM3 #define TRACE_TIM TIM3
#define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3) #define TRACE_TIM_CLK_EN() rcc_periph_clock_enable(RCC_TIM3)
#define TRACE_IRQ NVIC_TIM3_IRQ #define TRACE_IRQ NVIC_TIM3_IRQ
#define TRACE_ISR(x) tim3_isr(x) #define TRACE_ISR tim3_isr
#define SET_RUN_STATE(state) {running_status = (state);} #define SET_RUN_STATE(state) {running_status = (state);}
#define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, LED_IDLE_RUN, state);} #define SET_IDLE_STATE(state) {gpio_set_val(LED_PORT, LED_IDLE_RUN, state);}

View File

@ -42,9 +42,9 @@ int main(void)
if(gpio_get(GPIOB, GPIO12)) if(gpio_get(GPIOB, GPIO12))
dfu_jump_app_if_valid(); dfu_jump_app_if_valid();
dfu_protect(false); dfu_protect(DFU_MODE);
rcc_clock_setup_pll(&rcc_hse_configs[RCC_CLOCK_HSE8_72MHZ]); rcc_clock_setup_in_hse_8mhz_out_72mhz();
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8); systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
systick_set_reload(900000); systick_set_reload(900000);
@ -60,7 +60,7 @@ int main(void)
gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, gpio_set_mode(LED_PORT, GPIO_MODE_OUTPUT_2_MHZ,
GPIO_CNF_OUTPUT_PUSHPULL, LED_0 | LED_1 | LED_2); GPIO_CNF_OUTPUT_PUSHPULL, LED_0 | LED_1 | LED_2);
dfu_init(&st_usbfs_v1_usb_driver); dfu_init(&st_usbfs_v1_usb_driver, DFU_MODE);
/* Configure the USB pull up pin. */ /* Configure the USB pull up pin. */
gpio_set(GPIOA, GPIO8); gpio_set(GPIOA, GPIO8);

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the Black Magic Debug project. * This file is part of the Black Magic Debug project.
* *
* Copyright (C) 2019 - 2021 Uwe Bonnes * Copyright (C) 2019 - 2020 Uwe Bonnes
* (bon@elektron.ikp.physik.tu-darmstadt.de) * (bon@elektron.ikp.physik.tu-darmstadt.de)
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -24,17 +24,15 @@
#include "general.h" #include "general.h"
#include <unistd.h> #include <unistd.h>
#include <ctype.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include "version.h"
#include "target.h"
#include "target_internal.h" #include "target_internal.h"
#include "cortexm.h"
#include "command.h"
#include "cl_utils.h" #include "cl_utils.h"
#include "bmp_hosted.h"
#ifndef O_BINARY #ifndef O_BINARY
#define O_BINARY 0 #define O_BINARY 0
@ -45,18 +43,6 @@
# include <sys/mman.h> # include <sys/mman.h>
#endif #endif
static void cl_target_printf(struct target_controller *tc,
const char *fmt, va_list ap)
{
(void)tc;
vprintf(fmt, ap);
}
static struct target_controller cl_controller = {
.printf = cl_target_printf,
};
struct mmap_data { struct mmap_data {
void *data; void *data;
size_t size; size_t size;
@ -127,21 +113,17 @@ static void bmp_munmap(struct mmap_data *map)
#endif #endif
} }
static void cl_help(char **argv) static void cl_help(char **argv, BMP_CL_OPTIONS_t *opt)
{ {
bmp_ident(NULL); DEBUG_WARN("%s for: \n", opt->opt_idstring);
DEBUG_WARN("\tBMP Firmware, ST-Link V2/3, CMSIS_DAP, JLINK and "
"LIBFTDI/MPSSE\n\n");
DEBUG_WARN("Usage: %s [options]\n", argv[0]); DEBUG_WARN("Usage: %s [options]\n", argv[0]);
DEBUG_WARN("\t-h\t\t: This help.\n"); DEBUG_WARN("\t-h\t\t: This help.\n");
DEBUG_WARN("\t-v[bitmask]\t: Increasing verbosity. Bitmask:\n"); DEBUG_WARN("\t-v[bitmask]\t: Increasing verbosity. Bitmask:\n");
DEBUG_WARN("\t\t\t 1 = INFO, 2 = GDB, 4 = TARGET, 8 = PROBE, 16 = WIRE\n"); DEBUG_WARN("\t\t\t 1 = INFO, 2 = GDB, 4 = TARGET, 8 = PROBE, 16 = WIRE\n");
DEBUG_WARN("\t-l\t\t: List available probes\n");
DEBUG_WARN("Probe selection arguments:\n"); DEBUG_WARN("Probe selection arguments:\n");
DEBUG_WARN("\t-d \"path\"\t: Use serial BMP device at <path>"); DEBUG_WARN("\t-d \"path\"\t: Use serial device at \"path\"\n");
#if HOSTED_BMP_ONLY == 1 && defined(__APPLE__)
DEBUG_WARN("\n");
#else
DEBUG_WARN(". Deprecated!\n");
#endif
DEBUG_WARN("\t-P <pos>\t: Use debugger found at position <pos>\n"); DEBUG_WARN("\t-P <pos>\t: Use debugger found at position <pos>\n");
DEBUG_WARN("\t-n <num>\t: Use target device found at position <num>\n"); DEBUG_WARN("\t-n <num>\t: Use target device found at position <num>\n");
DEBUG_WARN("\t-s \"serial\"\t: Use dongle with (partial) " DEBUG_WARN("\t-s \"serial\"\t: Use dongle with (partial) "
@ -151,25 +133,16 @@ static void cl_help(char **argv)
DEBUG_WARN("Run mode related options:\n"); DEBUG_WARN("Run mode related options:\n");
DEBUG_WARN("\tDefault mode is to start the debug server at :2000\n"); DEBUG_WARN("\tDefault mode is to start the debug server at :2000\n");
DEBUG_WARN("\t-j\t\t: Use JTAG. SWD is default.\n"); DEBUG_WARN("\t-j\t\t: Use JTAG. SWD is default.\n");
DEBUG_WARN("\t-f\t\t: Set minimum high and low times of SWJ waveform.\n"); DEBUG_WARN("\t-C\t\t: Connect under reset\n");
DEBUG_WARN("\t-C\t\t: Connect under hardware reset\n");
DEBUG_WARN("\t-t\t\t: Scan SWD or JTAG and display information about \n" DEBUG_WARN("\t-t\t\t: Scan SWD or JTAG and display information about \n"
"\t\t\t connected devices\n"); "\t\t\t connected devices\n");
DEBUG_WARN("\t-T\t\t: Continuous read/write-back some value to allow\n"
"\t\t\t timing insection of SWJ. Abort with ^C\n");
DEBUG_WARN("\t-e\t\t: Assume \"resistor SWD connection\" on FTDI: TDI\n" DEBUG_WARN("\t-e\t\t: Assume \"resistor SWD connection\" on FTDI: TDI\n"
"\t\t\t connected to TMS, TDO to TDI with eventual resistor\n"); "\t\t\t connected to TMS, TDO to TDI with eventual resistor\n");
DEBUG_WARN("\t-E\t\t: Erase flash until flash end or for given size\n"); DEBUG_WARN("\t-E\t\t: Erase flash until flash end or for given size\n");
DEBUG_WARN("\t-w\t\t: Write binary file to target flash (default).\n"); DEBUG_WARN("\t-V\t\t: Verify flash against binary file\n");
DEBUG_WARN("\t-V\t\t: Verify flash against binary file. Can be combined\n"
"\t\t\t with -w to verify right after programming.\n");
DEBUG_WARN("\t-r\t\t: Read flash and write to binary file\n"); DEBUG_WARN("\t-r\t\t: Read flash and write to binary file\n");
DEBUG_WARN("\t-p\t\t: Supplies power to the target (where applicable)\n"); DEBUG_WARN("\t-p\t\t: Supplies power to the target (where applicable)\n");
DEBUG_WARN("\t-R[h]\t\t: Reset device. Default via SWJ or by hardware(h)\n"); DEBUG_WARN("\t-R\t\t: Reset device\n");
DEBUG_WARN("\t-H\t\t: Do not use high level commands (BMP-Remote)\n");
DEBUG_WARN("\t-m <target>\t: Use (target)id for SWD multi-drop.\n");
DEBUG_WARN("\t-M <string>\t: Run target specific monitor commands. Quote multi\n");
DEBUG_WARN("\t\t\t word strings. Run \"-M help\" for help.\n");
DEBUG_WARN("Flash operation modifiers options:\n"); DEBUG_WARN("Flash operation modifiers options:\n");
DEBUG_WARN("\tDefault action with given file is to write to flash\n"); DEBUG_WARN("\tDefault action with given file is to write to flash\n");
DEBUG_WARN("\t-a <addr>\t: Start flash operation at flash address <addr>\n" DEBUG_WARN("\t-a <addr>\t: Start flash operation at flash address <addr>\n"
@ -183,21 +156,15 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
{ {
int c; int c;
opt->opt_target_dev = 1; opt->opt_target_dev = 1;
opt->opt_flash_size = 0xffffffff; opt->opt_flash_size = 16 * 1024 *1024;
opt->opt_flash_start = 0xffffffff; while((c = getopt(argc, argv, "eEhv:d:s:I:c:CnltVta:S:jpP:rR")) != -1) {
opt->opt_max_swj_frequency = 4000000;
while((c = getopt(argc, argv, "eEhHv:d:f:s:I:c:Cln:m:M:wVtTa:S:jpP:rR::")) != -1) {
switch(c) { switch(c) {
case 'c': case 'c':
if (optarg) if (optarg)
opt->opt_cable = optarg; opt->opt_cable = optarg;
break; break;
case 'h': case 'h':
cl_debuglevel = 3; cl_help(argv, opt);
cl_help(argv);
break;
case 'H':
opt->opt_no_hl = true;
break; break;
case 'v': case 'v':
if (optarg) if (optarg)
@ -220,21 +187,6 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
if (optarg) if (optarg)
opt->opt_device = optarg; opt->opt_device = optarg;
break; break;
case 'f':
if (optarg) {
char *p;
uint32_t frequency = strtol(optarg, &p, 10);
switch(*p) {
case 'k':
frequency *= 1000;
break;
case 'M':
frequency *= 1000*1000;
break;
}
opt->opt_max_swj_frequency = frequency;
}
break;
case 's': case 's':
if (optarg) if (optarg)
opt->opt_serial = optarg; opt->opt_serial = optarg;
@ -250,28 +202,13 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
opt->opt_mode = BMP_MODE_TEST; opt->opt_mode = BMP_MODE_TEST;
cl_debuglevel |= BMP_DEBUG_INFO | BMP_DEBUG_STDOUT; cl_debuglevel |= BMP_DEBUG_INFO | BMP_DEBUG_STDOUT;
break; break;
case 'T':
opt->opt_mode = BMP_MODE_SWJ_TEST;
break;
case 'w':
if (opt->opt_mode == BMP_MODE_FLASH_VERIFY)
opt->opt_mode = BMP_MODE_FLASH_WRITE_VERIFY;
else
opt->opt_mode = BMP_MODE_FLASH_WRITE;
break;
case 'V': case 'V':
if (opt->opt_mode == BMP_MODE_FLASH_WRITE)
opt->opt_mode = BMP_MODE_FLASH_WRITE_VERIFY;
else
opt->opt_mode = BMP_MODE_FLASH_VERIFY; opt->opt_mode = BMP_MODE_FLASH_VERIFY;
break; break;
case 'r': case 'r':
opt->opt_mode = BMP_MODE_FLASH_READ; opt->opt_mode = BMP_MODE_FLASH_READ;
break; break;
case 'R': case 'R':
if ((optarg) && (tolower(optarg[0]) == 'h'))
opt->opt_mode = BMP_MODE_RESET_HW;
else
opt->opt_mode = BMP_MODE_RESET; opt->opt_mode = BMP_MODE_RESET;
break; break;
case 'p': case 'p':
@ -285,14 +222,6 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
if (optarg) if (optarg)
opt->opt_target_dev = strtol(optarg, NULL, 0); opt->opt_target_dev = strtol(optarg, NULL, 0);
break; break;
case 'm':
if (optarg)
opt->opt_targetid = strtol(optarg, NULL, 0);
break;
case 'M':
if (optarg)
opt->opt_monitor = optarg;
break;
case 'P': case 'P':
if (optarg) if (optarg)
opt->opt_position = atoi(optarg); opt->opt_position = atoi(optarg);
@ -320,16 +249,10 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
if (opt->opt_mode == BMP_MODE_DEBUG) if (opt->opt_mode == BMP_MODE_DEBUG)
opt->opt_mode = BMP_MODE_FLASH_WRITE; opt->opt_mode = BMP_MODE_FLASH_WRITE;
opt->opt_flash_file = argv[optind]; opt->opt_flash_file = argv[optind];
} else if ((opt->opt_mode == BMP_MODE_DEBUG) &&
(opt->opt_monitor)) {
opt->opt_mode = BMP_MODE_MONITOR; // To avoid DEBUG mode
} }
/* Checks */ /* Checks */
if ((opt->opt_flash_file) && ((opt->opt_mode == BMP_MODE_TEST ) || if ((opt->opt_flash_file) && ((opt->opt_mode == BMP_MODE_TEST ) ||
(opt->opt_mode == BMP_MODE_SWJ_TEST) || (opt->opt_mode == BMP_MODE_RESET))) {
(opt->opt_mode == BMP_MODE_RESET) ||
(opt->opt_mode == BMP_MODE_RESET_HW))) {
DEBUG_WARN("Ignoring filename in reset/test mode\n"); DEBUG_WARN("Ignoring filename in reset/test mode\n");
opt->opt_flash_file = NULL; opt->opt_flash_file = NULL;
} }
@ -338,131 +261,104 @@ void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv)
static void display_target(int i, target *t, void *context) static void display_target(int i, target *t, void *context)
{ {
(void)context; (void)context;
if (!strcmp(target_driver_name(t), "ARM Cortex-M")) {
DEBUG_INFO("***%2d%sUnknown %s Designer %3x Partno %3x %s\n",
i, target_attached(t)?" * ":" ",
target_driver_name(t),
target_designer(t),
target_idcode(t),
(target_core_name(t)) ? target_core_name(t): "");
} else {
DEBUG_INFO("*** %2d %c %s %s\n", i, target_attached(t)?'*':' ', DEBUG_INFO("*** %2d %c %s %s\n", i, target_attached(t)?'*':' ',
target_driver_name(t), target_driver_name(t),
(target_core_name(t)) ? target_core_name(t): ""); (target_core_name(t)) ? target_core_name(t): "");
} }
}
int cl_execute(BMP_CL_OPTIONS_t *opt) int cl_execute(BMP_CL_OPTIONS_t *opt)
{ {
int res = 0; int res = -1;
int num_targets; int num_targets;
#if defined(PLATFORM_HAS_POWER_SWITCH)
if (opt->opt_tpwr) { if (opt->opt_tpwr) {
DEBUG_INFO("Powering up device");
platform_target_set_power(true); platform_target_set_power(true);
platform_delay(500); platform_delay(500);
} }
if (opt->opt_mode == BMP_MODE_RESET_HW) { #endif
platform_srst_set_val(true);
platform_delay(1);
platform_srst_set_val(false);
return res;
}
if (opt->opt_connect_under_reset) if (opt->opt_connect_under_reset)
DEBUG_INFO("Connecting under reset\n"); DEBUG_INFO("Connecting under reset\n");
connect_assert_srst = opt->opt_connect_under_reset; connect_assert_srst = opt->opt_connect_under_reset;
platform_srst_set_val(opt->opt_connect_under_reset); platform_srst_set_val(opt->opt_connect_under_reset);
if (opt->opt_mode == BMP_MODE_TEST) if (opt->opt_mode == BMP_MODE_TEST)
DEBUG_INFO("Running in Test Mode\n"); DEBUG_INFO("Running in Test Mode\n");
if (platform_target_voltage())
DEBUG_INFO("Target voltage: %s Volt\n", platform_target_voltage()); DEBUG_INFO("Target voltage: %s Volt\n", platform_target_voltage());
if (opt->opt_usejtag) { if (opt->opt_usejtag) {
num_targets = platform_jtag_scan(NULL); num_targets = platform_jtag_scan(NULL);
} else { } else {
num_targets = platform_adiv5_swdp_scan(opt->opt_targetid); num_targets = platform_adiv5_swdp_scan();
if (!num_targets) {
DEBUG_INFO("Scan SWD failed, trying JTAG!\n");
num_targets = platform_jtag_scan(NULL);
}
} }
if (!num_targets) { if (!num_targets) {
DEBUG_WARN("No target found\n"); DEBUG_WARN("No target found\n");
return -1; return res;
} else { } else {
num_targets = target_foreach(display_target, &num_targets); target_foreach(display_target, NULL);
} }
if (opt->opt_target_dev > num_targets) { if (opt->opt_target_dev > num_targets) {
DEBUG_WARN("Given target number %d not available max %d\n", DEBUG_WARN("Given target nummer %d not available\n",
opt->opt_target_dev, num_targets); opt->opt_target_dev);
return -1; return res;
} }
target *t = target_attach_n(opt->opt_target_dev, &cl_controller); target *t = target_attach_n(opt->opt_target_dev, NULL);
if (!t) { if (!t) {
DEBUG_WARN("Can not attach to target %d\n", opt->opt_target_dev); DEBUG_WARN("Can not attach to target %d\n", opt->opt_target_dev);
res = -1;
goto target_detach; goto target_detach;
} }
/* List each defined RAM */
int n_ram = 0;
for (struct target_ram *r = t->ram; r; r = r->next)
n_ram++;
for (int n = n_ram; n >= 0; n --) {
struct target_ram *r = t->ram;
for (int i = 1; r; r = r->next, i++)
if (i == n)
DEBUG_INFO("RAM Start: 0x%08" PRIx32 " length = 0x%" PRIx32 "\n",
r->start, (uint32_t)r->length);
}
/* Always scan memory map to find lowest flash */ /* Always scan memory map to find lowest flash */
/* List each defined Flash */ char memory_map [1024], *p = memory_map;
uint32_t lowest_flash_start = 0xffffffff; uint32_t flash_start = 0xffffffff;
uint32_t lowest_flash_size = 0; if (target_mem_map(t, memory_map, sizeof(memory_map))) {
int n_flash = 0; while (*p && (*p == '<')) {
for (struct target_flash *f = t->flash; f; f = f->next) unsigned int start, size;
n_flash++; char *res;
for (int n = n_flash; n >= 0; n --) { int match;
struct target_flash *f = t->flash; match = strncmp(p, "<memory-map>", strlen("<memory-map>"));
for (int i = 1; f; f = f->next, i++) if (!match) {
if (i == n) { p += strlen("<memory-map>");
DEBUG_INFO("Flash Start: 0x%08" PRIx32 " length = 0x%" PRIx32 continue;
" blocksize 0x%" PRIx32 "\n", }
f->start, (uint32_t)f->length, (uint32_t)f->blocksize); match = strncmp(p, "<memory type=\"flash\" ", strlen("<memory type=\"flash\" "));
if (f->start < lowest_flash_start) { if (!match) {
lowest_flash_start = f->start; unsigned int blocksize;
lowest_flash_size = f->length; if (sscanf(p, "<memory type=\"flash\" start=\"%x\" length=\"%x\">"
"<property name=\"blocksize\">%x</property></memory>",
&start, &size, &blocksize)) {
if (opt->opt_mode == BMP_MODE_TEST)
DEBUG_INFO("Flash Start: 0x%08x, length %#9x, "
"blocksize %#8x\n", start, size, blocksize);
if (start < flash_start)
flash_start = start;
}
res = strstr(p, "</memory>");
p = res + strlen("</memory>");
continue;
}
match = strncmp(p, "<memory type=\"ram\" ", strlen("<memory type=\"ram\" "));
if (!match) {
if (sscanf(p, "<memory type=\"ram\" start=\"%x\" length=\"%x\"/",
&start, &size))
if (opt->opt_mode == BMP_MODE_TEST)
DEBUG_INFO("Ram Start: 0x%08x, length %#9x\n",
start, size);
res = strstr(p, "/>");
p = res + strlen("/>");
continue;
}
break;
} }
} }
} if (opt->opt_flash_start < flash_start)
if (opt->opt_flash_start == 0xffffffff) opt->opt_flash_start = flash_start;
opt->opt_flash_start = lowest_flash_start; if (opt->opt_mode == BMP_MODE_TEST)
if ((opt->opt_flash_size == 0xffffffff) &&
(opt->opt_mode != BMP_MODE_FLASH_WRITE) &&
(opt->opt_mode != BMP_MODE_FLASH_VERIFY) &&
(opt->opt_mode != BMP_MODE_FLASH_WRITE_VERIFY))
opt->opt_flash_size = lowest_flash_size;
if (opt->opt_mode == BMP_MODE_SWJ_TEST) {
switch (t->core[0]) {
case 'M':
DEBUG_WARN("Continuous read/write-back DEMCR. Abort with ^C\n");
while(1) {
uint32_t demcr;
target_mem_read(t, &demcr, CORTEXM_DEMCR, 4);
target_mem_write32(t, CORTEXM_DEMCR, demcr);
platform_delay(1); /* To allow trigger*/
}
default:
DEBUG_WARN("No test for this core type yet\n");
}
}
if ((opt->opt_mode == BMP_MODE_TEST) ||
(opt->opt_mode == BMP_MODE_SWJ_TEST))
goto target_detach; goto target_detach;
int read_file = -1; int read_file = -1;
if ((opt->opt_mode == BMP_MODE_FLASH_WRITE) || if ((opt->opt_mode == BMP_MODE_FLASH_WRITE) ||
(opt->opt_mode == BMP_MODE_FLASH_VERIFY) || (opt->opt_mode == BMP_MODE_FLASH_VERIFY)) {
(opt->opt_mode == BMP_MODE_FLASH_WRITE_VERIFY)) {
int mmap_res = bmp_mmap(opt->opt_flash_file, &map); int mmap_res = bmp_mmap(opt->opt_flash_file, &map);
if (mmap_res) { if (mmap_res) {
DEBUG_WARN("Can not map file: %s. Aborting!\n", strerror(errno)); DEBUG_WARN("Can not map file: %s. Aborting!\n", strerror(errno));
res = -1;
goto target_detach; goto target_detach;
} }
} else if (opt->opt_mode == BMP_MODE_FLASH_READ) { } else if (opt->opt_mode == BMP_MODE_FLASH_READ) {
@ -472,18 +368,12 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
if (read_file == -1) { if (read_file == -1) {
DEBUG_WARN("Error opening flashfile %s for read: %s\n", DEBUG_WARN("Error opening flashfile %s for read: %s\n",
opt->opt_flash_file, strerror(errno)); opt->opt_flash_file, strerror(errno));
res = -1; return res;
goto target_detach;
} }
} }
if (opt->opt_flash_size < map.size) if (opt->opt_flash_size < map.size)
/* restrict to size given on command line */ /* restrict to size given on command line */
map.size = opt->opt_flash_size; map.size = opt->opt_flash_size;
if (opt->opt_monitor) {
res = command_process(t, opt->opt_monitor);
if (res)
DEBUG_WARN("Command \"%s\" failed\n", opt->opt_monitor);
}
if (opt->opt_mode == BMP_MODE_RESET) { if (opt->opt_mode == BMP_MODE_RESET) {
target_reset(t); target_reset(t);
} else if (opt->opt_mode == BMP_MODE_FLASH_ERASE) { } else if (opt->opt_mode == BMP_MODE_FLASH_ERASE) {
@ -492,21 +382,18 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
unsigned int erased = target_flash_erase(t, opt->opt_flash_start, unsigned int erased = target_flash_erase(t, opt->opt_flash_start,
opt->opt_flash_size); opt->opt_flash_size);
if (erased) { if (erased) {
DEBUG_WARN("Erasure failed!\n"); DEBUG_WARN("Erased failed!\n");
res = -1;
goto free_map; goto free_map;
} }
target_reset(t); target_reset(t);
} else if ((opt->opt_mode == BMP_MODE_FLASH_WRITE) || } else if (opt->opt_mode == BMP_MODE_FLASH_WRITE) {
(opt->opt_mode == BMP_MODE_FLASH_WRITE_VERIFY)) {
DEBUG_INFO("Erase %zu bytes at 0x%08" PRIx32 "\n", map.size, DEBUG_INFO("Erase %zu bytes at 0x%08" PRIx32 "\n", map.size,
opt->opt_flash_start); opt->opt_flash_start);
uint32_t start_time = platform_time_ms(); uint32_t start_time = platform_time_ms();
unsigned int erased = target_flash_erase(t, opt->opt_flash_start, unsigned int erased = target_flash_erase(t, opt->opt_flash_start,
map.size); map.size);
if (erased) { if (erased) {
DEBUG_WARN("Erasure failed!\n"); DEBUG_WARN("Erased failed!\n");
res = -1;
goto free_map; goto free_map;
} else { } else {
DEBUG_INFO("Flashing %zu bytes at 0x%08" PRIx32 "\n", DEBUG_INFO("Flashing %zu bytes at 0x%08" PRIx32 "\n",
@ -514,34 +401,25 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
unsigned int flashed = target_flash_write(t, opt->opt_flash_start, unsigned int flashed = target_flash_write(t, opt->opt_flash_start,
map.data, map.size); map.data, map.size);
/* Buffered write cares for padding*/ /* Buffered write cares for padding*/
if (!flashed)
flashed = target_flash_done(t);
if (flashed) { if (flashed) {
DEBUG_WARN("Flashing failed!\n"); DEBUG_WARN("Flashing failed!\n");
res = -1;
goto free_map;
} else { } else {
DEBUG_INFO("Success!\n"); DEBUG_INFO("Success!\n");
res = 0;
} }
} }
target_flash_done(t);
target_reset(t);
uint32_t end_time = platform_time_ms(); uint32_t end_time = platform_time_ms();
DEBUG_WARN("Flash Write succeeded for %d bytes, %8.3f kiB/s\n", DEBUG_WARN("Flash Write succeeded for %d bytes, %8.3f kiB/s\n",
(int)map.size, (((map.size * 1.0)/(end_time - start_time)))); (int)map.size, (((map.size * 1.0)/(end_time - start_time))));
if (opt->opt_mode != BMP_MODE_FLASH_WRITE_VERIFY) { } else {
target_reset(t); #define WORKSIZE 1024
goto free_map;
}
}
if ((opt->opt_mode == BMP_MODE_FLASH_READ) ||
(opt->opt_mode == BMP_MODE_FLASH_VERIFY) ||
(opt->opt_mode == BMP_MODE_FLASH_WRITE_VERIFY)) {
#define WORKSIZE 0x1000
uint8_t *data = alloca(WORKSIZE); uint8_t *data = alloca(WORKSIZE);
if (!data) { if (!data) {
DEBUG_WARN("Can not malloc memory for flash read/verify " DEBUG_WARN("Can not malloc memory for flash read/verify "
"operation\n"); "operation\n");
res = -1; return res;
goto free_map;
} }
if (opt->opt_mode == BMP_MODE_FLASH_READ) if (opt->opt_mode == BMP_MODE_FLASH_READ)
DEBUG_INFO("Reading flash from 0x%08" PRIx32 " for %zu" DEBUG_INFO("Reading flash from 0x%08" PRIx32 " for %zu"
@ -569,14 +447,12 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
} else { } else {
bytes_read += worksize; bytes_read += worksize;
} }
if ((opt->opt_mode == BMP_MODE_FLASH_VERIFY) || if (opt->opt_mode == BMP_MODE_FLASH_VERIFY) {
(opt->opt_mode == BMP_MODE_FLASH_WRITE_VERIFY)) {
int difference = memcmp(data, flash, worksize); int difference = memcmp(data, flash, worksize);
if (difference){ if (difference){
DEBUG_WARN("Verify failed at flash region 0x%08" DEBUG_WARN("Verify failed at flash region 0x%08"
PRIx32 "\n", flash_src); PRIx32 "\n", flash_src);
res = -1; return -1;
goto free_map;
} }
flash += worksize; flash += worksize;
} else if (read_file != -1) { } else if (read_file != -1) {
@ -584,21 +460,19 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
if (written < worksize) { if (written < worksize) {
DEBUG_WARN("Read failed at flash region 0x%08" PRIx32 "\n", DEBUG_WARN("Read failed at flash region 0x%08" PRIx32 "\n",
flash_src); flash_src);
res = -1; return -1;
goto free_map;
} }
} }
flash_src += worksize; flash_src += worksize;
size -= worksize; size -= worksize;
if (size <= 0)
res = 0;
} }
uint32_t end_time = platform_time_ms(); uint32_t end_time = platform_time_ms();
if (read_file != -1) if (read_file != -1)
close(read_file); close(read_file);
DEBUG_WARN("Read/Verify succeeded for %d bytes, %8.3f kiB/s\n", DEBUG_WARN("Read/Verify succeeded for %d bytes, %8.3f kiB/s\n",
bytes_read, bytes_read, (((bytes_read * 1.0)/(end_time - start_time))));
(((bytes_read * 1.0)/(end_time - start_time))));
if (opt->opt_mode == BMP_MODE_FLASH_WRITE_VERIFY)
target_reset(t);
} }
free_map: free_map:
if (map.size) if (map.size)
@ -606,6 +480,5 @@ int cl_execute(BMP_CL_OPTIONS_t *opt)
target_detach: target_detach:
if (t) if (t)
target_detach(t); target_detach(t);
target_list_free();
return res; return res;
} }

View File

@ -1,7 +1,7 @@
/* /*
* This file is part of the Black Magic Debug project. * This file is part of the Black Magic Debug project.
* *
* Copyright (C) 2019 - 2021 Uwe Bonnes * Copyright (C) 2019 - 2020 Uwe Bonnes
* Written by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de) * Written by Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -24,20 +24,16 @@
#if !defined(__CL_UTILS_H) #if !defined(__CL_UTILS_H)
#define __CL_UTILS_H #define __CL_UTILS_H
#include "cortexm.h" #define RESP_TIMEOUT (100)
enum bmp_cl_mode { enum bmp_cl_mode {
BMP_MODE_DEBUG, BMP_MODE_DEBUG,
BMP_MODE_TEST, BMP_MODE_TEST,
BMP_MODE_RESET, BMP_MODE_RESET,
BMP_MODE_RESET_HW,
BMP_MODE_FLASH_ERASE, BMP_MODE_FLASH_ERASE,
BMP_MODE_FLASH_WRITE, BMP_MODE_FLASH_WRITE,
BMP_MODE_FLASH_WRITE_VERIFY,
BMP_MODE_FLASH_READ, BMP_MODE_FLASH_READ,
BMP_MODE_FLASH_VERIFY, BMP_MODE_FLASH_VERIFY
BMP_MODE_SWJ_TEST,
BMP_MODE_MONITOR,
}; };
typedef struct BMP_CL_OPTIONS_s { typedef struct BMP_CL_OPTIONS_s {
@ -47,20 +43,17 @@ typedef struct BMP_CL_OPTIONS_s {
bool opt_list_only; bool opt_list_only;
bool opt_connect_under_reset; bool opt_connect_under_reset;
bool external_resistor_swd; bool external_resistor_swd;
bool opt_no_hl;
char *opt_flash_file; char *opt_flash_file;
char *opt_device; char *opt_device;
char *opt_serial; char *opt_serial;
uint32_t opt_targetid;
char *opt_ident_string; char *opt_ident_string;
int opt_position; int opt_position;
char *opt_cable; char *opt_cable;
char *opt_monitor;
int opt_debuglevel; int opt_debuglevel;
int opt_target_dev; int opt_target_dev;
uint32_t opt_flash_start; uint32_t opt_flash_start;
uint32_t opt_max_swj_frequency;
size_t opt_flash_size; size_t opt_flash_size;
char *opt_idstring;
}BMP_CL_OPTIONS_t; }BMP_CL_OPTIONS_t;
void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv); void cl_init(BMP_CL_OPTIONS_t *opt, int argc, char **argv);

View File

@ -36,11 +36,13 @@
# include <fcntl.h> # include <fcntl.h>
#endif #endif
#include "general.h" #include <stdio.h>
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
#include "general.h"
#include "gdb_if.h" #include "gdb_if.h"
static int gdb_if_serv, gdb_if_conn; static int gdb_if_serv, gdb_if_conn;
@ -49,13 +51,8 @@ static int gdb_if_serv, gdb_if_conn;
int gdb_if_init(void) int gdb_if_init(void)
{ {
#if defined(_WIN32) || defined(__CYGWIN__) #if defined(_WIN32) || defined(__CYGWIN__)
int iResult;
WSADATA wsaData; WSADATA wsaData;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
DEBUG_WARN("WSAStartup failed with error: %ld\n", iResult);
exit(1);
}
#endif #endif
struct sockaddr_in addr; struct sockaddr_in addr;
int opt; int opt;
@ -70,47 +67,23 @@ int gdb_if_init(void)
addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_addr.s_addr = htonl(INADDR_ANY);
gdb_if_serv = socket(PF_INET, SOCK_STREAM, 0); gdb_if_serv = socket(PF_INET, SOCK_STREAM, 0);
if (gdb_if_serv == -1) { if (gdb_if_serv == -1)
DEBUG_WARN("PF_INET %d\n",gdb_if_serv);
continue; continue;
}
opt = 1; opt = 1;
if (setsockopt(gdb_if_serv, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(opt)) == -1) { if (setsockopt(gdb_if_serv, SOL_SOCKET, SO_REUSEADDR, (void*)&opt, sizeof(opt)) == -1) {
#if defined(_WIN32) || defined(__CYGWIN__)
DEBUG_WARN("error setsockopt SOL_SOCKET : %d error: %d\n", gdb_if_serv,
WSAGetLastError());
#else
DEBUG_WARN("error setsockopt SOL_SOCKET : %d error: %d\n", gdb_if_serv,
strerror(errno));
#endif
close(gdb_if_serv); close(gdb_if_serv);
continue; continue;
} }
if (setsockopt(gdb_if_serv, IPPROTO_TCP, TCP_NODELAY, (void*)&opt, sizeof(opt)) == -1) { if (setsockopt(gdb_if_serv, IPPROTO_TCP, TCP_NODELAY, (void*)&opt, sizeof(opt)) == -1) {
#if defined(_WIN32) || defined(__CYGWIN__)
DEBUG_WARN("error setsockopt IPPROTO_TCP : %d error: %d\n", gdb_if_serv,
WSAGetLastError());
#else
DEBUG_WARN("error setsockopt IPPROTO_TCP : %d error: %d\n", gdb_if_serv,
strerror(errno));
#endif
close(gdb_if_serv); close(gdb_if_serv);
continue; continue;
} }
if (bind(gdb_if_serv, (void*)&addr, sizeof(addr)) == -1) { if (bind(gdb_if_serv, (void*)&addr, sizeof(addr)) == -1) {
#if defined(_WIN32) || defined(__CYGWIN__)
DEBUG_WARN("error when binding socket: %d error: %d\n", gdb_if_serv,
WSAGetLastError());
#else
DEBUG_WARN("error when binding socket: %d error: %d\n", gdb_if_serv,
strerror(errno));
#endif
close(gdb_if_serv); close(gdb_if_serv);
continue; continue;
} }
if (listen(gdb_if_serv, 1) == -1) { if (listen(gdb_if_serv, 1) == -1) {
DEBUG_WARN("listen closed %d\n",gdb_if_serv);
close(gdb_if_serv); close(gdb_if_serv);
continue; continue;
} }
@ -127,7 +100,6 @@ unsigned char gdb_if_getchar(void)
unsigned char ret; unsigned char ret;
int i = 0; int i = 0;
#if defined(_WIN32) || defined(__CYGWIN__) #if defined(_WIN32) || defined(__CYGWIN__)
int iResult;
unsigned long opt; unsigned long opt;
#else #else
int flags; int flags;
@ -136,10 +108,7 @@ unsigned char gdb_if_getchar(void)
if(gdb_if_conn <= 0) { if(gdb_if_conn <= 0) {
#if defined(_WIN32) || defined(__CYGWIN__) #if defined(_WIN32) || defined(__CYGWIN__)
opt = 1; opt = 1;
iResult = ioctlsocket(gdb_if_serv, FIONBIO, &opt); ioctlsocket(gdb_if_serv, FIONBIO, &opt);
if (iResult != NO_ERROR) {
DEBUG_WARN("ioctlsocket failed with error: %ld\n", iResult);
}
#else #else
flags = fcntl(gdb_if_serv, F_GETFL); flags = fcntl(gdb_if_serv, F_GETFL);
fcntl(gdb_if_serv, F_SETFL, flags | O_NONBLOCK); fcntl(gdb_if_serv, F_SETFL, flags | O_NONBLOCK);

View File

@ -61,7 +61,9 @@ extern "C" {
} /* extern "C" */ } /* extern "C" */
#endif #endif
#include <general.h> #include <stdio.h>
#include <stdlib.h>
#include "hidapi.h" #include "hidapi.h"

View File

@ -0,0 +1,138 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "general.h"
#include "cl_utils.h"
static void LIBUSB_CALL on_trans_done(struct libusb_transfer *trans)
{
struct trans_ctx * const ctx = trans->user_data;
if (trans->status != LIBUSB_TRANSFER_COMPLETED)
{
DEBUG_WARN("on_trans_done: ");
if(trans->status == LIBUSB_TRANSFER_TIMED_OUT) {
DEBUG_WARN(" Timeout\n");
} else if (trans->status == LIBUSB_TRANSFER_CANCELLED) {
DEBUG_WARN(" cancelled\n");
} else if (trans->status == LIBUSB_TRANSFER_NO_DEVICE) {
DEBUG_WARN(" no device\n");
} else {
DEBUG_WARN(" unknown\n");
}
ctx->flags |= TRANS_FLAGS_HAS_ERROR;
}
ctx->flags |= TRANS_FLAGS_IS_DONE;
}
static int submit_wait(usb_link_t *link, struct libusb_transfer *trans) {
struct trans_ctx trans_ctx;
enum libusb_error error;
trans_ctx.flags = 0;
/* brief intrusion inside the libusb interface */
trans->callback = on_trans_done;
trans->user_data = &trans_ctx;
if ((error = libusb_submit_transfer(trans))) {
DEBUG_WARN("libusb_submit_transfer(%d): %s\n", error,
libusb_strerror(error));
exit(-1);
}
uint32_t start_time = platform_time_ms();
while (trans_ctx.flags == 0) {
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
if (libusb_handle_events_timeout(link->ul_libusb_ctx, &timeout)) {
DEBUG_WARN("libusb_handle_events()\n");
return -1;
}
uint32_t now = platform_time_ms();
if (now - start_time > 1000) {
libusb_cancel_transfer(trans);
DEBUG_WARN("libusb_handle_events() timeout\n");
return -1;
}
}
if (trans_ctx.flags & TRANS_FLAGS_HAS_ERROR) {
DEBUG_WARN("libusb_handle_events() | has_error\n");
return -1;
}
return 0;
}
/* One USB transaction */
int send_recv(usb_link_t *link,
uint8_t *txbuf, size_t txsize,
uint8_t *rxbuf, size_t rxsize)
{
int res = 0;
if( txsize) {
int txlen = txsize;
libusb_fill_bulk_transfer(link->req_trans,
link->ul_libusb_device_handle,
link->ep_tx | LIBUSB_ENDPOINT_OUT,
txbuf, txlen,
NULL, NULL, 0);
int i = 0;
DEBUG_WIRE(" Send (%3d): ", txlen);
for (; i < txlen; i++) {
DEBUG_WIRE("%02x", txbuf[i]);
if ((i & 7) == 7)
DEBUG_WIRE(".");
if ((i & 31) == 31)
DEBUG_WIRE("\n ");
}
if (!(i & 31))
DEBUG_WIRE("\n");
if (submit_wait(link, link->req_trans)) {
libusb_clear_halt(link->ul_libusb_device_handle, link->ep_tx);
return -1;
}
}
/* send_only */
if (rxsize != 0) {
/* read the response */
libusb_fill_bulk_transfer(link->rep_trans, link->ul_libusb_device_handle,
link->ep_rx | LIBUSB_ENDPOINT_IN,
rxbuf, rxsize, NULL, NULL, 0);
if (submit_wait(link, link->rep_trans)) {
DEBUG_WARN("clear 1\n");
libusb_clear_halt(link->ul_libusb_device_handle, link->ep_rx);
return -1;
}
res = link->rep_trans->actual_length;
if (res >0) {
int i;
uint8_t *p = rxbuf;
DEBUG_WIRE(" Rec (%zu/%d)", rxsize, res);
for (i = 0; i < res && i < 32 ; i++) {
if ( i && ((i & 7) == 0))
DEBUG_WIRE(".");
DEBUG_WIRE("%02x", p[i]);
}
}
}
DEBUG_WIRE("\n");
return res;
}

View File

@ -0,0 +1,41 @@
/*
* This file is part of the Black Magic Debug project.
*
* Copyright (C) 2020 Uwe Bonnes (bon@elektron.ikp.physik.tu-darmstadt.de)
*
* 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/>.
*/
#if !defined(__LIBUSB_UTILS_H)
#define __LIBUSB_UTILS_H
#include <libusb-1.0/libusb.h>
struct trans_ctx {
#define TRANS_FLAGS_IS_DONE (1 << 0)
#define TRANS_FLAGS_HAS_ERROR (1 << 1)
volatile unsigned long flags;
};
typedef struct {
libusb_context *ul_libusb_ctx;
libusb_device_handle *ul_libusb_device_handle;
unsigned char ep_tx;
unsigned char ep_rx;
struct libusb_transfer* req_trans;
struct libusb_transfer* rep_trans;
void *priv;
} usb_link_t;
int send_recv(usb_link_t *link, uint8_t *txbuf, size_t txsize,
uint8_t *rxbuf, size_t rxsize);
#endif

Some files were not shown because too many files have changed in this diff Show More