element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
    About the element14 Community
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      •  Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Spring Clean!
  • Challenges & Projects
  • Project14
  • Spring Clean!
  • More
  • Cancel
Spring Clean!
Spring Clean Projects 2026 Building a Low Power keyboard for Future Projects
  • News and Projects
  • Forum
  • Members
  • More
  • Cancel
  • New
Join Spring Clean! to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: arvindsa
  • Date Created: 31 May 2026 2:58 PM Date Created
  • Views 36 views
  • Likes 2 likes
  • Comments 0 comments
  • Spring Clean 2026
Related
Recommended

Building a Low Power keyboard for Future Projects

arvindsa
arvindsa
31 May 2026
Building a Low Power keyboard for Future Projects

In Nov 2025, I saw a post on hackster - https://www.hackster.io/news/solder-party-launches-the-keebdeck-a-compact-silicone-keyboard-for-space-constrained-projects-06d01d8d106f that a querty silicone keyboard had been released. I have been a big fan of QWERTY Keyboards, I do most of my typing on Keychron K10 Keyboard. But for my electronics project, I have been limited to using the CardKB from M5Stack https://shop.m5stack.com/products/cardkb-mini-keyboard?srsltid=AfmBOop73BkcZFg_WyZXwfYKMJ5xfTu4PyH3gwLlfR26xpvQzGUErWHu . it did not have any silicone cover or any keymap printed on user facing surface. So this looked so amazing that i impulsively purchased it without thinking or planning for making a project out of it.

image

It came in around a month, and i forgot about it, until this spring clean competition came. So I quickly started making the PCB for it. My requirements were 

  1. Use Row-Column Scanning to identify the key pressed
  2. Work as a I2C Slave to share the key pressed, along with an interrupt pin
  3. Sleep and be woken up by the key press without missing the key pressed
  4. Also debounce and ensure keypress are not duplicated unnecessary 

And for the the MCU i went for STM32U Series. It is extremely low power, I have been exposed to STM32 L and F series, but U series takes power saving even a step further. Even though there are subtle changes in the HAL functions, I still will go with the STM32 HAL Programming

Here is where i did something extremely un-necessary. I modified the footprint of the Keyboard from the one provided in their github repo. The aim was to add ghost preventing diodes. But, it turned out be a disaster as i forgot to wire them properly, 

image

So I had to make another one. But no experiments this time, Stuck to the original footprint.

image

image

image

In this i also added ability for backlighting, although it was a stretch goal for me.

Pin Assignment

Signal Pin Notes
R0 PA7 Row output, PP
R1 PB0 Row output, PP
R2 PB1 Row output, PP
R3 PB2 Row output, PP
R4 PB10 Row output, PP
R5 PB11 Row output, PP
C0–C2 PC13–PC15 Column inputs, pull-down
C3 PA1 Column input, pull-down
C4–C6 PA4–PA6 Column inputs, pull-down
C7–C10 PB12–PB15 Column inputs, pull-down
C11–C12 PA8–PA9 Column inputs, pull-down
WUP PA0 EXTI rising edge (wakeup path)
LED PA12 Status LED output
TX/RX PA2/PA3 USART2, 115200 8N1

The wakeup path is where all the columns lines feed through a BAT54C dual Schottky onto a single line that connects to PA0 (PWR_WKUP1). Before entering Stop1, all rows are driven HIGH. The moment I press a key, the column rises through the diode, the BAT54C passes it to PA0, the EXTI fires, and the MCU wakes. 

Firmware Structure

The firmware is generated with STM32CubeMX (GCC/Makefile output) and built with arm-none-eabi-gcc.

keebdeck-keyboard-fw/
├── keebdeck-keyboard-fw.ioc          ← CubeMX project (PA0, USART2, SWD, LED)
├── Makefile                           ← arm-none-eabi GCC build
├── flash.sh                           ← st-flash convenience wrapper
├── STM32U031xx_FLASH.ld               ← 64 KB flash, 16 KB RAM, stack 0x400
├── STM32U031xx_RAM.ld
├── startup_stm32u031xx.s              ← Reset handler, vector table
└── Core/
    ├── Inc/
    │   ├── main.h                     ← All Rx_Pin / Cx_Pin #defines live here
    │   ├── stm32u0xx_hal_conf.h       ← HAL module enable switches
    │   └── stm32u0xx_it.h
    └── Src/
        ├── main.c                     ← Entry point, matrix scan, Stop1 sleep
        ├── stm32u0xx_hal_msp.c        ← MspInit — peripheral clock enables
        ├── stm32u0xx_it.c             ← ISR stubs + EXTI0_1_IRQHandler
        ├── syscalls.c                 ← Newlib syscall stubs
        ├── sysmem.c                   ← Heap via sbrk
        └── system_stm32u0xx.c        ← SystemInit, SystemCoreClock

How the Matrix Scan Works

The scan loop is a simple row-at-a-time approach. Each pass through the superloop services one row, then advances to the next. A full 6-row cycle therefore takes 6 loop iterations.

image

/* Drive only row r HIGH, all others LOW */
for (int i = 0; i < 6; i++)
    HAL_GPIO_WritePin(row_ports[i], row_pins[i], (i == r) ? GPIO_PIN_SET : GPIO_PIN_RESET);

HAL_Delay(1); /* settle */

/* Read all 13 columns */
uint8_t c[13];
c[0]  = HAL_GPIO_ReadPin(C0_GPIO_Port,  C0_Pin)  ? 1 : 0;
/* ... c[1] through c[12] similarly ... */

For each key position, debounce runs as a counter: the raw signal has to agree for DEBOUNCE_COUNT (5) consecutive reads before the state is accepted. Once stable, a key-press fires a USART2 print of the key name. Key-held repeat fires after REPEAT_DELAY_MS (500 ms) and then every REPEAT_RATE_MS (50 ms).

if (c[col] != key_state[r][col])
{
    if (++key_count[r][col] >= DEBOUNCE_COUNT)
    {
        key_state[r][col] = c[col];
        key_count[r][col] = 0;
        if (c[col])
        {
            /* key pressed — log it */
            char buf[16];
            int len = snprintf(buf, sizeof(buf), "%s\r\n", keymap[r][col]);
            HAL_UART_Transmit(&huart2, (uint8_t *)buf, len, 50);
        }
    }
}

Stop1 Sleep and Wakeup

image

After 5 seconds of no key activity, the firmware puts the MCU into Stop1 mode. Before sleeping, all rows are driven HIGH — this is what arms the wakeup path through the BAT54C. A 10 ms settle delay flushes any transient that might have been captured during the row-HIGH transition, then both the EXTI pending bit and the NVIC pending bit are cleared so a glitch can't cause an immediate false wakeup:

HAL_Delay(10);
wakeup_edge = 0;
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
NVIC_ClearPendingIRQ(EXTI0_1_IRQn);

on Cortex-M0+, a pending SysTick interrupt will cause WFI to return immediately without entering Stop1 at all. HAL_SuspendTick() takes care of this:

HAL_SuspendTick();
HAL_PWREx_EnterSTOP1Mode(PWR_STOPENTRY_WFI);

/* --- wakes here on PA0 EXTI --- */
SystemClock_Config();   /* restore HSI 16 MHz — Stop1 kills the clock */
HAL_ResumeTick();

HSI is stopped in Stop1, so SystemClock_Config() must be called after wakeup to restore the 16 MHz clock before any HAL function that needs SysTick timing is used (including HAL_UART_Transmit). I learned this the hard way when the UART came back as garbage after the first wakeup.

After wakeup, the debounce counters are primed to DEBOUNCE_COUNT - 1 so the key that triggered the wakeup registers on the very first scan pass rather than sitting through 5 more cycles of debounce while still held:

memset(key_count, DEBOUNCE_COUNT - 1, sizeof(key_count));

Power Analysis

Using Nordic PPK2, I checked the power consumption

image

While running, it took 1.34mA and while sleeping it took 0.74mA. I know for a fact, that with further optimization, i can bring it down even more. But that is for another time.

Code

The Code for this project along with the kicad files can be found here : https://github.com/arvindsa/keebdeck-dekboard 

Demo Video 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

  • Sign in to reply
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2026 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube