# Exploring the Embedded Controller

**URL:** <https://community.frame.work/t/exploring-the-embedded-controller/12846>\
**Category:** General Topics\
**Created:** [December 24, 2021, 7:50pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846 "2021-12-24T19:50:59Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![DHowett](https://sea1.discourse-cdn.com/flex001/user_avatar/community.frame.work/dhowett/32/1990_2.png) [@DHowett](https://community.frame.work/u/DHowett)\
**Post date:** [December 24, 2021, 7:50pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/1 "2021-12-24T19:50:59Z")

</div>

Hey all! 👋🏻

For the past week, I’ve been exploring the embedded controller on our awesome laptops, and I’d like to share some of my findings.

This is going to be somewhat structured and somewhat stream-of-consciousness, so bear with me. Most of the same findings are written up on my website at [The Framework Laptop's Embedded Controller (EC) :: HowettNET](https://www.howett.net/posts/2021-12-framework-ec/).

# Rationale

@nrp mentioned [here](http://community.frame.work/t/free-the-ec-and-coreboot-only/791/5) that the EC firmware is based on chromium-ec, and it seemed like it would be a fun challenge to reverse engineer how the battery charge limit feature in 3.07 worked. Given that the EC _may_ eventually be open source, this could serve as a living document for its capabilities.

## Disclaimer

1. This information is current as of firmware version 3.07 with EC version `hx20_v0.0.1-369d3c3`.
2. This information comes with **no warranty**. If you break your computer, I’m sorry, but that might be a really interesting finding.
3. It’s my dearest hope to not tie the Framework team’s hands – if any of the information presented here limits what they can do in future versions for fear of breaking compatibility with a few community hacks, this project will have been a failure.

# Tools

The EC uses a customized version of the CrOS EC v3 LPC protocol, which Chromium’s `ectool` does not support out of the box. I’m hosting a fork at [GitHub - DHowett/framework-ec: Embedded Controller firmware for the Framework Laptop](https://github.com/DHowett/fw-ectool) that does. It only works on Linux.

## Instructions

1. If you’re using a kernel that supports lockdown and secure boot is enabled, make sure you turn it off. This application uses raw port I/O and requires a higher I/O privilege level, which is [locked down when secure boot is enabled](https://man7.org/linux/man-pages/man7/kernel_lockdown.7.html)
2. Clone the repository.
3. `make utils`. This will produce an `ectool` binary at `$/build/bds/util/ectool`.
4. `.../ectool --interface=fwk version`
5. Fun!

This tool offers an extended `raw` command, allowing you to send anything to the EC. It will handle encoding the packet as a v3 exchange.

**Syntax:** `raw 0xCOMMAND payload`  
`payload` takes the form of a long string of type codes (`b`, `w`, `d`, `q`) and values in hex.

**Examples:**

- `b1` will write one byte, `0x01`.
- `w3` will write one _word_ in little-endian, `0x03 0x00`.
- `b1w3` or `b1,w3` will write `0x01 0x03 0x00`.

# Findings

This thing is really cool! It supports a lot of the normal CrOS EC commands for reporting status and reconfiguring the system at runtime. Of particular note is `led` – [you can configure the two side LEDs and the power button](https://www.howett.net/posts/2021-12-framework-ec/#led).

Most of the features in the Advanced page of UEFI setup are synced to the EC on startup using a number of OEM commands, with values and structures documented [here](https://www.howett.net/posts/2021-12-framework-ec/#oem-commands). The settings are applied on _every boot_, so if you change something like the charge limit it will be reset on restart. This is both good and bad. 🙂

## Charge Limit

The charge limit is pushed to the EC using command `3E03`. You can set a new charge limit at runtime with…

```auto
ectool fwchargelimit 80

```

> Older versions of the tool did not support the `fwchargelimit` command, and you had to send the charge limit host command manually:
> 
> ```auto
> ectool --interface=fwk raw 0x3E03 b2,wXXXX
> 
> ```
> 
> where `XXXX` is the charge limit from 0-100 in hex (`00 .. 64`).

_ **EDIT 2022-01-10** : I’ve added a more ergonomic command for this!_

## Key Mapping

The “Swap Ctrl/Fn” setting relies on command `3E0C` (dubbed “Keyboard Mapping”). It looks like it takes a set of matrix positions and scancodes. As such, it’s possible to remap any key to emit any¹ scancode. To help with remapping, I’ve reversed the [key matrix layout](https://www.howett.net/data/framework_matrix)².

I thought it would be very cool to write an EFI driver that remapped Caps Lock to Escape on every boot. However, because the firmware doesn’t support ESP driver loading, it doesn’t work unless you have a compatible bootloader. The source lives [here](https://github.com/DHowett/FrameworkHacksPkg/tree/main/FrameworkKeyMapDriver) (edk2 required to build.)

Feel free to pile on with questions, info, or findings of your own!

¹ Almost any. I haven’t been able to set any extended scancodes that require escapes in the PC/AT scancode set.  
² The EC can simulate a key press at a matrix position, so I just ran `kbpress` 128 times and asked it to press every matrix position and observed what it emitted using `xev` and `evtest`. 😅 This was before I determined that the key mapping host command can report the matrix mapping! I went back and double-checked afterwards.

---

<div class="post-metadata">

**Author:** ![D.H](https://sea1.discourse-cdn.com/flex001/user_avatar/community.frame.work/d.h/32/17958_2.png) [@D.H](https://community.frame.work/u/D.H)\
**Post date:** [December 24, 2021, 7:58pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/2 "2021-12-24T19:58:44Z")

</div>

I have this working on my batch 5 i5 DIY under arch Linux, with secure boot off of course. Successfully changed charge limit up and down, so my “charge to 100% from userland control” and “auto default to 80% charge” goal is now complete! Merry Christmas to us!

Thanks @DHowett , @Kieran_Levin , @nrp and the rest of the framework team for making this possible!

---

<div class="post-metadata">

**Author:** ![D.H](https://sea1.discourse-cdn.com/flex001/user_avatar/community.frame.work/d.h/32/17958_2.png) [@D.H](https://community.frame.work/u/D.H)\
**Post date:** [December 24, 2021, 10:07pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/3 "2021-12-24T22:07:11Z")

</div>

Wrote a quick little bash script to accept a decimal charge target argument, check it for validity between 20 and 100 percent, change it to hex, and call ectool. If no argument is present, default to 80 percent target.

Be sure to set your path to ectool correctly if you are going to use this!

```auto
#!/bin/bash

case $1 in
    ''|*[!0-9]*) chg_dec=80 ;;
    *) chg_dec=$1 ;;
esac

  if [$chg_dec -gt 99]; then
    chg_dec=100
  elif [$chg_dec -lt 20]; then
    chg_dec=20
  fi

chg_hex=$( printf '%x\n' $chg_dec )

sudo /SET/PATH/TO/ectool --interface=fwk raw 0x3E03 b2,w$chg_hex

```

---

<div class="post-metadata">

**Author:** ![DHowett](https://sea1.discourse-cdn.com/flex001/user_avatar/community.frame.work/dhowett/32/1990_2.png) [@DHowett](https://community.frame.work/u/DHowett)\
**Post date:** [December 25, 2021, 12:18am UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/4 "2021-12-25T00:18:06Z")

</div>

It looks like the EFI Driver plan won’t work unaided; the firmware doesn’t appear to implement an optional part of the UEFI specification, where it can choose to respect `DriverOrder` and `Driver####`. It would be pretty cool if it would 😁

---

<div class="post-metadata">

**Author:** ![john\_doe](https://avatars.discourse-cdn.com/v4/letter/j/91b2a8/32.png) [@john\_doe](https://community.frame.work/u/john_doe)\
**Post date:** [December 26, 2021, 11:46pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/5 "2021-12-26T23:46:56Z")

</div>

Really cool , although some of us aren’t really that knowledged in programming, could you make a gui for those inexperienced users?

---

<div class="post-metadata">

**Author:** ![Yisroel\_Newmark](https://avatars.discourse-cdn.com/v4/letter/y/b3f665/32.png) [@Yisroel\_Newmark](https://community.frame.work/u/Yisroel_Newmark)\
**Post date:** [December 27, 2021, 8:00am UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/6 "2021-12-27T08:00:42Z")

</div>

> [@john\_doe](#):
>
> Really cool , although some of us aren’t really that knowledged in programming, could you make a gui for those inexperienced users?

Hello, I could maybe make a gui, what operating system do you want it for?

---

<div class="post-metadata">

**Author:** ![john\_doe](https://avatars.discourse-cdn.com/v4/letter/j/91b2a8/32.png) [@john\_doe](https://community.frame.work/u/john_doe)\
**Post date:** [December 27, 2021, 5:21pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/7 "2021-12-27T17:21:16Z")

</div>

> [@Yisroel\_Newmark](#):
>
> Hello, I could maybe make a gui, what operating system do you want it for?

I’m on Windows but you could also make one for Linux.

---

<div class="post-metadata">

**Author:** ![D.H](https://sea1.discourse-cdn.com/flex001/user_avatar/community.frame.work/d.h/32/17958_2.png) [@D.H](https://community.frame.work/u/D.H)\
**Post date:** [December 27, 2021, 6:06pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/8 "2021-12-27T18:06:11Z")

</div>

> [@Yisroel\_Newmark](#):
>
> Hello, I could maybe make a gui, what operating system do you want it for?

Would python work on both Linux and Winblows?

---

<div class="post-metadata">

**Author:** ![Yisroel\_Newmark](https://avatars.discourse-cdn.com/v4/letter/y/b3f665/32.png) [@Yisroel\_Newmark](https://community.frame.work/u/Yisroel_Newmark)\
**Post date:** [December 27, 2021, 6:08pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/9 "2021-12-27T18:08:20Z")

</div>

I don’t think the posted tool works on Windows out of the box, as it was designed for Chromebooks.

---

<div class="post-metadata">

**Author:** ![DHowett](https://sea1.discourse-cdn.com/flex001/user_avatar/community.frame.work/dhowett/32/1990_2.png) [@DHowett](https://community.frame.work/u/DHowett)\
**Post date:** [December 27, 2021, 7:50pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/10 "2021-12-27T19:50:13Z")

</div>

I’ve pushed an update to [fw-ectool](https://github.com/DHowett/fw-ectool) that adds a convenience command for setting the charge limit.

I’ve also learned that the charge limit and key mapping can be queried!

## Charge Limit

```auto
# Query
$ ectool --interface=fwk fwchargelimit
80

# Set
$ ectool --interface=fwk fwchargelimit 65
65

```

## Key Mapping

**Question:** What scancode is emitted by key matrix position r4, c8?

```auto
ectool --interface=fwk raw 0x3E0C d1,d0,b4,b8,w0
3e0c(...12 bytes...)
01 00 00 00 00 00 00 00 04 08 00 00 |............ |
                         ^ ^
                         | |
                         | |
Read 136 bytes | |
01 00 00 00 00 00 00 00 04 08 09 00 00 00 00 00 |................|
                         ^ ^ ^^^^^
                         | | `-Scancode
                         | `-Column
                         `-Row

```

_(the above exchange has been annotated; the tool doesn’t do cool stuff like that 🙁)_

Looks like it’s `0x0009`, or F10!

---

<div class="post-metadata">

**Author:** ![D.H](https://sea1.discourse-cdn.com/flex001/user_avatar/community.frame.work/d.h/32/17958_2.png) [@D.H](https://community.frame.work/u/D.H)\
**Post date:** [December 27, 2021, 7:53pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/11 "2021-12-27T19:53:29Z")

</div>

@DHowett

It appears this command is functional:

```auto
sudo ectool --interface=fwk fanduty XX

```

Also,

```auto
sudo ectool --interface=fwk autofanctrl 

```

does restore automatic fan control. I am considering writing a script and a companion service with rules for pushing the fan to high run for certain applications (X-Plane, Handbrake, etc) that seem to get just a little more fps work done with the fan pre-spun up to 100% vs in auto…

---

<div class="post-metadata">

**Author:** ![Jason\_Hottelet](https://avatars.discourse-cdn.com/v4/letter/j/8dc957/32.png) [@Jason\_Hottelet](https://community.frame.work/u/Jason_Hottelet)\
**Post date:** [December 27, 2021, 11:47pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/12 "2021-12-27T23:47:14Z")

</div>

> [@D.H](#):
>
> Would python work on both Linux and Winblows?

if you use something like pyinstaller, you can easily generate executables for the platform you are using it on. One option would be to use Wine for the windows executable and your Linux OS for the linux one.

---

<div class="post-metadata">

**Author:** ![D.H](https://sea1.discourse-cdn.com/flex001/user_avatar/community.frame.work/d.h/32/17958_2.png) [@D.H](https://community.frame.work/u/D.H)\
**Post date:** [December 28, 2021, 3:31am UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/13 "2021-12-28T03:31:47Z")

</div>

One interesting question, and this may be one for @Kieran_Levin , is what happens if the charge limit is set at zero?

---

<div class="post-metadata">

**Author:** ![DHowett](https://sea1.discourse-cdn.com/flex001/user_avatar/community.frame.work/dhowett/32/1990_2.png) [@DHowett](https://community.frame.work/u/DHowett)\
**Post date:** [December 28, 2021, 3:32am UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/14 "2021-12-28T03:32:17Z")

</div>

It rejects it; the actual lower limit is 20.

---

<div class="post-metadata">

**Author:** ![Shy\_Guy](https://sea1.discourse-cdn.com/flex001/user_avatar/community.frame.work/shy_guy/32/5280_2.png) [@Shy\_Guy](https://community.frame.work/u/Shy_Guy)\
**Post date:** [December 29, 2021, 4:46am UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/15 "2021-12-29T04:46:06Z")

</div>

Thx. Now have a charge limit set to ~60-80.  
Charge limit set to 80 whenever charge drops below 61.  
Charge limit set to 60 whenever charge goes above 79.

This mimicks my thinkpad’s settings and hopefully reduces charge cycles used. I’m not sure if maintaining a constant 60% charge uses more or less cycles than maintaining a charge between 60-80 while always plugged in. But I assume it doesn’t hurt too much if its worse since the battery is unused and will take days to go from 80% to 60% anyways.

Edit: I take that back. Its discharging at a rate that makes me think its only using battery power, though the led is flashing the same as it was when set to a static 60%. I guess if the charge limit is 60% and battery is 80%, it uses the battery without charging or supplementing power from ac until the limit is reached?

---

<div class="post-metadata">

**Author:** ![D.H](https://sea1.discourse-cdn.com/flex001/user_avatar/community.frame.work/d.h/32/17958_2.png) [@D.H](https://community.frame.work/u/D.H)\
**Post date:** [December 29, 2021, 2:38pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/16 "2021-12-29T14:38:36Z")

</div>

> [@Shy\_Guy](#):
>
> not sure if maintaining a constant 60% charge uses more or less cycles

From my mid-grade understanding of battery chemistry and longevity issues, I would choose to keep a single constant moderate charge level, versus constantly cycling up and down 20%.

---

<div class="post-metadata">

**Author:** ![feesh](https://avatars.discourse-cdn.com/v4/letter/f/eb9ed0/32.png) [@feesh](https://community.frame.work/u/feesh)\
**Post date:** [December 30, 2021, 6:01pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/17 "2021-12-30T18:01:22Z")

</div>

This is awesome work!

Excited to see if there’s any possibility for more advanced keyboard remapping. Would love to use the fn key as a modifier.

---

<div class="post-metadata">

**Author:** ![DHowett](https://sea1.discourse-cdn.com/flex001/user_avatar/community.frame.work/dhowett/32/1990_2.png) [@DHowett](https://community.frame.work/u/DHowett)\
**Post date:** [December 30, 2021, 7:22pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/18 "2021-12-30T19:22:00Z")

</div>

> [@feesh](#):
>
> Excited to see if there’s any possibility for more advanced keyboard remapping. Would love to use the fn key as a modifier.

Unfortunately, it looks like the Fn key mappings are compiled in (today) and can’t be changed. You can change what the key labelled Fn does by mapping it to a different scancode and assigning different behaviors to it in the OS, but you won’t be able to treat it like a “layer” in the classical keyboarding sense.

---

<div class="post-metadata">

**Author:** ![lbkNhubert](https://avatars.discourse-cdn.com/v4/letter/l/e19b73/32.png) [@lbkNhubert](https://community.frame.work/u/lbkNhubert)\
**Post date:** [December 31, 2021, 6:03pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/19 "2021-12-31T18:03:29Z")

</div>

@DHowett - thank you for building this, I’m enjoying poking around at things a bit. I noted on your page that the power led does not support blue (fyi for those reading, if you enter an incorrect color, in my case orange, you are presented with valid values - red green blue yellow white amber). When testing the different values, I found that when I entered blue as the color, the led appeared to turn off. While the ability at a glance to see if the power is on is lost, those who find the power led too bright may find this to be a reasonable temporary workaround to turn it off when so desired.

---

<div class="post-metadata">

**Author:** ![DHowett](https://sea1.discourse-cdn.com/flex001/user_avatar/community.frame.work/dhowett/32/1990_2.png) [@DHowett](https://community.frame.work/u/DHowett)\
**Post date:** [December 31, 2021, 9:29pm UTC](https://community.frame.work/t/exploring-the-embedded-controller/12846/20 "2021-12-31T21:29:31Z")

</div>

I’ve pushed a minor update to the page documenting host command `3E02`, some Fn key combinations, [VBAT RAM](https://www.howett.net/posts/2021-12-framework-ec/#vbat-ram), and that `fanduty`/`autofanctrl` works (thanks @D.H!)

### 3E02 ([more info](https://www.howett.net/posts/2021-12-framework-ec/#3e02---disable-fnpower-zap-vbat-ram))

This command seems to disable the FN/Power keys. When you call it with `0x01`, it remaps them to send scancodes `e016` and `e025` (respectively). When you call it with `0x5A` it resets some local configuration in the EC (charge limit, keyboard backlight, etc.)

### Keys ([more info](https://www.howett.net/posts/2021-12-framework-ec/#the-keyboard))

Fn+B is Ctrl+Break, Fn+P is Pause, and Fn+K is Scroll Lock.

* * *

Using blue to turn off the power button LED is pretty clever, actually!

[Next page](https://community.frame.work/t/exploring-the-embedded-controller/12846.md?page=2)
