This commit is contained in:
ploopyco 2025-07-23 08:59:18 -04:00 committed by GitHub
commit 3fa70de220
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 301 additions and 1 deletions

View File

@ -0,0 +1,69 @@
/* Copyright 2025 Colin Lam, Ploopy Corporation (contact@ploopy.co)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "as5600.h"
#include "print.h"
void as5600_init(void) {
i2c_init();
}
uint16_t get_rawangle(void) {
uint8_t data[] = {0, 0};
i2c_status_t s = i2c_read_register(AS5600_I2C_ADDRESS, REG_RAWANGLE, data, 2, 100);
if (s == I2C_STATUS_TIMEOUT) {
printf("Timeout on get_rawangle()\n");
} else if (s == I2C_STATUS_ERROR) {
printf("Error on get_rawangle()\n");
} else {
;
}
uint16_t rawangle = data[0] << 8 | data[1];
return rawangle;
}
bool is_magnet_too_high(void) {
uint8_t data[] = {0};
i2c_read_register(AS5600_I2C_ADDRESS, REG_STATUS, data, 1, 100);
uint8_t v = (data[0] >> 3) & 0x1;
if (v == 1) {
return true;
} else {
return false;
}
}
bool is_magnet_too_low(void) {
uint8_t data[] = {0};
i2c_read_register(AS5600_I2C_ADDRESS, REG_STATUS, data, 1, 100);
uint8_t v = (data[0] >> 4) & 0x1;
if (v == 1) {
return true;
} else {
return false;
}
}
bool is_magnet_present(void) {
uint8_t data[] = {0};
i2c_read_register(AS5600_I2C_ADDRESS, REG_STATUS, data, 1, 100);
uint8_t v = (data[0] >> 5) & 0x1;
if (v == 1) {
return true;
} else {
return false;
}
}

View File

@ -0,0 +1,54 @@
/* Copyright 2025 Colin Lam, Ploopy Corporation (contact@ploopy.co)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "i2c_master.h"
#define POINTING_DEVICE_AS5600_TICK_COUNT 128
// 12 was found to be a good value experimentally, balancing good
// responsiveness with low backlash.
#define POINTING_DEVICE_AS5600_DEADZONE 12
// The speed divisor decreases the speed. 1 is base speed; 2 is divided by 2,
// 3 is divided by 3, and so forth. For best results, make sure that
// POINTING_DEVICE_AS5600_SPEED_DIV is an integer divisor of
// POINTING_DEVICE_AS5600_DEADZONE (i.e. 3 is an integer divisor of 12, but
// 5 is not).
#define POINTING_DEVICE_AS5600_SPEED_DIV 2
#define AS5600_I2C_ADDRESS (0x36 << 1)
#define REG_ZMCO 0x00
#define REG_ZPOS 0x01
#define REG_MPOS 0x03
#define REG_MANG 0x05
#define REG_CONF 0x07
#define REG_RAWANGLE 0x0c
#define REG_ANGLE 0x0e
#define REG_STATUS 0x0b
#define REG_AGC 0x1a
#define REG_MAGNITUDE 0x1b
#define REG_BURN 0xff
void as5600_init(void);
uint16_t get_rawangle(void);
bool is_magnet_too_high(void);
bool is_magnet_too_low(void);
bool is_magnet_present(void);

View File

@ -0,0 +1,29 @@
/* Copyright 2025 Colin Lam (Ploopy Corporation)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#define POINTING_DEVICE_HIRES_SCROLL_ENABLE 0
#define POINTING_DEVICE_AS5600_ENABLE true
#define I2C_DRIVER I2CD1
#define I2C1_SDA_PIN GP22
#define I2C1_SCL_PIN GP23
#define UNUSABLE_PINS \
{ GP0, GP1, GP2, GP3, GP4, GP5, GP6, GP7, GP8, GP9, GP10, GP11, GP12, \
GP13, GP14, GP15, GP16, GP17, GP18, GP19, GP20, GP21, GP24, GP25, \
GP26, GP27, GP29 }

View File

@ -0,0 +1,28 @@
{
"keyboard_name": "Ploopy Knob",
"url": "www.ploopy.co",
"maintainer": "ploopyco",
"manufacturer": "Ploopy Corporation",
"processor": "RP2040",
"bootloader": "rp2040",
"usb": {
"vid": "0x5043",
"pid": "0x63C3",
"max_power": 100
},
"features": {
"extrakey": true,
"mousekey": true,
"nkro": true,
"pointing_device": true,
"console": true,
"os_detection": true
},
"layouts": {
"LAYOUT": {
"layout": [
{"x": 0, "y": 0, "matrix": [0, 0]}
]
}
}
}

View File

@ -0,0 +1,27 @@
/* Copyright 2023 Colin Lam (Ploopy Corporation)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include QMK_KEYBOARD_H
// Dummy
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {{{ KC_NO }}};
void keyboard_post_init_user(void) {
// Customise these values to desired behaviour
// debug_enable=true;
// debug_matrix=true;
// debug_keyboard=true;
// debug_mouse=true;
}

View File

@ -0,0 +1,4 @@
VPATH += keyboards/ploopyco/common
SRC += as5600.c
I2C_DRIVER_REQUIRED = yes
POINTING_DEVICE_DRIVER = custom

View File

@ -0,0 +1,31 @@
# Ploopyco Knob
It's a DIY, QMK-powered knob!
* Keyboard Maintainer: [PloopyCo](https://github.com/ploopyco)
* Hardware Supported: RP2040
* Hardware Availability: [Store](https://ploopy.co/knob), [GitHub](https://github.com/ploopyco)
Make example for this keyboard (after setting up your build environment):
qmk compile -kb ploopyco/knob/rev1_001 -km default
# Building Firmware
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
# Triggering the Bootloader
[Do you see those two golden holes in the board](https://ploopy.co/wp-content/uploads/2025/06/knob-vias.jpg)? Those are called **vias**. They act exactly like a switch does. Right now, that switch is OFF. However, if you take a paperclip or a pair of metal tweezers and touch those two vias, the two vias will form an electrical connection. Effectively, that switch turns ON.
Go ahead and connect the two vias, and then (while the vias are connected) plug in the Knob board into your computer.
The computer should recognise that a mass storage device was just plugged in. Once this is done, you should be able to drag and drop files onto the Knob board, as if the board was a USB drive. Feel free to remove the tweezers or paperclip at this point.
If you want to upload a new firmware file (a ".uf2" file, like "knob_awesome_version.uf2" or something), just drag it into the folder, and it'll automatically install on the Knob board and restart itself, in normal operating mode. You're done!
**TIP**: If your firmware is in some kind of strange state and uploading new firmware isn't fixing it, try uploading [a flash nuke](https://learn.adafruit.com/getting-started-with-raspberry-pi-pico-circuitpython/circuitpython#flash-resetting-uf2-3083182) to the Knob board before flashing the new firmware. It wipes the memory of the Knob board completely clean, which can help clear a few types of errors.
# Customizing your Ploopy Knob
You can find customziation options [here](../readme.md).

View File

@ -0,0 +1,10 @@
{
"usb": {
"device_version": "1.0.0"
},
"matrix_pins": {
"direct": [
[null]
]
}
}

View File

@ -0,0 +1,3 @@
This is the R1.001 version of the Knob. Future versions may have other features.
See the [main readme](../readme.md) for more details.

View File

@ -19,6 +19,7 @@
#include "ploopyco.h" #include "ploopyco.h"
#include "analog.h" #include "analog.h"
#include "opt_encoder.h" #include "opt_encoder.h"
#include "as5600.h"
// for legacy support // for legacy support
#if defined(OPT_DEBOUNCE) && !defined(PLOOPY_SCROLL_DEBOUNCE) #if defined(OPT_DEBOUNCE) && !defined(PLOOPY_SCROLL_DEBOUNCE)
@ -58,6 +59,10 @@
# define ENCODER_BUTTON_COL 0 # define ENCODER_BUTTON_COL 0
#endif #endif
#ifdef POINTING_DEVICE_AS5600_ENABLE
uint16_t current_position = 0;
#endif
keyboard_config_t keyboard_config; keyboard_config_t keyboard_config;
uint16_t dpi_array[] = PLOOPY_DPI_OPTIONS; uint16_t dpi_array[] = PLOOPY_DPI_OPTIONS;
#define DPI_OPTION_SIZE ARRAY_SIZE(dpi_array) #define DPI_OPTION_SIZE ARRAY_SIZE(dpi_array)
@ -163,6 +168,38 @@ report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
mouse_report.y = 0; mouse_report.y = 0;
} }
#ifdef POINTING_DEVICE_AS5600_ENABLE
// Get AS5600 rawangle
uint16_t ra = get_rawangle();
int16_t delta = (int16_t)(ra - current_position);
// Wrap into [-2048, 2047] to get shortest direction
if (delta > 2048) {
delta -= 4096;
} else if (delta < -2048) {
delta += 4096;
}
if (detected_host_os() == OS_WINDOWS || detected_host_os() == OS_LINUX) {
// Establish a deadzone to prevent spurious inputs
if (delta > POINTING_DEVICE_AS5600_DEADZONE || delta < -POINTING_DEVICE_AS5600_DEADZONE) {
current_position = ra;
mouse_report.v = delta / POINTING_DEVICE_AS5600_SPEED_DIV;
}
} else {
// Certain operating systems, like MacOS, don't play well with the
// high-res scrolling implementation. For more details, see:
// https://github.com/qmk/qmk_firmware/issues/17585#issuecomment-2325248167
if (delta >= POINTING_DEVICE_AS5600_TICK_COUNT) {
current_position = ra;
mouse_report.v = 1;
} else if (delta <= -POINTING_DEVICE_AS5600_TICK_COUNT) {
current_position = ra;
mouse_report.v = -1;
}
}
#endif
return pointing_device_task_user(mouse_report); return pointing_device_task_user(mouse_report);
} }
@ -204,7 +241,7 @@ bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
void keyboard_pre_init_kb(void) { void keyboard_pre_init_kb(void) {
// debug_enable = true; // debug_enable = true;
// debug_matrix = true; // debug_matrix = true;
// debug_mouse = true; //debug_mouse = true;
// debug_encoder = true; // debug_encoder = true;
/* Ground all output pins connected to ground. This provides additional /* Ground all output pins connected to ground. This provides additional
@ -237,6 +274,14 @@ void pointing_device_init_kb(void) {
pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]); pointing_device_set_cpi(dpi_array[keyboard_config.dpi_config]);
} }
#ifdef POINTING_DEVICE_AS5600_ENABLE
void keyboard_post_init_kb(void) {
// Init the AS5600 controlling the Dial
as5600_init();
current_position = get_rawangle();
}
#endif
void eeconfig_init_kb(void) { void eeconfig_init_kb(void) {
keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT; keyboard_config.dpi_config = PLOOPY_DPI_DEFAULT;
eeconfig_update_kb(keyboard_config.raw); eeconfig_update_kb(keyboard_config.raw);