TSDZ2 OSF for all displays, VLCD5-VLCD6-XH18, LCD3, 860C-850C-SW102.

hello, everyone, I'm a new user of TSDZ2B, and try to update to OSF v20.1 C.6.
but I met a connecting problem.
As the uploaded images, my speed sensor had two cables,
I don't know which one should I connect to ST-link dongle...

Did anyone have the similar setting of two speed sensor cables?
And which one is suittable for flashing OSF?

Many thanks for your help.
View attachment 369698View attachment 369699
You need to follow where the 2 cables go: number 1) should go into the motorhousing (to the controller), the other one - 2) goes to your lights.
You need to connect it to 1)

Ah - @dgc was faster ;)
 
Last edited:
  • Like
Reactions: dgc
New version update for stock displays (with configurator).
v20.1C.6-update-1, this is the list of changes:
1 - Added TSDZ8 to the configurator (for mstrens version).
2 - Fixed motor phase current bug.
3 - Added EKD01 display.
4 - Choice of the fifth level, for displays that support it, before ECO or after TURBO.
5 - Fixed issues with parameter setting and data display.
7 - Improved automatic and manual SOC reset.
6 - Improved torque sensor calibration procedure.
9 - Added delay to E02 error (torque sensor).

The manual SOC reset and torque sensor calibration procedure are much simplified.
For those who want to try, it is on GitHub as a master version:
https://github.com/emmebrusa/TSDZ2-Smart-EBike-1/archive/refs/heads/master.zip
Great, @mbrusa ! I just uploaded it and it seems to work fine.
Especially great is your new calibration procedure, which works without reprogramming, just via the display!
(At least that is how I understood it and how it seemed to work for me)

As always - thank you!
I am amazed what kind of optimization you are still getting out of this old controller.
Talking about product lifetime - none of my phones have such a long software support. :))
 
Must be one of two things, a good controller to start with or a very good programmer or perhaps a bit of both. I can remember doing spreadsheets on a IBM XT / 286 computer calculating pressure ramps against time for industrial processing, my mobile will do it in a flash took 5 minutes on the 286.
 
Must be one of two things, a good controller to start with or a very good programmer or perhaps a bit of both. I can remember doing spreadsheets on a IBM XT / 286 computer calculating pressure ramps against time for industrial processing, my mobile will do it in a flash took 5 minutes on the 286.
386dx33 first PC after atari 800xl i was10 and learned basic on it
 
Strange, I with "Assist Whitout pedaling" enabled, as soon as I put my foot down the motor starts.
Try posting the ini file obtained from the compilation (zipped).
but I have the same on 20,C5 on the SW102...

optimization you are still getting out of this old controller.
Let me ask you, what does "old controller" mean?)) It may well be enough to control not only the motor of a bicycle, but also the systems of a SAM missile)) So "old"... it's a bit of a mouthful) It is quite enough to control this type of engine and newer ones. Yes, the world of electric bicycles is gradually switching to the CAN bus system, but that's another story.

p.s. and well, you can call all this old, unless something truly new comes out)) So far, I don't know of any compact, lightweight mid-drive motor with a torque sensor...
 
Last edited:
Settings for tsdz2b close of bosch performance line cx
here are my settings
i have a bosch performance line bike too... these setting give tsdz2b a comportement close of bosch

Idea is to set hybrid eMTB (eMTB level are used) / torque (torque levels used), to put max RPM for ramp 90 or100 (so you want you run high RPM with assistance)

My setting are legal street mode (250 W 25km/h).

Warning: use patched hybrid mode (hybrid torque mode eMTB power based).
 

Attachments

  • setting.jpg
    setting.jpg
    304.4 KB · Views: 6
  • patch hybrid torque emtb_power.7z
    2.1 KB · Views: 2
  • ebike_app.c
    137 KB · Views: 2
Last edited:
....
Let me ask you, what does "old controller" mean?)) It may well be enough to control not only the motor of a bicycle, but also the systems of a SAM missile)) So "old"... it's a bit of a mouthful) It is quite enough to control this type of engine and newer ones. Yes, the world of electric bicycles is gradually switching to the CAN bus system, but that's another story.

p.s. and well, you can call all this old, unless something truly new comes out)) So far, I don't know of any compact, lightweight mid-drive motor with a torque sensor...
What I was referring to is the old µController used in this Motorcontroller: An 16MHz 8-bit STM8S105. Sure you can do a lot with an 8 bit µController - but for a true FOC algorithm, which 'modern' 32bit µControllers can handle and which make the motors really efficient and quiet, it is just not powerful enough.
Only due to the smart people like @casainho , @stancecoke , @mspider65 and @mbrusa we have now a firmware which does sort of FOC on this 8 bit system.

I was not referring to the complete TSZD2 as 'old'!
I agree that this is still one of the most economic mid-drive motor with torque sensor. And almost everything is DIY repairable with many standard parts incorporated. (I even re-wound one of the torque-sensor-coils once when it was broken - as well as repairing the sensor itself by replacing the (std.) Hall Sensor in it)
 
Last edited:
Great, @mbrusa ! I just uploaded it and it seems to work fine.
Especially great is your new calibration procedure, which works without reprogramming, just via the display!
(At least that is how I understood it and how it seemed to work for me)

As always - thank you!
I am amazed what kind of optimization you are still getting out of this old controller.
Talking about product lifetime - none of my phones have such a long software support. :))
Hi @endlessolli, yes reading the torque sensor is now easier.
The complete calibration is done by inserting the values of "Pedal torque adc offset" and "Pedal torque adc max" obtained with the new procedure into the configurator, and enabling "Torque sensor adv.", "Calibrated", "Estimated", all three. This is the recommended procedure.
It is true, the new calibration procedure can be completed on the display without reprogramming.
But it is not the same calibration that is obtained by inserting the data into the configurator, the result is similar but there are some differences to consider.
With the display storage, the parameters "Pedal torque adc range adjustment", "Pedal torque adc angle adjustment" are ignored, the scale is always remapped to 160. While "Pedal torque adc offset adjustment" has a different operation.
This alternative calibration is used with "Torque sensor adv." disabled.
While with "Torque sensor adv." enabled, if the calibration has not been done also in the configurator, the motor will work without calibration.
I added this possibility because, over time, the torque sensor values change to the point of causing error E02, in that case a quick calibration "on the road" can be useful.
 
Hi @endlessolli, yes reading the torque sensor is now easier.
...
But it is not the same calibration that is obtained by inserting the data into the configurator, the result is similar but there are some differences to consider.
With the display storage, the parameters "Pedal torque adc range adjustment", "Pedal torque adc angle adjustment" are ignored, the scale is always remapped to 160. While "Pedal torque adc offset adjustment" has a different operation.
This alternative calibration is used with "Torque sensor adv." disabled.
While with "Torque sensor adv." enabled, if the calibration has not been done also in the configurator, the motor will work without calibration.
I added this possibility because, over time, the torque sensor values change to the point of causing error E02, in that case a quick calibration "on the road" can be useful.

Dear @mbrusa : Could you explain (again?) how "Pedal torque adc range adjustment" works (when using the configurator calibration)?
As an example:
I use Power Assist and I have 'Torque sensor adv.', 'Calibrated' and 'Estimated' enabled.
I have entered measured values for 'Pedal Torque ADC offset (no weight)' = 53 and 'Pedal Torque ADC max (max weight)' = 143, so I have a (rather low) range of 90.
I assume, this '90' range is then mapped to '160' for 'Pedal torque adc range adjustment' = 0?
(and mapped to 133 with range adjustment set to -20 or mapped to 186 when set to +20.)
But what does that really do in terms of behavior?

With default value ('0'), I never can get my controller to deliver high Amperes, even with max pressure on the pedal. (compared to using no calibration at all)
How do need to change 'Pedal torque adc range adjustment' to give me more Amps at a given (high) pedal pressure?
In the direction of +20 or -20?
 
Settings for tsdz2b close of bosch performance line cx
here are my settings
i have a bosch performance line bike too... these setting give tsdz2b a comportement close of bosch

Idea is to set hybrid eMTB (eMTB level are used), to put max RPM for ramp 90 or100 (so you want you run high RPM )

My setting are legal street mode (250 W 25km/h).

Warning: use patched hybrid mode (eMTB hybrid).
I'm glad you found settings that satisfy you.
There is one thing that leaves me perplexed, and it is in almost all of your posts, the reference to 250W as maximum power.
I have never intervened because I have no intention of starting yet another discussion on the difference between nominal power and maximum power. You can find as many online as you want.
The maximum power of the Bosch Performance Line CX is 600W.
Hearing that a TSDZ2B with maximum power limited to 250W has a behavior close to Bosch, leaves me very perplexed. I don't know what to think.
 
Dear @mbrusa : Could you explain (again?) how "Pedal torque adc range adjustment" works (when using the configurator calibration)?
As an example:
I use Power Assist and I have 'Torque sensor adv.', 'Calibrated' and 'Estimated' enabled.
I have entered measured values for 'Pedal Torque ADC offset (no weight)' = 53 and 'Pedal Torque ADC max (max weight)' = 143, so I have a (rather low) range of 90.
I assume, this '90' range is then mapped to '160' for 'Pedal torque adc range adjustment' = 0?
(and mapped to 133 with range adjustment set to -20 or mapped to 186 when set to +20.)
But what does that really do in terms of behavior?

With default value ('0'), I never can get my controller to deliver high Amperes, even with max pressure on the pedal. (compared to using no calibration at all)
How do need to change 'Pedal torque adc range adjustment' to give me more Amps at a given (high) pedal pressure?
In the direction of +20 or -20?
To get more assistance you need to set "Pedal torque adc range adjustment" +20.
More assistance means that the maximum power is reached with less effort.
The maximum power is limited by "Motor power max" and "Battery current max".
Keep in mind that to increase the assistance there are also the level parameters available, with Power assist up to 500%.
There is another parameter that you can try "Pedal torque adc angle adjustment", it was born with another purpose, but it can be used to change the response of the torque sensor.
A negative value decreases the reactivity at low cadence and increases it at high cadence.
A positive value increases the reactivity at low cadence and decreases it at high cadence.
Try +20 and -20, you realize what happens, then there are all the intermediate values.
 
Hey!

edit: solved, common ground was missing.

I am trying to flash my 860C with the OSF firmware, however I can't get the flash to start in the APT Burn tools. I downloaded it from here: APT Burn tools v1.4 - bikel.pl which is the only place I could find it. On the back it says V58, while on with the OEM firmware it says hardware version P1.3 so I used the " 860C_V13-v20.1C.5-1-bootloader.bin" from the github. I am using my battery for the power source and have wired in a FT232 USB TTL converter, and I have seen someone mention they used this? as well as the flashing guide saying any USB TTL should work.

When I wire TX to RX and RX to TX:
I open the port, select the firmware and start the update both TX and RX values go up, if I press or hold the power button the RX stops briefly and then starts back up again. If I hold the power button it also boots the OEM firmware and as stated before the RX continues.

Wiring RX to RX and TX to TX
Opening the port, selecting firmware and starting the update first the TX value only goes up, but then the RX also starts to go up? pressing or holding the power button makes the pause of "rx not going up" to last longer, however after a while it starts going up again. Holding the power button like this does not turn the display on at all.

I have only wired the P+, GND, RX and TX, not the VIN. I also never connected the GND of the battery to the GND of the TTL converter, maybe this is my problem?

Edit: The common ground was my problem, managed to solve it, sorry for not trying that first before posting tho, only figured it out while writing.

I can't find anything about anyone having the exact same issue as me, any help would be appreciated! Once again; thanks for all the work you have put into this awesome project!
Thanks,
Philip
 
Last edited:
I'm glad you found settings that satisfy you.
There is one thing that leaves me perplexed, and it is in almost all of your posts, the reference to 250W as maximum power.
I have never intervened because I have no intention of starting yet another discussion on the difference between nominal power and maximum power. You can find as many online as you want.
The maximum power of the Bosch Performance Line CX is 600W.
Hearing that a TSDZ2B with maximum power limited to 250W has a behavior close to Bosch, leaves me very perplexed. I don't know what to think.
you right and soon it will be 750W...
but the problem is this firmware isnt certified...
what will happen in case of accident/death?
What is a short burst of power (not nominal).
I am ingenier and physic teacher but not lawyer.
i searched in EU law but nothing about this point, except motor are tested in nominal situation... No legal definition of transitiv regim.

I can do transitiv regim 500W for 0.5h and 4h 250W. Nominal will be 250W but not sure a lawyer will think so.
So how much time can we sustain 500W to be legal street mode ? 2 min? 1 min ? 30 s? 1s? no respons in legislation.
Bosch maintain it a few second but is certified with his firmware... that's the difference.

So i blocked to 250W it's more restrictive but in case of expertise it's more safe because you cant force motor (by setting at display offroad) to deliver more.

Edit : indeed tsdz2b dont has power burst bosch has in legal street 250w mode , even if you set 500w max power offroad)

So the feeling is different.
I 100% prefer bosch I bought one and dont regret it. I would buy again it's valuable.

I needed a cheap good motor to set an emtb for Holliday using my common every day bike battery . I needed a bike which can be fit back to muscular quickly if I take plane to my Holliday location, without battery.

Tsdz2 is not bosch and will never but it can be somehow similar. The big point is lack of inertial captor...
 
Last edited:
hybrid modification:
i tried to combine torque mode and emtb power based in a new hybrid function.
Better for eMTB.

Here is the new code of hybrid (ebike_app.c). you can modify manually before compile&flash or use patch (put in src folder)
to use you have to be in hybrid mode (javaconfigurator ). You can patch before using javaconfigurator compile and flash.

static void apply_hybrid_assist(void)
{
#define eMTB_ASSIST_DENOMINATOR_MIN 10 // Minimum denominator for eMTB assistance calculation

uint16_t current_target_from_torque = 0; // Target current from torque assist
uint16_t current_target_from_power = 0; // Target current from power assist
uint16_t current_target_final = 0; // Final target current (in ADC steps)
uint8_t emtb_mode_parameter = ui8_riding_mode_parameter_array[3][ui8_assist_level];

// Smooth start block (if needed, uncomment below)
// #if SMOOTH_START_ENABLED
// apply_smooth_start();
// #endif

// Check for assistance without pedal rotation:
// If the system is configured for no-pedal rotation assist, and no cadence is detected (0 RPM),
// yet the pedal torque delta exceeds a threshold, then simulate a cadence of 1 RPM.
if (m_configuration_variables.ui8_assist_without_pedal_rotation_enabled) {
if ((ui8_pedal_cadence_RPM == 0U) &&
(ui16_adc_pedal_torque_delta > (120 - ui8_assist_without_pedal_rotation_threshold))) {
ui8_pedal_cadence_RPM = 1;
}
}

// Force assistance when an error flag is set:
if (m_configuration_variables.ui8_assist_with_error_enabled) {
ui8_pedal_cadence_RPM = 1;
}

// If there is pedal activity or startup-assist is active, then calculate the assist:
if ((ui8_pedal_cadence_RPM > 0U) || (ui8_startup_assist_adc_battery_current_target)) {

// --- Torque-based assist (immediate response) ---
if (ui16_adc_pedal_torque_delta > 0U) {
uint8_t torque_assist_factor = ui8_riding_mode_parameter_array[TORQUE_ASSIST_MODE - 1][ui8_assist_level];
current_target_from_torque = (ui16_adc_pedal_torque_delta * torque_assist_factor) / TORQUE_ASSIST_FACTOR_DENOMINATOR;
} else {
current_target_from_torque = 0;
}

// --- Power-based (eMTB) assist (progressive response) ---
uint16_t assist_denominator = (508 - (emtb_mode_parameter << 1)) + eMTB_ASSIST_DENOMINATOR_MIN;
if (assist_denominator >= ui8_pedal_cadence_RPM) {
assist_denominator -= ui8_pedal_cadence_RPM;
}
else {
assist_denominator = 0;
}
assist_denominator += eMTB_ASSIST_DENOMINATOR_MIN;

uint16_t effective_delta = (uint16_t)(
(((uint32_t)ui16_adc_pedal_torque_delta * ui16_adc_pedal_torque_delta) + assist_denominator)
/ assist_denominator
);
current_target_from_power = effective_delta;

// --- Select the maximum contribution ---
if (current_target_from_power > current_target_from_torque) {
current_target_final = current_target_from_power;
} else {
current_target_final = current_target_from_torque;
}

// Apply the motor ramping (smoothing of acceleration/deceleration)
set_motor_ramp();

// Limit the final current target to the maximum allowed value
if (current_target_final > ui8_adc_battery_current_max) {
ui8_adc_battery_current_target = ui8_adc_battery_current_max;
} else {
ui8_adc_battery_current_target = (uint8_t) current_target_final;
}

#if STARTUP_ASSIST_ENABLED
// Startup assist: if startup assist flag is active, adjust the current target accordingly.
if (ui8_startup_assist_flag) {
if (ui8_adc_battery_current_target > ui8_startup_assist_adc_battery_current_target) {
ui8_startup_assist_adc_battery_current_target = ui8_adc_battery_current_target;
}
ui8_adc_battery_current_target = ui8_startup_assist_adc_battery_current_target;
} else {
ui8_startup_assist_adc_battery_current_target = 0;
}
#endif

// Set the PWM duty cycle target. If current target is nonzero, apply maximum PWM.
ui8_duty_cycle_target = (ui8_adc_battery_current_target) ? PWM_DUTY_CYCLE_MAX : 0;
}
}
 

Attachments

  • patch hybrid torque emtb_power.7z
    2.1 KB · Views: 0
  • ebike_app.c
    137 KB · Views: 2
hybrid modification:
i tried to combine torque mode and emtb power based in a new hybrid function.
Better for eMTB.

Here is the new code of hybrid (ebike_app.c). you can modify manually before compile&flash or use patch (put in src folder)
to use you have to be in hybrid mode (javaconfigurator ). You can patch before using javaconfigurator compile and flash.

static void apply_hybrid_assist(void)
{
#define eMTB_ASSIST_DENOMINATOR_MIN 10 // Minimum denominator for eMTB assistance calculation

uint16_t current_target_from_torque = 0; // Target current from torque assist
uint16_t current_target_from_power = 0; // Target current from power assist
uint16_t current_target_final = 0; // Final target current (in ADC steps)
uint8_t emtb_mode_parameter = ui8_riding_mode_parameter_array[3][ui8_assist_level];

// Smooth start block (if needed, uncomment below)
// #if SMOOTH_START_ENABLED
// apply_smooth_start();
// #endif

// Check for assistance without pedal rotation:
// If the system is configured for no-pedal rotation assist, and no cadence is detected (0 RPM),
// yet the pedal torque delta exceeds a threshold, then simulate a cadence of 1 RPM.
if (m_configuration_variables.ui8_assist_without_pedal_rotation_enabled) {
if ((ui8_pedal_cadence_RPM == 0U) &&
(ui16_adc_pedal_torque_delta > (120 - ui8_assist_without_pedal_rotation_threshold))) {
ui8_pedal_cadence_RPM = 1;
}
}

// Force assistance when an error flag is set:
if (m_configuration_variables.ui8_assist_with_error_enabled) {
ui8_pedal_cadence_RPM = 1;
}

// If there is pedal activity or startup-assist is active, then calculate the assist:
if ((ui8_pedal_cadence_RPM > 0U) || (ui8_startup_assist_adc_battery_current_target)) {

// --- Torque-based assist (immediate response) ---
if (ui16_adc_pedal_torque_delta > 0U) {
uint8_t torque_assist_factor = ui8_riding_mode_parameter_array[TORQUE_ASSIST_MODE - 1][ui8_assist_level];
current_target_from_torque = (ui16_adc_pedal_torque_delta * torque_assist_factor) / TORQUE_ASSIST_FACTOR_DENOMINATOR;
} else {
current_target_from_torque = 0;
}

// --- Power-based (eMTB) assist (progressive response) ---
uint16_t assist_denominator = (508 - (emtb_mode_parameter << 1)) + eMTB_ASSIST_DENOMINATOR_MIN;
if (assist_denominator >= ui8_pedal_cadence_RPM) {
assist_denominator -= ui8_pedal_cadence_RPM;
}
else {
assist_denominator = 0;
}
assist_denominator += eMTB_ASSIST_DENOMINATOR_MIN;

uint16_t effective_delta = (uint16_t)(
(((uint32_t)ui16_adc_pedal_torque_delta * ui16_adc_pedal_torque_delta) + assist_denominator)
/ assist_denominator
);
current_target_from_power = effective_delta;

// --- Select the maximum contribution ---
if (current_target_from_power > current_target_from_torque) {
current_target_final = current_target_from_power;
} else {
current_target_final = current_target_from_torque;
}

// Apply the motor ramping (smoothing of acceleration/deceleration)
set_motor_ramp();

// Limit the final current target to the maximum allowed value
if (current_target_final > ui8_adc_battery_current_max) {
ui8_adc_battery_current_target = ui8_adc_battery_current_max;
} else {
ui8_adc_battery_current_target = (uint8_t) current_target_final;
}

#if STARTUP_ASSIST_ENABLED
// Startup assist: if startup assist flag is active, adjust the current target accordingly.
if (ui8_startup_assist_flag) {
if (ui8_adc_battery_current_target > ui8_startup_assist_adc_battery_current_target) {
ui8_startup_assist_adc_battery_current_target = ui8_adc_battery_current_target;
}
ui8_adc_battery_current_target = ui8_startup_assist_adc_battery_current_target;
} else {
ui8_startup_assist_adc_battery_current_target = 0;
}
#endif

// Set the PWM duty cycle target. If current target is nonzero, apply maximum PWM.
ui8_duty_cycle_target = (ui8_adc_battery_current_target) ? PWM_DUTY_CYCLE_MAX : 0;
}
}
It would probably be good if you start a separate thread for your modification suggestions.
Orherwise is gets very hard to follow this thread. Also, people interested in your changes can find those easier.
Just a suggestion.
 
Hey!

edit: solved, common ground was missing.

I am trying to flash my 860C with the OSF firmware, however I can't get the flash to start in the APT Burn tools. I downloaded it from here: APT Burn tools v1.4 - bikel.pl which is the only place I could find it. On the back it says V58, while on with the OEM firmware it says hardware version P1.3 so I used the " 860C_V13-v20.1C.5-1-bootloader.bin" from the github. I am using my battery for the power source and have wired in a FT232 USB TTL converter, and I have seen someone mention they used this? as well as the flashing guide saying any USB TTL should work.

When I wire TX to RX and RX to TX:
I open the port, select the firmware and start the update both TX and RX values go up, if I press or hold the power button the RX stops briefly and then starts back up again. If I hold the power button it also boots the OEM firmware and as stated before the RX continues.

Wiring RX to RX and TX to TX
Opening the port, selecting firmware and starting the update first the TX value only goes up, but then the RX also starts to go up? pressing or holding the power button makes the pause of "rx not going up" to last longer, however after a while it starts going up again. Holding the power button like this does not turn the display on at all.

I have only wired the P+, GND, RX and TX, not the VIN. I also never connected the GND of the battery to the GND of the TTL converter, maybe this is my problem?

Edit: The common ground was my problem, managed to solve it, sorry for not trying that first before posting tho, only figured it out while writing.

I can't find anything about anyone having the exact same issue as me, any help would be appreciated! Once again; thanks for all the work you have put into this awesome project!
Thanks,
Philip
We have already talked about powering the display from the battery.
Even if you power the display with an external battery, you must also connect GND.
Possibly try to invert TX with RX.
860C V1.6 is a version that I do not know, try the file 860C_v20.1C.5-1-bootloader.bin, it is for version 2.0 but it could work.
Finally!! Thank you!! It was a ground problem! It flashed no problem.
 
Hi,

I just flashed OSF v20.1C.6 on my TSDZ2b (250W / 36V).
After biking a bit, I started getting E07 errors (overcurrent).

Any idea where it could be coming from?

I just observed I didn't change the street power limit to 500W.
Should I restrict it too ? (to 250W?)
 

Attachments

  • Capture_osf.PNG
    Capture_osf.PNG
    251.8 KB · Views: 3
Hi,

I just flashed OSF v20.1C.6 on my TSDZ2b (250W / 36V).
After biking a bit, I started getting E07 errors (overcurrent).

Any idea where it could be coming from?

I just observed I didn't change the street power limit to 500W.
Should I restrict it too ? (to 250W?)
I would say yes... legal is 250w nominal.
 
Back
Top