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