DAPLink (CMSIS-DAP) porting to Artery AT32F425, WCH CH32V203 and WCH CH32V305.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

1092 lines
24 KiB

/**
* @file SWDd_host.c
* @brief Host driver for accessing the DAP
*/
#include "swd_host.h"
#include "DAP_config.h"
#include "DAP.h"
#include "debug_cm.h"
uint32_t Flash_Page_Size = 4096;
extern uint32_t Flash_Page_Size;
#define NVIC_Addr (0xe000e000)
#define DBG_Addr (0xe000edf0)
// AP CSW register, base value
#define CSW_VALUE (CSW_RESERVED | CSW_MSTRDBG | CSW_HPROT | CSW_DBGSTAT | CSW_SADDRINC)
// SWD register access
#define SWD_REG_AP (1)
#define SWD_REG_DP (0)
#define SWD_REG_R (1<<1)
#define SWD_REG_W (0<<1)
#define SWD_REG_ADR(a) (a & 0x0c)
#define DCRDR 0xE000EDF8
#define DCRSR 0xE000EDF4
#define DHCSR 0xE000EDF0
#define REGWnR (1 << 16)
#define MAX_SWD_RETRY 10
#define MAX_TIMEOUT 1000000 // Timeout for syscalls on target
typedef struct {
uint32_t select;
uint32_t csw;
} DAP_STATE;
typedef struct {
uint32_t r[16];
uint32_t xpsr;
} DEBUG_STATE;
static DAP_STATE dap_state;
static uint8_t swd_read_core_register(uint32_t n, uint32_t *val);
static uint8_t swd_write_core_register(uint32_t n, uint32_t val);
void delaymS(uint32_t ms)
{
uint32_t cnt = SystemCoreClock/4/1000 * ms;
for(uint32_t i = 0; i < cnt; i++) __NOP();
}
static void int2array(uint8_t *res, uint32_t data, uint8_t len)
{
uint8_t i = 0;
for(i = 0; i < len; i++) {
res[i] = (data >> 8 * i) & 0xFF;
}
}
static uint8_t swd_transfer_retry(uint32_t req, uint32_t *data)
{
uint8_t i, ack;
for (i = 0; i < MAX_SWD_RETRY; i++) {
ack = SWD_Transfer(req, data);
if (ack != DAP_TRANSFER_WAIT) {
return ack;
}
}
return ack;
}
uint8_t swd_init(void)
{
DAP_Setup();
PORT_SWD_SETUP();
return 1;
}
uint8_t swd_off(void)
{
PORT_OFF();
return 1;
}
// Read debug port register.
uint8_t swd_read_dp(uint8_t adr, uint32_t *val)
{
uint32_t tmp_in;
uint8_t tmp_out[4];
uint8_t ack;
uint32_t tmp;
tmp_in = SWD_REG_DP | SWD_REG_R | SWD_REG_ADR(adr);
ack = swd_transfer_retry(tmp_in, (uint32_t *)tmp_out);
*val = 0;
tmp = tmp_out[3];
*val |= (tmp << 24);
tmp = tmp_out[2];
*val |= (tmp << 16);
tmp = tmp_out[1];
*val |= (tmp << 8);
tmp = tmp_out[0];
*val |= (tmp << 0);
return (ack == 0x01);
}
// Write debug port register
uint8_t swd_write_dp(uint8_t adr, uint32_t val)
{
uint32_t req;
uint8_t data[4];
uint8_t ack;
switch (adr) {
case DP_SELECT:
if (dap_state.select == val) {
return 1;
}
dap_state.select = val;
break;
default:
break;
}
req = SWD_REG_DP | SWD_REG_W | SWD_REG_ADR(adr);
int2array(data, val, 4);
ack = swd_transfer_retry(req, (uint32_t *)data);
return (ack == 0x01);
}
// Read access port register.
uint8_t swd_read_ap(uint32_t adr, uint32_t *val)
{
uint8_t tmp_in, ack;
uint8_t tmp_out[4];
uint32_t tmp;
uint32_t apsel = adr & 0xff000000;
uint32_t bank_sel = adr & APBANKSEL;
if (!swd_write_dp(DP_SELECT, apsel | bank_sel)) {
return 0;
}
tmp_in = SWD_REG_AP | SWD_REG_R | SWD_REG_ADR(adr);
// first dummy read
swd_transfer_retry(tmp_in, (uint32_t *)tmp_out);
ack = swd_transfer_retry(tmp_in, (uint32_t *)tmp_out);
*val = 0;
tmp = tmp_out[3];
*val |= (tmp << 24);
tmp = tmp_out[2];
*val |= (tmp << 16);
tmp = tmp_out[1];
*val |= (tmp << 8);
tmp = tmp_out[0];
*val |= (tmp << 0);
return (ack == 0x01);
}
// Write access port register
uint8_t swd_write_ap(uint32_t adr, uint32_t val)
{
uint8_t data[4];
uint8_t req, ack;
uint32_t apsel = adr & 0xff000000;
uint32_t bank_sel = adr & APBANKSEL;
if (!swd_write_dp(DP_SELECT, apsel | bank_sel)) {
return 0;
}
switch (adr) {
case AP_CSW:
if (dap_state.csw == val) {
return 1;
}
dap_state.csw = val;
break;
default:
break;
}
req = SWD_REG_AP | SWD_REG_W | SWD_REG_ADR(adr);
int2array(data, val, 4);
if (swd_transfer_retry(req, (uint32_t *)data) != 0x01) {
return 0;
}
req = SWD_REG_DP | SWD_REG_R | SWD_REG_ADR(DP_RDBUFF);
ack = swd_transfer_retry(req, NULL);
return (ack == 0x01);
}
// Write 32-bit word aligned values to target memory using address auto-increment.
// size is in bytes.
static uint8_t swd_write_block(uint32_t address, uint8_t *data, uint32_t size)
{
uint8_t tmp_in[4], req;
uint32_t size_in_words;
uint32_t i, ack;
if (size == 0) {
return 0;
}
size_in_words = size / 4;
// CSW register
if (!swd_write_ap(AP_CSW, CSW_VALUE | CSW_SIZE32)) {
return 0;
}
// TAR write
req = SWD_REG_AP | SWD_REG_W | (1 << 2);
int2array(tmp_in, address, 4);
if (swd_transfer_retry(req, (uint32_t *)tmp_in) != 0x01) {
return 0;
}
// DRW write
req = SWD_REG_AP | SWD_REG_W | (3 << 2);
for (i = 0; i < size_in_words; i++) {
if (swd_transfer_retry(req, (uint32_t *)data) != 0x01) {
return 0;
}
data += 4;
}
// dummy read
req = SWD_REG_DP | SWD_REG_R | SWD_REG_ADR(DP_RDBUFF);
ack = swd_transfer_retry(req, NULL);
return (ack == 0x01);
}
// Read 32-bit word aligned values from target memory using address auto-increment.
// size is in bytes.
static uint8_t swd_read_block(uint32_t address, uint8_t *data, uint32_t size)
{
uint8_t tmp_in[4], req, ack;
uint32_t size_in_words;
uint32_t i;
if (size == 0) {
return 0;
}
size_in_words = size / 4;
if (!swd_write_ap(AP_CSW, CSW_VALUE | CSW_SIZE32)) {
return 0;
}
// TAR write
req = SWD_REG_AP | SWD_REG_W | AP_TAR;
int2array(tmp_in, address, 4);
if (swd_transfer_retry(req, (uint32_t *)tmp_in) != DAP_TRANSFER_OK) {
return 0;
}
// read data
req = SWD_REG_AP | SWD_REG_R | AP_DRW;
// initiate first read, data comes back in next read
if (swd_transfer_retry(req, NULL) != 0x01) {
return 0;
}
for (i = 0; i < (size_in_words - 1); i++) {
if (swd_transfer_retry(req, (uint32_t *)data) != DAP_TRANSFER_OK) {
return 0;
}
data += 4;
}
// read last word
req = SWD_REG_DP | SWD_REG_R | SWD_REG_ADR(DP_RDBUFF);
ack = swd_transfer_retry(req, (uint32_t *)data);
return (ack == 0x01);
}
// Read target memory.
static uint8_t swd_read_data(uint32_t addr, uint32_t *val)
{
uint8_t tmp_in[4];
uint8_t tmp_out[4];
uint8_t req, ack;
uint32_t tmp;
// put addr in TAR register
int2array(tmp_in, addr, 4);
req = SWD_REG_AP | SWD_REG_W | (1 << 2);
if (swd_transfer_retry(req, (uint32_t *)tmp_in) != 0x01) {
return 0;
}
// read data
req = SWD_REG_AP | SWD_REG_R | (3 << 2);
if (swd_transfer_retry(req, (uint32_t *)tmp_out) != 0x01) {
return 0;
}
// dummy read
req = SWD_REG_DP | SWD_REG_R | SWD_REG_ADR(DP_RDBUFF);
ack = swd_transfer_retry(req, (uint32_t *)tmp_out);
*val = 0;
tmp = tmp_out[3];
*val |= (tmp << 24);
tmp = tmp_out[2];
*val |= (tmp << 16);
tmp = tmp_out[1];
*val |= (tmp << 8);
tmp = tmp_out[0];
*val |= (tmp << 0);
return (ack == 0x01);
}
// Write target memory.
static uint8_t swd_write_data(uint32_t address, uint32_t data)
{
uint8_t tmp_in[4];
uint8_t req, ack;
// put addr in TAR register
int2array(tmp_in, address, 4);
req = SWD_REG_AP | SWD_REG_W | (1 << 2);
if (swd_transfer_retry(req, (uint32_t *)tmp_in) != 0x01) {
return 0;
}
// write data
int2array(tmp_in, data, 4);
req = SWD_REG_AP | SWD_REG_W | (3 << 2);
if (swd_transfer_retry(req, (uint32_t *)tmp_in) != 0x01) {
return 0;
}
// dummy read
req = SWD_REG_DP | SWD_REG_R | SWD_REG_ADR(DP_RDBUFF);
ack = swd_transfer_retry(req, NULL);
return (ack == 0x01) ? 1 : 0;
}
// Read 32-bit word from target memory.
/* static */ uint8_t swd_read_word(uint32_t addr, uint32_t *val)
{
if (!swd_write_ap(AP_CSW, CSW_VALUE | CSW_SIZE32)) {
return 0;
}
if (!swd_read_data(addr, val)) {
return 0;
}
return 1;
}
// Write 32-bit word to target memory.
/* static */ uint8_t swd_write_word(uint32_t addr, uint32_t val)
{
if (!swd_write_ap(AP_CSW, CSW_VALUE | CSW_SIZE32)) {
return 0;
}
if (!swd_write_data(addr, val)) {
return 0;
}
return 1;
}
// Read 8-bit byte from target memory.
static uint8_t swd_read_byte(uint32_t addr, uint8_t *val)
{
uint32_t tmp;
if (!swd_write_ap(AP_CSW, CSW_VALUE | CSW_SIZE8)) {
return 0;
}
if (!swd_read_data(addr, &tmp)) {
return 0;
}
*val = (uint8_t)(tmp >> ((addr & 0x03) << 3));
return 1;
}
// Write 8-bit byte to target memory.
static uint8_t swd_write_byte(uint32_t addr, uint8_t val)
{
uint32_t tmp;
if (!swd_write_ap(AP_CSW, CSW_VALUE | CSW_SIZE8)) {
return 0;
}
tmp = val << ((addr & 0x03) << 3);
if (!swd_write_data(addr, tmp)) {
return 0;
}
return 1;
}
// Read unaligned data from target memory.
// size is in bytes.
uint8_t swd_read_memory(uint32_t address, uint8_t *data, uint32_t size)
{
uint32_t n;
// Read bytes until word aligned
while ((size > 0) && (address & 0x3)) {
if (!swd_read_byte(address, data)) {
return 0;
}
address++;
data++;
size--;
}
// Read word aligned blocks
while (size > 3) {
// Limit to auto increment page size
n = Flash_Page_Size - (address & (Flash_Page_Size - 1));
if (size < n) {
n = size & 0xFFFFFFFC; // Only count complete words remaining
}
if (!swd_read_block(address, data, n)) {
return 0;
}
address += n;
data += n;
size -= n;
}
// Read remaining bytes
while (size > 0) {
if (!swd_read_byte(address, data)) {
return 0;
}
address++;
data++;
size--;
}
return 1;
}
// Write unaligned data to target memory.
// size is in bytes.
uint8_t swd_write_memory(uint32_t address, uint8_t *data, uint32_t size)
{
uint32_t n = 0;
// Write bytes until word aligned
while ((size > 0) && (address & 0x3)) {
if (!swd_write_byte(address, *data)) {
return 0;
}
address++;
data++;
size--;
}
// Write word aligned blocks
while (size > 3) {
// Limit to auto increment page size
n = Flash_Page_Size - (address & (Flash_Page_Size - 1));
if (size < n) {
n = size & 0xFFFFFFFC; // Only count complete words remaining
}
if (!swd_write_block(address, data, n)) {
return 0;
}
address += n;
data += n;
size -= n;
}
// Write remaining bytes
while (size > 0) {
if (!swd_write_byte(address, *data)) {
return 0;
}
address++;
data++;
size--;
}
return 1;
}
// Execute system call.
static uint8_t swd_write_debug_state(DEBUG_STATE *state)
{
uint32_t i, status;
if (!swd_write_dp(DP_SELECT, 0)) {
return 0;
}
// R0, R1, R2, R3
for (i = 0; i < 4; i++) {
if (!swd_write_core_register(i, state->r[i])) {
return 0;
}
}
// R9
if (!swd_write_core_register(9, state->r[9])) {
return 0;
}
// R13, R14, R15
for (i = 13; i < 16; i++) {
if (!swd_write_core_register(i, state->r[i])) {
return 0;
}
}
// xPSR
if (!swd_write_core_register(16, state->xpsr)) {
return 0;
}
if (!swd_write_word(DBG_HCSR, DBGKEY | C_DEBUGEN)) {
return 0;
}
// check status
if (!swd_read_dp(DP_CTRL_STAT, &status)) {
return 0;
}
if (status & (STICKYERR | WDATAERR)) {
return 0;
}
return 1;
}
static uint8_t swd_read_core_register(uint32_t n, uint32_t *val)
{
int i = 0, timeout = 100;
if (!swd_write_word(DCRSR, n)) {
return 0;
}
// wait for S_REGRDY
for (i = 0; i < timeout; i++) {
if (!swd_read_word(DHCSR, val)) {
return 0;
}
if (*val & S_REGRDY) {
break;
}
}
if (i == timeout) {
return 0;
}
if (!swd_read_word(DCRDR, val)) {
return 0;
}
return 1;
}
static uint8_t swd_write_core_register(uint32_t n, uint32_t val)
{
int i = 0, timeout = 100;
if (!swd_write_word(DCRDR, val)) {
return 0;
}
if (!swd_write_word(DCRSR, n | REGWnR)) {
return 0;
}
// wait for S_REGRDY
for (i = 0; i < timeout; i++) {
if (!swd_read_word(DHCSR, &val)) {
return 0;
}
if (val & S_REGRDY) {
return 1;
}
}
return 0;
}
static uint8_t swd_wait_until_halted(void)
{
// Wait for target to stop
uint32_t val, i, timeout = MAX_TIMEOUT;
for (i = 0; i < timeout; i++) {
if (!swd_read_word(DBG_HCSR, &val)) {
return 0;
}
if (val & S_HALT) {
return 1;
}
}
return 0;
}
uint8_t swd_flash_syscall_exec(const program_syscall_t *sysCallParam, uint32_t entry, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4)
{
DEBUG_STATE state = {{0}, 0};
// Call flash algorithm function on target and wait for result.
state.r[0] = arg1; // R0: Argument 1
state.r[1] = arg2; // R1: Argument 2
state.r[2] = arg3; // R2: Argument 3
state.r[3] = arg4; // R3: Argument 4
state.r[9] = sysCallParam->static_base; // SB: Static Base
state.r[13] = sysCallParam->stack_pointer; // SP: Stack Pointer
state.r[14] = sysCallParam->breakpoint; // LR: Exit Point
state.r[15] = entry; // PC: Entry Point
state.xpsr = 0x01000000; // xPSR: T = 1, ISR = 0
if (!swd_write_debug_state(&state)) {
return 0;
}
if (!swd_wait_until_halted()) {
return 0;
}
if (!swd_read_core_register(0, &state.r[0])) {
return 0;
}
// Flash functions return 0 if successful.
if (state.r[0] != 0) {
return 0;
}
return 1;
}
// SWD Reset
static uint8_t swd_reset(void)
{
uint8_t tmp_in[8];
uint8_t i = 0;
for (i = 0; i < 8; i++) {
tmp_in[i] = 0xff;
}
SWJ_Sequence(51, tmp_in);
return 1;
}
// SWD Switch
static uint8_t swd_switch(uint16_t val)
{
uint8_t tmp_in[2];
tmp_in[0] = val & 0xff;
tmp_in[1] = (val >> 8) & 0xff;
SWJ_Sequence(16, tmp_in);
return 1;
}
// SWD Read ID
static uint8_t swd_read_idcode(uint32_t *id)
{
uint8_t tmp_in[1];
uint8_t tmp_out[4];
tmp_in[0] = 0x00;
SWJ_Sequence(8, tmp_in);
if (swd_read_dp(0, (uint32_t *)tmp_out) != 0x01) {
return 0;
}
*id = (tmp_out[3] << 24) | (tmp_out[2] << 16) | (tmp_out[1] << 8) | tmp_out[0];
return 1;
}
static uint8_t JTAG2SWD()
{
uint32_t tmp = 0;
if (!swd_reset()) {
return 0;
}
if (!swd_switch(0xE79E)) {
return 0;
}
if (!swd_reset()) {
return 0;
}
if (!swd_read_idcode(&tmp)) {
return 0;
}
return 1;
}
uint8_t swd_init_debug(void)
{
uint32_t tmp = 0;
int i = 0;
int timeout = 100;
// init dap state with fake values
dap_state.select = 0xffffffff;
dap_state.csw = 0xffffffff;
swd_init();
// call a target dependant function
// this function can do several stuff before really initing the debug
//target_before_init_debug();
if (!JTAG2SWD()) {
return 0;
}
if (!swd_write_dp(DP_ABORT, STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR)) {
return 0;
}
// Ensure CTRL/STAT register selected in DPBANKSEL
if (!swd_write_dp(DP_SELECT, 0)) {
return 0;
}
// Power up
if (!swd_write_dp(DP_CTRL_STAT, CSYSPWRUPREQ | CDBGPWRUPREQ)) {
return 0;
}
for (i = 0; i < timeout; i++) {
if (!swd_read_dp(DP_CTRL_STAT, &tmp)) {
return 0;
}
if ((tmp & (CDBGPWRUPACK | CSYSPWRUPACK)) == (CDBGPWRUPACK | CSYSPWRUPACK)) {
// Break from loop if powerup is complete
break;
}
}
if (i == timeout) {
// Unable to powerup DP
return 0;
}
if (!swd_write_dp(DP_CTRL_STAT, CSYSPWRUPREQ | CDBGPWRUPREQ | TRNNORMAL | MASKLANE)) {
return 0;
}
// call a target dependant function:
// some target can enter in a lock state, this function can unlock these targets
//target_unlock_sequence();
if (!swd_write_dp(DP_SELECT, 0)) {
return 0;
}
return 1;
}
/*
__attribute__((weak)) void swd_set_target_reset(uint8_t asserted)
{
(asserted) ? PIN_nRESET_OUT(0) : PIN_nRESET_OUT(1);
}
*/
void swd_set_target_reset(uint8_t asserted)
{
/* <EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD>жԴ˺<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>ö<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> asserted=1 <EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD> asserted=0 <EFBFBD><EFBFBD><EFBFBD>ã<EFBFBD>Ϊ<EFBFBD><EFBFBD>ֻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֻ<EFBFBD>ڵڶ<EFBFBD><EFBFBD>ε<EFBFBD><EFBFBD>ô˺<EFBFBD><EFBFBD><EFBFBD>ʱִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ */
if(asserted == 0)
{
swd_write_word((uint32_t)&SCB->AIRCR, ((0x5FA << SCB_AIRCR_VECTKEY_Pos) |(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | SCB_AIRCR_SYSRESETREQ_Msk));
}
}
uint8_t swd_set_target_state_hw(TARGET_RESET_STATE state)
{
uint32_t val;
int8_t ap_retries = 2;
/* Calling swd_init prior to entering RUN state causes operations to fail. */
if (state != RUN) {
swd_init();
}
switch (state) {
case RESET_HOLD:
swd_set_target_reset(1);
break;
case RESET_RUN:
swd_set_target_reset(1);
delaymS(20);
swd_set_target_reset(0);
delaymS(20);
swd_off();
break;
case RESET_PROGRAM:
if (!swd_init_debug()) {
return 0;
}
// Enable debug
while(swd_write_word(DBG_HCSR, DBGKEY | C_DEBUGEN) == 0) {
if( --ap_retries <=0 )
return 0;
// Target is in invalid state?
swd_set_target_reset(1);
delaymS(20);
swd_set_target_reset(0);
delaymS(20);
}
// Enable halt on reset
if (!swd_write_word(DBG_EMCR, VC_CORERESET)) {
return 0;
}
// Reset again
swd_set_target_reset(1);
delaymS(20);
swd_set_target_reset(0);
delaymS(20);
do {
if (!swd_read_word(DBG_HCSR, &val)) {
return 0;
}
} while ((val & S_HALT) == 0);
// Disable halt on reset
if (!swd_write_word(DBG_EMCR, 0)) {
return 0;
}
break;
case NO_DEBUG:
if (!swd_write_word(DBG_HCSR, DBGKEY)) {
return 0;
}
break;
case DEBUG:
if (!JTAG2SWD()) {
return 0;
}
if (!swd_write_dp(DP_ABORT, STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR)) {
return 0;
}
// Ensure CTRL/STAT register selected in DPBANKSEL
if (!swd_write_dp(DP_SELECT, 0)) {
return 0;
}
// Power up
if (!swd_write_dp(DP_CTRL_STAT, CSYSPWRUPREQ | CDBGPWRUPREQ)) {
return 0;
}
// Enable debug
if (!swd_write_word(DBG_HCSR, DBGKEY | C_DEBUGEN)) {
return 0;
}
break;
case HALT:
if (!swd_init_debug()) {
return 0;
}
// Enable debug and halt the core (DHCSR <- 0xA05F0003)
if (!swd_write_word(DBG_HCSR, DBGKEY | C_DEBUGEN | C_HALT)) {
return 0;
}
// Wait until core is halted
do {
if (!swd_read_word(DBG_HCSR, &val)) {
return 0;
}
} while ((val & S_HALT) == 0);
break;
case RUN:
if (!swd_write_word(DBG_HCSR, DBGKEY)) {
return 0;
}
swd_off();
default:
return 0;
}
return 1;
}
uint8_t swd_set_target_state_sw(TARGET_RESET_STATE state)
{
uint32_t val;
/* Calling swd_init prior to enterring RUN state causes operations to fail. */
if (state != RUN) {
swd_init();
}
switch (state) {
case RESET_HOLD:
swd_set_target_reset(1);
break;
case RESET_RUN:
swd_set_target_reset(1);
delaymS(20);
swd_set_target_reset(0);
delaymS(20);
swd_off();
break;
case RESET_PROGRAM:
if (!swd_init_debug()) {
return 0;
}
// Enable debug and halt the core (DHCSR <- 0xA05F0003)
if (!swd_write_word(DBG_HCSR, DBGKEY | C_DEBUGEN | C_HALT)) {
return 0;
}
// Wait until core is halted
do {
if (!swd_read_word(DBG_HCSR, &val)) {
return 0;
}
} while ((val & S_HALT) == 0);
// Enable halt on reset
if (!swd_write_word(DBG_EMCR, VC_CORERESET)) {
return 0;
}
// Perform a soft reset
if (!swd_read_word(NVIC_AIRCR, &val)) {
return 0;
}
if (!swd_write_word(NVIC_AIRCR, VECTKEY | (val & SCB_AIRCR_PRIGROUP_Msk) | SYSRESETREQ)) {
return 0;
}
delaymS(20);
do {
if (!swd_read_word(DBG_HCSR, &val)) {
return 0;
}
} while ((val & S_HALT) == 0);
// Disable halt on reset
if (!swd_write_word(DBG_EMCR, 0)) {
return 0;
}
break;
case NO_DEBUG:
if (!swd_write_word(DBG_HCSR, DBGKEY)) {
return 0;
}
break;
case DEBUG:
if (!JTAG2SWD()) {
return 0;
}
if (!swd_write_dp(DP_ABORT, STKCMPCLR | STKERRCLR | WDERRCLR | ORUNERRCLR)) {
return 0;
}
// Ensure CTRL/STAT register selected in DPBANKSEL
if (!swd_write_dp(DP_SELECT, 0)) {
return 0;
}
// Power up
if (!swd_write_dp(DP_CTRL_STAT, CSYSPWRUPREQ | CDBGPWRUPREQ)) {
return 0;
}
// Enable debug
if (!swd_write_word(DBG_HCSR, DBGKEY | C_DEBUGEN)) {
return 0;
}
break;
case HALT:
if (!swd_init_debug()) {
return 0;
}
// Enable debug and halt the core (DHCSR <- 0xA05F0003)
if (!swd_write_word(DBG_HCSR, DBGKEY | C_DEBUGEN | C_HALT)) {
return 0;
}
// Wait until core is halted
do {
if (!swd_read_word(DBG_HCSR, &val)) {
return 0;
}
} while ((val & S_HALT) == 0);
break;
case RUN:
if (!swd_write_word(DBG_HCSR, DBGKEY)) {
return 0;
}
swd_off();
default:
return 0;
}
return 1;
}