/* * 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" #include "spi_op.h" #include "spi_switch.h" #include "dap_utility.h" // Debug #define PRINT_SWD_PROTOCOL 0 // 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) #define PIN_DELAY() PIN_DELAY_FAST() // Generate SWJ Sequence // count: sequence bit count // data: pointer to sequence bit data // return: none #if ((DAP_SWD != 0) || (DAP_JTAG != 0)) void SWJ_Sequence (uint32_t count, const uint8_t *data) { if (count != 8 && count != 16 && count!= 51) { printf("[ERROR] wrong SWJ Swquence length:%d\r\n", (int)count); return; } DAP_SPI_Enable(); DAP_SPI_WriteBits(count, data); } #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) 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] //// TODO: low speed #define SWD_TransferFunction(speed) /* Speed may be useless, because all use this function */ \ static uint8_t SWD_Transfer##speed (uint32_t request, uint32_t *data) { \ SWD_Transfer_Common(request,data); \ return 1; \ } static uint8_t SWD_Transfer_Common (uint32_t request, uint32_t *data) { uint8_t ack; // uint32_t bit; uint32_t val; uint8_t parity; uint8_t computedParity; uint32_t n; int retryCount = 0; const uint8_t constantBits = 0b10000001U; /* Start Bit & Stop Bit & Park Bit is fixed. */ uint8_t requestByte; /* LSB */ DAP_SPI_Enable(); do { requestByte = constantBits | (((uint8_t)(request & 0xFU)) << 1U) | (ParityEvenUint8(request & 0xFU) << 5U); /* For 4bit, Parity can be equivalent to 8bit with all 0 high bits */ #if (PRINT_SWD_PROTOCOL == 1) switch (requestByte) { case 0xA5U: printf("IDCODE\r\n"); break; case 0xA9U: printf("W CTRL/STAT\r\n"); break; case 0xBDU: printf("RDBUFF\r\n"); break; case 0x8DU: printf("R CTRL/STAT\r\n"); break; case 0x81U: printf("W ABORT\r\n"); break; case 0xB1U: printf("W SELECT\r\n"); break; case 0xBBU: printf("W APc\r\n"); break; case 0x9FU: printf("R APc\r\n"); break; case 0x8BU: printf("W AP4\r\n"); break; case 0xA3U: printf("W AP0\r\n"); break; case 0X87U: printf("R AP0\r\n"); break; case 0xB7U: printf("R AP8\r\n"); break; default: //W AP8 printf("Unknown:%08x\r\n", requestByte); break; } #endif if (request & DAP_TRANSFER_RnW) { /* Read data */ DAP_SPI_Send_Header(requestByte, &ack, 0); // 0 Trn After ACK if (ack == DAP_TRANSFER_OK) { DAP_SPI_Read_Data(&val, &parity); computedParity = ParityEvenUint32(val); if ((computedParity ^ parity) & 1U) { ack = DAP_TRANSFER_ERROR; } if (data) { *data = val; } /* Capture Timestamp */ if (request & DAP_TRANSFER_TIMESTAMP) { DAP_Data.timestamp = TIMESTAMP_GET(); } } else if ((ack == DAP_TRANSFER_WAIT) || (ack == DAP_TRANSFER_FAULT)) { DAP_SPI_Generate_Cycle(1); #if (PRINT_SWD_PROTOCOL == 1) printf("WAIT\r\n"); #endif continue; // return DAP_TRANSFER_WAIT; } else { /* Protocol error */ DAP_SPI_Disable(); PIN_SWDIO_TMS_SET(); DAP_SPI_Enable(); DAP_SPI_Protocol_Error_Read(); DAP_SPI_Disable(); PIN_SWDIO_TMS_SET(); printf("Protocol Error: Read\r\n"); } return ((uint8_t)ack); } else { /* Write data */ parity = ParityEvenUint32(*data); DAP_SPI_Send_Header(requestByte, &ack, 1); // 1 Trn After ACK if (ack == DAP_TRANSFER_OK) { DAP_SPI_Write_Data(*data, parity); /* Capture Timestamp */ if (request & DAP_TRANSFER_TIMESTAMP) { DAP_Data.timestamp = TIMESTAMP_GET(); } /* Idle cycles */ n = DAP_Data.transfer.idle_cycles; if (n) { DAP_SPI_Generate_Cycle(n); } DAP_SPI_Disable(); PIN_SWDIO_TMS_SET(); return ((uint8_t)ack); } else if ((ack == DAP_TRANSFER_WAIT) || (ack == DAP_TRANSFER_FAULT)) { /* already turnaround. */ /* TODO: overrun transfer -> for read */ #if (PRINT_SWD_PROTOCOL == 1) printf("WAIT\r\n"); #endif continue; } else { //// FIXME: bug /* Protocol error */ DAP_SPI_Disable(); PIN_SWDIO_TMS_SET(); DAP_SPI_Enable(); DAP_SPI_Protocol_Error_Write(); DAP_SPI_Disable(); PIN_SWDIO_TMS_SET(); printf("Protocol Error: Write\r\n"); } return ((uint8_t)ack); } } while (retryCount++ < 99); return DAP_TRANSFER_ERROR; } #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] 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) */