Skip to content

Add support for the Sequre Si012 Pro Max - #2247

Merged
Ralim merged 4 commits into
Ralim:devfrom
amanpd7:si012-pro-max
Oct 17, 2026
Merged

Ralim merged 4 commits into
Ralim:devfrom
amanpd7:si012-pro-max

Conversation

@amanpd7

@amanpd7 amanpd7 commented Oct 14, 2026

Copy link
Copy Markdown
Contributor
  • Please check if the PR fulfills these requirements
  • The changes have been tested locally
  • There are no breaking changes known (if there are, detail these at the end)
  • What kind of change does this PR introduce?

New device support (Sequre Si012 Pro Max), plus a few small shared fixes.

  • What is the current behaviour?

The Si012 Pro Max is not supported. #2124 (thanks @jemarro12, whose pin map and bootloader offset this builds on) got it booting, but only one tip socket worked, PD did not, and the two sockets turned out to be mapped the wrong way round.

  • What is the new behaviour (if this is a feature change)?

New model Si012ProMax in the Sequre BSP (S99 flash layout, 0x4C00 bootloader):

  • Both tip sockets work: T12 on PB9/PA6, TS/SI on PB8/PA0 (swapped compared to Si012 Pro Max first Build #2124, confirmed on hardware). The socket in use is picked automatically and only its MOSFET is driven. T12 has priority; TS/SI is only selected from the home screen.
  • If both sockets read a tip at once (bare T12 body touching the TS/SI contacts), it shows "Tip Shorted" and drives neither. This is a real short on this hardware; the stock firmware reports it too.
  • PD: the HUSB238 runs standalone and the stock firmware never talks to it, so the input is just measured and treated as DC.
  • Flipped OLED, buzzer, the 10 LEDs (new LED mode setting: off / status / temperature / power), TC1047 board temperature cut-out.

Shared changes:

  • settings.yaml entries can have an include: macro, so the two new settings only exist on models that use them. Other models do not grow (the T55 CJK build only has ~28 bytes free in CI).

  • Debug menu: the MCU temperature item was unreachable on builds without a hall sensor (S99). Fixed.

  • Per-socket CJC offset, and isMCUTemperatureValid() so an implausible board sensor cannot trip the cut-out.

  • Other information:

Tested on my Si012 Pro Max: socket detection and heating on both sockets, short detection, PD (~20.6 V), flashing through the stock bootloader. Built for all languages on Si012ProMax and S60, and EN on S99, S60P, T55 and TS100.

Not verified yet: absolute tip temperature. Solder melt tests suggest it reads about 10% high (the S60 conversion is reused). I have a tip thermometer on order and will update the conversion. Opening as a draft until then.

  • An LLM (AI) was used for some of this code
  • An LLM was used, and I have manually audited the code. I understand what changes it made and why.

Most of the code changes and this description were drafted with Claude (Anthropic). The hardware testing, measurements and decisions were mine.

Builds on the first port by @jemarro12 in Ralim#2124 (pin map, 0x4C00 bootloader
offset, S60 thermocouple scaling), with the open points from that PR resolved
and verified on hardware.

Si012 Pro Max (new model Si012ProMax, Sequre BSP):
- Two tip sockets: T12 (PB9 / PA6) and TS / SI (PB8 / PA0). Ralim#2124 had these
  the other way round; confirmed on hardware. Both are sampled every cycle and
  the socket in use is picked automatically; only its MOSFET is ever driven.
- T12 has priority; the TS / SI socket is only selected from the home screen,
  and its output is refused while a T12 is sensed. A bare T12 body touching
  the TS / SI contacts is latched as "Tip Shorted" with no output (a real
  short on this hardware, as the stock firmware reports too).
- USB-C PD is a standalone HUSB238 the MCU does not talk to (the stock
  firmware only addresses the OLED), so the input is measured and treated as
  DC; this fixes the "PD debug state 55" seen in Ralim#2124.
- OLED mounted flipped, buzzer, 10 status LEDs with selectable modes
  (off / status / temperature bar / power bar), TC1047 board temperature
  cut-out with a plausibility check against the handle NTC at boot.
- S99 flash layout (0x4C00 bootloader, 78K code), 100 W cap, per-socket tip
  resistance defaults from Sequre's power chart.

Shared changes:
- Settings: optional "include" in settings.yaml so a setting only exists on
  models that define the macro; other models do not grow (the T55 CJC build
  has ~28 bytes to spare in CI).
- Debug menu: the MCU temperature item was unreachable on builds without a
  hall sensor (S99); also adds the active socket and the unused socket's raw
  reading on dual socket irons.
- Per-socket CJC calibration offset on dual socket irons.
- isMCUTemperatureValid() so an implausible board sensor cannot trip the
  thermal cut-out.

Not yet verified: absolute tip temperature (solder tests suggest the display
reads ~10% high; calibration with a tip thermometer to follow).
@amanpd7

amanpd7 commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

@Ralim need you to review this PR, i have already switched to IronOS with SI012 pro max and will update if i find any issues

@amanpd7
amanpd7 marked this pull request as ready for review October 14, 2026 09:09
Comment thread source/Core/BSP/Sequre/configuration.h Outdated

#ifdef MODEL_Si012ProMax
/*
* Sequre Si012 Pro Max: S60 / S99 style board with two tip sockets (T12 and TS100 / SI), each with its own

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please re-word these to be less LLM-speak if at all possible

Comment thread source/Core/BSP/Sequre/Setup.cpp Outdated
return (int16_t)((senseMv - 500) / 10);
}

// At boot the board and the handle are at about the same temperature. If the sensor disagrees with the handle

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't make this assumption; as a unit that has been aggressively used then power cycled would break this assumption.

Comment thread source/Core/Inc/Settings.h Outdated
SolderingTipType = 54, // Selecting the type of soldering tip fitted
ReverseButtonSettings = 55, // Change the A and B button assigment in Settings menu
BuzzerEnabled = 56, // Buzzer on/off (devices with a buzzer)
// Settings below only exist on the models that need them (see "include" in settings.yaml), so the ones above

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All settings need to have a fixed number, that is the same on all models

@@ -0,0 +1,5 @@
#include "ui_drawing.hpp"
#if defined(OLED_128x32) && defined(DUAL_TIP_SOCKETS)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a dedicated screen by itself, so should go in a utilities folder/file or in the file its used in.

Comment thread source/Core/Threads/UI/logic/utils/SolderingCommon.cpp
Comment thread README.md Outdated
| Sequre S60 | ❌ | ❌ | ✔️ | ❌ | ❌ | ❌ | ✔️ | Full OLED resolution not yet supported. |
| Sequre S60P | ❌ | ❌ | ✔️ | ❌ | ❌ | ❌ | ✔️ | Full OLED resolution not yet supported. |
| Sequre S99 | ✔️ | ❌ | ✔️ | ❌ | ❌ | ❌ | ✔️ | Buzzer. Selectable tip (5.5Ω/2.5Ω). |
| Sequre Si012 Pro Max | ✔️ | ❌ | ✔️ | ❌ | ❌ | ❌ | ✔️ | Buzzer, LEDs. T12 and TS/SI sockets, auto-selected. |

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| Sequre Si012 Pro Max | ✔️ | ❌ | ✔️ | ❌ | ❌ | ❌ | ✔️ | Buzzer, LEDs. T12 and TS/SI sockets, auto-selected. |
| Sequre Si012 Pro Max | ✔️ | ❌ | ✔️ | ❌ | ❌ | ❌ | ✔️ | |

The last column is really for limitations. I should fix S99

@Ralim Ralim left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Smaller changes.

Would be really good if you could manually look at each comment block and re-word in your words at the least. These read heavily as LLM-Speak

- New settings get fixed numbers on all models; drop the settings.yaml
  "include" support.
- Drop the TC1047 board temperature cut-out and its plausibility check, as
  the handle temperature at boot can't be assumed equal to the board's.
- Add TIP_SHORT_DETECTION for the shorted tip check.
- Move the socket label into the screens that use it.
- README: leave the notes column empty for the Si012 Pro Max.
- Shorten and reword comments.
The soldering screen turns its beep off itself, and keeps the deadline in
the screen's scratch state, which is cleared on a screen change. Leaving the
screen while it beeped (button, sleep) left the buzzer on until a power cycle.

- Turn the buzzer off on every screen change.
- Sequre: a tone stops by itself after at most one second.
@amanpd7

amanpd7 commented Oct 15, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 2c92f3e, a fix for the buzzer getting stuck on. This also affects the S99, since it's the same buzzer code.

What I saw

While using my Si012 Pro Max, the buzzer sometimes kept going after switching between idle and heating. Sometimes it stopped after 6-7 seconds, sometimes it never stopped. Pressing buttons did nothing, and the only way to stop it was a power cycle.

Cause

When the tip reaches the set temperature, the soldering screen starts a short beep and turns it off itself about 1/3 s later (Soldering.cpp). The "turn it off" time is kept in scratch_state.state3, and guiRenderLoop() clears scratch_state on every screen change.

So if you leave the soldering screen while it is beeping (button press to adjust the temperature, long press B to go home, going to sleep), nothing turns the buzzer off. Coming back to the soldering screen doesn't help either, because state3 is now 0 and the check that stops the beep never runs. The end-of-profile beep in SolderingProfile.cpp works the same way.

Fix

  • guiRenderLoop() calls setBuzzer(false) on every screen change, so a beep never carries over to another screen.
  • In the Sequre BSP, setBuzzer(true) now also sets a limit, and the TIM3 interrupt stops the tone after at most one second (2 * BUZZER_FREQ_HZ toggles). That is a backstop in case anything else forgets to turn it off.

No size change on the T55 or S60 (no buzzer pin there, so the call compiles away). The S99 grows by a few bytes.

I'll confirm on my iron once I've flashed it.

@amanpd7

amanpd7 commented Oct 15, 2026

Copy link
Copy Markdown
Contributor Author

it's confirmed, bug is gone.
@Ralim

@amanpd7
amanpd7 requested a review from Ralim October 15, 2026 12:38
Comment thread source/Core/BSP/Sequre/BSP.cpp Outdated
// timers.

// Tip PWM compare register, CCR3 unless set in Pins.h
#ifndef PWM_Out_CCR

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sort of implicit setting has bitten before. Better to be explicit in Pins.h for all models please

Comment thread source/Core/BSP/Sequre/BSP.cpp Outdated
else if (htim->Instance == TIM3) {
// Buzzer tone: square wave on a plain GPIO
HAL_GPIO_TogglePin(BUZZER_GPIO_Port, BUZZER_Pin);
// Buzzer tone: square wave on a plain GPIO, at most one second long

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Buzzer tone: square wave on a plain GPIO, at most one second long
// Buzzer tone: square wave on a plain GPIO

Comment thread source/Core/BSP/Sequre/BSP.cpp Outdated
}

// First n LEDs on
static uint16_t statusLEDBar(uint32_t n) { return n >= STATUS_LED_COUNT ? allStatusLEDs : (uint16_t)((1U << n) - 1); }

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static uint16_t statusLEDBar(uint32_t n) { return n >= STATUS_LED_COUNT ? allStatusLEDs : (uint16_t)((1U << n) - 1); }
static uint16_t getStatusLEDBarBitmask(uint32_t n) { return n >= STATUS_LED_COUNT ? allStatusLEDs : (uint16_t)((1U << n) - 1); }

Comment thread source/Core/BSP/Sequre/BSP.cpp
Comment thread source/Core/BSP/Sequre/Setup.cpp Outdated
#ifdef TIP2_TEMP_ADC1_CHANNEL
// Both sockets are read every cycle, an empty one reads near full scale.
// A T12 also touches the TS/SI contacts, so T12 wins and TS/SI is only picked while idle.
// Both sockets reading a tip means a short: no output until it clears.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Both sockets reading a tip means a short: no output until it clears.
// If a tip is detected in both sets of contacts, it is likely a short and we mask output and dont allow drive until the short is removed.

Again, please de-llm comments

Comment thread source/Core/Threads/GUIThread.cpp Outdated
// Post draw we handle any state transitions

if (newMode != currentOperatingMode) {
setBuzzer(false); // A beep never carries over to the next screen

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
setBuzzer(false); // A beep never carries over to the next screen
setBuzzer(false); // Ensure buzzer is stopped when changing screen

- Set PWM_Out_CCR in Pins.h for every Sequre model instead of defaulting it.
- Rename statusLEDBar to getStatusLEDBarBitmask.
- Comment wording from review.
@amanpd7
amanpd7 requested a review from Ralim October 16, 2026 05:16
@Ralim
Ralim merged commit 83b16ec into Ralim:dev Oct 17, 2026
22 checks passed
@Ralim

Ralim commented Oct 17, 2026

Copy link
Copy Markdown
Owner

Thank you 🙇🏼

shambler123 pushed a commit to shambler123/IronOSS99 that referenced this pull request Oct 17, 2026
The Si012 Pro Max (Ralim#2247) compiles the same BSP with
TIP_CURRENT_LIMIT_CHOP but does not define TIP_CHOP_SLOW_ABOVE_X100 and
TIP_CHOP_TURNOFF_TAIL_US, which broke its build after the merge. The
BSP now carries defaults, the S99 block keeps overriding them. With an
8 ohm T12 heater the slow set never engages, so the Si012 Pro Max
behaves exactly as before.
Ralim pushed a commit that referenced this pull request Oct 19, 2026
…tch (#2244) (#2248)

* S99: keep 2.5 ohm (JBC) cartridges within what the output stage can switch

Issue #2244: a C245 style cartridge on a 20 V PDO draws 8 A pulses, the
charger drops out after about 1.5 s and the MOSFET runs hot. The scope
captures in the thread show why: the gate is DC driven but slow (about
20 us to turn on, about 48 us to release through its pull-up), so the
FET keeps conducting for roughly 45 us after every off command. At the
5.9 kHz chop neither edge completes, the FET switches hard every cycle
and the average current ends up above the PDO rating. The stock 5.5 ohm
tip is unaffected: at 11.2 kHz the gate cannot follow at all and the
output is effectively DC.

Three changes, all behind new defines in the S99 block so they can be
tuned from test reports without touching the logic:

* TIP_PEAK_CURRENT_MAX_X100 (6 A): the FS2711 PDO selection skips any
  fixed PDO (and clamps the PPS request) whose voltage would push the
  tip current over this. A 2.5 ohm cartridge now negotiates 15 V / 3 A
  instead of 20 V; the stock tip picks the same PDO as before on every
  charger.
* TIP_CHOP_SLOW_ABOVE_X100 (4.5 A): above this tip current the chop uses
  a slow frequency set (3 kHz capped on PD, 1 kHz uncapped / DC) so the
  gate completes both edges; the per-edge loss grows with the current.
  The chop slows down further while the commanded pulse is shorter than
  two turn-off tails (low user power limits), and the thermal steps
  still stack on top.
* TIP_CHOP_TURNOFF_TAIL_US (45): on the slow set the tail is subtracted
  from the commanded on time, so the supply sees the intended average
  current instead of a pulse that is a tail longer than asked for.

Prescaler table extended with 50 (2.4 kHz) and 120 (1.0 kHz) entries.
Builds for S99 and S60P; stock tip path unchanged.

* Fix the PD debug screen never advancing past the first page

showPDDebug() for the FS2711 and HUSB238 did `*screen++`, which
increments the pointer rather than the page counter, so pressing the
front button never got past the PDO count and the PDO list could not be
reached. The FUSB302 variant already does `(*screen) += 1`.

* S99: compensate the net tail, not the whole turn-off tail

The first gate capture on a 2.5 ohm cartridge at 15 V (PR #2248) shows
the MOSFET stops conducting about 35 us after the off command, but it
also only starts conducting about 15 us after the on command, so the
net extra conduction per pulse is about 20 us, not 45. With 45 us taken
off the command the effective duty was 31 % (1.9 A average from the
charger) against the intended 43 %. TIP_CHOP_TURNOFF_TAIL_US goes to
25 us, which brings the average back to about 2.6 A at 15 V / 3 A, the
0.9 x rating the cap aims for. Chop frequency and FET loss unchanged.

* S99: 4 A peak current ceiling, PPS only without chopping

Test results on PR #2248: a 2.5 ohm cartridge at 15 V / 3 kHz (6 A
pulses) runs fine on a Lenovo 65 W charger but the Sequre-supplied
charger still drops out after about a second, at 1.9 A and at 2.6 A
average alike, with the bus dipping only 1.5 V. The same charger takes
the stock cartridge, which at 20 V draws 3.5 A effectively DC, 1.1x the
PDO rating. So it reacts to the pulse amplitude, not to the average or
the voltage. A charger model calibrated on those two points (fast
over-current detection against k x rating, any filter up to ~100 us and
any k between 1.1 and 1.7 fits) fails every 15 V and 12 V option and
passes 9 V: 3.6 A nominal, 3.3 A after the cable, the same 1.1x ratio
as the stock cartridge, and at 11.2 kHz with a 75 % cap the gate does
not really chop, so no switching loss either. Tip power about 27 W
instead of 35 W at 15 V.

With the ceiling below the best fixed PDO the PPS branch would have
picked e.g. 10 V / 3 A and pulled 4 A, so PPS requests are now also
clamped to the voltage the source current can supply through the tip
without chopping: a 100 W PPS source gives 10 V / 5 A (4 A DC, 40 W),
a 3 A PPS source stays on the fixed 9 V PDO.

Stock cartridge selection unchanged on every charger in the host
harness; builds for S99 and S60P.

* Sequre BSP: default values for the chop tunables

The Si012 Pro Max (#2247) compiles the same BSP with
TIP_CURRENT_LIMIT_CHOP but does not define TIP_CHOP_SLOW_ABOVE_X100 and
TIP_CHOP_TURNOFF_TAIL_US, which broke its build after the merge. The
BSP now carries defaults, the S99 block keeps overriding them. With an
8 ohm T12 heater the slow set never engages, so the Si012 Pro Max
behaves exactly as before.

* Leave the HUSB238 PD debug screen as it was

The same `*screen++` bug exists there, but fixing it costs 12 bytes and
the T55 ZH_CN image has none left (CI: region ROM overflowed by 12
bytes). The S99 / FS2711 fix stays; the HUSB238 screen has been stuck
on its first page since it was written, so nothing changes for the S60
and T55.

* S99: back to 15 V for 2.5 ohm, PPS by power, minimum chop pulse

Second test round on PR #2248 with the 4 A ceiling (9 V): the Sequre
charger now holds and the MOSFET stays cool there, but on the Lenovo
the MOSFET gets warm while heating and runs away at idle, 20 % duty at
5.9 kHz. Two things learned:

* The gate drive follows VBUS (-10 V at 20 V, -8.6 V at 15 V, so
  around -7 V at 9 V). At 9 V the MOSFET is barely enhanced and every
  edge crawls, so a low voltage is the wrong way to spare the charger.
  The ceiling goes back to 6 A, i.e. 15 V for a 2.5 ohm cartridge,
  which the first round had tested fine while heating.
* The Sequre charger that trips on 6 A pulses offers PPS 3-11 V / 5 A,
  and its PD debug readout is what revealed it. A PPS range is now
  scored like a fixed PDO, by the power it delivers at the highest
  voltage that needs no chopping (R x I_pps), and wins on power or as
  the gentle alternative to a fixed PDO with hard pulses. On that
  charger a 2.5 ohm cartridge takes 11 V / 5 A (4.4 A DC, 48 W) over
  15 V / 3 A (6 A pulses, 45 W); the Sequre charger is in the host
  harness with its real PDO list. The stock cartridge keeps its fixed
  20 V everywhere: PPS at 5.5 x 3.25 A = 17.9 V delivers less.
* Idle: the PID realises low power as short chop pulses, and a pulse
  shorter than the two gate edges is spent in the linear region
  whatever the voltage. On the slow set the chop now slows down until
  the pulse actually commanded (PID duty or cap, whichever is smaller)
  is at least TIP_CHOP_MIN_PULSE_US (100 us): 3 kHz at full power as
  before, 1.5 kHz at 20 %, 1 kHz at 10 %. The model puts the idle loss
  at 0.2-0.3 W instead of 0.8-1.5 W. The slow set is now selected by
  cartridge resistance (TIP_CHOP_SLOW_BELOW_RX10, 5 ohm) rather than
  tip current, so a 2.5 ohm cartridge gets it on 9 V and PPS 11 V too;
  for the stock cartridge nothing changes.

Also: the PD debug screen printed the PDO current 10x too high (mA
passed as A x100).

---------

Co-authored-by: markusstadtmann.ext@levatis.com <markus.stadtmann.ext@levatis.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants