SWD(Serial Wire Debug) interface
Dependents: USBMSD_LPC_HelloWorld lpcterm2 Simple-CMSIS-DAP 11u35_usbLocalFilesystem
SWD.cpp@0:86fde86e144f, 2013-09-14 (annotated)
- Committer:
- va009039
- Date:
- Sat Sep 14 12:50:46 2013 +0000
- Revision:
- 0:86fde86e144f
- Child:
- 1:794d2801ff94
first commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
va009039 | 0:86fde86e144f | 1 | // SWD.cpp 2013/9/14 |
va009039 | 0:86fde86e144f | 2 | #include "SWD.h" |
va009039 | 0:86fde86e144f | 3 | #include <algorithm> |
va009039 | 0:86fde86e144f | 4 | #include "mydebug.h" |
va009039 | 0:86fde86e144f | 5 | |
va009039 | 0:86fde86e144f | 6 | SWD::SWD(PinName swdio, PinName swclk, PinName reset) |
va009039 | 0:86fde86e144f | 7 | : _swdio(swdio), _swclk(swclk), _nreset(reset) |
va009039 | 0:86fde86e144f | 8 | { |
va009039 | 0:86fde86e144f | 9 | conf.turnaround = 1; |
va009039 | 0:86fde86e144f | 10 | conf.data_phase = 0; |
va009039 | 0:86fde86e144f | 11 | idle_cycles = 0; |
va009039 | 0:86fde86e144f | 12 | retry_count = 100; |
va009039 | 0:86fde86e144f | 13 | |
va009039 | 0:86fde86e144f | 14 | _cpu_delay_count = 2; |
va009039 | 0:86fde86e144f | 15 | TransferAbort = false; |
va009039 | 0:86fde86e144f | 16 | } |
va009039 | 0:86fde86e144f | 17 | |
va009039 | 0:86fde86e144f | 18 | void SWD::Setup() |
va009039 | 0:86fde86e144f | 19 | { |
va009039 | 0:86fde86e144f | 20 | _swclk = 1; |
va009039 | 0:86fde86e144f | 21 | _swdio.output(); |
va009039 | 0:86fde86e144f | 22 | _swdio = 1; |
va009039 | 0:86fde86e144f | 23 | _nreset.input(); |
va009039 | 0:86fde86e144f | 24 | _nreset.mode(PullUp); |
va009039 | 0:86fde86e144f | 25 | } |
va009039 | 0:86fde86e144f | 26 | |
va009039 | 0:86fde86e144f | 27 | void SWD::reset() |
va009039 | 0:86fde86e144f | 28 | { |
va009039 | 0:86fde86e144f | 29 | SWJPins(0x00, 0x80); |
va009039 | 0:86fde86e144f | 30 | SWJPins(0x80, 0x80); |
va009039 | 0:86fde86e144f | 31 | } |
va009039 | 0:86fde86e144f | 32 | |
va009039 | 0:86fde86e144f | 33 | void SWD::SWJSequence(int count, const uint8_t* data) |
va009039 | 0:86fde86e144f | 34 | { |
va009039 | 0:86fde86e144f | 35 | for(int n = 0; n < count; n++) { |
va009039 | 0:86fde86e144f | 36 | uint8_t val = data[n/8]; |
va009039 | 0:86fde86e144f | 37 | write_bit(val>>(n%8)); |
va009039 | 0:86fde86e144f | 38 | } |
va009039 | 0:86fde86e144f | 39 | } |
va009039 | 0:86fde86e144f | 40 | |
va009039 | 0:86fde86e144f | 41 | uint8_t SWD::SWJPins(uint32_t value, uint32_t select ,int waittime_us) |
va009039 | 0:86fde86e144f | 42 | { |
va009039 | 0:86fde86e144f | 43 | if (select & 0x01) { // swclk |
va009039 | 0:86fde86e144f | 44 | _swclk = (value & 0x01) ? 1 : 0; |
va009039 | 0:86fde86e144f | 45 | } |
va009039 | 0:86fde86e144f | 46 | if (select & 0x02) { // swdio |
va009039 | 0:86fde86e144f | 47 | _swdio = (value & 0x02) ? 1 : 0; |
va009039 | 0:86fde86e144f | 48 | } |
va009039 | 0:86fde86e144f | 49 | if (select & 0x80) { // nReset |
va009039 | 0:86fde86e144f | 50 | if (value & 0x80) { |
va009039 | 0:86fde86e144f | 51 | _nreset.input(); |
va009039 | 0:86fde86e144f | 52 | } else { |
va009039 | 0:86fde86e144f | 53 | _nreset.output(); |
va009039 | 0:86fde86e144f | 54 | _nreset = 0; |
va009039 | 0:86fde86e144f | 55 | } |
va009039 | 0:86fde86e144f | 56 | } |
va009039 | 0:86fde86e144f | 57 | if (waittime_us) { |
va009039 | 0:86fde86e144f | 58 | waittime_us = std::min(waittime_us, 3000000); |
va009039 | 0:86fde86e144f | 59 | Timer t; |
va009039 | 0:86fde86e144f | 60 | t.reset(); |
va009039 | 0:86fde86e144f | 61 | t.start(); |
va009039 | 0:86fde86e144f | 62 | while(t.read_us() < waittime_us) { |
va009039 | 0:86fde86e144f | 63 | if (select & 0x01) { // swclk |
va009039 | 0:86fde86e144f | 64 | if (_swclk ^ ((value & 0x01) ? 1 : 0)) { |
va009039 | 0:86fde86e144f | 65 | continue; |
va009039 | 0:86fde86e144f | 66 | } |
va009039 | 0:86fde86e144f | 67 | } |
va009039 | 0:86fde86e144f | 68 | if (select & 0x02) { // swdio |
va009039 | 0:86fde86e144f | 69 | if (_swdio ^ ((value & 0x02) ? 1 : 0)) { |
va009039 | 0:86fde86e144f | 70 | continue; |
va009039 | 0:86fde86e144f | 71 | } |
va009039 | 0:86fde86e144f | 72 | } |
va009039 | 0:86fde86e144f | 73 | if (select & 0x80) { // nReset |
va009039 | 0:86fde86e144f | 74 | if (_nreset ^ ((value & 0x80) ? 1 : 0)) { |
va009039 | 0:86fde86e144f | 75 | continue; |
va009039 | 0:86fde86e144f | 76 | } |
va009039 | 0:86fde86e144f | 77 | } |
va009039 | 0:86fde86e144f | 78 | break; |
va009039 | 0:86fde86e144f | 79 | } |
va009039 | 0:86fde86e144f | 80 | } |
va009039 | 0:86fde86e144f | 81 | return (_swclk ? 0x01 : 0x00) | (_swdio ? 0x02 : 0x00) | (_nreset ? 0x80 : 0x00); |
va009039 | 0:86fde86e144f | 82 | } |
va009039 | 0:86fde86e144f | 83 | |
va009039 | 0:86fde86e144f | 84 | void SWD::SWJClock(uint32_t clock_hz) |
va009039 | 0:86fde86e144f | 85 | { |
va009039 | 0:86fde86e144f | 86 | if (clock_hz) { |
va009039 | 0:86fde86e144f | 87 | uint32_t scc = SystemCoreClock; |
va009039 | 0:86fde86e144f | 88 | _cpu_delay_count = scc / 2 / clock_hz / 3; |
va009039 | 0:86fde86e144f | 89 | } |
va009039 | 0:86fde86e144f | 90 | } |
va009039 | 0:86fde86e144f | 91 | |
va009039 | 0:86fde86e144f | 92 | void SWD::TransferConfigure(int _idle_cycles, int _retry_count) |
va009039 | 0:86fde86e144f | 93 | { |
va009039 | 0:86fde86e144f | 94 | idle_cycles = _idle_cycles; |
va009039 | 0:86fde86e144f | 95 | retry_count = _retry_count; |
va009039 | 0:86fde86e144f | 96 | } |
va009039 | 0:86fde86e144f | 97 | |
va009039 | 0:86fde86e144f | 98 | void SWD::Configure(int turnaround, int data_phase) |
va009039 | 0:86fde86e144f | 99 | { |
va009039 | 0:86fde86e144f | 100 | conf.turnaround = turnaround; |
va009039 | 0:86fde86e144f | 101 | conf.data_phase = data_phase; |
va009039 | 0:86fde86e144f | 102 | } |
va009039 | 0:86fde86e144f | 103 | |
va009039 | 0:86fde86e144f | 104 | uint8_t SWD::Transfer(uint8_t request, uint32_t *data) |
va009039 | 0:86fde86e144f | 105 | { |
va009039 | 0:86fde86e144f | 106 | for(int retry = retry_count; retry >= 0; retry--) { |
va009039 | 0:86fde86e144f | 107 | uint8_t ack = rawTransfer(request, data); |
va009039 | 0:86fde86e144f | 108 | if (ack != SWD_WAIT || TransferAbort) { |
va009039 | 0:86fde86e144f | 109 | return ack; |
va009039 | 0:86fde86e144f | 110 | } |
va009039 | 0:86fde86e144f | 111 | } |
va009039 | 0:86fde86e144f | 112 | return SWD_WAIT; |
va009039 | 0:86fde86e144f | 113 | } |
va009039 | 0:86fde86e144f | 114 | |
va009039 | 0:86fde86e144f | 115 | #pragma Otime |
va009039 | 0:86fde86e144f | 116 | |
va009039 | 0:86fde86e144f | 117 | static uint32_t calc_parity(uint32_t data, int n) |
va009039 | 0:86fde86e144f | 118 | { |
va009039 | 0:86fde86e144f | 119 | uint32_t parity = 0; |
va009039 | 0:86fde86e144f | 120 | for(int i = 0; i < n; i++) { |
va009039 | 0:86fde86e144f | 121 | parity += data>>i; |
va009039 | 0:86fde86e144f | 122 | } |
va009039 | 0:86fde86e144f | 123 | return parity & 1; |
va009039 | 0:86fde86e144f | 124 | } |
va009039 | 0:86fde86e144f | 125 | |
va009039 | 0:86fde86e144f | 126 | uint8_t SWD::rawTransfer(uint8_t request, uint32_t *data) |
va009039 | 0:86fde86e144f | 127 | { |
va009039 | 0:86fde86e144f | 128 | write_bit(1); // start bit |
va009039 | 0:86fde86e144f | 129 | write_bit(request, 4); // APnDP,RnW,A2,A3 |
va009039 | 0:86fde86e144f | 130 | write_bit(calc_parity(request, 4)); // parity bit |
va009039 | 0:86fde86e144f | 131 | write_bit(0); // stop bit |
va009039 | 0:86fde86e144f | 132 | write_bit(1); // park bit |
va009039 | 0:86fde86e144f | 133 | |
va009039 | 0:86fde86e144f | 134 | _swdio.input(); |
va009039 | 0:86fde86e144f | 135 | clock_cycle(conf.turnaround); |
va009039 | 0:86fde86e144f | 136 | |
va009039 | 0:86fde86e144f | 137 | uint8_t ack = read_bit(3); |
va009039 | 0:86fde86e144f | 138 | if (ack == SWD_OK) { |
va009039 | 0:86fde86e144f | 139 | if (request & SWD_RnW) { // read |
va009039 | 0:86fde86e144f | 140 | uint32_t val = read_bit(32); |
va009039 | 0:86fde86e144f | 141 | uint32_t parity = read_bit(1); |
va009039 | 0:86fde86e144f | 142 | if (parity ^ calc_parity(val, 32)) { |
va009039 | 0:86fde86e144f | 143 | ack = SWD_ERROR; |
va009039 | 0:86fde86e144f | 144 | } |
va009039 | 0:86fde86e144f | 145 | if (data) { |
va009039 | 0:86fde86e144f | 146 | *data = val; |
va009039 | 0:86fde86e144f | 147 | } |
va009039 | 0:86fde86e144f | 148 | clock_cycle(conf.turnaround); |
va009039 | 0:86fde86e144f | 149 | _swdio.output(); |
va009039 | 0:86fde86e144f | 150 | } else { // write |
va009039 | 0:86fde86e144f | 151 | clock_cycle(conf.turnaround); |
va009039 | 0:86fde86e144f | 152 | _swdio.output(); |
va009039 | 0:86fde86e144f | 153 | uint32_t val = *data; |
va009039 | 0:86fde86e144f | 154 | write_bit(val, 32); |
va009039 | 0:86fde86e144f | 155 | write_bit(calc_parity(val, 32)); |
va009039 | 0:86fde86e144f | 156 | } |
va009039 | 0:86fde86e144f | 157 | if (idle_cycles) { |
va009039 | 0:86fde86e144f | 158 | _swdio = 0; |
va009039 | 0:86fde86e144f | 159 | clock_cycle(idle_cycles); |
va009039 | 0:86fde86e144f | 160 | } |
va009039 | 0:86fde86e144f | 161 | _swdio = 1; |
va009039 | 0:86fde86e144f | 162 | return ack; |
va009039 | 0:86fde86e144f | 163 | } |
va009039 | 0:86fde86e144f | 164 | |
va009039 | 0:86fde86e144f | 165 | if (ack == SWD_WAIT || ack == SWD_FAULT) { |
va009039 | 0:86fde86e144f | 166 | if (conf.data_phase && (request & SWD_RnW)) { |
va009039 | 0:86fde86e144f | 167 | clock_cycle(32+1); |
va009039 | 0:86fde86e144f | 168 | } |
va009039 | 0:86fde86e144f | 169 | clock_cycle(conf.turnaround); |
va009039 | 0:86fde86e144f | 170 | _swdio.output(); |
va009039 | 0:86fde86e144f | 171 | if (conf.data_phase && ((request & SWD_RnW) == 0)) { |
va009039 | 0:86fde86e144f | 172 | _swdio = 0; |
va009039 | 0:86fde86e144f | 173 | clock_cycle(32+1); |
va009039 | 0:86fde86e144f | 174 | } |
va009039 | 0:86fde86e144f | 175 | _swdio = 1; |
va009039 | 0:86fde86e144f | 176 | return ack; |
va009039 | 0:86fde86e144f | 177 | } |
va009039 | 0:86fde86e144f | 178 | clock_cycle(32 + 1 + conf.turnaround); |
va009039 | 0:86fde86e144f | 179 | _swdio.output(); |
va009039 | 0:86fde86e144f | 180 | return ack; |
va009039 | 0:86fde86e144f | 181 | } |
va009039 | 0:86fde86e144f | 182 | |
va009039 | 0:86fde86e144f | 183 | void SWD::pin_delay() |
va009039 | 0:86fde86e144f | 184 | { |
va009039 | 0:86fde86e144f | 185 | __IO int n = _cpu_delay_count; |
va009039 | 0:86fde86e144f | 186 | while(n-- > 0) |
va009039 | 0:86fde86e144f | 187 | ; |
va009039 | 0:86fde86e144f | 188 | } |
va009039 | 0:86fde86e144f | 189 | |
va009039 | 0:86fde86e144f | 190 | void SWD::clock_cycle(int n) |
va009039 | 0:86fde86e144f | 191 | { |
va009039 | 0:86fde86e144f | 192 | while(n-- > 0) { |
va009039 | 0:86fde86e144f | 193 | _swclk = 0; |
va009039 | 0:86fde86e144f | 194 | pin_delay(); |
va009039 | 0:86fde86e144f | 195 | _swclk = 1; |
va009039 | 0:86fde86e144f | 196 | pin_delay(); |
va009039 | 0:86fde86e144f | 197 | } |
va009039 | 0:86fde86e144f | 198 | } |
va009039 | 0:86fde86e144f | 199 | |
va009039 | 0:86fde86e144f | 200 | void SWD::write_bit(uint32_t data, int n) |
va009039 | 0:86fde86e144f | 201 | { |
va009039 | 0:86fde86e144f | 202 | for(int i = 0; i < n; i++) { |
va009039 | 0:86fde86e144f | 203 | _swdio = (data>>i) & 1; |
va009039 | 0:86fde86e144f | 204 | clock_cycle(); |
va009039 | 0:86fde86e144f | 205 | } |
va009039 | 0:86fde86e144f | 206 | } |
va009039 | 0:86fde86e144f | 207 | |
va009039 | 0:86fde86e144f | 208 | uint32_t SWD::read_bit(int n) |
va009039 | 0:86fde86e144f | 209 | { |
va009039 | 0:86fde86e144f | 210 | uint32_t data = 0; |
va009039 | 0:86fde86e144f | 211 | for(int i = 0; i < n; i++) { |
va009039 | 0:86fde86e144f | 212 | _swclk = 0; |
va009039 | 0:86fde86e144f | 213 | pin_delay(); |
va009039 | 0:86fde86e144f | 214 | uint32_t val = _swdio & 1; |
va009039 | 0:86fde86e144f | 215 | data |= val<<i; |
va009039 | 0:86fde86e144f | 216 | _swclk = 1; |
va009039 | 0:86fde86e144f | 217 | pin_delay(); |
va009039 | 0:86fde86e144f | 218 | } |
va009039 | 0:86fde86e144f | 219 | return data; |
va009039 | 0:86fde86e144f | 220 | } |