SPI SWD Protocol Implement
//================================================================================= // ARM SWD Mode Port Bit masks // #if (HW_CAPABILITY&CAP_SWD_HW) #ifndef DATA_PORT #define DATA_PORT PTAD #define DATA_PORT_DDR PTADD #define DATA_PORT_PER PTAPE #endif // SWD data out pin #define SWD_OUT PTAD_PTAD2 #define SWD_OUT_BIT (2) // Bit number! #define SWD_OUT_MASK (1<<SWD_OUT_BIT) #define SWD_OUT_PER PTAPE_PTAPE2 #define SWD_OUT_DDR PTADD_PTADD2 // SWD data out 3-state control #define SWD_OUT_EN PTAD_PTAD4 #define SWD_OUT_EN_BIT (4) // Bit number! #define SWD_OUT_EN_MASK (1<<SWD_OUT_EN_BIT) #define SWD_OUT_EN_PER PTAPE_PTAPE4 #define SWD_OUT_EN_DDR PTADD_PTADD4 // Following assume pin already configured by SWD_LOW(),SWD_HIGH(),SWD_3STATE() #define SWD_ENABLE_ASM BCLR SWD_OUT_EN_BIT,DATA_PORT #define SWD_3STATE_ASM BSET SWD_OUT_EN_BIT,DATA_PORT #define SWD_LOW_ASM BCLR SWD_OUT_BIT,DATA_PORT #define SWD_HIGH_ASM BSET SWD_OUT_BIT,DATA_PORT #define SWD_DISABLE_ASM BCLR SWD_OUT_EN_BIT,DATA_PORT_DDR #define SWD_ENABLE_DRV_ASM BSET SWD_OUT_EN_BIT,DATA_PORT_DDR // Following configure pin & driver #define SWD_LOW() (SWD_OUT=0, SWD_OUT_DDR=1, SWD_OUT_EN=0, SWD_OUT_EN_DDR=1) #define SWD_HIGH() (SWD_OUT=1, SWD_OUT_DDR=1, SWD_OUT_EN=0, SWD_OUT_EN_DDR=1) #define SWD_3STATE() (SWD_OUT_EN=1, SWD_OUT_EN_DDR=1, SWD_OUT_DDR=1) #define SWD_DISABLE() (SWD_OUT_EN=1, SWD_OUT_EN_DDR=0, SWD_OUT_DDR=0) // PUPs // SWD data in pin #define SWD_IN PTAD_PTAD0 #define SWD_IN_BIT (0) // Bit number! #define SWD_IN_MASK (1<<SWD_IN_BIT) #define SWD_IN_PER PTAPE_PTAPE0 #define SWD_IN_DDR PTADD_PTADD0 // SWCLK out pin #define SWCLK_OUT PTAD_PTAD3 #define SWCLK_OUT_BIT (3) // Bit number! #define SWCLK_OUT_MASK (1<<SWCLK_OUT_BIT) #define SWCLK_OUT_PER PTAPE_PTAPE3 #define SWCLK_OUT_DDR PTADD_PTADD3 // SWCLK enable pin - controls buffer enable #define SWCLK_OUT_EN PTBD_PTBD1 #define SWCLK_OUT_EN_BIT (1) // Bit number! #define SWCLK_OUT_EN_MASK (1<<SWCLK_OUT_EN_BIT) #define SWCLK_OUT_EN_PER PTBPE_PTBPE1 #define SWCLK_OUT_EN_DDR PTBDD_PTBDD1 // Following assume pin direction already set #define SWCLK_LOW_ASM BCLR SWCLK_OUT_BIT,DATA_PORT #define SWCLK_HIGH_ASM BSET SWCLK_OUT_BIT,DATA_PORT // Following configure pin & driver #define SWCLK_LOW() (SWCLK_OUT=0, SWCLK_OUT_DDR=1, SWCLK_OUT_EN=0, SWCLK_OUT_EN_DDR=1) #define SWCLK_HIGH() (SWCLK_OUT=1, SWCLK_OUT_DDR=1, SWCLK_OUT_EN=0, SWCLK_OUT_EN_DDR=1) #define SWCLK_3STATE() (SWCLK_OUT_EN=1, SWCLK_OUT_EN_DDR=1, SWCLK_OUT_DDR=1) // PUPs #define SWCLK_DISABLE() (SWCLK_OUT_EN=1, SWCLK_OUT_EN_DDR=0, SWCLK_OUT_DDR=0) // PUPs #endif // CAP_SWD
/* * SWD.h * * Created on: 04/08/2012 * Author: PODonoghue */ #ifndef SWD_H_ #define SWD_H_ #include "Common.h" // Ack values displaced by offset introduced during read (left justified 8-bit value) #define SWD_ACK_OK (0x1<<5) #define SWD_ACK_WAIT (0x2<<5) #define SWD_ACK_FAULT (0x4<<5) #define SWD_ACK_PROTOCOL (0x7<<5) void swd_interfaceIdle(void); void swd_init(void); void swd_txIdle8(void); U8 swd_test(void); U8 swd_sendCommandWithWait(U8 command); U8 swd_connect(void); U8 swd_readReg(U8 command, U8 *data); U8 swd_writeReg(U8 command, const U8 *data); U8 swd_readAPReg(const U8 *address, U8 *buff); U8 swd_writeAPReg(const U8 *address, const U8 *buff); U8 swd_clearStickyError(void); U8 swd_abortAP(void); #endif /* SWD_H_ */
/*! \file \brief ARM-SWD routines \verbatim USBDM Copyright (C) 2007 Peter O'Donoghue This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \endverbatim Change History +================================================================================================== | 21 Feb 2014 | Fixed unbalanced stack in swd_sendCommandWithWait() V4.10.6.30 | 10 Feb 2014 | Dramatically extended retry times to allow for slow clocks V4.10.6.20 | 30 Aug 2012 | ARM-JTAG & ARM-SWD Changes V4.9.5 +================================================================================================== \endverbatim */ #include "Common.h" #include "Configure.h" #include "Commands.h" #include "SWD.h" #include "Commands.h" #include "BDM.h" #include "BDM_CF.h" #include "CmdProcessing.h" #include "BDMCommon.h" #include "SPI.h" #include "TargetDefines.h" #include "SWD.h" #if TARGET_CAPABILITY & CAP_ARM_SWD //! SPI Masks - Mask to enable SPI as master Tx #define SPIxC1_OFF (SPIxC1_MSTR_MASK) //!< SPI Masks - Mask to disable SPI #define SPIxC1_M_ON_TX (SPIxC1_SPE_MASK|SPIxC1_MSTR_MASK|SPIxC1_CPOL_MASK|SPIxC1_CPHA_MASK|SPIxC1_SSOE_MASK|SPIxC1_LSBFE_MASK) #define SPIxC1_M_ON_RX (SPIxC1_SPE_MASK|SPIxC1_MSTR_MASK|SPIxC1_CPOL_MASK) //!< SPI Masks - Mask to enable SPI as master Tx #define SPIxC2_M_8 (0) //!< SPI Masks - 8-bit mode #define SPIxC2_M_16 (SPIxC2_SPIMODE_MASK) //!< SPI Masks - 8-bit mode // Can't use enumerations in assembly code #define BDM_RC_OKx (0) #define BDM_RC_NO_CONNECTIONx (5) #define BDM_RC_ACK_TIMEOUTx (30) #define BDM_RC_ARM_PARITY_ERRORx (51) #define BDM_RC_ARM_FAULT_ERRORx (52) #define SWD_READ_IDCODE 0xA5 // (Park,Stop,Parity,A[32],R/W,AP/DP,Start) = 10100101 // Masks for SWD_WR_DP_ABORT clear sticky #define SWD_DP_ABORT_CLEAR_STICKY_ERRORS_B3 0x1E // Masks for SWD_WR_DP_ABORT abort AP #define SWD_DP_ABORT_ABORT_AP_B3 0x01 // Masks for SWD_RD_DP_STATUS #define SWD_RD_DP_STATUS_ANYERROR_B3 0xB2 #pragma MESSAGE DISABLE C1404 // Disable warnings about missing return value #pragma MESSAGE DISABLE C5703 // Disable warnings about unused parameter //! Sets the SWD interface to an idle state //! RESET=3-state, SWCLK=High, SWDIO=3-state (SPI off) //! void swd_interfaceIdle(void) { #ifdef RESET_3STATE RESET_3STATE(); #endif SWD_3STATE(); SWCLK_HIGH(); SPIC1 = SPIxC1_OFF; } //! Initialise the SWD interface and sets it to an idle state //! RESET=3-state, SWCLK=High, SWDIO=3-state //! //! @note This includes once-off initialisation such as PUPs etc //! void swd_init(void) { // 4 pins SWD_OUT, SWD_OUT_EN, SWCLK_OUT, SWCLK_OUT_EN // Individually controlled PUPs SWD_OUT_PER = 1; // Prevent float when disabled SWD_OUT_EN_PER = 1; // Prevent drive when disabled SWCLK_OUT_PER = 1; // Prevent float when disabled SWCLK_OUT_EN_PER = 1; // Prevent drive when disabled SWD_IN_DDR = 0; // Make input SWD_IN_PER = 1; // Shouldn't be req. as external PUP for speed #ifdef RESET_IN_DDR RESET_IN_DDR = 0; // Make input #endif #ifdef RESET_IN_PER RESET_IN_PER = 1; // Needed for input level translation to 5V #endif #ifdef RESET_OUT_PER RESET_OUT_PER = 1; // Holds RESET_OUT inactive when unused #endif (void)spi_setSpeed(0); swd_interfaceIdle(); } //! Turns off the SWD interface //! //! Depending upon settings, may leave target power on. //! void swd_off( void ) { #if ((HW_CAPABILITY & CAP_FLASH) != 0) (void)bdmSetVpp(BDM_TARGET_VPP_OFF); #endif if (!bdm_option.leaveTargetPowered) { VDD_OFF(); } swd_interfaceIdle(); SWCLK_DISABLE(); SWD_DISABLE(); RESET_DISABLE(); } #define SWD_DATA1_CLK1 SWCLK_OUT_MASK|SWD_OUT_EN_MASK #define SWD_DATA0_CLK1 SWCLK_OUT_MASK|0 //! Transmits 1 clock with SWDIO 3-state //! void swd_turnAround() { asm { // 1 clock turn-around mov #SWD_OUT_MASK,DATA_PORT // SWDIO=3-state,SWCLK=0 ldx bitDelay // Low time delay dbnzx *-0 // [4n fppp] bset SWCLK_OUT_BIT,DATA_PORT // SWCLK=1 ldx bitDelay // High time delay dbnzx *-0 // [4n fppp] } } //! Transmits 8-bits of idle (SDIO=0) //! void swd_txIdle8(void) { asm { mov #SPIxC2_M_8,SPIxC2 // Initialise SPI (8 bit) mov #SPIxC1_M_ON_TX,SPIC1 // Enable SPI clr DATA_PORT // Enable SWD drive cmp SPIxS // Dummy status read clr SPIxD // Tx data (=0) L1: brclr SPIS_SPRF_BIT,SPIxS,L1 // Wait until Tx/Rx complete lda SPIxD // Discard rx data mov #SWCLK_OUT_MASK|SWD_OUT_EN_MASK,DATA_PORT // Setup for SWCLK=1, SWD=3-state clr SPIC1 // Disable SPI } } #if (SWD_IN_BIT != 0) #error "SWD_IN must be bit #0" #endif #pragma MESSAGE DISABLE C5703 // Disable warnings about unused parameter //! SWD command phase //! //! Writes 8-bit command and receives 3-bit response //! It will retry on WAIT response a limited number of times //! //! @param command - 8-bit command to write to SWD (including parity!) //! //! @return \n //! == \ref BDM_RC_OK => Success \n //! == \ref BDM_RC_ARM_FAULT_ERROR => FAULT response from target \n //! == \ref BDM_RC_ACK_TIMEOUT => Excessive number of WAIT responses from target \n //! == \ref BDM_RC_NO_CONNECTION => Unexpected/no response from target //! //! @note A turn-around clock period will be added on error responses //! uint8_t swd_sendCommandWithWait(uint8_t command) { asm { sta txTiming1 // Save data (for retry) ldx #(2000/250) // Set up outer retry count retry_outer: pshx // Save outer retry count mov #250,rxTiming1 // Reset inner retry count retry: // 8-bit Start|APnDP|R/W|Parity|Stop|Park lda txTiming1 // Get Tx data mov #SPIxC2_M_8,SPIxC2 // Initialise SPI (8 bit) mov #SPIxC1_M_ON_TX,SPIC1 // Enable SPI clr DATA_PORT // Enable SWD drive cmp SPIxS // Dummy status read sta SPIxD // Tx data L1: brclr SPIS_SPRF_BIT,SPIxS,L1 // Wait until Tx/Rx complete ldx SPIxD // Discard rx data SWD_3STATE_ASM // SWD=3-state clr SPIC1 // Disable SPI // 1 clock turn-around bclr SWCLK_OUT_BIT,DATA_PORT // SWCLK=0 ldx bitDelay // Low time delay dbnzx *-0 // [4n fppp] bset SWCLK_OUT_BIT,DATA_PORT // SWCLK=1 ldx bitDelay // High time delay dbnzx *-0 // [4n fppp] // 1st bit ACK clra // Clear initial data value bclr SWCLK_OUT_BIT,DATA_PORT // SWCLK=0 ldx bitDelay // Low time delay dbnzx *-0 // [4n fppp] ldx DATA_PORT // Capture data before rising edge rorx rora bset SWCLK_OUT_BIT,DATA_PORT // SWCLK=1 ldx bitDelay // High time delay dbnzx *-0 // [4n fppp] // 2nd bit ACK bclr SWCLK_OUT_BIT,DATA_PORT // SWCLK=0 ldx bitDelay // Low time delay dbnzx *-0 // [4n fppp] ldx DATA_PORT // Capture data before rising edge rorx rora bset SWCLK_OUT_BIT,DATA_PORT // SWCLK=1 ldx bitDelay // High time delay dbnzx *-0 // [4n fppp] // 3rd bit ACK bclr SWCLK_OUT_BIT,DATA_PORT // SWCLK=0 ldx bitDelay // Low time delay dbnzx *-0 // [4n fppp] ldx DATA_PORT rorx rora bset SWCLK_OUT_BIT,DATA_PORT // SWCLK=1 ldx bitDelay // High time delay dbnzx *-0 // [4n fppp] tax lda #BDM_RC_OKx cbeqx #SWD_ACK_OK,balanceStack // Do turn-around clock on anything other than ACK_OK response bclr SWCLK_OUT_BIT,DATA_PORT // SWCLK=0 lda bitDelay // Low time delay dbnza *-0 // [4n fppp] bset SWCLK_OUT_BIT,DATA_PORT // SWCLK=1 lda bitDelay // High time delay dbnza *-0 // [4n fppp] // Check for wait response cpx #SWD_ACK_WAIT // Wait response? bne identifyError // No - exit with other error // Check for wait timeout dbnz rxTiming1,retry // Retry limit reached pulx dbnzx retry_outer lda #BDM_RC_ACK_TIMEOUTx // Too many retries bra done // Return error (stack already balanced) identifyError: lda #BDM_RC_ARM_FAULT_ERRORx // Identify error cbeqx #SWD_ACK_FAULT,balanceStack lda #BDM_RC_NO_CONNECTIONx balanceStack: pulx // Balance stack done: } } #pragma MESSAGE DEFAULT C5703 // Restore warnings about unused parameter #pragma MESSAGE DISABLE C5703 // Disable warnings about unused parameter //! Transmits 32-bit value //! //! Sequence as follows: //! - 1-clock turn-around //! - 32-bit data value //! - 1-bit parity //! - 8-bit idle //! //! @param data - ptr to 32-bit data to Tx //! static void swd_tx32(const uint8_t *data) { asm { // 1 clock turn-around bclr SWCLK_OUT_BIT,DATA_PORT // SWCLK=0 lda bitDelay // Low time delay dbnza *-0 // [4n fppp] bset SWCLK_OUT_BIT,DATA_PORT // SWCLK=1 mov #SPIxC2_M_16,SPIxC2 // Initialise SPI (16 bit) mov #SPIxC1_M_ON_TX,SPIxC1 // Enable SPI clr DATA_PORT // Enable SWD drive cmp SPIxS // Dummy status read lda 3,x // Start Tx 1st & 2nd bytes sta SPIxDL lda 2,x sta SPIxDH lda 0,x // Do byte-wide parity eor 1,x eor 2,x eor 3,x ldhx 0,x // Get 3rd & 4th bytes L1: brclr SPIS_SPRF_BIT,SPIxS,L1 // Wait until previous Tx/Rx complete cphx SPIxD16 // Discard read data sthx SPIxD16 // Tx 3rd & 4th bytes // Calculate nibble parity psha // [2] nsa // [1] eor 1,sp // [4] ais #1 // [2] // Calculate final parity tax // [1] clra // [1] rorx // [1] adc #0 // [2] rorx // [1] adc #0 // [2] rorx // [1] adc #0 // [2] rorx // [1] adc #0 // [2] //parity in A.0 L2: brclr SPIS_SPRF_BIT,SPIxS,L2 // Wait until previous Tx/Rx complete ldhx SPIxD16 // Discard read data #if SWD_OUT_BIT >= 1 // move to SWD_OUT position lsla #endif #if SWD_OUT_BIT == 2 lsla #else #error Fix this code #endif and #SWD_OUT_MASK // SWD=p, SWCLK=0 sta DATA_PORT // Set up - no effect yet ldx bitDelay // Low time delay clr SPIC1 // Disable SPI, dbnzx *-0 // [4n fppp] bset SWCLK_OUT_BIT,DATA_PORT // SWD=p, SWCLK=1 // Start Tx of 8-bit idle mov #SPIxC2_M_8,SPIxC2 // Initialise SPI (8 bit) mov #SPIxC1_M_ON_TX,SPIC1 // Enable SPI clr DATA_PORT // Enable SWD drive cmp SPIxS // Dummy status read clr SPIxD // Tx data (=0) // Wait for Idle Tx to complete L3: brclr SPIS_SPRF_BIT,SPIxS,L3 // Wait until Tx/Rx complete cmp SPIxD // Discard rx data mov #SWCLK_OUT_MASK|SWD_OUT_EN_MASK,DATA_PORT // Setup for SWCLK=1, SWD=3-state clr SPIC1 // Disable SPI rts } } #pragma MESSAGE DEFAULT C5703 // Restore warnings about unused parameter #pragma MESSAGE DISABLE C5703 // Disable warnings about unused parameter //! Receives a 32-bit value with parity at end (33 total) //! //! Sequence as follows: //! - 32-bit data value //! - 1-bit parity //! - 8-bit idle //! //! @param data - ptr to buffer for Rx data //! //! @return BDM_RC_OK \n //! BDM_RC_ARM_PARITY_ERROR //! static uint8_t swd_rx32(uint8_t *data) { #define SPIS_SPTEF_BIT (5) #define SPIS_SPRF_BIT (7) asm { SWD_3STATE_ASM // SWD=3-state mov #SPIxC2_M_16,SPIxC2 // Initialise SPI (16 bit) mov #SPIxC1_M_ON_TX,SPIxC1 // Enable SPI cmp SPIxS // Dummy status read sthx SPIxD16 // Tx dummy/Rx L1: brclr SPIS_SPRF_BIT,SPIxS,L1 // Wait until Rx complete lda SPIxDH // Save data sta 2,x lda SPIxDL sta 3,x sthx SPIxD16 // Tx dummy/Rx L2: brclr SPIS_SPRF_BIT,SPIxS,L2 // Wait until Rx complete lda SPIxDH // Save data sta 0,x lda SPIxDL sta 1,x bclr SWCLK_OUT_BIT,DATA_PORT // Setup for SWCLK=0 clr SPIC1 // Disable SPI (SWCLK=0) // Parity bit lda bitDelay // Low time delay dbnza *-0 // [4n fppp] lda DATA_PORT // Capture data before rising clock edge bset SWCLK_OUT_BIT,DATA_PORT // SWCLK=1 and #SWD_IN_MASK // Convert parity to byte width // Single Parity bit remains - position is unimportant // Start Tx of 8-bit idle mov #SPIxC2_M_8,SPIxC2 // Initialise SPI (8 bit) mov #SPIxC1_M_ON_TX,SPIC1 // Enable SPI clr DATA_PORT // Enable SWD drive cmp SPIxS // Dummy status read clr SPIxD // Tx data (=0) // Do parity calculation eor 0,x // Do byte-wide parity on data & parity bit eor 1,x eor 2,x eor 3,x ldx bitDelay // High time delay dbnzx *-0 // [4n fppp] // Calculate nibble parity psha // [2] nsa // [1] eor 1,sp // [4] ais #1 // [2] // Calculate final parity tax // [1] clra // [1] rorx // [1] adc #0 // [2] rorx // [1] adc #0 // [2] rorx // [1] adc #0 // [2] rorx // [1] adc #0 // [2] and #1 // Parity in A.0 - should be 0 beq okExit lda #BDM_RC_ARM_PARITY_ERRORx okExit: // Wait for Idle Tx to complete L3: brclr SPIS_SPRF_BIT,SPIxS,L3 // Wait until Tx/Rx complete cmp SPIxD // Discard rx data mov #SWCLK_OUT_MASK|SWD_OUT_EN_MASK,DATA_PORT // Setup for SWCLK=1, SWD=3-state clr SPIC1 // Disable SPI rts } } #pragma MESSAGE DEFAULT C5703 // Restore warnings about unused parameter #pragma MESSAGE DISABLE C5703 // Disable warnings about unused parameter //! Switches interface to SWD //! //! Sequence as follows: //! - 64-bit sequence of 1's //! - 8-bit magic number 0xE79E //! - 64-bit sequence of 1's //! //! @note Interface is reset even if already in SWD mode so IDCODE must be read //! to enable interface //! static void swd_JTAGtoSWD(void) { asm { mov #SPIxC2_M_16,SPIxC2 // Initialise SPI (16 bit) mov #SPIxC1_M_ON_TX,SPIxC1 // Enable SPI clr DATA_PORT // Enable SWD drive cmp SPIxS // Dummy status read bsr txOnes // Send 64 clocks ldhx #0xE79E // Send magic # sthx SPIxD16 L5: brclr SPIS_SPTEF_BIT,SPIxS,L5 // Wait until Tx buffer empty bsr txOnes // Send 64 clocks L6: brclr SPIS_SPTEF_BIT,SPIxS,L6 // Wait until Tx buffer empty ldhx SPIxD16 // Discard last data mov #SWCLK_OUT_MASK|SWD_OUT_EN_MASK,DATA_PORT // Setup for SWCLK=1, SWD=3-state L7: brclr SPIS_SPRF_BIT,SPIxS,L7 // Wait until Tx complete ldhx SPIxD16 // Discard rx data clr SPIC1 // Disable SPI (SWCLK=1) rts txOnes: ldhx #0xFFFF // Tx 64 bits with '1' sthx SPIxD16 L1: brclr SPIS_SPTEF_BIT,SPIxS,L1 // Wait until Tx buffer empty sthx SPIxD16 L2: brclr SPIS_SPTEF_BIT,SPIxS,L2 // Wait until Tx buffer empty sthx SPIxD16 L3: brclr SPIS_SPTEF_BIT,SPIxS,L3 // Wait until Tx buffer empty sthx SPIxD16 L4: brclr SPIS_SPTEF_BIT,SPIxS,L4 // Wait until Tx buffer empty rts } } #pragma MESSAGE DEFAULT C5703 // Restore warnings about unused parameter //! SWD - Try to connect to the target //! //! This will do the following: //! - Switch the interface to SWD mode //! - Read IDCODE //! //! @return \n //! == \ref BDM_RC_OK => Success \n //! == \ref BDM_RC_NO_CONNECTION => Unexpected/no response from target //! uint8_t swd_connect(void) { uint8_t buff[4]; swd_JTAGtoSWD(); swd_txIdle8(); // Target must respond to read IDCODE immediately return swd_readReg(SWD_READ_IDCODE, buff); } //! Read ARM-SWD DP & AP register //! //! @param command - SWD command byte to select register etc. //! @param data - buffer for 32-bit value read //! //! @return \n //! == \ref BDM_RC_OK => Success \n //! == \ref BDM_RC_ARM_FAULT_ERROR => FAULT response from target \n //! == \ref BDM_RC_ACK_TIMEOUT => Excessive number of WAIT responses from target \n //! == \ref BDM_RC_NO_CONNECTION => Unexpected/no response from target \n //! == \ref BDM_RC_ARM_PARITY_ERROR => Parity error on data read //! //! @note Action and Data returned depends on register (some responses are pipelined)\n //! SWD_RD_DP_IDCODE - Value from IDCODE reg \n //! SWD_RD_DP_STATUS - Value from STATUS reg \n //! SWD_RD_DP_RESEND - LAST value read (AP read or DP-RDBUFF), FAULT on sticky error \n //! SWD_RD_DP_RDBUFF - Value from last AP read and clear READOK flag in STRL/STAT, FAULT on sticky error \n //! SWD_RD_AP_REGx - Value from last AP read, clear READOK flag in STRL/STAT and INITIATE next AP read, FAULT on sticky error //! uint8_t swd_readReg(uint8_t command, uint8_t *data) { uint8_t rc = swd_sendCommandWithWait(command); if (rc != BDM_RC_OK) { return rc; } return swd_rx32(data); } //! Write ARM-SWD DP & AP register //! //! @param command - SWD command byte to select register etc. //! @param data - buffer containing 32-bit value to write //! //! @return \n //! == \ref BDM_RC_OK => Success \n //! == \ref BDM_RC_ARM_FAULT_ERROR => FAULT response from target \n //! == \ref BDM_RC_ACK_TIMEOUT => Excessive number of WAIT responses from target \n //! == \ref BDM_RC_NO_CONNECTION => Unexpected/no response from target //! //! @note Action depends on register (some responses are pipelined)\n //! SWD_WR_DP_ABORT - Write value to ABORT register (accepted) \n //! SWD_WR_DP_CONTROL - Write value to CONTROL register (may be pending), FAULT on sticky error. \n //! SWD_WR_DP_SELECT - Write value to SELECT register (may be pending), FAULT on sticky error. \n //! SWD_WR_AP_REGx - Write to AP register. May initiate action e.g. memory access. Result is pending, FAULT on sticky error. //! uint8_t swd_writeReg(uint8_t command, const uint8_t *data) { uint8_t rc = swd_sendCommandWithWait(command); if (rc != BDM_RC_OK) { return rc; } swd_tx32(data); return rc; } //! Write register of Access Port //! //! @param 16-bit address \n //! A[15:8] => DP-AP-SELECT[31:24] (AP # Select) \n //! A[7:4] => DP-AP-SELECT[7:4] (Bank select within AP) \n //! A[3:2] => APACC[3:2] (Register select within bank) //! @param buff \n //! - [1..4] => 32-bit register value //! //! @return //! == \ref BDM_RC_OK => success //! //! @note - Access is completed before return //! uint8_t swd_writeAPReg(const uint8_t *address, const uint8_t *buff) { static const uint8_t writeAP[] = {SWD_WR_AP_REG0, SWD_WR_AP_REG1, SWD_WR_AP_REG2, SWD_WR_AP_REG3}; uint8_t rc; uint8_t regNo = writeAP[(address[1]&0xC)>>2]; uint8_t selectData[4]; selectData[0] = address[0]; selectData[1] = 0; selectData[2] = 0; selectData[3] = address[1]&0xF0; // Set up SELECT register for AP access rc = swd_writeReg(SWD_WR_DP_SELECT, selectData); if (rc != BDM_RC_OK) { return rc; } // Initiate write to AP register rc = swd_writeReg(regNo, buff); if (rc != BDM_RC_OK) { return rc; } // Read from READBUFF register to allow stall/status response return swd_readReg(SWD_RD_DP_RDBUFF, selectData); } //! Read register of Access Port //! //! @param 16-bit address \n //! A[15:8] => DP-AP-SELECT[31:24] (AP # Select) \n //! A[7:4] => DP-AP-SELECT[7:4] (Bank select within AP) \n //! A[3:2] => APACC[3:2] (Register select within bank) //! @param buff \n //! - [1..4] => 32-bit register value //! //! @return //! == \ref BDM_RC_OK => success //! //! @note - Access is completed before return //! uint8_t swd_readAPReg(const uint8_t *address, uint8_t *buff) { static const uint8_t readAP[] = {SWD_RD_AP_REG0, SWD_RD_AP_REG1, SWD_RD_AP_REG2, SWD_RD_AP_REG3}; uint8_t rc; uint8_t regNo = readAP[(address[1]&0xC)>>2]; uint8_t selectData[4]; selectData[0] = address[0]; selectData[1] = 0; selectData[2] = 0; selectData[3] = address[1]&0xF0; // Set up SELECT register for AP access rc = swd_writeReg(SWD_WR_DP_SELECT, selectData); if (rc != BDM_RC_OK) { return rc; } // Initiate read from AP register (dummy data) rc = swd_readReg(regNo, buff); if (rc != BDM_RC_OK) { return rc; } // Read from READBUFF register return swd_readReg(SWD_RD_DP_RDBUFF, buff); } //! ARM-SWD - clear sticky bits //! //! @return error code //! uint8_t swd_clearStickyError(void) { static const uint8_t swdClearErrors[4] = {0,0,0,SWD_DP_ABORT_CLEAR_STICKY_ERRORS_B3}; return swd_writeReg(SWD_WR_DP_ABORT, swdClearErrors); } //! ARM-SWD - clear sticky bits and abort AP transactions //! //! @return error code //! uint8_t swd_abortAP(void) { static const uint8_t swdClearErrors[4] = {0,0,0,SWD_DP_ABORT_CLEAR_STICKY_ERRORS_B3|SWD_DP_ABORT_ABORT_AP_B3}; return swd_writeReg(SWD_WR_DP_ABORT, swdClearErrors); } uint8_t swd_test(void) { return swd_connect(); // swd_JTAGtoSWD(); // return BDM_RC_OK; // return swd_connect(); } #endif // HW_CAPABILITY && CAP_SWD_HW