So, I got it working with OI sine firmware on olimex STM-H103 board. All needed components are used original (Igbt, drivers, current sensors and position sensor). Only added some voltage dividers where was needed...
Of course, not everything goes according to plan... I haven't been able to get the regen mode running yet. Motor still accelerates in regen mode. I don't know what to do with it anymore, I'll probably start a new thread about this problem.
VW Mild Hybrid Starter Alternator
- tom91
- Posts: 2962
- Joined: Fri Mar 01, 2019 9:15 pm
- Location: Bicester, Oxfordshire
- Has thanked: 328 times
- Been thanked: 847 times
Re: VW Mild Hybrid Starter Alternator
The alternator is not an induction motor is it? so it needs FOC and not Since
Re: VW Mild Hybrid Starter Alternator
squidopolis wrote: ↑Mon Jan 19, 2026 5:27 am Got this working, below is my python script:
#send_msg
# The CANlib library is initialized when the canlib module is imported. To be
# able to send a message, Frame also needs to be installed.
from canlib import canlib, Frame
import time
#CAN
ch_a = canlib.openChannel(channel=0)
ch_a.setBusParams(canlib.canBITRATE_500K)
ch_a.busOn()
#IGNITION MSG
IGN_counter = 0
IGN_DLC = 4
IGN_data_array = bytearray(4)
IGN_MSG_ID = (0x03C0 & 0xFFFF)
#MSG_EMG_01 MSG
EMG_01_counter = 0
EMG_01_DLC = 8
EMG_01_data_array = bytearray(8)
EMG_01_MSG_ID = (0x0151 & 0xFFFF)
MO_EMG_OperationModeReq = ( 1& 0xF)
MO_EMG_SpeedReq = (2048&0x7FFF)
MO_EMG_MaxTorqueGradient = (0x01&0x7F)
MO_EMG_Clamp15 = 1
MO_EMG_Deactivate_HV = 1
MO_EMG_MaxVoltage = (4&0xFF)
#MSG EMG_02 MSG
EMG_02_counter = 4
EMG_02_DLC = 8
EMG_02_data_array = bytearray(8)
EMG_02_MSG_ID = (0x0152 & 0xFFFF)
MO_EMG_MaxCurrent = (1027&0x7FF)
MO_EMG_MinCurrent = (1023&0x7FF)
MO_EMG_MinVoltage = (106&0xFF)
MO_EMG_TorqueReq = (32781&0xFFFF)
#Constant Bytes
# VAG MB 0 1 2 3 4 5 6 7 8 9 A B C D E F
MB0151 = bytearray([ 0x42, 0x7E, 0xB4, 0x01, 0x0A, 0x91, 0xDF, 0x10, 0xA1, 0x73, 0x59, 0x05, 0xF6, 0x79, 0x0B, 0xDE])
MB0152 = bytearray([ 0x58, 0x61, 0xCF, 0x30, 0x69, 0x6A, 0xC4, 0xC6, 0xB2, 0x53, 0x22, 0xB6, 0xEC, 0x95, 0xCA, 0xF8])
MB03C0 = bytearray([ 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3])
#Calculate the CRC checksum for VAG CAN Messages
def vw_crc_calc(byte_array: bytearray, DLC: byte, MSG_ID: int):
poly = 0x2F
xor_output = 0xFF
crc = 0XFF
magic_byte = 0x00
counter = byte_array[1]&0x0F
if MSG_ID == 0x151:
magic_byte = MB0151[counter]
elif MSG_ID == 0x152:
magic_byte = MB0152[counter]
elif MSG_ID == 0x3C0:
magic_byte = MB03C0[counter]
for i in range(1, DLC + 1):
if i<DLC:
crc ^= byte_array;
else:
crc ^= magic_byte;
for j in range(8):
if (crc&0x80):
crc = (crc << 1) ^ poly
else:
crc = (crc << 1);
crc ^= xor_output;
byte_array[0] = crc&0xFF
# Send command messages ~1ms for ~10seconds
for i in range(50000):
#load Ignition Frame
IGN_counter += 1
if IGN_counter>0xF:
IGN_counter = 0
#Load Data (Constant 0x23 Value)
IGN_data_array[1]=IGN_counter&0xF
IGN_data_array[2] = 0x2
#IGN_data_array[3] = 0x03
#Modify CRC byte[0]
vw_crc_calc(IGN_data_array, IGN_DLC, IGN_MSG_ID)
#Send Igniton CAN FRAME
frame = Frame(IGN_MSG_ID, IGN_data_array, flags=canlib.MessageFlag.STD )
ch_a.write(frame)
#load EMG_01 Frame
EMG_01_counter += 1
if EMG_01_counter>0xF:
EMG_01_counter = 0
#load Data
EMG_01_data_array[1]=((MO_EMG_OperationModeReq<<4)&0xF0)+(EMG_01_counter&0xF)
EMG_01_data_array[2]=(MO_EMG_SpeedReq&0xFF)
#EMG_01_data_array[3]=((MO_EMG_SpeedReq>>8)&0x7F)+((MO_EMG_Clamp15<<7)&0x80)
#EMG_01_data_array[4]= ((MO_EMG_Deactivate_HV<<2)&0x1C)
EMG_01_data_array[4]=0xFF;
EMG_01_data_array[5]=0x01;
#EMG_01_data_array[4]= 0x26;
#EMG_01_data_array[5]= (MO_EMG_MaxVoltage&0x1)
#=
EMG_01_data_array[7]=(MO_EMG_MaxTorqueGradient&0x7F)
#Modify CRC byte[0]
vw_crc_calc(EMG_01_data_array, EMG_01_DLC, EMG_01_MSG_ID)
#Send EMG 01 CAN FRAME
frame = Frame(EMG_01_MSG_ID, EMG_01_data_array, flags=canlib.MessageFlag.STD )
ch_a.write(frame)
#load EMG_02 Frame
EMG_02_counter += 1
if EMG_02_counter>0xF:
EMG_02_counter = 0
#load Data
EMG_02_data_array[1] = ((MO_EMG_MaxCurrent<<4)&0xF0)+(EMG_02_counter&0xF)
EMG_02_data_array[2] = ((MO_EMG_MaxCurrent>>4)&0x7F)+((MO_EMG_MinCurrent<<7)&0x80)
EMG_02_data_array[3] = ((MO_EMG_MinCurrent>>1)&0xFF)
# EMG_02_data_array[4] = ((MO_EMG_MinCurrent>>9)&0x3)
EMG_02_data_array[4] = 0x3D
EMG_02_data_array[5] = (MO_EMG_TorqueReq&0xFF)
EMG_02_data_array[6] = ((MO_EMG_TorqueReq>>8)&0xFF)
EMG_02_data_array[7] = (MO_EMG_MinVoltage&0xFF)
#Modify CRC byte[0]
vw_crc_calc(EMG_02_data_array, EMG_02_DLC, EMG_02_MSG_ID)
#Send EMG 01 CAN FRAME
frame = Frame(EMG_02_MSG_ID, EMG_02_data_array, flags=canlib.MessageFlag.STD )
ch_a.write(frame)
#Constants
B000_const = bytearray ([0x76,0x40,0x01,0x05,0x02,0x00,0x00,0x00])
frame = Frame(0x1B000076, B000_const, flags=canlib.MessageFlag.EXT)
ch_a.write(frame)
B504_const = bytearray ([0xC4,0x09,0x00,0x00,0x26,0x19,0x14,0x51])
frame = Frame(0x504, B504_const, flags=canlib.MessageFlag.STD )
ch_a.write(frame)
B3A3_const = bytearray ([0x17,0x9C,0xFB,0x41,0x42,0x3F,0xFE,0xCC])
frame = Frame(0x3A3, B3A3_const, flags=canlib.MessageFlag.STD )
ch_a.write(frame)
B18B_const = bytearray ([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
frame = Frame(0x18B, B18B_const, flags=canlib.MessageFlag.STD )
ch_a.write(frame)
B18D_const = bytearray ([0x00,0xF0,0x7F,0xC1,0x00,0x80,0x26,0x2])
frame = Frame(0x18D, B18D_const, flags=canlib.MessageFlag.STD )
ch_a.write(frame)
B171_const = bytearray ([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
frame = Frame(0x171, B171_const, flags=canlib.MessageFlag.STD )
ch_a.write(frame)
BEE_const = bytearray ([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00])
frame = Frame(0xEE, BEE_const, flags=canlib.MessageFlag.STD )
ch_a.write(frame)
if i % 2 == 0:
B040_const = bytearray ([0x07,0x0E,0x00,0x00,0x80,0x00,0x20,0x62])
frame = Frame(0x040, B040_const, flags=canlib.MessageFlag.STD )
ch_a.write(frame)
else:
B040_const = bytearray ([0x4B,0x0F,0x00,0x00,0x80,0x00,0x20,0x64])
frame = Frame(0x040, B040_const, flags=canlib.MessageFlag.STD )
ch_a.write(frame)
if i % 2 == 0:
B0FD_const = bytearray ([0x23,0xE0,0x3F,0x00,0x00,0x00,0x00,0x00])
frame = Frame(0x0FD, B0FD_const, flags=canlib.MessageFlag.STD )
ch_a.write(frame)
else:
B0FD_const = bytearray ([0x29,0xE1,0x3F,0x00,0x00,0x00,0x00,0x00])
frame = Frame(0x0FD, B0FD_const, flags=canlib.MessageFlag.STD )
ch_a.write(frame)
B0A8_const = bytearray ([0x00,0xE0,0x3F,0x57,0x7F,0x64,0x00,0x00])
frame = Frame(0x0A8, B0A8_const, flags=canlib.MessageFlag.STD )
ch_a.write(frame)
# Example: print first 5 rows of data
#print(f"{msgID_INT:04x}: ,{d0_INT:04x},{d1_INT:04x},{d2_INT:04x},{d3_INT:04x},{d4_INT:04x},{d5_INT:04x},{d6_INT:04x},{d7_INT:04x}")
#print(i)
time.sleep(0.01)
# Lastly, close all channels with close() to finish up.
ch_a.close()
#ch_b.close()
Sorry, I seem to have missed this post before. The signals in your EM_01 and EM_02 largely match what I was seeing in the firmware and the behavior of the motor. Where did you find those signal definitions and names?
Adrianbb wrote: ↑Tue Mar 10, 2026 4:43 pm So, I got it working with OI sine firmware on olimex STM-H103 board. All needed components are used original (Igbt, drivers, current sensors and position sensor). Only added some voltage dividers where was needed...
Of course, not everything goes according to plan... I haven't been able to get the regen mode running yet. Motor still accelerates in regen mode. I don't know what to do with it anymore, I'll probably start a new thread about this problem.
Nice! Can you elaborate on what firmware you are using? Did you write it yourself or are you using some open source example?
It should be an induction motor. It has what looks like a squirrel cage rotor.
Re: VW Mild Hybrid Starter Alternator
Ah, nice! Now I'm wondering how hard it would be to port to the SPC56 on the stock board...