Compare commits

...

11 Commits

Author SHA1 Message Date
Jonathan Bell
c0ff91421a Debugprobe release 2.0 2024-03-18 16:37:56 +00:00
Jonathan Bell
b5962e0818 Fix builds for which UART_TX_LED aren't defined 2024-03-18 16:37:56 +00:00
Jonathan Bell
ddc028fe18 cdc_acm: turn on UART_TX LED when sending break signals
Software typically asserts line break for an extended period
(e.g. PuTTY will assert continuously until the next keypress), so
provide feedback via the LED.

Also declare variables used in both tinyusb callback and uart_thread context
as volatile.
2024-03-18 16:01:35 +00:00
Jonathan Bell
af2540b045 cdc_uart: add CTS/RTS configuration options to board_example_config
For high data rate applications it's desirable to use hardware flow control
to prevent characters getting dropped when faced with the vagaries of RTOS
and kernel latencies. Adding PROBE_UART_HWFC enables the UART's CTS/RTS pins,
and SET_LINE_STATE messages no longer affect the RTS pin.
2024-03-18 16:01:35 +00:00
Jonathan Bell
d5047e7ef8 cdc_uart: add break handling
Implement break set/unset and declare the interface as capable of sending
line breaks.
2024-03-18 16:01:35 +00:00
geekman
a7aa0766f0 Make target reset functionality work out-of-the-box (#123)
* Fix up target reset functionality.

- Correct GPIO direction logic error in `probe_assert_reset`
- Remember to de-assert nRESET on deinit

* board_pico_config: use pin 1 for reset

This pin is normally used for UART debug output, but that is
undocumented. Repurpose it as reset output.

Signed-off-by: Sean Cross <sean@xobs.io>

* main: move stdio_uart_init() before DAP_Setup()

When using GP1 as a reset line, this is necessary to overwrite the
stdio function call from reusing the pin as a debug output.

Signed-off-by: Sean Cross <sean@xobs.io>

---------

Signed-off-by: Sean Cross <sean@xobs.io>
Co-authored-by: Sean Cross <sean@xobs.io>
2024-03-18 15:12:46 +00:00
David Lynch
b09854c639 fix: Corrected typo in preprocessor ifdef
* Changed PROBE_UART_RX_LED to PROBE_UART_TX_LED in ifdef to control TX LED
2024-03-18 09:33:57 +00:00
Jonathan Bell
327e15f176 board_debug_probe_config.h - nit 2024-02-05 16:17:46 +00:00
Jonathan Bell
62f4a31335 Update README.md 2024-02-05 16:17:46 +00:00
Jonathan Bell
abf675ca8c More renaming
- Prefix DAP-specific defines with DAP_
- PROBE_ defines refer to config options selected by a board type
2024-02-05 16:17:46 +00:00
Jonathan Bell
d0c03d2564 Rename picoprobe to debugprobe
Picoprobe is a registered trademark. Rename to debugprobe, and make it clear
that the code in this repository is firmware for the Debug Probe.
2024-02-05 16:17:46 +00:00
16 changed files with 284 additions and 193 deletions

View File

@@ -5,11 +5,11 @@ include(pico_sdk_import.cmake)
set(FREERTOS_KERNEL_PATH ${CMAKE_CURRENT_LIST_DIR}/freertos)
include(FreeRTOS_Kernel_import.cmake)
project(picoprobe)
project(debugprobe)
pico_sdk_init()
add_executable(picoprobe
add_executable(debugprobe
src/led.c
src/main.c
src/usb_descriptors.c
@@ -20,7 +20,7 @@ add_executable(picoprobe
src/tusb_edpt_handler.c
)
target_sources(picoprobe PRIVATE
target_sources(debugprobe PRIVATE
CMSIS_5/CMSIS/DAP/Firmware/Source/DAP.c
CMSIS_5/CMSIS/DAP/Firmware/Source/JTAG_DP.c
CMSIS_5/CMSIS/DAP/Firmware/Source/DAP_vendor.c
@@ -28,35 +28,35 @@ target_sources(picoprobe PRIVATE
#CMSIS_5/CMSIS/DAP/Firmware/Source/SW_DP.c
)
target_include_directories(picoprobe PRIVATE
target_include_directories(debugprobe PRIVATE
CMSIS_5/CMSIS/DAP/Firmware/Include/
CMSIS_5/CMSIS/Core/Include/
include/
)
target_compile_options(picoprobe PRIVATE -Wall)
target_compile_options(debugprobe PRIVATE -Wall)
pico_generate_pio_header(picoprobe ${CMAKE_CURRENT_LIST_DIR}/src/probe.pio)
pico_generate_pio_header(picoprobe ${CMAKE_CURRENT_LIST_DIR}/src/probe_oen.pio)
pico_generate_pio_header(debugprobe ${CMAKE_CURRENT_LIST_DIR}/src/probe.pio)
pico_generate_pio_header(debugprobe ${CMAKE_CURRENT_LIST_DIR}/src/probe_oen.pio)
target_include_directories(picoprobe PRIVATE src)
target_include_directories(debugprobe PRIVATE src)
target_compile_definitions (picoprobe PRIVATE
target_compile_definitions (debugprobe PRIVATE
PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1
)
option (DEBUGPROBE "compile for the debugprobe" OFF)
if (DEBUGPROBE)
target_compile_definitions (picoprobe PRIVATE
DEBUGPROBE=1
option (DEBUG_ON_PICO "Compile firmware for the Pico instead of Debug Probe" OFF)
if (DEBUG_ON_PICO)
target_compile_definitions (debugprobe PRIVATE
DEBUG_ON_PICO=1
)
set_target_properties(picoprobe PROPERTIES
OUTPUT_NAME "debugprobe"
set_target_properties(debugprobe PROPERTIES
OUTPUT_NAME "debugprobe_on_pico"
)
endif ()
target_link_libraries(picoprobe PRIVATE
target_link_libraries(debugprobe PRIVATE
pico_multicore
pico_stdlib
pico_unique_id
@@ -67,6 +67,6 @@ target_link_libraries(picoprobe PRIVATE
FreeRTOS-Kernel-Heap1
)
pico_set_binary_type(picoprobe copy_to_ram)
pico_set_binary_type(debugprobe copy_to_ram)
pico_add_extra_outputs(picoprobe)
pico_add_extra_outputs(debugprobe)

View File

@@ -1,41 +1,53 @@
# Picoprobe
Picoprobe allows a Pico / RP2040 to be used as USB -> SWD and UART bridge. This means it can be used as a debugger and serial console for another Pico.
# Debugprobe
Firmware source for the Raspberry Pi Debug Probe SWD/UART accessory. Can also be run on a Raspberry Pi Pico.
[Raspberry Pi Debug Probe product page](https://www.raspberrypi.com/products/debug-probe/)
[Raspberry Pi Pico product page](https://www.raspberrypi.com/products/raspberry-pi-pico/)
# Documentation
Picoprobe documentation can be found in the [Pico Getting Started Guide](https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf). See "Appendix A: Using Picoprobe".
Debug Probe documentation can be found in the [Pico Getting Started Guide](https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf). See "Appendix A: Using the Debug Probe".
# Hacking
For the purpose of making changes or studying of the code, you may want to compile the code yourself.
For the purpose of making changes or studying of the code, you may want to compile the code yourself.
To compile this project firstly initialize and update the submodules:
First, clone the repository:
```
git clone https://github.com/raspberrypi/debugprobe
cd debugprobe
```
Initialize and update the submodules:
```
git submodule update --init
```
then create and switch to the build directory:
Then create and switch to the build directory:
```
mkdir build
cd build
```
then run cmake and build the code:
If your environment doesn't contain `PICO_SDK_PATH`, then either add it to your environment variables with `export PICO_SDK_PATH=/path/to/sdk` or add `PICO_SDK_PATH=/path/to/sdk` to the arguments to CMake below.
Run cmake and build the code:
```
cmake ..
make
```
Done! You should now have a `picoprobe.uf2` that you can upload to your Pico in the normal way.
Done! You should now have a `debugprobe.uf2` that you can upload to your Debug Probe via the UF2 bootloader.
If you want to create the version that runs on the Raspberry Pi Debug Probe, then you need to invoke `cmake` in the sequence above with the `DEBUGPROBE=ON` option:
If you want to create the version that runs on the Pico, then you need to invoke `cmake` in the sequence above with the `DEBUG_ON_PICO=ON` option:
```
cmake -DDEBUGPROBE=ON ..
cmake -DDEBUG_ON_PICO=ON ..
```
This will build with the configuration for the Debug Probe and call the output program `debugprobe.uf2`, as opposed to `picoprobe.uf2` for the vanilla version.
This will build with the configuration for the Pico and call the output program `debugprobe_on_pico.uf2`, as opposed to `debugprobe.uf2` for the accessory hardware.
Note that if you first ran through the whole sequence to compile for the Pico, then you don't need to start back at the top. You can just go back to the `cmake` step and start from there.
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.
# TODO
- TinyUSB's vendor interface is FIFO-based and not packet-based. Using raw tx/rx callbacks is preferable as this stops DAP command batches from being concatenated, which confused openOCD.
- Instead of polling, move the DAP thread to an asynchronously started/stopped one-shot operation to reduce CPU wakeups
- AutoBaud selection, as PIO is a capable frequency counter
- Possibly include RTT support

View File

@@ -47,12 +47,12 @@ This information includes:
#include <hardware/gpio.h>
#include "cmsis_compiler.h"
#include "picoprobe_config.h"
#include "probe_config.h"
#include "probe.h"
/// Processor Clock of the Cortex-M MCU used in the Debug Unit.
/// This value is used to calculate the SWD/JTAG clock speed.
/* Picoprobe actually uses kHz rather than Hz, so just lie about it here */
/* Debugprobe actually uses kHz rather than Hz, so just lie about it here */
#define CPU_CLOCK 125000000U ///< Specifies the CPU Clock in Hz.
/// Number of processor cycles for I/O Port write operations.
@@ -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 PICOPROBE_DAP_CONNECTED_LED
gpio_put(PICOPROBE_DAP_CONNECTED_LED, bit);
#ifdef DEBUGPROBE_DAP_CONNECTED_LED
gpio_put(DEBUGPROBE_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 PICOPROBE_DAP_RUNNING_LED
gpio_put(PICOPROBE_DAP_RUNNING_LED, bit);
#ifdef DEBUGPROBE_DAP_RUNNING_LED
gpio_put(DEBUGPROBE_DAP_RUNNING_LED, bit);
#endif
}

View File

@@ -23,8 +23,8 @@
*
*/
#ifndef BOARD_DEBUGPROBE_H_
#define BOARD_DEBUGPROBE_H_
#ifndef BOARD_DEBUG_PROBE_H_
#define BOARD_DEBUG_PROBE_H_
#define PROBE_IO_SWDI
#define PROBE_CDC_UART
@@ -39,16 +39,16 @@
#define PROBE_PIN_SWDIO (PROBE_PIN_OFFSET + 2)
// UART config
#define PICOPROBE_UART_TX 4
#define PICOPROBE_UART_RX 5
#define PICOPROBE_UART_INTERFACE uart1
#define PICOPROBE_UART_BAUDRATE 115200
#define PROBE_UART_TX 4
#define PROBE_UART_RX 5
#define PROBE_UART_INTERFACE uart1
#define PROBE_UART_BAUDRATE 115200
#define PICOPROBE_USB_CONNECTED_LED 2
#define PICOPROBE_DAP_CONNECTED_LED 15
#define PICOPROBE_DAP_RUNNING_LED 16
#define PICOPROBE_UART_RX_LED 7
#define PICOPROBE_UART_TX_LED 8
#define PROBE_USB_CONNECTED_LED 2
#define PROBE_DAP_CONNECTED_LED 15
#define PROBE_DAP_RUNNING_LED 16
#define PROBE_UART_RX_LED 7
#define PROBE_UART_TX_LED 8
#define PROBE_PRODUCT_STRING "Debug Probe (CMSIS-DAP)"

View File

@@ -37,6 +37,10 @@
/* Include CDC interface to bridge to target UART. Omit if not used. */
#define PROBE_CDC_UART
/* Board implements hardware flow control for UART RTS/CTS instead of ACM control */
#define PROBE_UART_HWFC
/* Target reset GPIO (active-low). Omit if not used.*/
#define PROBE_PIN_RESET 1
@@ -64,21 +68,29 @@
#endif
#if defined(PROBE_CDC_UART)
#define PICOPROBE_UART_TX 4
#define PICOPROBE_UART_RX 5
#define PICOPROBE_UART_INTERFACE uart1
#define PICOPROBE_UART_BAUDRATE 115200
/* Flow control - some or all of these can be omitted if not used */
#define PICOPROBE_UART_RTS 9
#define PICOPROBE_UART_DTR 10
#define PROBE_UART_TX 4
#define PROBE_UART_RX 5
#define PROBE_UART_INTERFACE uart1
#define PROBE_UART_BAUDRATE 115200
#if defined(PROBE_UART_HWFC)
/* Hardware flow control - see 1.4.3 in the RP2040 datasheet for valid pin settings */
#define PROBE_UART_CTS 6
#define PROBE_UART_RTS 7
#else
/* Software flow control - RTS and DTR can be omitted if not used */
#define PROBE_UART_RTS 9
#endif
#define PROBE_UART_DTR 10
#endif
/* LED config - some or all of these can be omitted if not used */
#define PICOPROBE_USB_CONNECTED_LED 2
#define PICOPROBE_DAP_CONNECTED_LED 15
#define PICOPROBE_DAP_RUNNING_LED 16
#define PICOPROBE_UART_RX_LED 7
#define PICOPROBE_UART_TX_LED 8
#define PROBE_USB_CONNECTED_LED 2
#define PROBE_DAP_CONNECTED_LED 15
#define PROBE_DAP_RUNNING_LED 16
#define PROBE_UART_RX_LED 7
#define PROBE_UART_TX_LED 8
#define PROBE_PRODUCT_STRING "Example Debug Probe"

View File

@@ -40,13 +40,13 @@
#endif
// UART config
#define PICOPROBE_UART_TX 4
#define PICOPROBE_UART_RX 5
#define PICOPROBE_UART_INTERFACE uart1
#define PICOPROBE_UART_BAUDRATE 115200
#define PROBE_UART_TX 4
#define PROBE_UART_RX 5
#define PROBE_UART_INTERFACE uart1
#define PROBE_UART_BAUDRATE 115200
#define PICOPROBE_USB_CONNECTED_LED 25
#define PROBE_USB_CONNECTED_LED 25
#define PROBE_PRODUCT_STRING "Picoprobe (CMSIS-DAP)"
#define PROBE_PRODUCT_STRING "Debugprobe on Pico (CMSIS-DAP)"
#endif
#endif

View File

@@ -29,10 +29,12 @@
#include "tusb.h"
#include "picoprobe_config.h"
#include "probe_config.h"
TaskHandle_t uart_taskhandle;
TickType_t last_wake, interval = 100;
volatile TickType_t break_expiry;
volatile bool timed_break;
/* Max 1 FIFO worth of data */
static uint8_t tx_buf[32];
@@ -41,42 +43,55 @@ static uint8_t rx_buf[32];
#define DEBOUNCE_MS 40
static uint debounce_ticks = 5;
#ifdef PICOPROBE_UART_TX_LED
static uint tx_led_debounce;
#ifdef PROBE_UART_TX_LED
static volatile uint tx_led_debounce;
#endif
#ifdef PICOPROBE_UART_RX_LED
#ifdef PROBE_UART_RX_LED
static uint rx_led_debounce;
#endif
void cdc_uart_init(void) {
gpio_set_function(PICOPROBE_UART_TX, GPIO_FUNC_UART);
gpio_set_function(PICOPROBE_UART_RX, GPIO_FUNC_UART);
gpio_set_pulls(PICOPROBE_UART_TX, 1, 0);
gpio_set_pulls(PICOPROBE_UART_RX, 1, 0);
uart_init(PICOPROBE_UART_INTERFACE, PICOPROBE_UART_BAUDRATE);
gpio_set_function(PROBE_UART_TX, GPIO_FUNC_UART);
gpio_set_function(PROBE_UART_RX, GPIO_FUNC_UART);
gpio_set_pulls(PROBE_UART_TX, 1, 0);
gpio_set_pulls(PROBE_UART_RX, 1, 0);
uart_init(PROBE_UART_INTERFACE, PROBE_UART_BAUDRATE);
#ifdef PICOPROBE_UART_RTS
gpio_init(PICOPROBE_UART_RTS);
gpio_set_dir(PICOPROBE_UART_RTS, GPIO_OUT);
gpio_put(PICOPROBE_UART_RTS, 1);
#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).
* Default to pulling in the active direction, so an unconnected CTS
* behaves the same as if CTS were not enabled. */
gpio_set_pulls(PROBE_UART_CTS, 0, 1);
gpio_set_function(PROBE_UART_RTS, GPIO_FUNC_UART);
gpio_set_function(PROBE_UART_CTS, GPIO_FUNC_UART);
uart_set_hw_flow(PROBE_UART_INTERFACE, true, true);
#else
#ifdef PROBE_UART_RTS
gpio_init(PROBE_UART_RTS);
gpio_set_dir(PROBE_UART_RTS, GPIO_OUT);
gpio_put(PROBE_UART_RTS, 1);
#endif
#ifdef PICOPROBE_UART_DTR
gpio_init(PICOPROBE_UART_DTR);
gpio_set_dir(PICOPROBE_UART_DTR, GPIO_OUT);
gpio_put(PICOPROBE_UART_DTR, 1);
#endif
#ifdef PROBE_UART_DTR
gpio_init(PROBE_UART_DTR);
gpio_set_dir(PROBE_UART_DTR, GPIO_OUT);
gpio_put(PROBE_UART_DTR, 1);
#endif
}
void cdc_task(void)
bool cdc_task(void)
{
static int was_connected = 0;
static uint cdc_tx_oe = 0;
uint rx_len = 0;
bool keep_alive = false;
// Consume uart fifo regardless even if not connected
while(uart_is_readable(PICOPROBE_UART_INTERFACE) && (rx_len < sizeof(rx_buf))) {
rx_buf[rx_len++] = uart_getc(PICOPROBE_UART_INTERFACE);
while(uart_is_readable(PROBE_UART_INTERFACE) && (rx_len < sizeof(rx_buf))) {
rx_buf[rx_len++] = uart_getc(PROBE_UART_INTERFACE);
}
if (tud_cdc_connected()) {
@@ -85,8 +100,8 @@ void cdc_task(void)
/* Implicit overflow if we don't write all the bytes to the host.
* Also throw away bytes if we can't write... */
if (rx_len) {
#ifdef PICOPROBE_UART_RX_LED
gpio_put(PICOPROBE_UART_RX_LED, 1);
#ifdef PROBE_UART_RX_LED
gpio_put(PROBE_UART_RX_LED, 1);
rx_led_debounce = debounce_ticks;
#endif
written = MIN(tud_cdc_write_available(), rx_len);
@@ -98,11 +113,11 @@ void cdc_task(void)
tud_cdc_write_flush();
}
} else {
#ifdef PICOPROBE_UART_RX_LED
#ifdef PROBE_UART_RX_LED
if (rx_led_debounce)
rx_led_debounce--;
else
gpio_put(PICOPROBE_UART_RX_LED, 0);
gpio_put(PROBE_UART_RX_LED, 0);
#endif
}
@@ -110,39 +125,60 @@ void cdc_task(void)
size_t watermark = MIN(tud_cdc_available(), sizeof(tx_buf));
if (watermark > 0) {
size_t tx_len;
#ifdef PICOPROBE_UART_TX_LED
gpio_put(PICOPROBE_UART_TX_LED, 1);
#ifdef PROBE_UART_TX_LED
gpio_put(PROBE_UART_TX_LED, 1);
tx_led_debounce = debounce_ticks;
#endif
/* Batch up to half a FIFO of data - don't clog up on RX */
watermark = MIN(watermark, 16);
tx_len = tud_cdc_read(tx_buf, watermark);
uart_write_blocking(PICOPROBE_UART_INTERFACE, tx_buf, tx_len);
uart_write_blocking(PROBE_UART_INTERFACE, tx_buf, tx_len);
} else {
#ifdef PICOPROBE_UART_TX_LED
#ifdef PROBE_UART_TX_LED
if (tx_led_debounce)
tx_led_debounce--;
else
gpio_put(PICOPROBE_UART_TX_LED, 0);
gpio_put(PROBE_UART_TX_LED, 0);
#endif
}
/* Pending break handling */
if (timed_break) {
if (((int)break_expiry - (int)xTaskGetTickCount()) < 0) {
timed_break = false;
uart_set_break(PROBE_UART_INTERFACE, false);
#ifdef PROBE_UART_TX_LED
tx_led_debounce = 0;
#endif
} else {
keep_alive = true;
}
}
} else if (was_connected) {
tud_cdc_write_clear();
uart_set_break(PROBE_UART_INTERFACE, false);
timed_break = false;
was_connected = 0;
#ifdef PROBE_UART_TX_LED
tx_led_debounce = 0;
#endif
cdc_tx_oe = 0;
}
return keep_alive;
}
void cdc_thread(void *ptr)
{
BaseType_t delayed;
last_wake = xTaskGetTickCount();
bool keep_alive;
/* Threaded with a polling interval that scales according to linerate */
while (1) {
cdc_task();
delayed = xTaskDelayUntil(&last_wake, interval);
if (delayed == pdFALSE)
last_wake = xTaskGetTickCount();
keep_alive = cdc_task();
if (!keep_alive) {
delayed = xTaskDelayUntil(&last_wake, interval);
if (delayed == pdFALSE)
last_wake = xTaskGetTickCount();
}
}
}
@@ -158,12 +194,12 @@ void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_coding)
vTaskSuspend(uart_taskhandle);
interval = MAX(1, micros / ((1000 * 1000) / configTICK_RATE_HZ));
debounce_ticks = MAX(1, configTICK_RATE_HZ / (interval * DEBOUNCE_MS));
picoprobe_info("New baud rate %ld micros %ld interval %lu\n",
probe_info("New baud rate %ld micros %ld interval %lu\n",
line_coding->bit_rate, micros, interval);
uart_deinit(PICOPROBE_UART_INTERFACE);
uart_deinit(PROBE_UART_INTERFACE);
tud_cdc_write_clear();
tud_cdc_read_flush();
uart_init(PICOPROBE_UART_INTERFACE, line_coding->bit_rate);
uart_init(PROBE_UART_INTERFACE, line_coding->bit_rate);
switch (line_coding->parity) {
case CDC_LINE_CODING_PARITY_ODD:
@@ -173,7 +209,7 @@ void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_coding)
parity = UART_PARITY_EVEN;
break;
default:
picoprobe_info("invalid parity setting %u\n", line_coding->parity);
probe_info("invalid parity setting %u\n", line_coding->parity);
/* fallthrough */
case CDC_LINE_CODING_PARITY_NONE:
parity = UART_PARITY_NONE;
@@ -188,7 +224,7 @@ void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_coding)
data_bits = line_coding->data_bits;
break;
default:
picoprobe_info("invalid data bits setting: %u\n", line_coding->data_bits);
probe_info("invalid data bits setting: %u\n", line_coding->data_bits);
data_bits = 8;
break;
}
@@ -201,38 +237,64 @@ void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_coding)
stop_bits = 2;
break;
default:
picoprobe_info("invalid stop bits setting: %u\n", line_coding->stop_bits);
probe_info("invalid stop bits setting: %u\n", line_coding->stop_bits);
/* fallthrough */
case CDC_LINE_CONDING_STOP_BITS_1:
stop_bits = 1;
break;
}
uart_set_format(PICOPROBE_UART_INTERFACE, data_bits, stop_bits, parity);
uart_set_format(PROBE_UART_INTERFACE, data_bits, stop_bits, parity);
vTaskResume(uart_taskhandle);
}
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
{
#ifdef PICOPROBE_UART_RTS
gpio_put(PICOPROBE_UART_RTS, !rts);
#ifdef PROBE_UART_RTS
gpio_put(PROBE_UART_RTS, !rts);
#endif
#ifdef PICOPROBE_UART_DTR
gpio_put(PICOPROBE_UART_DTR, !dtr);
#ifdef PROBE_UART_DTR
gpio_put(PROBE_UART_DTR, !dtr);
#endif
/* CDC drivers use linestate as a bodge to activate/deactivate the interface.
* Resume our UART polling on activate, stop on deactivate */
if (!dtr && !rts) {
vTaskSuspend(uart_taskhandle);
#ifdef PICOPROBE_UART_RX_LED
gpio_put(PICOPROBE_UART_RX_LED, 0);
#ifdef PROBE_UART_RX_LED
gpio_put(PROBE_UART_RX_LED, 0);
rx_led_debounce = 0;
#endif
#ifdef PICOPROBE_UART_RX_LED
gpio_put(PICOPROBE_UART_TX_LED, 0);
#ifdef PROBE_UART_TX_LED
gpio_put(PROBE_UART_TX_LED, 0);
tx_led_debounce = 0;
#endif
} else
vTaskResume(uart_taskhandle);
}
void tud_cdc_send_break_cb(uint8_t itf, uint16_t wValue) {
switch(wValue) {
case 0:
uart_set_break(PROBE_UART_INTERFACE, false);
timed_break = false;
break;
case 0xffff:
uart_set_break(PROBE_UART_INTERFACE, true);
timed_break = false;
#ifdef PROBE_UART_TX_LED
gpio_put(PROBE_UART_TX_LED, 1);
tx_led_debounce = 1 << 30;
#endif
break;
default:
uart_set_break(PROBE_UART_INTERFACE, true);
timed_break = true;
#ifdef PROBE_UART_TX_LED
gpio_put(PROBE_UART_TX_LED, 1);
tx_led_debounce = 1 << 30;
#endif
break_expiry = xTaskGetTickCount() + (wValue * (configTICK_RATE_HZ / 1000));
break;
}
}

View File

@@ -28,7 +28,7 @@
void cdc_thread(void *ptr);
void cdc_uart_init(void);
void cdc_task(void);
bool cdc_task(void);
extern TaskHandle_t uart_taskhandle;

View File

@@ -26,27 +26,27 @@
#include <pico/stdlib.h>
#include <stdint.h>
#include "picoprobe_config.h"
#include "probe_config.h"
void led_init(void) {
#ifdef PICOPROBE_USB_CONNECTED_LED
gpio_init(PICOPROBE_USB_CONNECTED_LED);
gpio_set_dir(PICOPROBE_USB_CONNECTED_LED, GPIO_OUT);
#ifdef PROBE_USB_CONNECTED_LED
gpio_init(PROBE_USB_CONNECTED_LED);
gpio_set_dir(PROBE_USB_CONNECTED_LED, GPIO_OUT);
#endif
#ifdef PICOPROBE_DAP_CONNECTED_LED
gpio_init(PICOPROBE_DAP_CONNECTED_LED);
gpio_set_dir(PICOPROBE_DAP_CONNECTED_LED, GPIO_OUT);
#ifdef PROBE_DAP_CONNECTED_LED
gpio_init(PROBE_DAP_CONNECTED_LED);
gpio_set_dir(PROBE_DAP_CONNECTED_LED, GPIO_OUT);
#endif
#ifdef PICOPROBE_DAP_RUNNING_LED
gpio_init(PICOPROBE_DAP_RUNNING_LED);
gpio_set_dir(PICOPROBE_DAP_RUNNING_LED, GPIO_OUT);
#ifdef PROBE_DAP_RUNNING_LED
gpio_init(PROBE_DAP_RUNNING_LED);
gpio_set_dir(PROBE_DAP_RUNNING_LED, GPIO_OUT);
#endif
#ifdef PICOPROBE_UART_RX_LED
gpio_init(PICOPROBE_UART_RX_LED);
gpio_set_dir(PICOPROBE_UART_RX_LED, GPIO_OUT);
#ifdef PROBE_UART_RX_LED
gpio_init(PROBE_UART_RX_LED);
gpio_set_dir(PROBE_UART_RX_LED, GPIO_OUT);
#endif
#ifdef PICOPROBE_UART_TX_LED
gpio_init(PICOPROBE_UART_TX_LED);
gpio_set_dir(PICOPROBE_UART_TX_LED, GPIO_OUT);
#ifdef PROBE_UART_TX_LED
gpio_init(PROBE_UART_TX_LED);
gpio_set_dir(PROBE_UART_TX_LED, GPIO_OUT);
#endif
}

View File

@@ -34,7 +34,7 @@
#include "bsp/board.h"
#include "tusb.h"
#include "picoprobe_config.h"
#include "probe_config.h"
#include "probe.h"
#include "cdc_uart.h"
#include "get_serial.h"
@@ -42,8 +42,8 @@
#include "tusb_edpt_handler.h"
#include "DAP.h"
// UART0 for Picoprobe debug
// UART1 for picoprobe to target device
// UART0 for debugprobe debug
// UART1 for debugprobe to target device
static uint8_t TxDataBuffer[CFG_TUD_HID_EP_BUFSIZE];
static uint8_t RxDataBuffer[CFG_TUD_HID_EP_BUFSIZE];
@@ -62,11 +62,11 @@ void usb_thread(void *ptr)
wake = xTaskGetTickCount();
do {
tud_task();
#ifdef PICOPROBE_USB_CONNECTED_LED
if (!gpio_get(PICOPROBE_USB_CONNECTED_LED) && tud_ready())
gpio_put(PICOPROBE_USB_CONNECTED_LED, 1);
#ifdef PROBE_USB_CONNECTED_LED
if (!gpio_get(PROBE_USB_CONNECTED_LED) && tud_ready())
gpio_put(PROBE_USB_CONNECTED_LED, 1);
else
gpio_put(PICOPROBE_USB_CONNECTED_LED, 0);
gpio_put(PROBE_USB_CONNECTED_LED, 0);
#endif
// Go to sleep for up to a tick if nothing to do
if (!tud_task_event_ready())
@@ -85,13 +85,13 @@ int main(void) {
usb_serial_init();
cdc_uart_init();
tusb_init();
stdio_uart_init();
DAP_Setup();
stdio_uart_init();
led_init();
picoprobe_info("Welcome to Picoprobe!\n");
probe_info("Welcome to debugprobe!\n");
if (THREADED) {
/* UART needs to preempt USB as if we don't, characters get lost */
@@ -106,7 +106,7 @@ int main(void) {
tud_task();
cdc_task();
#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_DAP_V2)
#if (PROBE_DEBUG_PROTOCOL == PROTO_DAP_V2)
if (tud_vendor_available()) {
uint32_t resp_len;
tud_vendor_read(RxDataBuffer, sizeof(RxDataBuffer));
@@ -145,7 +145,7 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep
tud_hid_report(0, TxDataBuffer, response_size);
}
#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_DAP_V2)
#if (PROBE_DEBUG_PROTOCOL == PROTO_DAP_V2)
extern uint8_t const desc_ms_os_20[];
bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)

View File

@@ -31,7 +31,7 @@
#include <hardware/gpio.h>
#include "led.h"
#include "picoprobe_config.h"
#include "probe_config.h"
#include "probe.pio.h"
#include "tusb.h"
@@ -61,7 +61,7 @@ static struct _probe probe;
void probe_set_swclk_freq(uint freq_khz) {
uint clk_sys_freq_khz = clock_get_hz(clk_sys) / 1000;
picoprobe_info("Set swclk freq %dKHz sysclk %dkHz\n", freq_khz, clk_sys_freq_khz);
probe_info("Set swclk freq %dKHz sysclk %dkHz\n", freq_khz, clk_sys_freq_khz);
uint32_t divider = clk_sys_freq_khz / freq_khz / 4;
if (divider == 0)
divider = 1;
@@ -72,7 +72,7 @@ void probe_assert_reset(bool state)
{
#if defined(PROBE_PIN_RESET)
/* Change the direction to out to drive pin to 0 or to in to emulate open drain */
gpio_set_dir(PROBE_PIN_RESET, state);
gpio_set_dir(PROBE_PIN_RESET, state == 0 ? GPIO_OUT : GPIO_IN);
#endif
}
@@ -105,7 +105,7 @@ void probe_write_bits(uint bit_count, uint32_t data_byte) {
DEBUG_PINS_SET(probe_timing, DBG_PIN_WRITE);
pio_sm_put_blocking(pio0, PROBE_SM, fmt_probe_command(bit_count, true, CMD_WRITE));
pio_sm_put_blocking(pio0, PROBE_SM, data_byte);
picoprobe_dump("Write %d bits 0x%x\n", bit_count, data_byte);
probe_dump("Write %d bits 0x%x\n", bit_count, data_byte);
// Return immediately so we can cue up the next command whilst this one runs
DEBUG_PINS_CLR(probe_timing, DBG_PIN_WRITE);
}
@@ -124,7 +124,7 @@ uint32_t probe_read_bits(uint bit_count) {
data_shifted = data >> (32 - bit_count);
}
picoprobe_dump("Read %d bits 0x%x (shifted 0x%x)\n", bit_count, data, data_shifted);
probe_dump("Read %d bits 0x%x (shifted 0x%x)\n", bit_count, data, data_shifted);
DEBUG_PINS_CLR(probe_timing, DBG_PIN_READ);
return data_shifted;
}
@@ -170,6 +170,9 @@ void probe_deinit(void)
probe_read_mode();
pio_sm_set_enabled(pio0, PROBE_SM, 0);
pio_remove_program(pio0, &probe_program, probe.offset);
probe_assert_reset(1); // de-assert nRESET
probe.initted = 0;
}
}

View File

@@ -23,52 +23,52 @@
*
*/
#ifndef PICOPROBE_H_
#define PICOPROBE_H_
#ifndef PROBE_CONFIG_H_
#define PROBE_CONFIG_H_
#include "FreeRTOS.h"
#include "task.h"
#if false
#define picoprobe_info(format,args...) \
#define probe_info(format,args...) \
do { \
vTaskSuspendAll(); \
printf(format, ## args); \
xTaskResumeAll(); \
} while (0)
#else
#define picoprobe_info(format,...) ((void)0)
#define probe_info(format,...) ((void)0)
#endif
#if false
#define picoprobe_debug(format,args...) \
#define probe_debug(format,args...) \
do { \
vTaskSuspendAll(); \
printf(format, ## args); \
xTaskResumeAll(); \
} while (0)
#else
#define picoprobe_debug(format,...) ((void)0)
#define probe_debug(format,...) ((void)0)
#endif
#if false
#define picoprobe_dump(format,args...)\
#define probe_dump(format,args...)\
do { \
vTaskSuspendAll(); \
printf(format, ## args); \
xTaskResumeAll(); \
} while (0)
#else
#define picoprobe_dump(format,...) ((void)0)
#define probe_dump(format,...) ((void)0)
#endif
// TODO tie this up with PICO_BOARD defines in the main SDK
#ifndef DEBUGPROBE
#ifdef DEBUG_ON_PICO
#include "board_pico_config.h"
#else
#include "board_debugprobe_config.h"
#include "board_debug_probe_config.h"
#endif
//#include "board_example_config.h"
@@ -77,8 +77,8 @@ do { \
#define PROTO_DAP_V2 2
// Interface config
#ifndef PICOPROBE_DEBUG_PROTOCOL
#define PICOPROBE_DEBUG_PROTOCOL PROTO_DAP_V2
#ifndef PROBE_DEBUG_PROTOCOL
#define PROBE_DEBUG_PROTOCOL PROTO_DAP_V2
#endif
#endif

View File

@@ -19,7 +19,7 @@
/*
* This is a shim between the SW_DP functions and the PIO
* implementation used for Picoprobe. Instead of calling bitbash functions,
* implementation used for Debugprobe. Instead of calling bitbash functions,
* hand off the bit sequences to a SM for asynchronous completion.
*/
@@ -47,7 +47,7 @@ void SWJ_Sequence (uint32_t count, const uint8_t *data) {
probe_set_swclk_freq(MAKE_KHZ(DAP_Data.clock_delay));
cached_delay = DAP_Data.clock_delay;
}
picoprobe_debug("SWJ sequence count = %d FDB=0x%2x\n", count, data[0]);
probe_debug("SWJ sequence count = %d FDB=0x%2x\n", count, data[0]);
n = count;
while (n > 0) {
if (n > 8)
@@ -74,7 +74,7 @@ void SWD_Sequence (uint32_t info, const uint8_t *swdo, uint8_t *swdi) {
probe_set_swclk_freq(MAKE_KHZ(DAP_Data.clock_delay));
cached_delay = DAP_Data.clock_delay;
}
picoprobe_debug("SWD sequence\n");
probe_debug("SWD sequence\n");
n = info & SWD_SEQUENCE_CLK;
if (n == 0U) {
n = 64U;
@@ -119,7 +119,7 @@ uint8_t SWD_Transfer (uint32_t request, uint32_t *data) {
probe_set_swclk_freq(MAKE_KHZ(DAP_Data.clock_delay));
cached_delay = DAP_Data.clock_delay;
}
picoprobe_debug("SWD_transfer\n");
probe_debug("SWD_transfer\n");
/* Generate the request packet */
prq |= (1 << 0); /* Start Bit */
for (n = 1; n < 5; n++) {
@@ -149,7 +149,7 @@ uint8_t SWD_Transfer (uint32_t request, uint32_t *data) {
}
if (data)
*data = val;
picoprobe_debug("Read %02x ack %02x 0x%08x parity %01x\n",
probe_debug("Read %02x ack %02x 0x%08x parity %01x\n",
prq, ack, val, bit);
/* Turnaround for line idle */
probe_hiz_clocks(DAP_Data.swd_conf.turnaround);
@@ -163,7 +163,7 @@ uint8_t SWD_Transfer (uint32_t request, uint32_t *data) {
parity = __builtin_popcount(val);
/* Write Parity Bit */
probe_write_bits(1, parity & 0x1);
picoprobe_debug("write %02x ack %02x 0x%08x parity %01x\n",
probe_debug("write %02x ack %02x 0x%08x parity %01x\n",
prq, ack, val, parity);
}
/* Capture Timestamp */

View File

@@ -82,8 +82,8 @@ uint16_t dap_edpt_open(uint8_t __unused rhport, tusb_desc_interface_t const *itf
{
TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass &&
PICOPROBE_INTERFACE_SUBCLASS == itf_desc->bInterfaceSubClass &&
PICOPROBE_INTERFACE_PROTOCOL == itf_desc->bInterfaceProtocol, 0);
DAP_INTERFACE_SUBCLASS == itf_desc->bInterfaceSubClass &&
DAP_INTERFACE_PROTOCOL == itf_desc->bInterfaceProtocol, 0);
// Initialise circular buffer indices
USBResponseBuffer.wptr = 0;
@@ -198,20 +198,20 @@ void dap_thread(void *ptr)
*/
n = USBRequestBuffer.rptr;
while (USBRequestBuffer.data[n % DAP_PACKET_COUNT][0] == ID_DAP_QueueCommands) {
picoprobe_info("%u %u DAP queued cmd %s len %02x\n",
probe_info("%u %u 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;
n++;
while (n == USBRequestBuffer.wptr) {
/* Need yield in a loop here, as IN callbacks will also wake the thread */
picoprobe_info("DAP wait\n");
probe_info("DAP wait\n");
vTaskSuspend(dap_taskhandle);
}
}
// Read a single packet from the USB buffer into the DAP Request buffer
memcpy(DAPRequestBuffer, RD_SLOT_PTR(USBRequestBuffer), DAP_PACKET_SIZE);
picoprobe_info("%u %u DAP cmd %s len %02x\n",
probe_info("%u %u DAP cmd %s len %02x\n",
USBRequestBuffer.wptr, USBRequestBuffer.rptr,
dap_cmd_string[DAPRequestBuffer[0]], DAPRequestBuffer[1]);
USBRequestBuffer.rptr++;
@@ -227,7 +227,7 @@ void dap_thread(void *ptr)
}
_resp_len = DAP_ExecuteCommand(DAPRequestBuffer, DAPResponseBuffer);
picoprobe_info("%u %u DAP resp %s\n",
probe_info("%u %u DAP resp %s\n",
USBResponseBuffer.wptr, USBResponseBuffer.rptr,
dap_cmd_string[DAPResponseBuffer[0]]);
@@ -268,7 +268,7 @@ usbd_class_driver_t const _dap_edpt_driver =
.xfer_cb = dap_edpt_xfer_cb,
.sof = NULL,
#if CFG_TUSB_DEBUG >= 2
.name = "PICOPROBE ENDPOINT"
.name = "DAP ENDPOINT"
#endif
};

View File

@@ -12,8 +12,8 @@
#include "device/usbd_pvt.h"
#include "DAP_config.h"
#define PICOPROBE_INTERFACE_SUBCLASS 0x00
#define PICOPROBE_INTERFACE_PROTOCOL 0x00
#define DAP_INTERFACE_SUBCLASS 0x00
#define DAP_INTERFACE_PROTOCOL 0x00
typedef struct {
uint8_t data[DAP_PACKET_COUNT][DAP_PACKET_SIZE];
@@ -29,10 +29,10 @@ extern TaskHandle_t dap_taskhandle, tud_taskhandle;
void dap_thread(void *ptr);
/* Endpoint Handling */
void picoprobe_edpt_init(void);
uint16_t picoprobe_edpt_open(uint8_t __unused rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
bool picoprobe_edpt_control_xfer_cb(uint8_t __unused rhport, uint8_t stage, tusb_control_request_t const *request);
bool picoprobe_edpt_xfer_cb(uint8_t __unused rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
void dap_edpt_init(void);
uint16_t dap_edpt_open(uint8_t __unused rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
bool dap_edpt_control_xfer_cb(uint8_t __unused rhport, uint8_t stage, tusb_control_request_t const *request);
bool dap_edpt_xfer_cb(uint8_t __unused rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
/* Helper Functions */
bool buffer_full(buffer_t *buffer);

View File

@@ -27,7 +27,7 @@
#include "tusb.h"
#include "get_serial.h"
#include "picoprobe_config.h"
#include "probe_config.h"
//--------------------------------------------------------------------+
// Device Descriptors
@@ -36,7 +36,7 @@ tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_DAP_V2)
#if (PROBE_DEBUG_PROTOCOL == PROTO_DAP_V2)
.bcdUSB = 0x0210, // USB Specification version 2.1 for BOS
#else
.bcdUSB = 0x0110,
@@ -48,7 +48,7 @@ tusb_desc_device_t const desc_device =
.idVendor = 0x2E8A, // Pi
.idProduct = 0x000c, // CMSIS-DAP Debug Probe
.bcdDevice = 0x0103, // Version 01.03
.bcdDevice = 0x0200, // Version 02.00
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
@@ -77,10 +77,10 @@ enum
#define CDC_NOTIFICATION_EP_NUM 0x81
#define CDC_DATA_OUT_EP_NUM 0x02
#define CDC_DATA_IN_EP_NUM 0x83
#define PROBE_OUT_EP_NUM 0x04
#define PROBE_IN_EP_NUM 0x85
#define DAP_OUT_EP_NUM 0x04
#define DAP_IN_EP_NUM 0x85
#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_DAP_V1)
#if (PROBE_DEBUG_PROTOCOL == PROTO_DAP_V1)
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_HID_INOUT_DESC_LEN)
#else
#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_VENDOR_DESC_LEN)
@@ -97,19 +97,19 @@ uint8_t const * tud_hid_descriptor_report_cb(uint8_t itf)
return desc_hid_report;
}
uint8_t const desc_configuration[] =
uint8_t desc_configuration[] =
{
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, 0, 100),
// Interface 0
#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_DAP_V1)
#if (PROBE_DEBUG_PROTOCOL == PROTO_DAP_V1)
// HID (named interface)
TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_PROBE, 4, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), PROBE_OUT_EP_NUM, PROBE_IN_EP_NUM, CFG_TUD_HID_EP_BUFSIZE, 1),
#elif (PICOPROBE_DEBUG_PROTOCOL == PROTO_DAP_V2)
TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_PROBE, 4, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), DAP_OUT_EP_NUM, DAP_IN_EP_NUM, CFG_TUD_HID_EP_BUFSIZE, 1),
#elif (PROBE_DEBUG_PROTOCOL == PROTO_DAP_V2)
// Bulk (named interface)
TUD_VENDOR_DESCRIPTOR(ITF_NUM_PROBE, 5, PROBE_OUT_EP_NUM, PROBE_IN_EP_NUM, 64),
#elif (PICOPROBE_DEBUG_PROTOCOL == PROTO_OPENOCD_CUSTOM)
TUD_VENDOR_DESCRIPTOR(ITF_NUM_PROBE, 5, DAP_OUT_EP_NUM, DAP_IN_EP_NUM, 64),
#elif (PROBE_DEBUG_PROTOCOL == PROTO_OPENOCD_CUSTOM)
// Bulk
TUD_VENDOR_DESCRIPTOR(ITF_NUM_PROBE, 0, PROBE_OUT_EP_NUM, PROBE_IN_EP_NUM, 64),
TUD_VENDOR_DESCRIPTOR(ITF_NUM_PROBE, 0, DAP_OUT_EP_NUM, DAP_IN_EP_NUM, 64),
#endif
// Interface 1 + 2
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_COM, 6, CDC_NOTIFICATION_EP_NUM, 64, CDC_DATA_OUT_EP_NUM, CDC_DATA_IN_EP_NUM, 64),
@@ -121,6 +121,8 @@ uint8_t const desc_configuration[] =
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
(void) index; // for multiple configurations
/* Hack in CAP_BREAK support */
desc_configuration[CONFIG_TOTAL_LEN - TUD_CDC_DESC_LEN + 8 + 9 + 5 + 5 + 4 - 1] = 0x6;
return desc_configuration;
}