]>
Commit | Line | Data |
---|---|---|
4d9f1640 TP |
1 | ## |
2 | ## This file is part of the libsigrokdecode project. | |
3 | ## | |
4 | ## Copyright (C) 2020 Analog Devices Inc. | |
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 3 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 | ||
22 | slave_address = { | |
23 | 0x00: ['GND', 'GND', 'GND', 'G'], | |
24 | 0x01: ['FLOAT', 'FLOAT', 'FLOAT', 'F'], | |
25 | 0x02: ['VCC', 'VCC', 'VCC', 'V'], | |
26 | } | |
27 | ||
28 | commands = { | |
29 | 0x00: ['Write Input Register', 'Write In Reg', 'Wr In Reg', 'WIR'], | |
30 | 0x01: ['Update DAC', 'Update', 'U'], | |
31 | 0x03: ['Write and Power Up DAC', 'Write & Power Up', 'W&PU'], | |
32 | 0x04: ['Power Down DAC', 'Power Down', 'PD'], | |
33 | 0x0F: ['No Operation', 'No Op', 'NO'], | |
34 | } | |
35 | ||
36 | addresses = { | |
37 | 0x00: ['DAC A', 'A'], | |
38 | 0x01: ['DAC B', 'B'], | |
39 | 0x0F: ['All DACs', 'All'], | |
40 | } | |
41 | ||
a430f3a9 | 42 | input_voltage_format = ['%.6fV', '%.2fV'] |
4d9f1640 TP |
43 | |
44 | class Decoder(srd.Decoder): | |
45 | api_version = 3 | |
46 | id = 'ltc26x7' | |
47 | name = 'LTC26x7' | |
48 | longname = 'Linear Technology LTC26x7' | |
49 | desc = 'Linear Technology LTC26x7 16-/14-/12-bit rail-to-rail DACs.' | |
50 | license = 'gplv2+' | |
51 | inputs = ['i2c'] | |
52 | outputs = [] | |
39770181 | 53 | tags = ['IC', 'Analog/digital'] |
4d9f1640 | 54 | options = ( |
9fcac08e | 55 | {'id': 'chip', 'desc': 'Chip', 'default': 'ltc2607', |
4d9f1640 | 56 | 'values': ('ltc2607', 'ltc2617', 'ltc2627')}, |
c7c4c06c | 57 | {'id': 'vref', 'desc': 'Reference voltage (V)', 'default': 1.5}, |
4d9f1640 TP |
58 | ) |
59 | annotations = ( | |
60 | ('slave_addr', 'Slave address'), | |
61 | ('command', 'Command'), | |
62 | ('address', 'Address'), | |
629f90af UH |
63 | ('dac_a_voltage', 'DAC A voltage'), |
64 | ('dac_b_voltage', 'DAC B voltage'), | |
65 | ) | |
66 | annotation_rows = ( | |
67 | ('addr_cmd', 'Address/command', (0, 1, 2)), | |
68 | ('dac_a_voltages', 'DAC A voltages', (3,)), | |
69 | ('dac_b_voltages', 'DAC B voltages', (4,)), | |
4d9f1640 | 70 | ) |
4d9f1640 TP |
71 | |
72 | def __init__(self): | |
73 | self.reset() | |
74 | ||
75 | def reset(self): | |
76 | self.state = 'IDLE' | |
77 | self.ss = -1 | |
78 | self.data = 0x00 | |
629f90af | 79 | self.dac_val = 0 |
4d9f1640 TP |
80 | |
81 | def start(self): | |
82 | self.out_ann = self.register(srd.OUTPUT_ANN) | |
83 | ||
84 | def convert_ternary_str(self, n): | |
85 | if n == 0: | |
86 | return [0, 0, 0] | |
87 | nums = [] | |
88 | while n: | |
89 | n, r = divmod(n, 3) | |
90 | nums.append(r) | |
91 | while len(nums) < 3: | |
92 | nums.append(0) | |
93 | return list(reversed(nums)) | |
94 | ||
95 | def handle_slave_addr(self, data): | |
96 | if data == 0x73: | |
97 | ann = ['Global address', 'Global addr', 'Glob addr', 'GA'] | |
98 | self.put(self.ss, self.es, self.out_ann, [0, ann]) | |
99 | return | |
100 | ann = ['CA2=%s CA1=%s CA0=%s', '2=%s 1=%s 0=%s', '%s %s %s', '%s %s %s'] | |
101 | addr = 0 | |
102 | for i in range(7): | |
103 | if i in [2, 3]: | |
104 | continue | |
105 | offset = i | |
106 | if i > 3: | |
107 | offset -= 2 | |
108 | mask = 1 << i | |
109 | if data & mask: | |
110 | mask = 1 << offset | |
111 | addr |= mask | |
112 | ||
113 | addr -= 0x04 | |
114 | ternary_values = self.convert_ternary_str(addr) | |
115 | for i in range(len(ann)): | |
116 | ann[i] = ann[i] % (slave_address[ternary_values[0]][i], | |
117 | slave_address[ternary_values[1]][i], | |
118 | slave_address[ternary_values[2]][i]) | |
119 | self.put(self.ss, self.es, self.out_ann, [0, ann]) | |
120 | ||
121 | def handle_cmd_addr(self, data): | |
122 | cmd_val = (data >> 4) & 0x0F | |
629f90af | 123 | self.dac_val = (data & 0x0F) |
4d9f1640 TP |
124 | sm = (self.ss + self.es) // 2 |
125 | ||
126 | self.put(self.ss, sm, self.out_ann, [1, commands[cmd_val]]) | |
629f90af | 127 | self.put(sm, self.es, self.out_ann, [2, addresses[self.dac_val]]) |
4d9f1640 TP |
128 | |
129 | def handle_data(self, data): | |
130 | self.data = (self.data << 8) & 0xFF00 | |
131 | self.data += data | |
c7c4c06c | 132 | if self.options['chip'] == 'ltc2617': |
4d9f1640 | 133 | self.data = (self.data >> 2) |
c7c4c06c UH |
134 | self.data = (self.options['vref'] * self.data) / 0x3FFF |
135 | elif self.options['chip'] == 'ltc2627': | |
4d9f1640 | 136 | self.data = (self.data >> 4) |
c7c4c06c | 137 | self.data = (self.options['vref'] * self.data) / 0x0FFF |
4d9f1640 | 138 | else: |
c7c4c06c | 139 | self.data = (self.options['vref'] * self.data) / 0xFFFF |
4d9f1640 TP |
140 | ann = [] |
141 | for format in input_voltage_format: | |
142 | ann.append(format % self.data) | |
143 | self.data = 0 | |
144 | ||
629f90af UH |
145 | if self.dac_val == 0x0F: # All DACs (A and B). |
146 | self.put(self.ss, self.es, self.out_ann, [3 + 0, ann]) | |
147 | self.put(self.ss, self.es, self.out_ann, [3 + 1, ann]) | |
148 | else: | |
149 | self.put(self.ss, self.es, self.out_ann, [3 + self.dac_val, ann]) | |
4d9f1640 TP |
150 | |
151 | def decode(self, ss, es, data): | |
152 | cmd, databyte = data | |
153 | self.es = es | |
154 | ||
155 | # State machine. | |
156 | if self.state == 'IDLE': | |
157 | # Wait for an I²C START condition. | |
158 | if cmd != 'START': | |
159 | return | |
160 | self.state = 'GET SLAVE ADDR' | |
161 | elif self.state == 'GET SLAVE ADDR': | |
162 | # Wait for an address write operation. | |
163 | if cmd != 'ADDRESS WRITE': | |
164 | return | |
165 | self.ss = ss | |
166 | self.handle_slave_addr(databyte) | |
167 | self.ss = -1 | |
168 | self.state = 'GET CMD ADDR' | |
169 | elif self.state == 'GET CMD ADDR': | |
170 | if cmd != 'DATA WRITE': | |
171 | return | |
172 | self.ss = ss | |
173 | self.handle_cmd_addr(databyte) | |
174 | self.ss = -1 | |
175 | self.state = 'WRITE DATA' | |
176 | elif self.state == 'WRITE DATA': | |
177 | if cmd == 'DATA WRITE': | |
178 | if self.ss == -1: | |
179 | self.ss = ss | |
180 | self.data = databyte | |
181 | return | |
182 | self.handle_data(databyte) | |
183 | self.ss = -1 | |
184 | elif cmd == 'STOP': | |
185 | self.state = 'IDLE' | |
186 | else: | |
187 | return |