2 ## This file is part of the libsigrokdecode project.
4 ## Copyright (C) 2018 Mike Jagdis <mjagdis@eris-associates.co.uk>
6 ## This program is free software; you can redistribute it and/or modify
7 ## it under the terms of the GNU General Public License as published by
8 ## the Free Software Foundation; either version 2 of the License, or
9 ## (at your option) any later version.
11 ## This program is distributed in the hope that it will be useful,
12 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ## GNU General Public License for more details.
16 ## You should have received a copy of the GNU General Public License
17 ## along with this program; if not, write to the Free Software
18 ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 import sigrokdecode as srd
24 class SamplerateError(Exception):
27 class Decoder(srd.Decoder):
31 longname = 'STM8 SWIM bus'
32 desc = 'STM8 Single Wire Interface Module (SWIM) protocol.'
37 {'id': 'debug', 'desc': 'Debug', 'default': 'no', 'values': ('yes', 'no') },
40 {'id': 'swim', 'name': 'SWIM', 'desc': 'SWIM data line'},
44 ('enterseq', 'SWIM enter sequence'),
45 ('start-host', 'Start bit (host)'),
46 ('start-target', 'Start bit (target)'),
47 ('parity', 'Parity bit'),
48 ('ack', 'Acknowledgement'),
49 ('nack', 'Negative acknowledgement'),
50 ('byte-write', 'Byte write'),
51 ('byte-read', 'Byte read'),
52 ('cmd-unknown', 'Unknown SWIM command'),
53 ('cmd', 'SWIM command'),
54 ('bytes', 'Byte count'),
55 ('address', 'Address'),
56 ('data-write', 'Data write'),
57 ('data-read', 'Data read'),
61 ('bits', 'Bits', (0,)),
62 ('framing', 'Framing', (2, 3, 4, 5, 6, 7, 8)),
63 ('protocol', 'Protocol', (1, 9, 10, 11, 12, 13, 14)),
64 ('debug', 'Debug', (15,)),
67 ('tx', 'Dump of data written to target'),
68 ('rx', 'Dump of data read from target'),
72 # SWIM clock for the target is normally HSI/2 where HSI is 8MHz +- 5%
73 # although the divisor can be removed by setting the SWIMCLK bit in
74 # the CLK_SWIMCCR register. There is no standard for the host so we
75 # will be generous and assume it is using an 8MHz +- 10% oscillator.
76 # We do not need to be accurate. We just need to avoid treating enter
77 # sequence pulses as bits. A synchronization frame will cause this
80 self.HSI_min = self.HSI * 0.9
81 self.HSI_max = self.HSI * 1.1
82 self.swim_clock = self.HSI_min / 2
84 self.eseq_edge = [[-1, None], [-1, None]]
86 self.eseq_pairstart = None
91 self.bit_edge = [[-1, None], [-1, None]]
94 self.bitseq_end = None
95 self.proto_state = 'CMD'
97 def metadata(self, key, value):
98 if key == srd.SRD_CONF_SAMPLERATE:
99 self.samplerate = value
101 def adjust_timings(self):
102 # A low-speed bit is 22 SWIM clocks long.
103 # There are options to shorten bits to 10 clocks or use HSI rather
104 # than HSI/2 as the SWIM clock but the longest valid bit should be no
105 # more than this many samples. This does not need to be accurate.
106 # It exists simply to prevent bits extending unecessarily far into
107 # trailing bus-idle periods. This will be adjusted every time we see
108 # a synchronization frame or start bit in order to show idle periods
109 # as accurately as possible.
110 self.bit_reflen = math.ceil(self.samplerate * 22 / self.swim_clock)
113 self.out_ann = self.register(srd.OUTPUT_ANN)
114 self.out_binary = self.register(srd.OUTPUT_BINARY)
116 if not self.samplerate:
117 raise SamplerateError('Cannot decode without samplerate.')
119 # A synchronization frame is a low that lasts for more than 64 but no
120 # more than 128 SWIM clock periods based on the standard SWIM clock.
121 # Note: we also allow for the possibility that the SWIM clock divisor
122 # has been disabled here.
123 self.sync_reflen_min = math.floor(self.samplerate * 64 / self.HSI_max)
124 self.sync_reflen_max = math.ceil(self.samplerate * 128 / (self.HSI_min / 2))
126 if self.options['debug'] == 'yes':
131 # The SWIM entry sequence is 4 pulses at 2kHz followed by 4 at 1kHz.
132 self.eseq_reflen = math.ceil(self.samplerate / 2048)
134 self.adjust_timings()
137 if self.proto_state == 'CMD':
139 if self.bitseq_value == 0x00:
140 self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [10, ['system reset', 'SRST', '!']])
141 elif self.bitseq_value == 0x01:
142 self.proto_state = 'N'
143 self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [10, ['read on-the-fly', 'ROTF', 'r']])
144 elif self.bitseq_value == 0x02:
145 self.proto_state = 'N'
146 self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [10, ['write on-the-fly', 'WOTF', 'w']])
148 self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [9, ['unknown', 'UNK']])
149 elif self.proto_state == 'N':
151 self.proto_byte_count = self.bitseq_value
152 self.proto_state = '@E'
153 self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [11, ['byte count 0x%02x' % self.bitseq_value, 'bytes 0x%02x' % self.bitseq_value, '0x%02x' % self.bitseq_value, '%02x' % self.bitseq_value, '%x' % self.bitseq_value]])
154 elif self.proto_state == '@E':
156 self.proto_addr = self.bitseq_value
157 self.proto_addr_start = self.bitseq_start
158 self.proto_state = '@H'
159 elif self.proto_state == '@H':
161 self.proto_addr = (self.proto_addr << 8) | self.bitseq_value
162 self.proto_state = '@L'
163 elif self.proto_state == '@L':
165 self.proto_addr = (self.proto_addr << 8) | self.bitseq_value
166 self.proto_state = 'D'
167 self.put(self.proto_addr_start, self.bitseq_end, self.out_ann, [12, ['address 0x%06x' % self.proto_addr, 'addr 0x%06x' % self.proto_addr, '0x%06x' % self.proto_addr, '%06x' %self.proto_addr, '%x' % self.proto_addr]])
169 if self.proto_byte_count > 0:
170 self.proto_byte_count -= 1
171 if self.proto_byte_count == 0:
172 self.proto_state = 'CMD'
174 self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [13 + self.bitseq_dir, ['0x%02x' % self.bitseq_value, '%02x' % self.bitseq_value, '%x' % self.bitseq_value]])
175 self.put(self.bitseq_start, self.bitseq_end, self.out_binary, [0 + self.bitseq_dir, bytes([self.bitseq_value])])
177 self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [15, ['%d more' % self.proto_byte_count, '%d' % self.proto_byte_count]])
179 def bitseq(self, bitstart, bitend, bit):
180 if self.bitseq_len == 0:
181 # Looking for start of a bit sequence (command or byte).
182 self.bit_reflen = bitend - bitstart
183 self.bitseq_value = 0
184 self.bitseq_dir = bit
186 self.put(bitstart, bitend, self.out_ann, [2 + self.bitseq_dir, ['start', 's']])
187 elif (self.proto_state == 'CMD' and self.bitseq_len == 4) or (self.proto_state != 'CMD' and self.bitseq_len == 9):
189 self.bitseq_end = bitstart
192 self.put(bitstart, bitend, self.out_ann, [4, ['parity', 'par', 'p']])
194 # The start bit is not data but was used for parity calculation.
195 self.bitseq_value &= 0xff
196 self.put(self.bitseq_start, self.bitseq_end, self.out_ann, [7 + self.bitseq_dir, ['0x%02x' % self.bitseq_value, '%02x' % self.bitseq_value, '%x' % self.bitseq_value]])
197 elif (self.proto_state == 'CMD' and self.bitseq_len == 5) or (self.proto_state != 'CMD' and self.bitseq_len == 10):
200 self.put(bitstart, bitend, self.out_ann, [5, ['ack', 'a']])
202 self.put(bitstart, bitend, self.out_ann, [6, ['nack', 'n']])
204 # We only pass data that was ack'd up the stack.
210 if self.bitseq_len == 1:
211 self.bitseq_start = bitstart
212 self.bitseq_value = (self.bitseq_value << 1) | bit
215 def bit(self, start, mid, end):
216 if mid - start >= end - mid:
217 self.put(start, end, self.out_ann, [0, ['0']])
220 self.put(start, end, self.out_ann, [0, ['1']])
223 self.bitseq(start, end, bit)
225 def detect_synchronize_frame(self, start, end):
226 # Strictly speaking, synchronization frames are only recognised when
227 # SWIM is active. A falling edge on reset disables SWIM and an enter
228 # sequence is needed to re-enable it. However we do not want to be
229 # reliant on seeing the NRST pin just for that and we also want to be
230 # able to decode SWIM even if we just sample parts of the dialogue.
231 # For this reason we limit ourselves to only recognizing
232 # synchronization frames that have believable lengths based on our
233 # knowledge of the range of possible SWIM clocks.
234 if self.samplenum - self.eseq_edge[1][1] >= self.sync_reflen_min and self.samplenum - self.eseq_edge[1][1] <= self.sync_reflen_max:
235 self.put(self.eseq_edge[1][1], self.samplenum, self.out_ann, [1, ['synchronization frame', 'synchronization', 'sync', 's']])
237 # A low that lasts for more than 64 SWIM clock periods causes a
238 # reset of the SWIM communication state machine and will switch
239 # the SWIM to low-speed mode (SWIM_CSR.HS is cleared).
242 # The low SHOULD last 128 SWIM clocks. This is used to
243 # resynchronize in order to allow for variation in the frequency
244 # of the internal RC oscillator.
245 self.swim_clock = 128 * (self.samplerate / (self.samplenum - self.eseq_edge[1][1]))
246 self.adjust_timings()
248 def eseq_potential_start(self, start, end):
249 self.eseq_pairstart = start
250 self.eseq_reflen = end - start
251 self.eseq_pairnum = 1
253 def detect_enter_sequence(self, start, end):
254 # According to the spec the enter sequence is four pulses at 2kHz
255 # followed by four at 1kHz. We do not check the frequency but simply
256 # check the lengths of successive pulses against the first. This means
257 # we have no need to account for the accuracy (or lack of) of the
259 if self.eseq_pairnum == 0 or abs(self.eseq_reflen - (end - start)) > 2:
260 self.eseq_potential_start(start, end)
262 elif self.eseq_pairnum < 4:
263 # The next three pulses should be the same length as the first.
264 self.eseq_pairnum += 1
266 if self.eseq_pairnum == 4:
267 self.eseq_reflen /= 2
269 # The final four pulses should each be half the length of the
270 # initial pair. Again, a mismatch causes us to reset and use the
271 # current pulse as a new potential enter sequence start.
272 self.eseq_pairnum += 1
273 if self.eseq_pairnum == 8:
274 # Four matching pulses followed by four more that match each
275 # other but are half the length of the first 4. SWIM is active!
276 self.put(self.eseq_pairstart, end, self.out_ann, [1, ['enter sequence', 'enter seq', 'enter', 'ent', 'e']])
277 self.eseq_pairnum = 0
281 if self.bit_maxlen >= 0:
282 (swim,) = self.wait()
285 (swim,) = self.wait({0: 'e'})
287 if swim != self.eseq_edge[1][0]:
288 if swim == 1 and self.eseq_edge[1][1] is not None:
289 self.detect_synchronize_frame(self.eseq_edge[1][1], self.samplenum)
290 if self.eseq_edge[0][1] is not None:
291 self.detect_enter_sequence(self.eseq_edge[0][1], self.samplenum)
292 self.eseq_edge.pop(0)
293 self.eseq_edge.append([swim, self.samplenum])
295 if (swim != self.bit_edge[1][0] and (swim != 1 or self.bit_edge[1][0] != -1)) or self.bit_maxlen == 0:
296 if self.bit_maxlen == 0 and self.bit_edge[1][0] == 1:
299 if self.bit_edge[1][0] != 0 and swim == 0:
300 self.bit_maxlen = self.bit_reflen
302 if self.bit_edge[0][0] == 0 and self.bit_edge[1][0] == 1 and self.samplenum - self.bit_edge[0][1] <= self.bit_reflen + 2:
303 self.bit(self.bit_edge[0][1], self.bit_edge[1][1], self.samplenum)
306 self.bit_edge.append([swim, self.samplenum])