stm32f1/lib/swd.h

208 lines
9.1 KiB
C
Raw Normal View History

2021-03-10 14:12:31 +01:00
/** 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
2021-03-10 14:12:31 +01:00
* @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_NOREPLY = 0x7, /**< Error (pulled-up line not driven) */
2021-03-10 14:12:31 +01:00
};
/** 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);
2021-03-16 12:15:49 +01:00
/** release peripherals used for SWD communication
2021-03-10 14:12:31 +01:00
*/
void swd_release(void);
2021-03-12 13:10:59 +01:00
/** 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);
2021-03-10 14:12:31 +01:00
/* 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
2021-03-16 12:15:35 +01:00
* @param[in] designer DESIGNER value (bits 1-11 in DPIDR/IDCODE)
* @param[in] partno PARTNO part number bits 12-27 in DPIDR/IDCODE)
2021-03-10 14:12:31 +01:00
* @return DAP name
*/
2021-03-16 12:15:35 +01:00
const char* swd_dpidr_partno(uint16_t designer, uint16_t partno);
2021-03-10 14:12:31 +01:00