]> sigrok.org Git - libsigrokdecode.git/blob - decoders/avr_isp/pd.py
avr_isp: Add more parts
[libsigrokdecode.git] / decoders / avr_isp / pd.py
1 ##
2 ## This file is part of the libsigrokdecode project.
3 ##
4 ## Copyright (C) 2012-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, see <http://www.gnu.org/licenses/>.
18 ##
19
20 import sigrokdecode as srd
21 from .parts import *
22
23 class Ann:
24     PE, RSB0, RSB1, RSB2, CE, RFB, RHFB, REFB, \
25     RLB, REEM, RP, LPMP, WP, WARN, DEV, = range(15)
26
27 VENDOR_CODE_ATMEL = 0x1e
28
29 class Decoder(srd.Decoder):
30     api_version = 3
31     id = 'avr_isp'
32     name = 'AVR ISP'
33     longname = 'AVR In-System Programming'
34     desc = 'Atmel AVR In-System Programming (ISP) protocol.'
35     license = 'gplv2+'
36     inputs = ['spi']
37     outputs = []
38     tags = ['Debug/trace']
39     annotations = (
40         ('pe', 'Programming enable'),
41         ('rsb0', 'Read signature byte 0'),
42         ('rsb1', 'Read signature byte 1'),
43         ('rsb2', 'Read signature byte 2'),
44         ('ce', 'Chip erase'),
45         ('rfb', 'Read fuse bits'),
46         ('rhfb', 'Read high fuse bits'),
47         ('refb', 'Read extended fuse bits'),
48         ('rlb', 'Read lock bits'),
49         ('reem', 'Read EEPROM memory'),
50         ('rp', 'Read program memory'),
51         ('lpmp' , 'Load program memory page'),
52         ('wp', 'Write program memory'),
53         ('warning', 'Warning'),
54         ('dev', 'Device'),
55     )
56     annotation_rows = (
57         ('commands', 'Commands', (Ann.PE, Ann.RSB0, Ann.RSB1, Ann.RSB2,
58             Ann.CE, Ann.RFB, Ann.RHFB, Ann.REFB,
59             Ann.RLB, Ann.REEM, Ann.RP, Ann.LPMP, Ann.WP,)),
60         ('warnings', 'Warnings', (Ann.WARN,)),
61         ('devs', 'Devices', (Ann.DEV,)),
62     )
63
64     def __init__(self):
65         self.reset()
66
67     def reset(self):
68         self.state = 'IDLE'
69         self.mosi_bytes, self.miso_bytes = [], []
70         self.ss_cmd, self.es_cmd = 0, 0
71         self.xx, self.yy, self.zz, self.mm = 0, 0, 0, 0
72         self.ss_device = None
73
74     def start(self):
75         self.out_ann = self.register(srd.OUTPUT_ANN)
76
77     def putx(self, data):
78         self.put(self.ss_cmd, self.es_cmd, self.out_ann, data)
79
80     def handle_cmd_programming_enable(self, cmd, ret):
81         # Programming enable.
82         # Note: The chip doesn't send any ACK for 'Programming enable'.
83         self.putx([Ann.PE, ['Programming enable']])
84
85         # Sanity check on reply.
86         if ret[1:4] != [0xac, 0x53, cmd[2]]:
87             self.putx([Ann.WARN, ['Warning: Unexpected bytes in reply!']])
88
89     def handle_cmd_read_signature_byte_0x00(self, cmd, ret):
90         # Signature byte 0x00: vendor code.
91         self.vendor_code = ret[3]
92         v = vendor_code[self.vendor_code]
93         self.putx([Ann.RSB0, ['Vendor code: 0x%02x (%s)' % (ret[3], v)]])
94
95         # Store for later.
96         self.xx = cmd[1] # Same as ret[2].
97         self.yy = cmd[3]
98         self.zz = ret[0]
99
100         # Sanity check on reply.
101         if ret[1] != 0x30 or ret[2] != cmd[1]:
102             self.putx([Ann.WARN, ['Warning: Unexpected bytes in reply!']])
103
104         # Sanity check for the vendor code.
105         if self.vendor_code != VENDOR_CODE_ATMEL:
106             self.putx([Ann.WARN, ['Warning: Vendor code was not 0x1e (Atmel)!']])
107
108     def handle_cmd_read_signature_byte_0x01(self, cmd, ret):
109         # Signature byte 0x01: part family and memory size.
110         self.part_fam_flash_size = ret[3]
111         self.putx([Ann.RSB1, ['Part family / memory size: 0x%02x' % ret[3]]])
112
113         # Store for later.
114         self.mm = cmd[3]
115         self.ss_device = self.ss_cmd
116
117         # Sanity check on reply.
118         if ret[1] != 0x30 or ret[2] != cmd[1] or ret[0] != self.yy:
119             self.putx([Ann.WARN, ['Warning: Unexpected bytes in reply!']])
120
121     def handle_cmd_read_signature_byte_0x02(self, cmd, ret):
122         # Signature byte 0x02: part number.
123         self.part_number = ret[3]
124         self.putx([Ann.RSB2, ['Part number: 0x%02x' % ret[3]]])
125
126         p = part[(self.part_fam_flash_size, self.part_number)]
127         data = [Ann.DEV, ['Device: Atmel %s' % p]]
128         self.put(self.ss_device, self.es_cmd, self.out_ann, data)
129
130         # Sanity check on reply.
131         if ret[1] != 0x30 or ret[2] != self.xx or ret[0] != self.mm:
132             self.putx([Ann.WARN, ['Warning: Unexpected bytes in reply!']])
133
134         self.xx, self.yy, self.zz, self.mm = 0, 0, 0, 0
135
136     def handle_cmd_chip_erase(self, cmd, ret):
137         # Chip erase (erases both flash an EEPROM).
138         # Upon successful chip erase, the lock bits will also be erased.
139         # The only way to end a Chip Erase cycle is to release RESET#.
140         self.putx([Ann.CE, ['Chip erase']])
141
142         # TODO: Check/handle RESET#.
143
144         # Sanity check on reply.
145         bit = (ret[2] & (1 << 7)) >> 7
146         if ret[1] != 0xac or bit != 1 or ret[3] != cmd[2]:
147             self.putx([Ann.WARN, ['Warning: Unexpected bytes in reply!']])
148
149     def handle_cmd_read_fuse_bits(self, cmd, ret):
150         # Read fuse bits.
151         self.putx([Ann.RFB, ['Read fuse bits: 0x%02x' % ret[3]]])
152
153         # TODO: Decode fuse bits.
154         # TODO: Sanity check on reply.
155
156     def handle_cmd_read_fuse_high_bits(self, cmd, ret):
157         # Read fuse high bits.
158         self.putx([Ann.RHFB, ['Read fuse high bits: 0x%02x' % ret[3]]])
159
160         # TODO: Decode fuse bits.
161         # TODO: Sanity check on reply.
162
163     def handle_cmd_read_extended_fuse_bits(self, cmd, ret):
164         # Read extended fuse bits.
165         self.putx([Ann.REFB, ['Read extended fuse bits: 0x%02x' % ret[3]]])
166
167         # TODO: Decode fuse bits.
168         # TODO: Sanity check on reply.
169
170     def handle_cmd_read_lock_bits(self, cmd, ret):
171         # Read lock bits
172         self.putx([Ann.RLB, ['Read lock bits: 0x%02x' % ret[3]]])
173
174     def handle_cmd_read_eeprom_memory(self, cmd, ret):
175         # Read EEPROM Memory
176         _addr = ((cmd[1] & 1) << 8) + cmd[2]
177         self.putx([Ann.REEM, ['Read EEPROM Memory: [0x%03x]: 0x%02x' % (_addr, ret[3])]])
178
179     def handle_cmd_read_program_memory(self, cmd, ret):
180         # Read Program Memory
181         _HL = 'Low'
182         _H = 'L'
183         if cmd[0] & 0x08:
184             _HL = 'High'
185             _H = 'H'
186         _addr = ((cmd[1] & 0x0f) << 8) + cmd[2]
187         self.putx([Ann.RP, [
188             'Read program memory %s: [0x%03x]: 0x%02x' % (_HL, _addr, ret[3]),
189             '[%03x%s]:%02x' % (_addr, _H, ret[3]),
190             '%02x' % ret[3]
191         ]])
192
193     def handle_cmd_load_program_memory_page(self, cmd, ret):
194         # Load Program Memory Page
195         _HL = 'Low'
196         _H = 'L'
197         if cmd[0] & 0x08:
198             _HL = 'High'
199             _H = 'H'
200         _addr = cmd[2] & 0x1F
201         self.putx([Ann.LPMP, [
202             'Load program memory page %s: [0x%03x]: 0x%02x' % (_HL, _addr, cmd[3]),
203             '[%03x%s]=%02x' % (_addr, _H, cmd[3]),
204             '%02x' % cmd[3]
205         ]])
206
207     def handle_cmd_write_program_memory_page(self, cmd, ret):
208         # Write Program Memory Page
209         _addr = ((cmd[1] & 0x0F) << 3) + (cmd[2] << 5)
210         self.putx([Ann.WP, ['Write program memory page: 0x%02x' % _addr]])
211
212     def handle_command(self, cmd, ret):
213         if cmd[:2] == [0xac, 0x53]:
214             self.handle_cmd_programming_enable(cmd, ret)
215         elif cmd[0] == 0xac and (cmd[1] & (1 << 7)) == (1 << 7):
216             self.handle_cmd_chip_erase(cmd, ret)
217         elif cmd[:3] == [0x50, 0x00, 0x00]:
218             self.handle_cmd_read_fuse_bits(cmd, ret)
219         elif cmd[:3] == [0x58, 0x08, 0x00]:
220             self.handle_cmd_read_fuse_high_bits(cmd, ret)
221         elif cmd[:3] == [0x50, 0x08, 0x00]:
222             self.handle_cmd_read_extended_fuse_bits(cmd, ret)
223         elif cmd[0] == 0x30 and cmd[2] == 0x00:
224             self.handle_cmd_read_signature_byte_0x00(cmd, ret)
225         elif cmd[0] == 0x30 and cmd[2] == 0x01:
226             self.handle_cmd_read_signature_byte_0x01(cmd, ret)
227         elif cmd[0] == 0x30 and cmd[2] == 0x02:
228             self.handle_cmd_read_signature_byte_0x02(cmd, ret)
229         elif cmd[:2] == [0x58, 0x00]:
230             self.handle_cmd_read_lock_bits(cmd,ret)
231         elif cmd[0] == 0xa0 and (cmd[1] & (3 << 6)) == (0 << 6):
232             self.handle_cmd_read_eeprom_memory(cmd, ret)
233         elif (cmd[0] == 0x20 or cmd[0] == 0x28) and ((cmd[1] & 0xf0) == 0x00):
234             self.handle_cmd_read_program_memory(cmd, ret)
235         elif (cmd[0] == 0x40 or cmd[0] == 0x48) and ((cmd[1] & 0xf0) == 0x00):
236             self.handle_cmd_load_program_memory_page(cmd, ret)
237         elif (cmd[0] == 0x4C and ((cmd[1] & 0xf0) == 0x00)):
238             self.handle_cmd_write_program_memory_page(cmd, ret)
239         else:
240             c = '%02x %02x %02x %02x' % tuple(cmd)
241             r = '%02x %02x %02x %02x' % tuple(ret)
242             self.putx([Ann.WARN, ['Unknown command: %s (reply: %s)!' % (c, r)]])
243
244     def decode(self, ss, es, data):
245         ptype, mosi, miso = data
246
247         # For now, only use DATA and BITS packets.
248         if ptype not in ('DATA', 'BITS'):
249             return
250
251         # Store the individual bit values and ss/es numbers. The next packet
252         # is guaranteed to be a 'DATA' packet belonging to this 'BITS' one.
253         if ptype == 'BITS':
254             self.miso_bits, self.mosi_bits = miso, mosi
255             return
256
257         self.ss, self.es = ss, es
258
259         if len(self.mosi_bytes) == 0:
260             self.ss_cmd = ss
261
262         # Append new bytes.
263         self.mosi_bytes.append(mosi)
264         self.miso_bytes.append(miso)
265
266         # All commands consist of 4 bytes.
267         if len(self.mosi_bytes) < 4:
268             return
269
270         self.es_cmd = es
271
272         self.handle_command(self.mosi_bytes, self.miso_bytes)
273
274         self.mosi_bytes = []
275         self.miso_bytes = []