[FIRST DRIVE] Toyota Prius gen2 plug and play
-
turnip73
- Posts: 58
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 22 times
- Been thanked: 47 times
Re: [FIRST DRIVE] Toyota Prius gen2 plug and play
hmm...
So while testing my updated stm32-car code, I've realized that the Toyota hybrid control ecu is not sending the can bus information I'm expecting because the ecu/car is not in ready mode.
I knew I would have to deal with this eventually but seems that time is now...
That leads me to two options:-
A) Spoof the inputs to the Toyota hybrid control ecu
B) Implement the functionality from the Toyota hybrid control ecu needed in stm32-car.
Spoof the inputs to the Toyota hybrid control ecu
1) resolver/inverter
2) contactor/precharge charge voltages
3) Toyota BMS
Implement the functionality from the Toyota hybrid control ecu needed in stm32-car.
1) shift leaver
2) key authentication
3) A/C control
4) All the other stuff I don't know I need yet...
I'll start with spoofing resolver/inverter. I've had a go at this in the past, but not successful
see [viewtopic.php?p=44241#p44241]. To trick the Toyota hybrid control ecu to stay in ready mode and drive, it has to get feed back from current sensors and/or resolver.
I've seen in [ Latula EV test his SDU card using a signal generator
I think my options are
I) By any chance is the Toyota hybrid control ecu sending any information over CAN that Open Inverter ecu can use as resolver information to drive the motor
II) Can Open Inverter ecu hw/sw be modified to use the resolver information generated by the Toyota hybrid control ecu
III) Update Open Inverter ecu to create spoof resolver information for the Toyota hybrid control ecu
Attached Toyota resolver information
So while testing my updated stm32-car code, I've realized that the Toyota hybrid control ecu is not sending the can bus information I'm expecting because the ecu/car is not in ready mode.
I knew I would have to deal with this eventually but seems that time is now...
That leads me to two options:-
A) Spoof the inputs to the Toyota hybrid control ecu
B) Implement the functionality from the Toyota hybrid control ecu needed in stm32-car.
Spoof the inputs to the Toyota hybrid control ecu
1) resolver/inverter
2) contactor/precharge charge voltages
3) Toyota BMS
Implement the functionality from the Toyota hybrid control ecu needed in stm32-car.
1) shift leaver
2) key authentication
3) A/C control
4) All the other stuff I don't know I need yet...
I'll start with spoofing resolver/inverter. I've had a go at this in the past, but not successful
see [viewtopic.php?p=44241#p44241]. To trick the Toyota hybrid control ecu to stay in ready mode and drive, it has to get feed back from current sensors and/or resolver.
I've seen in [ Latula EV test his SDU card using a signal generator
I think my options are
I) By any chance is the Toyota hybrid control ecu sending any information over CAN that Open Inverter ecu can use as resolver information to drive the motor
II) Can Open Inverter ecu hw/sw be modified to use the resolver information generated by the Toyota hybrid control ecu
III) Update Open Inverter ecu to create spoof resolver information for the Toyota hybrid control ecu
Attached Toyota resolver information
-
turnip73
- Posts: 58
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 22 times
- Been thanked: 47 times
Re: [FIRST DRIVE] Toyota Prius gen2 plug and play
noI) By any chance is the Toyota hybrid control ecu sending any information over CAN that Open Inverter ecu can use as resolver information to drive the motor
OK, so this is the plan...
First attempt:
Use external excitation from Toyota VH ecu in OI
IO excitation is 9v peek to peek and 4.4 kHz Toyota excitation is 20v peek to peek 10 kHz. Plan is:-
HW:
1) Get Toyota excitation and resolver output down to ~3v peek to peek.
2) Get Toyota excitation in to stm32 (can I use "START" PB6/TIM4_CH1 see [https://github.com/jsphuebner/inverter- ... 2-v1.0.pdf])
SW:
1) Set OI excitation to 10 kHz (can this be done?)
2) Get Toyota excitation edge
2) Compare Toyota and OI excitation edge and add/subtract to resolverSampleDelay [https://github.com/jsphuebner/stm32-sin ... ncoder.cpp]?
20231120 updates removed OI resolver pico scope output (this was old data not OI resolver), both resolver output are kHz.
20231121 got an OI resolver pico scope output confirmed 9v peek to peek
Re: [FIRST DRIVE] Toyota Prius gen2 plug and play
Wow I would imagine trying to keep the oem hv ecu happy while driving with the inverter controlled by OI would be a massive task possibly requiring generating appropriate current and motor position signals possibly proportional to the pwm of the phase driver outputs from the hv ecu, I suspect a fixed set of values would cause errors,
I’m starting to think that taking over contactor contol ect and cutting the hv ecu out of the equation is going to be an easier route,
On a separate note, I’d really appreciate a capture of the a/c comms,
I’m starting to think that taking over contactor contol ect and cutting the hv ecu out of the equation is going to be an easier route,
On a separate note, I’d really appreciate a capture of the a/c comms,
-
turnip73
- Posts: 58
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 22 times
- Been thanked: 47 times
Re: [FIRST DRIVE] Toyota Prius gen2 plug and play
See my options/resoing in post above. Car runs and drives with the hv ecu out of the equation but I ran into probelms to integrate OI with rest of car when not in ready mode e.g hv ecu happy. In the past I've been able to run OI sin software open loop with oem hv ecu connected.Ev8 wrote: ↑Sat Nov 18, 2023 8:24 am Wow I would imagine trying to keep the oem hv ecu happy while driving with the inverter controlled by OI would be a massive task possibly requiring generating appropriate current and motor position signals possibly proportional to the pwm of the phase driver outputs from the hv ecu, I suspect a fixed set of values would cause errors,
I’m starting to think that taking over contactor contol ect and cutting the hv ecu out of the equation is going to be an easier route,
On a separate note, I’d really appreciate a capture of the a/c comms,
Re a/c comms I hope to try johu's idea to use the a/c as changer unmodifed (maybe making sure the gates are permanently low achieves the same)
johu wrote: ↑Tue Sep 05, 2023 7:30 am Yes much agreed. I modded the inverter and controller quite heavily to be able to charge reliably. Of course a controller can't take all of that away but it can be facilitated.
Mods for single phase boost charging:
- Swapped input and output of the buck/boost stage
- Removed 4 IGBTs of the A/C inverter and replaced them with a bridge rectifier (maybe making sure the gates are permanently low achieves the same)
- Fitted a current sensor to the cable going from said A/C inverter into the input of the boost converter to be able to measure charge current
- Disabling that current sensor with a relay while NOT charging
- Connected GSDN to the DC switch signal
It's the Hilux of inverters, virtually invincible unless I start mucking around with it![]()
-
turnip73
- Posts: 58
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 22 times
- Been thanked: 47 times
Re: [FIRST DRIVE] Toyota Prius gen2 plug and play
No luck so far changing the OI resolver excitation frequency.
If I comment out line:
https://github.com/jsphuebner/stm32-sin ... r.cpp#L471
Code: Select all
gpio_set_mode(NORTH_EXC_PORT, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, NORTH_EXC_PIN);My assumption was that the interrupt frequency that sets the resolver excitation frequency was set some where above in the InitResolverMode function but I haven't figure it out yet.
- johu
- Site Admin
- Posts: 6969
- Joined: Thu Nov 08, 2018 10:52 pm
- Location: Kassel/Germany
- Has thanked: 455 times
- Been thanked: 1771 times
- Contact:
Re: [FIRST DRIVE] Toyota Prius gen2 plug and play
Changing the excitation frequency is hard as it is indeed half the interrupt frequency of 8.8 kHz.
Not sure what you're trying to achieve on a higher level but if you want only excitation disabled you can switch to SinCos mode
Not sure what you're trying to achieve on a higher level but if you want only excitation disabled you can switch to SinCos mode
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
-
turnip73
- Posts: 58
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 22 times
- Been thanked: 47 times
Re: [FIRST DRIVE] Toyota Prius gen2 plug and play
I want to use an external resolver exciter from the Toyota HV ECU so both Toyota HV ECU and OI can use the resolver.
-
turnip73
- Posts: 58
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 22 times
- Been thanked: 47 times
Re: [FIRST DRIVE] Toyota Prius gen2 plug and play
Hmm, time for an update to this thread. After getting nowhere with trying to keep the HV ECU happy, I started on implementing/reverse engineering of functionality of the HV ECU. I picked the A/C control, as others on the forum had made some progress on the A/C Denso ES27C.
However, the internet says I cannot use the IGBT K1517 4L2 50SE as a diode/rectifier in reverse because of how IGBT's are constructed.
My other options are:-
1) stack a diode on top of the IGBT
2) not use the A/C Inverter to rectify (use an external rectifier)
Next I want to tackle is trying to charge using the A/C Inverter without modifications and the Buck/Boost converter.
However, the internet says I cannot use the IGBT K1517 4L2 50SE as a diode/rectifier in reverse because of how IGBT's are constructed.
My other options are:-
1) stack a diode on top of the IGBT
2) not use the A/C Inverter to rectify (use an external rectifier)
-
turnip73
- Posts: 58
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 22 times
- Been thanked: 47 times
Re: [FIRST DRIVE] Toyota Prius gen2 plug and play
Working on setting up boost charging, using a Denso 13140-0050 current sensor. Converting the Denso 13140-0050 output 5V to 0V (0A at ~2.5V) to 0V to ~2.5 for the gen2 board using an esp32:
Code: Select all
// === Pin Definitions ===
const int adcPin = 34; // ADC1_CH6 (GPIO34) — input: 0…2.5 V
const int dacPin = 25; // DAC1 (GPIO25) — output: 0…2.5 V
// === Constants ===
const float VREF = 3.3; // ESP32 ADC reference voltage
const int MAX_ADC = 4095; // 12-bit ADC resolution
const float VIN_MAX = 2.7; // maximum expected input (V)
const float VOUT_MAX = 2.7; // desired maximum output (V)
void setup() {
Serial.begin(115200);
}
void loop() {
// 1) Read ADC
int raw = analogRead(adcPin);
float vin = (raw / float(MAX_ADC)) * VREF; // scale to 0…3.3 V
// 2) Invert & clamp: map vin from [0…VIN_MAX] → [VOUT_MAX…0]
float vOut = (VIN_MAX - vin);
if (vOut < 0) vOut = 0;
else if (vOut > VOUT_MAX) vOut = VOUT_MAX;
// 3) Convert to DAC units (0…255→0…3.3 V), but we only drive up to VOUT_MAX
int dacVal = int((vOut / VREF) * 255.0);
dacWrite(dacPin, dacVal);
// 4) Debug
Serial.print("VIN = ");
Serial.print(vin, 3);
Serial.print(" V → VOUT = ");
Serial.print(vOut, 3);
Serial.println(" V");
delay(100);
}
-
turnip73
- Posts: 58
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 22 times
- Been thanked: 47 times
Re: [FIRST DRIVE] Toyota Prius gen2 plug and play
Had a busy couple of days working on the project. I replaced and balanced the cars original battery pack with some used ones I picked up. With the rest of the modules I started rebuilding a 2nd pack. I worked on the test setup for boost charging using the A/C inverter. I got as far as contactors closings and inverter and OI board in boost mode but ran into a issue. I was expecting the buck/booster converter to let power thought to the A/C inverter. I only have V1.1 cards and Johannes mentioned in a thread that the V1.3 will give you power to the A/C inverter and DCDC alt least in drive mode. I need at least 50V for the A/C inverter to start up or I fear it will just blow gates like it did for Johannes. Any ideas how I can get power to the A/C inverter to activate the gate? I also made a rudimentary web interface for the Battery ECU. The Current sensor setup also need some tinkering or maybe just use same setup as Johannes but that requires mods to the OI board.
-
turnip73
- Posts: 58
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 22 times
- Been thanked: 47 times
Re: [FIRST DRIVE] Toyota Prius gen2 plug and play
Wrote a small Prius Battery ECU decoder using an ESP32 and a couple of 3.3V Can Boards before I get ahead of my self over sharing the Toyota hybrid batteries:
Code: Select all
// === ESP32 Prius CAN Parser ===
// Monitors Prius Gen2 Battery ECU on 2 CAN buses
#include <ACAN_ESP32.h>
#include <mcp_can.h>
#include <SPI.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
AsyncWebServer server(80);
// === Battery 1 (ESP32 CAN) ===
float packVoltage1 = 0.0;
float packCurrent1 = 0.0;
int soc1 = 0;
int ccl1 = 0, cdl1 = 0;
int temp1a = 0, temp1b = 0;
uint16_t faultCode1 = 0;
uint8_t deltaSOC1 = 0, flags1 = 0;
uint16_t calibX1 = 0, calibY1 = 0, calibZ1 = 0;
float blockVoltages1[14] = {0};
uint8_t isoTPBuf1[64];
size_t isoTPLen1 = 0;
// === Battery 2 (MCP2515 CAN) ===
float packVoltage2 = 0.0;
float packCurrent2 = 0.0;
int soc2 = 0;
int ccl2 = 0, cdl2 = 0;
int temp2a = 0, temp2b = 0;
uint16_t faultCode2 = 0;
uint8_t deltaSOC2 = 0, flags2 = 0;
uint16_t calibX2 = 0, calibY2 = 0, calibZ2 = 0;
float blockVoltages2[14] = {0};
uint8_t isoTPBuf2[64];
size_t isoTPLen2 = 0;
MCP_CAN can2(15);
unsigned long lastTesterPing = 0;
const unsigned long testerPingInterval = 3000; // 3 sec
int pid = 1;
void setup() {
Serial.begin(115200);
WiFi.softAP("PriusMonitor", "hybridpower");
Serial.println(WiFi.softAPIP());
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
String html = "<html><head><meta http-equiv='refresh' content='2'></head><body><h1>Prius BMS Data</h1>";
html += "<h2>Battery 1</h2>";
html += "<p>Voltage: " + String(packVoltage1) + " V</p>";
html += "<p>Current: " + String(packCurrent1) + " A</p>";
html += "<p>SOC: " + String(soc1/2.0) + " %</p>";
html += "<p>Delta SOC: " + String(deltaSOC1/2.0) + " %</p>";
html += "<p>CCL/CDL: " + String(ccl1) + "/" + String(cdl1) + " A</p>";
html += "<p>Temps: " + String(temp1a) + ", " + String(temp1b) + "</p>";
html += "<p>Flags: 0x" + String(flags1, HEX) + "</p>";
html += "<p>Blocks:</p><ul>";
for (int i=0; i<14; i++) html += "<li>Block "+String(i+1)+": "+String(blockVoltages1[i])+" V</li>";
html += "</ul>";
html += "<h2>Battery 2</h2>";
html += "<p>Voltage: " + String(packVoltage2) + " V</p>";
html += "<p>Current: " + String(packCurrent2) + " A</p>";
html += "<p>SOC: " + String(soc2/2.0) + " %</p>";
html += "<p>Delta SOC: " + String(deltaSOC2/2.0) + " %</p>";
html += "<p>CCL/CDL: " + String(ccl2) + "/" + String(cdl2) + " A</p>";
html += "<p>Temps: " + String(temp2a) + ", " + String(temp2b) + "</p>";
html += "<p>Flags: 0x" + String(flags2, HEX) + "</p>";
html += "<p>Blocks:</p><ul>";
for (int i=0; i<14; i++) html += "<li>Block "+String(i+1)+": "+String(blockVoltages2[i])+" V</li>";
html += "</ul>";
html += "</body></html>";
request->send(200, "text/html", html);
});
server.begin();
ACAN_ESP32_Settings settings1(500000);
settings1.mRxPin = GPIO_NUM_16;
settings1.mTxPin = GPIO_NUM_17;
if (ACAN_ESP32::can.begin(settings1) == 0) {
Serial.println("Internal CAN OK");
} else {
Serial.println("Internal CAN FAILED");
}
SPI.begin();
while (CAN_OK != can2.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ)) {
Serial.println("MCP2515 init failed. Retrying...");
delay(1000);
}
can2.setMode(MCP_NORMAL);
Serial.println("MCP2515 CAN OK");
}
void loop() {
CANMessage frame;
if (ACAN_ESP32::can.receive(frame)) parseCAN(frame, 1);
long unsigned int rxId; uint8_t len = 0, buf[8];
if (can2.readMsgBuf(&rxId, &len, buf) == CAN_OK) {
CANMessage m; m.id = rxId; m.len = len; memcpy(m.data, buf, len);
parseCAN(m, 2);
}
if (millis() - lastTesterPing >= testerPingInterval) {
lastTesterPing = millis();
uint8_t req1[] = {0x02, 0x21, 0xCE,0,0,0,0,0};
uint8_t req2[] = {0x02, 0x21, 0xCE,0,0,0,0,0};
uint8_t req3[] = {0x02, 0x21, 0xCE,0,0,0,0,0};
uint8_t req4[] = {0x02, 0x21, 0xCE,0,0,0,0,0};
CANMessage tx; tx.id = 0x7E3; tx.len = 8;
if (pid==1) memcpy(tx.data, req1, 8);
if (pid==2) memcpy(tx.data, req2, 8);
if (pid==3) memcpy(tx.data, req3, 8);
if (pid==4) memcpy(tx.data, req4, 8);
ACAN_ESP32::can.tryToSend(tx);
can2.sendMsgBuf(0x7E3, 0, 8, tx.data);
pid++; if (pid>4) pid=1;
}
}
void parsePIDMap(uint8_t* data, size_t len) {
if (len < 4) return;
uint8_t base = data[2];
Serial.printf("[PIDMAP] Base 0x%02X\n", base);
for (int i=0; i<4; i++) {
uint8_t b = data[3+i];
for (int bit=7; bit>=0; bit--) {
if (b & (1<<bit)) {
uint8_t pid = base + (i*8 + (7-bit)) + 1;
Serial.printf(" -> PID: 0x%02X\n", pid);
}
}
}
}
void decodeBlocks(uint8_t* data, size_t len, int bus) {
float* blocks = (bus == 1) ? blockVoltages1 : blockVoltages2;
// We expect at least 2 bytes of header + 14 * 2 = 30 bytes of data
if (len < 2 + 14 * 2) {
Serial.printf("[BUS%d] decodeBlocks() called with insufficient data!\n", bus);
return;
}
Serial.printf("[BUS%d] data:", bus);
for (size_t i = 0; i < len; i++) {
Serial.printf(" %02X", data[i]);
}
Serial.println();
for (int i = 0; i < 14; i++) {
uint8_t D = data[2 + i * 2];
uint8_t E = data[2 + i * 2 + 1];
blocks[i] = (2.56f * D) + (0.01f * E) - 327.68f;
}
Serial.printf("[BUS%d] Blocks:", bus);
float sum = 0.0;
for (int i = 0; i < 14; i++) {
Serial.printf(" %.2f", blocks[i]);
sum += blocks[i];
}
Serial.printf("\n[BUS%d] Sum of blocks: %.2f V\n", bus, sum);
}
void parseCAN(const CANMessage &frame, int bus) {
float &packVoltage = (bus==1) ? packVoltage1 : packVoltage2;
float &packCurrent = (bus==1) ? packCurrent1 : packCurrent2;
int &soc = (bus==1) ? soc1 : soc2;
int &ccl = (bus==1) ? ccl1 : ccl2;
int &cdl = (bus==1) ? cdl1 : cdl2;
int &tempA = (bus==1) ? temp1a : temp2a;
int &tempB = (bus==1) ? temp1b : temp2b;
uint16_t &faultCode = (bus==1) ? faultCode1 : faultCode2;
uint8_t &deltaSOC = (bus==1) ? deltaSOC1 : deltaSOC2;
uint16_t &calibX = (bus==1) ? calibX1 : calibX2;
uint16_t &calibY = (bus==1) ? calibY1 : calibY2;
uint16_t &calibZ = (bus==1) ? calibZ1 : calibZ2;
uint8_t &flags = (bus==1) ? flags1 : flags2;
switch (frame.id) {
case 0x03B: { int16_t raw = ((frame.data[0]&0x0F)<<8)|frame.data[1];
if (raw & 0x800) raw -= 0x1000; packCurrent = raw*0.1;
packVoltage = (frame.data[2]<<8)|frame.data[3]; break; }
case 0x3CB: { cdl=frame.data[0]; ccl=frame.data[1]; deltaSOC=frame.data[2];
soc=frame.data[3]; tempA=(int8_t)frame.data[4]; tempB=(int8_t)frame.data[5]; break; }
case 0x3CD: { faultCode=(frame.data[0]<<8)|frame.data[1];
packVoltage=(frame.data[2]<<8)|frame.data[3]; break; }
case 0x3C9: { calibY=(frame.data[0]<<4)|(frame.data[1]>>4);
calibZ=((frame.data[1]&0x0F)<<8)|frame.data[2];
calibX=(frame.data[3]<<4)|(frame.data[4]>>4); break; }
case 0x4D1: { flags = frame.data[7]; break; }
}
if (frame.id==0x7EB) {
uint8_t* buf = (bus==1) ? isoTPBuf1 : isoTPBuf2;
size_t &isoLen = (bus==1) ? isoTPLen1 : isoTPLen2;
uint8_t pci = frame.data[0];
if ((pci & 0xF0)==0x00) {
isoLen = pci&0x0F; memcpy(buf, frame.data+1, isoLen);
if (buf[1]==0x61 && (buf[2]&0xF0)==0x40) parsePIDMap(buf, isoLen);
else decodeBlocks(buf+3, isoLen-3, bus);
} else if ((pci&0xF0)==0x10) {
isoLen=frame.data[1]; size_t cpy=frame.len-2;
memcpy(buf, frame.data+2, cpy); isoLen=cpy;
// Send Flow Control
CANMessage fc;
fc.id = 0x7E3;
fc.len = 8;
fc.data[0] = 0x30; // Flow Control
fc.data[1] = 0x00; // No block size
fc.data[2] = 0x05; // 5 ms
for (int i = 3; i < 8; i++) fc.data[i] = 0;
if (bus == 1)
ACAN_ESP32::can.tryToSend(fc);
else
can2.sendMsgBuf(fc.id, 0, fc.len, fc.data);
} else if ((pci&0xF0)==0x20) {
size_t cpy=frame.len-1; memcpy(buf+isoLen, frame.data+1, cpy);
isoLen+=cpy; if (isoLen>=14) decodeBlocks(buf+3, isoLen-3, bus);
}
}
}
Re: [FIRST DRIVE] Toyota Prius gen2 plug and play
Does this code allow you to use the prius battery pack natively?
I am looking to use a prius battery pack as my bench top testing battery and was hoping to not have to buy a different BMS to use as it will mot be my final battery configuration.
-
turnip73
- Posts: 58
- Joined: Wed Dec 26, 2018 1:38 pm
- Location: Greystones Ireland
- Has thanked: 22 times
- Been thanked: 47 times
Re: [FIRST DRIVE] Toyota Prius gen2 plug and play
yes, visual for integration with OI see https://github.com/hakanrolsson/stm32-c ... prius-gen2
For info on the battery ecu's can messages, see http://www.eaa-phev.org/wiki/Prius_PHEV ... #CAN_Tools