Dapper Miser implementation of CMSIS-DAP, MC HCK as SWD Adapter
Dapper Miser
In late 2013, I created a functional implementation of CMSIS-DAP that runs in a low cost ~$1 PIC16F1454 microcontroller.
My interest was seeing it deployed as a CMSIS-DAP debugger *integrated* into a low-cost hobbyist/educational ARM development board.
Hack-A-Day (the source of most link traffic here) mischaracterized it as a $1 standalone debugger.
It had a ridiculous Rube Goldberg (Heath Robinson) description of using a salvage USB cable.
At best, I think they "buried the lead"; at worst, it was click bait.
A variety of source code is available here and here,
http://sourceforge.net/u/majbthrd/profile/
but this does not include the Dapper Miser source code.
about CMSIS-DAP
In a (half-baked) attempt to discourage lots of proprietary debug pod implementations,
ARM published a "CMSIS-DAP" specification.
However, rather than make it an open standard that could be readily adopted by vendors,
said specification is bound by a EULA with onerous terms.
If there was something new or novel about the CMSIS-DAP specification,
I might be more sympathetic about the EULA.
However, it is not even a particularly well-thought out protocol API;
there is certainly nothing new or novel about it.
Practicing CMSIS-DAP could not possibly be inferred as a license for the ARM Debug Interface that CMSIS-DAP talks to;
moreover, that would be something already licensed from ARM by the target chip manufacturer.
(The EULA is seemingly akin to clamping down on the availability of sneakers/trainers in order to combat store theft.
The shoes may be worn by crooks, but they are also worn by legitimate store patrons.)
mbed (an ARM subdivision) has released incomplete source code for CMSIS-DAP that depends upon Keil
(another ARM subdivision) USB libraries which must be purchased separately.
Just as a proof of concept (and not optimized for speed or purpose),
over a weekend in 2014 I adapted said mbed code to run on the STM32F072
using the publicly available STMicro USB library. The source code is here.
http://dappermime.sourceforge.net/
The resultant negative consequence of ARM's cloaking CMSIS-DAP
in such an EULA was that the open source community (examples: here, here, and here)
fractured into a cornucopia of bespoke APIs incompatible with each other and development tools. What a pity.
Proof of concept: Open source ARM SWD debug and general purpose board
Erich of MCUonEclipse writes:
The Freescale FRDM boards are using a Kinetis K20 based circuit (see “OpenSDA on the Freedom KL25Z Board“):
However, that firmware is not open:
the K20 is secured and protected, so the firmware cannot be changed.
Newer Freescale FRDM boards like FRDM-K22F2 and FRDM-K64F
do have an open source bootloader and debug firmware (see “DOC-100720“).
So: take a Freescale Kinetis K20 ARM Cortex-M4, the open source bootloader and firmware,
shrink everything to the size of a Teensy board, add headers both to debug the K20
and an off-board microcontroller, and we have tiny board which can be used
as a standalone versatile microcontroller board:
usable for small projects or usable as debug probe.
Features and wish list:
- Universal, tiny, breadboard friendly which can be used by students for their own projects
and which can be used in courses and lab work. - Freescale Kinetis K20 device, ARM Cortex M4, running up to 50 MHz, powerful enough for most tasks
- 128 KByte FLASH, 16 KByte RAM
- USB connector (both power and connectivity)
- Optional battery power
- Optional real time clock
- Reset/User button
- LED
- Breadboard friendly pin out, all pins available on the outside
- SWD debug interface to debug the onboard K20
- Ability to debug off-board devices with OpenSDAv2
- Small size, around 40×25 mm (TBD)
- Low cost (TBD, less than $<20, depends on quantity)
To prove the concept, we used the FRDM-K20D50M board, added buffers/level shifter and an inverter,
hooked everything up to a SWD cable, loading the bootloader
and debug firmware, and we are able to use it as a debug probe
Self Hosted Toolchain: The MC HCK as SWD Adapter
I am happy to announce that we have a self-hosted toolchain:
The MC HCK can now act as SWD debug adapter for other MC HCKs,
without requiring any other external debug adapters or development boards.
The SWD interface is a debug interface, similar to JTAG;
however, it only requires two signal lines, and it is specific to ARM processors.
In the MC HCK toolchain, we use SWD to initially program the USB bootloader,
as well as to debug code. See below for a short example session.
With this, the MC HCK project has reached an important step on the way towards
creating an entirely free (FLOSS) and inexpensive modern microcontroller platform.
Bootstrapping yourself
Of course, if you are starting from zero, with only blank, self-built MC HCKs,
you will face a chicken-and-egg problem:
how to program the first MC HCK?
Head over to the wiki, which explains how to get started using other SWD programmer options,
such as the Bus Pirate or the Bus Blaster.
And thanks to our portable SWD bitbang code,
other development boards will also be able to bootstrap the MC HCK toolchain,
starting (very soon!) with an Arduino sketch.
Even though the MC HCK SWD adapter could be used to connect to other microcontrollers as well,
there is no specific code support yet.
But our open source friends have you covered:
check out Versaloon or the great Black Magic Probe, which directly presents as GDB target
and whose source helped a lot in developing the MC HCK SWD toolchain.
Dapper Miser Source Code
/* CMSIS-DAP Interface Firmware
* Copyright (c) 2009-2013 ARM Limited
*
* 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
*
* http://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.
*/ #ifndef __DAP_H__
#define __DAP_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 #include <stddef.h>
#include <stdint.h> // 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 (uint32_t request, uint32_t *data);
extern uint8_t SWD_Transfer (uint32_t request, uint32_t *data); extern void Delayms (uint32_t delay); 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 3 // Number of cycles for one iteration
static __inline void PIN_DELAY_SLOW (uint32_t delay) {
volatile int32_t count; count = delay;
while (--count);
} // Fixed delay for fast clock generation
#define DELAY_FAST_CYCLES 0 // Number of cycles
static __inline void PIN_DELAY_FAST (void) {
//__nop();
} #endif /* __DAP_H__ */
/*
Dapper Mime - an open-source CMSIS-DAP implementation HAL
for STM32F0xx2 this file is used by the mbed CMSIS-DAP routines
Copyright (C) 2014 Peter Lawrence Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/ #ifndef __DAP_CONFIG_H__
#define __DAP_CONFIG_H__ #include "stm32f0xx.h" /* we must manually ensure continuity with bcdDevice value in usbd_desc.c */
#define DAP_FW_VER "0.01" #define CPU_CLOCK 48000000 #define IO_PORT_WRITE_CYCLES 2 /* the Apache-license mbed CMSIS-DAP only provides source for SWD, so SWD-only is the only option */
#define DAP_SWD 1
#define DAP_JTAG 0
#define DAP_DEFAULT_PORT 1 /* SWD */ #define DAP_JTAG_DEV_CNT 0 #define DAP_DEFAULT_SWJ_CLOCK 100000 #define DAP_PACKET_SIZE 64 /* 64 is the max value for USB Full-Speed */
#define DAP_PACKET_COUNT 5 #define TARGET_DEVICE_FIXED 0 /* 1 = known, 0 = unknown */ #if TARGET_DEVICE_FIXED
#define TARGET_DEVICE_VENDOR ""
#define TARGET_DEVICE_NAME ""
#endif #define PIN_SWCLK_BITPOS (1)
#define PIN_SWCLK (1<<PIN_SWCLK_BITPOS)
#define PIN_SWDIO_BITPOS (0)
#define PIN_SWDIO (1<<PIN_SWDIO_BITPOS)
#define PIN_nRESET (0) /*
SWD functionality
*/ static __inline void PORT_SWD_SETUP (void)
{
GPIOA->BSRR = PIN_SWCLK | PIN_SWDIO;
GPIOA->MODER &= ~( (0x3 << (PIN_SWCLK_BITPOS << )) | (0x3 << (PIN_SWDIO_BITPOS << )) );
GPIOA->MODER |= ( (0x1 << (PIN_SWCLK_BITPOS << )) | (0x1 << (PIN_SWDIO_BITPOS << )) );
GPIOA->OTYPER &= ~( PIN_SWCLK | PIN_SWDIO );
GPIOA->OSPEEDR &= ~( (0x3 << (PIN_SWCLK_BITPOS << )) | (0x3 << (PIN_SWDIO_BITPOS << )) );
GPIOA->OSPEEDR |= ( (0x3 << (PIN_SWCLK_BITPOS << )) | (0x3 << (PIN_SWDIO_BITPOS << )) );
} static __inline void PORT_OFF (void)
{
GPIOA->BRR = PIN_SWCLK | PIN_SWDIO;
GPIOA->MODER &= ~( (0x3 << (PIN_SWCLK_BITPOS << )) | (0x3 << (PIN_SWDIO_BITPOS << )) );
} static __inline void PIN_SWCLK_TCK_SET (void)
{
GPIOA->BSRR = PIN_SWCLK;
} static __inline void PIN_SWCLK_TCK_CLR (void)
{
GPIOA->BRR = PIN_SWCLK;
} static __inline uint32_t PIN_SWDIO_TMS_IN (void)
{
return (GPIOA->IDR & PIN_SWDIO) ? 0x1 : 0x0;
} static __inline void PIN_SWDIO_TMS_SET (void)
{
GPIOA->BSRR = PIN_SWDIO;
} static __inline void PIN_SWDIO_TMS_CLR (void)
{
GPIOA->BRR = PIN_SWDIO;
} static __inline uint32_t PIN_SWDIO_IN (void)
{
return (GPIOA->IDR & PIN_SWDIO) ? 0x1 : 0x0;
} static __inline void PIN_SWDIO_OUT (uint32_t bit)
{
if (bit & )
GPIOA->BSRR = PIN_SWDIO;
else
GPIOA->BRR = PIN_SWDIO;
} static __inline void PIN_SWDIO_OUT_ENABLE (void)
{
GPIOA->MODER &= ~( (0x3 << (PIN_SWDIO_BITPOS << )) );
GPIOA->MODER |= ( (0x1 << (PIN_SWDIO_BITPOS << )) );
} static __inline void PIN_SWDIO_OUT_DISABLE (void)
{
GPIOA->MODER &= ~( (0x3 << (PIN_SWDIO_BITPOS << )) );
} /*
JTAG-only functionality (not used in this application)
*/ static __inline void PORT_JTAG_SETUP (void) {} static __inline uint32_t PIN_TDI_IN (void) { return ; } static __inline void PIN_TDI_OUT (uint32_t bit) {} static __inline uint32_t PIN_TDO_IN (void) { return ; } static __inline uint32_t PIN_nTRST_IN (void) { return ; } static __inline void PIN_nTRST_OUT (uint32_t bit) {} /*
other functionality not applicable to this application
*/
static __inline uint32_t PIN_SWCLK_TCK_IN (void) { return ; } static __inline uint32_t PIN_nRESET_IN (void) { return ; } static __inline void PIN_nRESET_OUT (uint32_t bit) {} static __inline void LED_CONNECTED_OUT (uint32_t bit) {} static __inline void LED_RUNNING_OUT (uint32_t bit) {} static __inline void DAP_SETUP (void) {} static __inline uint32_t RESET_TARGET (void) { return ; } #endif
/* CMSIS-DAP Interface Firmware
* Copyright (c) 2009-2013 ARM Limited
*
* 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
*
* http://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.
*/ #include <string.h>
#include "DAP_config.h"
#include "DAP.h" #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 // Clock Macros #define MAX_SWJ_CLOCK(delay_cycles) \
(CPU_CLOCK/ / (IO_PORT_WRITE_CYCLES + delay_cycles)) #define CLOCK_DELAY(swj_clock) \
((CPU_CLOCK/ / 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 = ; 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[] = ((DAP_SWD != ) ? ( << ) : ) |
((DAP_JTAG != ) ? ( << ) : );
length = ;
break;
case DAP_ID_PACKET_SIZE:
info[] = (uint8_t)(DAP_PACKET_SIZE >> );
info[] = (uint8_t)(DAP_PACKET_SIZE >> );
length = ;
break;
case DAP_ID_PACKET_COUNT:
info[] = DAP_PACKET_COUNT;
length = ;
break;
} return (length);
} // Timer Functions #if ((DAP_SWD != 0) || (DAP_JTAG != 0)) // Start Timer
static __inline void TIMER_START (uint32_t usec) {
SysTick->VAL = ;
SysTick->LOAD = usec * CPU_CLOCK/;
SysTick->CTRL = ( << SysTick_CTRL_ENABLE_Pos) |
( << SysTick_CTRL_CLKSOURCE_Pos);
} // Stop Timer
static __inline void TIMER_STOP (void) {
SysTick->CTRL = ;
} // Check if Timer expired
static __inline uint32_t TIMER_EXPIRED (void) {
return ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) ? : );
} #endif // Delay for specified time
// delay: delay time in ms
void Delayms(uint32_t delay) {
delay *= (CPU_CLOCK/ + (DELAY_SLOW_CYCLES-)) / DELAY_SLOW_CYCLES;
PIN_DELAY_SLOW(delay);
} // 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+) | (*(request+) << );
delay *= (CPU_CLOCK/ + (DELAY_SLOW_CYCLES-)) / DELAY_SLOW_CYCLES; PIN_DELAY_SLOW(delay); *response = DAP_OK;
return ();
} // 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:
LED_CONNECTED_OUT((*(request+) & ));
break;
case DAP_LED_TARGET_RUNNING:
LED_RUNNING_OUT((*(request+) & ));
break;
default:
*response = DAP_ERROR;
return ();
} *response = DAP_OK;
return ();
} // 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:
DAP_Data.debug_port = DAP_PORT_SWD;
PORT_SWD_SETUP();
break;
#endif
#if (DAP_JTAG != 0)
case DAP_PORT_JTAG:
DAP_Data.debug_port = DAP_PORT_JTAG;
PORT_JTAG_SETUP();
break;
#endif
default:
*response = DAP_PORT_DISABLED;
return ();
} *response = port;
return ();
} // 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) { DAP_Data.debug_port = DAP_PORT_DISABLED;
PORT_OFF(); *response = DAP_OK;
return ();
} // 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+) = RESET_TARGET();
*(response+) = DAP_OK;
return ();
} // 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) {
uint32_t value;
uint32_t select;
uint32_t wait; value = *(request+);
select = *(request+);
wait = (*(request+) << ) |
(*(request+) << ) |
(*(request+) << ) |
(*(request+) << ); if (select & ( << DAP_SWJ_SWCLK_TCK)) {
if (value & ( << DAP_SWJ_SWCLK_TCK)) {
PIN_SWCLK_TCK_SET();
} else {
PIN_SWCLK_TCK_CLR();
}
}
if (select & ( << DAP_SWJ_SWDIO_TMS)) {
if (value & ( << DAP_SWJ_SWDIO_TMS)) {
PIN_SWDIO_TMS_SET();
} else {
PIN_SWDIO_TMS_CLR();
}
}
if (select & ( << DAP_SWJ_TDI)) {
PIN_TDI_OUT(value >> DAP_SWJ_TDI);
}
if (select & ( << DAP_SWJ_nTRST)) {
PIN_nTRST_OUT(value >> DAP_SWJ_nTRST);
}
if (select & ( << DAP_SWJ_nRESET)) {
PIN_nRESET_OUT(value >> DAP_SWJ_nRESET);
} if (wait) {
if (wait > ) wait = ;
TIMER_START(wait);
do {
if (select & ( << DAP_SWJ_SWCLK_TCK)) {
if ((value >> DAP_SWJ_SWCLK_TCK) ^ PIN_SWCLK_TCK_IN()) continue;
}
if (select & ( << DAP_SWJ_SWDIO_TMS)) {
if ((value >> DAP_SWJ_SWDIO_TMS) ^ PIN_SWDIO_TMS_IN()) continue;
}
if (select & ( << DAP_SWJ_TDI)) {
if ((value >> DAP_SWJ_TDI) ^ PIN_TDI_IN()) continue;
}
if (select & ( << DAP_SWJ_nTRST)) {
if ((value >> DAP_SWJ_nTRST) ^ PIN_nTRST_IN()) continue;
}
if (select & ( << 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) |
(PIN_TDI_IN() << DAP_SWJ_TDI) |
(PIN_TDO_IN() << DAP_SWJ_TDO) |
(PIN_nTRST_IN() << DAP_SWJ_nTRST) |
(PIN_nRESET_IN() << DAP_SWJ_nRESET); *response = (uint8_t)value;
return ();
}
#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+) << ) |
(*(request+) << ) |
(*(request+) << ) |
(*(request+) << ); if (clock == ) {
*response = DAP_ERROR;
return ();
} if (clock >= MAX_SWJ_CLOCK(DELAY_FAST_CYCLES)) {
DAP_Data.fast_clock = ;
DAP_Data.clock_delay = ;
} else {
DAP_Data.fast_clock = ; delay = (CPU_CLOCK/ + (clock - )) / clock;
if (delay > IO_PORT_WRITE_CYCLES) {
delay -= IO_PORT_WRITE_CYCLES;
delay = (delay + (DELAY_SLOW_CYCLES - )) / DELAY_SLOW_CYCLES;
} else {
delay = ;
} DAP_Data.clock_delay = delay;
} *response = DAP_OK;
return ();
}
#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 == ) count = ; SWJ_Sequence(count, request); *response = DAP_OK;
return ();
}
#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) + ;
DAP_Data.swd_conf.data_phase = (value & 0x04) ? : ; *response = DAP_OK; return ();
}
#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; if (DAP_Data.debug_port != DAP_PORT_SWD) {
*response = DAP_ERROR;
return ();
} // Load data (Ignore DAP index)
data = (*(request+) << ) |
(*(request+) << ) |
(*(request+) << ) |
(*(request+) << ); // Write Abort register
SWD_Transfer(DP_ABORT, &data);
*response = DAP_OK; return ();
}
#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; *response++ = DAP_OK;
response_count = ; sequence_count = *request++;
while (sequence_count--) {
sequence_info = *request++;
JTAG_Sequence(sequence_info, request, response);
count = sequence_info & JTAG_SEQUENCE_TCK;
if (count == ) count = ;
count = (count + ) / ;
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; count = *request++;
DAP_Data.jtag_dev.count = count; bits = ;
for (n = ; 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 = ; n < count; n++) {
bits -= DAP_Data.jtag_dev.ir_length[n];
DAP_Data.jtag_dev.ir_after[n] = bits;
} *response = DAP_OK;
return ();
}
#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; if (DAP_Data.debug_port != DAP_PORT_JTAG) {
err:*response = DAP_ERROR;
return ();
} // 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+) = DAP_OK;
*(response+) = (uint8_t)(data >> );
*(response+) = (uint8_t)(data >> );
*(response+) = (uint8_t)(data >> );
*(response+) = (uint8_t)(data >> ); return (+);
}
#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; if (DAP_Data.debug_port != DAP_PORT_JTAG) {
err:*response = DAP_ERROR;
return ();
} // 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+) << ) |
(*(request+) << ) |
(*(request+) << ) |
(*(request+) << ); // Write Abort register
JTAG_WriteAbort(data);
*response = DAP_OK; return ();
}
#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+);
DAP_Data.transfer.retry_count = *(request+) | (*(request+) << );
DAP_Data.transfer.match_retry = *(request+) | (*(request+) << ); *response = DAP_OK; return ();
} // 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) {
uint32_t request_count;
uint32_t request_value;
uint32_t response_count;
uint32_t response_value;
uint8_t *response_head;
uint32_t post_read;
uint32_t check_write;
uint32_t match_value;
uint32_t match_retry;
uint32_t retry;
uint32_t data; response_count = ;
response_value = ;
response_head = response;
response += ; DAP_TransferAbort = ; post_read = ;
check_write = ; request++; // Ignore DAP index request_count = *request++;
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 = ;
}
if (response_value != DAP_TRANSFER_OK) break;
// Store previous AP data
*response++ = (uint8_t) data;
*response++ = (uint8_t)(data >> );
*response++ = (uint8_t)(data >> );
*response++ = (uint8_t)(data >> );
}
if (request_value & DAP_TRANSFER_MATCH_VALUE) {
// Read with value match
match_value = (*(request+) << ) |
(*(request+) << ) |
(*(request+) << ) |
(*(request+) << );
request += ;
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 == ) {
// 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 = ;
}
} 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 >> );
*response++ = (uint8_t)(data >> );
*response++ = (uint8_t)(data >> );
}
}
check_write = ;
} 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 >> );
*response++ = (uint8_t)(data >> );
*response++ = (uint8_t)(data >> );
post_read = ;
}
// Load data
data = (*(request+) << ) |
(*(request+) << ) |
(*(request+) << ) |
(*(request+) << );
request += ;
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 = ;
}
}
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 >> );
*response++ = (uint8_t)(data >> );
*response++ = (uint8_t)(data >> );
} 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+) = (uint8_t)response_count;
*(response_head+) = (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; response_count = ;
response_value = ;
response_head = response;
response += ; DAP_TransferAbort = ; ir = ;
post_read = ; // 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) == )) {
// 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 = ;
}
if (response_value != DAP_TRANSFER_OK) break;
// Store previous data
*response++ = (uint8_t) data;
*response++ = (uint8_t)(data >> );
*response++ = (uint8_t)(data >> );
*response++ = (uint8_t)(data >> );
}
if (request_value & DAP_TRANSFER_MATCH_VALUE) {
// Read with value match
match_value = (*(request+) << ) |
(*(request+) << ) |
(*(request+) << ) |
(*(request+) << );
request += ;
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 == ) {
// 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 = ;
}
}
} 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 >> );
*response++ = (uint8_t)(data >> );
*response++ = (uint8_t)(data >> );
post_read = ;
}
// Load data
data = (*(request+) << ) |
(*(request+) << ) |
(*(request+) << ) |
(*(request+) << );
request += ;
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 >> );
*response++ = (uint8_t)(data >> );
*response++ = (uint8_t)(data >> );
} 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+) = (uint8_t)response_count;
*(response_head+) = (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; response_count = ;
response_value = ;
response_head = response;
response += ; DAP_TransferAbort = ; request++; // Ignore DAP index request_count = *request | (*(request+) << );
request += ;
if (request_count == ) 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 == ) && (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 >> );
*response++ = (uint8_t)(data >> );
*response++ = (uint8_t)(data >> );
response_count++;
}
} else {
// Write register block
while (request_count--) {
// Load data
data = (*(request+) << ) |
(*(request+) << ) |
(*(request+) << ) |
(*(request+) << );
request += ;
// 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+) = (uint8_t)(response_count >> );
*(response_head+) = (uint8_t)(response_count >> );
*(response_head+) = (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; response_count = ;
response_value = ;
response_head = response;
response += ; DAP_TransferAbort = ; // 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+) << );
request += ;
if (request_count == ) 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 == ) {
// 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 >> );
*response++ = (uint8_t)(data >> );
*response++ = (uint8_t)(data >> );
response_count++;
}
} else {
// Write register block
while (request_count--) {
// Load data
data = (*(request+) << ) |
(*(request+) << ) |
(*(request+) << ) |
(*(request+) << );
request += ;
// 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+) = (uint8_t)(response_count >> );
*(response_head+) = (uint8_t)(response_count >> );
*(response_head+) = (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
uint32_t DAP_ProcessVendorCommand(uint8_t *request, uint8_t *response) {
*response = ID_DAP_Invalid;
return ();
} // 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+);
*response = num;
return ( + 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 ();
#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 ();
#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 ();
#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+) = ; // Response count
*(response+) = ; // Response value
num = ;
}
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+) = ; // Response count [7:0]
*(response+) = ; // Response count[15:8]
*(response+) = ; // Response value
num = ;
}
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 ();
}
break; default:
*(response-) = ID_DAP_Invalid;
return ();
} return ( + num);
} // Setup DAP
void DAP_Setup(void) {
// Default settings (only non-zero values)
DAP_Data.debug_port = DAP_PORT_DISABLED;
//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 = ;
//DAP_Data.transfer.match_retry = 0;
//DAP_Data.transfer.match_mask = 0x000000;
#if (DAP_SWD != 0)
DAP_Data.swd_conf.turnaround = ;
//DAP_Data.swd_conf.data_phase = 0;
#endif
#if (DAP_JTAG != 0)
//DAP_Data.jtag_dev.count = 0;
#endif DAP_SETUP(); // Device specific setup
}
/* CMSIS-DAP Interface Firmware
* Copyright (c) 2009-2013 ARM Limited
*
* 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
*
* http://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.
*/ #include "DAP_config.h"
#include "DAP.h" // SW Macros #define PIN_SWCLK_SET PIN_SWCLK_TCK_SET
#define PIN_SWCLK_CLR PIN_SWCLK_TCK_CLR #define SW_CLOCK_CYCLE() \
PIN_SWCLK_CLR(); \
PIN_DELAY(); \
PIN_SWCLK_SET(); \
PIN_DELAY() #define SW_WRITE_BIT(bit) \
PIN_SWDIO_OUT(bit); \
PIN_SWCLK_CLR(); \
PIN_DELAY(); \
PIN_SWCLK_SET(); \
PIN_DELAY() #define SW_READ_BIT(bit) \
PIN_SWCLK_CLR(); \
PIN_DELAY(); \
bit = PIN_SWDIO_IN(); \
PIN_SWCLK_SET(); \
PIN_DELAY() #define PIN_DELAY() PIN_DELAY_SLOW(DAP_Data.clock_delay) // Generate SWJ Sequence
// count: sequence bit count
// data: pointer to sequence bit data
// return: none
#if ((DAP_SWD != 0) || (DAP_JTAG != 0))
void SWJ_Sequence (uint32_t count, uint8_t *data) {
uint32_t val;
uint32_t n; val = ;
n = ;
while (count--) {
if (n == ) {
val = *data++;
n = ;
}
if (val & ) {
PIN_SWDIO_TMS_SET();
} else {
PIN_SWDIO_TMS_CLR();
}
SW_CLOCK_CYCLE();
val >>= ;
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 (uint32_t request, uint32_t *data) { \
uint32_t ack; \
uint32_t bit; \
uint32_t val; \
uint32_t parity; \
\
uint32_t n; \
\
/* Packet Request */ \
parity = ; \
SW_WRITE_BIT(); /* Start Bit */ \
bit = request >> ; \
SW_WRITE_BIT(bit); /* APnDP Bit */ \
parity += bit; \
bit = request >> ; \
SW_WRITE_BIT(bit); /* RnW Bit */ \
parity += bit; \
bit = request >> ; \
SW_WRITE_BIT(bit); /* A2 Bit */ \
parity += bit; \
bit = request >> ; \
SW_WRITE_BIT(bit); /* A3 Bit */ \
parity += bit; \
SW_WRITE_BIT(parity); /* Parity Bit */ \
SW_WRITE_BIT(); /* Stop Bit */ \
SW_WRITE_BIT(); /* Park Bit */ \
\
/* Turnaround */ \
PIN_SWDIO_OUT_DISABLE(); \
for (n = DAP_Data.swd_conf.turnaround; n; n--) { \
SW_CLOCK_CYCLE(); \
} \
\
/* Acknowledge response */ \
SW_READ_BIT(bit); \
ack = bit << ; \
SW_READ_BIT(bit); \
ack |= bit << ; \
SW_READ_BIT(bit); \
ack |= bit << ; \
\
if (ack == DAP_TRANSFER_OK) { /* OK response */ \
/* Data transfer */ \
if (request & DAP_TRANSFER_RnW) { \
/* Read data */ \
val = ; \
parity = ; \
for (n = ; n; n--) { \
SW_READ_BIT(bit); /* Read RDATA[0:31] */ \
parity += bit; \
val >>= ; \
val |= bit << ; \
} \
SW_READ_BIT(bit); /* Read Parity */ \
if ((parity ^ bit) & ) { \
ack = DAP_TRANSFER_ERROR; \
} \
if (data) *data = val; \
/* Turnaround */ \
for (n = DAP_Data.swd_conf.turnaround; n; n--) { \
SW_CLOCK_CYCLE(); \
} \
PIN_SWDIO_OUT_ENABLE(); \
} else { \
/* Turnaround */ \
for (n = DAP_Data.swd_conf.turnaround; n; n--) { \
SW_CLOCK_CYCLE(); \
} \
PIN_SWDIO_OUT_ENABLE(); \
/* Write data */ \
val = *data; \
parity = ; \
for (n = ; n; n--) { \
SW_WRITE_BIT(val); /* Write WDATA[0:31] */ \
parity += val; \
val >>= ; \
} \
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(); \
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) != )) { \
for (n = +; 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) == )) { \
PIN_SWDIO_OUT(); \
for (n = +; n; n--) { \
SW_CLOCK_CYCLE(); /* Dummy Write WDATA[0:31] + Parity */ \
} \
} \
PIN_SWDIO_OUT(); \
return (ack); \
} \
\
/* Protocol error */ \
for (n = DAP_Data.swd_conf.turnaround + + ; n; n--) { \
SW_CLOCK_CYCLE(); /* Back off data phase */ \
} \
PIN_SWDIO_OUT(); \
return (ack); \
} // SW_CLOCK_SYCLE : SWCLK=0, Delay, SWCLK=1, Delay
// After Transfer : SWCLK=1, SWDIO=1
#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) */
#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() /* OK response ****************************************************************/
// data_phase : read : Read RDATA[0:31] + Parity, Turnaround, Idle cycles
// data_phase : write : Turnaround, Write WDATA[0:31] + Parity, Idle cycles /* WAIT or FAULT response *****************************************************/
// data_phase : read : Dummy Read RDATA[0:31] + Parity, Turnaround
// data_phase : write : Turnaround, Dummy Write WDATA[0:31] + Parity /* Protocol error *************************************************************/
// turnaround, DATA, Parity uint8_t SWD_Transfer( uint32_t request, uint32_t *data )
{
uint32_t ack;
uint32_t bit;
uint32_t val;
uint32_t parity; uint32_t n; /* Packet Request */
parity = ;
SW_WRITE_BIT( ); /* Start Bit */
bit = request >> ;
SW_WRITE_BIT( bit ); /* APnDP Bit */
parity += bit;
bit = request >> ;
SW_WRITE_BIT( bit ); /* RnW Bit */
parity += bit;
bit = request >> ;
SW_WRITE_BIT( bit ); /* A2 Bit */
parity += bit;
bit = request >> ;
SW_WRITE_BIT( bit ); /* A3 Bit */
parity += bit;
SW_WRITE_BIT( parity ); /* Parity Bit */
SW_WRITE_BIT( ); /* Stop Bit */
SW_WRITE_BIT( ); /* Park Bit */ /* Turnaround : 1..N Cycles */
PIN_SWDIO_OUT_DISABLE( );
for ( n = DAP_Data.swd_conf.turnaround; n; n-- )
{
SW_CLOCK_CYCLE( )
;
} /* Acknowledge response */
SW_READ_BIT( bit );
ack = bit << ;
SW_READ_BIT( bit );
ack |= bit << ;
SW_READ_BIT( bit );
ack |= bit << ; if ( ack == DAP_TRANSFER_OK ) /* OK response ********************************/
{
/* Data transfer */
if ( request & DAP_TRANSFER_RnW ) /* Read data ****************************/
{
val = ;
parity = ;
for ( n = ; n; n-- ) /* Read RDATA[0:31] */
{
SW_READ_BIT( bit );
parity += bit;
val >>= ;
val |= bit << ;
} SW_READ_BIT( bit ); /* Read Parity */ if ( ( parity ^ bit ) & )
{
ack = DAP_TRANSFER_ERROR;
} if ( data )
*data = val; for ( n = DAP_Data.swd_conf.turnaround; n; n-- ) /* Turnaround */
{
SW_CLOCK_CYCLE( )
;
} PIN_SWDIO_OUT_ENABLE( );
}
else /* Write data ********************************************************/
{
for ( n = DAP_Data.swd_conf.turnaround; n; n-- ) /* Turnaround */
{
SW_CLOCK_CYCLE( )
;
} PIN_SWDIO_OUT_ENABLE( ); val = *data;
parity = ;
for ( n = ; n; n-- ) /* Write WDATA[0:31] */
{
SW_WRITE_BIT( val );
parity += val;
val >>= ;
} SW_WRITE_BIT( parity ); /* Write Parity Bit */ } // if ( request & DAP_TRANSFER_RnW ) /* Read data */ else /* Write data */ /* Idle cycles */
n = DAP_Data.transfer.idle_cycles;
if ( n )
{
PIN_SWDIO_OUT( );
for ( ; n; n-- )
{
SW_CLOCK_CYCLE( )
;
}
} PIN_SWDIO_OUT( );
return ( ack );
} // if ( ack == DAP_TRANSFER_OK ) /* OK response ***************************/ /* WAIT or FAULT response ***************************************************/
// data_phase : read : Dummy Read RDATA[0:31] + Parity, Turnaround
// data_phase : write : Turnaround, Dummy Write WDATA[0:31] + Parity
if ( ( ack == DAP_TRANSFER_WAIT ) || ( ack == DAP_TRANSFER_FAULT ) )
{
if ( DAP_Data.swd_conf.data_phase
&& ( ( request & DAP_TRANSFER_RnW ) != ) )
{
for ( n = + ; n; n-- ) /* Dummy Read RDATA[0:31] + Parity */
{
SW_CLOCK_CYCLE( )
;
}
} /* 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 ) == ) )
{
PIN_SWDIO_OUT( );
for ( n = + ; n; n-- ) /* Dummy Write WDATA[0:31] + Parity */
{
SW_CLOCK_CYCLE( )
;
}
} PIN_SWDIO_OUT( );
return ( ack );
} /* Protocol error : turnaround, DATA, Parity ********************************/
//
for ( n = DAP_Data.swd_conf.turnaround + + ; n; n-- )
{
SW_CLOCK_CYCLE( )
; /* Back off data phase */
} PIN_SWDIO_OUT( );
return ( ack );
}
Dapper Miser implementation of CMSIS-DAP, MC HCK as SWD Adapter的更多相关文章
- cmsis dap interface firmware
cmsis dap interface firmware The source code of the mbed HDK (tools + libraries) is available in thi ...
- STM32开发笔记之——CMSIS DAP
都说开发stm32都是使用kail iar+jatg/swd的方式,然而arm公司已经开发出了CMSIS DAP的开源下载工具,全称是CoreSight Debug Access Port,网络上有大 ...
- STM32CubeIDE下载安装-GPIO基本配置操作-Debug调试(基于CMSIS DAP Debug)
1.在ST官网下载STM32CubeIDE而不是STM32CubeMX,并且STM32CubeIDE是免费的.(STM32CubeIDE不支持中文路径,不然编译会出错) 2.如果你用的是keil开发环 ...
- SWD接口:探索&泄密&延伸
http://bbs.21ic.com/icview-871133-1-1.html 文买了个JLINKV9,以为神器,拿到手发现根本不是,完全没必要替换V8,想自己做个另类的调试器,当然想只是想而已 ...
- Booting dircetly into Redlink FW from flash
Booting dircetly into Redlink FW from flash Hello, the usual way to use the Redlink FW is a two-step ...
- ARM JTAG 信号 RTCK 应该如何处理?
用户在调试内嵌可综合内核的 CPU 如 ARM7TDMI-S 时,需要通过打开仿真器的自适应时钟功能. 此时,ARM仿真器根据 RTCK 时钟信号的频率,产生可用于 CPU 内核当前时钟主频的最快的 ...
- Keil debugging techniques and alternative printf (SWO function)
One of the basic needs of the embedded software development through the terminal to output debugging ...
- Serial Wire Debug (SWD) Interface -- PSoc5
PSoC 5 supports programming through the serial wire debug (SWD) interface. There are two signals in ...
- CMSIS-DAP仿真器_学习(转载)
先给大家普及一下,哈哈.CMSIS-DAP仿真器,是ARM官方做的开源仿真器,没有版权,自由制作.官方给的源代码,使用的是NXP的单片机LPC4320做的.这个源代码,只要你安装了KEIL5,就可以找 ...
随机推荐
- 第12月第15天 mysqlx boost reswift
1. INSTALL PLUGIN mysqlx SONAME 'mysqlx.so' https://yq.aliyun.com/articles/38288 2. boost boost::sha ...
- [转]perf + 火焰图分析程序性能
1.perf命令简要介绍 性能调优时,我们通常需要分析查找到程序百分比高的热点代码片段,这便需要使用 perf record 记录单个函数级别的统计信息,并使用 perf report 来显示统计结果 ...
- C++ socket 网络编程 简单聊天室
操作系统里的进程通讯方式有6种:(有名/匿名)管道.信号.消息队列.信号量.内存(最快).套接字(最常用),这里我们来介绍用socket来实现进程通讯. 1.简单实现一个单向发送与接收 这是套接字的工 ...
- 大数据系列之数据仓库Hive命令使用及JDBC连接
Hive系列博文,持续更新~~~ 大数据系列之数据仓库Hive原理 大数据系列之数据仓库Hive安装 大数据系列之数据仓库Hive中分区Partition如何使用 大数据系列之数据仓库Hive命令使用 ...
- ubuntu 安装(install) pwntcha[一个做"验证码识别"的开源程序]
一.安装 1. sudo apt-get install libsdl1.2-dev libsdl1.2debian sudo apt-get install libsdl1.2-dev(比较大,10 ...
- tomcat报错:java.net.SocketException: Permission denied["http-nio-80"]
tomcat报错:java.net.SocketException: Permission denied["http-nio-80"] 问题:使用非root账户tomcat启动to ...
- wordpress配置通过IP直接访问及apache的配置
wordpress配置通过IP直接访问 环境: 操作系统:centos6.5 yum安装lamp环境: yum -y install mysql mysql-server php php-mysql ...
- MYSQL 添加外键报错
2014年6月16日 10:48:51 出错的部分提示摘录: #1452 - Cannot add or update a child row: a foreign key constraint fa ...
- 解除IIS配置节锁定
C:\windows\system32\inetsrv\appcmd unlock config -section:system.webServer/modules
- CI框架中自带的加密解密如何应用
首先我们找到配置文件application/config/config.php ,找到如下代码: ? 1 $config['encryption_key'] = "YOUR KEY&quo ...