commit 972b965591cd02f2225e4197fdb865b5f5d1524b Author: powertomato Date: Sat Nov 8 20:37:01 2014 +0100 Initial commit diff --git a/src/DAP.c b/src/DAP.c new file mode 100644 index 0000000..6460dc3 --- /dev/null +++ b/src/DAP.c @@ -0,0 +1,1505 @@ +/****************************************************************************** + * @file DAP.c + * @brief CMSIS-DAP Commands + * @version V1.00 + * @date 31. May 2012 + * + * @note + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * @par + * ARM Limited (ARM) is supplying this software for use with Cortex-M + * processor based microcontrollers. + * + * @par + * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. + * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + * + ******************************************************************************/ + +#include +#include "DAP_config.h" +#include "DAP.h" +#include "Timer.h" +#include "Debug.h" + +#define DAP_FW_VER "1.0" // Firmware Version + + +#if (DAP_PACKET_SIZE < 64) +#error "Minimum Packet Size is 64" +#endif +#if (DAP_PACKET_SIZE > 32768) +#error "Maximum Packet Size is 32768" +#endif +#if (DAP_PACKET_COUNT < 1) +#error "Minimum Packet Count is 1" +#endif +#if (DAP_PACKET_COUNT > 255) +#error "Maximum Packet Count is 255" +#endif + + +// XXX Clock Macros +#if IO_PORT_WRITE_CYCLES +#define MAX_SWJ_CLOCK(delay_cycles) (CPU_CLOCK / 2 / (IO_PORT_WRITE_CYCLES + delay_cycles)) +#else +#define MAX_SWJ_CLOCK(delay_cycles) (CPU_CLOCK/2) +#endif +#define CLOCK_DELAY(swj_clock) ((CPU_CLOCK / 2 / swj_clock) - IO_PORT_WRITE_CYCLES) + + DAP_Data_t DAP_Data; // DAP Data +volatile uint8_t DAP_TransferAbort; // Trasfer Abort Flag + + +#ifdef DAP_VENDOR +const char DAP_Vendor [] = DAP_VENDOR; +#endif +#ifdef DAP_PRODUCT +const char DAP_Product[] = DAP_PRODUCT; +#endif +#ifdef DAP_SER_NUM +const char DAP_SerNum [] = DAP_SER_NUM; +#endif +const char DAP_FW_Ver [] = DAP_FW_VER; + +#if TARGET_DEVICE_FIXED +const char TargetDeviceVendor [] = TARGET_DEVICE_VENDOR; +const char TargetDeviceName [] = TARGET_DEVICE_NAME; +#endif + + +// Get DAP Information +// id: info identifier +// info: pointer to info data +// return: number of bytes in info data +static uint8_t DAP_Info(uint8_t id, uint8_t *info) +{ + uint8_t length = 0; + + DEBUG("DAP_Info: %02X\n", id); + + switch (id) + { + case DAP_ID_VENDOR: +#ifdef DAP_VENDOR + memcpy(info, DAP_Vendor, sizeof(DAP_Vendor)); + length = sizeof(DAP_Vendor); +#endif + break; + case DAP_ID_PRODUCT: +#ifdef DAP_PRODUCT + memcpy(info, DAP_Product, sizeof(DAP_Product)); + length = sizeof(DAP_Product); +#endif + break; + case DAP_ID_SER_NUM: +#ifdef DAP_SER_NUM + memcpy(info, DAP_SerNum, sizeof(DAP_SerNum)); + length = sizeof(DAP_SerNum); +#endif + break; + case DAP_ID_FW_VER: + memcpy(info, DAP_FW_Ver, sizeof(DAP_FW_Ver)); + length = sizeof(DAP_FW_Ver); + break; + case DAP_ID_DEVICE_VENDOR: +#if TARGET_DEVICE_FIXED + memcpy(info, TargetDeviceVendor, sizeof(TargetDeviceVendor)); + length = sizeof(DAP_Target_Device); +#endif + break; + case DAP_ID_DEVICE_NAME: +#if TARGET_DEVICE_FIXED + memcpy(info, TargetDeviceName, sizeof(TargetDeviceName)); + length = sizeof(DAP_Target_Device); +#endif + break; + case DAP_ID_CAPABILITIES: + info[0] = ((DAP_SWD != 0) ? (1 << 0) : 0) | + ((DAP_JTAG != 0) ? (1 << 1) : 0); + length = 1; + break; + case DAP_ID_PACKET_SIZE: + info[0] = (uint8_t)(DAP_PACKET_SIZE >> 0); + info[1] = (uint8_t)(DAP_PACKET_SIZE >> 8); + length = 2; + break; + case DAP_ID_PACKET_COUNT: + info[0] = DAP_PACKET_COUNT; + length = 1; + break; + } + + return (length); +} + + + + + +// Process Delay command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +static uint32_t DAP_Delay(uint8_t *request, uint8_t *response) { + uint32_t delay; + + delay = *(request + 0) | (*(request + 1) << 8); + Delayus(delay); + //delay *= (CPU_CLOCK / 1000000 + (DELAY_SLOW_CYCLES-1)) / DELAY_SLOW_CYCLES; + //PIN_DELAY_SLOW(delay); + + *response = DAP_OK; + return (1); +} + + +// Process LED command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +static uint32_t DAP_LED(uint8_t *request, uint8_t *response) +{ + switch (*request) + { + case DAP_LED_DEBUGGER_CONNECTED: + DEBUG("DAP_LED: CONNECTED %02X\n", (*(request+1) & 1)); + LED_CONNECTED_OUT((*(request+1) & 1)); + break; + case DAP_LED_TARGET_RUNNING: + DEBUG("DAP_LED: RUNNING %02X\n", (*(request+1) & 1)); + LED_RUNNING_OUT((*(request+1) & 1)); + break; + default: + DEBUG("DAP_LED: ERROR\n"); + *response = DAP_ERROR; + return (1); + } + *response = DAP_OK; + return (1); +} + + +// Process Connect command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +static uint32_t DAP_Connect(uint8_t *request, uint8_t *response) +{ + uint32_t port; + + if (*request == DAP_PORT_AUTODETECT) + { + port = DAP_DEFAULT_PORT; + } + else + { + port = *request; + } + + switch (port) + { +#if (DAP_SWD != 0) + case DAP_PORT_SWD: + DEBUG("DAP_CONNECT: SWD\n"); + DAP_Data.debug_port = DAP_PORT_SWD; + PORT_SWD_SETUP(); + break; +#endif +#if (DAP_JTAG != 0) + case DAP_PORT_JTAG: + DEBUG("DAP_CONNECT: JTAG\n"); + DAP_Data.debug_port = DAP_PORT_JTAG; + PORT_JTAG_SETUP(); + break; +#endif + default: + DEBUG("DAP_CONNECT: DISABLED\n"); + *response = DAP_PORT_DISABLED; + return (1); + } + + *response = port; + return (1); +} + + +// Process Disconnect command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +static uint32_t DAP_Disconnect(uint8_t *response) +{ + DEBUG("DAP_DISCONNECT: DISABLED\n"); + DAP_Data.debug_port = DAP_PORT_DISABLED; + PORT_OFF(); + + *response = DAP_OK; + return (1); +} + + +// Process Reset Target command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +static uint32_t DAP_ResetTarget(uint8_t *response) +{ + *(response + 1) = RESET_TARGET(); + *(response + 0) = DAP_OK; + DEBUG("DAP_RESET: %02X\n", *(response + 1)); + return (2); +} + + +// Process SWJ Pins command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if ((DAP_SWD != 0) || (DAP_JTAG != 0)) +static uint32_t DAP_SWJ_Pins(uint8_t *request, uint8_t *response) +{ + uint8_t value; + uint8_t select; + uint32_t wait; + + value = *(request + 0); + select = *(request + 1); + wait = (*(request + 2) << 0) | + (*(request + 3) << 8) | + (*(request + 4) << 16) | + (*(request + 5) << 24); + + DEBUG("DAP_SWJ_Pins: %04X %04X %04X", select, value, wait); + + if (select & (1 << DAP_SWJ_SWCLK_TCK)) + { + if (value & (1 << DAP_SWJ_SWCLK_TCK)) + PIN_SWCLK_TCK_SET(); + else + PIN_SWCLK_TCK_CLR(); + } + + if (select & (1 << DAP_SWJ_SWDIO_TMS)) + { + if (value & (1 << DAP_SWJ_SWDIO_TMS)) + PIN_SWDIO_TMS_SET(); + else + PIN_SWDIO_TMS_CLR(); + } + +#if (DAP_JTAG != 0) + if (select & (1 << DAP_SWJ_TDI)) + PIN_TDI_OUT(value >> DAP_SWJ_TDI); +#endif + + if (select & (1 << DAP_SWJ_nTRST)) + PIN_nTRST_OUT(value >> DAP_SWJ_nTRST); + + if (select & (1 << DAP_SWJ_nRESET)) + PIN_nRESET_OUT(value >> DAP_SWJ_nRESET); + + if (wait) + { + if (wait > 3000000) + wait = 3000000; + TIMER_START(wait); + do { + if (select & (1 << DAP_SWJ_SWCLK_TCK)) + { + if ((value >> DAP_SWJ_SWCLK_TCK) ^ PIN_SWCLK_TCK_IN()) + continue; + } + if (select & (1 << DAP_SWJ_SWDIO_TMS)) + { + if ((value >> DAP_SWJ_SWDIO_TMS) ^ PIN_SWDIO_TMS_IN()) + continue; + } +#if (DAP_JTAG != 0) + if (select & (1 << DAP_SWJ_TDI)) + { + if ((value >> DAP_SWJ_TDI) ^ PIN_TDI_IN()) + continue; + } +#endif + if (select & (1 << DAP_SWJ_nTRST)) + { + if ((value >> DAP_SWJ_nTRST) ^ PIN_nTRST_IN()) + continue; + } + if (select & (1 << DAP_SWJ_nRESET)) + { + if ((value >> DAP_SWJ_nRESET) ^ PIN_nRESET_IN()) + continue; + } + break; + } while (!TIMER_EXPIRED()); + TIMER_STOP(); + } + + value = (PIN_SWCLK_TCK_IN() << DAP_SWJ_SWCLK_TCK) | + (PIN_SWDIO_TMS_IN() << DAP_SWJ_SWDIO_TMS) | +#if (DAP_JTAG != 0) + (PIN_TDI_IN() << DAP_SWJ_TDI) | + (PIN_TDO_IN() << DAP_SWJ_TDO) | +#endif + (PIN_nTRST_IN() << DAP_SWJ_nTRST) | + (PIN_nRESET_IN() << DAP_SWJ_nRESET); + + DEBUG(" %02X\n", (uint8_t)value); + *response = (uint8_t)value; + return (1); +} +#endif + + +// Process SWJ Clock command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if ((DAP_SWD != 0) || (DAP_JTAG != 0)) +static uint32_t DAP_SWJ_Clock(uint8_t *request, uint8_t *response) +{ + uint32_t clock; + uint32_t delay; + + clock = (*(request+0) << 0) | + (*(request+1) << 8) | + (*(request+2) << 16) | + (*(request+3) << 24); + + DEBUG("DAP_SWJ_Clock: %u\n", clock); + + if (clock == 0) + { + *response = DAP_ERROR; + return (1); + } + + /*TODO fast clock if (clock >= MAX_SWJ_CLOCK(DELAY_FAST_CYCLES)) + { + DAP_Data.fast_clock = 1; + DAP_Data.clock_delay = 1; + } + else*/ + { + DAP_Data.fast_clock = 0; + + delay = (CPU_CLOCK / 2 + (clock - 1)) / clock; + if (delay > IO_PORT_WRITE_CYCLES) + { + delay -= IO_PORT_WRITE_CYCLES; + delay = (delay + (DELAY_SLOW_CYCLES - 1)) / DELAY_SLOW_CYCLES; + } + else + { + delay = 1; + } + + DAP_Data.clock_delay = delay; + int success = ftdi_set_baudrate (&__ftdic, clock/2); + if( success < 0){ + DEBUG("Could not set baudrate: %s\n",ftdi_get_error_string(&__ftdic)); + } + } + + + *response = DAP_OK; + return (1); +} +#endif + + +// Process SWJ Sequence command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if ((DAP_SWD != 0) || (DAP_JTAG != 0)) +static uint32_t DAP_SWJ_Sequence(uint8_t *request, uint8_t *response) +{ + uint32_t count; + + count = *request++; + if (count == 0) count = 256; + + DEBUG("DAP_SWJ_Sequence: %u\n", count); + + SWJ_Sequence(count, request); + + *response = DAP_OK; + return (1); +} +#endif + + +// Process SWD Configure command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_SWD != 0) +static uint32_t DAP_SWD_Configure(uint8_t *request, uint8_t *response) +{ + uint8_t value; + + value = *request; + DAP_Data.swd_conf.turnaround = (value & 0x03) + 1; + DAP_Data.swd_conf.data_phase = (value & 0x04) ? 1 : 0; + + DEBUG("DAP_SWD_Configure: %d %d\n", + DAP_Data.swd_conf.turnaround, + DAP_Data.swd_conf.data_phase + ); + + *response = DAP_OK; + return (1); +} +#endif + + +// Process SWD Abort command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_SWD != 0) +static uint32_t DAP_SWD_Abort(uint8_t *request, uint8_t *response) +{ + uint32_t data; + + DEBUG("DAP_SWD_Abort: "); + + if (DAP_Data.debug_port != DAP_PORT_SWD) + { + DEBUG("ERROR\n"); + *response = DAP_ERROR; + return (1); + } + + // Load data (Ignore DAP index) + data = (*(request+1) << 0) | + (*(request+2) << 8) | + (*(request+3) << 16) | + (*(request+4) << 24); + + DEBUG("%04X\n", data); + // Write Abort register + SWD_Transfer(DP_ABORT, &data); + *response = DAP_OK; + return (1); +} +#endif + + +// Process JTAG Sequence command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_JTAG != 0) +static uint32_t DAP_JTAG_Sequence(uint8_t *request, uint8_t *response) +{ + uint32_t sequence_info; + uint32_t sequence_count; + uint32_t response_count; + uint32_t count; + + DEBUG("DAP_JTAG_Sequence: \n"); + + *response++ = DAP_OK; + response_count = 1; + + sequence_count = *request++; + while (sequence_count--) + { + sequence_info = *request++; + JTAG_Sequence(sequence_info, request, response); + count = sequence_info & JTAG_SEQUENCE_TCK; + if (count == 0) count = 64; + count = (count + 7) / 8; + request += count; + if (sequence_info & JTAG_SEQUENCE_TDO) + { + response += count; + response_count += count; + } + } + + return (response_count); +} +#endif + + +// Process JTAG Configure command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_JTAG != 0) +static uint32_t DAP_JTAG_Configure(uint8_t *request, uint8_t *response) +{ + uint32_t count; + uint32_t length; + uint32_t bits; + uint32_t n; + + DEBUG("DAP_JTAG_Configure: \n"); + + count = *request++; + DAP_Data.jtag_dev.count = count; + + bits = 0; + for (n = 0; n < count; n++) + { + length = *request++; + DAP_Data.jtag_dev.ir_length[n] = length; + DAP_Data.jtag_dev.ir_before[n] = bits; + bits += length; + } + for (n = 0; n < count; n++) + { + bits -= DAP_Data.jtag_dev.ir_length[n]; + DAP_Data.jtag_dev.ir_after[n] = bits; + } + + *response = DAP_OK; + return (1); +} +#endif + + +// Process JTAG IDCODE command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_JTAG != 0) +static uint32_t DAP_JTAG_IDCode(uint8_t *request, uint8_t *response) +{ + uint32_t data; + + DEBUG("DAP_JTAG_IDCode: "); + + if (DAP_Data.debug_port != DAP_PORT_JTAG) + { +err: DEBUG("ERROR\n"); + *response = DAP_ERROR; + return (1); + } + + // Device index (JTAP TAP) + DAP_Data.jtag_dev.index = *request; + if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) + goto err; + + // Select JTAG chain + JTAG_IR(JTAG_IDCODE); + + // Read IDCODE register + data = JTAG_ReadIDCode(); + + // Store Data + *(response+0) = DAP_OK; + *(response+1) = (uint8_t)(data >> 0); + *(response+2) = (uint8_t)(data >> 8); + *(response+3) = (uint8_t)(data >> 16); + *(response+4) = (uint8_t)(data >> 24); + + DEBUG("%04X\n", data); + + return (1+4); +} +#endif + + +// Process JTAG Abort command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_JTAG != 0) +static uint32_t DAP_JTAG_Abort(uint8_t *request, uint8_t *response) +{ + uint32_t data; + + DEBUG("DAP_JTAG_Abort: "); + if (DAP_Data.debug_port != DAP_PORT_JTAG) + { +err: DEBUG("ERROR\n"); + *response = DAP_ERROR; + return (1); + } + + // Device index (JTAP TAP) + DAP_Data.jtag_dev.index = *request; + if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) goto err; + + // Select JTAG chain + JTAG_IR(JTAG_ABORT); + + // Load data + data = (*(request+1) << 0) | + (*(request+2) << 8) | + (*(request+3) << 16) | + (*(request+4) << 24); + + // Write Abort register + JTAG_WriteAbort(data); + *response = DAP_OK; + + DEBUG("%04X\n", data); + + return (1); +} +#endif + + +// Process Transfer Configure command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +static uint32_t DAP_TransferConfigure(uint8_t *request, uint8_t *response) +{ + DAP_Data.transfer.idle_cycles = *(request+0); + DAP_Data.transfer.retry_count = *(request+1) | (*(request+2) << 8); + DAP_Data.transfer.match_retry = *(request+3) | (*(request+4) << 8); + DEBUG("DAP_TransferConfigure: %d %d %d\n", + DAP_Data.transfer.idle_cycles, + DAP_Data.transfer.retry_count, + DAP_Data.transfer.match_retry + ); + *response = DAP_OK; + return (1); +} + + +// Process SWD Transfer command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_SWD != 0) +static uint32_t DAP_SWD_Transfer(uint8_t *request, uint8_t *response) +{ + uint8_t request_count; + uint8_t request_value; + uint8_t response_count; + uint8_t response_value; + uint8_t *response_head; + uint32_t post_read; + uint32_t check_write; + uint32_t match_value; + uint16_t match_retry; + uint16_t retry; + uint32_t data; + + response_count = 0; + response_value = 0; + response_head = response; + response += 2; + + DAP_TransferAbort = 0; + + post_read = 0; + check_write = 0; + + request++; // Ignore DAP index + + request_count = *request++; + DEBUG("DAP_SWD_Transfer: %d\n", request_count); + + while (request_count--) + { + request_value = *request++; + if (request_value & DAP_TRANSFER_RnW) + { + // Read register + if (post_read) + { + // Read was posted before + retry = DAP_Data.transfer.retry_count; + if ((request_value & (DAP_TRANSFER_APnDP | DAP_TRANSFER_MATCH_VALUE)) == DAP_TRANSFER_APnDP) + { + // Read previous AP data and post next AP read + do + { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } + else + { + // Read previous AP data + do + { + response_value = SWD_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + post_read = 0; + } + if (response_value != DAP_TRANSFER_OK) + break; + // Store previous AP data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + } + if (request_value & DAP_TRANSFER_MATCH_VALUE) + { + // Read with value match + match_value = (*(request+0) << 0) | + (*(request+1) << 8) | + (*(request+2) << 16) | + (*(request+3) << 24); + request += 4; + match_retry = DAP_Data.transfer.match_retry; + if (request_value & DAP_TRANSFER_APnDP) + { + // Post AP read + retry = DAP_Data.transfer.retry_count; + do + { + response_value = SWD_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) break; + } + do + { + // Read register until its value matches or retry counter expires + retry = DAP_Data.transfer.retry_count; + do + { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + + if (response_value != DAP_TRANSFER_OK) + break; + } while (((data & DAP_Data.transfer.match_mask) != match_value) && match_retry-- && !DAP_TransferAbort); + if ((data & DAP_Data.transfer.match_mask) != match_value) + { + response_value |= DAP_TRANSFER_MISMATCH; + } + if (response_value != DAP_TRANSFER_OK) break; + } + else + { + // Normal read + retry = DAP_Data.transfer.retry_count; + if (request_value & DAP_TRANSFER_APnDP) + { + // Read AP register + if (post_read == 0) + { + // Post AP read + do + { + response_value = SWD_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) break; + post_read = 1; + } + } + else + { + // Read DP register + do + { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) break; + // Store data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + } + } + check_write = 0; + } + else + { + // Write register + if (post_read) + { + // Read previous data + retry = DAP_Data.transfer.retry_count; + do + { + response_value = SWD_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + + if (response_value != DAP_TRANSFER_OK) + break; + // Store previous data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + post_read = 0; + } + // Load data + data = (*(request+0) << 0) | + (*(request+1) << 8) | + (*(request+2) << 16) | + (*(request+3) << 24); + request += 4; + if (request_value & DAP_TRANSFER_MATCH_MASK) + { + // Write match mask + DAP_Data.transfer.match_mask = data; + response_value = DAP_TRANSFER_OK; + } + else + { + // Write DP/AP register + retry = DAP_Data.transfer.retry_count; + do + { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + + if (response_value != DAP_TRANSFER_OK) + break; + check_write = 1; + } + } + response_count++; + if (DAP_TransferAbort) + break; + } + + if (response_value == DAP_TRANSFER_OK) + { + if (post_read) + { + // Read previous data + retry = DAP_Data.transfer.retry_count; + do + { + response_value = SWD_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) goto end; + // Store previous data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + } + else if (check_write) + { + // Check last write + retry = DAP_Data.transfer.retry_count; + do + { + response_value = SWD_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } + } + +end: + *(response_head + 0) = (uint8_t)response_count; + *(response_head + 1) = (uint8_t)response_value; + + return (response - response_head); +} +#endif + + +// Process JTAG Transfer command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_JTAG != 0) +static uint32_t DAP_JTAG_Transfer(uint8_t *request, uint8_t *response) +{ + uint32_t request_count; + uint32_t request_value; + uint32_t request_ir; + uint32_t response_count; + uint32_t response_value; + uint8_t *response_head; + uint32_t post_read; + uint32_t match_value; + uint32_t match_retry; + uint32_t retry; + uint32_t data; + uint32_t ir; + + DEBUG("DAP_JTAG_Transfer:\n"); + + response_count = 0; + response_value = 0; + response_head = response; + response += 2; + + DAP_TransferAbort = 0; + + ir = 0; + post_read = 0; + + // Device index (JTAP TAP) + DAP_Data.jtag_dev.index = *request++; + if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) goto end; + + request_count = *request++; + while (request_count--) { + request_value = *request++; + request_ir = (request_value & DAP_TRANSFER_APnDP) ? JTAG_APACC : JTAG_DPACC; + if (request_value & DAP_TRANSFER_RnW) { + // Read register + if (post_read) { + // Read was posted before + retry = DAP_Data.transfer.retry_count; + if ((ir == request_ir) && ((request_value & DAP_TRANSFER_MATCH_VALUE) == 0)) { + // Read previous data and post next read + do { + response_value = JTAG_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } else { + // Select JTAG chain + if (ir != JTAG_DPACC) { + ir = JTAG_DPACC; + JTAG_IR(ir); + } + // Read previous data + do { + response_value = JTAG_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + post_read = 0; + } + if (response_value != DAP_TRANSFER_OK) break; + // Store previous data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + } + if (request_value & DAP_TRANSFER_MATCH_VALUE) { + // Read with value match + match_value = (*(request+0) << 0) | + (*(request+1) << 8) | + (*(request+2) << 16) | + (*(request+3) << 24); + request += 4; + match_retry = DAP_Data.transfer.match_retry; + // Select JTAG chain + if (ir != request_ir) { + ir = request_ir; + JTAG_IR(ir); + } + // Post DP/AP read + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) break; + do { + // Read register until its value matches or retry counter expires + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) break; + } while (((data & DAP_Data.transfer.match_mask) != match_value) && match_retry-- && !DAP_TransferAbort); + if ((data & DAP_Data.transfer.match_mask) != match_value) { + response_value |= DAP_TRANSFER_MISMATCH; + } + if (response_value != DAP_TRANSFER_OK) break; + } else { + // Normal read + if (post_read == 0) { + // Select JTAG chain + if (ir != request_ir) { + ir = request_ir; + JTAG_IR(ir); + } + // Post DP/AP read + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) break; + post_read = 1; + } + } + } else { + // Write register + if (post_read) { + // Select JTAG chain + if (ir != JTAG_DPACC) { + ir = JTAG_DPACC; + JTAG_IR(ir); + } + // Read previous data + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) break; + // Store previous data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + post_read = 0; + } + // Load data + data = (*(request+0) << 0) | + (*(request+1) << 8) | + (*(request+2) << 16) | + (*(request+3) << 24); + request += 4; + if (request_value & DAP_TRANSFER_MATCH_MASK) { + // Write match mask + DAP_Data.transfer.match_mask = data; + response_value = DAP_TRANSFER_OK; + } else { + // Select JTAG chain + if (ir != request_ir) { + ir = request_ir; + JTAG_IR(ir); + } + // Write DP/AP register + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) break; + } + } + response_count++; + if (DAP_TransferAbort) break; + } + + if (response_value == DAP_TRANSFER_OK) { + // Select JTAG chain + if (ir != JTAG_DPACC) { + ir = JTAG_DPACC; + JTAG_IR(ir); + } + if (post_read) { + // Read previous data + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) goto end; + // Store previous data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + } else { + // Check last write + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } + } + +end: + *(response_head+0) = (uint8_t)response_count; + *(response_head+1) = (uint8_t)response_value; + + return (response - response_head); +} +#endif + + +// Process SWD Transfer Block command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_SWD != 0) +static uint32_t DAP_SWD_TransferBlock(uint8_t *request, uint8_t *response) +{ + uint32_t request_count; + uint32_t request_value; + uint32_t response_count; + uint32_t response_value; + uint8_t *response_head; + uint32_t retry; + uint32_t data; + + DEBUG("DAP_SWD_TransferBlock:\n"); + + response_count = 0; + response_value = 0; + response_head = response; + response += 3; + + DAP_TransferAbort = 0; + + request++; // Ignore DAP index + + request_count = *request | (*(request+1) << 8); + request += 2; + if (request_count == 0) goto end; + + request_value = *request++; + if (request_value & DAP_TRANSFER_RnW) + { + // Read register block + if (request_value & DAP_TRANSFER_APnDP) + { + // Post AP read + retry = DAP_Data.transfer.retry_count; + do + { + response_value = SWD_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) goto end; + } + while (request_count--) + { + // Read DP/AP register + if ((request_count == 0) && (request_value & DAP_TRANSFER_APnDP)) + { + // Last AP read + request_value = DP_RDBUFF | DAP_TRANSFER_RnW; + } + retry = DAP_Data.transfer.retry_count; + do + { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) goto end; + // Store data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + response_count++; + } + } + else + { + // Write register block + while (request_count--) + { + // Load data + data = (*(request+0) << 0) | + (*(request+1) << 8) | + (*(request+2) << 16) | + (*(request+3) << 24); + request += 4; + // Write DP/AP register + retry = DAP_Data.transfer.retry_count; + do + { + response_value = SWD_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) goto end; + response_count++; + } + // Check last write + retry = DAP_Data.transfer.retry_count; + do + { + response_value = SWD_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } + +end: + *(response_head+0) = (uint8_t)(response_count >> 0); + *(response_head+1) = (uint8_t)(response_count >> 8); + *(response_head+2) = (uint8_t) response_value; + + return (response - response_head); +} +#endif + + +// Process JTAG Transfer Block command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if (DAP_JTAG != 0) +static uint32_t DAP_JTAG_TransferBlock(uint8_t *request, uint8_t *response) +{ + uint32_t request_count; + uint32_t request_value; + uint32_t response_count; + uint32_t response_value; + uint8_t *response_head; + uint32_t retry; + uint32_t data; + uint32_t ir; + + DEBUG("DAP_JTAG_TransferBlock:\n"); + + response_count = 0; + response_value = 0; + response_head = response; + response += 3; + + DAP_TransferAbort = 0; + + // Device index (JTAP TAP) + DAP_Data.jtag_dev.index = *request++; + if (DAP_Data.jtag_dev.index >= DAP_Data.jtag_dev.count) goto end; + + request_count = *request | (*(request+1) << 8); + request += 2; + if (request_count == 0) goto end; + + request_value = *request++; + + // Select JTAG chain + ir = (request_value & DAP_TRANSFER_APnDP) ? JTAG_APACC : JTAG_DPACC; + JTAG_IR(ir); + + if (request_value & DAP_TRANSFER_RnW) { + // Post read + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) goto end; + // Read register block + while (request_count--) { + // Read DP/AP register + if (request_count == 0) { + // Last read + if (ir != JTAG_DPACC) { + JTAG_IR(JTAG_DPACC); + } + request_value = DP_RDBUFF | DAP_TRANSFER_RnW; + } + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) goto end; + // Store data + *response++ = (uint8_t) data; + *response++ = (uint8_t)(data >> 8); + *response++ = (uint8_t)(data >> 16); + *response++ = (uint8_t)(data >> 24); + response_count++; + } + } else { + // Write register block + while (request_count--) { + // Load data + data = (*(request+0) << 0) | + (*(request+1) << 8) | + (*(request+2) << 16) | + (*(request+3) << 24); + request += 4; + // Write DP/AP register + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(request_value, &data); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + if (response_value != DAP_TRANSFER_OK) goto end; + response_count++; + } + // Check last write + if (ir != JTAG_DPACC) { + JTAG_IR(JTAG_DPACC); + } + retry = DAP_Data.transfer.retry_count; + do { + response_value = JTAG_Transfer(DP_RDBUFF | DAP_TRANSFER_RnW, NULL); + } while ((response_value == DAP_TRANSFER_WAIT) && retry-- && !DAP_TransferAbort); + } + +end: + *(response_head+0) = (uint8_t)(response_count >> 0); + *(response_head+1) = (uint8_t)(response_count >> 8); + *(response_head+2) = (uint8_t) response_value; + + return (response - response_head); +} +#endif + + +// Process DAP Vendor command and prepare response +// Default function (can be overridden) +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +#if 0 +__weak uint32_t DAP_ProcessVendorCommand(uint8_t *request, uint8_t *response) +{ + DEBUG("DAP_ProcessVendorCommand:\n"); + *response = ID_DAP_Invalid; + return (1); +} +#endif + + +// Process DAP command and prepare response +// request: pointer to request data +// response: pointer to response data +// return: number of bytes in response +uint32_t DAP_ProcessCommand(uint8_t *request, uint8_t *response) +{ + uint32_t num; + + if ((*request >= ID_DAP_Vendor0) && (*request <= ID_DAP_Vendor31)) + { + return DAP_ProcessVendorCommand(request, response); + } + + *response++ = *request; + + switch (*request++) + { + case ID_DAP_Info: + num = DAP_Info(*request, response + 1); + *response = num; + return (2 + num); + case ID_DAP_LED: + num = DAP_LED(request, response); + break; + case ID_DAP_Connect: + num = DAP_Connect(request, response); + break; + case ID_DAP_Disconnect: + num = DAP_Disconnect(response); + break; + case ID_DAP_Delay: + num = DAP_Delay(request, response); + break; + case ID_DAP_ResetTarget: + num = DAP_ResetTarget(response); + break; + +#if ((DAP_SWD != 0) || (DAP_JTAG != 0)) + case ID_DAP_SWJ_Pins: + num = DAP_SWJ_Pins(request, response); + break; + case ID_DAP_SWJ_Clock: + num = DAP_SWJ_Clock(request, response); + break; + case ID_DAP_SWJ_Sequence: + num = DAP_SWJ_Sequence(request, response); + break; +#else + case ID_DAP_SWJ_Pins: + case ID_DAP_SWJ_Clock: + case ID_DAP_SWJ_Sequence: + *response = DAP_ERROR; + return (2); +#endif + +#if (DAP_SWD != 0) + case ID_DAP_SWD_Configure: + num = DAP_SWD_Configure(request, response); + break; +#else + case ID_DAP_SWD_Configure: + *response = DAP_ERROR; + return (2); +#endif + +#if (DAP_JTAG != 0) + case ID_DAP_JTAG_Sequence: + num = DAP_JTAG_Sequence(request, response); + break; + case ID_DAP_JTAG_Configure: + num = DAP_JTAG_Configure(request, response); + break; + case ID_DAP_JTAG_IDCODE: + num = DAP_JTAG_IDCode(request, response); + break; +#else + case ID_DAP_JTAG_Sequence: + case ID_DAP_JTAG_Configure: + case ID_DAP_JTAG_IDCODE: + *response = DAP_ERROR; + return (2); +#endif + + case ID_DAP_TransferConfigure: + num = DAP_TransferConfigure(request, response); + break; + + case ID_DAP_Transfer: + switch (DAP_Data.debug_port) + { +#if (DAP_SWD != 0) + case DAP_PORT_SWD: + num = DAP_SWD_Transfer (request, response); + break; +#endif +#if (DAP_JTAG != 0) + case DAP_PORT_JTAG: + num = DAP_JTAG_Transfer(request, response); + break; +#endif + default: + *(response+0) = 0; // Response count + *(response+1) = 0; // Response value + num = 2; + } + break; + + case ID_DAP_TransferBlock: + switch (DAP_Data.debug_port) + { +#if (DAP_SWD != 0) + case DAP_PORT_SWD: + num = DAP_SWD_TransferBlock (request, response); + break; +#endif +#if (DAP_JTAG != 0) + case DAP_PORT_JTAG: + num = DAP_JTAG_TransferBlock(request, response); + break; +#endif + default: + *(response+0) = 0; // Response count [7:0] + *(response+1) = 0; // Response count[15:8] + *(response+2) = 0; // Response value + num = 3; + } + break; + + case ID_DAP_WriteABORT: + switch (DAP_Data.debug_port) + { +#if (DAP_SWD != 0) + case DAP_PORT_SWD: + num = DAP_SWD_Abort (request, response); + break; +#endif +#if (DAP_JTAG != 0) + case DAP_PORT_JTAG: + num = DAP_JTAG_Abort(request, response); + break; +#endif + default: + *response = DAP_ERROR; + return (2); + } + break; + + default: + *(response-1) = ID_DAP_Invalid; + return (1); + } + return (1 + num); +} + + +// Setup DAP +void DAP_Setup(void) +{ + // Default settings (only non-zero values) + //DAP_Data.debug_port = 0; + //DAP_Data.fast_clock = 0; + DAP_Data.clock_delay = CLOCK_DELAY(DAP_DEFAULT_SWJ_CLOCK); + //DAP_Data.transfer.idle_cycles = 0; + DAP_Data.transfer.retry_count = 100; + //DAP_Data.transfer.match_retry = 0; + //DAP_Data.transfer.match_mask = 0x000000; +#if (DAP_SWD != 0) + DAP_Data.swd_conf.turnaround = 1; + //DAP_Data.swd_conf.data_phase = 0; +#endif +#if (DAP_JTAG != 0) + //DAP_Data.jtag_dev.count = 0; +#endif + + DAP_SETUP(); // Device specific setup +} diff --git a/src/DAP.h b/src/DAP.h new file mode 100644 index 0000000..509a2e3 --- /dev/null +++ b/src/DAP.h @@ -0,0 +1,221 @@ +/****************************************************************************** + * @file DAP.h + * @brief CMSIS-DAP Definitions + * @version V1.00 + * @date 31. May 2012 + * + * @note + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * @par + * ARM Limited (ARM) is supplying this software for use with Cortex-M + * processor based microcontrollers. + * + * @par + * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. + * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + * + ******************************************************************************/ + +#ifndef __DAP_H__ +#define __DAP_H__ + +#include +#include +#include "Timer.h" + +// DAP Command IDs +#define ID_DAP_Info 0x00 +#define ID_DAP_LED 0x01 +#define ID_DAP_Connect 0x02 +#define ID_DAP_Disconnect 0x03 +#define ID_DAP_TransferConfigure 0x04 +#define ID_DAP_Transfer 0x05 +#define ID_DAP_TransferBlock 0x06 +#define ID_DAP_TransferAbort 0x07 +#define ID_DAP_WriteABORT 0x08 +#define ID_DAP_Delay 0x09 +#define ID_DAP_ResetTarget 0x0A +#define ID_DAP_SWJ_Pins 0x10 +#define ID_DAP_SWJ_Clock 0x11 +#define ID_DAP_SWJ_Sequence 0x12 +#define ID_DAP_SWD_Configure 0x13 +#define ID_DAP_JTAG_Sequence 0x14 +#define ID_DAP_JTAG_Configure 0x15 +#define ID_DAP_JTAG_IDCODE 0x16 + +// DAP Vendor Command IDs +#define ID_DAP_Vendor0 0x80 +#define ID_DAP_Vendor1 0x81 +#define ID_DAP_Vendor2 0x82 +#define ID_DAP_Vendor3 0x83 +#define ID_DAP_Vendor4 0x84 +#define ID_DAP_Vendor5 0x85 +#define ID_DAP_Vendor6 0x86 +#define ID_DAP_Vendor7 0x87 +#define ID_DAP_Vendor8 0x88 +#define ID_DAP_Vendor9 0x89 +#define ID_DAP_Vendor10 0x8A +#define ID_DAP_Vendor11 0x8B +#define ID_DAP_Vendor12 0x8C +#define ID_DAP_Vendor13 0x8D +#define ID_DAP_Vendor14 0x8E +#define ID_DAP_Vendor15 0x8F +#define ID_DAP_Vendor16 0x90 +#define ID_DAP_Vendor17 0x91 +#define ID_DAP_Vendor18 0x92 +#define ID_DAP_Vendor19 0x93 +#define ID_DAP_Vendor20 0x94 +#define ID_DAP_Vendor21 0x95 +#define ID_DAP_Vendor22 0x96 +#define ID_DAP_Vendor23 0x97 +#define ID_DAP_Vendor24 0x98 +#define ID_DAP_Vendor25 0x99 +#define ID_DAP_Vendor26 0x9A +#define ID_DAP_Vendor27 0x9B +#define ID_DAP_Vendor28 0x9C +#define ID_DAP_Vendor29 0x9D +#define ID_DAP_Vendor30 0x9E +#define ID_DAP_Vendor31 0x9F + +#define ID_DAP_Invalid 0xFF + +// DAP Status Code +#define DAP_OK 0 +#define DAP_ERROR 0xFF + +// DAP ID +#define DAP_ID_VENDOR 1 +#define DAP_ID_PRODUCT 2 +#define DAP_ID_SER_NUM 3 +#define DAP_ID_FW_VER 4 +#define DAP_ID_DEVICE_VENDOR 5 +#define DAP_ID_DEVICE_NAME 6 +#define DAP_ID_CAPABILITIES 0xF0 +#define DAP_ID_PACKET_COUNT 0xFE +#define DAP_ID_PACKET_SIZE 0xFF + +// DAP LEDs +#define DAP_LED_DEBUGGER_CONNECTED 0 +#define DAP_LED_TARGET_RUNNING 1 + +// DAP Port +#define DAP_PORT_AUTODETECT 0 // Autodetect Port +#define DAP_PORT_DISABLED 0 // Port Disabled (I/O pins in High-Z) +#define DAP_PORT_SWD 1 // SWD Port (SWCLK, SWDIO) + nRESET +#define DAP_PORT_JTAG 2 // JTAG Port (TCK, TMS, TDI, TDO, nTRST) + nRESET + +// DAP SWJ Pins +#define DAP_SWJ_SWCLK_TCK 0 // SWCLK/TCK +#define DAP_SWJ_SWDIO_TMS 1 // SWDIO/TMS +#define DAP_SWJ_TDI 2 // TDI +#define DAP_SWJ_TDO 3 // TDO +#define DAP_SWJ_nTRST 5 // nTRST +#define DAP_SWJ_nRESET 7 // nRESET + +// DAP Transfer Request +#define DAP_TRANSFER_APnDP (1<<0) +#define DAP_TRANSFER_RnW (1<<1) +#define DAP_TRANSFER_A2 (1<<2) +#define DAP_TRANSFER_A3 (1<<3) +#define DAP_TRANSFER_MATCH_VALUE (1<<4) +#define DAP_TRANSFER_MATCH_MASK (1<<5) + +// DAP Transfer Response +#define DAP_TRANSFER_OK (1<<0) +#define DAP_TRANSFER_WAIT (1<<1) +#define DAP_TRANSFER_FAULT (1<<2) +#define DAP_TRANSFER_ERROR (1<<3) +#define DAP_TRANSFER_MISMATCH (1<<4) + + +// Debug Port Register Addresses +#define DP_IDCODE 0x00 // IDCODE Register (SW Read only) +#define DP_ABORT 0x00 // Abort Register (SW Write only) +#define DP_CTRL_STAT 0x04 // Control & Status +#define DP_WCR 0x04 // Wire Control Register (SW Only) +#define DP_SELECT 0x08 // Select Register (JTAG R/W & SW W) +#define DP_RESEND 0x08 // Resend (SW Read Only) +#define DP_RDBUFF 0x0C // Read Buffer (Read Only) + +// JTAG IR Codes +#define JTAG_ABORT 0x08 +#define JTAG_DPACC 0x0A +#define JTAG_APACC 0x0B +#define JTAG_IDCODE 0x0E +#define JTAG_BYPASS 0x0F + +// JTAG Sequence Info +#define JTAG_SEQUENCE_TCK 0x3F // TCK count +#define JTAG_SEQUENCE_TMS 0x40 // TMS value +#define JTAG_SEQUENCE_TDO 0x80 // TDO capture + + +// DAP Data structure +typedef struct { + uint8_t debug_port; // Debug Port + uint8_t fast_clock; // Fast Clock Flag + uint32_t clock_delay; // Clock Delay + struct { // Transfer Configuration + uint8_t idle_cycles; // Idle cycles after transfer + uint16_t retry_count; // Number of retries after WAIT response + uint16_t match_retry; // Number of retries if read value does not match + uint32_t match_mask; // Match Mask + } transfer; +#if (DAP_SWD != 0) + struct { // SWD Configuration + uint8_t turnaround; // Turnaround period + uint8_t data_phase; // Always generate Data Phase + } swd_conf; +#endif +#if (DAP_JTAG != 0) + struct { // JTAG Device Chain + uint8_t count; // Number of devices + uint8_t index; // Device index (device at TDO has index 0) +#if (DAP_JTAG_DEV_CNT != 0) + uint8_t ir_length[DAP_JTAG_DEV_CNT]; // IR Length in bits + uint16_t ir_before[DAP_JTAG_DEV_CNT]; // Bits before IR + uint16_t ir_after [DAP_JTAG_DEV_CNT]; // Bits after IR +#endif + } jtag_dev; +#endif +} DAP_Data_t; + +extern DAP_Data_t DAP_Data; // DAP Data +extern volatile uint8_t DAP_TransferAbort; // Transfer Abort Flag + + +// Functions +extern void SWJ_Sequence (uint32_t count, uint8_t *data); +extern void JTAG_Sequence (uint32_t info, uint8_t *tdi, uint8_t *tdo); +extern void JTAG_IR (uint32_t ir); +extern uint32_t JTAG_ReadIDCode (void); +extern void JTAG_WriteAbort (uint32_t data); +extern uint8_t JTAG_Transfer (uint8_t request, uint32_t *data); +extern uint8_t SWD_Transfer (uint8_t request, uint32_t *data); + +extern uint32_t DAP_ProcessVendorCommand (uint8_t *request, uint8_t *response); + +extern uint32_t DAP_ProcessCommand (uint8_t *request, uint8_t *response); +extern void DAP_Setup (void); + +// Configurable delay for clock generation +#define DELAY_SLOW_CYCLES 1 // Number of cycles for one iteration +static __forceinline void PIN_DELAY_SLOW (uint32_t delay) { + //Delayus(delay); + //printf("delay %d\n",delay); + FTDI_SUBMIT(); +} + +// Fixed delay for fast clock generation +#define DELAY_FAST_CYCLES 0 // Number of cycles +static __forceinline void PIN_DELAY_FAST (void) { +//__nop(); + FTDI_SUBMIT(); +} + + +#endif /* __DAP_H__ */ diff --git a/src/DAP_config.h b/src/DAP_config.h new file mode 100644 index 0000000..342089b --- /dev/null +++ b/src/DAP_config.h @@ -0,0 +1,659 @@ +/**************************************************************************//** + * @file DAP_config.h + * @brief CMSIS-DAP Configuration File (Template) + * @version V1.00 + * @date 31. May 2012 + * + * @note + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * @par + * ARM Limited (ARM) is supplying this software for use with Cortex-M + * processor based microcontrollers. + * + * @par + * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. + * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + * + ******************************************************************************/ + +#ifndef __DAP_CONFIG_H__ +#define __DAP_CONFIG_H__ + + +//************************************************************************************************** +/** +\defgroup DAP_Config_Debug_gr CMSIS-DAP Debug Unit Information +\ingroup DAP_ConfigIO_gr +@{ +Provides definitions about: + - Definition of Cortex-M processor parameters used in CMSIS-DAP Debug Unit. + - Debug Unit communication packet size. + - Debug Access Port communication mode (JTAG or SWD). + - Optional information about a connected Target Device (for Evaluation Boards). +*/ +#include "ftdi_vars.h" +#include "device.h" // Debug Unit Cortex-M Processor Header File +#include "Debug.h" +#include +#include + + +/// Processor Clock of the Cortex-M MCU used in the Debug Unit. +/// On the Desktop-libftdi version, this is the maximum resolution of the timer +/// This value is used to calculate the SWD/JTAG clock speed. +#define CPU_CLOCK 1000000 ///< Clock in Hz + +/// Number of processor cycles for I/O Port write operations. +/// This value is used to calculate the SWD/JTAG clock speed that is generated with I/O +/// Port write operations in the Debug Unit by a Cortex-M MCU. Most Cortex-M processors +/// requrie 2 processor cycles for a I/O Port Write operation. If the Debug Unit uses +/// a Cortex-M0+ processor with high-speed peripheral I/O only 1 processor cycle might be +/// requrired. +#define IO_PORT_WRITE_CYCLES 0 ///< I/O Cycles: 2=default, 1=Cortex-M0+ fast I/0 + +/// Indicate that Serial Wire Debug (SWD) communication mode is available at the Debug Access Port. +/// This information is returned by the command \ref DAP_Info as part of Capabilities. +#define DAP_SWD 1 ///< SWD Mode: 1 = available, 0 = not available + +/// Indicate that JTAG communication mode is available at the Debug Port. +/// This information is returned by the command \ref DAP_Info as part of Capabilities. +#define DAP_JTAG 1 ///< JTAG Mode: 1 = available, 0 = not available. + +/// Configure maximum number of JTAG devices on the scan chain connected to the Debug Access Port. +/// This setting impacts the RAM requirements of the Debug Unit. Valid range is 1 .. 255. +#define DAP_JTAG_DEV_CNT 8 ///< Maximum number of JTAG devices on scan chain + +/// Default communication mode on the Debug Access Port. +/// Used for the command \ref DAP_Connect when Port Default mode is selected. +#define DAP_DEFAULT_PORT 1 ///< Default JTAG/SWJ Port Mode: 1 = SWD, 2 = JTAG. + +/// Default communication speed on the Debug Access Port for SWD and JTAG mode. +/// Used to initialize the default SWD/JTAG clock frequency. +/// The command \ref DAP_SWJ_Clock can be used to overwrite this default setting. +#define DAP_DEFAULT_SWJ_CLOCK 10000 ///< Default SWD/JTAG clock frequency in Hz. + +/// Maximum Package Size for Command and Response data. +/// This configuration settings is used to optimized the communication performance with the +/// debugger and depends on the USB peripheral. Change setting to 1024 for High-Speed USB. +#define DAP_PACKET_SIZE 64 ///< USB: 64 = Full-Speed, 1024 = High-Speed. + +/// Maximum Package Buffers for Command and Response data. +/// This configuration settings is used to optimized the communication performance with the +/// debugger and depends on the USB peripheral. For devices with limited RAM or USB buffer the +/// setting can be reduced (valid range is 1 .. 255). Change setting to 4 for High-Speed USB. +#define DAP_PACKET_COUNT 64 ///< Buffers: 64 = Full-Speed, 4 = High-Speed. + + +/// Debug Unit is connected to fixed Target Device. +/// The Debug Unit may be part of an evaluation board and always connected to a fixed +/// known device. In this case a Device Vendor and Device Name string is stored which +/// may be used by the debugger or IDE to configure device parameters. +#define TARGET_DEVICE_FIXED 0 ///< Target Device: 1 = known, 0 = unknown; + +#if TARGET_DEVICE_FIXED +#define TARGET_DEVICE_VENDOR "ARM" ///< String indicating the Silicon Vendor +#define TARGET_DEVICE_NAME "Cortex-M4" ///< String indicating the Target Device +#endif + +///@} + +//************************************************************************************************** +/** +\defgroup DAP_Config_PortIO_gr CMSIS-DAP Hardware I/O Pin Access +\ingroup DAP_ConfigIO_gr +@{ + +Standard I/O Pins of the CMSIS-DAP Hardware Debug Port support standard JTAG mode +and Serial Wire Debug (SWD) mode. In SWD mode only 2 pins are required to implement the debug +interface of a device. The following I/O Pins are provided: + +JTAG I/O Pin | SWD I/O Pin | CMSIS-DAP Hardware pin mode +---------------------------- | -------------------- | --------------------------------------------- +TCK: Test Clock | SWCLK: Clock | Output Push/Pull +TMS: Test Mode Select | SWDIO: Data I/O | Output Push/Pull; Input (for receiving data) +TDI: Test Data Input | | Output Push/Pull +TDO: Test Data Output | | Input +nTRST: Test Reset (optional) | | Output Open Drain with pull-up resistor +nRESET: Device Reset | nRESET: Device Reset | Output Open Drain with pull-up resistor + + +DAP Hardware I/O Pin Access Functions +------------------------------------- +The various I/O Pins are accessed by functions that implement the Read, Write, Set, or Clear to +these I/O Pins. + +For the SWDIO I/O Pin there are additional functions that are called in SWD I/O mode only. +This functions are provided to achieve faster I/O that is possible with some advanced GPIO +peripherals that can independently write/read a single I/O pin without affecting any other pins +of the same I/O port. The following SWDIO I/O Pin functions are provided: + - \ref PIN_SWDIO_OUT_ENABLE to enable the output mode from the DAP hardware. + - \ref PIN_SWDIO_OUT_DISABLE to enable the input mode to the DAP hardware. + - \ref PIN_SWDIO_IN to read from the SWDIO I/O pin with utmost possible speed. + - \ref PIN_SWDIO_OUT to write to the SWDIO I/O pin with utmost possible speed. +*/ + +// Configure DAP I/O pins ------------------------------ + +#define TMS_SWDIO DCD +#define TCK_SWCLK RI +#define TDO_SWO RXD +#define TDI RTS +#define nRESET DTR +#define nTRST TXD +#define LED_CONN CTS +#define LED_RUN DSR + +static __inline const char* pin_to_str(uint8_t pin){ + switch(pin){ + case TMS_SWDIO: + return "TMS_SWDIO(DCD)"; + case TCK_SWCLK: + return "TCK_SWCLK(RI)"; + case TDO_SWO: + return "TDO_SWO(RXD)"; + case TDI: + return "TDI(RTS)"; + case nRESET: + return "nRESET(DTR)"; + case nTRST: + return "nTRST(TXD)"; + case LED_CONN: + return "LED_CONN(CTS)"; + case LED_RUN: + return "LED_RUN(DSR)"; + default: + return "???"; + } +} + +static __inline void FTDI_BITBANG_SETUP() { + int success; + /* Enable bitbang mode */ + success = ftdi_set_bitmode(&__ftdic, dir_state, BITMODE_BITBANG ); + if( success<0 ){ + DEBUG("Could not change to async. bitbang: %s\n",ftdi_get_error_string(&__ftdic)); + } + success = ftdi_write_data(&__ftdic,&out_state,1); + if( success < 0){ + DEBUG("Could not write pins: %s\n",ftdi_get_error_string(&__ftdic)); + } + /*ftdi_read_data_set_chunksize(&__ftdic,1); + ftdi_write_data_set_chunksize(&__ftdic,1);*/ +} + +/** Setup of the Debug Unit I/O pins and LEDs (called when Debug Unit is initialized). +This function performs the initialization of the CMSIS-DAP Hardware I/O Pins and the +Status LEDs. In detail the operation of Hardware I/O and LED pins are enabled and set: + - I/O clock system enabled. + - all I/O pins: input buffer enabled, output pins are set to HighZ mode. + - for nTRST, nRESET a weak pull-up (if available) is enabled. + - LED output pins are enabled and LEDs are turned off. +*/ +static __inline void DAP_SETUP (void) { + /* Initialize context for subsequent function calls */ + ftdi_init(&__ftdic); + int success; + /* Open FTDI device based on FT232R vendor & product IDs */ + success = ftdi_usb_open(&__ftdic, VID, PID); + if(success < 0) { + DEBUG("Can't open device [%x:%x]: %s\n",VID,PID,ftdi_get_error_string(&__ftdic)); + exit(1); + } + + dir_state = LED_CONN|LED_RUN; + out_state = 0xFF & ~(LED_CONN|LED_RUN); + FTDI_BITBANG_SETUP(); + + success = ftdi_set_baudrate (&__ftdic, DAP_DEFAULT_SWJ_CLOCK/2); + if( success < 0){ + DEBUG("Could not set baudrate: %s\n",ftdi_get_error_string(&__ftdic)); + } + uint8_t foo; + success = ftdi_read_data(&__ftdic,&foo,1); +} + + +static __forceinline void FTDI_WRITE_OUT( ) { + int success; + if( out_state_buff_pos==0 ){ + DEBUG("buffer is empty %d \n",out_state_buff_pos); + return; + } + success = ftdi_write_data(&__ftdic,out_state_buff,out_state_buff_pos); + if( success<0 ){ + DEBUG("Could not write pins: %s\n",ftdi_get_error_string(&__ftdic)); + exit(1); + } + out_state_buff_pos=0; +} + +static __forceinline void FTDI_SUBMIT( ) { + out_state_buff[out_state_buff_pos] = out_state; + out_state_buff_pos++; + if( out_state_buff_pos>=BUFFER_SIZE ){ + DEBUG("FTDI bitbang-buffer overflow!\n"); + FTDI_WRITE_OUT( ); + } +} + +/** Setup JTAG I/O pins: TCK, TMS, TDI, TDO, nTRST, and nRESET. +Configures the DAP Hardware I/O pins for JTAG mode: + - TCK, TMS, TDI, nTRST, nRESET to output mode and set to high level. + - TDO to input mode. +*/ +static __inline void PORT_JTAG_SETUP (void) { + /* Initialize context for subsequent function calls */ + dir_state = LED_CONN|LED_RUN|TCK_SWCLK|TMS_SWDIO|TDI|nRESET;; + out_state = TCK_SWCLK | TMS_SWDIO | TDI | nTRST | nRESET; + FTDI_BITBANG_SETUP(); +} + + +/** Setup SWD I/O pins: SWCLK, SWDIO, and nRESET. +Configures the DAP Hardware I/O pins for Serial Wire Debug (SWD) mode: + - SWCLK, SWDIO, nRESET to output mode and set to default high level. + - TDI, TMS, nTRST to HighZ mode (pins are unused in SWD mode). +*/ +static __inline void PORT_SWD_SETUP (void) { + /* Initialize context for subsequent function calls */ + dir_state = LED_CONN|LED_RUN|TCK_SWCLK|TMS_SWDIO|nRESET; + out_state = TCK_SWCLK | TMS_SWDIO | nRESET; + FTDI_BITBANG_SETUP(); +} + +static __inline void FTDI_BEGIN_READ(){ + /* submit signal change buffer */ + FTDI_SUBMIT(); + FTDI_WRITE_OUT(); + /* flush read buffer */ + int success; + + success = ftdi_set_bitmode(&__ftdic, dir_state, BITMODE_SYNCBB ); + if( success<0 ){ + DEBUG("Could not change to sync. bitbang: %s\n",ftdi_get_error_string(&__ftdic)); + } + success = ftdi_usb_purge_rx_buffer(&__ftdic); + if( success<0 ){ + DEBUG("Could not flush buffer: %s\n",ftdi_get_error_string(&__ftdic)); + } + //memset ( pin_read_buff, 0, BUFFER_SIZE*sizeof(int) ); + is_in_read_mode = 1; +} + +static __inline void FTDI_END_READ(){ + int success, remaining; + uint32_t read_size; + read_size = remaining = out_state_buff_pos; + FTDI_SUBMIT(); + FTDI_WRITE_OUT(); + success = 0; + uint8_t *ptr = in_buff; + while( remaining ){ + success = ftdi_read_data(&__ftdic,ptr,remaining); + if( success<0 ){ + DEBUG("Error while read: %s\n",ftdi_get_error_string(&__ftdic)); + exit(1); + } + ptr+=success; + remaining-=success; + printf("try %d\n", success); + } + printf("Read %d/%d bytes\n",(int)(ptr-in_buff),read_size); + if( read_size!=success ){ + DEBUG("Not sufficient bytes read: %s\n",ftdi_get_error_string(&__ftdic)); + }else{ + DEBUG("Read %d bytes\n",read_size); + int i; + for(i=0;i> 1) & 0x55) ; + c = (c & 0x33) + ((c >> 2) & 0x33); + c = (c & 0x0F) + ((c >> 4) & 0x0F); + return c; +} + +/** SWDIO I/O pin: Get Input (used in SWD mode only). +\return Current status of the SWDIO DAP hardware I/O pin. +*/ +static __forceinline void PIN_SWDIO_IN (uint8_t *ptr,uint8_t bit){ + + if( ptr!=NULL ){ + DEBUG("setting read-to-pointer for pin reads!\n"); + read_slot = ptr; + if( bit_count(bit)==1 ){ + pin_read_mask=bit; + }else{ + pin_read_mask=1; + } + } + + /* correlate the read with the output buffer */ + pin_read_buff[pin_read_pos].pos = out_state_buff_pos; + pin_read_buff[pin_read_pos].bitmask = pin_read_mask; + + pin_read_mask = pin_read_mask<<1; + if( !pin_read_mask ){ + pin_read_mask = 1; + read_slot += 1; + } + + pin_read_buff[pin_read_pos].ptr = read_slot; + pin_read_pos++; + + if( pin_read_pos==BUFFER_SIZE ){ + DEBUG("read buffer overflow!\n"); + } + + +} + +/** SWDIO I/O pin: Set Output (used in SWD mode only). +\param bit Output value for the SWDIO DAP hardware I/O pin. +*/ +static __forceinline void PIN_SWDIO_OUT (uint32_t bit) { + PIN_SET(TMS_SWDIO,bit); +} + +/** SWDIO I/O pin: Switch to Output mode (used in SWD mode only). +Configure the SWDIO DAP hardware I/O pin to output mode. This function is +called prior \ref PIN_SWDIO_OUT function calls. +*/ +static __forceinline void PIN_SWDIO_OUT_ENABLE (void) { + /* SWD is changing DIO line to output, submit current IO state + and send it to FTDI*/ + DEBUG("SWDIO -> out\n"); + dir_state |= TMS_SWDIO; + int success = ftdi_set_bitmode(&__ftdic, dir_state, __ftdic.bitbang_mode ); + if( success<0 ){ + DEBUG("Could not change SWDIO to out: %s\n",ftdi_get_error_string(&__ftdic)); + } +} + +/** SWDIO I/O pin: Switch to Input mode (used in SWD mode only). +Configure the SWDIO DAP hardware I/O pin to input mode. This function is +called prior \ref PIN_SWDIO_IN function calls. +*/ +static __forceinline void PIN_SWDIO_OUT_DISABLE (void) { + /* SWD is changing DIO line to input, submit current IO state + and send it to FTDI */ + DEBUG("SWDIO -> in\n"); + dir_state &= ~TMS_SWDIO; + + int success = ftdi_set_bitmode(&__ftdic, dir_state, __ftdic.bitbang_mode ); + if( success<0 ){ + DEBUG("Could not change SWDIO to in: %s\n",ftdi_get_error_string(&__ftdic)); + } +} + + +// TDI Pin I/O --------------------------------------------- + +/** TDI I/O pin: Get Input. +\return Current status of the TDI DAP hardware I/O pin. +*/ +static __forceinline uint32_t PIN_TDI_IN (void) { + return PIN_IN(TDI); +} + +/** TDI I/O pin: Set Output. +\param bit Output value for the TDI DAP hardware I/O pin. +*/ +static __forceinline void PIN_TDI_OUT (uint32_t bit) { + PIN_SET(TDI,bit); +} + + +// TDO Pin I/O --------------------------------------------- + +/** TDO I/O pin: Get Input. +\return Current status of the TDO DAP hardware I/O pin. +*/ +static __forceinline uint32_t PIN_TDO_IN (void) { + return PIN_IN(TDO_SWO); +} + + +// nTRST Pin I/O ------------------------------------------- + +/** nTRST I/O pin: Get Input. +\return Current status of the nTRST DAP hardware I/O pin. +*/ +static __forceinline uint32_t PIN_nTRST_IN (void) { + return PIN_IN(nTRST); +} + +/** nTRST I/O pin: Set Output. +\param bit JTAG TRST Test Reset pin status: + - 0: issue a JTAG TRST Test Reset. + - 1: release JTAG TRST Test Reset. +*/ +static __forceinline void PIN_nTRST_OUT (uint32_t bit) { + PIN_SET(nTRST,bit); +} + +// nRESET Pin I/O------------------------------------------ + +/** nRESET I/O pin: Get Input. +\return Current status of the nRESET DAP hardware I/O pin. +*/ +static __forceinline uint32_t PIN_nRESET_IN (void) { + return PIN_IN(nRESET); +} + +/** nRESET I/O pin: Set Output. +\param bit target device hardware reset pin status: + - 0: issue a device hardware reset. + - 1: release device hardware reset. +*/ +static __forceinline void PIN_nRESET_OUT (uint32_t bit) { + PIN_SET(nRESET,bit); +} + +///@} + + +//************************************************************************************************** +/** +\defgroup DAP_Config_LEDs_gr CMSIS-DAP Hardware Status LEDs +\ingroup DAP_ConfigIO_gr +@{ + +CMSIS-DAP Hardware may provide LEDs that indicate the status of the CMSIS-DAP Debug Unit. + +It is recommended to provide the following LEDs for status indication: + - Connect LED: is active when the DAP hardware is connected to a debugger. + - Running LED: is active when the debugger has put the target device into running state. +*/ + +/** Debug Unit: Set status of Connected LED. +\param bit status of the Connect LED. + - 1: Connect LED ON: debugger is connected to CMSIS-DAP Debug Unit. + - 0: Connect LED OFF: debugger is not connected to CMSIS-DAP Debug Unit. +*/ +static __inline void LED_CONNECTED_OUT (uint32_t bit) { + PIN_SET(LED_CONN,bit); +} + +/** Debug Unit: Set status Target Running LED. +\param bit status of the Target Running LED. + - 1: Target Running LED ON: program execution in target started. + - 0: Target Running LED OFF: program execution in target stopped. +*/ +static __inline void LED_RUNNING_OUT (uint32_t bit) { + PIN_SET( LED_RUN,bit); +} + +///@} + + +//************************************************************************************************** +/** +\defgroup DAP_Config_Initialization_gr CMSIS-DAP Initialization +\ingroup DAP_ConfigIO_gr +@{ + +CMSIS-DAP Hardware I/O and LED Pins are initialized with the function \ref DAP_SETUP. +*/ + +/** Reset Target Device with custom specific I/O pin or command sequence. +This function allows the optional implementation of a device specific reset sequence. +It is called when the command \ref DAP_ResetTarget and is for example required +when a device needs a time-critical unlock sequence that enables the debug port. +\return 0 = no device specific reset sequence is implemented.\n + 1 = a device specific reset sequence is implemented. +*/ +static __inline uint32_t RESET_TARGET (void) { + return (0); // change to '1' when a device reset sequence is implemented +} + +///@} + + +#endif /* __DAP_CONFIG_H__ */ diff --git a/src/DAP_vendor.c b/src/DAP_vendor.c new file mode 100644 index 0000000..3109bd1 --- /dev/null +++ b/src/DAP_vendor.c @@ -0,0 +1,122 @@ +/**************************************************************************//** + * @file DAP_vendor.c + * @brief CMSIS-DAP Vendor Commands + * @version V1.00 + * @date 1. June 2012 + * + * @note + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * @par + * ARM Limited (ARM) is supplying this software for use with Cortex-M + * processor based microcontrollers. + * + * @par + * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. + * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + * + ******************************************************************************/ + +#include "DAP_config.h" +#include "DAP.h" + +//************************************************************************************************** +/** +\defgroup DAP_Vendor_Adapt_gr Adapt Vendor Commands +\ingroup DAP_Vendor_gr +@{ + +The file DAP_vendor.c provides template source code for extension of a Debug Unit with +Vendor Commands. Copy this file to the project folder of the Debug Unit and add the +file to the MDK-ARM project under the file group Configuration. +*/ + +/** Process DAP Vendor Command and prepare Response Data +\param request pointer to request data +\param response pointer to response data +\return number of bytes in Response Data +*/ + +#define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) +#define SWJ_CLOCK_CYCLE() \ + PIN_SWCLK_TCK_CLR(); \ + PIN_DELAY(); \ + PIN_SWCLK_TCK_SET(); \ + PIN_DELAY() + +uint32_t DAP_ProcessVendorCommand(uint8_t *request, uint8_t *response) { + uint32_t num = 0; + + switch (request[0]) { // first byte in request is Command ID + case ID_DAP_Vendor0: +#if 0 // example user command + *response++ = *request++; // copy Command ID + num++; // increment return count + if (*request == 1) { // when first command data byte is 1 + *response++ = 'U'; // send 'U' as response + num++; // increment return count + } +#endif + break; + + case ID_DAP_Vendor1: + response[0]=request[0]; + int i; + for(i=0;i<100;i++){ + PIN_SWCLK_TCK_CLR(); + PIN_DELAY(); + PIN_SWCLK_TCK_SET(); + PIN_DELAY(); + } + break; + case ID_DAP_Vendor2: + response[0]=request[0]; + uint8_t bit=0; + PIN_SWDIO_OUT_DISABLE(); + FTDI_BEGIN_READ(); + PIN_SWCLK_TCK_CLR(); + PIN_DELAY(); + PIN_SWDIO_IN(&bit,1); + PIN_SWCLK_TCK_SET(); + PIN_DELAY(); + PIN_SWDIO_OUT_ENABLE(); + FTDI_END_READ(); + break; + case ID_DAP_Vendor3: break; + case ID_DAP_Vendor4: break; + case ID_DAP_Vendor5: break; + case ID_DAP_Vendor6: break; + case ID_DAP_Vendor7: break; + case ID_DAP_Vendor8: break; + case ID_DAP_Vendor9: break; + case ID_DAP_Vendor10: break; + case ID_DAP_Vendor11: break; + case ID_DAP_Vendor12: break; + case ID_DAP_Vendor13: break; + case ID_DAP_Vendor14: break; + case ID_DAP_Vendor15: break; + case ID_DAP_Vendor16: break; + case ID_DAP_Vendor17: break; + case ID_DAP_Vendor18: break; + case ID_DAP_Vendor19: break; + case ID_DAP_Vendor20: break; + case ID_DAP_Vendor21: break; + case ID_DAP_Vendor22: break; + case ID_DAP_Vendor23: break; + case ID_DAP_Vendor24: break; + case ID_DAP_Vendor25: break; + case ID_DAP_Vendor26: break; + case ID_DAP_Vendor27: break; + case ID_DAP_Vendor28: break; + case ID_DAP_Vendor29: break; + case ID_DAP_Vendor30: break; + case ID_DAP_Vendor31: break; + } + + return (num); +} + +///@} diff --git a/src/Debug.h b/src/Debug.h new file mode 100644 index 0000000..53ba487 --- /dev/null +++ b/src/Debug.h @@ -0,0 +1,15 @@ +/* + * Debug.c + * + * Created on: 01.11.2014 + * Author: powertomato + */ + +#include + +#ifndef SRC_DEBUG_H_ +#define SRC_DEBUG_H_ + + #define DEBUG(format, ...) fprintf (stderr, format, ##__VA_ARGS__) + +#endif //SRC_DEBUG_H_ diff --git a/src/JTAG_DP.c b/src/JTAG_DP.c new file mode 100644 index 0000000..336ca3b --- /dev/null +++ b/src/JTAG_DP.c @@ -0,0 +1,365 @@ +/****************************************************************************** + * @file JTAG_DP.c + * @brief CMSIS-DAP JTAG DP I/O + * @version V1.00 + * @date 31. May 2012 + * + * @note + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * @par + * ARM Limited (ARM) is supplying this software for use with Cortex-M + * processor based microcontrollers. + * + * @par + * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. + * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + * + ******************************************************************************/ + +#include "DAP_config.h" +#include "DAP.h" + + +// JTAG Macros + +#define PIN_TCK_SET PIN_SWCLK_TCK_SET +#define PIN_TCK_CLR PIN_SWCLK_TCK_CLR +#define PIN_TMS_SET PIN_SWDIO_TMS_SET +#define PIN_TMS_CLR PIN_SWDIO_TMS_CLR + +#define JTAG_CYCLE_TCK() \ + PIN_TCK_CLR(); \ + PIN_DELAY(); \ + PIN_TCK_SET(); \ + PIN_DELAY() + +#define JTAG_CYCLE_TDI(tdi) \ + PIN_TDI_OUT(tdi); \ + PIN_TCK_CLR(); \ + PIN_DELAY(); \ + PIN_TCK_SET(); \ + PIN_DELAY() + +#define JTAG_CYCLE_TDO(tdo) \ + PIN_TCK_CLR(); \ + PIN_DELAY(); \ + tdo = PIN_TDO_IN(); \ + PIN_TCK_SET(); \ + PIN_DELAY() + +#define JTAG_CYCLE_TDIO(tdi,tdo) \ + PIN_TDI_OUT(tdi); \ + PIN_TCK_CLR(); \ + PIN_DELAY(); \ + tdo = PIN_TDO_IN(); \ + PIN_TCK_SET(); \ + PIN_DELAY() + +#define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) + + +#if (DAP_JTAG != 0) + + +// Generate JTAG Sequence +// info: sequence information +// tdi: pointer to TDI generated data +// tdo: pointer to TDO captured data +// return: none +void JTAG_Sequence (uint32_t info, uint8_t *tdi, uint8_t *tdo) { + uint32_t i_val; + uint32_t o_val; + uint32_t bit; + uint32_t n, k; + + n = info & JTAG_SEQUENCE_TCK; + if (n == 0) n = 64; + + if (info & JTAG_SEQUENCE_TMS) { + PIN_TMS_SET(); + } else { + PIN_TMS_CLR(); + } + + while (n) { + i_val = *tdi++; + o_val = 0; + for (k = 8; k && n; k--, n--) { + JTAG_CYCLE_TDIO(i_val, bit); + i_val >>= 1; + o_val >>= 1; + o_val |= bit << 7; + } + o_val >>= k; + if (info & JTAG_SEQUENCE_TDO) { + *tdo++ = o_val; + } + } +} + + +// JTAG Set IR +// ir: IR value +// return: none +#define JTAG_IR_Function(speed) /**/ \ +void JTAG_IR_##speed (uint32_t ir) { \ + uint32_t n; \ + \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Select-DR-Scan */ \ + JTAG_CYCLE_TCK(); /* Select-IR-Scan */ \ + PIN_TMS_CLR(); \ + JTAG_CYCLE_TCK(); /* Capture-IR */ \ + JTAG_CYCLE_TCK(); /* Shift-IR */ \ + \ + PIN_TDI_OUT(1); \ + for (n = DAP_Data.jtag_dev.ir_before[DAP_Data.jtag_dev.index]; n; n--) { \ + JTAG_CYCLE_TCK(); /* Bypass before data */ \ + } \ + for (n = DAP_Data.jtag_dev.ir_length[DAP_Data.jtag_dev.index] - 1; n; n--) { \ + JTAG_CYCLE_TDI(ir); /* Set IR bits (except last) */ \ + ir >>= 1; \ + } \ + n = DAP_Data.jtag_dev.ir_after[DAP_Data.jtag_dev.index]; \ + if (n) { \ + JTAG_CYCLE_TDI(ir); /* Set last IR bit */ \ + PIN_TDI_OUT(1); \ + for (--n; n; n--) { \ + JTAG_CYCLE_TCK(); /* Bypass after data */ \ + } \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Bypass & Exit1-IR */ \ + } else { \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TDI(ir); /* Set last IR bit & Exit1-IR */ \ + } \ + \ + JTAG_CYCLE_TCK(); /* Update-IR */ \ + PIN_TMS_CLR(); \ + JTAG_CYCLE_TCK(); /* Idle */ \ + PIN_TDI_OUT(1); \ +} + + +// JTAG Transfer I/O +// request: A[3:2] RnW APnDP +// data: DATA[31:0] +// return: ACK[2:0] +#define JTAG_TransferFunction(speed) /**/ \ +uint8_t JTAG_Transfer##speed (uint32_t request, uint32_t *data) { \ + uint32_t ack; \ + uint32_t bit; \ + uint32_t val; \ + uint32_t n; \ + \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Select-DR-Scan */ \ + PIN_TMS_CLR(); \ + JTAG_CYCLE_TCK(); /* Capture-DR */ \ + JTAG_CYCLE_TCK(); /* Shift-DR */ \ + \ + for (n = DAP_Data.jtag_dev.index; n; n--) { \ + JTAG_CYCLE_TCK(); /* Bypass before data */ \ + } \ + \ + JTAG_CYCLE_TDIO(request >> 1, bit); /* Set RnW, Get ACK.0 */ \ + ack = bit << 1; \ + JTAG_CYCLE_TDIO(request >> 2, bit); /* Set A2, Get ACK.1 */ \ + ack |= bit << 0; \ + JTAG_CYCLE_TDIO(request >> 3, bit); /* Set A3, Get ACK.2 */ \ + ack |= bit << 2; \ + \ + if (ack != DAP_TRANSFER_OK) { \ + /* Exit on error */ \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Exit1-DR */ \ + goto exit; \ + } \ + \ + if (request & DAP_TRANSFER_RnW) { \ + /* Read Transfer */ \ + val = 0; \ + for (n = 31; n; n--) { \ + JTAG_CYCLE_TDO(bit); /* Get D0..D30 */ \ + val |= bit << 31; \ + val >>= 1; \ + } \ + n = DAP_Data.jtag_dev.count - DAP_Data.jtag_dev.index - 1; \ + if (n) { \ + JTAG_CYCLE_TDO(bit); /* Get D31 */ \ + for (--n; n; n--) { \ + JTAG_CYCLE_TCK(); /* Bypass after data */ \ + } \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Bypass & Exit1-DR */ \ + } else { \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TDO(bit); /* Get D31 & Exit1-DR */ \ + } \ + val |= bit << 31; \ + if (data) *data = val; \ + } else { \ + /* Write Transfer */ \ + val = *data; \ + for (n = 31; n; n--) { \ + JTAG_CYCLE_TDI(val); /* Set D0..D30 */ \ + val >>= 1; \ + } \ + n = DAP_Data.jtag_dev.count - DAP_Data.jtag_dev.index - 1; \ + if (n) { \ + JTAG_CYCLE_TDI(val); /* Set D31 */ \ + for (--n; n; n--) { \ + JTAG_CYCLE_TCK(); /* Bypass after data */ \ + } \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TCK(); /* Bypass & Exit1-DR */ \ + } else { \ + PIN_TMS_SET(); \ + JTAG_CYCLE_TDI(val); /* Set D31 & Exit1-DR */ \ + } \ + } \ + \ +exit: \ + JTAG_CYCLE_TCK(); /* Update-DR */ \ + PIN_TMS_CLR(); \ + JTAG_CYCLE_TCK(); /* Idle */ \ + PIN_TDI_OUT(1); \ + \ + /* Idle cycles */ \ + n = DAP_Data.transfer.idle_cycles; \ + while (n--) { \ + JTAG_CYCLE_TCK(); /* Idle */ \ + } \ + \ + return (ack); \ +} + + +#undef PIN_DELAY +#define PIN_DELAY() PIN_DELAY_FAST() +JTAG_IR_Function(Fast); +JTAG_TransferFunction(Fast); + +#undef PIN_DELAY +#define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) +JTAG_IR_Function(Slow); +JTAG_TransferFunction(Slow); + + +// JTAG Read IDCODE register +// return: value read +uint32_t JTAG_ReadIDCode (void) { + uint32_t bit; + uint32_t val; + uint32_t n; + + PIN_TMS_SET(); + JTAG_CYCLE_TCK(); /* Select-DR-Scan */ + PIN_TMS_CLR(); + JTAG_CYCLE_TCK(); /* Capture-DR */ + JTAG_CYCLE_TCK(); /* Shift-DR */ + + for (n = DAP_Data.jtag_dev.index; n; n--) { + JTAG_CYCLE_TCK(); /* Bypass before data */ + } + + val = 0; + for (n = 31; n; n--) { + JTAG_CYCLE_TDO(bit); /* Get D0..D30 */ + val |= bit << 31; + val >>= 1; + } + PIN_TMS_SET(); + JTAG_CYCLE_TDO(bit); /* Get D31 & Exit1-DR */ + val |= bit << 31; + + JTAG_CYCLE_TCK(); /* Update-DR */ + PIN_TMS_CLR(); + JTAG_CYCLE_TCK(); /* Idle */ + + return (val); +} + + +// JTAG Write ABORT register +// data: value to write +// return: none +void JTAG_WriteAbort (uint32_t data) { + uint32_t n; + + PIN_TMS_SET(); + JTAG_CYCLE_TCK(); /* Select-DR-Scan */ + PIN_TMS_CLR(); + JTAG_CYCLE_TCK(); /* Capture-DR */ + JTAG_CYCLE_TCK(); /* Shift-DR */ + + for (n = DAP_Data.jtag_dev.index; n; n--) { + JTAG_CYCLE_TCK(); /* Bypass before data */ + } + + PIN_TDI_OUT(0); + JTAG_CYCLE_TCK(); /* Set RnW=0 (Write) */ + JTAG_CYCLE_TCK(); /* Set A2=0 */ + JTAG_CYCLE_TCK(); /* Set A3=0 */ + + for (n = 31; n; n--) { + JTAG_CYCLE_TDI(data); /* Set D0..D30 */ + data >>= 1; + } + n = DAP_Data.jtag_dev.count - DAP_Data.jtag_dev.index - 1; + if (n) { + JTAG_CYCLE_TDI(data); /* Set D31 */ + for (--n; n; n--) { + JTAG_CYCLE_TCK(); /* Bypass after data */ + } + PIN_TMS_SET(); + JTAG_CYCLE_TCK(); /* Bypass & Exit1-DR */ + } else { + PIN_TMS_SET(); + JTAG_CYCLE_TDI(data); /* Set D31 & Exit1-DR */ + } + + JTAG_CYCLE_TCK(); /* Update-DR */ + PIN_TMS_CLR(); + JTAG_CYCLE_TCK(); /* Idle */ + PIN_TDI_OUT(1); +} + + +// JTAG Set IR +// ir: IR value +// return: none +void JTAG_IR (uint32_t ir) { + if (DAP_Data.fast_clock) { + JTAG_IR_Fast(ir); + } else { + JTAG_IR_Slow(ir); + } +} + + +// JTAG Transfer I/O +// request: A[3:2] RnW APnDP +// data: DATA[31:0] +// return: ACK[2:0] +uint8_t JTAG_Transfer(uint8_t request, uint32_t *data) +{ + return JTAG_TransferSlow(request, data); +#if 0 //XXX JTAG transfer fast + if (DAP_Data.fast_clock) + { + return JTAG_TransferFast(request, data); + return JTAG_TransferSlow(request, data); + } else { + return JTAG_TransferSlow(request, data); + } +#endif + +} + + +#endif /* (DAP_JTAG != 0) */ diff --git a/src/SW_DP.c b/src/SW_DP.c new file mode 100644 index 0000000..3b09144 --- /dev/null +++ b/src/SW_DP.c @@ -0,0 +1,248 @@ +/****************************************************************************** + * @file SW_DP.c + * @brief CMSIS-DAP SW DP I/O + * @version V1.00 + * @date 31. May 2012 + * + * @note + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * @par + * ARM Limited (ARM) is supplying this software for use with Cortex-M + * processor based microcontrollers. + * + * @par + * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. + * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + * + ******************************************************************************/ + +#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(ptr,bit) \ + PIN_SWCLK_CLR(); \ + PIN_DELAY(); \ + PIN_SWDIO_IN(ptr,bit); \ + 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)) +void SWJ_Sequence (uint32_t count, uint8_t *data) +{ + uint8_t val; + uint8_t n; + + val = 0; + n = 0; + DEBUG("DATA:"); + while (count--) + { + if (n == 0) + { + val = *data++; + DEBUG(" %02X", val); + n = 8; + } + if (val & 1) + { + PIN_SWDIO_TMS_SET(); + } + else + { + PIN_SWDIO_TMS_CLR(); + } + SW_CLOCK_CYCLE(); + val >>= 1; + n--; + } + DEBUG("\n"); +} +#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) /**/ \ +uint8_t SWD_Transfer##speed (uint8_t request, uint32_t *data) { \ + uint8_t ack; \ + uint32_t bit; \ + uint8_t val[4]; \ + uint32_t parity; \ + \ + uint32_t n; \ + \ + /* Packet Request */ \ + parity = 0; \ + SW_WRITE_BIT(1); /* 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; \ + parity += bit; \ + SW_WRITE_BIT(parity); /* Parity Bit */ \ + SW_WRITE_BIT(0); /* Stop Bit */ \ + SW_WRITE_BIT(1); /* Park Bit */ \ + \ + /* Turnaround */ \ + PIN_SWDIO_OUT_DISABLE(); \ + for (n = DAP_Data.swd_conf.turnaround; n; n--) { \ + SW_CLOCK_CYCLE(); \ + } \ + \ + /* Acknowledge response */ \ + SW_READ_BIT(&ack,1); \ + SW_READ_BIT(NULL,0); \ + SW_READ_BIT(NULL,0); \ + FTDI_END_READ(); \ + \ + if (ack == DAP_TRANSFER_OK) { /* OK response */ \ + /* Data transfer */ \ + if (request & DAP_TRANSFER_RnW) { \ + /* Read data */ \ + memset( val, 0, 4); \ + parity = 0; \ + SW_READ_BIT(val,1); \ + for (n = 31; n; n--) { \ + SW_READ_BIT(NULL,0); /* Read RDATA[0:31] */ \ + } /*TODO calc parity */ \ + SW_READ_BIT((uint8_t*)&parity,1); /* Read parity bit */ \ + FTDI_END_READ(); \ + if ((parity ^ bit) & 1) { \ + ack = DAP_TRANSFER_ERROR; \ + } \ + if (data){ *data = val[0]<<24 | val[1]<<16 | val[2]<<8 | val[3]; } \ + /* 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 */ \ + uint32_t dat = *data; \ + parity = 0; \ + for (n = 32; n; n--) { \ + SW_WRITE_BIT(dat); /* Write WDATA[0:31] */ \ + parity += dat; \ + dat >>= 1; \ + } \ + SW_WRITE_BIT(parity); /* Write Parity Bit */ \ + } \ + /* Idle cycles */ \ + n = DAP_Data.transfer.idle_cycles; \ + if (n) { \ + PIN_SWDIO_OUT(0); \ + for (; n; n--) { \ + SW_CLOCK_CYCLE(); \ + } \ + } \ + PIN_SWDIO_OUT(1); \ + return (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) != 0)) { \ + for (n = 32+1; 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) == 0)) { \ + PIN_SWDIO_OUT(0); \ + for (n = 32+1; n; n--) { \ + SW_CLOCK_CYCLE(); /* Dummy Write WDATA[0:31] + Parity */ \ + } \ + } \ + PIN_SWDIO_OUT(1); \ + return (ack); \ + } \ + \ + /* Protocol error */ \ + for (n = DAP_Data.swd_conf.turnaround + 32 + 1; n; n--) { \ + SW_CLOCK_CYCLE(); /* Back off data phase */ \ + } \ + PIN_SWDIO_OUT(1); \ + return (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] +uint8_t SWD_Transfer(uint8_t request, uint32_t *data) +{ + return SWD_TransferSlow(request, data); +#if 0 // XXX SWD transer fast + if (DAP_Data.fast_clock) + { + return SWD_TransferFast(request, data); + } + else + { + return SWD_TransferSlow(request, data); + } +#endif +} + + +#endif /* (DAP_SWD != 0) */ diff --git a/src/Timer.c b/src/Timer.c new file mode 100644 index 0000000..df6484b --- /dev/null +++ b/src/Timer.c @@ -0,0 +1,51 @@ +/* + * Timer.c + * + * Created on: 01.11.2014 + * Author: powertomato + */ +#include "Timer.h" +#include "device.h" /* for NULL*/ + +static int64_t get_time() { + struct timeval tv; + gettimeofday(&tv,NULL); + return tv.tv_sec*(uint64_t)1000000+tv.tv_usec; +} + +static int64_t target_time = -1; +void TIMER_START (uint32_t usec) +{ + target_time = get_time()+usec; +} + +void TIMER_STOP (void) +{ + target_time = -1; +} + +uint32_t TIMER_EXPIRED (void) +{ + if(target_time==-1){ + return 0; + }else if( target_time <= get_time() ){ + return 1; + } + return 0; +} + +void Delayus(uint64_t us) { + TIMER_START(us); + // TODO usleep nanosleep + while( !TIMER_EXPIRED()); +} + +// Delay for specified time +// delay: delay time in ms +void Delayms(uint32_t delay) +{ + //delay *= (CPU_CLOCK / 1000 + (DELAY_SLOW_CYCLES-1)) / DELAY_SLOW_CYCLES; + //PIN_DELAY_SLOW(delay); + Delayus(delay*1000); +} + diff --git a/src/Timer.h b/src/Timer.h new file mode 100644 index 0000000..e6b6394 --- /dev/null +++ b/src/Timer.h @@ -0,0 +1,20 @@ +/* + * Timer.h + * + * Created on: 01.11.2014 + * Author: powertomato + */ + +#ifndef SRC_TIMER_H_ +#define SRC_TIMER_H_ + +#include +#include + +void TIMER_START (uint32_t usec); +void TIMER_STOP (void); +uint32_t TIMER_EXPIRED (void); +void Delayus(uint64_t us); +void Delayms(uint32_t delay); + +#endif /* SRC_TIMER_H_ */ diff --git a/src/device.h b/src/device.h new file mode 100644 index 0000000..b0cd264 --- /dev/null +++ b/src/device.h @@ -0,0 +1,20 @@ +/* + * device.h + * + * Created on: 01.11.2014 + * Author: powertomato + */ + +#ifndef SRC_DEVICE_H_ +#define SRC_DEVICE_H_ + +#define __weak +#ifdef __forceinline +#undef __forceinline +#endif +#define __forceinline __inline +#ifndef NULL +# define NULL ((void*)0) +#endif + +#endif /* SRC_DEVICE_H_ */ diff --git a/src/ftdi_vars.c b/src/ftdi_vars.c new file mode 100644 index 0000000..0b85c3e --- /dev/null +++ b/src/ftdi_vars.c @@ -0,0 +1,28 @@ +/* + * ftdi.c + * + * Created on: 01.11.2014 + * Author: powertomato + */ + + +#include "ftdi_vars.h" + +struct ftdi_context __ftdic; +uint16_t VID = 0x0403; +uint16_t PID = 0x6001; + +uint8_t out_state; +uint8_t dir_state; + +uint8_t out_state_buff[BUFFER_SIZE]; +int out_state_buff_pos = 0; + +uint8_t in_buff[BUFFER_SIZE]; +uint8_t *read_slot; + +red_pos_t pin_read_buff[BUFFER_SIZE]; +int pin_read_pos = 0; +uint8_t pin_read_mask = 1; + +int is_in_read_mode = 0; diff --git a/src/ftdi_vars.h b/src/ftdi_vars.h new file mode 100644 index 0000000..b256d0b --- /dev/null +++ b/src/ftdi_vars.h @@ -0,0 +1,50 @@ +/* + * ftdi.h + * + * Created on: 01.11.2014 + * Author: powertomato + */ + +#ifndef SRC_FTDI_VARS_H_ +#define SRC_FTDI_VARS_H_ + +#include + +#define BUFFER_SIZE (64*4) + +#define RI (1<<7) +#define DCD (1<<6) +#define DSR (1<<5) +#define DTR (1<<4) +#define CTS (1<<3) +#define RTS (1<<2) +#define RXD (1<<1) +#define TXD (1<<0) + +typedef struct { + uint8_t* ptr; + uint8_t bitmask; + int pos; +} red_pos_t; + + +extern struct ftdi_context __ftdic; +extern uint16_t VID; +extern uint16_t PID; + +extern uint8_t out_state; +extern uint8_t dir_state; +extern uint8_t out_state_buff[BUFFER_SIZE]; +extern int out_state_buff_pos; + +extern uint8_t in_buff[BUFFER_SIZE]; +extern uint8_t *read_slot; + +extern red_pos_t pin_read_buff[BUFFER_SIZE]; +extern int pin_read_pos; + +extern uint8_t pin_read_mask; +extern int is_in_read_mode; + + +#endif /* SRC_FTDI_VARS_H_ */ diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..d53c4aa --- /dev/null +++ b/src/main.c @@ -0,0 +1,55 @@ +/****************************************************************************** + * @file main.c + * @brief CMSIS-DAP Main module + * @version V1.00 + * @date 31. May 2012 + * + * @note + * Copyright (C) 2012 ARM Limited. All rights reserved. + * + * @par + * ARM Limited (ARM) is supplying this software for use with Cortex-M + * processor based microcontrollers. + * + * @par + * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED + * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. + * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER. + * + ******************************************************************************/ + +#include +#include "DAP_config.h" +#include "DAP.h" + +#include + + +extern void wait_for_client(void); +extern void process_data(void); +// Main program +int main (void) { + + DAP_Setup(); // DAP Setup + + //DAP_PACKET_COUNT + LED_CONNECTED_OUT(1); // Turn on Debugger Connected LED + LED_RUNNING_OUT(1); // Turn on Target Running LED + Delayms(500); // Wait for 500ms + LED_RUNNING_OUT(0); // Turn off Target Running LED + LED_CONNECTED_OUT(0); // Turn off Debugger Connected LED + printf("Wait client... "); + fflush(stdout); + wait_for_client(); + printf("connected\n"); + + while (1) { // Endless Loop + //usbd_hid_process(); // Process USB HID Data + // TODO thread sleep + //printf("process_data\n"); + process_data(); + //Delayms(1000); + } +} diff --git a/src/socket_ipc.c b/src/socket_ipc.c new file mode 100644 index 0000000..a2ffcff --- /dev/null +++ b/src/socket_ipc.c @@ -0,0 +1,171 @@ +/* + * socket_ipc.c + * + * Created on: 03.11.2014 + * Author: powertomato + */ + +#include +#include +#include "DAP_config.h" +#include "DAP.h" +#include +#include +#include +#include +#include +#include +#include + +static volatile uint8_t request_full; // Request Buffer Usage Flag +static volatile uint32_t request_head; // ReqBuff Buffer In Index +static volatile uint32_t request_tail; // ReqBuff Buffer Out Index + +static volatile uint8_t response_full; // Response Buffer Usage Flag +static volatile uint32_t response_head; // Response Buffer In Index +static volatile uint32_t response_tail; // Response Buffer Out Index + +static uint8_t request_buff[DAP_PACKET_COUNT][DAP_PACKET_SIZE]; // ReqBuff Buffer +static uint8_t response_buff[DAP_PACKET_COUNT][DAP_PACKET_SIZE]; // Response Buffer + +#ifdef __CYGWIN__ /*include oddness...*/ +typedef struct { + sa_family_t sin_family; /* Address family */ + in_port_t sin_port; /* Port number */ + struct in_addr sin_addr; /* Internet address */ + + /* Pad to size of `struct sockaddr'. */ + unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) + - sizeof(unsigned short int) - sizeof(struct in_addr)]; +} sockaddr_in_t; +#else +typedef struct sockaddr_in sockaddr_in_t; +#endif + +int sockfd, newsockfd, portno, clilen; +sockaddr_in_t serv_addr; +sockaddr_in_t cli_addr; + +// USB HID Callback: when system initializes +void wait_for_client(void) { + + request_full = 0; + request_head = 0; + request_tail = 0; + response_full = 0; + response_head = 0; + response_tail = 0; + + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + DEBUG("ERROR opening socket"); + exit(1); + } + bzero((char *) &serv_addr, sizeof(serv_addr)); + portno = 4777; + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(portno); + if (bind(sockfd, (struct sockaddr *) &serv_addr, + sizeof(serv_addr)) < 0){ + DEBUG("ERROR on binding"); + exit(1); + } + listen(sockfd,5); + + clilen = sizeof(cli_addr); + newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, (socklen_t*)&clilen); + if (newsockfd < 0){ + DEBUG("ERROR on accept"); + exit(1); + } + + int flags; + flags = fcntl(newsockfd, F_GETFL, 0); + if(flags < 0 ){ + flags = 0; + } + if( fcntl(newsockfd, F_SETFL, flags | O_NONBLOCK) < 0 ){ + DEBUG("ERROR seting non-blocking!\n"); + } +} + + +// USB HID Callback: when data needs to be prepared for the host +int write_response() { + if ((response_tail != response_head) || response_full) { + int n = write(newsockfd,response_buff[response_tail],DAP_PACKET_SIZE); + if (n != DAP_PACKET_SIZE){ + DEBUG("ERROR writing to socket"); + } + + // remove a response + response_tail = (response_tail+1) % DAP_PACKET_COUNT; + response_full = 0; + return (DAP_PACKET_SIZE); + } + return (0); +} + + +// USB HID Callback: when data is received from the host +void buffer_request(uint8_t *buff, int len) { + if (len == 0){ + return; + } + if (buff[0] == ID_DAP_TransferAbort) { + DAP_TransferAbort = 1; + return; + } + if (request_full) { + return; // Discard packet when buffer is full + } + // add a request + memcpy(request_buff[request_head], buff, len); + request_head++; + if (request_head == DAP_PACKET_COUNT) { + request_head = 0; + } + if (request_head == request_tail) { + request_full = 1; + } +} +// Process USB HID Data +void process_data(void) { + static uint8_t buff[DAP_PACKET_SIZE]; + static int buff_pos = 0; + + int n; + n = read(newsockfd,buff+buff_pos,DAP_PACKET_SIZE); + + if( n>0 ) { + buff_pos += n; + if( buff_pos==DAP_PACKET_SIZE ) { + buffer_request(buff,DAP_PACKET_SIZE); + buff_pos=0; + } + } + + // Process pending requests + if ((request_tail != request_head) || request_full) { + + // Process DAP Command and prepare response + DAP_ProcessCommand(request_buff[request_tail], response_buff[response_head]); + if( out_state_buff_pos != 0 ){ + FTDI_WRITE_OUT(); + } + + // remove a request + request_tail = (request_tail + 1) % DAP_PACKET_COUNT; + request_full = 0; + + // add a response + response_head = (response_head + 1) % DAP_PACKET_COUNT; + if (response_head == response_tail) { + response_full = 1; + } + write_response(); + } +} +