Skip to content

Commit

Permalink
Refactored soft off. Squashed and merged.
Browse files Browse the repository at this point in the history
Co-authored-by: [email protected]
  • Loading branch information
Nick-Munnich committed Aug 24, 2024
1 parent 42cdca5 commit ab03ece
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 326 deletions.
68 changes: 48 additions & 20 deletions docs/docs/config/kscan.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,15 @@ Applies to: `compatible = "zmk,kscan-gpio-direct"`

Definition file: [zmk/app/module/dts/bindings/kscan/zmk,kscan-gpio-direct.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/module/dts/bindings/kscan/zmk%2Ckscan-gpio-direct.yaml)

| Property | Type | Description | Default |
| ------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------- | ------- |
| `input-gpios` | GPIO array | Input GPIOs (one per key). Can be either direct GPIO pin or `gpio-key` references. | |
| `debounce-press-ms` | int | Debounce time for key press in milliseconds. Use 0 for eager debouncing. | 5 |
| `debounce-release-ms` | int | Debounce time for key release in milliseconds. | 5 |
| `debounce-scan-period-ms` | int | Time between reads in milliseconds when any key is pressed. | 1 |
| `poll-period-ms` | int | Time between reads in milliseconds when no key is pressed and `CONFIG_ZMK_KSCAN_DIRECT_POLLING` is enabled. | 10 |
| `toggle-mode` | bool | Use toggle switch mode. | n |
| `wakeup-source` | bool | Mark this kscan instance as able to wake the keyboard from deep sleep | n |
| Property | Type | Description | Default |
| ------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------- | ------- |
| `input-gpios` | GPIO array | Input GPIOs (one per key). Can be either direct GPIO pin or `gpio-key` references | |
| `debounce-press-ms` | int | Debounce time for key press in milliseconds. Use 0 for eager debouncing | 5 |
| `debounce-release-ms` | int | Debounce time for key release in milliseconds | 5 |
| `debounce-scan-period-ms` | int | Time between reads in milliseconds when any key is pressed | 1 |
| `poll-period-ms` | int | Time between reads in milliseconds when no key is pressed and `CONFIG_ZMK_KSCAN_DIRECT_POLLING` is enabled | 10 |
| `toggle-mode` | bool | Use toggle switch mode | n |
| `wakeup-source` | bool | Mark this kscan instance as able to wake the keyboard | n |

Assuming the switches connect each GPIO pin to the ground, the [GPIO flags](https://docs.zephyrproject.org/3.5.0/hardware/peripherals/gpio.html#api-reference) for the elements in `input-gpios` should be `(GPIO_ACTIVE_LOW | GPIO_PULL_UP)`:

Expand Down Expand Up @@ -133,16 +133,16 @@ Applies to: `compatible = "zmk,kscan-gpio-matrix"`

Definition file: [zmk/app/module/dts/bindings/kscan/zmk,kscan-gpio-matrix.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/module/dts/bindings/kscan/zmk%2Ckscan-gpio-matrix.yaml)

| Property | Type | Description | Default |
| ------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------- | ----------- |
| `row-gpios` | GPIO array | Matrix row GPIOs in order, starting from the top row | |
| `col-gpios` | GPIO array | Matrix column GPIOs in order, starting from the leftmost row | |
| `debounce-press-ms` | int | Debounce time for key press in milliseconds. Use 0 for eager debouncing. | 5 |
| `debounce-release-ms` | int | Debounce time for key release in milliseconds. | 5 |
| `debounce-scan-period-ms` | int | Time between reads in milliseconds when any key is pressed. | 1 |
| `diode-direction` | string | The direction of the matrix diodes | `"row2col"` |
| `poll-period-ms` | int | Time between reads in milliseconds when no key is pressed and `CONFIG_ZMK_KSCAN_MATRIX_POLLING` is enabled. | 10 |
| `wakeup-source` | bool | Mark this kscan instance as able to wake the keyboard from deep sleep | n |
| Property | Type | Description | Default |
| ------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------- | ----------- |
| `row-gpios` | GPIO array | Matrix row GPIOs in order, starting from the top row | |
| `col-gpios` | GPIO array | Matrix column GPIOs in order, starting from the leftmost row | |
| `debounce-press-ms` | int | Debounce time for key press in milliseconds. Use 0 for eager debouncing | 5 |
| `debounce-release-ms` | int | Debounce time for key release in milliseconds | 5 |
| `debounce-scan-period-ms` | int | Time between reads in milliseconds when any key is pressed | 1 |
| `diode-direction` | string | The direction of the matrix diodes | `"row2col"` |
| `poll-period-ms` | int | Time between reads in milliseconds when no key is pressed and `CONFIG_ZMK_KSCAN_MATRIX_POLLING` is enabled | 10 |
| `wakeup-source` | bool | Mark this kscan instance as able to wake the keyboard | n |

The `diode-direction` property must be one of:

Expand Down Expand Up @@ -198,7 +198,7 @@ Definition file: [zmk/app/module/dts/bindings/kscan/zmk,kscan-gpio-charlieplex.y
| `debounce-release-ms` | int | Debounce time for key release in milliseconds. | 5 |
| `debounce-scan-period-ms` | int | Time between reads in milliseconds when any key is pressed. | 1 |
| `poll-period-ms` | int | Time between reads in milliseconds when no key is pressed and `interrupt-gpois` is not set. | 10 |
| `wakeup-source` | bool | Mark this kscan instance as able to wake the keyboard from deep sleep | n |
| `wakeup-source` | bool | Mark this kscan instance as able to wake the keyboard | n |

Define the transform with a [matrix transform](#matrix-transform). The row is always the driven pin, and the column always the receiving pin (input to the controller).
For example, in `RC(5,0)` power flows from the 6th pin in `gpios` to the 1st pin in `gpios`.
Expand Down Expand Up @@ -362,6 +362,34 @@ Definition file: [zmk/app/dts/bindings/zmk,matrix-transform.yaml](https://github

The `map` array should be defined using the `RC()` macro from [dt-bindings/zmk/matrix_transform.h](https://github.com/zmkfirmware/zmk/blob/main/app/include/dt-bindings/zmk/matrix_transform.h). It should have one item per logical position in the keymap. Each item should list the physical row and column that should trigger the key in that position.

## Kscan Sideband Behavior Driver

The Kscan sideband behaviors node can be used to assign behaviors to keys in a manner distinctly separate from the keymap. These assignments and definitions will not be affected by nor have any effect on the keymap.

### Devicetree

Applies to: `compatible = "zmk,kscan-sideband-behaviors"`

Definition file: [zmk/app/dts/bindings/kscan/zmk,matrix-transform.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/kscan/zmk%2Ckscan-sideband-behaviors.yaml)

| Property | Type | Description |
| --------------- | ------- | --------------------------------------------------------- |
| `kscan` | phandle | Phandle to a kscan containing keys to assign behaviors to |
| `auto-enable` | bool | Enables the sideband instance on startup unconditionally |
| `wakeup-source` | bool | Mark this kscan instance as able to wake the keyboard |

If `auto-enable` is not set, then the sideband behavior will wait for an external activation source before being enabled, e.g. being assigned as the chosen `zmk,kscan`. The `kscan` can contain additional keys, which will be used by the keymap if this node is set as the chosen `zmk,kscan` and has an appropriate matrix transformation defined.

Each child node should have the following properties:

| Property | Type | Description | Default |
| ---------- | ------------- | ------------------------------------------------------------------------------------- | ------- |
| `row` | int | The row index of the key in the `kscan` to intercept and trigger a behavior for | 0 |
| `column` | int | The column index of the key in the `kscan` to intercept and trigger a behavior for | |
| `bindings` | phandle-array | The behavior that should be triggered when the matching row and column event triggers | |

## Examples

### Example: Skipping Unused Positions

Any keyboard which is not a grid of 1 unit keys will likely have some unused positions in the matrix. A matrix transform can be used to skip the unused positions so users don't have to set them to `&none` in keymaps.
Expand Down
61 changes: 38 additions & 23 deletions docs/docs/config/power.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,20 @@ sidebar_label: Power Management
See [Configuration Overview](index.md) for instructions on how to
change these settings.

## Idle/Sleep
## Low Power States

Configuration for entering low power modes when the keyboard is idle.

In the idle state, peripherals such as displays and lighting are disabled, but the keyboard remains connected to Bluetooth so it can immediately respond when you press a key.

In the deep sleep state, the keyboard additionally disconnects from Bluetooth and any external power output is disabled. This state uses very little power, but it may take a few seconds to reconnect after waking. To allow a device to wake from deep sleep, the `wakeup-source` property needs to be applied to the `kscan` driver of said device. See [soft off](../features/soft-off.md#wakeup-sources) for an example.

### Kconfig

Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/Kconfig)

| Config | Type | Description | Default |
| ------------------------------- | ---- | ----------------------------------------------------- | ------- |
| `CONFIG_ZMK_IDLE_TIMEOUT` | int | Milliseconds of inactivity before entering idle state | 30000 |
| `CONFIG_ZMK_SLEEP` | bool | Enable deep sleep support | n |
| `CONFIG_ZMK_IDLE_SLEEP_TIMEOUT` | int | Milliseconds of inactivity before entering deep sleep | 900000 |

## Soft Off

The [soft off feature](../features/soft-off.md) allows turning the keyboard on/off from either dedicated hardware, or using the [`&soft_off` behavior](../keymaps/behaviors/soft-off.md) to turn off and a reset button to turn back on again.
Configuration for entering [low power states](../features/low-power-states.md) when the keyboard is idle.

### Kconfig

Definition file: [zmk/app/Kconfig](https://github.com/zmkfirmware/zmk/blob/main/app/Kconfig)

| Config | Type | Description | Default |
| ------------------------ | ---- | ------------------------------------------------------------------- | ------- |
| `CONFIG_ZMK_PM_SOFT_OFF` | bool | Enable soft off functionality from the keymap or dedicated hardware | n |
| Config | Type | Description | Default |
| ------------------------------- | ---- | ------------------------------------------------------------------- | ------- |
| `CONFIG_ZMK_IDLE_TIMEOUT` | int | Milliseconds of inactivity before entering idle state | 30000 |
| `CONFIG_ZMK_SLEEP` | bool | Enable deep sleep support | n |
| `CONFIG_ZMK_IDLE_SLEEP_TIMEOUT` | int | Milliseconds of inactivity before entering deep sleep | 900000 |
| `CONFIG_ZMK_PM_SOFT_OFF` | bool | Enable soft off functionality from the keymap or dedicated hardware | n |

## External Power Control

Expand All @@ -56,3 +41,33 @@ Applies to: `compatible = "zmk,ext-power-generic"`
| --------------- | ---------- | ------------------------------------------------------------- |
| `control-gpios` | GPIO array | List of GPIOs which should be active to enable external power |
| `init-delay-ms` | int | number of milliseconds to delay after initializing the driver |

## GPIO Key Wakeup Trigger

A device similar to a [kscan](./kscan.md) which will be enabled only when the keyboard is entering [soft off](../features/low-power-states.md#soft-off) state. This is used to configure a GPIO key to wake the keyboard from [soft off](../features/low-power-states.md#soft-off) once it is pressed.

### Devicetree

Applies to: `compatible = "zmk,gpio-key-wakeup-trigger"`

Definition file: [zmk/app/dts/bindings/zmk,gpio-key-wakeup-trigger.yaml](https://github.com/zmkfirmware/zmk/blob/main/app/dts/bindings/zmk%2Cgpio-key-wakeup-trigger.yaml)

| Property | Type | Description |
| --------------- | ---------- | --------------------------------------------------------------------------------------------- |
| `trigger` | phandle | Phandle to a GPIO key to be used to wake from soft off |
| `wakeup-source` | bool | Mark this device as able to wake the keyboard |
| `extra-gpios` | GPIO array | :ist of GPIO pins (including the appropriate flags) to set active before going into power off |

The `wakeup-source` property should always be present, otherwise this node is pointless. The `extra-gpios` property should be used to ensure the GPIO pin will trigger properly to wake the keyboard. For example, for a `col2row` matrix kscan, these are the column pins relevant for soft off.

## Soft Off Wakeup Sources

Selects a list of devices to enable during [soft off](../features/low-power-states.md#soft-off), allowing those with `wakeup-source` as a property to wake the keyboard.

### Devicetree

Applies to: `compatible = "zmk,soft-off-wakeup-sources"`

| Property | Type | Description |
| ---------------- | ------------- | ------------------------------------------------------------------------------------------------- |
| `wakeup-sources` | phandle array | List of devices to enable during the shutdown process to be sure they can later wake the keyboard |
70 changes: 70 additions & 0 deletions docs/docs/features/low-power-states.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
title: Low Power States
sidebar_label: Low Power States
---

## Idle

In the idle state, peripherals such as displays and lighting are disabled, but the keyboard remains connected to Bluetooth so it can immediately respond when you press a key. Idle state is entered automatically after a timeout period that is [30 seconds by default](../config/power.md#low-power-states).

## Deep Sleep

In the deep sleep state, the keyboard additionally disconnects from Bluetooth and any external power output is disabled. This state uses very little power, but it may take a few seconds to reconnect after waking.

### Config

Deep sleep must be enabled via its corresponding [config](../config/power.md#low-power-states).

### Wakeup Sources

Zephyr has general support for the concept of a device as a "wakeup source". Using deep sleep requires `kscan` nodes to have the `wakeup-source` property to enable them to wake the keyboard, e.g.:

```dts
/ {
kscan: kscan {
compatible = "zmk,kscan-gpio-matrix";
diode-direction = "col2row";
wakeup-source;
...
};
};
```

It is recommended to add the `wakeup-source` property to `kscan` devices even if the deep sleep feature is not used -- there is no downside to it.

## Soft Off

The soft off feature is used to turn the keyboard on and off explicitly, rather than through a timeout like the deep sleep feature. Depending on the keyboard, this may be through a dedicated on/off push button defined in hardware, or merely through an additional binding in the keymap to turn the device off and an existing reset button to turn the device back on.

The feature is intended as an alternative to using a hardware switch to physically cut power from the battery to the keyboard. This can be useful for existing PCBs not designed for wireless that don't have a power switch, or for new designs that favor a push button on/off like found on other devices. It yields power savings comparable to the deep sleep state.

:::note

The power off is accomplished by putting the MCU into a "soft off" state. Power is _not_ technically removed from the entire system, but the device will only be woken from the state by a few possible events.

:::

A device can be put in the soft off state by:

- Triggering a hardware-defined dedicated GPIO pin, if one exists;
- Triggering the [soft off behavior](../keymaps/behaviors/soft-off.md) from the keymap.

Once in the soft off state, the device can only be woken up by:

- Triggering any GPIO pin specified to enable waking from sleep, if one exists;
- Pressing a reset button found on the device.

The GPIO pin used to wake from sleep can be a hardware-defined one, such as for a dedicated on-off push button, or it can be a single specific key switch reused for waking up (which may be accidentally pressed, e.g. while the device is being carried in a bag). To allow the simultaneous pressing of multiple key switches to trigger and exit soft off, some keyboards make use of additional hardware to integrate the dedicated GPIO pin into the keyboard matrix.

### Config

Soft off must be enabled via [its corresponding config](../config/power.md#low-power-states) before it can be used.

### Using Soft Off

If your keyboard has hardware designed to take advantage of soft off, refer to your keyboard's documentation.

For keyboards which do not have such hardware, using soft off is as simple as placing the [soft off behavior](../keymaps/behaviors/soft-off.md) in your keymap and then invoking it.

You can then wake up the keyboard by pressing the reset button once, and repeating this for each side for split keyboards.
Loading

0 comments on commit ab03ece

Please sign in to comment.