]> sigrok.org Git - libsigrokdecode.git/blame - decoders/spi/pd.py
Change PD options to be a tuple of dictionaries.
[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
18## along with this program; if not, write to the Free Software
19## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20##
ad2dc0de 21
677d597b 22import sigrokdecode as srd
67e847fd 23
0702e0cf 24'''
c515eed7 25OUTPUT_PYTHON format:
0702e0cf
UH
26
27SPI packet:
28[<cmd>, <data1>, <data2>]
29
30Commands:
31 - 'DATA': <data1> contains the MISO data, <data2> contains the MOSI data.
32 The data is _usually_ 8 bits (but can also be fewer or more bits).
12549f11
UH
33 Both data items are Python numbers (not strings), or None if the respective
34 probe was not supplied.
cddd11bc
UH
35 - 'BITS': <data1>/<data2> contain a list of bit values in this MISO/MOSI data
36 item, and for each of those also their respective start-/endsample numbers.
0702e0cf
UH
37 - 'CS CHANGE': <data1> is the old CS# pin value, <data2> is the new value.
38 Both data items are Python numbers (0/1), not strings.
39
40Examples:
41 ['CS-CHANGE', 1, 0]
42 ['DATA', 0xff, 0x3a]
cddd11bc
UH
43 ['BITS', [[1, 80, 82], [1, 83, 84], [1, 85, 86], [1, 87, 88],
44 [1, 89, 90], [1, 91, 92], [1, 93, 94], [1, 95, 96]],
d78e0beb
UH
45 [[0, 80, 82], [1, 83, 84], [0, 85, 86], [1, 87, 88],
46 [1, 89, 90], [1, 91, 92], [0, 93, 94], [0, 95, 96]]]
0702e0cf 47 ['DATA', 0x65, 0x00]
12549f11
UH
48 ['DATA', 0xa8, None]
49 ['DATA', None, 0x55]
0702e0cf
UH
50 ['CS-CHANGE', 0, 1]
51'''
52
8a7ce2a3 53# Key: (CPOL, CPHA). Value: SPI mode.
94bbdb9a
UH
54# Clock polarity (CPOL) = 0/1: Clock is low/high when inactive.
55# Clock phase (CPHA) = 0/1: Data is valid on the leading/trailing clock edge.
c94c8c91
UH
56spi_mode = {
57 (0, 0): 0, # Mode 0
58 (0, 1): 1, # Mode 1
59 (1, 0): 2, # Mode 2
60 (1, 1): 3, # Mode 3
61}
62
677d597b 63class Decoder(srd.Decoder):
a2c2afd9 64 api_version = 1
67e847fd 65 id = 'spi'
2b7d0e2b 66 name = 'SPI'
3d3da57d 67 longname = 'Serial Peripheral Interface'
a465436e 68 desc = 'Full-duplex, synchronous, serial bus.'
6eb87578
GM
69 license = 'gplv2+'
70 inputs = ['logic']
71 outputs = ['spi']
6b5b91d2 72 probes = [
49e8a4d6 73 {'id': 'clk', 'name': 'CLK', 'desc': 'Clock'},
6b5b91d2 74 ]
efa64173 75 optional_probes = [
49e8a4d6
UH
76 {'id': 'miso', 'name': 'MISO', 'desc': 'Master in, slave out'},
77 {'id': 'mosi', 'name': 'MOSI', 'desc': 'Master out, slave in'},
78 {'id': 'cs', 'name': 'CS#', 'desc': 'Chip-select'},
efa64173 79 ]
84c1c0b5
BV
80 options = (
81 {'id': 'cs_polarity', 'desc': 'CS# polarity', 'default': 'active-low',
82 'values': ('active-low', 'active-high')},
83 {'id': 'cpol', 'desc': 'Clock polarity', 'default': 0,
84 'values': (0, 1)},
85 {'id': 'cpha', 'desc': 'Clock phase', 'default': 0,
86 'values': (0, 1)},
87 {'id': 'bitorder', 'desc': 'Bit order within the SPI data',
88 'default': 'msb-first', 'values': ('msb-first', 'lsb-first')},
89 {'id': 'wordsize', 'desc': 'Word size of SPI data', 'default': 8},
90 )
b1bb5eed 91 annotations = [
cddd11bc
UH
92 ['miso-data', 'MISO data'],
93 ['mosi-data', 'MOSI data'],
94 ['miso-bits', 'MISO bits'],
95 ['mosi-bits', 'MOSI bits'],
9f2f42c0 96 ['warnings', 'Human-readable warnings'],
b1bb5eed 97 ]
06b52ebb 98 annotation_rows = (
cddd11bc
UH
99 ('miso-data', 'MISO data', (0,)),
100 ('miso-bits', 'MISO bits', (2,)),
101 ('mosi-data', 'MOSI data', (1,)),
102 ('mosi-bits', 'MOSI bits', (3,)),
103 ('other', 'Other', (4,)),
06b52ebb 104 )
6eb87578 105
3643fc3f 106 def __init__(self):
8a3c8792 107 self.samplerate = None
bcd14870 108 self.oldclk = 1
a10bfc48 109 self.bitcount = 0
bbc100f7 110 self.misodata = self.mosidata = 0
cddd11bc 111 self.misobits = []
bbc100f7 112 self.mosibits = []
ec0afe27 113 self.startsample = -1
d6bace96 114 self.samplenum = -1
bb08f4b3 115 self.cs_was_deasserted = False
3e3c0330 116 self.oldcs = -1
2fcd7c22 117 self.oldpins = None
bbc100f7 118 self.have_cs = self.have_miso = self.have_mosi = None
191ec8c5 119 self.state = 'IDLE'
6eb87578 120
8a3c8792
BV
121 def metadata(self, key, value):
122 if key == srd.SRD_CONF_SAMPLERATE:
123 self.samplerate = value
124
8915b346 125 def start(self):
c515eed7 126 self.out_python = self.register(srd.OUTPUT_PYTHON)
be465111 127 self.out_ann = self.register(srd.OUTPUT_ANN)
8a3c8792
BV
128 self.out_bitrate = self.register(srd.OUTPUT_META,
129 meta=(int, 'Bitrate', 'Bitrate during transfers'))
3643fc3f 130
ec0afe27
UH
131 def putw(self, data):
132 self.put(self.startsample, self.samplenum, self.out_ann, data)
133
bbc100f7
UH
134 def putdata(self):
135 # Pass MISO and MOSI bits and then data to the next PD up the stack.
136 so = self.misodata if self.have_miso else None
137 si = self.mosidata if self.have_mosi else None
138 so_bits = self.misobits if self.have_miso else None
139 si_bits = self.mosibits if self.have_mosi else None
7c09dbb2
UH
140
141 if self.have_miso:
142 ss, es = self.misobits[-1][1], self.misobits[0][2]
143 if self.have_mosi:
144 ss, es = self.mosibits[-1][1], self.mosibits[0][2]
145
146 self.put(ss, es, self.out_python, ['BITS', si_bits, so_bits])
147 self.put(ss, es, self.out_python, ['DATA', si, so])
cddd11bc 148
bbc100f7
UH
149 # Bit annotations.
150 if self.have_miso:
151 for bit in self.misobits:
152 self.put(bit[1], bit[2], self.out_ann, [2, ['%d' % bit[0]]])
153 if self.have_mosi:
154 for bit in self.mosibits:
155 self.put(bit[1], bit[2], self.out_ann, [3, ['%d' % bit[0]]])
156
157 # Dataword annotations.
158 if self.have_miso:
808c6e74 159 self.put(ss, es, self.out_ann, [0, ['%02X' % self.misodata]])
bbc100f7 160 if self.have_mosi:
808c6e74 161 self.put(ss, es, self.out_ann, [1, ['%02X' % self.mosidata]])
cddd11bc 162
d482a2d3
UH
163 def reset_decoder_state(self):
164 self.misodata = 0 if self.have_miso else None
165 self.mosidata = 0 if self.have_mosi else None
166 self.misobits = [] if self.have_miso else None
167 self.mosibits = [] if self.have_mosi else None
168 self.bitcount = 0
169
bcd14870 170 def handle_bit(self, miso, mosi, clk, cs):
cddd11bc 171 # If this is the first bit of a dataword, save its sample number.
191ec8c5
UH
172 if self.bitcount == 0:
173 self.startsample = self.samplenum
bb08f4b3 174 self.cs_was_deasserted = False
efa64173
UH
175 if self.have_cs:
176 active_low = (self.options['cs_polarity'] == 'active-low')
bb08f4b3 177 deasserted = (cs == 1) if active_low else (cs == 0)
efa64173 178 if deasserted:
bb08f4b3 179 self.cs_was_deasserted = True
2fcd7c22 180
191ec8c5 181 ws = self.options['wordsize']
d6bace96 182
bbc100f7
UH
183 # Receive MISO bit into our shift register.
184 if self.have_miso:
185 if self.options['bitorder'] == 'msb-first':
186 self.misodata |= miso << (ws - 1 - self.bitcount)
187 else:
188 self.misodata |= miso << self.bitcount
189
191ec8c5 190 # Receive MOSI bit into our shift register.
12549f11
UH
191 if self.have_mosi:
192 if self.options['bitorder'] == 'msb-first':
193 self.mosidata |= mosi << (ws - 1 - self.bitcount)
194 else:
195 self.mosidata |= mosi << self.bitcount
3e3c0330 196
808c6e74 197 # Guesstimate the endsample for this bit (can be overridden below).
bbc100f7
UH
198 es = self.samplenum
199 if self.bitcount > 0:
8e8096e8
UH
200 if self.have_miso:
201 es += self.samplenum - self.misobits[0][1]
202 elif self.have_mosi:
203 es += self.samplenum - self.mosibits[0][1]
c94c8c91 204
cddd11bc 205 if self.have_miso:
d78e0beb 206 self.misobits.insert(0, [miso, self.samplenum, es])
cddd11bc 207 if self.have_mosi:
d78e0beb 208 self.mosibits.insert(0, [mosi, self.samplenum, es])
bbc100f7
UH
209
210 if self.bitcount > 0 and self.have_miso:
d78e0beb 211 self.misobits[1][2] = self.samplenum
bbc100f7 212 if self.bitcount > 0 and self.have_mosi:
d78e0beb 213 self.mosibits[1][2] = self.samplenum
cddd11bc 214
191ec8c5 215 self.bitcount += 1
1ea831e9 216
191ec8c5
UH
217 # Continue to receive if not enough bits were received, yet.
218 if self.bitcount != ws:
219 return
b1bb5eed 220
bbc100f7 221 self.putdata()
12549f11
UH
222
223 # Meta bitrate.
bbc100f7
UH
224 elapsed = 1 / float(self.samplerate)
225 elapsed *= (self.samplenum - self.startsample + 1)
8a3c8792
BV
226 bitrate = int(1 / elapsed * self.options['wordsize'])
227 self.put(self.startsample, self.samplenum, self.out_bitrate, bitrate)
228
bb08f4b3 229 if self.have_cs and self.cs_was_deasserted:
cddd11bc 230 self.putw([4, ['CS# was deasserted during this data word!']])
191ec8c5 231
d482a2d3 232 self.reset_decoder_state()
191ec8c5 233
bcd14870 234 def find_clk_edge(self, miso, mosi, clk, cs):
efa64173 235 if self.have_cs and self.oldcs != cs:
191ec8c5 236 # Send all CS# pin value changes.
c515eed7 237 self.put(self.samplenum, self.samplenum, self.out_python,
191ec8c5
UH
238 ['CS-CHANGE', self.oldcs, cs])
239 self.oldcs = cs
efa64173 240 # Reset decoder state when CS# changes (and the CS# pin is used).
d482a2d3 241 self.reset_decoder_state()
191ec8c5
UH
242
243 # Ignore sample if the clock pin hasn't changed.
bcd14870 244 if clk == self.oldclk:
191ec8c5 245 return
b1bb5eed 246
bcd14870 247 self.oldclk = clk
b1bb5eed 248
191ec8c5
UH
249 # Sample data on rising/falling clock edge (depends on mode).
250 mode = spi_mode[self.options['cpol'], self.options['cpha']]
bcd14870 251 if mode == 0 and clk == 0: # Sample on rising clock edge
191ec8c5 252 return
bcd14870 253 elif mode == 1 and clk == 1: # Sample on falling clock edge
191ec8c5 254 return
bcd14870 255 elif mode == 2 and clk == 1: # Sample on falling clock edge
191ec8c5 256 return
bcd14870 257 elif mode == 3 and clk == 0: # Sample on rising clock edge
191ec8c5
UH
258 return
259
260 # Found the correct clock edge, now get the SPI bit(s).
bcd14870 261 self.handle_bit(miso, mosi, clk, cs)
191ec8c5
UH
262
263 def decode(self, ss, es, data):
8a3c8792
BV
264 if self.samplerate is None:
265 raise Exception("Cannot decode without samplerate.")
12549f11 266 # Either MISO or MOSI can be omitted (but not both). CS# is optional.
191ec8c5 267 for (self.samplenum, pins) in data:
01329e88 268
191ec8c5
UH
269 # Ignore identical samples early on (for performance reasons).
270 if self.oldpins == pins:
271 continue
bcd14870 272 self.oldpins, (clk, miso, mosi, cs) = pins, pins
12549f11
UH
273 self.have_miso = (miso in (0, 1))
274 self.have_mosi = (mosi in (0, 1))
efa64173 275 self.have_cs = (cs in (0, 1))
b1bb5eed 276
9ed11500
UH
277 # Either MISO or MOSI (but not both) can be omitted.
278 if not (self.have_miso or self.have_mosi):
279 raise Exception('Either MISO or MOSI (or both) pins required.')
280
191ec8c5
UH
281 # State machine.
282 if self.state == 'IDLE':
bcd14870 283 self.find_clk_edge(miso, mosi, clk, cs)
191ec8c5
UH
284 else:
285 raise Exception('Invalid state: %s' % self.state)
ad2dc0de 286