]> sigrok.org Git - libsigrokdecode.git/blame - decoders/spi/pd.py
avr_isp: Add more parts
[libsigrokdecode.git] / decoders / spi / pd.py
CommitLineData
6eb87578 1##
50bd5d25 2## This file is part of the libsigrokdecode project.
6eb87578
GM
3##
4## Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
12549f11 5## Copyright (C) 2012-2014 Uwe Hermann <uwe@hermann-uwe.de>
6eb87578
GM
6##
7## This program is free software; you can redistribute it and/or modify
8## it under the terms of the GNU General Public License as published by
9## the Free Software Foundation; either version 2 of the License, or
10## (at your option) any later version.
11##
12## This program is distributed in the hope that it will be useful,
13## but WITHOUT ANY WARRANTY; without even the implied warranty of
14## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15## GNU General Public License for more details.
16##
17## You should have received a copy of the GNU General Public License
4539e9ca 18## along with this program; if not, see <http://www.gnu.org/licenses/>.
6eb87578 19##
ad2dc0de 20
677d597b 21import sigrokdecode as srd
8c90d7bd
PLE
22from collections import namedtuple
23
24Data = namedtuple('Data', ['ss', 'es', 'val'])
67e847fd 25
0702e0cf 26'''
c515eed7 27OUTPUT_PYTHON format:
0702e0cf 28
bf69977d
UH
29Packet:
30[<ptype>, <data1>, <data2>]
0702e0cf 31
bf69977d 32<ptype>:
34929ee0 33 - 'DATA': <data1> contains the MOSI data, <data2> contains the MISO data.
0702e0cf 34 The data is _usually_ 8 bits (but can also be fewer or more bits).
12549f11 35 Both data items are Python numbers (not strings), or None if the respective
6a15597a 36 channel was not supplied.
34929ee0 37 - 'BITS': <data1>/<data2> contain a list of bit values in this MOSI/MISO data
cddd11bc 38 item, and for each of those also their respective start-/endsample numbers.
92a06d0b 39 - 'CS-CHANGE': <data1> is the old CS# pin value, <data2> is the new value.
1c49e875 40 Both data items are Python numbers (0/1), not strings. At the beginning of
8a110ab1
JS
41 the decoding a packet is generated with <data1> = None and <data2> being the
42 initial state of the CS# pin or None if the chip select pin is not supplied.
8c90d7bd
PLE
43 - 'TRANSFER': <data1>/<data2> contain a list of Data() namedtuples for each
44 byte transferred during this block of CS# asserted time. Each Data() has
45 fields ss, es, and val.
0702e0cf
UH
46
47Examples:
8a110ab1 48 ['CS-CHANGE', None, 1]
0702e0cf
UH
49 ['CS-CHANGE', 1, 0]
50 ['DATA', 0xff, 0x3a]
cddd11bc
UH
51 ['BITS', [[1, 80, 82], [1, 83, 84], [1, 85, 86], [1, 87, 88],
52 [1, 89, 90], [1, 91, 92], [1, 93, 94], [1, 95, 96]],
d78e0beb
UH
53 [[0, 80, 82], [1, 83, 84], [0, 85, 86], [1, 87, 88],
54 [1, 89, 90], [1, 91, 92], [0, 93, 94], [0, 95, 96]]]
0702e0cf 55 ['DATA', 0x65, 0x00]
12549f11
UH
56 ['DATA', 0xa8, None]
57 ['DATA', None, 0x55]
0702e0cf 58 ['CS-CHANGE', 0, 1]
8c90d7bd
PLE
59 ['TRANSFER', [Data(ss=80, es=96, val=0xff), ...],
60 [Data(ss=80, es=96, val=0x3a), ...]]
0702e0cf
UH
61'''
62
8a7ce2a3 63# Key: (CPOL, CPHA). Value: SPI mode.
94bbdb9a
UH
64# Clock polarity (CPOL) = 0/1: Clock is low/high when inactive.
65# Clock phase (CPHA) = 0/1: Data is valid on the leading/trailing clock edge.
c94c8c91
UH
66spi_mode = {
67 (0, 0): 0, # Mode 0
68 (0, 1): 1, # Mode 1
69 (1, 0): 2, # Mode 2
70 (1, 1): 3, # Mode 3
71}
72
f04964c6 73class ChannelError(Exception):
37b0da68
BV
74 pass
75
677d597b 76class Decoder(srd.Decoder):
15814cab 77 api_version = 3
67e847fd 78 id = 'spi'
2b7d0e2b 79 name = 'SPI'
3d3da57d 80 longname = 'Serial Peripheral Interface'
a465436e 81 desc = 'Full-duplex, synchronous, serial bus.'
6eb87578
GM
82 license = 'gplv2+'
83 inputs = ['logic']
84 outputs = ['spi']
d6d8a8a4 85 tags = ['Embedded/industrial']
6a15597a 86 channels = (
49e8a4d6 87 {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'},
da9bcbd9 88 )
6a15597a 89 optional_channels = (
49e8a4d6
UH
90 {'id': 'miso', 'name': 'MISO', 'desc': 'Master in, slave out'},
91 {'id': 'mosi', 'name': 'MOSI', 'desc': 'Master out, slave in'},
92 {'id': 'cs', 'name': 'CS#', 'desc': 'Chip-select'},
da9bcbd9 93 )
84c1c0b5
BV
94 options = (
95 {'id': 'cs_polarity', 'desc': 'CS# polarity', 'default': 'active-low',
96 'values': ('active-low', 'active-high')},
97 {'id': 'cpol', 'desc': 'Clock polarity', 'default': 0,
98 'values': (0, 1)},
99 {'id': 'cpha', 'desc': 'Clock phase', 'default': 0,
100 'values': (0, 1)},
b0918d40 101 {'id': 'bitorder', 'desc': 'Bit order',
84c1c0b5 102 'default': 'msb-first', 'values': ('msb-first', 'lsb-first')},
b0918d40 103 {'id': 'wordsize', 'desc': 'Word size', 'default': 8},
84c1c0b5 104 )
da9bcbd9
BV
105 annotations = (
106 ('miso-data', 'MISO data'),
107 ('mosi-data', 'MOSI data'),
e144452b
UH
108 ('miso-bit', 'MISO bit'),
109 ('mosi-bit', 'MOSI bit'),
110 ('warning', 'Warning'),
a69b0f0b
UH
111 ('miso-transfer', 'MISO transfer'),
112 ('mosi-transfer', 'MOSI transfer'),
da9bcbd9 113 )
06b52ebb 114 annotation_rows = (
cddd11bc 115 ('miso-bits', 'MISO bits', (2,)),
e144452b
UH
116 ('miso-data-vals', 'MISO data', (0,)),
117 ('miso-transfers', 'MISO transfers', (5,)),
cddd11bc 118 ('mosi-bits', 'MOSI bits', (3,)),
e144452b
UH
119 ('mosi-data-vals', 'MOSI data', (1,)),
120 ('mosi-transfers', 'MOSI transfers', (6,)),
cddd11bc 121 ('other', 'Other', (4,)),
06b52ebb 122 )
49d0e05c
UH
123 binary = (
124 ('miso', 'MISO'),
125 ('mosi', 'MOSI'),
126 )
6eb87578 127
3643fc3f 128 def __init__(self):
10aeb8ea
GS
129 self.reset()
130
131 def reset(self):
8a3c8792 132 self.samplerate = None
a10bfc48 133 self.bitcount = 0
bbc100f7 134 self.misodata = self.mosidata = 0
cddd11bc 135 self.misobits = []
bbc100f7 136 self.mosibits = []
8c90d7bd
PLE
137 self.misobytes = []
138 self.mosibytes = []
486b19ce 139 self.ss_block = -1
8c90d7bd 140 self.ss_transfer = -1
bb08f4b3 141 self.cs_was_deasserted = False
bbc100f7 142 self.have_cs = self.have_miso = self.have_mosi = None
6eb87578 143
8915b346 144 def start(self):
c515eed7 145 self.out_python = self.register(srd.OUTPUT_PYTHON)
be465111 146 self.out_ann = self.register(srd.OUTPUT_ANN)
2f370328 147 self.out_binary = self.register(srd.OUTPUT_BINARY)
f04db50a
JG
148 self.out_bitrate = self.register(srd.OUTPUT_META,
149 meta=(int, 'Bitrate', 'Bitrate during transfers'))
8284ca73 150 self.bw = (self.options['wordsize'] + 7) // 8
3643fc3f 151
f04db50a
JG
152 def metadata(self, key, value):
153 if key == srd.SRD_CONF_SAMPLERATE:
154 self.samplerate = value
155
ec0afe27 156 def putw(self, data):
486b19ce 157 self.put(self.ss_block, self.samplenum, self.out_ann, data)
ec0afe27 158
bbc100f7
UH
159 def putdata(self):
160 # Pass MISO and MOSI bits and then data to the next PD up the stack.
161 so = self.misodata if self.have_miso else None
162 si = self.mosidata if self.have_mosi else None
163 so_bits = self.misobits if self.have_miso else None
164 si_bits = self.mosibits if self.have_mosi else None
7c09dbb2
UH
165
166 if self.have_miso:
167 ss, es = self.misobits[-1][1], self.misobits[0][2]
8284ca73
UH
168 bdata = so.to_bytes(self.bw, byteorder='big')
169 self.put(ss, es, self.out_binary, [0, bdata])
7c09dbb2
UH
170 if self.have_mosi:
171 ss, es = self.mosibits[-1][1], self.mosibits[0][2]
8284ca73
UH
172 bdata = si.to_bytes(self.bw, byteorder='big')
173 self.put(ss, es, self.out_binary, [1, bdata])
7c09dbb2
UH
174
175 self.put(ss, es, self.out_python, ['BITS', si_bits, so_bits])
176 self.put(ss, es, self.out_python, ['DATA', si, so])
cddd11bc 177
8c90d7bd
PLE
178 if self.have_miso:
179 self.misobytes.append(Data(ss=ss, es=es, val=so))
180 if self.have_mosi:
181 self.mosibytes.append(Data(ss=ss, es=es, val=si))
182
bbc100f7
UH
183 # Bit annotations.
184 if self.have_miso:
185 for bit in self.misobits:
186 self.put(bit[1], bit[2], self.out_ann, [2, ['%d' % bit[0]]])
187 if self.have_mosi:
188 for bit in self.mosibits:
189 self.put(bit[1], bit[2], self.out_ann, [3, ['%d' % bit[0]]])
190
191 # Dataword annotations.
192 if self.have_miso:
808c6e74 193 self.put(ss, es, self.out_ann, [0, ['%02X' % self.misodata]])
bbc100f7 194 if self.have_mosi:
808c6e74 195 self.put(ss, es, self.out_ann, [1, ['%02X' % self.mosidata]])
cddd11bc 196
d482a2d3
UH
197 def reset_decoder_state(self):
198 self.misodata = 0 if self.have_miso else None
199 self.mosidata = 0 if self.have_mosi else None
200 self.misobits = [] if self.have_miso else None
201 self.mosibits = [] if self.have_mosi else None
202 self.bitcount = 0
203
cdceaa94
AS
204 def cs_asserted(self, cs):
205 active_low = (self.options['cs_polarity'] == 'active-low')
206 return (cs == 0) if active_low else (cs == 1)
207
bcd14870 208 def handle_bit(self, miso, mosi, clk, cs):
cddd11bc 209 # If this is the first bit of a dataword, save its sample number.
191ec8c5 210 if self.bitcount == 0:
486b19ce 211 self.ss_block = self.samplenum
cdceaa94
AS
212 self.cs_was_deasserted = \
213 not self.cs_asserted(cs) if self.have_cs else False
2fcd7c22 214
191ec8c5 215 ws = self.options['wordsize']
d399c641 216 bo = self.options['bitorder']
d6bace96 217
bbc100f7
UH
218 # Receive MISO bit into our shift register.
219 if self.have_miso:
d399c641 220 if bo == 'msb-first':
bbc100f7
UH
221 self.misodata |= miso << (ws - 1 - self.bitcount)
222 else:
223 self.misodata |= miso << self.bitcount
224
191ec8c5 225 # Receive MOSI bit into our shift register.
12549f11 226 if self.have_mosi:
d399c641 227 if bo == 'msb-first':
12549f11
UH
228 self.mosidata |= mosi << (ws - 1 - self.bitcount)
229 else:
230 self.mosidata |= mosi << self.bitcount
3e3c0330 231
808c6e74 232 # Guesstimate the endsample for this bit (can be overridden below).
bbc100f7
UH
233 es = self.samplenum
234 if self.bitcount > 0:
8e8096e8
UH
235 if self.have_miso:
236 es += self.samplenum - self.misobits[0][1]
237 elif self.have_mosi:
238 es += self.samplenum - self.mosibits[0][1]
c94c8c91 239
cddd11bc 240 if self.have_miso:
d78e0beb 241 self.misobits.insert(0, [miso, self.samplenum, es])
cddd11bc 242 if self.have_mosi:
d78e0beb 243 self.mosibits.insert(0, [mosi, self.samplenum, es])
bbc100f7
UH
244
245 if self.bitcount > 0 and self.have_miso:
d78e0beb 246 self.misobits[1][2] = self.samplenum
bbc100f7 247 if self.bitcount > 0 and self.have_mosi:
d78e0beb 248 self.mosibits[1][2] = self.samplenum
cddd11bc 249
191ec8c5 250 self.bitcount += 1
1ea831e9 251
191ec8c5
UH
252 # Continue to receive if not enough bits were received, yet.
253 if self.bitcount != ws:
254 return
b1bb5eed 255
bbc100f7 256 self.putdata()
12549f11
UH
257
258 # Meta bitrate.
956721de 259 if self.samplerate:
fa7fdc54
GS
260 elapsed = 1 / float(self.samplerate)
261 elapsed *= (self.samplenum - self.ss_block + 1)
d399c641 262 bitrate = int(1 / elapsed * ws)
fa7fdc54 263 self.put(self.ss_block, self.samplenum, self.out_bitrate, bitrate)
8a3c8792 264
bb08f4b3 265 if self.have_cs and self.cs_was_deasserted:
cddd11bc 266 self.putw([4, ['CS# was deasserted during this data word!']])
191ec8c5 267
d482a2d3 268 self.reset_decoder_state()
191ec8c5 269
de15aa2a
GS
270 def find_clk_edge(self, miso, mosi, clk, cs, first):
271 if self.have_cs and (first or self.matched[self.have_cs]):
191ec8c5 272 # Send all CS# pin value changes.
de15aa2a 273 oldcs = None if first else 1 - cs
c515eed7 274 self.put(self.samplenum, self.samplenum, self.out_python,
de15aa2a 275 ['CS-CHANGE', oldcs, cs])
8c90d7bd
PLE
276
277 if self.cs_asserted(cs):
278 self.ss_transfer = self.samplenum
279 self.misobytes = []
280 self.mosibytes = []
4275cee2 281 elif self.ss_transfer != -1:
a69b0f0b
UH
282 if self.have_miso:
283 self.put(self.ss_transfer, self.samplenum, self.out_ann,
284 [5, [' '.join(format(x.val, '02X') for x in self.misobytes)]])
285 if self.have_mosi:
286 self.put(self.ss_transfer, self.samplenum, self.out_ann,
287 [6, [' '.join(format(x.val, '02X') for x in self.mosibytes)]])
8c90d7bd
PLE
288 self.put(self.ss_transfer, self.samplenum, self.out_python,
289 ['TRANSFER', self.mosibytes, self.misobytes])
290
efa64173 291 # Reset decoder state when CS# changes (and the CS# pin is used).
d482a2d3 292 self.reset_decoder_state()
191ec8c5 293
cdceaa94
AS
294 # We only care about samples if CS# is asserted.
295 if self.have_cs and not self.cs_asserted(cs):
296 return
297
191ec8c5 298 # Ignore sample if the clock pin hasn't changed.
de15aa2a 299 if first or not self.matched[0]:
191ec8c5 300 return
b1bb5eed 301
191ec8c5
UH
302 # Sample data on rising/falling clock edge (depends on mode).
303 mode = spi_mode[self.options['cpol'], self.options['cpha']]
bcd14870 304 if mode == 0 and clk == 0: # Sample on rising clock edge
191ec8c5 305 return
bcd14870 306 elif mode == 1 and clk == 1: # Sample on falling clock edge
191ec8c5 307 return
bcd14870 308 elif mode == 2 and clk == 1: # Sample on falling clock edge
191ec8c5 309 return
bcd14870 310 elif mode == 3 and clk == 0: # Sample on rising clock edge
191ec8c5
UH
311 return
312
313 # Found the correct clock edge, now get the SPI bit(s).
bcd14870 314 self.handle_bit(miso, mosi, clk, cs)
191ec8c5 315
15814cab 316 def decode(self):
de15aa2a
GS
317 # The CLK input is mandatory. Other signals are (individually)
318 # optional. Yet either MISO or MOSI (or both) must be provided.
319 # Tell stacked decoders when we don't have a CS# signal.
320 if not self.has_channel(0):
321 raise ChannelError('Either MISO or MOSI (or both) pins required.')
15814cab
GS
322 self.have_miso = self.has_channel(1)
323 self.have_mosi = self.has_channel(2)
15814cab
GS
324 if not self.have_miso and not self.have_mosi:
325 raise ChannelError('Either MISO or MOSI (or both) pins required.')
de15aa2a 326 self.have_cs = self.has_channel(3)
15814cab
GS
327 if not self.have_cs:
328 self.put(0, 0, self.out_python, ['CS-CHANGE', None, None])
329
de15aa2a
GS
330 # We want all CLK changes. We want all CS changes if CS is used.
331 # Map 'have_cs' from boolean to an integer index. This simplifies
332 # evaluation in other locations.
333 wait_cond = [{0: 'e'}]
334 if self.have_cs:
335 self.have_cs = len(wait_cond)
336 wait_cond.append({3: 'e'})
337
15814cab
GS
338 # "Pixel compatibility" with the v2 implementation. Grab and
339 # process the very first sample before checking for edges. The
de15aa2a
GS
340 # previous implementation did this by seeding old values with
341 # None, which led to an immediate "change" in comparison.
d399c641 342 (clk, miso, mosi, cs) = self.wait({})
de15aa2a 343 self.find_clk_edge(miso, mosi, clk, cs, True)
15814cab
GS
344
345 while True:
d399c641 346 (clk, miso, mosi, cs) = self.wait(wait_cond)
de15aa2a 347 self.find_clk_edge(miso, mosi, clk, cs, False)