Compare commits

...

24 Commits

Author SHA1 Message Date
Jonathan Bell
53875ec320 Debugprobe release v2.2.1
This release is a point release because unknown/stale submodule(s)
caused a regression with long UART TX strings that subsequently could
not be reproduced.

The build artifacts for this release were compiled on a Raspberry Pi 5
running Raspberry Pi OS (Debian 12) instead of Ubuntu 22.04 on amd64.
2025-01-09 14:49:12 +00:00
Jonathan Bell
9226fac61a Debugprobe release v2.2.0 2024-12-03 13:16:13 +00:00
Jonathan Bell
06c7792560 main: kludge for Pi 5 reboot crashes
The Pi 5 bootloader will leave devices it doesn't care about in the
Addressed state, so tud_mount_cb never gets called. Handoff from the
bootloader to Linux causes a suspend event followed by Reset.

Check if the interface association was configured on entry to Suspend or
Resume. Also, TinyUSB doesn't expose Bus Reset events for whatever
reason, so there's nothing that tears down the interface threads.
2024-12-03 11:48:25 +00:00
Jonathan Bell
1752f2a61b CMmakeLists.txt: add pico2 variant target naming 2024-11-29 10:02:49 +00:00
Jonathan Bell
e887004fdf Debugprobe release v2.1.0 2024-11-27 15:48:41 +00:00
Jonathan Bell
df68d70400 Fix PORT_SWD/PORT_OFF mismatch - do GPIO setup in each 2024-11-27 15:48:41 +00:00
Jonathan Bell
0c84dd0dc1 FreeRTOS: use upstream port again, RP2350 support has landed
But the RP2350 kernel import is broken, use copy from pico-examples 2.1.0
2024-11-27 15:10:38 +00:00
Jonathan Bell
4238b780c2 main: handle RP2040's broken USB error handling
RP2040-E15 can also be triggered if a Debug Probe is connected to a
board with a floating ground. Typically this causes port ESD protection
to temporarily activate, meaning the Dp/Dm state gets corrupted. If this
happens in the middle of a handshake packet, the SIE can lock up.

The only way to detect this case is if SOF_RD stops advancing without a
corresponding suspend interrupt - so add a watchdog thread that forces a
disconnect if the hardware stops reporting frame counts.

This is disruptive, but immediate notification that the probe broke is
preferable to silently failing until the next character is sent by the host.

Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
2024-11-27 14:19:33 +00:00
Jonathan Bell
189e367332 main: add callbacks for discrete USB states
We can save more power by parking threads when suspended, and threads
should be deleted when disconnected.

Also fix an inefficiency in usb_thread wakeups when the device is yet to
be configured, but is addressed - slowing down control transfers.

Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
2024-11-27 14:19:33 +00:00
Jonathan Bell
d9c507f579 dap_edpt_driver: handle deinit properly
Zap pending buffers if the interface went away.
Also fix -Wformat warnings.

Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
2024-11-27 14:19:33 +00:00
Jonathan Bell
6d2f83e30c cdc_uart: be more careful about when the thread gets parked or resumed
tud_cdc_connected tests dtr, not rts - so we should do the same.

Don't unconditionally wake the uart thread when set_line_coding happens
- Windows frequently calls this after every linestate change, including
device close.

Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
2024-11-27 14:19:33 +00:00
Jonathan Bell
1182803822 probe: revert pins to Hi-Z when PORT_OFF is called
Alternative implementation of #146
Fixes #146
2024-11-27 14:10:51 +00:00
Andrew Burge
65b1e73589 Where enabled: Add calls to set the various xxx_LED status lines as GPIO outputs
Signed-off-by: Andrew Burge <andrew.burge@raspberrypi.com>
2024-11-27 11:03:04 +00:00
Jonathan Bell
152f85d2ec Specify MIT license as the project's default.
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
2024-11-27 10:58:50 +00:00
Jonathan Bell
d85fd1f58d Remove unattributed contributions from the project
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
2024-11-27 10:45:59 +00:00
Jonathan Bell
8f5d6fcc9f Clarify pico_sdk_import.cmake license
This file was copied from the pico-sdk, which is a BSD 3-Clause project.
2024-11-20 11:21:58 +00:00
Jonathan Bell
9aed4ca509 Add license and copyright to probe_oen.pio
This file is directly attributable to Raspberry Pi.
2024-11-20 11:12:09 +00:00
Jonathan Bell
e4585d551a probe: don't include pio headers directly 2024-11-07 15:13:03 +00:00
Jonathan Bell
46b9613d14 Update to support building for Pico 2
- Update CMSIS to 5.7.0
- Update FreeRTOS to downstream commit aa52f214d

Note: for an existing repository clone, you must run
git submodule update --init
and delete and regenerate your build/ directory.
2024-08-08 14:40:22 +01:00
Jonathan Bell
2bbe900d68 Debugprobe release 2.0.1 2024-04-16 13:43:17 +01:00
tanxiao
7410b45e1d rename PROBE_IO_SWDIOEN to PROBE_IO_OEN 2024-03-26 19:12:28 +00:00
tanxiao
920f717e71 Add pin names to binary information 2024-03-26 19:12:28 +00:00
Taylor Alexander
34a4ba0e01 Fix incorrect LED ifdefs 2024-03-26 19:11:14 +00:00
Jonathan Bell
0476e9cae5 cdc_uart: add missing clear-break reset of TX LED 2024-03-19 14:49:41 +00:00
20 changed files with 352 additions and 146 deletions

View File

@@ -9,8 +9,12 @@ project(debugprobe)
pico_sdk_init()
if (${PICO_SDK_VERSION_MAJOR} LESS 2)
message(SEND_ERROR "Version 2 of the Pico SDK is required to compile this project. Please update your installation at ${PICO_SDK_PATH}")
endif ()
add_executable(debugprobe
src/led.c
src/probe_config.c
src/main.c
src/usb_descriptors.c
src/probe.c
@@ -47,12 +51,20 @@ target_compile_definitions (debugprobe PRIVATE
option (DEBUG_ON_PICO "Compile firmware for the Pico instead of Debug Probe" OFF)
if (DEBUG_ON_PICO)
target_compile_definitions (debugprobe PRIVATE
target_compile_definitions (debugprobe PRIVATE
DEBUG_ON_PICO=1
)
set_target_properties(debugprobe PROPERTIES
OUTPUT_NAME "debugprobe_on_pico"
)
if (PICO_BOARD STREQUAL "pico")
set_target_properties(debugprobe PROPERTIES
OUTPUT_NAME "debugprobe_on_pico"
)
elseif (PICO_BOARD STREQUAL "pico2")
set_target_properties(debugprobe PROPERTIES
OUTPUT_NAME "debugprobe_on_pico2"
)
else ()
error("Unsupported board ${PICO_BOARD}" PICO_BOARD)
endif ()
endif ()

91
FreeRTOS_Kernel_import.cmake Executable file → Normal file
View File

@@ -1,3 +1,4 @@
# SPDX-License-Identifier: BSD-3-clause
# This is a copy of <FREERTOS_KERNEL_PATH>/portable/ThirdParty/GCC/RP2040/FREERTOS_KERNEL_import.cmake
# This can be dropped into an external project to help locate the FreeRTOS kernel
@@ -10,38 +11,68 @@ if (DEFINED ENV{FREERTOS_KERNEL_PATH} AND (NOT FREERTOS_KERNEL_PATH))
message("Using FREERTOS_KERNEL_PATH from environment ('${FREERTOS_KERNEL_PATH}')")
endif ()
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "portable/ThirdParty/GCC/RP2040")
# undo the above
set(FREERTOS_KERNEL_RP2040_BACK_PATH "../../../..")
if (NOT FREERTOS_KERNEL_PATH)
# check if we are inside the FreeRTOS kernel tree (i.e. this file has been included directly)
get_filename_component(_ACTUAL_PATH ${CMAKE_CURRENT_LIST_DIR} REALPATH)
get_filename_component(_POSSIBLE_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} REALPATH)
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
# first pass we look in old tree; second pass we look in new tree
foreach(SEARCH_PASS RANGE 0 1)
if (SEARCH_PASS)
# ports may be moving to submodule in the future
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "portable/ThirdParty/Community-Supported-Ports/GCC")
set(FREERTOS_KERNEL_RP2040_BACK_PATH "../../../../..")
else()
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "portable/ThirdParty/GCC")
set(FREERTOS_KERNEL_RP2040_BACK_PATH "../../../..")
endif()
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
message("Setting FREERTOS_KERNEL_PATH to ${FREERTOS_KERNEL_PATH} based on location of FreeRTOS-Kernel-import.cmake")
elseif (PICO_SDK_PATH AND EXISTS "${PICO_SDK_PATH}/../FreeRTOS-Kernel")
set(FREERTOS_KERNEL_PATH ${PICO_SDK_PATH}/../FreeRTOS-Kernel)
message("Defaulting FREERTOS_KERNEL_PATH as sibling of PICO_SDK_PATH: ${FREERTOS_KERNEL_PATH}")
endif()
endif ()
if (NOT FREERTOS_KERNEL_PATH)
foreach(POSSIBLE_SUFFIX Source FreeRTOS-Kernel FreeRTOS/Source)
# check if FreeRTOS-Kernel exists under directory that included us
set(SEARCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
get_filename_component(_POSSIBLE_PATH ${SEARCH_ROOT}/${POSSIBLE_SUFFIX} REALPATH)
if (EXISTS ${_POSSIBLE_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)
get_filename_component(FREERTOS_KERNEL_PATH ${_POSSIBLE_PATH} REALPATH)
message("Setting FREERTOS_KERNEL_PATH to '${FREERTOS_KERNEL_PATH}' found relative to enclosing project")
if(PICO_PLATFORM STREQUAL "rp2040")
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2040")
else()
if (PICO_PLATFORM STREQUAL "rp2350-riscv")
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2350_RISC-V")
else()
set(FREERTOS_KERNEL_RP2040_RELATIVE_PATH "${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/RP2350_ARM_NTZ")
endif()
endif()
if (NOT FREERTOS_KERNEL_PATH)
# check if we are inside the FreeRTOS kernel tree (i.e. this file has been included directly)
get_filename_component(_ACTUAL_PATH ${CMAKE_CURRENT_LIST_DIR} REALPATH)
get_filename_component(_POSSIBLE_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} REALPATH)
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
endif()
if (_ACTUAL_PATH STREQUAL _POSSIBLE_PATH)
get_filename_component(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/${FREERTOS_KERNEL_RP2040_BACK_PATH} REALPATH)
message("Setting FREERTOS_KERNEL_PATH to ${FREERTOS_KERNEL_PATH} based on location of FreeRTOS-Kernel-import.cmake")
break()
elseif (PICO_SDK_PATH AND EXISTS "${PICO_SDK_PATH}/../FreeRTOS-Kernel")
set(FREERTOS_KERNEL_PATH ${PICO_SDK_PATH}/../FreeRTOS-Kernel)
message("Defaulting FREERTOS_KERNEL_PATH as sibling of PICO_SDK_PATH: ${FREERTOS_KERNEL_PATH}")
break()
endif()
endforeach()
endif()
endif ()
if (NOT FREERTOS_KERNEL_PATH)
foreach(POSSIBLE_SUFFIX Source FreeRTOS-Kernel FreeRTOS/Source)
# check if FreeRTOS-Kernel exists under directory that included us
set(SEARCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
get_filename_component(_POSSIBLE_PATH ${SEARCH_ROOT}/${POSSIBLE_SUFFIX} REALPATH)
if (EXISTS ${_POSSIBLE_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)
get_filename_component(FREERTOS_KERNEL_PATH ${_POSSIBLE_PATH} REALPATH)
message("Setting FREERTOS_KERNEL_PATH to '${FREERTOS_KERNEL_PATH}' found relative to enclosing project")
break()
endif()
endforeach()
if (FREERTOS_KERNEL_PATH)
break()
endif()
endif()
# user must have specified
if (FREERTOS_KERNEL_PATH)
if (EXISTS "${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}")
break()
endif()
endif()
endforeach ()
if (NOT FREERTOS_KERNEL_PATH)
message(FATAL_ERROR "FreeRTOS location was not specified. Please set FREERTOS_KERNEL_PATH.")
@@ -54,8 +85,8 @@ if (NOT EXISTS ${FREERTOS_KERNEL_PATH})
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' not found")
endif()
if (NOT EXISTS ${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}/CMakeLists.txt)
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' does not contain an RP2040 port here: ${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}")
message(FATAL_ERROR "Directory '${FREERTOS_KERNEL_PATH}' does not contain a '${PICO_PLATFORM}' port here: ${FREERTOS_KERNEL_RP2040_RELATIVE_PATH}")
endif()
set(FREERTOS_KERNEL_PATH ${FREERTOS_KERNEL_PATH} CACHE PATH "Path to the FreeRTOS_KERNEL" FORCE)
add_subdirectory(${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} FREERTOS_KERNEL)
add_subdirectory(${FREERTOS_KERNEL_PATH}/${FREERTOS_KERNEL_RP2040_RELATIVE_PATH} FREERTOS_KERNEL)

23
LICENSE Normal file
View File

@@ -0,0 +1,23 @@
Unless otherwise indicated in individual files, this project is licenced as:
MIT License
Copyright (c) 2024 Raspberry Pi Ltd
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.

View File

@@ -47,6 +47,21 @@ This will build with the configuration for the Pico and call the output program
Note that if you first ran through the whole sequence to compile for the Debug Probe, then you don't need to start back at the top. You can just go back to the `cmake` step and start from there.
# Building for the Pico 2
If using an existing debugprobe clone:
- You must completely regenerate your build directory, or use a different one.
- You must also sync and update submodules as rp2350 needs a downstream FreeRTOS port for now.
- `PICO_SDK_PATH` must point to a version 2.0.0 or greater install.
```
git submodule sync
git submodule update --init
mkdir build-pico2
cd build-pico2
cmake -DDEBUG_ON_PICO=1 -DPICO_BOARD=pico2 -DPICO_PLATFORM=rp2350 ../
```
# TODO
- AutoBaud selection, as PIO is a capable frequency counter

View File

@@ -502,8 +502,8 @@ It is recommended to provide the following LEDs for status indication:
- 0: Connect LED OFF: debugger is not connected to CMSIS-DAP Debug Unit.
*/
__STATIC_INLINE void LED_CONNECTED_OUT (uint32_t bit) {
#ifdef DEBUGPROBE_DAP_CONNECTED_LED
gpio_put(DEBUGPROBE_DAP_CONNECTED_LED, bit);
#ifdef PROBE_DAP_CONNECTED_LED
gpio_put(PROBE_DAP_CONNECTED_LED, bit);
#endif
}
@@ -513,8 +513,8 @@ __STATIC_INLINE void LED_CONNECTED_OUT (uint32_t bit) {
- 0: Target Running LED OFF: program execution in target stopped.
*/
__STATIC_INLINE void LED_RUNNING_OUT (uint32_t bit) {
#ifdef DEBUGPROBE_DAP_RUNNING_LED
gpio_put(DEBUGPROBE_DAP_RUNNING_LED, bit);
#ifdef PROBE_DAP_RUNNING_LED
gpio_put(PROBE_DAP_RUNNING_LED, bit);
#endif
}
@@ -561,7 +561,16 @@ Status LEDs. In detail the operation of Hardware I/O and LED pins are enabled an
- LED output pins are enabled and LEDs are turned off.
*/
__STATIC_INLINE void DAP_SETUP (void) {
probe_gpio_init();
// We synchronously setup probe IOs when the respective PIO program is loaded - not at start of day
#ifdef PROBE_DAP_CONNECTED_LED
gpio_init(PROBE_DAP_CONNECTED_LED);
gpio_set_dir(PROBE_DAP_CONNECTED_LED, GPIO_OUT);
#endif
#ifdef PROBE_DAP_RUNNING_LED
gpio_init(PROBE_DAP_RUNNING_LED);
gpio_set_dir(PROBE_DAP_RUNNING_LED, GPIO_OUT);
#endif
}
/** Reset Target Device with custom specific I/O pin or command sequence.

View File

@@ -60,7 +60,7 @@
#endif
/* PIO config for PROBE_IO_OEN - note that SWDIOEN and SWCLK are both side_set signals, so must be consecutive. */
#if defined(PROBE_IO_SWDIOEN)
#if defined(PROBE_IO_OEN)
#define PROBE_PIN_SWDIOEN (PROBE_PIN_OFFSET + 0)
#define PROBE_PIN_SWCLK (PROBE_PIN_OFFSET + 1)
#define PROBE_PIN_SWDIO (PROBE_PIN_OFFSET + 2)

View File

@@ -1,3 +1,4 @@
# SPDX-License-Identifier: BSD-3-Clause
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK

View File

@@ -110,6 +110,13 @@
#define configSUPPORT_PICO_SYNC_INTEROP 1
#define configSUPPORT_PICO_TIME_INTEROP 1
/* RP2350 grows some features */
#define configENABLE_FPU 1
#define configENABLE_MPU 0
#define configENABLE_TRUSTZONE 0
#define configRUN_FREERTOS_SECURE_ONLY 1
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 16
#include <assert.h>
/* Define to trap errors during development. */
#define configASSERT(x) assert(x)

View File

@@ -26,7 +26,6 @@
#include <pico/stdlib.h>
#include "FreeRTOS.h"
#include "task.h"
#include "tusb.h"
#include "probe_config.h"
@@ -58,6 +57,17 @@ void cdc_uart_init(void) {
gpio_set_pulls(PROBE_UART_RX, 1, 0);
uart_init(PROBE_UART_INTERFACE, PROBE_UART_BAUDRATE);
#ifdef PROBE_UART_TX_LED
tx_led_debounce = 0;
gpio_init(PROBE_UART_TX_LED);
gpio_set_dir(PROBE_UART_TX_LED, GPIO_OUT);
#endif
#ifdef PROBE_UART_RX_LED
rx_led_debounce = 0;
gpio_init(PROBE_UART_RX_LED);
gpio_set_dir(PROBE_UART_RX_LED, GPIO_OUT);
#endif
#ifdef PROBE_UART_HWFC
/* HWFC implies that hardware flow control is implemented and the
* UART operates in "full-duplex" mode (See USB CDC PSTN120 6.3.12).
@@ -191,7 +201,8 @@ void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_coding)
*/
uint32_t micros = (1000 * 1000 * 16 * 10) / MAX(line_coding->bit_rate, 1);
/* Modifying state, so park the thread before changing it. */
vTaskSuspend(uart_taskhandle);
if (tud_cdc_connected())
vTaskSuspend(uart_taskhandle);
interval = MAX(1, micros / ((1000 * 1000) / configTICK_RATE_HZ));
debounce_ticks = MAX(1, configTICK_RATE_HZ / (interval * DEBOUNCE_MS));
probe_info("New baud rate %ld micros %ld interval %lu\n",
@@ -245,7 +256,10 @@ void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_coding)
}
uart_set_format(PROBE_UART_INTERFACE, data_bits, stop_bits, parity);
vTaskResume(uart_taskhandle);
/* Windows likes to arbitrarily set/get line coding after dtr/rts changes, so
* don't resume if we shouldn't */
if(tud_cdc_connected())
vTaskResume(uart_taskhandle);
}
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
@@ -259,7 +273,7 @@ void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
/* CDC drivers use linestate as a bodge to activate/deactivate the interface.
* Resume our UART polling on activate, stop on deactivate */
if (!dtr && !rts) {
if (!dtr) {
vTaskSuspend(uart_taskhandle);
#ifdef PROBE_UART_RX_LED
gpio_put(PROBE_UART_RX_LED, 0);
@@ -278,6 +292,9 @@ void tud_cdc_send_break_cb(uint8_t itf, uint16_t wValue) {
case 0:
uart_set_break(PROBE_UART_INTERFACE, false);
timed_break = false;
#ifdef PROBE_UART_TX_LED
tx_led_debounce = 0;
#endif
break;
case 0xffff:
uart_set_break(PROBE_UART_INTERFACE, true);

View File

@@ -1,52 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2021 a-pushkin on GitHub
*
* 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 <pico/stdlib.h>
#include <stdint.h>
#include "probe_config.h"
void led_init(void) {
#ifdef PROBE_USB_CONNECTED_LED
gpio_init(PROBE_USB_CONNECTED_LED);
gpio_set_dir(PROBE_USB_CONNECTED_LED, GPIO_OUT);
#endif
#ifdef PROBE_DAP_CONNECTED_LED
gpio_init(PROBE_DAP_CONNECTED_LED);
gpio_set_dir(PROBE_DAP_CONNECTED_LED, GPIO_OUT);
#endif
#ifdef PROBE_DAP_RUNNING_LED
gpio_init(PROBE_DAP_RUNNING_LED);
gpio_set_dir(PROBE_DAP_RUNNING_LED, GPIO_OUT);
#endif
#ifdef PROBE_UART_RX_LED
gpio_init(PROBE_UART_RX_LED);
gpio_set_dir(PROBE_UART_RX_LED, GPIO_OUT);
#endif
#ifdef PROBE_UART_TX_LED
gpio_init(PROBE_UART_TX_LED);
gpio_set_dir(PROBE_UART_TX_LED, GPIO_OUT);
#endif
}

View File

@@ -1,31 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2021 a-pushkin on GitHub
*
* 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.
*
*/
#ifndef LED_H
#define LED_H
void led_init(void);
#endif

View File

@@ -31,16 +31,20 @@
#include <stdio.h>
#include <string.h>
#if PICO_SDK_VERSION_MAJOR >= 2
#include "bsp/board_api.h"
#else
#include "bsp/board.h"
#endif
#include "tusb.h"
#include "probe_config.h"
#include "probe.h"
#include "cdc_uart.h"
#include "get_serial.h"
#include "led.h"
#include "tusb_edpt_handler.h"
#include "DAP.h"
#include "hardware/structs/usb.h"
// UART0 for debugprobe debug
// UART1 for debugprobe to target device
@@ -54,10 +58,45 @@ static uint8_t RxDataBuffer[CFG_TUD_HID_EP_BUFSIZE];
#define TUD_TASK_PRIO (tskIDLE_PRIORITY + 2)
#define DAP_TASK_PRIO (tskIDLE_PRIORITY + 1)
TaskHandle_t dap_taskhandle, tud_taskhandle;
TaskHandle_t dap_taskhandle, tud_taskhandle, mon_taskhandle;
static int was_configured;
void dev_mon(void *ptr)
{
uint32_t sof[3];
int i = 0;
TickType_t wake;
wake = xTaskGetTickCount();
do {
/* ~5 SOF events per tick */
xTaskDelayUntil(&wake, 100);
if (tud_connected() && !tud_suspended()) {
sof[i++] = usb_hw->sof_rd & USB_SOF_RD_BITS;
i = i % 3;
} else {
for (i = 0; i < 3; i++)
sof[i] = 0;
}
if ((sof[0] | sof[1] | sof[2]) != 0) {
if ((sof[0] == sof[1]) && (sof[1] == sof[2])) {
probe_info("Watchdog timeout! Resetting USBD\n");
/* uh oh, signal disconnect (implicitly resets the controller) */
tud_deinit(0);
/* Make sure the port got the message */
xTaskDelayUntil(&wake, 1);
tud_init(0);
}
}
} while (1);
}
void usb_thread(void *ptr)
{
#ifdef PROBE_USB_CONNECTED_LED
gpio_init(PROBE_USB_CONNECTED_LED);
gpio_set_dir(PROBE_USB_CONNECTED_LED, GPIO_OUT);
#endif
TickType_t wake;
wake = xTaskGetTickCount();
do {
@@ -68,8 +107,11 @@ void usb_thread(void *ptr)
else
gpio_put(PROBE_USB_CONNECTED_LED, 0);
#endif
// If suspended or disconnected, delay for 1ms (20 ticks)
if (tud_suspended() || !tud_connected())
xTaskDelayUntil(&wake, 20);
// Go to sleep for up to a tick if nothing to do
if (!tud_task_event_ready())
else if (!tud_task_event_ready())
xTaskDelayUntil(&wake, 1);
} while (1);
}
@@ -80,6 +122,8 @@ void usb_thread(void *ptr)
#endif
int main(void) {
// Declare pins in binary information
bi_decl_config();
board_init();
usb_serial_init();
@@ -89,16 +133,13 @@ int main(void) {
DAP_Setup();
led_init();
probe_info("Welcome to debugprobe!\n");
if (THREADED) {
/* UART needs to preempt USB as if we don't, characters get lost */
xTaskCreate(cdc_thread, "UART", configMINIMAL_STACK_SIZE, NULL, UART_TASK_PRIO, &uart_taskhandle);
xTaskCreate(usb_thread, "TUD", configMINIMAL_STACK_SIZE, NULL, TUD_TASK_PRIO, &tud_taskhandle);
/* Lowest priority thread is debug - need to shuffle buffers before we can toggle swd... */
xTaskCreate(dap_thread, "DAP", configMINIMAL_STACK_SIZE, NULL, DAP_TASK_PRIO, &dap_taskhandle);
#if PICO_RP2040
xTaskCreate(dev_mon, "WDOG", configMINIMAL_STACK_SIZE, NULL, TUD_TASK_PRIO, &mon_taskhandle);
#endif
vTaskStartScheduler();
}
@@ -182,6 +223,48 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ
}
#endif
void tud_suspend_cb(bool remote_wakeup_en)
{
probe_info("Suspended\n");
/* Were we actually configured? If not, threads don't exist */
if (was_configured) {
vTaskSuspend(uart_taskhandle);
vTaskSuspend(dap_taskhandle);
}
/* slow down clk_sys for power saving ? */
}
void tud_resume_cb(void)
{
probe_info("Resumed\n");
if (was_configured) {
vTaskResume(uart_taskhandle);
vTaskResume(dap_taskhandle);
}
}
void tud_unmount_cb(void)
{
probe_info("Disconnected\n");
vTaskSuspend(uart_taskhandle);
vTaskSuspend(dap_taskhandle);
vTaskDelete(uart_taskhandle);
vTaskDelete(dap_taskhandle);
was_configured = 0;
}
void tud_mount_cb(void)
{
probe_info("Connected, Configured\n");
if (!was_configured) {
/* UART needs to preempt USB as if we don't, characters get lost */
xTaskCreate(cdc_thread, "UART", configMINIMAL_STACK_SIZE, NULL, UART_TASK_PRIO, &uart_taskhandle);
/* Lowest priority thread is debug - need to shuffle buffers before we can toggle swd... */
xTaskCreate(dap_thread, "DAP", configMINIMAL_STACK_SIZE, NULL, DAP_TASK_PRIO, &dap_taskhandle);
was_configured = 1;
}
}
void vApplicationTickHook (void)
{
};

View File

@@ -30,9 +30,8 @@
#include <hardware/clocks.h>
#include <hardware/gpio.h>
#include "led.h"
#include "probe_config.h"
#include "probe.pio.h"
#include "probe.h"
#include "tusb.h"
#define DIV_ROUND_UP(m, n) (((m) + (n) - 1) / (n))
@@ -147,6 +146,7 @@ void probe_write_mode(void) {
void probe_init() {
if (!probe.initted) {
probe_gpio_init();
uint offset = pio_add_program(pio0, &probe_program);
probe.offset = offset;
@@ -172,7 +172,7 @@ void probe_deinit(void)
pio_remove_program(pio0, &probe_program, probe.offset);
probe_assert_reset(1); // de-assert nRESET
probe_gpio_deinit();
probe.initted = 0;
}
}

View File

@@ -86,6 +86,19 @@ static inline void probe_gpio_init()
gpio_pull_up(PROBE_PIN_SWDIO);
}
// DAP interface says all pins have to be High-Z when disabled
static inline void probe_gpio_deinit()
{
#if defined(PROBE_PIN_RESET)
gpio_deinit(PROBE_PIN_RESET);
gpio_disable_pulls(PROBE_PIN_RESET);
#endif
gpio_deinit(PROBE_PIN_SWCLK);
gpio_disable_pulls(PROBE_PIN_SWCLK);
gpio_deinit(PROBE_PIN_SWDIO);
gpio_disable_pulls(PROBE_PIN_SWDIO);
}
static inline void probe_sm_init(pio_sm_config* sm_config) {
// Set SWCLK as a sideset pin

48
src/probe_config.c Normal file
View File

@@ -0,0 +1,48 @@
#include "probe_config.h"
#include "pico/binary_info.h"
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
void bi_decl_config()
{
#ifdef PROBE_PIN_RESET
bi_decl(bi_1pin_with_name(PROBE_PIN_RESET, "PROBE RESET"));
#endif
#ifdef PROBE_PIN_SWCLK
bi_decl(bi_1pin_with_name(PROBE_PIN_SWCLK, "PROBE SWCLK"));
#endif
#ifdef PROBE_PIN_SWDIO
bi_decl(bi_1pin_with_name(PROBE_PIN_SWDIO, "PROBE SWDIO"));
#endif
#ifdef PROBE_PIN_SWDI
bi_decl(bi_1pin_with_name(PROBE_PIN_SWDI, "PROBE SWDI"));
#endif
#ifdef PROBE_PIN_SWDIOEN
bi_decl(bi_1pin_with_name(PROBE_PIN_SWDIOEN, "PROBE SWDIOEN"));
#endif
#ifdef PROBE_CDC_UART
bi_decl(bi_program_feature("PROBE UART INTERFACE " STR(PROBE_UART_INTERFACE)));
bi_decl(bi_program_feature("PROBE UART BAUDRATE " STR(PROBE_UART_BAUDRATE)));
bi_decl(bi_1pin_with_name(PROBE_UART_TX, "PROBE UART TX"));
bi_decl(bi_1pin_with_name(PROBE_UART_RX, "PROBE UART RX"));
#endif
#ifdef PROBE_UART_CTS
bi_decl(bi_1pin_with_name(PROBE_UART_CTS, "PROBE UART CTS"));
#endif
#ifdef PROBE_UART_RTS
bi_decl(bi_1pin_with_name(PROBE_UART_RTS, "PROBE UART RTS"));
#endif
#ifdef PROBE_UART_DTR
bi_decl(bi_1pin_with_name(PROBE_UART_DTR, "PROBE UART DTR"));
#endif
}

View File

@@ -72,6 +72,8 @@ do { \
#endif
//#include "board_example_config.h"
// Add the configuration to binary information
void bi_decl_config();
#define PROTO_DAP_V1 1
#define PROTO_DAP_V2 2

View File

@@ -1,3 +1,6 @@
; SPDX-License-Identifier: MIT
; Copyright (c) 2023 Raspberry Pi Ltd
; Output-enable active-low variant of the SWD probe
; This program is very similar to the one in probe.pio. The only difference is
@@ -60,6 +63,21 @@ static inline void probe_gpio_init()
gpio_pull_up(PROBE_PIN_SWDIOEN);
}
// DAP interface says all pins have to be High-Z when disabled
static inline void probe_gpio_deinit()
{
#if defined(PROBE_PIN_RESET)
gpio_deinit(PROBE_PIN_RESET);
gpio_disable_pulls(PROBE_PIN_RESET);
#endif
gpio_deinit(PROBE_PIN_SWCLK);
gpio_disable_pulls(PROBE_PIN_SWCLK);
// Note for SWDIOEN - make sure the driver output enable is removed before removing drive - leave pull-up enabled
gpio_deinit(PROBE_PIN_SWDIOEN);
gpio_deinit(PROBE_PIN_SWDIO);
gpio_disable_pulls(PROBE_PIN_SWDIO);
}
static inline void probe_sm_init(pio_sm_config* sm_config) {
// Set SWDIOEN and SWCLK as sideset pins

View File

@@ -41,6 +41,15 @@ void dap_edpt_init(void) {
}
bool dap_edpt_deinit(void)
{
memset(DAPRequestBuffer, 0, sizeof(DAPRequestBuffer));
memset(DAPResponseBuffer, 0, sizeof(DAPResponseBuffer));
USBRequestBuffer.wptr = USBRequestBuffer.rptr = 0;
USBResponseBuffer.wptr = USBResponseBuffer.rptr = 0;
return true;
}
void dap_edpt_reset(uint8_t __unused rhport)
{
itf_num = 0;
@@ -198,7 +207,7 @@ void dap_thread(void *ptr)
*/
n = USBRequestBuffer.rptr;
while (USBRequestBuffer.data[n % DAP_PACKET_COUNT][0] == ID_DAP_QueueCommands) {
probe_info("%u %u DAP queued cmd %s len %02x\n",
probe_info("%lu %lu DAP queued cmd %s len %02x\n",
USBRequestBuffer.wptr, USBRequestBuffer.rptr,
dap_cmd_string[USBRequestBuffer.data[n % DAP_PACKET_COUNT][0]], USBRequestBuffer.data[n % DAP_PACKET_COUNT][1]);
USBRequestBuffer.data[n % DAP_PACKET_COUNT][0] = ID_DAP_ExecuteCommands;
@@ -211,7 +220,7 @@ void dap_thread(void *ptr)
}
// Read a single packet from the USB buffer into the DAP Request buffer
memcpy(DAPRequestBuffer, RD_SLOT_PTR(USBRequestBuffer), DAP_PACKET_SIZE);
probe_info("%u %u DAP cmd %s len %02x\n",
probe_info("%lu %lu DAP cmd %s len %02x\n",
USBRequestBuffer.wptr, USBRequestBuffer.rptr,
dap_cmd_string[DAPRequestBuffer[0]], DAPRequestBuffer[1]);
USBRequestBuffer.rptr++;
@@ -227,7 +236,7 @@ void dap_thread(void *ptr)
}
_resp_len = DAP_ExecuteCommand(DAPRequestBuffer, DAPResponseBuffer);
probe_info("%u %u DAP resp %s\n",
probe_info("%lu %lu DAP resp %s\n",
USBResponseBuffer.wptr, USBResponseBuffer.rptr,
dap_cmd_string[DAPResponseBuffer[0]]);
@@ -262,6 +271,7 @@ void dap_thread(void *ptr)
usbd_class_driver_t const _dap_edpt_driver =
{
.init = dap_edpt_init,
.deinit = dap_edpt_deinit,
.reset = dap_edpt_reset,
.open = dap_edpt_open,
.control_xfer_cb = dap_edpt_control_xfer_cb,

View File

@@ -48,7 +48,7 @@ tusb_desc_device_t const desc_device =
.idVendor = 0x2E8A, // Pi
.idProduct = 0x000c, // CMSIS-DAP Debug Probe
.bcdDevice = 0x0200, // Version 02.00
.bcdDevice = 0x0221, // Version 02.21
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
@@ -244,4 +244,4 @@ TU_VERIFY_STATIC(sizeof(desc_ms_os_20) == MS_OS_20_DESC_LEN, "Incorrect size");
uint8_t const * tud_descriptor_bos_cb(void)
{
return desc_bos;
}
}