Skip to content

Instantly share code, notes, and snippets.

@windix
Last active March 30, 2024 10:23
Show Gist options
  • Save windix/0f40517f1fa88efe1868d73ad8be6980 to your computer and use it in GitHub Desktop.
Save windix/0f40517f1fa88efe1868d73ad8be6980 to your computer and use it in GitHub Desktop.
RP2040-Keyboard.ino

This sketch is for Waveshare Ctrl C/V Shortcut Keyboard For Programmers, 3-Key Development Board, Adopts RP2040 Microcontroller Chip.

Please follow the wiki to setup the Arduino IDE and connect the keyboard.

Compare to the "original" firmware, I have implemented below features:

  • Support both Windows and Mac (pick one of the META_KEY definition)
  • Support three keyboard layouts:
    • mode_control_c_v(): the stocking ctrl + C + V layout
    • mode_copy_paste_cut(): the copy + paste + cut layout
    • mode_do_nothing(): press key doesn't do anything, only change backlight colours
  • Support two backlight LED modes:
    • led_mode_all(): the stocking press one key lights up all mode
    • led_mode_only_one(): only light up the key pressed
  • Bug fix: change from GRB to RGB mode
  • New feature: when press all three keys, put pi pico into firmware upload mode (since the BOOT button is hard to reach without taking the board out).

Hope you enjoying it!

#include <Keyboard.h>
#include <FastLED.h>
#define LED_PIN 18 // GPIO 18
#define NUM_LEDS 3
// From left to right, when the USB ports are on top and right
#define KEY1 14 // "Ctrl", GPIO 14
#define KEY2 13 // "C", GPIO 13
#define KEY3 12 // "V", GPIO 12
#define FLAG_KEY1 0
#define FLAG_KEY2 1
#define FLAG_KEY3 2
// PC uses Control, Mac uses Command
// Pick one:
#define META_KEY KEY_LEFT_CTRL // For PC
// #define META_KEY KEY_LEFT_GUI // For Mac
#define DELAY_BETWEEN_KEY_PRESS 10
CRGB leds[NUM_LEDS];
int flag[NUM_LEDS];
// For debounce
int keys[] = {KEY1, KEY2, KEY3};
unsigned long debounceDelay = 10;
int buttonState[NUM_LEDS];
int lastButtonState[NUM_LEDS];
unsigned long lastDebounceTime[NUM_LEDS];
// Reboot into firmware upload mode programmatically
// source:
// https://forums.raspberrypi.com/viewtopic.php?t=328795
// https://forums.raspberrypi.com/viewtopic.php?t=326333
static void wait_and_reboot() {
#if configUSE_IDLE_HOOK // if there's an IDLE hook, it's because it is used to kick the watchdog
__asm volatile(" cpsid i ");
while (true) {}; // reboot should happen here when watchdog times out
#else
watchdog_reboot(0, 0, 25);
#endif
}
void setup() {
// make pins input and turn on the pull-up resistor so they go high unless
// connected to ground:
pinMode(KEY1, INPUT_PULLUP);
pinMode(KEY2, INPUT_PULLUP);
pinMode(KEY3, INPUT_PULLUP);
// init debounce vars
for (int i = 0; i < NUM_LEDS; i++) {
buttonState[i] = HIGH; // unpressed is High
lastButtonState[i] = HIGH; // unpressed is High
lastDebounceTime[i] = 0;
}
FastLED.addLeds<WS2812, LED_PIN, RGB>(leds, NUM_LEDS);
// Indicate code loaded
for (int i = 0; i < 3; i++) {
for (int j = 0; j < NUM_LEDS; j++) {
leds[j] = CRGB(255, 255, 255);
}
FastLED.show();
delay(100);
for (int j = 0; j < NUM_LEDS; j++) {
leds[j] = CRGB(0, 0, 0);
}
FastLED.show();
delay(200);
}
Keyboard.begin();
}
void handle_keys_with_debounce(uint8_t keysDef[NUM_LEDS][2]) {
int reading;
for (int i = 0; i < NUM_LEDS; i++) {
reading = digitalRead(keys[i]);
if (reading != lastButtonState[i]) {
lastDebounceTime[i] = millis();
}
if ((millis() - lastDebounceTime[i]) > debounceDelay) {
if (reading != buttonState[i]) {
buttonState[i] = reading;
if (reading == LOW) {
for (int j = 0; j < sizeof(keysDef[i]); j++) {
if (keysDef[i][j] != 0) {
Keyboard.press(keysDef[i][j]);
}
}
flag[i] = 1;
} else {
Keyboard.releaseAll();
flag[i] = 0;
}
}
}
lastButtonState[i] = reading;
}
}
void led_mode_all() {
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = CRGB(flag[FLAG_KEY1] * 255, flag[FLAG_KEY2] * 255, flag[FLAG_KEY3] * 255);
}
}
void led_mode_only_one() {
leds[0] = CRGB(flag[FLAG_KEY1] * 255, 0, 0);
leds[1] = CRGB(0, flag[FLAG_KEY2] * 255, 0);
leds[2] = CRGB(0, 0, flag[FLAG_KEY3] * 255);
}
void loop() {
uint8_t mode_control_c_v[NUM_LEDS][2] = {
{META_KEY, 0},
{'c', 0},
{'v', 0}
};
uint8_t mode_copy_paste_cut[NUM_LEDS][2] = {
{META_KEY, 'c'},
{META_KEY, 'v'},
{META_KEY, 'x'}
};
uint8_t mode_do_nothing[NUM_LEDS][2] = {
{0, 0},
{0, 0},
{0, 0}
};
// choose one mode
handle_keys_with_debounce(mode_copy_paste_cut);
led_mode_all();
// led_mode_only_one();
FastLED.show();
delay(5);
// Since the BOOT button is not easy to reach without take the board out,
// here we checks if ALL three keys are pressed we will enter firmware upload mode
if (flag[FLAG_KEY1] && flag[FLAG_KEY2] && flag[FLAG_KEY3]) {
multicore_reset_core1();
reset_usb_boot(0, 0);
reset_usb_boot(0, 0);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment