* Add kmini

* Change keyboard USB description
master
Maarten Dekkers 2018-07-12 21:42:36 +02:00 committed by Drashna Jaelre
parent 9c35c5979c
commit ed98250e62
8 changed files with 600 additions and 0 deletions

View File

@ -0,0 +1,58 @@
/* Copyright 2018 Maarten Dekkers <maartenwut@gmail.com>
*
* 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/>.
*/
#ifndef CONFIG_H
#define CONFIG_H
#include "config_common.h"
/* USB Device descriptor parameter */
#define VENDOR_ID 0xFEED
#define PRODUCT_ID 0x6050
#define DEVICE_VER 0x0104
#define MANUFACTURER Revo
#define PRODUCT KMAC Kmini
#define DESCRIPTION QMK keyboard firmware for Revo KMAC Mini
/* key matrix size */
#define MATRIX_ROWS 5
#define MATRIX_COLS 17
/*
* Keyboard Matrix Assignments
* The KMAC uses a demultiplexer for some of the cols.
* See matrix.c for more details.
*/
#define MATRIX_ROW_PINS { D0, D1, D2, D3, D5 }
#define MATRIX_COL_PINS { }
#define UNUSED_PINS
/* COL2ROW, ROW2COL, or CUSTOM_MATRIX */
#define DIODE_DIRECTION CUSTOM_MATRIX
/* number of backlight levels */
#define BACKLIGHT_LEVELS 3
// #define BACKLIGHT_PIN B7
// #define BACKLIGHT_BREATHING
/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
#define DEBOUNCING_DELAY 5
/* key combination for magic key command */
#define IS_COMMAND() ( \
keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \
)
#endif

View File

@ -0,0 +1,6 @@
{
"keyboard_name": "KMAC Mini",
"url": "http://kbdmodadmin.cafe24.com/product/detail.html?product_no=12&cate_no=4&display_group=1",
"maintainer": "maartenwut"
}
}

View File

@ -0,0 +1,60 @@
/* Copyright 2018 Maarten Dekkers <maartenwut@gmail.com>
*
* 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 "kmini.h"
// Helpful defines
#define _____ KC_TRNS
// Each layer gets a name for readability, which is then used in the keymap matrix below.
// The underscores don't mean anything - you can have a layer called STUFF or any other name.
// Layer names don't all need to be of the same length, obviously, and you can also skip them
// entirely and just use numbers.
#define _MA 0
#define _FN 1
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_MA] = LAYOUT(
KC_F1, KC_F2, KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_INS, \
KC_F3, KC_F4, KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL, \
KC_F5, KC_F6, KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_PGUP, \
KC_F7, KC_F8, KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_PGDN, \
KC_F9, KC_F10, KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, MO(_FN), KC_LEFT, KC_DOWN, KC_RGHT \
),
[_FN] = LAYOUT(
_____, _____, _____, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, RESET, _____, \
_____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, \
_____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, \
_____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, _____, \
_____, _____, _____, _____, _____, _____, _____, _____, _____, _____ \
),
};
void led_set_user(uint8_t usb_led) {
if (usb_led & (1<<USB_LED_CAPS_LOCK)) {
PORTB &= ~(1<<1); // LO
} else {
PORTB |= (1<<1); // HI
}
}
void matrix_init_user(void) {
}
void matrix_scan_user(void) {
}

View File

@ -0,0 +1,53 @@
/* Copyright 2018 Maarten Dekkers <maartenwut@gmail.com>
*
* 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 "kmini.h"
void matrix_init_kb(void) {
// put your keyboard start-up code here
// runs once when the firmware starts up
led_init_ports();
matrix_init_user();
}
void matrix_scan_kb(void) {
// put your looping keyboard code here
// runs every cycle (a lot)
matrix_scan_user();
}
bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
// put your per-action keyboard code here
// runs for every action, just before processing by the firmware
return process_record_user(keycode, record);
}
void led_init_ports(void) {
DDRB |= (1<<1); // OUT
DDRB |= (1<<2); // OUT
DDRB |= (1<<3); // OUT
}
/* LED pin configuration
* Caps Lock: Low B1
* Side1: Low B3
* Side2: Low B2
*/
void led_set_kb(uint8_t usb_led) {
led_set_user(usb_led);
}

View File

@ -0,0 +1,36 @@
/* Copyright 2018 Maarten Dekkers <maartenwut@gmail.com>
*
* 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/>.
*/
#ifndef KMINI_H
#define KMINI_H
#define ___ KC_NO
#include "quantum.h"
#define LAYOUT( \
K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, K0E, K0F, K0G, \
K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, K1E, K1F, K1G, \
K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, K2D, K2F, K2G, \
K30, K31, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, K3E, K3F, K3G, \
K40, K41, K42, K43, K44, K47, K4C, K4E, K4F, K4G \
) { \
{K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0D, K0E, K0F, K0G}, \
{K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, K1E, K1F, K1G}, \
{K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, K2D, ___, K2F, K2G}, \
{K30, K31, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, ___, K3E, K3F, K3G}, \
{K40, K41, K42, K43, K44, ___, ___, K47, ___, ___, ___, ___, K4C, ___, K4E, K4F, K4G}, \
}
#endif

View File

@ -0,0 +1,303 @@
/* Copyright 2018 Maarten Dekkers <maartenwut@gmail.com>
*
* 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 <stdint.h>
#include <stdbool.h>
#if defined(__AVR__)
#include <avr/io.h>
#endif
#include "wait.h"
#include "print.h"
#include "debug.h"
#include "util.h"
#include "matrix.h"
#include "timer.h"
/* Set 0 if debouncing isn't needed */
#ifndef DEBOUNCING_DELAY
# define DEBOUNCING_DELAY 5
#endif
#define COL_SHIFTER ((uint32_t)1)
static uint16_t debouncing_time;
static bool debouncing = false;
static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
/* matrix state(1:on, 0:off) */
static matrix_row_t matrix[MATRIX_ROWS];
static matrix_row_t matrix_debouncing[MATRIX_ROWS];
static void init_rows(void);
static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col);
static void unselect_cols(void);
static void select_col(uint8_t col);
inline
uint8_t matrix_rows(void) {
return MATRIX_ROWS;
}
inline
uint8_t matrix_cols(void) {
return MATRIX_COLS;
}
void matrix_init(void) {
unselect_cols();
init_rows();
// initialize matrix state: all keys off
for (uint8_t i=0; i < MATRIX_ROWS; i++) {
matrix[i] = 0;
matrix_debouncing[i] = 0;
}
matrix_init_quantum();
}
uint8_t matrix_scan(void)
{
// Set col, read rows
for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
bool matrix_changed = read_rows_on_col(matrix_debouncing, current_col);
if (matrix_changed) {
debouncing = true;
debouncing_time = timer_read();
}
}
if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) {
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
matrix[i] = matrix_debouncing[i];
}
debouncing = false;
}
matrix_scan_quantum();
return 1;
}
inline
bool matrix_is_on(uint8_t row, uint8_t col)
{
return (matrix[row] & ((matrix_row_t)1<col));
}
inline
matrix_row_t matrix_get_row(uint8_t row)
{
return matrix[row];
}
void matrix_print(void)
{
print("\nr/c 0123456789ABCDEFGHIJKLMNOPQRSTUV \n");
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
phex(row); print(": ");
print_bin_reverse32(matrix_get_row(row));
print("\n");
}
}
uint8_t matrix_key_count(void)
{
uint8_t count = 0;
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
count += bitpop32(matrix[i]);
}
return count;
}
static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col)
{
bool matrix_changed = false;
// Select col and wait for col selecton to stabilize
select_col(current_col);
wait_us(30);
// For each row...
for(uint8_t row_index = 0; row_index < MATRIX_ROWS; row_index++)
{
// Store last value of row prior to reading
matrix_row_t last_row_value = current_matrix[row_index];
// Check row pin state
// Use the otherwise unused row: 3, col: 0 for caps lock
if (row_index == 2 && current_col == 2) {
// Pin E2 uses active low
if ((_SFR_IO8(E2 >> 4) & _BV(E2 & 0xF)) == 0)
{
// Pin LO, set col bit
current_matrix[row_index] |= (COL_SHIFTER << current_col);
}
else
{
// Pin HI, clear col bit
current_matrix[row_index] &= ~(COL_SHIFTER << current_col);
}
}
else {
if ((_SFR_IO8(row_pins[row_index] >> 4) & _BV(row_pins[row_index] & 0xF)))
{
// Pin HI, set col bit
current_matrix[row_index] |= (COL_SHIFTER << current_col);
}
else
{
// Pin LO, clear col bit
current_matrix[row_index] &= ~(COL_SHIFTER << current_col);
}
}
// Determine if the matrix changed state
if ((last_row_value != current_matrix[row_index]) && !(matrix_changed))
{
matrix_changed = true;
}
}
// Unselect cols
unselect_cols();
return matrix_changed;
}
/* Row pin configuration
* row: 0 1 2 3 4
* pin: D0 D1 D2 D3 D5
*
* Caps lock uses its own pin E2
*/
static void init_rows(void) {
DDRD &= ~((1<<0)| (1<<1) | (1<<2) | (1<<3) | (1<<5)); // IN
PORTD &= ~((1<<0)| (1<<1) | (1<<2) | (1<<3) | (1<<5)); // LO
DDRE &= ~(1<<2); // IN
PORTE |= (1<<2); // HI
}
/* Columns 0 - 16
* col 0: B5
* col 1: B6
* These columns use a 74HC237D 3 to 8 bit demultiplexer.
* A B C GL1
* col / pin: PF0 PF1 PC7 PC6
* 2: 0 0 0 1
* 3: 1 0 0 1
* 4: 0 1 0 1
* 5: 1 1 0 1
* 6: 0 0 1 1
* 7: 1 0 1 1
* 8: 0 1 1 1
* 9: 1 1 1 1
* col 10: E6
* col 11: B0
* col 12: B7
* col 13: D4
* col 14: D6
* col 15: D7
* col 16: B4
*/
static void unselect_cols(void) {
DDRB |= (1<<5) | (1<<6) | (1<<0) | (1<<7) | (1<<4); // OUT
PORTB &= ~((1<<5) | (1<<6) | (1<<0) | (1<<7) | (1<<4)); // LO
DDRD |= (1<<4) | (1<<6) | (1<<7); // OUT
PORTD &= ~((1<<4) | (1<<6) | (1<<7)); // LO
DDRE |= (1<<6); // OUT
PORTE &= ~((1<<6)); // LO
DDRF |= (1<<0) | (1<<1); // OUT
PORTF &= ~((1<<0) | (1<<1)); // LO
DDRC |= (1<<7) | (1<<6); // OUT
PORTC &= ~((1<<7) | (1<<6)); // LO
}
static void select_col(uint8_t col)
{
switch (col) {
case 0:
PORTB |= (1<<5); // HI
break;
case 1:
PORTB |= (1<<6); // HI
break;
case 2:
PORTC |= (1<<6); // HI
break;
case 3:
PORTC |= (1<<6); // HI
PORTF |= (1<<0); // HI
break;
case 4:
PORTC |= (1<<6); // HI
PORTF |= (1<<1); // HI
break;
case 5:
PORTC |= (1<<6); // HI
PORTF |= (1<<0); // HI
PORTF |= (1<<1); // HI
break;
case 6:
PORTC |= (1<<6); // HI
PORTC |= (1<<7); // HI
break;
case 7:
PORTC |= (1<<6); // HI
PORTF |= (1<<0); // HI
PORTC |= (1<<7); // HI
break;
case 8:
PORTC |= (1<<6); // HI
PORTF |= (1<<1); // HI
PORTC |= (1<<7); // HI
break;
case 9:
PORTC |= (1<<6); // HI
PORTF |= (1<<0); // HI
PORTF |= (1<<1); // HI
PORTC |= (1<<7); // HI
break;
case 10:
PORTE |= (1<<6); // HI
break;
case 11:
PORTB |= (1<<0); // HI
break;
case 12:
PORTB |= (1<<7); // HI
break;
case 13:
PORTD |= (1<<4); // HI
break;
case 14:
PORTD |= (1<<6); // HI
break;
case 15:
PORTD |= (1<<7); // HI
break;
case 16:
PORTB |= (1<<4); // HI
break;
}
}

View File

@ -0,0 +1,13 @@
Kmini keyboard firmware
======================
The Revo Kmini is a 65% keyboard with an additional two columns on the left. It is programmed with the 'KMAC key map', which only works on Windows and according to a [user](https://www.keebtalk.com/t/programming-revo-kmini/2107/7) it cannot map media controls or change the capslock key.
## Hardware
Columns 0, 1 and 10-16 and rows 0-4 are wired directly to the ATmega32u4, and columns 2-9 are wired to the [74HC237D demultiplexer](https://www.mouser.de/datasheet/2/916/74HC237-1319445.pdf). Capslock is on E2 and also triggers a reset if held when plugging the cable in. There are three possible places for leds, which are the capslock key and the two keys above the right arrow key. All three of them are individually controllable. The ATmega32u4 runs on an external crystal on 8mhz, so you'll have to change the bitclock on the ISP programmer if you're unable to read or write the chip.
## How to build
Please read the [documentation](https://docs.qmk.fm).
## How to flash
Hold the capslock key while plugging in the USB and flash the .hex file using QMK Toolbox or Atmel FLIP.

View File

@ -0,0 +1,71 @@
# Project specific files
SRC = matrix.c
# MCU name
MCU = atmega32u4
# Processor frequency.
# This will define a symbol, F_CPU, in all source code files equal to the
# processor frequency in Hz. You can then use this symbol in your source code to
# calculate timings. Do NOT tack on a 'UL' at the end, this will be done
# automatically to create a 32-bit value in your source code.
#
# This will be an integer division of F_USB below, as it is sourced by
# F_USB after it has run through any CPU prescalers. Note that this value
# does not *change* the processor frequency - it should merely be updated to
# reflect the processor speed set externally so that the code can use accurate
# software delays.
F_CPU = 8000000
#
# LUFA specific
#
# Target architecture (see library "Board Types" documentation).
ARCH = AVR8
# Input clock frequency.
# This will define a symbol, F_USB, in all source code files equal to the
# input clock frequency (before any prescaling is performed) in Hz. This value may
# differ from F_CPU if prescaling is used on the latter, and is required as the
# raw input clock is fed directly to the PLL sections of the AVR for high speed
# clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL'
# at the end, this will be done automatically to create a 32-bit value in your
# source code.
#
# If no clock division is performed on the input clock inside the AVR (via the
# CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU.
F_USB = $(F_CPU)
# Interrupt driven control endpoint task(+60)
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
# Boot Section Size in *bytes*
# Teensy halfKay 512
# Teensy++ halfKay 1024
# Atmel DFU loader 4096
# LUFA bootloader 4096
# USBaspLoader 2048
OPT_DEFS += -DBOOTLOADER_SIZE=4096
# Build Options
# change yes to no to disable
#
BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000)
MOUSEKEY_ENABLE = yes # Mouse keys(+4700)
EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
CONSOLE_ENABLE = no # Console for debug(+400)
COMMAND_ENABLE = yes # Commands for debug and configuration
CUSTOM_MATRIX = yes # Custom matrix file
# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
NKRO_ENABLE = yes # USB Nkey Rollover
BACKLIGHT_ENABLE = yes # Enable keyboard backlight functionality
MIDI_ENABLE = no # MIDI support (+2400 to 4200, depending on config)
UNICODE_ENABLE = no # Unicode
BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID
AUDIO_ENABLE = no # Audio output on port C6
FAUXCLICKY_ENABLE = no # Use buzzer to emulate clicky switches