Compare commits
6 Commits
pio-progra
...
debug-prob
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59ced31058 | ||
|
|
4a3d23a85a | ||
|
|
b10589915c | ||
|
|
6cf7e08291 | ||
|
|
7adec12fa9 | ||
|
|
abc32c8ada |
@@ -35,8 +35,14 @@ target_include_directories(picoprobe PRIVATE
|
||||
|
||||
target_compile_options(picoprobe PRIVATE -Wall)
|
||||
|
||||
if (DEFINED ENV{PICOPROBE_LED})
|
||||
message("PICOPROBE_LED is defined as " $ENV{PICOPROBE_LED})
|
||||
target_compile_definitions(picoprobe PRIVATE PICOPROBE_LED=$ENV{PICOPROBE_LED})
|
||||
endif()
|
||||
|
||||
set(DBG_PIN_COUNT=4)
|
||||
|
||||
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)
|
||||
|
||||
target_include_directories(picoprobe PRIVATE src)
|
||||
|
||||
|
||||
@@ -3,9 +3,3 @@ Picoprobe allows a Pico / RP2040 to be used as USB -> SWD and UART bridge. This
|
||||
|
||||
# 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".
|
||||
|
||||
# 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
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023 Raspberry Pi (Trading) 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BOARD_DEBUGPROBE_H_
|
||||
#define BOARD_DEBUGPROBE_H_
|
||||
|
||||
#define PROBE_IO_SWDI
|
||||
#define PROBE_CDC_UART
|
||||
// No reset pin
|
||||
|
||||
// PIO config
|
||||
#define PROBE_SM 0
|
||||
#define PROBE_PIN_OFFSET 12
|
||||
#define PROBE_PIN_SWCLK (PROBE_PIN_OFFSET + 0)
|
||||
// For level-shifted input.
|
||||
#define PROBE_PIN_SWDI (PROBE_PIN_OFFSET + 1)
|
||||
#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 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_PRODUCT_STRING "Debug Probe (CMSIS-DAP)"
|
||||
|
||||
#endif
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023 Raspberry Pi (Trading) 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BOARD_EXAMPLE_H_
|
||||
#define BOARD_EXAMPLE_H_
|
||||
#error "Example board configuration requested - specify PICO_BOARD and re-run CMake."
|
||||
|
||||
/* Select one of these. */
|
||||
/* Direct connection - SWCLK/SWDIO on two GPIOs */
|
||||
#define PROBE_IO_RAW
|
||||
/* SWCLK connected to a GPIO, SWDO driven from a GPIO, SWDI sampled via a level shifter */
|
||||
#define PROBE_IO_SWDI
|
||||
/* Level-shifted SWCLK, SWDIO with separate SWDO, SWDI and OE_N pin */
|
||||
#define PROBE_IO_OEN
|
||||
|
||||
/* Include CDC interface to bridge to target UART. Omit if not used. */
|
||||
#define PROBE_CDC_UART
|
||||
/* Target reset GPIO (active-low). Omit if not used.*/
|
||||
#define PROBE_PIN_RESET 0
|
||||
|
||||
#define PROBE_SM 0
|
||||
#define PROBE_PIN_OFFSET 12
|
||||
/* PIO config for PROBE_IO_RAW */
|
||||
#if defined(PROBE_IO_RAW)
|
||||
#define PROBE_PIN_SWCLK (PROBE_PIN_OFFSET + 0)
|
||||
#define PROBE_PIN_SWDIO (PROBE_PIN_OFFSET + 1)
|
||||
#endif
|
||||
|
||||
/* PIO config for PROBE_IO_SWDI */
|
||||
#if defined(PROBE_IO_SWDI)
|
||||
#define PROBE_PIN_SWCLK (PROBE_PIN_OFFSET + 0)
|
||||
#define PROBE_PIN_SWDIO (PROBE_PIN_OFFSET + 1)
|
||||
#define PROBE_PIN_SWDI (PROBE_PIN_OFFSET + 2)
|
||||
#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)
|
||||
#define PROBE_PIN_SWDIOEN (PROBE_PIN_OFFSET + 0)
|
||||
#define PROBE_PIN_SWCLK (PROBE_PIN_OFFSET + 1)
|
||||
#define PROBE_PIN_SWDIO (PROBE_PIN_OFFSET + 2)
|
||||
#define PROBE_PIN_SWDI (PROBE_PIN_OFFSET + 3)
|
||||
#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
|
||||
#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_PRODUCT_STRING "Example Debug Probe"
|
||||
|
||||
#endif
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023 Raspberry Pi (Trading) 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BOARD_PICO_H_
|
||||
#define BOARD_PICO_H_
|
||||
|
||||
#define PROBE_IO_RAW
|
||||
#define PROBE_CDC_UART
|
||||
|
||||
// PIO config
|
||||
#define PROBE_SM 0
|
||||
#define PROBE_PIN_OFFSET 2
|
||||
#define PROBE_PIN_SWCLK (PROBE_PIN_OFFSET + 0) // 2
|
||||
#define PROBE_PIN_SWDIO (PROBE_PIN_OFFSET + 1) // 3
|
||||
// Target reset config
|
||||
#define PROBE_PIN_RESET 0
|
||||
|
||||
// UART config
|
||||
#define PICOPROBE_UART_TX 4
|
||||
#define PICOPROBE_UART_RX 5
|
||||
#define PICOPROBE_UART_INTERFACE uart1
|
||||
#define PICOPROBE_UART_BAUDRATE 115200
|
||||
|
||||
#define PICOPROBE_USB_CONNECTED_LED 25
|
||||
|
||||
#define PROBE_PRODUCT_STRING "Picoprobe (CMSIS-DAP)"
|
||||
|
||||
#endif
|
||||
@@ -3,6 +3,8 @@
|
||||
# This can be dropped into an external project to help locate this SDK
|
||||
# It should be include()ed prior to project()
|
||||
|
||||
# todo document
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
|
||||
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
|
||||
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
|
||||
@@ -18,8 +20,8 @@ if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_P
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
|
||||
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
|
||||
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the PICO SDK")
|
||||
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of PICO SDK from git if not otherwise locatable")
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
|
||||
|
||||
if (NOT PICO_SDK_PATH)
|
||||
@@ -29,31 +31,20 @@ if (NOT PICO_SDK_PATH)
|
||||
if (PICO_SDK_FETCH_FROM_GIT_PATH)
|
||||
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
|
||||
endif ()
|
||||
# GIT_SUBMODULES_RECURSE was added in 3.17
|
||||
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG master
|
||||
GIT_SUBMODULES_RECURSE FALSE
|
||||
)
|
||||
else ()
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG master
|
||||
)
|
||||
endif ()
|
||||
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG master
|
||||
)
|
||||
if (NOT pico_sdk)
|
||||
message("Downloading Raspberry Pi Pico SDK")
|
||||
message("Downloading PICO SDK")
|
||||
FetchContent_Populate(pico_sdk)
|
||||
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
|
||||
endif ()
|
||||
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
|
||||
else ()
|
||||
message(FATAL_ERROR
|
||||
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
|
||||
"PICO SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
@@ -65,9 +56,9 @@ endif ()
|
||||
|
||||
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
|
||||
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the PICO SDK")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
|
||||
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the PICO SDK" FORCE)
|
||||
|
||||
include(${PICO_SDK_INIT_CMAKE_FILE})
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
/* Memory allocation related definitions. */
|
||||
#define configSUPPORT_STATIC_ALLOCATION 0
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
#define configTOTAL_HEAP_SIZE (64*1024)
|
||||
#define configTOTAL_HEAP_SIZE (128*1024)
|
||||
#define configAPPLICATION_ALLOCATED_HEAP 0
|
||||
|
||||
/* Hook function related definitions. */
|
||||
|
||||
@@ -39,14 +39,8 @@ static uint8_t rx_buf[CFG_TUD_CDC_RX_BUFSIZE];
|
||||
// Actually s^-1 so 25ms
|
||||
#define DEBOUNCE_MS 40
|
||||
static uint debounce_ticks = 5;
|
||||
|
||||
#ifdef PICOPROBE_UART_TX_LED
|
||||
static uint tx_led_debounce;
|
||||
#endif
|
||||
|
||||
#ifdef PICOPROBE_UART_RX_LED
|
||||
static uint rx_led_debounce;
|
||||
#endif
|
||||
|
||||
void cdc_uart_init(void) {
|
||||
gpio_set_function(PICOPROBE_UART_TX, GPIO_FUNC_UART);
|
||||
|
||||
26
src/led.c
26
src/led.c
@@ -28,7 +28,16 @@
|
||||
|
||||
#include "picoprobe_config.h"
|
||||
|
||||
#define LED_COUNT_SHIFT 14
|
||||
#define LED_COUNT_MAX 5 * (1 << LED_COUNT_SHIFT)
|
||||
|
||||
static uint32_t led_count;
|
||||
|
||||
void led_init(void) {
|
||||
led_count = 0;
|
||||
gpio_init(PICOPROBE_LED);
|
||||
gpio_set_dir(PICOPROBE_LED, GPIO_OUT);
|
||||
gpio_put(PICOPROBE_LED, 1);
|
||||
#ifdef PICOPROBE_USB_CONNECTED_LED
|
||||
gpio_init(PICOPROBE_USB_CONNECTED_LED);
|
||||
gpio_set_dir(PICOPROBE_USB_CONNECTED_LED, GPIO_OUT);
|
||||
@@ -50,3 +59,20 @@ void led_init(void) {
|
||||
gpio_set_dir(PICOPROBE_UART_TX_LED, GPIO_OUT);
|
||||
#endif
|
||||
}
|
||||
|
||||
void led_task(void) {
|
||||
if (led_count != 0) {
|
||||
--led_count;
|
||||
gpio_put(PICOPROBE_LED, !((led_count >> LED_COUNT_SHIFT) & 1));
|
||||
}
|
||||
}
|
||||
|
||||
void led_signal_activity(uint total_bits) {
|
||||
if (led_count == 0) {
|
||||
gpio_put(PICOPROBE_LED, 0);
|
||||
}
|
||||
|
||||
if (led_count < LED_COUNT_MAX) {
|
||||
led_count += total_bits;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,5 +27,7 @@
|
||||
#define LED_H
|
||||
|
||||
void led_init(void);
|
||||
void led_task(void);
|
||||
void led_signal_activity(uint total_bits);
|
||||
|
||||
#endif
|
||||
|
||||
21
src/main.c
21
src/main.c
@@ -70,11 +70,6 @@ void usb_thread(void *ptr)
|
||||
} while (1);
|
||||
}
|
||||
|
||||
// Workaround API change in 0.13
|
||||
#if (TUSB_VERSION_MAJOR == 0) && (TUSB_VERSION_MINOR <= 12)
|
||||
#define tud_vendor_flush(x) ((void)0)
|
||||
#endif
|
||||
|
||||
void dap_thread(void *ptr)
|
||||
{
|
||||
uint32_t resp_len;
|
||||
@@ -83,7 +78,6 @@ void dap_thread(void *ptr)
|
||||
tud_vendor_read(RxDataBuffer, sizeof(RxDataBuffer));
|
||||
resp_len = DAP_ProcessCommand(RxDataBuffer, TxDataBuffer);
|
||||
tud_vendor_write(TxDataBuffer, resp_len);
|
||||
tud_vendor_flush();
|
||||
} else {
|
||||
// Trivial delay to save power
|
||||
vTaskDelay(1);
|
||||
@@ -92,14 +86,18 @@ void dap_thread(void *ptr)
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
uint32_t resp_len;
|
||||
|
||||
board_init();
|
||||
usb_serial_init();
|
||||
cdc_uart_init();
|
||||
tusb_init();
|
||||
|
||||
#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_OPENOCD_CUSTOM)
|
||||
probe_gpio_init();
|
||||
probe_init();
|
||||
#else
|
||||
DAP_Setup();
|
||||
|
||||
#endif
|
||||
led_init();
|
||||
|
||||
picoprobe_info("Welcome to Picoprobe!\n");
|
||||
@@ -116,10 +114,11 @@ int main(void) {
|
||||
while (!THREADED) {
|
||||
tud_task();
|
||||
cdc_task();
|
||||
|
||||
#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_DAP_V2)
|
||||
#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_OPENOCD_CUSTOM)
|
||||
probe_task();
|
||||
led_task();
|
||||
#elif (PICOPROBE_DEBUG_PROTOCOL == PROTO_DAP_V2)
|
||||
if (tud_vendor_available()) {
|
||||
uint32_t resp_len;
|
||||
tud_vendor_read(RxDataBuffer, sizeof(RxDataBuffer));
|
||||
resp_len = DAP_ProcessCommand(RxDataBuffer, TxDataBuffer);
|
||||
tud_vendor_write(TxDataBuffer, resp_len);
|
||||
|
||||
@@ -45,13 +45,41 @@
|
||||
#define picoprobe_dump(format,...) ((void)0)
|
||||
#endif
|
||||
|
||||
// TODO tie this up with PICO_BOARD defines in the main SDK
|
||||
|
||||
#include "board_pico_config.h"
|
||||
//#include "board_debugprobe_config.h"
|
||||
//#include "board_example_config.h"
|
||||
// PIO config
|
||||
#define PROBE_SM 0
|
||||
#define PROBE_PIN_OFFSET 12
|
||||
#define PROBE_PIN_SWCLK (PROBE_PIN_OFFSET + 0) // 2
|
||||
#define PROBE_PIN_SWDIO (PROBE_PIN_OFFSET + 2) // 3
|
||||
#define PROBE_PIN_SWDI (PROBE_PIN_OFFSET + 1) // 1 - for level-shifted input
|
||||
|
||||
// Target reset config
|
||||
#define PROBE_PIN_RESET 0
|
||||
|
||||
// UART config
|
||||
#define PICOPROBE_UART_TX 4
|
||||
#define PICOPROBE_UART_RX 5
|
||||
#define PICOPROBE_UART_INTERFACE uart1
|
||||
#define PICOPROBE_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
|
||||
|
||||
// LED config
|
||||
#ifndef PICOPROBE_LED
|
||||
|
||||
#ifndef PICO_DEFAULT_LED_PIN
|
||||
#error PICO_DEFAULT_LED_PIN is not defined, run PICOPROBE_LED=<led_pin> cmake
|
||||
#elif PICO_DEFAULT_LED_PIN == -1
|
||||
#error PICO_DEFAULT_LED_PIN is defined as -1, run PICOPROBE_LED=<led_pin> cmake
|
||||
#else
|
||||
#define PICOPROBE_LED PICO_DEFAULT_LED_PIN
|
||||
#endif
|
||||
|
||||
#define PROTO_OPENOCD_CUSTOM 0
|
||||
#define PROTO_DAP_V1 1
|
||||
#define PROTO_DAP_V2 2
|
||||
|
||||
@@ -61,3 +89,5 @@
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
237
src/probe.c
237
src/probe.c
@@ -52,6 +52,15 @@ CU_REGISTER_DEBUG_PINS(probe_timing)
|
||||
|
||||
#define PROBE_BUF_SIZE 8192
|
||||
struct _probe {
|
||||
// Total length
|
||||
uint tx_len;
|
||||
// Data back to host
|
||||
uint8_t tx_buf[PROBE_BUF_SIZE];
|
||||
|
||||
// CMD / Data RX'd from
|
||||
uint rx_len;
|
||||
uint8_t rx_buf[PROBE_BUF_SIZE];
|
||||
|
||||
// PIO offset
|
||||
uint offset;
|
||||
uint initted;
|
||||
@@ -59,56 +68,54 @@ struct _probe {
|
||||
|
||||
static struct _probe probe;
|
||||
|
||||
enum PROBE_CMDS {
|
||||
PROBE_INVALID = 0, // Invalid command
|
||||
PROBE_WRITE_BITS = 1, // Host wants us to write bits
|
||||
PROBE_READ_BITS = 2, // Host wants us to read bits
|
||||
PROBE_SET_FREQ = 3, // Set TCK
|
||||
PROBE_RESET = 4, // Reset all state
|
||||
PROBE_TARGET_RESET = 5, // Reset target
|
||||
};
|
||||
|
||||
struct __attribute__((__packed__)) probe_cmd_hdr {
|
||||
uint8_t id;
|
||||
uint8_t cmd;
|
||||
uint32_t bits;
|
||||
};
|
||||
|
||||
struct __attribute__((__packed__)) probe_pkt_hdr {
|
||||
uint32_t total_packet_length;
|
||||
};
|
||||
|
||||
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);
|
||||
uint32_t divider = clk_sys_freq_khz / freq_khz / 4;
|
||||
if (divider == 0)
|
||||
divider = 1;
|
||||
// Worked out with saleae
|
||||
uint32_t divider = clk_sys_freq_khz / freq_khz / 2;
|
||||
pio_sm_set_clkdiv_int_frac(pio0, PROBE_SM, divider, 0);
|
||||
}
|
||||
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef enum probe_pio_command {
|
||||
CMD_WRITE = 0,
|
||||
CMD_SKIP,
|
||||
CMD_TURNAROUND,
|
||||
CMD_READ
|
||||
} probe_pio_command_t;
|
||||
|
||||
static inline uint32_t fmt_probe_command(uint bit_count, bool out_en, probe_pio_command_t cmd) {
|
||||
uint cmd_addr =
|
||||
cmd == CMD_WRITE ? probe.offset + probe_offset_write_cmd :
|
||||
cmd == CMD_SKIP ? probe.offset + probe_offset_get_next_cmd :
|
||||
cmd == CMD_TURNAROUND ? probe.offset + probe_offset_turnaround_cmd :
|
||||
probe.offset + probe_offset_read_cmd;
|
||||
return ((bit_count - 1) & 0xff) | ((uint)out_en << 8) | (cmd_addr << 9);
|
||||
}
|
||||
|
||||
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, bit_count - 1);
|
||||
pio_sm_put_blocking(pio0, PROBE_SM, data_byte);
|
||||
DEBUG_PINS_SET(probe_timing, DBG_PIN_WRITE_WAIT);
|
||||
picoprobe_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
|
||||
// Wait for pio to push garbage to rx fifo so we know it has finished sending
|
||||
pio_sm_get_blocking(pio0, PROBE_SM);
|
||||
DEBUG_PINS_CLR(probe_timing, DBG_PIN_WRITE_WAIT);
|
||||
DEBUG_PINS_CLR(probe_timing, DBG_PIN_WRITE);
|
||||
}
|
||||
|
||||
void probe_hiz_clocks(uint bit_count) {
|
||||
pio_sm_put_blocking(pio0, PROBE_SM, fmt_probe_command(bit_count, false, CMD_TURNAROUND));
|
||||
pio_sm_put_blocking(pio0, PROBE_SM, 0);
|
||||
}
|
||||
|
||||
uint32_t probe_read_bits(uint bit_count) {
|
||||
DEBUG_PINS_SET(probe_timing, DBG_PIN_READ);
|
||||
pio_sm_put_blocking(pio0, PROBE_SM, fmt_probe_command(bit_count, false, CMD_READ));
|
||||
pio_sm_put_blocking(pio0, PROBE_SM, bit_count - 1);
|
||||
uint32_t data = pio_sm_get_blocking(pio0, PROBE_SM);
|
||||
uint32_t data_shifted = data;
|
||||
if (bit_count < 32) {
|
||||
@@ -120,39 +127,69 @@ uint32_t probe_read_bits(uint bit_count) {
|
||||
return data_shifted;
|
||||
}
|
||||
|
||||
static void probe_wait_idle() {
|
||||
pio0->fdebug = 1u << (PIO_FDEBUG_TXSTALL_LSB + PROBE_SM);
|
||||
while (!(pio0->fdebug & (1u << (PIO_FDEBUG_TXSTALL_LSB + PROBE_SM))))
|
||||
;
|
||||
}
|
||||
|
||||
void probe_read_mode(void) {
|
||||
pio_sm_put_blocking(pio0, PROBE_SM, fmt_probe_command(0, false, CMD_SKIP));
|
||||
probe_wait_idle();
|
||||
pio_sm_exec(pio0, PROBE_SM, pio_encode_jmp(probe.offset + probe_offset_in_posedge));
|
||||
while(pio0->dbg_padoe & (1 << PROBE_PIN_SWDIO));
|
||||
}
|
||||
|
||||
void probe_write_mode(void) {
|
||||
pio_sm_put_blocking(pio0, PROBE_SM, fmt_probe_command(0, true, CMD_SKIP));
|
||||
probe_wait_idle();
|
||||
pio_sm_exec(pio0, PROBE_SM, pio_encode_jmp(probe.offset + probe_offset_out_negedge));
|
||||
while(!(pio0->dbg_padoe & (1 << PROBE_PIN_SWDIO)));
|
||||
}
|
||||
|
||||
void probe_gpio_init()
|
||||
{
|
||||
// Funcsel pins
|
||||
pio_gpio_init(pio0, PROBE_PIN_SWCLK);
|
||||
pio_gpio_init(pio0, PROBE_PIN_SWDIO);
|
||||
// Make sure SWDIO has a pullup on it. Idle state is high
|
||||
gpio_pull_up(PROBE_PIN_SWDIO);
|
||||
}
|
||||
|
||||
void probe_init() {
|
||||
// Target reset pin: pull up, input to emulate open drain pin
|
||||
gpio_pull_up(PROBE_PIN_RESET);
|
||||
// gpio_init will leave the pin cleared and set as input
|
||||
gpio_init(PROBE_PIN_RESET);
|
||||
if (!probe.initted) {
|
||||
uint offset = pio_add_program(pio0, &probe_program);
|
||||
probe.offset = offset;
|
||||
|
||||
pio_sm_config sm_config = probe_program_get_default_config(offset);
|
||||
probe_sm_init(&sm_config);
|
||||
|
||||
// Set SWCLK as a sideset pin
|
||||
sm_config_set_sideset_pins(&sm_config, PROBE_PIN_SWCLK);
|
||||
|
||||
// Set SWDIO offset
|
||||
sm_config_set_out_pins(&sm_config, PROBE_PIN_SWDIO, 1);
|
||||
sm_config_set_set_pins(&sm_config, PROBE_PIN_SWDIO, 1);
|
||||
#ifdef PROBE_PIN_SWDI
|
||||
sm_config_set_in_pins(&sm_config, PROBE_PIN_SWDI);
|
||||
#else
|
||||
sm_config_set_in_pins(&sm_config, PROBE_PIN_SWDIO);
|
||||
#endif
|
||||
|
||||
// Set SWD and SWDIO pins as output to start. This will be set in the sm
|
||||
pio_sm_set_consecutive_pindirs(pio0, PROBE_SM, PROBE_PIN_OFFSET, 2, true);
|
||||
|
||||
// shift output right, autopull off, autopull threshold
|
||||
sm_config_set_out_shift(&sm_config, true, false, 0);
|
||||
// shift input right as swd data is lsb first, autopush off
|
||||
sm_config_set_in_shift(&sm_config, true, false, 0);
|
||||
|
||||
// Init SM with config
|
||||
pio_sm_init(pio0, PROBE_SM, offset, &sm_config);
|
||||
|
||||
// Set up divisor
|
||||
probe_set_swclk_freq(1000);
|
||||
|
||||
// Jump SM to command dispatch routine, and enable it
|
||||
pio_sm_exec(pio0, PROBE_SM, offset + probe_offset_get_next_cmd);
|
||||
// Enable SM
|
||||
pio_sm_set_enabled(pio0, PROBE_SM, 1);
|
||||
probe.initted = 1;
|
||||
}
|
||||
|
||||
// Jump to write program
|
||||
probe_write_mode();
|
||||
}
|
||||
|
||||
void probe_deinit(void)
|
||||
@@ -164,3 +201,119 @@ void probe_deinit(void)
|
||||
probe.initted = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void probe_handle_read(uint total_bits) {
|
||||
picoprobe_debug("Read %d bits\n", total_bits);
|
||||
probe_read_mode();
|
||||
|
||||
uint chunk;
|
||||
uint bits = total_bits;
|
||||
while (bits > 0) {
|
||||
if (bits > 8) {
|
||||
chunk = 8;
|
||||
} else {
|
||||
chunk = bits;
|
||||
}
|
||||
probe.tx_buf[probe.tx_len] = (uint8_t)probe_read_bits(chunk);
|
||||
probe.tx_len++;
|
||||
// Decrement remaining bits
|
||||
bits -= chunk;
|
||||
}
|
||||
}
|
||||
|
||||
void probe_handle_write(uint8_t *data, uint total_bits) {
|
||||
picoprobe_debug("Write %d bits\n", total_bits);
|
||||
|
||||
led_signal_activity(total_bits);
|
||||
|
||||
probe_write_mode();
|
||||
|
||||
uint chunk;
|
||||
uint bits = total_bits;
|
||||
while (bits > 0) {
|
||||
if (bits > 8) {
|
||||
chunk = 8;
|
||||
} else {
|
||||
chunk = bits;
|
||||
}
|
||||
|
||||
probe_write_bits(chunk, (uint32_t)*data++);
|
||||
bits -= chunk;
|
||||
}
|
||||
}
|
||||
|
||||
void probe_prepare_read_header(struct probe_cmd_hdr *hdr) {
|
||||
// We have a read so need to prefix the data with the cmd header
|
||||
if (probe.tx_len == 0) {
|
||||
// Reserve some space for probe_pkt_hdr
|
||||
probe.tx_len += sizeof(struct probe_pkt_hdr);
|
||||
}
|
||||
|
||||
memcpy((void*)&probe.tx_buf[probe.tx_len], hdr, sizeof(struct probe_cmd_hdr));
|
||||
probe.tx_len += sizeof(struct probe_cmd_hdr);
|
||||
}
|
||||
|
||||
void probe_handle_pkt(void) {
|
||||
uint8_t *pkt = &probe.rx_buf[0] + sizeof(struct probe_pkt_hdr);
|
||||
uint remaining = probe.rx_len - sizeof(struct probe_pkt_hdr);
|
||||
|
||||
DEBUG_PINS_SET(probe_timing, DBG_PIN_PKT);
|
||||
|
||||
picoprobe_debug("Processing packet of length %d\n", probe.rx_len);
|
||||
|
||||
probe.tx_len = 0;
|
||||
while (remaining) {
|
||||
struct probe_cmd_hdr *hdr = (struct probe_cmd_hdr*)pkt;
|
||||
uint data_bytes = DIV_ROUND_UP(hdr->bits, 8);
|
||||
pkt += sizeof(struct probe_cmd_hdr);
|
||||
remaining -= sizeof(struct probe_cmd_hdr);
|
||||
|
||||
if (hdr->cmd == PROBE_WRITE_BITS) {
|
||||
uint8_t *data = pkt;
|
||||
probe_handle_write(data, hdr->bits);
|
||||
pkt += data_bytes;
|
||||
remaining -= data_bytes;
|
||||
} else if (hdr->cmd == PROBE_READ_BITS) {
|
||||
probe_prepare_read_header(hdr);
|
||||
probe_handle_read(hdr->bits);
|
||||
} else if (hdr->cmd == PROBE_SET_FREQ) {
|
||||
probe_set_swclk_freq(hdr->bits);
|
||||
} else if (hdr->cmd == PROBE_RESET) {
|
||||
// TODO: Is there anything to do after a reset?
|
||||
// tx len and rx len should already be 0
|
||||
;
|
||||
} else if (hdr->cmd == PROBE_TARGET_RESET) {
|
||||
probe_assert_reset(hdr->bits);
|
||||
}
|
||||
}
|
||||
probe.rx_len = 0;
|
||||
|
||||
if (probe.tx_len) {
|
||||
// Fill in total packet length before sending
|
||||
struct probe_pkt_hdr *tx_hdr = (struct probe_pkt_hdr*)&probe.tx_buf[0];
|
||||
tx_hdr->total_packet_length = probe.tx_len;
|
||||
tud_vendor_write(&probe.tx_buf[0], probe.tx_len);
|
||||
picoprobe_debug("Picoprobe wrote %d response bytes\n", probe.tx_len);
|
||||
}
|
||||
probe.tx_len = 0;
|
||||
|
||||
DEBUG_PINS_CLR(probe_timing, DBG_PIN_PKT);
|
||||
}
|
||||
|
||||
// USB bits
|
||||
void probe_task(void) {
|
||||
if ( tud_vendor_available() ) {
|
||||
uint count = tud_vendor_read(&probe.rx_buf[probe.rx_len], 64);
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
probe.rx_len += count;
|
||||
}
|
||||
|
||||
if (probe.rx_len >= sizeof(struct probe_pkt_hdr)) {
|
||||
struct probe_pkt_hdr *pkt_hdr = (struct probe_pkt_hdr*)&probe.rx_buf[0];
|
||||
if (pkt_hdr->total_packet_length == probe.rx_len) {
|
||||
probe_handle_pkt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
16
src/probe.h
16
src/probe.h
@@ -26,24 +26,18 @@
|
||||
#ifndef PROBE_H_
|
||||
#define PROBE_H_
|
||||
|
||||
#if defined(PROBE_IO_RAW) || defined(PROBE_IO_SWDI)
|
||||
#include "probe.pio.h"
|
||||
#endif
|
||||
|
||||
#if defined(PROBE_IO_OEN)
|
||||
#include "probe_oen.pio.h"
|
||||
#endif
|
||||
|
||||
void probe_set_swclk_freq(uint freq_khz);
|
||||
|
||||
// Bit counts in the range 1..256
|
||||
void probe_write_bits(uint bit_count, uint32_t data_byte);
|
||||
uint32_t probe_read_bits(uint bit_count);
|
||||
void probe_hiz_clocks(uint bit_count);
|
||||
|
||||
void probe_read_mode(void);
|
||||
void probe_write_mode(void);
|
||||
|
||||
void probe_handle_read(uint total_bits);
|
||||
void probe_handle_write(uint8_t *data, uint total_bits);
|
||||
|
||||
void probe_task(void);
|
||||
void probe_gpio_init(void);
|
||||
void probe_init(void);
|
||||
void probe_deinit(void);
|
||||
|
||||
|
||||
106
src/probe.pio
106
src/probe.pio
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021-2023 Raspberry Pi (Trading) Ltd.
|
||||
* Copyright (c) 2021 Raspberry Pi (Trading) 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
|
||||
@@ -23,91 +23,27 @@
|
||||
*
|
||||
*/
|
||||
|
||||
// Every TX FIFO entry is either a command, or up to 32 bits of data.
|
||||
// Command format:
|
||||
//
|
||||
// | 13:9 | 8 | 7:0 |
|
||||
// | Cmd | Dir | Count |
|
||||
//
|
||||
// Count is the number of bits to be transferred by this command, minus 1.
|
||||
// Dir is the output enable for the SWDIO pin.
|
||||
// Cmd is the address of the write_cmd, read_cmd or get_next_cmd label.
|
||||
//
|
||||
// write_cmd expects a FIFO data entry, but read_cmd does not.
|
||||
//
|
||||
// read_cmd pushes data to the FIFO, but write_cmd does not. (The lack of RX
|
||||
// garbage on writes allows the interface code to return early after pushing a
|
||||
// write command, as there is no need in general to poll for a command's
|
||||
// completion as long as all commands are executed in order.)
|
||||
//
|
||||
// The SWCLK period is 4 PIO SM execution cycles.
|
||||
|
||||
.program probe
|
||||
.side_set 1 opt
|
||||
|
||||
public write_cmd:
|
||||
public turnaround_cmd: ; Alias of write, used for probe_oen.pio
|
||||
pull
|
||||
write_bitloop:
|
||||
out pins, 1 [1] side 0x0 ; Data is output by host on negedge
|
||||
jmp x-- write_bitloop [1] side 0x1 ; ...and captured by target on posedge
|
||||
; Fall through to next command
|
||||
.wrap_target
|
||||
public get_next_cmd:
|
||||
pull side 0x0 ; SWCLK is initially low
|
||||
out x, 8 ; Get bit count
|
||||
out pindirs, 1 ; Set SWDIO direction
|
||||
out pc, 5 ; Go to command routine
|
||||
public out_negedge:
|
||||
set pindirs, 1 side 0x0 ; Init OE clock 0
|
||||
pull ; Pull number of bits to shift -1 from tx fifo and put into output shift register
|
||||
mov x, osr ; mov bits to shift -1 from output shift register into x
|
||||
pull ; Pull data to shift out
|
||||
out_negedge_bitloop:
|
||||
out pins, 1 side 0x0 ; clock data out on falling edge
|
||||
jmp x-- out_negedge_bitloop side 0x1 ; data is present for posedge
|
||||
set pins, 1 side 0x0 ; Drive data high (idle bus state)
|
||||
push ; Push to rx fifo just so processor knows when done
|
||||
jmp out_negedge ; Wait for next transaction
|
||||
|
||||
read_bitloop:
|
||||
nop ; Additional delay on taken loop branch
|
||||
public read_cmd:
|
||||
in pins, 1 [1] side 0x1 ; Data is captured by host on posedge
|
||||
jmp x-- read_bitloop side 0x0
|
||||
push
|
||||
.wrap ; Wrap to next command
|
||||
|
||||
|
||||
; Implement probe_gpio_init() and probe_sm_init() methods here - set pins, offsets, sidesets etc
|
||||
% c-sdk {
|
||||
|
||||
static inline void probe_gpio_init()
|
||||
{
|
||||
#if defined(PROBE_PIN_RESET)
|
||||
// Target reset pin: pull up, input to emulate open drain pin
|
||||
gpio_pull_up(PROBE_PIN_RESET);
|
||||
// gpio_init will leave the pin cleared and set as input
|
||||
gpio_init(PROBE_PIN_RESET);
|
||||
#endif
|
||||
// Funcsel pins
|
||||
pio_gpio_init(pio0, PROBE_PIN_SWCLK);
|
||||
pio_gpio_init(pio0, PROBE_PIN_SWDIO);
|
||||
// Make sure SWDIO has a pullup on it. Idle state is high
|
||||
gpio_pull_up(PROBE_PIN_SWDIO);
|
||||
}
|
||||
|
||||
static inline void probe_sm_init(pio_sm_config* sm_config) {
|
||||
|
||||
// Set SWCLK as a sideset pin
|
||||
sm_config_set_sideset_pins(sm_config, PROBE_PIN_SWCLK);
|
||||
|
||||
// Set SWDIO offset
|
||||
sm_config_set_out_pins(sm_config, PROBE_PIN_SWDIO, 1);
|
||||
sm_config_set_set_pins(sm_config, PROBE_PIN_SWDIO, 1);
|
||||
#ifdef PROBE_IO_SWDI
|
||||
sm_config_set_in_pins(sm_config, PROBE_PIN_SWDI);
|
||||
#else
|
||||
sm_config_set_in_pins(sm_config, PROBE_PIN_SWDIO);
|
||||
#endif
|
||||
|
||||
|
||||
// Set SWD and SWDIO pins as output to start. This will be set in the sm
|
||||
pio_sm_set_consecutive_pindirs(pio0, PROBE_SM, PROBE_PIN_OFFSET, 2, true);
|
||||
|
||||
// shift output right, autopull off, autopull threshold
|
||||
sm_config_set_out_shift(sm_config, true, false, 0);
|
||||
// shift input right as swd data is lsb first, autopush off
|
||||
sm_config_set_in_shift(sm_config, true, false, 0);
|
||||
}
|
||||
|
||||
%}
|
||||
public in_posedge:
|
||||
set pindirs, 0 side 0x0 ; INIT IE clock 0
|
||||
pull ; Pull number of bits to shift -1 from tx fifo and put into output shift register
|
||||
mov x, osr ; mov bits to shift -1 from output shift register into x into x
|
||||
in_posedge_bitloop:
|
||||
in pins, 1 side 0x1 ; Generate posedge and read data
|
||||
jmp x-- in_posedge_bitloop side 0x0 ;
|
||||
push ; Push to rx fifo when done
|
||||
jmp in_posedge ; Jump back to start
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
; Output-enable active-low variant of the SWD probe
|
||||
|
||||
; This program is very similar to the one in probe.pio. The only difference is
|
||||
; that here write_cmd and turnaround_cmd are split into two separate routines,
|
||||
; whose difference is OEn being high/low.
|
||||
|
||||
; SWDIO_OEn is pin 0, SWCLK pin 1, SWDIO (out) pin 2, SWDI (in) pin 3.
|
||||
; Pin 0 and 1 are sideset pins
|
||||
|
||||
.program probe
|
||||
.side_set 2 opt
|
||||
|
||||
public turnaround_cmd:
|
||||
pull
|
||||
turnaround_bitloop:
|
||||
nop [1] side 0x1
|
||||
jmp x-- turnaround_bitloop [1] side 0x3
|
||||
jmp get_next_cmd
|
||||
|
||||
public write_cmd:
|
||||
pull
|
||||
write_bitloop:
|
||||
out pins, 1 [1] side 0x0 ; Data is output by host on negedge
|
||||
jmp x-- write_bitloop [1] side 0x2 ; ...and captured by target on posedge
|
||||
; Fall through to next command
|
||||
.wrap_target
|
||||
public get_next_cmd:
|
||||
pull side 0x1 ; SWCLK initially low, OEn disabled
|
||||
out x, 8 ; Get bit count
|
||||
out pindirs, 1 ; Set SWDIO direction
|
||||
out pc, 5 ; Go to command routine
|
||||
|
||||
read_bitloop:
|
||||
nop ; Additional delay on taken loop branch
|
||||
public read_cmd:
|
||||
in pins, 1 [1] side 0x3 ; Data is captured by host on posedge
|
||||
jmp x-- read_bitloop side 0x1
|
||||
push
|
||||
.wrap ; Wrap to next command
|
||||
|
||||
|
||||
; Implement probe_gpio_init() and probe_sm_init() methods here - set pins, offsets, sidesets etc
|
||||
% c-sdk {
|
||||
|
||||
static inline void probe_gpio_init()
|
||||
{
|
||||
#if defined(PROBE_PIN_RESET)
|
||||
// Target reset pin: pull up, input to emulate open drain pin
|
||||
gpio_pull_up(PROBE_PIN_RESET);
|
||||
// gpio_init will leave the pin cleared and set as input
|
||||
gpio_init(PROBE_PIN_RESET);
|
||||
#endif
|
||||
// Funcsel pins
|
||||
pio_gpio_init(pio0, PROBE_PIN_SWDIOEN);
|
||||
pio_gpio_init(pio0, PROBE_PIN_SWCLK);
|
||||
pio_gpio_init(pio0, PROBE_PIN_SWDIO);
|
||||
|
||||
// Make sure SWDIO has a pullup on it. Idle state is high
|
||||
gpio_pull_up(PROBE_PIN_SWDIO);
|
||||
gpio_pull_up(PROBE_PIN_SWDIOEN);
|
||||
}
|
||||
|
||||
static inline void probe_sm_init(pio_sm_config* sm_config) {
|
||||
|
||||
// Set SWDIOEN and SWCLK as sideset pins
|
||||
sm_config_set_sideset_pins(sm_config, PROBE_PIN_SWDIOEN);
|
||||
|
||||
// Set SWDIO offset
|
||||
sm_config_set_out_pins(sm_config, PROBE_PIN_SWDIO, 1);
|
||||
sm_config_set_set_pins(sm_config, PROBE_PIN_SWDIO, 1);
|
||||
sm_config_set_in_pins(sm_config, PROBE_PIN_SWDI);
|
||||
|
||||
// Set SWDIOEN, SWD and SWDIO pins as output to start. This will be set in the sm
|
||||
pio_sm_set_consecutive_pindirs(pio0, PROBE_SM, PROBE_PIN_OFFSET, 3, true);
|
||||
|
||||
// shift output right, autopull off, autopull threshold
|
||||
sm_config_set_out_shift(sm_config, true, false, 0);
|
||||
// shift input right as swd data is lsb first, autopush off
|
||||
sm_config_set_in_shift(sm_config, true, false, 0);
|
||||
}
|
||||
|
||||
%}
|
||||
@@ -133,6 +133,8 @@ uint8_t SWD_Transfer (uint32_t request, uint32_t *data) {
|
||||
probe_write_bits(8, prq);
|
||||
|
||||
/* Turnaround (ignore read bits) */
|
||||
probe_read_mode();
|
||||
|
||||
ack = probe_read_bits(DAP_Data.swd_conf.turnaround + 3);
|
||||
ack >>= DAP_Data.swd_conf.turnaround;
|
||||
|
||||
@@ -152,10 +154,12 @@ uint8_t SWD_Transfer (uint32_t request, uint32_t *data) {
|
||||
picoprobe_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);
|
||||
probe_read_bits(DAP_Data.swd_conf.turnaround);
|
||||
probe_write_mode();
|
||||
} else {
|
||||
/* Turnaround for write */
|
||||
probe_hiz_clocks(DAP_Data.swd_conf.turnaround);
|
||||
probe_read_bits(DAP_Data.swd_conf.turnaround);
|
||||
probe_write_mode();
|
||||
|
||||
/* Write WDATA[0:31] */
|
||||
val = *data;
|
||||
@@ -174,9 +178,9 @@ uint8_t SWD_Transfer (uint32_t request, uint32_t *data) {
|
||||
/* Idle cycles - drive 0 for N clocks */
|
||||
if (DAP_Data.transfer.idle_cycles) {
|
||||
for (n = DAP_Data.transfer.idle_cycles; n; ) {
|
||||
if (n > 256) {
|
||||
probe_write_bits(256, 0);
|
||||
n -= 256;
|
||||
if (n > 32) {
|
||||
probe_write_bits(32, 0);
|
||||
n -= 32;
|
||||
} else {
|
||||
probe_write_bits(n, 0);
|
||||
n -= n;
|
||||
@@ -191,7 +195,8 @@ uint8_t SWD_Transfer (uint32_t request, uint32_t *data) {
|
||||
/* Dummy Read RDATA[0:31] + Parity */
|
||||
probe_read_bits(33);
|
||||
}
|
||||
probe_hiz_clocks(DAP_Data.swd_conf.turnaround);
|
||||
probe_read_bits(DAP_Data.swd_conf.turnaround);
|
||||
probe_write_mode();
|
||||
if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) == 0U)) {
|
||||
/* Dummy Write WDATA[0:31] + Parity */
|
||||
probe_write_bits(32, 0);
|
||||
@@ -204,6 +209,7 @@ uint8_t SWD_Transfer (uint32_t request, uint32_t *data) {
|
||||
n = DAP_Data.swd_conf.turnaround + 32U + 1U;
|
||||
/* Back off data phase */
|
||||
probe_read_bits(n);
|
||||
probe_write_mode();
|
||||
return ((uint8_t)ack);
|
||||
}
|
||||
|
||||
|
||||
@@ -74,10 +74,6 @@
|
||||
#define CFG_TUD_VENDOR_RX_BUFSIZE 8192
|
||||
#define CFG_TUD_VENDOR_TX_BUFSIZE 8192
|
||||
|
||||
#ifndef TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX
|
||||
#define TUD_OPT_RP2040_USB_DEVICE_UFRAME_FIX 1
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -47,7 +47,11 @@ tusb_desc_device_t const desc_device =
|
||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||
|
||||
.idVendor = 0x2E8A, // Pi
|
||||
#if (PICOPROBE_DEBUG_PROTOCOL == PROTO_OPENOCD_CUSTOM)
|
||||
.idProduct = 0x0004, // Picoprobe
|
||||
#else
|
||||
.idProduct = 0x000c, // CMSIS-DAP Debug Probe
|
||||
#endif
|
||||
.bcdDevice = 0x0101, // Version 01.01
|
||||
.iManufacturer = 0x01,
|
||||
.iProduct = 0x02,
|
||||
@@ -133,7 +137,7 @@ char const* string_desc_arr [] =
|
||||
{
|
||||
(const char[]) { 0x09, 0x04 }, // 0: is supported language is English (0x0409)
|
||||
"Raspberry Pi", // 1: Manufacturer
|
||||
PROBE_PRODUCT_STRING, // 2: Product
|
||||
"Debug Probe (CMSIS-DAP)", // 2: Product
|
||||
usb_serial, // 3: Serial, uses flash unique ID
|
||||
"CMSIS-DAP v1 Interface", // 4: Interface descriptor for HID transport
|
||||
"CMSIS-DAP v2 Interface", // 5: Interface descriptor for Bulk transport
|
||||
|
||||
Reference in New Issue
Block a user