sh68f89 platform and ciy-x77 device - #74
Merged
Merged
Conversation
Adds the register header for the SinoWealth SH68F89 and its platform notes. The part is register-for-register the SH88F6162, so the map is transcribed from that datasheet's section 7 and cross-checks clean against the vendor Keil header at all 192 sfr and 166 sbit declarations. Covers both SFR pages, every named bit the datasheet gives, the USB RAM window at 0x0B28 and the 15 interrupt vectors, which start with the four PCA units rather than the SH68F881's INT0/Timer4/INT1/Timer3.
Adds the SH68F89 platform and the CIY X77, a full-size board built on it. The platform is close to the SH68F881 in shape and different in nearly every address: the USB block sits at 0xAA-0xBF on SFR page 1 with none of the endpoint control registers bit addressable, USB RAM is at 0x0B28 above 40 bytes of LCD RAM, and interrupt numbers 0-3 are the four PCA units, so the tick lands on Timer2 at vector 5 and USB at vector 12. SYSCLK is the PLL at 24MHz, settled by polling PLLCON.PLLSTA rather than by a blind delay. The X77 keeps its settings in an external 24Cxx EEPROM on a bit-banged bus rather than in the MCU's own data block, which is what the stock firmware does and leaves the on-chip block free. SDA and SCL share port 5 with the matrix rows, so the row read masks them off. The base keymap is decoded from the stock image rather than guessed: its key records store a usage directly for most keys and an index into a second table for the rest, and resolving that gives all 116 matrix positions. The 12 an ANSI board does not fit are wired to KC_NO. Per-key RGB runs off the four PCA units and is not brought up yet; the three lock LEDs are.
RSTSTAT is 0xB1 on page 0 and USBCON on page 1, so a watchdog kick taken with page 1 latched writes 0x02 into USBCON and drops the D+ pull-up. The EEPROM bit-bang held page 1 across its half-period delays, and delay_us() kicks from inside its loop, so settings_load() at boot disconnected USB before it ever enumerated. The bus now spins on nops and kicks between transfers instead. Also selects SFR page 0 by clearing INSCON bit 7 alongside BKS0. The register table calls bit 7 unimplemented, but the datasheet text names a BKS1 and the ISP bootloader selects page 0 with `anl INSCON,#0x3f`.
The stock firmware ships one keymap for the whole X77 family, so its matrix is wider than this unit: columns 18-21 on P7 decode to a complete numpad that an ANSI TKL does not fit, the same way the keymap's ISO and JIS positions are not fitted. Drops MATRIX_COLS to 18 and leaves P7 an input, since those pins may not be routed on a TKL board. That also takes the columns entirely onto SFR page 0, so only the row read still crosses the page boundary. All 18 columns and all 6 rows are confirmed on hardware, along with the factory information block (PART 68f8900000, OPT b8c0038c matching what a programmer reads over ICP) and a settings round-trip through the external 24Cxx that survives a power cycle. Also marks EP2 busy when the debug console sends: console_task gates on usb_hw_ep2_in_free(), so leaving it clear let each log line overwrite the previous one before the host had collected it.
The backlight is nine PCA compare channels multiplexed over the matrix
columns, with P4.4 and P4.5 selecting rows 0-2 or rows 3-5, so a column
takes two subframes and a frame is 36.
Three things the existing reverse engineering did not have, all
established on hardware:
* P7.0 gates the backlight supply and is active low. Nothing lights
without it however the PCA is set up, and it is easy to miss sitting
next to the matrix columns on P7.1-P7.4.
* P4.4 and P4.5 are the row-group enables, set at the end of a PCA0
interrupt and cleared at the start of the next.
* The colour order is blue, green, red. Confirmed on the board and
against the firmware, where led_fill_all(0,0,0xff) fills red.
P3 and P4 are never read back. Both mix PCA outputs with other functions,
so a read samples live PWM on those bits and writing the value back
latches a channel on; it showed as one column of keys brighter than the
rest. Every write now goes through a computed value, sharing one P4
shadow with the column driver.
The systick slots come down to 0.25 ms for a subframe and 1 ms for a
scan: at 36 subframes the old 8 ms scan slot was a 30% dark duty and read
as a visible blink.
The four PCA units are the part's only PWM, so their bring-up and the glitch-free reload sequence belong beside the other platform drivers rather than in a board file; the board keeps the channel-to-LED mapping, which is all that is board specific. Evaluating the effect is by far the most expensive thing per subframe and was running in the tick interrupt. At the 0.25 ms subframe this port now uses it does not fit there, and overrunning starved the USB interrupt until the device stopped enumerating while the backlight carried on looking fine. It runs from the main loop now, leaving the interrupt with nine compare writes and the column drive.
The backlight section records the pin map, the two row-group enables, the blue-green-red channel order and the P7.0 supply enable, none of which are guessable from the pinout and the last of which is what keeps a correctly configured board dark.
carlossless
force-pushed
the
ciy-x77-sh68f89
branch
from
September 12, 2026 21:13
6f6ee13 to
adfb7f8
Compare
The Tab row ran a column long and the Shift row a column short, so neither lined up with the block borders above and below them, and the Fn layer only drew half the board. Both are now a full TKL at one width.
The blocks, the specs and the dispatch chain were each in the order the platforms were added, so a new one had no obvious insertion point. All three are now A-Z: bk3632, sh68f881, sh68f89, sh68f90. Pure reorder; every firmware image is byte-identical.
carlossless
force-pushed
the
ciy-x77-sh68f89
branch
from
September 13, 2026 09:26
0f2788b to
f9c04a0
Compare
…ture
bb_i2c joins bb_spi as a shared bit-bang driver: the board supplies the
two pins and, where they sit on a non-default SFR page, the wrapper that
selects it, so the driver itself stays page agnostic.
The 24Cxx settings store becomes a feature a board opts into with
`'nvm': '24cxx'`, the same way the wireless one works, rather than
something the sh68f89 platform hardcodes. Another board on this part can
now use flash or the on-chip block instead.
Two things fixed rather than carried across:
* The write-protect macros were doing a read-modify-write on P4, which
also carries three PCA outputs, so a read sampled live PWM. They go
through the shadow now, like every other write to that port.
* led_drive rebuilt the whole P4 byte from KB_P4_IDLE, which has write
protect asserted, so every LED subframe re-protected the EEPROM,
including from under a settings save. It left a half-written record
that failed its checksum on the next boot. It now touches only the
bits it owns.
Verified on hardware: a save made with the backlight running survives a
power cycle, twice.
…ts own ldo_init() only enabled the regulator on the sh68f90; on the other two it enabled nothing and existed to latch RSTSTAT, while the regulator was brought up from clock_init(). All three now do the same two things, and REGCON is written in exactly one place per part. The reset-source latch stays in ldo_init() because RSTSTAT doubles as the watchdog kick, so the flags survive only until something kicks, and this is the first platform call on every part. Clearing the analog and display blocks is not clock work either. It moves to peripherals_init(), called from main() once the clock is up and before any board init, so clock.c is only the clock. The sh68f90 gets an empty one: nothing on that part mux'es away a pin the firmware uses.
The Fn layer was carried over from another board and only two of its twelve function-row keys happened to match this one. The stock layer is decodable: the table at 0xC610 is a 48-entry pool in two halves, a base key's record indexes pool[n] and its secondary function is pool[n + 48]. That gives the media set exactly: my computer, WWW home, mail, calculator, stop, previous, play/pause, next, then volume down, volume up and mute. Stock puts a lighting control on F9 and effect selects on 1-5, so the Fx keys take those. Keyboard lock moves off F12, which is mute on this board, to Pause, which stock leaves with no secondary function. Stock's remaining secondary functions are its own key classes rather than HID usages, and which class is which is behavioural rather than visible in the image, so they are left alone.
The user manual in the reverse-engineering repo documents the backlight controls, and the keycap glyphs in its diagram settle which key each one is on. Cross-checked against the firmware, every pair lines up: Fn+F9 cycle the animation type 0x0B u=00 Fn+PgUp/PgDn brightness type 0x0C Fn+-/= animation speed type 0x0D Fn+Up/Down colour type 0x12 Fn+Left/Righ backlight direction type 0x0E u=0a/0b Fn+Gui Windows key lock type 0x0E u=01 Fn+End Fn lock type 0x0E u=02 Fn+Del restore backlight defaults type 0x0E u=05 Brightness and speed were on the wrong keys. Colour is new: the offset goes into the wheel index, so the colour keys rotate the whole animation, and it persists like the other settings. Restoring the defaults is new too and takes Del as stock does, without the five second hold. Not reproduced: the backlight recording on Esc and 1-5, the Fn lock, and the direction control, which these animations have no notion of. user_settings_t grows a byte for the colour. Every nvm backend stores the record length and checks it, so an existing record simply fails to validate and the defaults come back.
The comments and the board notes explained several choices by pointing at the firmware that shipped on the device. The facts are the same either way and a reader of this tree cannot check that reference, so they now just say what the board does.
ldo.c now writes REGCON and nothing else. The latch was sitting there only because ldo_init() happened to be the first platform call, which is the wrong reason for it to live in a file about the regulator. It gets reset.c, and reset_init() becomes the first call in main(), since RSTSTAT doubles as the watchdog kick and the flags survive only until something kicks. reset.h declares reset_status, so the boards that report it no longer each extern it themselves.
The keyboard lock, the NKRO toggle and the WASD swap came in with a keymap copied from another board. None of them exists here: W and Pause carry no secondary function at all, and ScrLk carries something unrelated. The Gui lock stays, that one is real.
Both variants share the matrix; the ISO one gains the hash key next to the tall Enter at (3,12) and the extra key left of Z at (4,14), and gives up (2,13), which the tall Enter covers. The ANSI layout is unchanged and stays the default. indicators.c moves up to the keyboard directory, since the backlight is a property of the board rather than of the keymap and both layouts want the same one. Meson looks for it at either level, so the boards that keep theirs in the layout directory are unaffected.
The Caps row ran two columns short and the Shift row one, so neither lined up with the borders around them, and the Fn layer was left without a diagram at all.
The KC_NO entries in the macro say which positions are unpopulated, and the diagram above each keymap says what the board looks like.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the SinoWealth SH68F89 platform and the CIY X77, a TKL board built on it, with key scan, USB, lock LEDs, per-key RGB on the four PCA units and settings in an external 24Cxx, all verified on hardware.