]> sigrok.org Git - libsigrokdecode.git/blame - decoders/eeprom24xx/pd.py
Add 24xx I2C EEPROM protocol decoder.
[libsigrokdecode.git] / decoders / eeprom24xx / pd.py
CommitLineData
c4d52210
UH
1##
2## This file is part of the libsigrokdecode project.
3##
4## Copyright (C) 2014 Uwe Hermann <uwe@hermann-uwe.de>
5##
6## This program is free software; you can redistribute it and/or modify
7## it under the terms of the GNU General Public License as published by
8## the Free Software Foundation; either version 2 of the License, or
9## (at your option) any later version.
10##
11## This program is distributed in the hope that it will be useful,
12## but WITHOUT ANY WARRANTY; without even the implied warranty of
13## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14## GNU General Public License for more details.
15##
16## You should have received a copy of the GNU General Public License
17## along with this program; if not, write to the Free Software
18## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19##
20
21import sigrokdecode as srd
22from .lists import *
23
24class Decoder(srd.Decoder):
25 api_version = 2
26 id = 'eeprom24xx'
27 name = '24xx EEPROM'
28 longname = '24xx I²C EEPROM'
29 desc = '24xx series I²C EEPROM protocol.'
30 license = 'gplv2+'
31 inputs = ['i2c']
32 outputs = ['eeprom24xx']
33 options = (
34 {'id': 'chip', 'desc': 'Chip', 'default': 'generic',
35 'values': tuple(chips.keys())},
36 {'id': 'addr_counter', 'desc': 'Initial address counter value',
37 'default': 0},
38 )
39 annotations = (
40 # Warnings
41 ('warnings', 'Warnings'),
42 # Bits/bytes
43 ('control-code', 'Control code'),
44 ('address-pin', 'Address pin (A0/A1/A2)'),
45 ('rw-bit', 'Read/write bit'),
46 ('word-addr-byte', 'Word address byte'),
47 ('data-byte', 'Data byte'),
48 # Fields
49 ('control-word', 'Control word'),
50 ('word-addr', 'Word address'),
51 ('data', 'Data'),
52 # Operations
53 ('byte-write', 'Byte write'),
54 ('page-write', 'Page write'),
55 ('cur-addr-read', 'Current address read'),
56 ('random-read', 'Random read'),
57 ('seq-random-read', 'Sequential random read'),
58 ('seq-cur-addr-read', 'Sequential current address read'),
59 ('ack-polling', 'Acknowledge polling'),
60 ('set-bank-addr', 'Set bank address'), # SBA. Only 34AA04.
61 ('read-bank-addr', 'Read bank address'), # RBA. Only 34AA04.
62 ('set-wp', 'Set write protection'), # SWP
63 ('clear-all-wp', 'Clear all write protection'), # CWP
64 ('read-wp', 'Read write protection status'), # RPS
65 )
66 annotation_rows = (
67 ('bits-bytes', 'Bits/bytes', (1, 2, 3, 4, 5)),
68 ('fields', 'Fields', (6, 7, 8)),
69 ('ops', 'Operations', tuple(range(9, 21))),
70 ('warnings', 'Warnings', (0,)),
71 )
72 binary = (
73 ('binary', 'Binary'),
74 )
75
76 def __init__(self, **kwargs):
77 self.reset()
78
79 def start(self):
80 self.out_ann = self.register(srd.OUTPUT_ANN)
81 self.out_bin = self.register(srd.OUTPUT_BINARY)
82 self.chip = chips[self.options['chip']]
83 self.addr_counter = self.options['addr_counter']
84
85 def putb(self, data):
86 self.put(self.ss_block, self.es_block, self.out_ann, data)
87
88 def putbin(self, data):
89 self.put(self.ss_block, self.es_block, self.out_bin, data)
90
91 def putbits(self, bit1, bit2, bits, data):
92 self.put(bits[bit1][1], bits[bit2][2], self.out_ann, data)
93
94 def reset(self):
95 self.state = 'WAIT FOR START'
96 self.packets = []
97 self.bytebuf = []
98 self.is_cur_addr_read = False
99 self.is_random_access_read = False
100 self.is_seq_random_read = False
101 self.is_byte_write = False
102 self.is_page_write = False
103
104 def packet_append(self):
105 self.packets.append([self.ss, self.es, self.cmd, self.databyte, self.bits])
106 if self.cmd in ('DATA READ', 'DATA WRITE'):
107 self.bytebuf.append(self.databyte)
108
109 def hexbytes(self, idx):
110 return ' '.join(['%02X' % b for b in self.bytebuf[idx:]])
111
112 def put_control_word(self, bits):
113 s = ''.join(['%d' % b[0] for b in reversed(bits[4:])])
114 self.putbits(7, 4, bits, [1, ['Control code bits: ' + s,
115 'Control code: ' + s, 'Ctrl code: ' + s, 'Ctrl code', 'Ctrl', 'C']])
116 for i in reversed(range(self.chip['addr_pins'])):
117 self.putbits(i + 1, i + 1, bits,
118 [2, ['Address bit %d: %d' % (i, bits[i + 1][0]),
119 'Addr bit %d' % i, 'A%d' % i, 'A']])
120 s1 = 'read' if bits[0][0] == 1 else 'write'
121 s2 = 'R' if bits[0][0] == 1 else 'W'
122 self.putbits(0, 0, bits, [3, ['R/W bit: ' + s1, 'R/W', 'RW', s2]])
123 self.putbits(7, 0, bits, [6, ['Control word', 'Control', 'CW', 'C']])
124
125 def put_word_addr(self, p):
126 if self.chip['addr_bytes'] == 1:
127 a = p[1][3]
128 self.put(p[1][0], p[1][1], self.out_ann,
129 [4, ['Word address byte: %02X' % a, 'Word addr byte: %02X' % a,
130 'Addr: %02X' % a, 'A: %02X' % a, '%02X' % a]])
131 self.put(p[1][0], p[1][1], self.out_ann, [7, ['Word address',
132 'Word addr', 'Addr', 'A']])
133 self.addr_counter = a
134 else:
135 a = p[1][3]
136 self.put(p[1][0], p[1][1], self.out_ann,
137 [4, ['Word address high byte: %02X' % a,
138 'Word addr high byte: %02X' % a,
139 'Addr high: %02X' % a, 'AH: %02X' % a, '%02X' % a]])
140 a = p[2][3]
141 self.put(p[2][0], p[2][1], self.out_ann,
142 [4, ['Word address low byte: %02X' % a,
143 'Word addr low byte: %02X' % a,
144 'Addr low: %02X' % a, 'AL: %02X' % a, '%02X' % a]])
145 self.put(p[1][0], p[2][1], self.out_ann, [7, ['Word address',
146 'Word addr', 'Addr', 'A']])
147 self.addr_counter = (p[1][3] << 8) | p[2][3]
148
149 def put_data_byte(self, p):
150 if self.chip['addr_bytes'] == 1:
151 s = '%02X' % self.addr_counter
152 else:
153 s = '%04X' % self.addr_counter
154 self.put(p[0], p[1], self.out_ann, [5, ['Data byte %s: %02X' % \
155 (s, p[3]), 'Data byte: %02X' % p[3], \
156 'Byte: %02X' % p[3], 'DB: %02X' % p[3], '%02X' % p[3]]])
157
158 def put_data_bytes(self, idx, cls, s):
159 for p in self.packets[idx:]:
160 self.put_data_byte(p)
161 self.addr_counter += 1
162 self.put(self.packets[idx][0], self.packets[-1][1], self.out_ann,
163 [8, ['Data', 'D']])
164 a = ''.join(['%s' % c[0] for c in s.split()]).upper()
165 self.putb([cls, ['%s (%s): %s' % (s, self.addr_and_len(), \
166 self.hexbytes(self.chip['addr_bytes'])),
167 '%s (%s)' % (s, self.addr_and_len()), s, a, s[0]]])
168 self.putbin((0, bytes(self.bytebuf[self.chip['addr_bytes']:])))
169
170 def addr_and_len(self):
171 if self.chip['addr_bytes'] == 1:
172 a = '%02X' % self.bytebuf[0]
173 else:
174 a = '%02X%02X' % tuple(self.bytebuf[:2])
175 num_data_bytes = len(self.bytebuf) - self.chip['addr_bytes']
176 d = '%d bytes' % num_data_bytes
177 if num_data_bytes <= 1:
178 d = d[:-1]
179 return 'addr=%s, %s' % (a, d)
180
181 def decide_on_seq_or_rnd_read(self):
182 if len(self.bytebuf) < 2:
183 self.reset()
184 return
185 if len(self.bytebuf) == 2:
186 self.is_random_access_read = True
187 else:
188 self.is_seq_random_read = True
189
190 def put_operation(self):
191 idx = 1 + self.chip['addr_bytes']
192 if self.is_byte_write:
193 # Byte write: word address, one data byte.
194 self.put_word_addr(self.packets)
195 self.put_data_bytes(idx, 9, 'Byte write')
196 elif self.is_page_write:
197 # Page write: word address, two or more data bytes.
198 self.put_word_addr(self.packets)
199 intitial_addr = self.addr_counter
200 self.put_data_bytes(idx, 10, 'Page write')
201 num_bytes_to_write = len(self.packets[idx:])
202 if num_bytes_to_write > self.chip['page_size']:
203 self.putb([0, ['Warning: Wrote %d bytes but page size is '
204 'only %d bytes!' % (num_bytes_to_write,
205 self.chip['page_size'])]])
206 page1 = int(intitial_addr / self.chip['page_size'])
207 page2 = int((self.addr_counter - 1) / self.chip['page_size'])
208 if page1 != page2:
209 self.putb([0, ['Warning: Page write crossed page boundary '
210 'from page %d to %d!' % (page1, page2)]])
211 elif self.is_cur_addr_read:
212 # Current address read: no word address, one data byte.
213 self.put_data_byte(self.packets[1])
214 self.put(self.packets[1][0], self.packets[-1][1], self.out_ann,
215 [8, ['Data', 'D']])
216 self.putb([11, ['Current address read: %02X' % self.bytebuf[0],
217 'Current address read', 'Cur addr read', 'CAR', 'C']])
218 self.putbin((0, bytes([self.bytebuf[0]])))
219 self.addr_counter += 1
220 elif self.is_random_access_read:
221 # Random access read: word address, one data byte.
222 self.put_control_word(self.packets[idx][4])
223 self.put_word_addr(self.packets)
224 self.put_data_bytes(idx + 1, 12, 'Random access read')
225 elif self.is_seq_random_read:
226 # Sequential random read: word address, two or more data bytes.
227 self.put_control_word(self.packets[idx][4])
228 self.put_word_addr(self.packets)
229 self.put_data_bytes(idx + 1, 13, 'Sequential random read')
230
231 def handle_wait_for_start(self):
232 # Wait for an I²C START condition.
233 if self.cmd not in ('START', 'START REPEAT'):
234 return
235 self.ss_block = self.ss
236 self.state = 'GET CONTROL WORD'
237
238 def handle_get_control_word(self):
239 # The packet after START must be an ADDRESS READ or ADDRESS WRITE.
240 if self.cmd not in ('ADDRESS READ', 'ADDRESS WRITE'):
241 self.reset()
242 return
243 self.packet_append()
244 self.put_control_word(self.bits)
245 self.state = '%s GET ACK NACK AFTER CONTROL WORD' % self.cmd[8]
246
247 def handle_r_get_ack_nack_after_control_word(self):
248 if self.cmd == 'ACK':
249 self.state = 'R GET WORD ADDR OR BYTE'
250 elif self.cmd == 'NACK':
251 self.es_block = self.es
252 self.putb([0, ['Warning: No reply from slave!']])
253 self.reset()
254 else:
255 self.reset()
256
257 def handle_r_get_word_addr_or_byte(self):
258 if self.cmd == 'STOP':
259 self.es_block = self.es
260 self.putb([0, ['Warning: Slave replied, but master aborted!']])
261 self.reset()
262 return
263 elif self.cmd != 'DATA READ':
264 self.reset()
265 return
266 self.packet_append()
267 self.state = 'R GET ACK NACK AFTER WORD ADDR OR BYTE'
268
269 def handle_r_get_ack_nack_after_word_addr_or_byte(self):
270 if self.cmd == 'ACK':
271 self.state = 'R GET RESTART'
272 elif self.cmd == 'NACK':
273 self.is_cur_addr_read = True
274 self.state = 'GET STOP AFTER LAST BYTE'
275 else:
276 self.reset()
277
278 def handle_r_get_restart(self):
279 if self.cmd == 'RESTART':
280 self.state = 'R READ BYTE'
281 else:
282 self.reset()
283
284 def handle_r_read_byte(self):
285 if self.cmd == 'DATA READ':
286 self.packet_append()
287 self.state = 'R GET ACK NACK AFTER BYTE WAS READ'
288 else:
289 self.reset()
290
291 def handle_r_get_ack_nack_after_byte_was_read(self):
292 if self.cmd == 'ACK':
293 self.state = 'R READ BYTE'
294 elif self.cmd == 'NACK':
295 # It's either a RANDOM READ or a SEQUENTIAL READ.
296 self.state = 'GET STOP AFTER LAST BYTE'
297 else:
298 self.reset()
299
300 def handle_w_get_ack_nack_after_control_word(self):
301 if self.cmd == 'ACK':
302 self.state = 'W GET WORD ADDR'
303 elif self.cmd == 'NACK':
304 self.es_block = self.es
305 self.putb([0, ['Warning: No reply from slave!']])
306 self.reset()
307 else:
308 self.reset()
309
310 def handle_w_get_word_addr(self):
311 if self.cmd == 'STOP':
312 self.es_block = self.es
313 self.putb([0, ['Warning: Slave replied, but master aborted!']])
314 self.reset()
315 return
316 elif self.cmd != 'DATA WRITE':
317 self.reset()
318 return
319 self.packet_append()
320 self.state = 'W GET ACK AFTER WORD ADDR'
321
322 def handle_w_get_ack_after_word_addr(self):
323 if self.cmd == 'ACK':
324 self.state = 'W DETERMINE EEPROM READ OR WRITE'
325 else:
326 self.reset()
327
328 def handle_w_determine_eeprom_read_or_write(self):
329 if self.cmd == 'START REPEAT':
330 # It's either a RANDOM ACCESS READ or SEQUENTIAL RANDOM READ.
331 self.state = 'R2 GET CONTROL WORD'
332 elif self.cmd == 'DATA WRITE':
333 self.packet_append()
334 self.state = 'W GET ACK NACK AFTER BYTE WAS WRITTEN'
335 else:
336 self.reset()
337
338 def handle_w_write_byte(self):
339 if self.cmd == 'DATA WRITE':
340 self.packet_append()
341 self.state = 'W GET ACK NACK AFTER BYTE WAS WRITTEN'
342 elif self.cmd == 'STOP':
343 if len(self.bytebuf) < 2:
344 self.reset()
345 return
346 self.es_block = self.es
347 if len(self.bytebuf) == 2:
348 self.is_byte_write = True
349 else:
350 self.is_page_write = True
351 self.put_operation()
352 self.reset()
353 elif self.cmd == 'START REPEAT':
354 # It's either a RANDOM ACCESS READ or SEQUENTIAL RANDOM READ.
355 self.state = 'R2 GET CONTROL WORD'
356 else:
357 self.reset()
358
359 def handle_w_get_ack_nack_after_byte_was_written(self):
360 if self.cmd == 'ACK':
361 self.state = 'W WRITE BYTE'
362 else:
363 self.reset()
364
365 def handle_r2_get_control_word(self):
366 if self.cmd == 'ADDRESS READ':
367 self.packet_append()
368 self.state = 'R2 GET ACK AFTER ADDR READ'
369 else:
370 self.reset()
371
372 def handle_r2_get_ack_after_addr_read(self):
373 if self.cmd == 'ACK':
374 self.state = 'R2 READ BYTE'
375 else:
376 self.reset()
377
378 def handle_r2_read_byte(self):
379 if self.cmd == 'DATA READ':
380 self.packet_append()
381 self.state = 'R2 GET ACK NACK AFTER BYTE WAS READ'
382 elif self.cmd == 'STOP':
383 self.decide_on_seq_or_rnd_read()
384 self.es_block = self.es
385 self.putb([0, ['Warning: STOP expected after a NACK (not ACK)']])
386 self.put_operation()
387 self.reset()
388 else:
389 self.reset()
390
391 def handle_r2_get_ack_nack_after_byte_was_read(self):
392 if self.cmd == 'ACK':
393 self.state = 'R2 READ BYTE'
394 elif self.cmd == 'NACK':
395 self.decide_on_seq_or_rnd_read()
396 self.state = 'GET STOP AFTER LAST BYTE'
397 else:
398 self.reset()
399
400 def handle_get_stop_after_last_byte(self):
401 if self.cmd == 'STOP':
402 self.es_block = self.es
403 self.put_operation()
404 self.reset()
405 elif self.cmd == 'START REPEAT':
406 self.es_block = self.es
407 self.putb([0, ['Warning: STOP expected (not RESTART)']])
408 self.put_operation()
409 self.reset()
410 self.ss_block = self.ss
411 self.state = 'GET CONTROL WORD'
412 else:
413 self.reset()
414
415 def decode(self, ss, es, data):
416 self.cmd, self.databyte = data
417
418 # Collect the 'BITS' packet, then return. The next packet is
419 # guaranteed to belong to these bits we just stored.
420 if self.cmd == 'BITS':
421 self.bits = self.databyte
422 return
423
424 # Store the start/end samples of this I²C packet.
425 self.ss, self.es = ss, es
426
427 # State machine.
428 s = 'handle_%s' % self.state.lower().replace(' ', '_')
429 handle_state = getattr(self, s)
430 handle_state()