stm32f1/lib/swd.h

208 lines
9.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/** library for Serial Wire Debug (SWD) communication
* @file
* @author King Kévin <kingkevin@cuvoodoo.info>
* @copyright SPDX-License-Identifier: GPL-3.0-or-later
* @date 2018-2021
* @note peripherals used: timer @ref swd_timer, GPIO @ref swd_gpio
* @implements "ARM Debug Interface Architecture Specification ADIv6.0" (ARM IHI 0074A)
* @note this library implements DP architecture version 3 (DPv3), but only DPv1 feature could be tested.
* @implements The physical layer (electrical characteristic and timing) is described in "ARM DSTREAM System and Interface Design Reference Guide" (ARM DUI0499K)
*/
/** @remark{
* This library implements DP architecture version 3 (DPv3), but only DPv1 feature could be tested.
*
* See B2.1.1 DP architecture versions summary for more details about the versions:
* - DPv0 is only available using JTAG (e.g. does not support SWD).
* - DPv1 introduces SWD (with protocol version 1).
* - DPv2 adds multi-drop support (with protocol version 2).
* - DPv3 add register for 64-bit support.
*
* I couldn't find any hardware supporting SWD protocol version 2 to test DPv2 and DPv3 features, in particular dormant state and target select.
* According to https://developer.arm.com/docs/103489514/latest/does-the-cortex-m3-or-cortex-m4-processor-that-i-have-licensed-support-multi-drop-serial-wire-debug, although it is a property of the debug standard (e.g. CoreSight block) rather than core, no Cortex-M3 or Cortex-M4 seem to support DPv2/SWDv2.
* }
*/
#pragma once
/** Debug Port (DP) register address
* @implements ARM IHI 0074A B2.1.2 DP architecture version 3 (DPv3) address map
*/
enum swd_a_dp_e {
SWD_A_DP_DPIDR = 0x0, /**< Debug Port Identification Register (DP: v1, access: RO) */
SWD_A_DP_DPIDR1 = 0x0, /**< Debug Port Identification Register 1 (DP: v3, access: RO) */
SWD_A_DP_BASEPTR0 = 0x0, /**< Base Pointer 0 (DP: v3, access: RO) */
SWD_A_DP_BASEPTR1 = 0x0, /**< Base Pointer 1 (DP: v3, access: RO) */
SWD_A_DP_ABORT = 0x0, /**< AP Abort register (DP: v0, access: WO) */
SWD_A_DP_CTRL_STAT = 0x4, /**< Control/Status register (DP: v0, access: RW) */
SWD_A_DP_DLCR = 0x4, /**< Data Link Control Register (DP: v1, access: RW) */
SWD_A_DP_TARGETID = 0x4, /**< Target Identification register (DP: v2, access: RO) */
SWD_A_DP_DLPIDR = 0x4, /**< Data Link Protocol Identification Register (DP: v2, access: RO) */
SWD_A_DP_EVENTSTAT = 0x4, /**< Event Status register (DP: v0, access: RO) */
SWD_A_DP_SELECT1 = 0x4, /**< AP Select register 1 (DP: v3, access: WO) */
SWD_A_DP_SELECT = 0x8, /**< AP Select register (DP: v0, access: WO) */
SWD_A_DP_RESEND = 0x8, /**< Read Resend register (DP: v1, access: RO) */
SWD_A_DP_RDBUFF = 0xc, /**< Read Buffer register (DP: v0, access: RO) */
SWD_A_DP_TARGETSEL = 0xc, /**< Target Selection register (DP: v2, access: WO) */
};
/** Access Port (AP) MEM-AP register address
* @implements ARM IHI 0074A C2.5 MEM-AP Programmers Model
* @note only the registers addressable with A[3:2] are included
*/
enum swd_a_ap_memap_e {
SWD_A_AP_MEMAP_CSW = 0x0, /**< Control/Status Word register (access: RW) */
SWD_A_AP_MEMAP_TAR = 0x4, /**< Transfer Address Register (access: RW) */
SWD_A_AP_MEMAP_TAR_EXT = 0x8, /**< Transfer Address Register, large physical address extension (access: RW) */
SWD_A_AP_MEMAP_DRW = 0xc, /**< Data Read/Write register (access: RW) */
};
/** Access Port (AP) JTAG-AP register address
* @implements ARM IHI 0074A C3.4 JTAG-AP programmers model
* @note only the registers addressable with A[3:2] are included
*/
enum swd_a_ap_jtagap_e {
SWD_A_AP_JTAGAP_CSW = 0x0, /**< Control/Status Word register (access: RW) */
SWD_A_AP_JTAGAP_PSEL = 0x4, /**< Port Select register (access: RW) */
SWD_A_AP_JTAGAP_PSTA = 0x8, /**< Port Status Register (access: RW) */
};
/** ACk acknowledge response
* @implements ARM IHI 0074A B4.2 SWD protocol operation
*/
enum swd_ack_e {
SWD_ACK_OK = 0x1, /**< Successful operation */
SWD_ACK_WAIT = 0x2, /**< Wait for response */
SWD_ACK_FAULT = 0x4, /**< Fault */
SWD_ACK_ERROR = 0x7, /**< Error (pulled-up line not driven) */
};
/** Activation codes
* @implements ARM IHI 0074A B5.3.4 Leaving dormant state
*/
enum swd_activation_code_e {
SWD_ACTIVATION_CODE_JTAG, /**< JTAG-Serial */
SWD_ACTIVATION_CODE_SWDP, /**< ARM CoreSight SW-DP */
SWD_ACTIVATION_CODE_JTAGDP, /**< ARM CoreSight JTAG-DP */
};
/** setup SWD peripheral
*/
void swd_setup(uint32_t freq);
/** release 1-wire peripheral
*/
void swd_release(void);
/** release used pins */
void swd_release_pins(void);
/** set SWCLK and SWDIO pins
* @param[in] swclk_port port for SWCLK pin
* @param[in] swclk_pin pin for SWCLK pin
* @param[in] swclk_port port for SWDIO pin
* @param[in] swclk_pin pin for SWDIO pin
* @return true if operation succeeded, false if pin is unknown
*/
bool swd_set_pins(uint32_t swclk_port, uint32_t swclk_pin, uint32_t swdio_port, uint32_t swdio_pin);
/* DPv1/SWDv1 operations */
/** send line reset sequence to put target in reset state
* @implements ARM IHI 0074A B4.3.3 Connection and line reset sequence
* @note this does not include the tailing idle cycles
*/
void swd_line_reset(void);
/** send JTAG to SWD sequence to switch the target SWJ-DP from JTAG to SWD
* @note a line reset must be perform just before
* @implements ARM IHI 0074A B5.2.2 Switching from JTAG to SWD operation
*/
void swd_jtag_to_swd(void);
/** send SWD to JTAG sequence to switch the target SWJ-DP from SWD to JTAG
* @note a line reset must be perform just before
* @implements ARM IHI 0074A B5.2.3 Switching from SWD to JTAG operation
*/
void swd_swd_to_jtag(void);
/** send idle cycles
* @param[in] nb number idle cycles to send
* @note at least two idle cycles a required after a line reset and before a packet request
* @implements ARM IHI 0074A B4.1.4 Idle cycles
*/
void swd_idle_cycles(uint8_t nb);
/** send packet request
* @param[in] apndp true to access the Access Port (AP) or false to access the Debug Port (DP) access register
* @param[in] a address field for the DP or AP register Address (complete address, not just bits 3:2)
* @param[in] rnw true for read access, false for write access
* @implements ARM IHI 0074A B4.2 SWD protocol operation
*/
void swd_packet_request(bool apndp, uint8_t a, bool rnw);
/** insert turnaround cycle
* @param[in] nb number idle for the turnaround (by default 1, else set in DLCR.TURNROUND)
* @note used to switch between reading and writing on the data signal
* @implements ARM IHI 0074A B4.1.3 Line turnaround
*/
void swd_turnaround(uint8_t nb);
/** read acknowledge response (ACK)
* @return ACK
* @implements ARM IHI 0074A B4.2 SWD protocol operation
*/
enum swd_ack_e swd_acknowledge_response(void);
/** write data
* @param[in] wdata data to write
* @implements ARM IHI 0074A B4.2 SWD protocol operation
*/
void swd_write(uint32_t wdata);
/** read data
* @param[out] rdata read data
* @return if parity check passed
* @implements ARM IHI 0074A B4.2 SWD protocol operation
*/
bool swd_read(uint32_t* rdata);
/* DPv2/SWDv2 operations */
/** send JTAG to dormant state (DS) sequence
* @note the preceding line reset does not seem mandatory, but recommended
* @implements ARM IHI 0074A B5.3.2 Switching from JTAG to dormant state
* @remark it is not mentioned what happens if the TAP is in SWD state (probably nothing)
*/
void swd_jtag_to_ds(void);
/** send SWD to dormant state (DS) sequence
* @note no preceding line reset is requires
* @implements ARM IHI 0074A B5.3.3 Switching from SWD to dormant state
* @remark it is not mentioned what happens if the TAP is in JTAG state (probably nothing)
*/
void swd_swd_to_ds(void);
/** send selection code and activation alert to leave dormant state and go into JTAG or SWD mode
* @param[in] activation_code activation code to select protocol (JTAG, or SWD)
* @implements ARM IHI 0074A B5.3.3 Switching from SWD to dormant state
* @remark it is not mentioned what happens if the TAP is in any other state
*/
void swd_selection_alert(enum swd_activation_code_e activation_code);
/** perform SWD transaction (one sequence of bits read or write)
* @param[in] output bits to write (LSb first)
* @param[in] bit_count number of bits to read/write
* @param[in] write true for write transaction, false for read transaction
* @return the bits read
* @note this should only be used for unimplemented operations
*/
uint64_t swd_transaction(uint64_t output, uint8_t bit_count, bool write);
/** get manufacturer name corresponding to the designer id
* @param[in] bank bank number (first 4 bits of the DESIGNER value)
* @param[in] id JEP106 id (last 7 bits of the DESIGNER value)
* @return manufacturer name
* @implements JEDEC JEP106
* @note from the OpenOCD project
* @date 2015
* @copyright Andreas Fritiofson <andreas.fritiofson@gmail.com>
*/
const char* swd_jep106_manufacturer(uint8_t bank, uint8_t id);
/** get DAP name corresponding to the DPIDR part number
* @param[in] designer DESIGNER value
* @param[in] partno DPIDR part number
* @return DAP name
*/
const char* swd_dpidr_partno(uint16_t designer, uint8_t partno);