]> sigrok.org Git - libsigrokdecode.git/blame - decoders/spi/pd.py
spi: Create the out_bitrate annotation unconditionally
[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']
6a15597a 85 channels = (
49e8a4d6 86 {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'},
da9bcbd9 87 )
6a15597a 88 optional_channels = (
49e8a4d6
UH
89 {'id': 'miso', 'name': 'MISO', 'desc': 'Master in, slave out'},
90 {'id': 'mosi', 'name': 'MOSI', 'desc': 'Master out, slave in'},
91 {'id': 'cs', 'name': 'CS#', 'desc': 'Chip-select'},
da9bcbd9 92 )
84c1c0b5
BV
93 options = (
94 {'id': 'cs_polarity', 'desc': 'CS# polarity', 'default': 'active-low',
95 'values': ('active-low', 'active-high')},
96 {'id': 'cpol', 'desc': 'Clock polarity', 'default': 0,
97 'values': (0, 1)},
98 {'id': 'cpha', 'desc': 'Clock phase', 'default': 0,
99 'values': (0, 1)},
b0918d40 100 {'id': 'bitorder', 'desc': 'Bit order',
84c1c0b5 101 'default': 'msb-first', 'values': ('msb-first', 'lsb-first')},
b0918d40 102 {'id': 'wordsize', 'desc': 'Word size', 'default': 8},
84c1c0b5 103 )
da9bcbd9
BV
104 annotations = (
105 ('miso-data', 'MISO data'),
106 ('mosi-data', 'MOSI data'),
107 ('miso-bits', 'MISO bits'),
108 ('mosi-bits', 'MOSI bits'),
109 ('warnings', 'Human-readable warnings'),
110 )
06b52ebb 111 annotation_rows = (
cddd11bc
UH
112 ('miso-data', 'MISO data', (0,)),
113 ('miso-bits', 'MISO bits', (2,)),
114 ('mosi-data', 'MOSI data', (1,)),
115 ('mosi-bits', 'MOSI bits', (3,)),
116 ('other', 'Other', (4,)),
06b52ebb 117 )
49d0e05c
UH
118 binary = (
119 ('miso', 'MISO'),
120 ('mosi', 'MOSI'),
121 )
6eb87578 122
3643fc3f 123 def __init__(self):
10aeb8ea
GS
124 self.reset()
125
126 def reset(self):
8a3c8792 127 self.samplerate = None
a10bfc48 128 self.bitcount = 0
bbc100f7 129 self.misodata = self.mosidata = 0
cddd11bc 130 self.misobits = []
bbc100f7 131 self.mosibits = []
8c90d7bd
PLE
132 self.misobytes = []
133 self.mosibytes = []
486b19ce 134 self.ss_block = -1
d6bace96 135 self.samplenum = -1
8c90d7bd 136 self.ss_transfer = -1
bb08f4b3 137 self.cs_was_deasserted = False
bbc100f7 138 self.have_cs = self.have_miso = self.have_mosi = None
6eb87578 139
8915b346 140 def start(self):
c515eed7 141 self.out_python = self.register(srd.OUTPUT_PYTHON)
be465111 142 self.out_ann = self.register(srd.OUTPUT_ANN)
2f370328 143 self.out_binary = self.register(srd.OUTPUT_BINARY)
f04db50a
JG
144 self.out_bitrate = self.register(srd.OUTPUT_META,
145 meta=(int, 'Bitrate', 'Bitrate during transfers'))
8284ca73 146 self.bw = (self.options['wordsize'] + 7) // 8
3643fc3f 147
f04db50a
JG
148 def metadata(self, key, value):
149 if key == srd.SRD_CONF_SAMPLERATE:
150 self.samplerate = value
151
ec0afe27 152 def putw(self, data):
486b19ce 153 self.put(self.ss_block, self.samplenum, self.out_ann, data)
ec0afe27 154
bbc100f7
UH
155 def putdata(self):
156 # Pass MISO and MOSI bits and then data to the next PD up the stack.
157 so = self.misodata if self.have_miso else None
158 si = self.mosidata if self.have_mosi else None
159 so_bits = self.misobits if self.have_miso else None
160 si_bits = self.mosibits if self.have_mosi else None
7c09dbb2
UH
161
162 if self.have_miso:
163 ss, es = self.misobits[-1][1], self.misobits[0][2]
8284ca73
UH
164 bdata = so.to_bytes(self.bw, byteorder='big')
165 self.put(ss, es, self.out_binary, [0, bdata])
7c09dbb2
UH
166 if self.have_mosi:
167 ss, es = self.mosibits[-1][1], self.mosibits[0][2]
8284ca73
UH
168 bdata = si.to_bytes(self.bw, byteorder='big')
169 self.put(ss, es, self.out_binary, [1, bdata])
7c09dbb2
UH
170
171 self.put(ss, es, self.out_python, ['BITS', si_bits, so_bits])
172 self.put(ss, es, self.out_python, ['DATA', si, so])
cddd11bc 173
8c90d7bd
PLE
174 if self.have_miso:
175 self.misobytes.append(Data(ss=ss, es=es, val=so))
176 if self.have_mosi:
177 self.mosibytes.append(Data(ss=ss, es=es, val=si))
178
bbc100f7
UH
179 # Bit annotations.
180 if self.have_miso:
181 for bit in self.misobits:
182 self.put(bit[1], bit[2], self.out_ann, [2, ['%d' % bit[0]]])
183 if self.have_mosi:
184 for bit in self.mosibits:
185 self.put(bit[1], bit[2], self.out_ann, [3, ['%d' % bit[0]]])
186
187 # Dataword annotations.
188 if self.have_miso:
808c6e74 189 self.put(ss, es, self.out_ann, [0, ['%02X' % self.misodata]])
bbc100f7 190 if self.have_mosi:
808c6e74 191 self.put(ss, es, self.out_ann, [1, ['%02X' % self.mosidata]])
cddd11bc 192
d482a2d3
UH
193 def reset_decoder_state(self):
194 self.misodata = 0 if self.have_miso else None
195 self.mosidata = 0 if self.have_mosi else None
196 self.misobits = [] if self.have_miso else None
197 self.mosibits = [] if self.have_mosi else None
198 self.bitcount = 0
199
cdceaa94
AS
200 def cs_asserted(self, cs):
201 active_low = (self.options['cs_polarity'] == 'active-low')
202 return (cs == 0) if active_low else (cs == 1)
203
bcd14870 204 def handle_bit(self, miso, mosi, clk, cs):
cddd11bc 205 # If this is the first bit of a dataword, save its sample number.
191ec8c5 206 if self.bitcount == 0:
486b19ce 207 self.ss_block = self.samplenum
cdceaa94
AS
208 self.cs_was_deasserted = \
209 not self.cs_asserted(cs) if self.have_cs else False
2fcd7c22 210
191ec8c5 211 ws = self.options['wordsize']
d399c641 212 bo = self.options['bitorder']
d6bace96 213
bbc100f7
UH
214 # Receive MISO bit into our shift register.
215 if self.have_miso:
d399c641 216 if bo == 'msb-first':
bbc100f7
UH
217 self.misodata |= miso << (ws - 1 - self.bitcount)
218 else:
219 self.misodata |= miso << self.bitcount
220
191ec8c5 221 # Receive MOSI bit into our shift register.
12549f11 222 if self.have_mosi:
d399c641 223 if bo == 'msb-first':
12549f11
UH
224 self.mosidata |= mosi << (ws - 1 - self.bitcount)
225 else:
226 self.mosidata |= mosi << self.bitcount
3e3c0330 227
808c6e74 228 # Guesstimate the endsample for this bit (can be overridden below).
bbc100f7
UH
229 es = self.samplenum
230 if self.bitcount > 0:
8e8096e8
UH
231 if self.have_miso:
232 es += self.samplenum - self.misobits[0][1]
233 elif self.have_mosi:
234 es += self.samplenum - self.mosibits[0][1]
c94c8c91 235
cddd11bc 236 if self.have_miso:
d78e0beb 237 self.misobits.insert(0, [miso, self.samplenum, es])
cddd11bc 238 if self.have_mosi:
d78e0beb 239 self.mosibits.insert(0, [mosi, self.samplenum, es])
bbc100f7
UH
240
241 if self.bitcount > 0 and self.have_miso:
d78e0beb 242 self.misobits[1][2] = self.samplenum
bbc100f7 243 if self.bitcount > 0 and self.have_mosi:
d78e0beb 244 self.mosibits[1][2] = self.samplenum
cddd11bc 245
191ec8c5 246 self.bitcount += 1
1ea831e9 247
191ec8c5
UH
248 # Continue to receive if not enough bits were received, yet.
249 if self.bitcount != ws:
250 return
b1bb5eed 251
bbc100f7 252 self.putdata()
12549f11
UH
253
254 # Meta bitrate.
956721de 255 if self.samplerate:
fa7fdc54
GS
256 elapsed = 1 / float(self.samplerate)
257 elapsed *= (self.samplenum - self.ss_block + 1)
d399c641 258 bitrate = int(1 / elapsed * ws)
fa7fdc54 259 self.put(self.ss_block, self.samplenum, self.out_bitrate, bitrate)
8a3c8792 260
bb08f4b3 261 if self.have_cs and self.cs_was_deasserted:
cddd11bc 262 self.putw([4, ['CS# was deasserted during this data word!']])
191ec8c5 263
d482a2d3 264 self.reset_decoder_state()
191ec8c5 265
de15aa2a
GS
266 def find_clk_edge(self, miso, mosi, clk, cs, first):
267 if self.have_cs and (first or self.matched[self.have_cs]):
191ec8c5 268 # Send all CS# pin value changes.
de15aa2a 269 oldcs = None if first else 1 - cs
c515eed7 270 self.put(self.samplenum, self.samplenum, self.out_python,
de15aa2a 271 ['CS-CHANGE', oldcs, cs])
8c90d7bd
PLE
272
273 if self.cs_asserted(cs):
274 self.ss_transfer = self.samplenum
275 self.misobytes = []
276 self.mosibytes = []
277 else:
278 self.put(self.ss_transfer, self.samplenum, self.out_python,
279 ['TRANSFER', self.mosibytes, self.misobytes])
280
efa64173 281 # Reset decoder state when CS# changes (and the CS# pin is used).
d482a2d3 282 self.reset_decoder_state()
191ec8c5 283
cdceaa94
AS
284 # We only care about samples if CS# is asserted.
285 if self.have_cs and not self.cs_asserted(cs):
286 return
287
191ec8c5 288 # Ignore sample if the clock pin hasn't changed.
de15aa2a 289 if first or not self.matched[0]:
191ec8c5 290 return
b1bb5eed 291
191ec8c5
UH
292 # Sample data on rising/falling clock edge (depends on mode).
293 mode = spi_mode[self.options['cpol'], self.options['cpha']]
bcd14870 294 if mode == 0 and clk == 0: # Sample on rising clock edge
191ec8c5 295 return
bcd14870 296 elif mode == 1 and clk == 1: # Sample on falling clock edge
191ec8c5 297 return
bcd14870 298 elif mode == 2 and clk == 1: # Sample on falling clock edge
191ec8c5 299 return
bcd14870 300 elif mode == 3 and clk == 0: # Sample on rising clock edge
191ec8c5
UH
301 return
302
303 # Found the correct clock edge, now get the SPI bit(s).
bcd14870 304 self.handle_bit(miso, mosi, clk, cs)
191ec8c5 305
15814cab 306 def decode(self):
de15aa2a
GS
307 # The CLK input is mandatory. Other signals are (individually)
308 # optional. Yet either MISO or MOSI (or both) must be provided.
309 # Tell stacked decoders when we don't have a CS# signal.
310 if not self.has_channel(0):
311 raise ChannelError('Either MISO or MOSI (or both) pins required.')
15814cab
GS
312 self.have_miso = self.has_channel(1)
313 self.have_mosi = self.has_channel(2)
15814cab
GS
314 if not self.have_miso and not self.have_mosi:
315 raise ChannelError('Either MISO or MOSI (or both) pins required.')
de15aa2a 316 self.have_cs = self.has_channel(3)
15814cab
GS
317 if not self.have_cs:
318 self.put(0, 0, self.out_python, ['CS-CHANGE', None, None])
319
de15aa2a
GS
320 # We want all CLK changes. We want all CS changes if CS is used.
321 # Map 'have_cs' from boolean to an integer index. This simplifies
322 # evaluation in other locations.
323 wait_cond = [{0: 'e'}]
324 if self.have_cs:
325 self.have_cs = len(wait_cond)
326 wait_cond.append({3: 'e'})
327
15814cab
GS
328 # "Pixel compatibility" with the v2 implementation. Grab and
329 # process the very first sample before checking for edges. The
de15aa2a
GS
330 # previous implementation did this by seeding old values with
331 # None, which led to an immediate "change" in comparison.
d399c641 332 (clk, miso, mosi, cs) = self.wait({})
de15aa2a 333 self.find_clk_edge(miso, mosi, clk, cs, True)
15814cab
GS
334
335 while True:
d399c641 336 (clk, miso, mosi, cs) = self.wait(wait_cond)
de15aa2a 337 self.find_clk_edge(miso, mosi, clk, cs, False)