Line |
Branch |
Decision |
Exec |
Source |
1 |
|
|
|
/* |
2 |
|
|
|
* @file pt2001.cpp |
3 |
|
|
|
* |
4 |
|
|
|
* The NXP PT2001 is a programmable gate driver IC for precision solenoid control applications. |
5 |
|
|
|
* |
6 |
|
|
|
* Useful wires: |
7 |
|
|
|
* 5v, 3(3.3v), Gnd, 12v, VccIO(3v) SPI, DRVEN, RSTB |
8 |
|
|
|
* |
9 |
|
|
|
* For MC33816 vs PT2000 differences see |
10 |
|
|
|
* https://www.nxp.com/docs/en/application-note/AN5203.pdf |
11 |
|
|
|
* |
12 |
|
|
|
* @date May 3, 2019 |
13 |
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2020 |
14 |
|
|
|
* @author Matthew Kennedy |
15 |
|
|
|
*/ |
16 |
|
|
|
|
17 |
|
|
|
#include <rusefi/pt2001.h> |
18 |
|
|
|
#include <rusefi/arrays.h> |
19 |
|
|
|
|
20 |
|
|
|
#include <PT2001_LoadData.h> |
21 |
|
|
|
|
22 |
|
|
|
const int MC_CK = 6; // PLL x24 / CLK_DIV 4 = 6Mhz |
23 |
|
|
|
|
24 |
|
|
|
const int MAX_SPI_MODE_A_TRANSFER_SIZE = 31; //max size for register config transfer |
25 |
|
|
|
|
26 |
|
|
|
enum { |
27 |
|
|
|
CODE_RAM1, |
28 |
|
|
|
CODE_RAM2, |
29 |
|
|
|
DATA_RAM |
30 |
|
|
|
}; |
31 |
|
|
|
enum { |
32 |
|
|
|
REG_MAIN, |
33 |
|
|
|
REG_CH1, |
34 |
|
|
|
REG_CH2, |
35 |
|
|
|
REG_IO, |
36 |
|
|
|
REG_DIAG |
37 |
|
|
|
}; |
38 |
|
|
|
|
39 |
|
|
✗ |
static bool validateChipId(uint16_t id) { |
40 |
|
|
✗ |
return (id >> 8) == 0x9D; |
41 |
|
|
|
} |
42 |
|
|
|
|
43 |
|
|
✗ |
void Pt2001Base::setupSpi() { |
44 |
|
|
✗ |
select(); |
45 |
|
|
|
// Select Channel command |
46 |
|
|
✗ |
send(0x7FE1); |
47 |
|
|
|
// Common Page |
48 |
|
|
✗ |
send(0x0004); |
49 |
|
|
|
|
50 |
|
|
|
|
51 |
|
|
|
// Configure SPI command |
52 |
|
|
✗ |
send(0x3901); |
53 |
|
|
|
// Mode A + Watchdog timer full |
54 |
|
|
|
//send(0x001F); |
55 |
|
|
✗ |
send(0x009F); // + fast slew rate on miso |
56 |
|
|
✗ |
deselect(); |
57 |
|
|
✗ |
} |
58 |
|
|
|
|
59 |
|
|
✗ |
uint16_t Pt2001Base::readId() { |
60 |
|
|
✗ |
select(); |
61 |
|
|
✗ |
send(0xBAA1); |
62 |
|
|
✗ |
uint16_t ID = recv(); |
63 |
|
|
✗ |
deselect(); |
64 |
|
|
✗ |
return ID; |
65 |
|
|
|
} |
66 |
|
|
|
|
67 |
|
|
|
// Read a single word in Data RAM |
68 |
|
|
✗ |
uint16_t Pt2001Base::readDram(MC33816Mem addr) { |
69 |
|
|
✗ |
uint16_t addrInt = static_cast<uint16_t>(addr); |
70 |
|
|
|
|
71 |
|
|
✗ |
select(); |
72 |
|
|
|
// Select Channel command, Common Page |
73 |
|
|
✗ |
send(0x7FE1); |
74 |
|
|
✗ |
send(0x0004); |
75 |
|
|
|
// read (MSB=1) at data ram x9 (SCV_I_Hold), and 1 word |
76 |
|
|
✗ |
send((0x8000 | addrInt << 5) + 1); |
77 |
|
|
✗ |
uint16_t readValue = recv(); |
78 |
|
|
|
|
79 |
|
|
✗ |
deselect(); |
80 |
|
|
✗ |
return readValue; |
81 |
|
|
|
} |
82 |
|
|
|
|
83 |
|
|
|
// Update a single word in Data RAM |
84 |
|
|
✗ |
void Pt2001Base::writeDram(MC33816Mem addr, uint16_t data) { |
85 |
|
|
✗ |
uint16_t addrInt = static_cast<uint16_t>(addr); |
86 |
|
|
|
|
87 |
|
|
✗ |
select(); |
88 |
|
|
|
// Select Channel command, Common Page |
89 |
|
|
✗ |
send(0x7FE1); |
90 |
|
|
✗ |
send(0x0004); |
91 |
|
|
|
// write (MSB=0) at data ram x9 (SCV_I_Hold), and 1 word |
92 |
|
|
✗ |
send((addrInt << 5) + 1); |
93 |
|
|
✗ |
send(data); |
94 |
|
|
|
|
95 |
|
|
✗ |
deselect(); |
96 |
|
|
✗ |
} |
97 |
|
|
|
|
98 |
|
|
✗ |
static uint16_t dacEquation(float current) { |
99 |
|
|
|
/* |
100 |
|
|
|
Current, given in A |
101 |
|
|
|
I = (DAC_VALUE * V_DAC_LSB - V_DA_BIAS)/(G_DA_DIFF * R_SENSEx) |
102 |
|
|
|
DAC_VALUE = ((I*G_DA_DIFF * R_SENSEx) + V_DA_BIAS) / V_DAC_LSB |
103 |
|
|
|
V_DAC_LSB is the DAC resolution = 9.77mv |
104 |
|
|
|
V_DA_BIAS = 250mV |
105 |
|
|
|
G_DA_DIFF = Gain: 5.79, 8.68, [12.53], 19.25 |
106 |
|
|
|
R_SENSE = 10mOhm soldered on board |
107 |
|
|
|
*/ |
108 |
|
|
✗ |
return ((current * 12.53f * 10) + 250.0f) / 9.77f; |
109 |
|
|
|
} |
110 |
|
|
|
|
111 |
|
|
✗ |
void Pt2001Base::setTimings() { |
112 |
|
|
✗ |
setBoostVoltage(getBoostVoltage()); |
113 |
|
|
|
|
114 |
|
|
|
// Convert mA to DAC values |
115 |
|
|
✗ |
writeDram(MC33816Mem::Iboost, dacEquation(getBoostCurrent())); |
116 |
|
|
✗ |
writeDram(MC33816Mem::Ipeak, dacEquation(getPeakCurrent())); |
117 |
|
|
✗ |
writeDram(MC33816Mem::Ihold, dacEquation(getHoldCurrent())); |
118 |
|
|
|
|
119 |
|
|
|
// in micro seconds to clock cycles |
120 |
|
|
✗ |
writeDram(MC33816Mem::Tpeak_off, (MC_CK * getTpeakOff())); |
121 |
|
|
✗ |
writeDram(MC33816Mem::Tpeak_tot, (MC_CK * getTpeakTot())); |
122 |
|
|
✗ |
writeDram(MC33816Mem::Tbypass, (MC_CK * getTbypass())); |
123 |
|
|
✗ |
writeDram(MC33816Mem::Thold_off, (MC_CK * getTholdOff())); |
124 |
|
|
✗ |
writeDram(MC33816Mem::Thold_tot, (MC_CK * getTHoldTot())); |
125 |
|
|
✗ |
writeDram(MC33816Mem::Tboost_min, (MC_CK * getTBoostMin())); |
126 |
|
|
✗ |
writeDram(MC33816Mem::Tboost_max, (MC_CK * getTBoostMax())); |
127 |
|
|
|
|
128 |
|
|
|
// HPFP solenoid settings |
129 |
|
|
✗ |
writeDram(MC33816Mem::HPFP_Ipeak, dacEquation(getPumpPeakCurrent())); |
130 |
|
|
✗ |
writeDram(MC33816Mem::HPFP_Ihold, dacEquation(getPumpHoldCurrent())); |
131 |
|
|
✗ |
writeDram(MC33816Mem::HPFP_Thold_off, MC_CK * getPumpTholdOff()); |
132 |
|
|
✗ |
writeDram(MC33816Mem::HPFP_Thold_tot, MC_CK * getPumpTholdTot()); |
133 |
|
|
✗ |
} |
134 |
|
|
|
|
135 |
|
|
✗ |
void Pt2001Base::setBoostVoltage(float volts) { |
136 |
|
|
|
// Sanity checks, Datasheet says not too high, nor too low |
137 |
|
|
✗ |
if (volts > 72.0f) { |
138 |
|
|
✗ |
onError("DI Boost voltage setpoint too high"); |
139 |
|
|
✗ |
return; |
140 |
|
|
|
} |
141 |
|
|
✗ |
if (volts < 10.0f) { |
142 |
|
|
✗ |
onError("DI Boost voltage setpoint too low"); |
143 |
|
|
✗ |
return; |
144 |
|
|
|
} |
145 |
|
|
|
|
146 |
|
|
|
// There's a 1/32 divider on the input, then the DAC's output is 9.77mV per LSB. (1 / 32) / 0.00977 = 3.199 counts per volt. |
147 |
|
|
✗ |
uint16_t data = (volts * 3.25f) + 1.584f; |
148 |
|
|
✗ |
writeDram(MC33816Mem::Vboost_high, data+1); |
149 |
|
|
✗ |
writeDram(MC33816Mem::Vboost_low, data-1); |
150 |
|
|
|
// Remember to strobe driven!! |
151 |
|
|
|
} |
152 |
|
|
|
|
153 |
|
|
✗ |
bool Pt2001Base::checkFlash() { |
154 |
|
|
✗ |
select(); |
155 |
|
|
|
|
156 |
|
|
|
// ch1 |
157 |
|
|
|
// read (MSB=1) at location, and 1 word |
158 |
|
|
✗ |
send((0x8000 | 0x100 << 5) + 1); |
159 |
|
|
✗ |
if (!(recv() & (1<<5))) { |
160 |
|
|
✗ |
deselect(); |
161 |
|
|
✗ |
return false; |
162 |
|
|
|
} |
163 |
|
|
|
|
164 |
|
|
|
// ch2 |
165 |
|
|
|
// read (MSB=1) at location, and 1 word |
166 |
|
|
✗ |
send((0x8000 | 0x120 << 5) + 1); |
167 |
|
|
|
|
168 |
|
|
✗ |
if (!(recv() & (1<<5))) { |
169 |
|
|
✗ |
deselect(); |
170 |
|
|
✗ |
return false; |
171 |
|
|
|
} |
172 |
|
|
|
|
173 |
|
|
✗ |
deselect(); |
174 |
|
|
✗ |
return true; |
175 |
|
|
|
} |
176 |
|
|
|
|
177 |
|
|
✗ |
void Pt2001Base::clearDriverStatus(){ |
178 |
|
|
|
// Note: There is a config at 0x1CE & 1 that can reset this status config register on read |
179 |
|
|
|
// otherwise the reload/recheck occurs with this write |
180 |
|
|
|
// resetting it is necessary to clear default reset behavoir, as well as if an issue has been resolved |
181 |
|
|
✗ |
setupSpi(); // ensure on common page? |
182 |
|
|
✗ |
select(); |
183 |
|
|
✗ |
send((0x0000 | 0x1D2 << 5) + 1); // write, location, one word |
184 |
|
|
✗ |
send(0x0000); // anything to clear |
185 |
|
|
✗ |
deselect(); |
186 |
|
|
✗ |
} |
187 |
|
|
|
|
188 |
|
|
✗ |
uint16_t Pt2001Base::readStatus(int reg) { |
189 |
|
|
✗ |
setupSpi(); // ensure on common page? |
190 |
|
|
✗ |
select(); |
191 |
|
|
✗ |
send((0x8000 | reg << 5) + 1); |
192 |
|
|
✗ |
uint16_t driverStatus = recv(); |
193 |
|
|
✗ |
deselect(); |
194 |
|
|
✗ |
return driverStatus; |
195 |
|
|
|
} |
196 |
|
|
|
|
197 |
|
|
✗ |
uint16_t Pt2001Base::readDriverStatus() { |
198 |
|
|
✗ |
return readStatus(0x1D2); |
199 |
|
|
|
} |
200 |
|
|
|
|
201 |
|
|
✗ |
static bool checkUndervoltVccP(uint16_t driverStatus){ |
202 |
|
|
✗ |
return (driverStatus & (1<<0)); |
203 |
|
|
|
} |
204 |
|
|
|
|
205 |
|
|
✗ |
static bool checkUndervoltV5(uint16_t driverStatus){ |
206 |
|
|
✗ |
return (driverStatus & (1<<1)); |
207 |
|
|
|
} |
208 |
|
|
|
|
209 |
|
|
|
// static bool checkOverTemp(uint16_t driverStatus){ |
210 |
|
|
|
// return (driverStatus & (1<<3)); |
211 |
|
|
|
// } |
212 |
|
|
|
|
213 |
|
|
✗ |
static bool checkDrivenEnabled(uint16_t driverStatus){ |
214 |
|
|
✗ |
return (driverStatus & (1<<4)); |
215 |
|
|
|
} |
216 |
|
|
|
|
217 |
|
|
✗ |
void Pt2001Base::enableFlash() { |
218 |
|
|
✗ |
select(); |
219 |
|
|
✗ |
send(0x2001); //ch1 |
220 |
|
|
✗ |
send(0x0018); //enable flash |
221 |
|
|
✗ |
send(0x2401); //ch2 |
222 |
|
|
✗ |
send(0x0018); // enable flash |
223 |
|
|
✗ |
deselect(); |
224 |
|
|
✗ |
} |
225 |
|
|
|
|
226 |
|
|
✗ |
void Pt2001Base::periodicCallback() { |
227 |
|
|
|
// todo: read status/diag via SPI |
228 |
|
|
✗ |
} |
229 |
|
|
|
|
230 |
|
|
✗ |
void Pt2001Base::downloadRam(int target) { |
231 |
|
|
✗ |
uint16_t memory_area = 0; // memory area |
232 |
|
|
✗ |
uint16_t start_address = 0; // start address |
233 |
|
|
✗ |
uint16_t codeWidthRegAddr = 0; // code width register address |
234 |
|
|
✗ |
uint16_t size = 0; // size of RAM data |
235 |
|
|
✗ |
uint16_t command = 0; // command data |
236 |
|
|
✗ |
const uint16_t *RAM_ptr = nullptr; // pointer to array of data to be sent to the chip |
237 |
|
|
|
|
238 |
|
|
|
//Why Again? For Every time, just in case? |
239 |
|
|
✗ |
setupSpi(); |
240 |
|
|
|
|
241 |
|
|
✗ |
switch(target) // selects target |
242 |
|
|
|
{ |
243 |
|
|
✗ |
case CODE_RAM1: |
244 |
|
|
✗ |
memory_area = 0x1; |
245 |
|
|
✗ |
start_address = 0; |
246 |
|
|
✗ |
codeWidthRegAddr = 0x107; |
247 |
|
|
✗ |
RAM_ptr = PT2001_code_RAM1; |
248 |
|
|
|
// todo: use efi::size? |
249 |
|
|
✗ |
size = sizeof(PT2001_code_RAM1) / 2; |
250 |
|
|
✗ |
break; |
251 |
|
|
|
|
252 |
|
|
✗ |
case CODE_RAM2: |
253 |
|
|
✗ |
memory_area = 0x2; |
254 |
|
|
✗ |
start_address = 0; |
255 |
|
|
✗ |
codeWidthRegAddr = 0x127; |
256 |
|
|
✗ |
RAM_ptr = PT2001_code_RAM2; |
257 |
|
|
|
// todo: use efi::size? |
258 |
|
|
✗ |
size = sizeof(PT2001_code_RAM2) / 2; |
259 |
|
|
✗ |
break; |
260 |
|
|
|
|
261 |
|
|
✗ |
case DATA_RAM: // ch1 only? |
262 |
|
|
✗ |
memory_area = 0x4; |
263 |
|
|
✗ |
start_address = 0; |
264 |
|
|
✗ |
RAM_ptr = PT2001_data_RAM; |
265 |
|
|
|
// todo: use efi::size? |
266 |
|
|
✗ |
size = sizeof(PT2001_data_RAM) / 2; |
267 |
|
|
✗ |
break; |
268 |
|
|
|
// optional, both data_rams with 0x3, writes same code to both |
269 |
|
|
✗ |
default: |
270 |
|
|
✗ |
break; |
271 |
|
|
|
} |
272 |
|
|
|
|
273 |
|
|
|
// Chip-Select high |
274 |
|
|
✗ |
select(); |
275 |
|
|
|
|
276 |
|
|
✗ |
if (target != DATA_RAM) |
277 |
|
|
|
{ |
278 |
|
|
✗ |
command = codeWidthRegAddr << 5; // control width register address |
279 |
|
|
✗ |
command |= 1; // number of words to follow |
280 |
|
|
✗ |
send(command); // sends code_width command |
281 |
|
|
✗ |
send(size); // sends size (Code Width) |
282 |
|
|
|
} |
283 |
|
|
|
|
284 |
|
|
|
// Select Channel command |
285 |
|
|
✗ |
send(0x7FE1); |
286 |
|
|
|
// RAM1, RAM2, or Common Page (Data RAM) |
287 |
|
|
✗ |
send(memory_area); |
288 |
|
|
|
|
289 |
|
|
|
// "Command" of starting address |
290 |
|
|
|
// up to 0x03FE of code ram |
291 |
|
|
|
// up to 0x0080 of data ram |
292 |
|
|
✗ |
command = start_address << 5; |
293 |
|
|
✗ |
send(command); // sends start address command |
294 |
|
|
|
|
295 |
|
|
✗ |
sendLarge(RAM_ptr, size); |
296 |
|
|
✗ |
deselect(); |
297 |
|
|
✗ |
} |
298 |
|
|
|
|
299 |
|
|
✗ |
void Pt2001Base::downloadRegister(int r_target) { |
300 |
|
|
✗ |
uint16_t r_start_address = 0; // start address |
301 |
|
|
✗ |
uint16_t r_size = 0; // size of configuration data |
302 |
|
|
✗ |
uint16_t r_command = 0; // command data |
303 |
|
|
✗ |
uint16_t remainder_size = 0; // remainder size |
304 |
|
|
✗ |
const uint16_t *reg_ptr = nullptr; // pointer to array of data to be sent to the chip |
305 |
|
|
|
|
306 |
|
|
✗ |
switch(r_target) // selects target |
307 |
|
|
|
{ |
308 |
|
|
✗ |
case REG_CH1: // channel 1 configurations |
309 |
|
|
✗ |
r_start_address = 0x100; |
310 |
|
|
✗ |
reg_ptr = PT2001_ch1_config; |
311 |
|
|
✗ |
r_size = efi::size(PT2001_ch1_config); |
312 |
|
|
✗ |
break; |
313 |
|
|
|
|
314 |
|
|
✗ |
case REG_CH2: // channel 2 configurations |
315 |
|
|
✗ |
r_start_address = 0x120; |
316 |
|
|
✗ |
reg_ptr = PT2001_ch2_config; |
317 |
|
|
✗ |
r_size = efi::size(PT2001_ch2_config); |
318 |
|
|
✗ |
break; |
319 |
|
|
|
|
320 |
|
|
✗ |
case REG_DIAG: // diagnostic configurations |
321 |
|
|
✗ |
r_start_address = 0x140; |
322 |
|
|
✗ |
reg_ptr = PT2001_diag_config; |
323 |
|
|
✗ |
r_size = efi::size(PT2001_diag_config); |
324 |
|
|
✗ |
break; |
325 |
|
|
|
|
326 |
|
|
✗ |
case REG_IO: // IO configurations |
327 |
|
|
✗ |
r_start_address = 0x180; |
328 |
|
|
✗ |
reg_ptr = PT2001_io_config; |
329 |
|
|
✗ |
r_size = efi::size(PT2001_io_config); |
330 |
|
|
✗ |
break; |
331 |
|
|
|
|
332 |
|
|
✗ |
case REG_MAIN: // main configurations |
333 |
|
|
✗ |
r_start_address = 0x1C0; |
334 |
|
|
✗ |
reg_ptr = PT2001_main_config; |
335 |
|
|
✗ |
r_size = efi::size(PT2001_main_config); |
336 |
|
|
✗ |
break; |
337 |
|
|
|
|
338 |
|
|
✗ |
default: |
339 |
|
|
✗ |
break; |
340 |
|
|
|
} |
341 |
|
|
|
|
342 |
|
|
|
//for location < size(remainder?) |
343 |
|
|
|
// is location == 0? or past max xfer, send command + expected size |
344 |
|
|
|
// if location = max xfer |
345 |
|
|
|
// |
346 |
|
|
|
// retrieve data, send it, increase pointer |
347 |
|
|
|
// increase |
348 |
|
|
|
|
349 |
|
|
✗ |
if (r_size > MAX_SPI_MODE_A_TRANSFER_SIZE) //if size is too large, split into two sections ... MULTIPLE sections.. |
350 |
|
|
|
{ |
351 |
|
|
✗ |
remainder_size = r_size - MAX_SPI_MODE_A_TRANSFER_SIZE; // creates remaining size |
352 |
|
|
✗ |
r_size = MAX_SPI_MODE_A_TRANSFER_SIZE; // sets first size |
353 |
|
|
|
} |
354 |
|
|
|
|
355 |
|
|
✗ |
r_command = r_start_address << 5; // start address |
356 |
|
|
✗ |
r_command += r_size; // number of words to follow |
357 |
|
|
|
|
358 |
|
|
✗ |
select(); // Chip |
359 |
|
|
|
|
360 |
|
|
✗ |
send(r_command); // sends address and number of words to be sent |
361 |
|
|
|
|
362 |
|
|
✗ |
sendLarge(reg_ptr, r_size); |
363 |
|
|
|
|
364 |
|
|
✗ |
if (remainder_size > 0) // if remainder size is greater than 0, download the rest |
365 |
|
|
|
{ |
366 |
|
|
✗ |
r_start_address += r_size; // new start address |
367 |
|
|
✗ |
r_command = r_start_address << 5; // start address |
368 |
|
|
✗ |
r_command += remainder_size; // number of words to follow |
369 |
|
|
|
|
370 |
|
|
✗ |
send(r_command); // sends address and number of words to be sent |
371 |
|
|
✗ |
sendLarge(reg_ptr + r_size, remainder_size); |
372 |
|
|
|
} |
373 |
|
|
✗ |
deselect(); |
374 |
|
|
✗ |
} |
375 |
|
|
|
|
376 |
|
|
|
// void initMc33816() { |
377 |
|
|
|
// // |
378 |
|
|
|
// // see setTest33816EngineConfiguration for default configuration |
379 |
|
|
|
// // Pins |
380 |
|
|
|
// if (!isBrainPinValid(engineConfiguration->mc33816_cs) || |
381 |
|
|
|
// !isBrainPinValid(engineConfiguration->mc33816_rstb) || |
382 |
|
|
|
// !isBrainPinValid(engineConfiguration->mc33816_driven)) { |
383 |
|
|
|
// return; |
384 |
|
|
|
// } |
385 |
|
|
|
// if (isBrainPinValid(engineConfiguration->mc33816_flag0)) { |
386 |
|
|
|
// efiSetPadMode("mc33816 flag0", engineConfiguration->mc33816_flag0, getInputMode(PI_DEFAULT)); |
387 |
|
|
|
// } |
388 |
|
|
|
|
389 |
|
|
|
// chipSelect.initPin("mc33 CS", engineConfiguration->mc33816_cs /*, &engineConfiguration->csPinMode*/); |
390 |
|
|
|
|
391 |
|
|
|
// // Initialize the chip via ResetB |
392 |
|
|
|
// resetB.initPin("mc33 RESTB", engineConfiguration->mc33816_rstb); |
393 |
|
|
|
// // High Voltage via DRIVEN |
394 |
|
|
|
// driven.initPin("mc33 DRIVEN", engineConfiguration->mc33816_driven); |
395 |
|
|
|
|
396 |
|
|
|
|
397 |
|
|
|
// spiCfg.ssport = getHwPort("hip", engineConfiguration->mc33816_cs); |
398 |
|
|
|
// spiCfg.sspad = getHwPin("hip", engineConfiguration->mc33816_cs); |
399 |
|
|
|
|
400 |
|
|
|
// // hard-coded for now, just resolve the conflict with SD card! |
401 |
|
|
|
// engineConfiguration->mc33816spiDevice = SPI_DEVICE_3; |
402 |
|
|
|
|
403 |
|
|
|
// driver = getSpiDevice(engineConfiguration->mc33816spiDevice); |
404 |
|
|
|
// if (driver == NULL) { |
405 |
|
|
|
// // error already reported |
406 |
|
|
|
// return; |
407 |
|
|
|
// } |
408 |
|
|
|
|
409 |
|
|
|
// spiStart(driver, &spiCfg); |
410 |
|
|
|
|
411 |
|
|
|
// addConsoleAction("mc33_stats", showStats); |
412 |
|
|
|
// addConsoleAction("mc33_restart", mcRestart); |
413 |
|
|
|
// //addConsoleActionI("mc33_send", sendWord); |
414 |
|
|
|
|
415 |
|
|
|
// initMc33816IfNeeded(); |
416 |
|
|
|
// } |
417 |
|
|
|
|
418 |
|
|
✗ |
const char * mcFaultToString(McFault fault) { |
419 |
|
|
✗ |
switch (fault) { |
420 |
|
|
✗ |
case McFault::NoComm: |
421 |
|
|
✗ |
return "NoComm"; |
422 |
|
|
✗ |
case McFault::NoFlash: |
423 |
|
|
✗ |
return "NoFlash"; |
424 |
|
|
✗ |
case McFault::UnderVoltageAfter: |
425 |
|
|
✗ |
return "UnderVoltageAfter"; |
426 |
|
|
✗ |
case McFault::flag0: |
427 |
|
|
✗ |
return "flag0"; |
428 |
|
|
✗ |
case McFault::UnderVoltage5: |
429 |
|
|
✗ |
return "UnderVoltage5"; |
430 |
|
|
✗ |
case McFault::Driven: |
431 |
|
|
✗ |
return "Driven"; |
432 |
|
|
✗ |
case McFault::UnderVoltage7: |
433 |
|
|
✗ |
return "UnderVoltage7"; |
434 |
|
|
✗ |
default: |
435 |
|
|
✗ |
return "TODO"; |
436 |
|
|
|
} |
437 |
|
|
|
return "TODO"; |
438 |
|
|
|
} |
439 |
|
|
|
|
440 |
|
|
✗ |
void Pt2001Base::shutdown() { |
441 |
|
|
✗ |
setDriveEN(false); // ensure HV is off |
442 |
|
|
✗ |
setResetB(false); // turn off the chip |
443 |
|
|
✗ |
} |
444 |
|
|
|
|
445 |
|
|
✗ |
bool Pt2001Base::restart() { |
446 |
|
|
✗ |
bool flag0before = false; |
447 |
|
|
✗ |
bool flag0after = false; |
448 |
|
|
|
|
449 |
|
|
|
// Start with everything off |
450 |
|
|
✗ |
shutdown(); |
451 |
|
|
✗ |
deselect(); |
452 |
|
|
|
|
453 |
|
|
✗ |
if (getVbatt() < 8) { |
454 |
|
|
✗ |
onError("GDI not Restarting until we see VBatt"); |
455 |
|
|
✗ |
return false; |
456 |
|
|
|
} |
457 |
|
|
|
|
458 |
|
|
|
// Wait for chip to reset, then release reset and wait again |
459 |
|
|
✗ |
sleepMs(1); |
460 |
|
|
✗ |
setResetB(true); |
461 |
|
|
✗ |
sleepMs(1); |
462 |
|
|
|
|
463 |
|
|
|
// Flag0 should be floating - pulldown means it should read low |
464 |
|
|
✗ |
flag0before = readFlag0(); |
465 |
|
|
|
|
466 |
|
|
✗ |
acquireBus(); |
467 |
|
|
✗ |
setupSpi(); |
468 |
|
|
|
|
469 |
|
|
✗ |
clearDriverStatus(); // Initial clear necessary |
470 |
|
|
✗ |
status = readDriverStatus(); |
471 |
|
|
✗ |
if (checkUndervoltV5(status)) { |
472 |
|
|
✗ |
onError(McFault::UnderVoltage5); |
473 |
|
|
✗ |
shutdown(); |
474 |
|
|
✗ |
releaseBus(); |
475 |
|
|
✗ |
return false; |
476 |
|
|
|
} |
477 |
|
|
|
|
478 |
|
|
✗ |
uint16_t chipId = readId(); |
479 |
|
|
✗ |
if (!validateChipId(chipId)) { |
480 |
|
|
✗ |
onError(McFault::NoComm); |
481 |
|
|
✗ |
shutdown(); |
482 |
|
|
✗ |
releaseBus(); |
483 |
|
|
✗ |
return false; |
484 |
|
|
|
} |
485 |
|
|
|
|
486 |
|
|
✗ |
downloadRam(CODE_RAM1); // transfers code RAM1 |
487 |
|
|
✗ |
downloadRam(CODE_RAM2); // transfers code RAM2 |
488 |
|
|
✗ |
downloadRam(DATA_RAM); // transfers data RAM |
489 |
|
|
✗ |
downloadRegister(REG_MAIN); // download main register configurations |
490 |
|
|
|
|
491 |
|
|
|
// current configuration of REG_MAIN would toggle flag0 from LOW to HIGH |
492 |
|
|
✗ |
flag0after = readFlag0(); |
493 |
|
|
✗ |
if (flag0before || !flag0after) { |
494 |
|
|
✗ |
if (errorOnUnexpectedFlag()) { |
495 |
|
|
✗ |
onError(McFault::flag0); |
496 |
|
|
✗ |
shutdown(); |
497 |
|
|
✗ |
releaseBus(); |
498 |
|
|
✗ |
return false; |
499 |
|
|
|
} |
500 |
|
|
|
} |
501 |
|
|
|
|
502 |
|
|
✗ |
downloadRegister(REG_CH1); // download channel 1 register configurations |
503 |
|
|
✗ |
downloadRegister(REG_CH2); // download channel 2 register configurations |
504 |
|
|
✗ |
downloadRegister(REG_IO); // download IO register configurations |
505 |
|
|
✗ |
downloadRegister(REG_DIAG); // download diag register configuration |
506 |
|
|
|
|
507 |
|
|
✗ |
setTimings(); |
508 |
|
|
|
|
509 |
|
|
|
// Finished downloading, let's run the code |
510 |
|
|
✗ |
enableFlash(); |
511 |
|
|
|
|
512 |
|
|
|
// give it a moment to take effect |
513 |
|
|
✗ |
sleepMs(10); |
514 |
|
|
|
|
515 |
|
|
✗ |
if (!checkFlash()) { |
516 |
|
|
✗ |
onError(McFault::NoFlash); |
517 |
|
|
✗ |
shutdown(); |
518 |
|
|
✗ |
releaseBus(); |
519 |
|
|
✗ |
return false; |
520 |
|
|
|
} |
521 |
|
|
|
|
522 |
|
|
✗ |
clearDriverStatus(); |
523 |
|
|
✗ |
sleepMs(5); |
524 |
|
|
|
|
525 |
|
|
✗ |
status = readDriverStatus(); |
526 |
|
|
✗ |
if (checkUndervoltVccP(status)) { |
527 |
|
|
✗ |
onError(McFault::UnderVoltage7); |
528 |
|
|
✗ |
shutdown(); |
529 |
|
|
✗ |
releaseBus(); |
530 |
|
|
✗ |
return false; |
531 |
|
|
|
} |
532 |
|
|
|
|
533 |
|
|
|
// Drive High Voltage |
534 |
|
|
✗ |
setDriveEN(true); // driven = HV |
535 |
|
|
✗ |
sleepMs(10); // Give it a moment |
536 |
|
|
✗ |
status = readDriverStatus(); |
537 |
|
|
✗ |
if (!checkDrivenEnabled(status)) { |
538 |
|
|
✗ |
onError(McFault::Driven); |
539 |
|
|
✗ |
shutdown(); |
540 |
|
|
✗ |
releaseBus(); |
541 |
|
|
✗ |
return false; |
542 |
|
|
|
} |
543 |
|
|
|
|
544 |
|
|
✗ |
status = readDriverStatus(); |
545 |
|
|
✗ |
if (checkUndervoltVccP(status)) { |
546 |
|
|
✗ |
onError(McFault::UnderVoltageAfter); // Likely DC-DC LS7 is dead! |
547 |
|
|
✗ |
shutdown(); |
548 |
|
|
✗ |
releaseBus(); |
549 |
|
|
✗ |
return false; |
550 |
|
|
|
} |
551 |
|
|
|
|
552 |
|
|
✗ |
onError(McFault::None); |
553 |
|
|
|
|
554 |
|
|
✗ |
releaseBus(); |
555 |
|
|
✗ |
return true; |
556 |
|
|
|
} |
557 |
|
|
|
|