• Hello ES! We could use some help to get us past the finish line on building the new knowledgebase for the forum.
    Can you donate? Please see our fundraising page. Thank you!

TSDZ8 OSF (open source firmware)

At this stage, I would like to finalise some changes before moving some code in separate files and use conditional #include.
This could probably be done but take care that later on, I expect to remove all those options and just keep the best one.
I created the new options (#define) to allow to test each new functionality one by one so, better isolate bugs.

About lead angle: In principe lead angle should increase with speed (erps) and with current. In main branch, only current was taken into account. In TSDZ2, it was based on (1/2 * current + 1/2 current /duty_cycle). Here I consider than duty cycle varies logically from 0...1 (in fact it varies from 0 to 255 because OSF does not manage fractional).
In my new version with DYNAMIC LEAD_ANGLE = 2, I plan to set a basis value based on erps and the ESC should adjust slightly.

At this stage, I do not focuss to much on lead angle. I would already be happy if the motor runs with the new code (increasing precision of rotor position) and with no pll, no dynamic hall positioning, no dynamic lead angle.
When this works, we can test the option in a wel defined sequence.

About the value of current: I was not able to compare the real current with the values provided by OSF. For TSDZ2, mbrusa made test and saw that to convert ADC (10bit) to Amp, he add to multiply by 16 and divide by 100. I first did the same for TSDZ2 (still reducing the ADC from TSDZ8 from 12 bits to 10bits to keep the same ratio). Ebikestuff made tests (at the very beginning of OSF TSDZ8) and he said that the values provided by OSF matches the real measurements he made. That is why I kept this ratio. If you now see that the values does not matches, best is to change the ratio that is defined in main.h
#define BATTERY_CURRENT_PER_10_BIT_ADC_STEP_X100 16 // 0.16A x 10 bit ADC step
 
@HazzaHodgson
I just put on github (for 860C ; in test 1 branch) a new version.
I found several bugs in the PLL code (provided by chatgpt).
I also made some changes in order to be able to disable/enable PLL. I added a new #define in main.h
#define USE_PLL_FOR_POSITION_AND_VELOCITY (0) // do not use PLL (use only interpolation on HALL)
// still use PLL to be able to compare
// (1) calculate rotor position using PLL once rpm is high enough
I strongly suggest that you first try with option (0) PLL disabled and other options on 0 too.
You could see if motor runs fine with option 0 and no load.
If it still does not work, there is no sense to go further.
If OK you can try with some load (e.g. applying some brake on the wheel)
If OK, you can try to activate PLL with no load and with load.

If this work it should already be a success (even if this does not really improve compare to the main version)
 
i tried all options 0 and motor started but i still get the square wave sounding issue
eventually motor blocked msg
I checked the code once more and did not find a real bug.
Still there is a check that stop automatically the motor when rpm is to slow. In main branch, the value was set to 75 rpm. In the code in test 1 branch it was set on 150 rpm. It could be that when motor starts, it does not get immediately this speed. It is calculated based on the time required to make 1/6 of an electric revolution (so also at the very beginning). If the value is too high, it could be that the motor start and stop immediately. I put on gihub (test branch) a version where the value is set on 75 instead of 150.
When all options are set on 0, the version in test has nearly the same code as the version in main branch except that all angles are now 256 X bigger and some are in int16 or uint16 instead of uint8 (this is q8_8_t and uq8_8_t types).

For info, the parameter that define the min rpm that stop the motor is added in main.h
 
I checked the code once more and did not find a real bug.
Still there is a check that stop automatically the motor when rpm is to slow. In main branch, the value was set to 75 rpm. In the code in test 1 branch it was set on 150 rpm. It could be that when motor starts, it does not get immediately this speed. It is calculated based on the time required to make 1/6 of an electric revolution (so also at the very beginning). If the value is too high, it could be that the motor start and stop immediately. I put on gihub (test branch) a version where the value is set on 75 instead of 150.
When all options are set on 0, the version in test has nearly the same code as the version in main branch except that all angles are now 256 X bigger and some are in int16 or uint16 instead of uint8 (this is q8_8_t and uq8_8_t types).

For info, the parameter that define the min rpm that stop the motor is added in main.h
i see speed update properly and everything. I just checked and git pull didnt sync your most recent commits D:. ill try again and get back to you asap! i just received the gear to flash my display so im going to play with that firmware next. I was thinking of adding a lot of toggles and menu items to test stuff on the fly rather than compile, flash, compile, flash, it gets exhausting running up and down stairs xD i finally figured out how to flash using linux which saves a huuuuuuuuuuge amount of time (i had to reboot to windows to flash everytime) -_________- also fyi, i changed adc steps for current from 16 to 15 and its a lot closer of a reading to my watt meter now. i had to change in main.h the limits to match
#define ADC_10_BIT_BATTERY_EXTRACURRENT 53 (8)
#define ADC_10_BIT_BATTERY_CURRENT_MAX 200 (30)
#define ADC_10_BIT_MOTOR_PHASE_CURRENT_MAX 333 (50)
EDIT: i just checked again and it did infact sync, i just looked at the dates and times not lncluding motor.c etc lol
but yeah it really sounds like phase/hall missmatch
i had pretty high wattage pulled when i last tested t (250 watts with no load)
the motor blocked error will be the result of halls/phase
it does spin smooth-ish however it sounds like a cheap square wave controller which makes me think halls are just not processing. when i was messing around with my previous motor which was a geared hub, when halls/phases were missmatched i got different results, i either
1. span backwards
2. heavy vibrating and shuddering - no rotation
3. would spin slowly but sound loud and high power pull
3rd one is what i get testing your current build
 
Last edited:
in the meantime, if anyones interested ;)
My most recent custom build

A meme-grade performance firmware for the TSDZ8 mid-drive that somehow survived QA.
It rethinks the FOC angle, duty-ramp logic, and launch behaviour — delivering snappier torque, smoother soft-starts, and occasional rider ejection.

Safe to test. Unsafe to underestimate.

⚙️ Core Features
⚡ Phase amps up. Battery amps follow. TSDZ16 for the price of a z8 :) 50A/30A

⚡ Launch Logic 2.0 — spins slow until it feels a load, then delivers divine punishment.

🧠 FOC Advance Personality — adaptive lead-angle based on current and mood.

🛞 Duty Cycle Controller — progressive ramp with soft-launch failsafe (because hard-launch was a lawsuit).

🔥 Overcurrent Handler — tries its best to stop you from reinventing fireworks.

🧯 Failsafe Timeout — gives up after 300 ticks, assumes you met God.

🧠 Commit Highlights
feat: launch control implemented — sometimes launches you too
fix: motor now understands "gently" (most days)
perf: 0-to-oh-dear-god times improved by 420%
refactor: smoothed duty ramp, roughened pavement
docs: added disclaimer so my lawyer can sleep
meta: rider lift coefficient successfully exceeds expectations

🧩 Known Issues

May treat gentle throttle as emotional betrayal.

Chain durability now measured in seconds per smile.

Occasionally confuses “traction” with “suggestion.”

Hybrid and Power pas modes are currently borked

⚠️ Disclaimer
DO NOT USE IF YOUR BATTERY BMS IS LOWER THAN 30A
I can make a release for normal 24a if requested

This firmware is tuned for enthusiastic physics experiments.
Safety limits (voltage, current, thermal) remain active — but physics doesn’t care.
Use at your own risk. Possible side-effects include:

spontaneous wheelies,

emotional bonding with asphalt,

and unplanned rapid ascension events.

Ride safe, laugh louder, and remember:
Torque is a privilege, not a right.

Grab it here - Release TSDZ8 — Motor Launch Yes / Rider Launch Yes · 8hodgsonkh/OSF_860C
 
I've taken a video of the hall sensor order if it's any use, it's a random pattern I believe it should be a constant sequence? Unless display just doesn't update it fast enough
 
I've taken a video of the hall sensor order if it's any use, it's a random pattern I believe it should be a constant sequence? Unless display just doesn't update it fast enough
The refresh rate on the display is not fast enough. At max speed (4700rpm), the value changes about 300 erps * 6 sector = 1800Hz..
The communication rate between controller and display is much much slower.
The value makes sense only when motor is halted.
 
The refresh rate on the display is not fast enough. At max speed (4700rpm), the value changes about 300 erps * 6 sector = 1800Hz..
The communication rate between controller and display is much much slower.
The value makes sense only when motor is halted.
yeah had same issue. i tried enabling the stuff in main.h just to make sure and it gave the very distinctive hall missmatch vibrations so its confirmed
 
Did you already tried to change from #define RPM_FOR_STOP 150 to #define RPM_FOR_STOP 75.
Before my last github, it was in motor.c but in last update, I moved it to main.h when I chaged 150 to 75.
 
yeah, i can run motor slow to keep it going but its running very badly, i get the motor blocked message from a safety clamp, that usually trips if i hold brake and try power motor
 
@HazzaHodgson

For your information, the best way to analyse data on the controller is the uprobe tool with segger link. It is quite easy to use.
In order to use it, I took an extension cord for the wheel speed sensor. I removed the external plastic isolator in the middle. I got access to 3 wires (GND, SWD, SWO and I connected themtoo to a connector) . I made another cable that allows me to link to Segger device. When I want to flash or analyse data, I just connect segger to the connector on the extension cord. Itook care not to connect Vcc. So Segger can't never provide power supply to the controller. When I want to flash, I power ther controller with the main battery and the display button. To analyse the data with uprobe I do the same.
 
yeah, i can run motor slow to keep it going but its running very badly, i get the motor blocked message from a safety clamp, that usually trips if i hold brake and try power motor
Do you get an error code on the display? This code could at least say the check being activated.
 
so a splitter cable? speed sensor always plugged in with an extra port for segger? or u mean just the cable for segger?
on mine its got the normal speed sensor plug that splits into 4 to plug into the segger, if i just dont plug in the vcc and power controller it will work? i tried without vcc once but jflash didnt see controller i guess thats cos i didnt power it up with bike battery?
 
Do you get an error code on the display? This code could at least say the check being activated.
not an error code, just the "motor blocked" error message
this is activated with
static uint8_t ui8_motor_blocked_counter;

// if battery current is over the current threshold and the motor ERPS is below threshold start setting motor blocked error code
if ((ui16_battery_current_filtered_x5 > MOTOR_BLOCKED_BATTERY_CURRENT_THRESHOLD_X5)
&& (ui16_motor_speed_erps < MOTOR_BLOCKED_ERPS_THRESHOLD)) {
// increment motor blocked counter with 100 milliseconds
++ui8_motor_blocked_counter;

// check if motor is blocked for more than some safe threshold
if (ui8_motor_blocked_counter > MOTOR_BLOCKED_COUNTER_THRESHOLD) {
// set error code
ui8_m_system_state |= ERROR_MOTOR_BLOCKED;
}
}
else {
// current is below the threshold and/or motor ERPS is above the threshold so reset the counter
ui8_motor_blocked_counter = 0;
}
 
not an error code, just the "motor blocked" error message
this is activated with
static uint8_t ui8_motor_blocked_counter;

// if battery current is over the current threshold and the motor ERPS is below threshold start setting motor blocked error code
if ((ui16_battery_current_filtered_x5 > MOTOR_BLOCKED_BATTERY_CURRENT_THRESHOLD_X5)
&& (ui16_motor_speed_erps < MOTOR_BLOCKED_ERPS_THRESHOLD)) {
// increment motor blocked counter with 100 milliseconds
++ui8_motor_blocked_counter;

// check if motor is blocked for more than some safe threshold
if (ui8_motor_blocked_counter > MOTOR_BLOCKED_COUNTER_THRESHOLD) {
// set error code
ui8_m_system_state |= ERROR_MOTOR_BLOCKED;
}
}
else {
// current is below the threshold and/or motor ERPS is above the threshold so reset the counter
ui8_motor_blocked_counter = 0;
}
OK. I forgot that this check exists. So there is clearly some bug in the way the magnetic flux is generated but I do not see the bug in the code. I will make a copy of old and new motor.c and remove all unused stuff when all options are set on 0? Perhaps this comparison will help finding the mistake.
 
okay good luck!
are you unable to test too?
hall positions might be unique to each motor
with q8 calculations instead of it being more accurate it could wildly spin out instead. idk lol
 
okay good luck!
are you unable to test too?
hall positions might be unique to each motor
with q8 calculations instead of it being more accurate it could wildly spin out instead. idk lol
I can't test myself currently.
Hall positions are (nearly) the same for all motors otherwise version from main branch would not work.

usin Q8_8 format does not change the logic. It just wrap on 16bits just like uint8 wrap after 8 bit. So it wraps over 360° (65536 is equivalent to 360°)
 
I can't test myself currently.
Hall positions are (nearly) the same for all motors otherwise version from main branch would not work.

usin Q8_8 format does not change the logic. It just wrap on 16bits just like uint8 wrap after 8 bit. So it wraps over 360° (65536 is equivalent to 360°)
how comes? away from home or motor broke or smth?
since you know to uprobe and stuff, would be much easier diagnosing some bugs...could also check some tweaks i did.
if not totally ok, i will keep testing your builds now and then. ill try learn to probe, but a bit awkward for me since my pc upstairs bike downstairs, so i cant physically watch the motor while i probe lol
 
so it turns out u can flash osf on 860 display using jtlink (if its V9 +) no need for expensive bootloader bot.
took me many attempts to try get it to update....it updated, 10% progress then failed. kept failing. 9 hours later i decided to try windows com driver instead of segger and flashed np. thought i bricked it :|
 
so it turns out u can flash osf on 860 display using jtlink (if its V9 +) no need for expensive bootloader bot.
took me many attempts to try get it to update....it updated, 10% progress then failed. kept failing. 9 hours later i decided to try windows com driver instead of segger and flashed np. thought i bricked it :|
That seems good to know. Considering you need the j-link for the controller anyway. Still need an separate power source for the display, I assume?
 
ill try learn to probe, but a bit awkward for me since my pc upstairs bike downstairs, so i cant physically watch the motor while i probe lol
I use a Bluetooth module like the HM10 instead of the display to send the interested data to my mobile phone during test rides. You can analyze the data stream afterwards on your PC, or look at the live data on your phone. This helps a lot, to see what happens during real riding.
1760333617199.png
 
That seems good to know. Considering you need the j-link for the controller anyway. Still need an separate power source for the display, I assume?
I don't think it's a reliable method actually I think I bricked my display 😂either because of a bad flash OR v13 being annoying with bootloaders. I think it's flashing the app at the address xxxxx0000 rather than xxxxx5000(I can't remember exactly numbers) I think this is because of being stuck with apt burn. I can't choose the address to flash there. Tried making sure the mapping is right with firmware. I've got a usb2uart chip coming today to see if that's the problem or not.
And about the power source I tried 2 different things
First one was with powering + and grnd from the 5v on jlink into a bucket converter to increase voltage to display. It's too weak to power my display ( it just flickers on)
The 2nd one I ran 5v and grd to the buck from a usb charger plug. This powered my display perfectly but the flashing would always stop at 10% or 13%. I never got a successful flash that way. I did with the first method (according to apt burn) is just click power fast and it would flash. But I'm not sure if that being unstable for power is why my screen wont fully boot or if it's because of bootloader issues. I tried loads of different versions V12, v13, v20
I will confirm once I attempt with the usual usb2uart adapter.
Also it could be my pcs usb power isn't strong enough but I was trying it from a usb 3.2 port
Powering from ebike battery is out the question for me unless I put the display back on my bike and ran my usb extension down like I do for my controller. Ironically I e never had an issue flashing my controller with a 20 metre extension 😭
 
Hi everyone, I tested the Katalana 35 version on a mountain bike, but it doesn't work at all. It has no power uphill. It maxes out at 600 watts, and at high pedal rotations, it reaches 100 rpm.
The motor dies and cuts out power. At this point, the original software is much better.
Which version do you recommend I try? I mountain bike on unpaved climbs, including steps and obstacles. I need continuous power of 1000 watts at other frequencies.
Which version can I try?
 
Hi everyone, I tested the Katalana 35 version on a mountain bike, but it doesn't work at all. It has no power uphill. It maxes out at 600 watts, and at high pedal rotations, it reaches 100 rpm.
The motor dies and cuts out power. At this point, the original software is much better.
Which version do you recommend I try? I mountain bike on unpaved climbs, including steps and obstacles. I need continuous power of 1000 watts at other frequencies.
Which version can I try?
Do you use 860c display? If not did you setup the right params and flash the config?
 
Back
Top