]> sigrok.org Git - libsigrokdecode.git/blame - decoders/spi/pd.py
spi: Fix a bug when only supplying MOSI (but not MISO).
[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 ]
238b4080 80 options = {
94bbdb9a
UH
81 'cs_polarity': ['CS# polarity', 'active-low'],
82 'cpol': ['Clock polarity', 0],
83 'cpha': ['Clock phase', 0],
84 'bitorder': ['Bit order within the SPI data', 'msb-first'],
c94c8c91 85 'wordsize': ['Word size of SPI data', 8], # 1-64?
3eda7779 86 'format': ['Data format', 'hex'],
238b4080 87 }
b1bb5eed 88 annotations = [
cddd11bc
UH
89 ['miso-data', 'MISO data'],
90 ['mosi-data', 'MOSI data'],
91 ['miso-bits', 'MISO bits'],
92 ['mosi-bits', 'MOSI bits'],
9f2f42c0 93 ['warnings', 'Human-readable warnings'],
b1bb5eed 94 ]
06b52ebb 95 annotation_rows = (
cddd11bc
UH
96 ('miso-data', 'MISO data', (0,)),
97 ('miso-bits', 'MISO bits', (2,)),
98 ('mosi-data', 'MOSI data', (1,)),
99 ('mosi-bits', 'MOSI bits', (3,)),
100 ('other', 'Other', (4,)),
06b52ebb 101 )
6eb87578 102
3643fc3f 103 def __init__(self):
8a3c8792 104 self.samplerate = None
bcd14870 105 self.oldclk = 1
a10bfc48 106 self.bitcount = 0
bbc100f7 107 self.misodata = self.mosidata = 0
cddd11bc 108 self.misobits = []
bbc100f7 109 self.mosibits = []
ec0afe27 110 self.startsample = -1
d6bace96 111 self.samplenum = -1
bb08f4b3 112 self.cs_was_deasserted = False
3e3c0330 113 self.oldcs = -1
2fcd7c22 114 self.oldpins = None
bbc100f7 115 self.have_cs = self.have_miso = self.have_mosi = None
191ec8c5 116 self.state = 'IDLE'
6eb87578 117
8a3c8792
BV
118 def metadata(self, key, value):
119 if key == srd.SRD_CONF_SAMPLERATE:
120 self.samplerate = value
121
8915b346 122 def start(self):
c515eed7 123 self.out_python = self.register(srd.OUTPUT_PYTHON)
be465111 124 self.out_ann = self.register(srd.OUTPUT_ANN)
8a3c8792
BV
125 self.out_bitrate = self.register(srd.OUTPUT_META,
126 meta=(int, 'Bitrate', 'Bitrate during transfers'))
3643fc3f 127
ec0afe27 128 def putpw(self, data):
c515eed7 129 self.put(self.startsample, self.samplenum, self.out_python, data)
ec0afe27
UH
130
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
140 self.putpw(['BITS', si_bits, so_bits])
141 self.putpw(['DATA', si, so])
cddd11bc 142
bbc100f7
UH
143 # Bit annotations.
144 if self.have_miso:
145 for bit in self.misobits:
146 self.put(bit[1], bit[2], self.out_ann, [2, ['%d' % bit[0]]])
147 if self.have_mosi:
148 for bit in self.mosibits:
149 self.put(bit[1], bit[2], self.out_ann, [3, ['%d' % bit[0]]])
150
151 # Dataword annotations.
152 if self.have_miso:
d78e0beb 153 ss, es = self.misobits[-1][1], self.misobits[0][2]
808c6e74 154 self.put(ss, es, self.out_ann, [0, ['%02X' % self.misodata]])
bbc100f7 155 if self.have_mosi:
d78e0beb 156 ss, es = self.mosibits[-1][1], self.mosibits[0][2]
808c6e74 157 self.put(ss, es, self.out_ann, [1, ['%02X' % self.mosidata]])
cddd11bc 158
d482a2d3
UH
159 def reset_decoder_state(self):
160 self.misodata = 0 if self.have_miso else None
161 self.mosidata = 0 if self.have_mosi else None
162 self.misobits = [] if self.have_miso else None
163 self.mosibits = [] if self.have_mosi else None
164 self.bitcount = 0
165
bcd14870 166 def handle_bit(self, miso, mosi, clk, cs):
cddd11bc 167 # If this is the first bit of a dataword, save its sample number.
191ec8c5
UH
168 if self.bitcount == 0:
169 self.startsample = self.samplenum
bb08f4b3 170 self.cs_was_deasserted = False
efa64173
UH
171 if self.have_cs:
172 active_low = (self.options['cs_polarity'] == 'active-low')
bb08f4b3 173 deasserted = (cs == 1) if active_low else (cs == 0)
efa64173 174 if deasserted:
bb08f4b3 175 self.cs_was_deasserted = True
2fcd7c22 176
191ec8c5 177 ws = self.options['wordsize']
d6bace96 178
bbc100f7
UH
179 # Receive MISO bit into our shift register.
180 if self.have_miso:
181 if self.options['bitorder'] == 'msb-first':
182 self.misodata |= miso << (ws - 1 - self.bitcount)
183 else:
184 self.misodata |= miso << self.bitcount
185
191ec8c5 186 # Receive MOSI bit into our shift register.
12549f11
UH
187 if self.have_mosi:
188 if self.options['bitorder'] == 'msb-first':
189 self.mosidata |= mosi << (ws - 1 - self.bitcount)
190 else:
191 self.mosidata |= mosi << self.bitcount
3e3c0330 192
808c6e74 193 # Guesstimate the endsample for this bit (can be overridden below).
bbc100f7
UH
194 es = self.samplenum
195 if self.bitcount > 0:
8e8096e8
UH
196 if self.have_miso:
197 es += self.samplenum - self.misobits[0][1]
198 elif self.have_mosi:
199 es += self.samplenum - self.mosibits[0][1]
c94c8c91 200
cddd11bc 201 if self.have_miso:
d78e0beb 202 self.misobits.insert(0, [miso, self.samplenum, es])
cddd11bc 203 if self.have_mosi:
d78e0beb 204 self.mosibits.insert(0, [mosi, self.samplenum, es])
bbc100f7
UH
205
206 if self.bitcount > 0 and self.have_miso:
d78e0beb 207 self.misobits[1][2] = self.samplenum
bbc100f7 208 if self.bitcount > 0 and self.have_mosi:
d78e0beb 209 self.mosibits[1][2] = self.samplenum
cddd11bc 210
191ec8c5 211 self.bitcount += 1
1ea831e9 212
191ec8c5
UH
213 # Continue to receive if not enough bits were received, yet.
214 if self.bitcount != ws:
215 return
b1bb5eed 216
bbc100f7 217 self.putdata()
12549f11
UH
218
219 # Meta bitrate.
bbc100f7
UH
220 elapsed = 1 / float(self.samplerate)
221 elapsed *= (self.samplenum - self.startsample + 1)
8a3c8792
BV
222 bitrate = int(1 / elapsed * self.options['wordsize'])
223 self.put(self.startsample, self.samplenum, self.out_bitrate, bitrate)
224
bb08f4b3 225 if self.have_cs and self.cs_was_deasserted:
cddd11bc 226 self.putw([4, ['CS# was deasserted during this data word!']])
191ec8c5 227
d482a2d3 228 self.reset_decoder_state()
191ec8c5 229
bcd14870 230 def find_clk_edge(self, miso, mosi, clk, cs):
efa64173 231 if self.have_cs and self.oldcs != cs:
191ec8c5 232 # Send all CS# pin value changes.
c515eed7 233 self.put(self.samplenum, self.samplenum, self.out_python,
191ec8c5
UH
234 ['CS-CHANGE', self.oldcs, cs])
235 self.oldcs = cs
efa64173 236 # Reset decoder state when CS# changes (and the CS# pin is used).
d482a2d3 237 self.reset_decoder_state()
191ec8c5
UH
238
239 # Ignore sample if the clock pin hasn't changed.
bcd14870 240 if clk == self.oldclk:
191ec8c5 241 return
b1bb5eed 242
bcd14870 243 self.oldclk = clk
b1bb5eed 244
191ec8c5
UH
245 # Sample data on rising/falling clock edge (depends on mode).
246 mode = spi_mode[self.options['cpol'], self.options['cpha']]
bcd14870 247 if mode == 0 and clk == 0: # Sample on rising clock edge
191ec8c5 248 return
bcd14870 249 elif mode == 1 and clk == 1: # Sample on falling clock edge
191ec8c5 250 return
bcd14870 251 elif mode == 2 and clk == 1: # Sample on falling clock edge
191ec8c5 252 return
bcd14870 253 elif mode == 3 and clk == 0: # Sample on rising clock edge
191ec8c5
UH
254 return
255
256 # Found the correct clock edge, now get the SPI bit(s).
bcd14870 257 self.handle_bit(miso, mosi, clk, cs)
191ec8c5
UH
258
259 def decode(self, ss, es, data):
8a3c8792
BV
260 if self.samplerate is None:
261 raise Exception("Cannot decode without samplerate.")
12549f11 262 # Either MISO or MOSI can be omitted (but not both). CS# is optional.
191ec8c5 263 for (self.samplenum, pins) in data:
01329e88 264
191ec8c5
UH
265 # Ignore identical samples early on (for performance reasons).
266 if self.oldpins == pins:
267 continue
bcd14870 268 self.oldpins, (clk, miso, mosi, cs) = pins, pins
12549f11
UH
269 self.have_miso = (miso in (0, 1))
270 self.have_mosi = (mosi in (0, 1))
efa64173 271 self.have_cs = (cs in (0, 1))
b1bb5eed 272
9ed11500
UH
273 # Either MISO or MOSI (but not both) can be omitted.
274 if not (self.have_miso or self.have_mosi):
275 raise Exception('Either MISO or MOSI (or both) pins required.')
276
191ec8c5
UH
277 # State machine.
278 if self.state == 'IDLE':
bcd14870 279 self.find_clk_edge(miso, mosi, clk, cs)
191ec8c5
UH
280 else:
281 raise Exception('Invalid state: %s' % self.state)
ad2dc0de 282