]> sigrok.org Git - libsigrokdecode.git/blame - decoders/spi/pd.py
s/out_proto/out_python/.
[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.
0702e0cf
UH
35 - 'CS CHANGE': <data1> is the old CS# pin value, <data2> is the new value.
36 Both data items are Python numbers (0/1), not strings.
37
38Examples:
39 ['CS-CHANGE', 1, 0]
40 ['DATA', 0xff, 0x3a]
41 ['DATA', 0x65, 0x00]
12549f11
UH
42 ['DATA', 0xa8, None]
43 ['DATA', None, 0x55]
0702e0cf
UH
44 ['CS-CHANGE', 0, 1]
45'''
46
8a7ce2a3 47# Key: (CPOL, CPHA). Value: SPI mode.
94bbdb9a
UH
48# Clock polarity (CPOL) = 0/1: Clock is low/high when inactive.
49# Clock phase (CPHA) = 0/1: Data is valid on the leading/trailing clock edge.
c94c8c91
UH
50spi_mode = {
51 (0, 0): 0, # Mode 0
52 (0, 1): 1, # Mode 1
53 (1, 0): 2, # Mode 2
54 (1, 1): 3, # Mode 3
55}
56
677d597b 57class Decoder(srd.Decoder):
a2c2afd9 58 api_version = 1
67e847fd 59 id = 'spi'
2b7d0e2b 60 name = 'SPI'
3d3da57d 61 longname = 'Serial Peripheral Interface'
a465436e 62 desc = 'Full-duplex, synchronous, serial bus.'
6eb87578
GM
63 license = 'gplv2+'
64 inputs = ['logic']
65 outputs = ['spi']
6b5b91d2 66 probes = [
bcd14870 67 {'id': 'clk', 'name': 'CLK', 'desc': 'SPI clock line'},
6b5b91d2 68 ]
efa64173 69 optional_probes = [
12549f11
UH
70 {'id': 'miso', 'name': 'MISO',
71 'desc': 'SPI MISO line (master in, slave out)'},
72 {'id': 'mosi', 'name': 'MOSI',
73 'desc': 'SPI MOSI line (master out, slave in)'},
efa64173
UH
74 {'id': 'cs', 'name': 'CS#', 'desc': 'SPI chip-select line'},
75 ]
238b4080 76 options = {
94bbdb9a
UH
77 'cs_polarity': ['CS# polarity', 'active-low'],
78 'cpol': ['Clock polarity', 0],
79 'cpha': ['Clock phase', 0],
80 'bitorder': ['Bit order within the SPI data', 'msb-first'],
c94c8c91 81 'wordsize': ['Word size of SPI data', 8], # 1-64?
3eda7779 82 'format': ['Data format', 'hex'],
238b4080 83 }
b1bb5eed 84 annotations = [
9f2f42c0
UH
85 ['miso-data', 'MISO SPI data'],
86 ['mosi-data', 'MOSI SPI data'],
87 ['warnings', 'Human-readable warnings'],
b1bb5eed 88 ]
6eb87578 89
3643fc3f 90 def __init__(self):
8a3c8792 91 self.samplerate = None
bcd14870 92 self.oldclk = 1
a10bfc48 93 self.bitcount = 0
4917bb31 94 self.mosidata = 0
d6bace96 95 self.misodata = 0
ec0afe27 96 self.startsample = -1
d6bace96 97 self.samplenum = -1
01329e88 98 self.cs_was_deasserted_during_data_word = 0
3e3c0330 99 self.oldcs = -1
2fcd7c22 100 self.oldpins = None
12549f11
UH
101 self.have_cs = None
102 self.have_miso = None
103 self.have_mosi = None
191ec8c5 104 self.state = 'IDLE'
6eb87578 105
8a3c8792
BV
106 def metadata(self, key, value):
107 if key == srd.SRD_CONF_SAMPLERATE:
108 self.samplerate = value
109
8915b346 110 def start(self):
c515eed7 111 self.out_python = self.register(srd.OUTPUT_PYTHON)
be465111 112 self.out_ann = self.register(srd.OUTPUT_ANN)
8a3c8792
BV
113 self.out_bitrate = self.register(srd.OUTPUT_META,
114 meta=(int, 'Bitrate', 'Bitrate during transfers'))
3643fc3f 115
ec0afe27 116 def putpw(self, data):
c515eed7 117 self.put(self.startsample, self.samplenum, self.out_python, data)
ec0afe27
UH
118
119 def putw(self, data):
120 self.put(self.startsample, self.samplenum, self.out_ann, data)
121
bcd14870 122 def handle_bit(self, miso, mosi, clk, cs):
191ec8c5
UH
123 # If this is the first bit, save its sample number.
124 if self.bitcount == 0:
125 self.startsample = self.samplenum
efa64173
UH
126 if self.have_cs:
127 active_low = (self.options['cs_polarity'] == 'active-low')
128 deasserted = cs if active_low else not cs
129 if deasserted:
130 self.cs_was_deasserted_during_data_word = 1
2fcd7c22 131
191ec8c5 132 ws = self.options['wordsize']
d6bace96 133
191ec8c5 134 # Receive MOSI bit into our shift register.
12549f11
UH
135 if self.have_mosi:
136 if self.options['bitorder'] == 'msb-first':
137 self.mosidata |= mosi << (ws - 1 - self.bitcount)
138 else:
139 self.mosidata |= mosi << self.bitcount
3e3c0330 140
191ec8c5 141 # Receive MISO bit into our shift register.
12549f11
UH
142 if self.have_miso:
143 if self.options['bitorder'] == 'msb-first':
144 self.misodata |= miso << (ws - 1 - self.bitcount)
145 else:
146 self.misodata |= miso << self.bitcount
c94c8c91 147
191ec8c5 148 self.bitcount += 1
1ea831e9 149
191ec8c5
UH
150 # Continue to receive if not enough bits were received, yet.
151 if self.bitcount != ws:
152 return
b1bb5eed 153
12549f11
UH
154 si = self.mosidata if self.have_mosi else None
155 so = self.misodata if self.have_miso else None
8a3c8792 156
12549f11
UH
157 # Pass MOSI and MISO to the next PD up the stack.
158 self.putpw(['DATA', si, so])
b1bb5eed 159
12549f11
UH
160 # Annotations.
161 if self.have_miso:
162 self.putw([0, ['%02X' % self.misodata]])
163 if self.have_mosi:
164 self.putw([1, ['%02X' % self.mosidata]])
165
166 # Meta bitrate.
8a3c8792
BV
167 elapsed = 1 / float(self.samplerate) * (self.samplenum - self.startsample + 1)
168 bitrate = int(1 / elapsed * self.options['wordsize'])
169 self.put(self.startsample, self.samplenum, self.out_bitrate, bitrate)
170
12549f11 171 if self.have_cs and self.cs_was_deasserted_during_data_word:
c1411010 172 self.putw([2, ['CS# was deasserted during this data word!']])
191ec8c5
UH
173
174 # Reset decoder state.
12549f11
UH
175 self.misodata = 0 if self.have_miso else None
176 self.mosidata = 0 if self.have_mosi else None
177 self.bitcount = 0
191ec8c5 178
bcd14870 179 def find_clk_edge(self, miso, mosi, clk, cs):
efa64173 180 if self.have_cs and self.oldcs != cs:
191ec8c5 181 # Send all CS# pin value changes.
c515eed7 182 self.put(self.samplenum, self.samplenum, self.out_python,
191ec8c5
UH
183 ['CS-CHANGE', self.oldcs, cs])
184 self.oldcs = cs
efa64173 185 # Reset decoder state when CS# changes (and the CS# pin is used).
12549f11
UH
186 self.misodata = 0 if self.have_miso else None
187 self.mosidata = 0 if self.have_mosi else None
188 self.bitcount = 0
191ec8c5
UH
189
190 # Ignore sample if the clock pin hasn't changed.
bcd14870 191 if clk == self.oldclk:
191ec8c5 192 return
b1bb5eed 193
bcd14870 194 self.oldclk = clk
b1bb5eed 195
191ec8c5
UH
196 # Sample data on rising/falling clock edge (depends on mode).
197 mode = spi_mode[self.options['cpol'], self.options['cpha']]
bcd14870 198 if mode == 0 and clk == 0: # Sample on rising clock edge
191ec8c5 199 return
bcd14870 200 elif mode == 1 and clk == 1: # Sample on falling clock edge
191ec8c5 201 return
bcd14870 202 elif mode == 2 and clk == 1: # Sample on falling clock edge
191ec8c5 203 return
bcd14870 204 elif mode == 3 and clk == 0: # Sample on rising clock edge
191ec8c5
UH
205 return
206
207 # Found the correct clock edge, now get the SPI bit(s).
bcd14870 208 self.handle_bit(miso, mosi, clk, cs)
191ec8c5
UH
209
210 def decode(self, ss, es, data):
8a3c8792
BV
211 if self.samplerate is None:
212 raise Exception("Cannot decode without samplerate.")
12549f11 213 # Either MISO or MOSI can be omitted (but not both). CS# is optional.
191ec8c5 214 for (self.samplenum, pins) in data:
01329e88 215
191ec8c5
UH
216 # Ignore identical samples early on (for performance reasons).
217 if self.oldpins == pins:
218 continue
bcd14870 219 self.oldpins, (clk, miso, mosi, cs) = pins, pins
12549f11
UH
220 self.have_miso = (miso in (0, 1))
221 self.have_mosi = (mosi in (0, 1))
efa64173 222 self.have_cs = (cs in (0, 1))
b1bb5eed 223
191ec8c5
UH
224 # State machine.
225 if self.state == 'IDLE':
bcd14870 226 self.find_clk_edge(miso, mosi, clk, cs)
191ec8c5
UH
227 else:
228 raise Exception('Invalid state: %s' % self.state)
ad2dc0de 229