Last active
November 1, 2016 13:37
-
-
Save agatti/a92574bf726706f77fa26b9fc4934ee2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* This file is part of the Bus Pirate project | |
* (http://code.google.com/p/the-bus-pirate/). | |
* | |
* Written and maintained by the Bus Pirate project. | |
* | |
* To the extent possible under law, the project has | |
* waived all copyright and related or neighboring rights to Bus Pirate. This | |
* work is published from United States. | |
* | |
* For details see: http://creativecommons.org/publicdomain/zero/1.0/. | |
* | |
* This program is distributed in the hope that it will be useful, | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
*/ | |
#include "swd.h" | |
//#ifdef BP_ENABLE_SWD_SUPPORT | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdbool.h> | |
#include "binIO.h" | |
#include "base.h" | |
#include "bitbang.h" | |
extern mode_configuration_t mode_configuration; | |
#define SWD_CLK BP_CLK | |
#define SWD_CLK_DIR BP_CLK_DIR | |
#define SWD_DATA BP_CS | |
#define SWD_DATA_DIR BP_CS_DIR | |
/* Sent LSB first, processed MSB first. */ | |
#define SWD_OK 0b00000100 | |
#define SWD_WAIT 0b00000010 | |
#define SWD_FAULT 0b00000001 | |
#define SWD_RESPONSE_OK 0 | |
#define SWD_RESPONSE_WAIT 1 | |
#define SWD_RESPONSE_FAULT 2 | |
#define SWD_RESPONSE_UNKNOWN 3 | |
#define SWD_RESPONSE_PARITY 4 | |
typedef struct { | |
uint8_t start_bit : 1; | |
uint8_t ap_dp : 1; | |
uint8_t read_write : 1; | |
uint8_t address_bits : 2; | |
uint8_t parity_bit : 1; | |
uint8_t stop_bit : 1; | |
uint8_t park_bit : 1; | |
} swd_request_t; | |
#define BINARY_IO_COMMAND_EXIT 0 | |
#define BINARY_IO_COMMAND_SEND_DATA 1 | |
#define BINARY_IO_COMMAND_READ_DATA 2 | |
#define SWD_READ ON | |
#define SWD_WRITE OFF | |
static void clock_byte_out(uint8_t value); | |
static uint8_t clock_byte_in(void); | |
static void clock_bit_out(bool value); | |
static bool clock_bit_in(void); | |
static void pulse_clock_line(void); | |
static uint8_t read_acknowledgment(void); | |
void binary_io_swd_version_string(void) { | |
bp_write_string("SWD1"); | |
} | |
static const uint8_t REQUEST_PARITY_TABLE = 0b01010110; | |
static const uint8_t PAYLOAD_PARITY_TABLE[] = { | |
0b10010110, 0b01101001, 0b01101001, 0b10010110, | |
0b01101001, 0b10010110, 0b10010110, 0b01101001, | |
0b01101001, 0b10010110, 0b10010110, 0b01101001, | |
0b10010110, 0b01101001, 0b01101001, 0b10010110, | |
0b01101001, 0b10010110, 0b10010110, 0b01101001, | |
0b10010110, 0b01101001, 0b01101001, 0b10010110, | |
0b10010110, 0b01101001, 0b01101001, 0b10010110, | |
0b01101001, 0b10010110, 0b10010110, 0b01101001, | |
}; | |
/* | |
* Commands: | |
* | |
* 0b00000000 Exit mode. | |
* 0b00010xxx Send data. | |
* ||| | |
* ||+--> AP/DP bit | |
* ++---> Address bits | |
* [32 bits of data to send] | |
* -> 0, {1,2,3} = error | |
* -> 1 = success | |
* | |
* 0b00100xxx Read data. | |
* ||| | |
* ||+--> AP/DP bit | |
* ++---> Address bits | |
* -> 0, {1,2,3,4} = error | |
* -> 1, {byte3, byte2, byte1, byte0}[MSB first] = success | |
* | |
*/ | |
void binary_io_swd_loop(void) { | |
uint8_t input_byte; | |
uint8_t command; | |
/* CLK pin -> SWD CLK [ OUTPUT ] */ | |
/* CS pin -> SWD Data [ INPUT / OUTPUT ] */ | |
mode_configuration.high_impedance = ON; | |
mode_configuration.lsbEN = OFF; | |
SWD_CLK_DIR = OUTPUT; | |
SWD_CLK = LOW; | |
SWD_DATA_DIR = INPUT; | |
SWD_DATA = LOW; | |
binary_io_swd_version_string(); | |
while (true) { | |
input_byte = UART1RX(); | |
command = input_byte >> 4; | |
switch (command) { | |
case BINARY_IO_COMMAND_EXIT: { | |
return; | |
} | |
case BINARY_IO_COMMAND_SEND_DATA: { | |
uint8_t payload[4] = { 0 }; | |
uint8_t index; | |
uint8_t acknowledgment; | |
uint8_t parity = 0; | |
swd_request_t request = { 0 }; | |
for (index = 0; index < sizeof(payload); index++) { | |
payload[index] = UART1RX(); | |
} | |
request.start_bit = ON; | |
request.ap_dp = (input_byte & 0b00000001) ? ON : OFF; | |
request.address_bits = ((input_byte & 0b00000110) >> 1) & 0b00000011; | |
request.read_write = SWD_WRITE; | |
request.parity_bit = ((REQUEST_PARITY_TABLE & | |
(1 << (input_byte & 0b00000111))) >> | |
(input_byte & 0b00000111)) & 0b00000001 ? ON : OFF; | |
request.stop_bit = OFF; | |
request.park_bit = ON; | |
clock_byte_out(*((uint8_t *)&request)); | |
pulse_clock_line(); | |
acknowledgment = read_acknowledgment(); | |
if (acknowledgment != SWD_OK) { | |
UART1TX(BP_BINARY_IO_RESULT_FAILURE); | |
switch (acknowledgment) { | |
case SWD_OK: | |
break; | |
case SWD_WAIT: | |
UART1TX(SWD_RESPONSE_WAIT); | |
break; | |
case SWD_FAULT: | |
UART1TX(SWD_RESPONSE_FAULT); | |
break; | |
default: | |
UART1TX(SWD_RESPONSE_UNKNOWN); | |
break; | |
} | |
break; | |
} | |
pulse_clock_line(); | |
for (index = 0; index < 4; index++) { | |
parity += ((payload[index] >> 5) & | |
(1 << (payload[index] & 0b00000111))) != 0 ? 1 : 0; | |
} | |
for (index = 0; index < 4; index++) { | |
clock_byte_out(payload[index]); | |
} | |
clock_bit_out(parity & 0b00000001); | |
pulse_clock_line(); | |
UART1TX(BP_BINARY_IO_RESULT_SUCCESS); | |
break; | |
} | |
case BINARY_IO_COMMAND_READ_DATA: { | |
uint8_t payload[4] = { 0 }; | |
uint8_t index; | |
uint8_t acknowledgment; | |
uint8_t parity = 0; | |
bool read_parity; | |
swd_request_t request = { 0 }; | |
request.start_bit = ON; | |
request.ap_dp = (input_byte & 0b00000001) ? ON : OFF; | |
request.address_bits = ((input_byte & 0b00000110) >> 1) & 0b00000011; | |
request.read_write = SWD_READ; | |
request.parity_bit = ((REQUEST_PARITY_TABLE & | |
(1 << (input_byte & 0b00000111))) >> | |
(input_byte & 0b00000111)) & 0b00000001 ? ON : OFF; | |
request.stop_bit = OFF; | |
request.park_bit = ON; | |
clock_byte_out(*((uint8_t *)&request)); | |
pulse_clock_line(); | |
acknowledgment = read_acknowledgment(); | |
if (acknowledgment != SWD_OK) { | |
UART1TX(BP_BINARY_IO_RESULT_FAILURE); | |
switch (acknowledgment) { | |
case SWD_OK: | |
break; | |
case SWD_WAIT: | |
UART1TX(SWD_RESPONSE_WAIT); | |
break; | |
case SWD_FAULT: | |
UART1TX(SWD_RESPONSE_FAULT); | |
break; | |
default: | |
UART1TX(SWD_RESPONSE_UNKNOWN); | |
break; | |
} | |
break; | |
} | |
for (index = 0; index < 4; index++) { | |
payload[index] = clock_byte_in(); | |
parity += ((payload[index] >> 5) & | |
(1 << (payload[index] & 0b00000111))) != 0 ? 1 : 0; | |
} | |
read_parity = clock_bit_in(); | |
if (read_parity != (parity & 0b00000001)) { | |
UART1TX(BP_BINARY_IO_RESULT_FAILURE); | |
UART1TX(SWD_RESPONSE_PARITY); | |
break; | |
} | |
pulse_clock_line(); | |
UART1TX(BP_BINARY_IO_RESULT_SUCCESS); | |
for (index = 0; index < 4; index++) { | |
UART1TX(payload[index]); | |
} | |
break; | |
} | |
default: | |
UART1TX(BP_BINARY_IO_RESULT_FAILURE); | |
break; | |
} | |
} | |
} | |
void clock_byte_out(uint8_t value) { | |
uint8_t mask = 0b10000000; | |
SWD_DATA_DIR = OUTPUT; | |
while (mask != 0) { | |
SWD_DATA = ((value & mask) == mask) ? HIGH : LOW; | |
pulse_clock_line(); | |
mask >>= 1; | |
} | |
SWD_DATA_DIR = INPUT; | |
} | |
uint8_t clock_byte_in(void) { | |
uint8_t value = 0; | |
uint8_t index; | |
SWD_DATA_DIR = INPUT; | |
for (index = 0; index < 8; index++) { | |
value |= (SWD_DATA == HIGH) ? 1 : 0; | |
pulse_clock_line(); | |
value <<= 1; | |
} | |
return value; | |
} | |
void clock_bit_out(bool value) { | |
SWD_DATA_DIR = OUTPUT; | |
SWD_DATA = value; | |
pulse_clock_line(); | |
SWD_DATA_DIR = INPUT; | |
} | |
bool clock_bit_in(void) { | |
bool result; | |
SWD_DATA_DIR = INPUT; | |
result = SWD_DATA; | |
pulse_clock_line(); | |
return result; | |
} | |
void pulse_clock_line(void) { | |
SWD_CLK = HIGH; | |
SWD_CLK = LOW; | |
} | |
uint8_t read_acknowledgment(void) { | |
uint8_t buffer; | |
SWD_DATA_DIR = INPUT; | |
buffer = SWD_DATA; | |
pulse_clock_line(); | |
buffer = (buffer << 1) | SWD_DATA; | |
pulse_clock_line(); | |
buffer = (buffer << 1) | SWD_DATA; | |
pulse_clock_line(); | |
return buffer; | |
} | |
//#endif /* BP_ENABLE_SWD_SUPPORT */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment