/* * Copyright (c) 2013-2017 ARM Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the License); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ---------------------------------------------------------------------- * * $Date: 1. December 2017 * $Revision: V2.0.0 * * Project: CMSIS-DAP Source * Title: SW_DP.c CMSIS-DAP SW DP I/O * *---------------------------------------------------------------------------*/ #include "DAP_config.h" #include "DAP.h" // SW Macros #define PIN_SWCLK_SET PIN_SWCLK_TCK_SET #define PIN_SWCLK_CLR PIN_SWCLK_TCK_CLR #define SW_CLOCK_CYCLE() \ PIN_SWCLK_CLR(); \ PIN_DELAY(); \ PIN_SWCLK_SET(); \ PIN_DELAY() #define SW_WRITE_BIT(bit) \ PIN_SWDIO_OUT(bit); \ PIN_SWCLK_CLR(); \ PIN_DELAY(); \ PIN_SWCLK_SET(); \ PIN_DELAY() #define SW_READ_BIT(bit) \ PIN_SWCLK_CLR(); \ PIN_DELAY(); \ bit = PIN_SWDIO_IN(); \ PIN_SWCLK_SET(); \ PIN_DELAY() #define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) // Generate SWJ Sequence // count: sequence bit count // data: pointer to sequence bit data // return: none #if ((DAP_SWD != 0) || (DAP_JTAG != 0)) __WEAK void SWJ_Sequence (uint32_t count, const uint8_t *data) { uint32_t val; uint32_t n; val = 0U; n = 0U; while (count--) { if (n == 0U) { val = *data++; n = 8U; } if (val & 1U) { PIN_SWDIO_TMS_SET(); } else { PIN_SWDIO_TMS_CLR(); } SW_CLOCK_CYCLE(); val >>= 1; n--; } } #endif // Generate SWD Sequence // info: sequence information // swdo: pointer to SWDIO generated data // swdi: pointer to SWDIO captured data // return: none #if (DAP_SWD != 0) __WEAK void SWD_Sequence (uint32_t info, const uint8_t *swdo, uint8_t *swdi) { uint32_t val; uint32_t bit; uint32_t n, k; n = info & SWD_SEQUENCE_CLK; if (n == 0U) { n = 64U; } if (info & SWD_SEQUENCE_DIN) { while (n) { val = 0U; for (k = 8U; k && n; k--, n--) { SW_READ_BIT(bit); val >>= 1; val |= bit << 7; } val >>= k; *swdi++ = (uint8_t)val; } } else { while (n) { val = *swdo++; for (k = 8U; k && n; k--, n--) { SW_WRITE_BIT(val); val >>= 1; } } } } #endif #if (DAP_SWD != 0) // SWD Transfer I/O // request: A[3:2] RnW APnDP // data: DATA[31:0] // return: ACK[2:0] #define SWD_TransferFunction(speed) /**/ \ static uint8_t SWD_Transfer##speed (uint32_t request, uint32_t *data) { \ uint32_t ack; \ uint32_t bit; \ uint32_t val; \ uint32_t parity; \ \ uint32_t n; \ \ /* Packet Request */ \ parity = 0U; \ SW_WRITE_BIT(1U); /* Start Bit */ \ bit = request >> 0; \ SW_WRITE_BIT(bit); /* APnDP Bit */ \ parity += bit; \ bit = request >> 1; \ SW_WRITE_BIT(bit); /* RnW Bit */ \ parity += bit; \ bit = request >> 2; \ SW_WRITE_BIT(bit); /* A2 Bit */ \ parity += bit; \ bit = request >> 3; \ SW_WRITE_BIT(bit); /* A3 Bit */ \ parity += bit; \ SW_WRITE_BIT(parity); /* Parity Bit */ \ SW_WRITE_BIT(0U); /* Stop Bit */ \ SW_WRITE_BIT(1U); /* Park Bit */ \ \ /* Turnaround */ \ PIN_SWDIO_OUT_DISABLE(); \ for (n = DAP_Data.swd_conf.turnaround; n; n--) { \ SW_CLOCK_CYCLE(); \ } \ \ /* Acknowledge response */ \ SW_READ_BIT(bit); \ ack = bit << 0; \ SW_READ_BIT(bit); \ ack |= bit << 1; \ SW_READ_BIT(bit); \ ack |= bit << 2; \ \ if (ack == DAP_TRANSFER_OK) { /* OK response */ \ /* Data transfer */ \ if (request & DAP_TRANSFER_RnW) { \ /* Read data */ \ val = 0U; \ parity = 0U; \ for (n = 32U; n; n--) { \ SW_READ_BIT(bit); /* Read RDATA[0:31] */ \ parity += bit; \ val >>= 1; \ val |= bit << 31; \ } \ SW_READ_BIT(bit); /* Read Parity */ \ if ((parity ^ bit) & 1U) { \ ack = DAP_TRANSFER_ERROR; \ } \ if (data) { *data = val; } \ /* Turnaround */ \ for (n = DAP_Data.swd_conf.turnaround; n; n--) { \ SW_CLOCK_CYCLE(); \ } \ PIN_SWDIO_OUT_ENABLE(); \ } else { \ /* Turnaround */ \ for (n = DAP_Data.swd_conf.turnaround; n; n--) { \ SW_CLOCK_CYCLE(); \ } \ PIN_SWDIO_OUT_ENABLE(); \ /* Write data */ \ val = *data; \ parity = 0U; \ for (n = 32U; n; n--) { \ SW_WRITE_BIT(val); /* Write WDATA[0:31] */ \ parity += val; \ val >>= 1; \ } \ SW_WRITE_BIT(parity); /* Write Parity Bit */ \ } \ /* Capture Timestamp */ \ if (request & DAP_TRANSFER_TIMESTAMP) { \ DAP_Data.timestamp = TIMESTAMP_GET(); \ } \ /* Idle cycles */ \ n = DAP_Data.transfer.idle_cycles; \ if (n) { \ PIN_SWDIO_OUT(0U); \ for (; n; n--) { \ SW_CLOCK_CYCLE(); \ } \ } \ PIN_SWDIO_OUT(1U); \ return ((uint8_t)ack); \ } \ \ if ((ack == DAP_TRANSFER_WAIT) || (ack == DAP_TRANSFER_FAULT)) { \ /* WAIT or FAULT response */ \ if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) != 0U)) { \ for (n = 32U+1U; n; n--) { \ SW_CLOCK_CYCLE(); /* Dummy Read RDATA[0:31] + Parity */ \ } \ } \ /* Turnaround */ \ for (n = DAP_Data.swd_conf.turnaround; n; n--) { \ SW_CLOCK_CYCLE(); \ } \ PIN_SWDIO_OUT_ENABLE(); \ if (DAP_Data.swd_conf.data_phase && ((request & DAP_TRANSFER_RnW) == 0U)) { \ PIN_SWDIO_OUT(0U); \ for (n = 32U+1U; n; n--) { \ SW_CLOCK_CYCLE(); /* Dummy Write WDATA[0:31] + Parity */ \ } \ } \ PIN_SWDIO_OUT(1U); \ return ((uint8_t)ack); \ } \ \ /* Protocol error */ \ for (n = DAP_Data.swd_conf.turnaround + 32U + 1U; n; n--) { \ SW_CLOCK_CYCLE(); /* Back off data phase */ \ } \ PIN_SWDIO_OUT_ENABLE(); \ PIN_SWDIO_OUT(1U); \ return ((uint8_t)ack); \ } #undef PIN_DELAY #define PIN_DELAY() PIN_DELAY_FAST() SWD_TransferFunction(Fast) #undef PIN_DELAY #define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) SWD_TransferFunction(Slow) // SWD Transfer I/O // request: A[3:2] RnW APnDP // data: DATA[31:0] // return: ACK[2:0] __WEAK uint8_t SWD_Transfer(uint32_t request, uint32_t *data) { if (DAP_Data.fast_clock) { return SWD_TransferFast(request, data); } else { return SWD_TransferSlow(request, data); } } #endif /* (DAP_SWD != 0) */