NEK Type A (#5175)

* project creation and config.h import

* fix name

* cleanup

* layout for left

* working left with feather pins

* full keymap

* ?

* let's do this

* non working twimaster version

* it fucking works!

* bluetooth!

* cleanup

* use auto output for ADAFRUIT_BLE

* remove auto from custom matrix

* better ble auto

* fix f1

* revert

* fix ble

* update readme

* Update readme.md

* Update readme.md
This commit is contained in:
Mike Roberts 2019-05-11 21:12:06 -04:00 committed by MechMerlin
parent d53cbd2dc6
commit f542c0589b
12 changed files with 870 additions and 0 deletions

View file

@ -0,0 +1,55 @@
/*
Copyright 2018 Mike Roberts
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 "config_common.h"
/* USB Device descriptor parameter */
#define VENDOR_ID 0xFEED
#define PRODUCT_ID 0x0000
#define DEVICE_VER 0x0001
#define MANUFACTURER miker
#define PRODUCT nek_type_a
#define DESCRIPTION NEK Type A
/* key matrix size */
#define MATRIX_ROWS 6
#define MATRIX_COLS 18
/* left columns are all onboard, right columns all on expander */
#define COL_EXPANDED { false, false, false, false, false, false, false, true, true, true, true, true, true, true, true, true, true, true}
#define MATRIX_COL_PINS { C6, D7, B5, B6, B7, D6, D3, GPA0, GPA1, GPA2, GPA3, GPA4, GPA5, GPA6, GPA7, GPB0, GPB1, GPB2 }
#define MATRIX_ROW_PINS { F7, F6, F5, F4, F1, F0 }
#define DIODE_DIRECTION ROW2COL
/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
#define DEBOUNCING_DELAY 5
/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
#define LOCKING_SUPPORT_ENABLE
/* Locking resynchronize hack */
#define LOCKING_RESYNC_ENABLE
/* key combination for magic key command */
#define IS_COMMAND() ( \
keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \
)

View file

View file

@ -0,0 +1,19 @@
/* Copyright 2018 Mike Roberts
*
* 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
// place overrides here

View file

@ -0,0 +1,39 @@
/* Copyright 2018 Mike Roberts
*
* 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
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = LAYOUT(
KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC__MUTE, KC__VOLDOWN, KC__VOLUP, \
KC_GRAVE, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINUS, KC_EQUAL, KC_BSPACE, KC_INSERT, KC_HOME, KC_PGUP, \
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRACKET, KC_RBRACKET, KC_BSLASH, KC_DELETE, KC_END, KC_PGDOWN, \
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCOLON, KC_QUOTE, KC_ENTER, \
KC_LSHIFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMMA, KC_DOT, KC_SLASH, KC_RSHIFT, KC_UP, \
KC_LCTRL, KC_LALT, KC_LCMD, KC_SPC, KC_SPC, KC_RCMD, KC_RALT, KC_RCTRL, KC_APP, KC_LEFT, KC_DOWN, KC_RIGHT \
),
};
void matrix_init_user(void) {
}
void matrix_scan_user(void) {
}
void led_set_user(uint8_t usb_led) {
}

View file

@ -0,0 +1,3 @@
![NEK Type A Layout](https://i.imgur.com/ElEVvze.png)
# Default NEK Type A Keymap

View file

@ -0,0 +1,412 @@
/*
Copyright 2012-2018 Jun Wako, Jack Humbert, Mike Roberts
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/>.
*/
/*
* This matrix.c has been hacked up to support some columns being on an ex pander in ROW2COL mode.
* The columns are only ever selected and unselected, never read. Unselecting a single column via the expander is not
* implemented because updating one column costs the same as updating all the columns in a bank. Currently both banks
* are unselected but two i2c transactions could be removed if we only unselect the the proper half.
*/
#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"
#include "mcp23017.h"
#include "outputselect.h"
/* Set 0 if debouncing isn't needed */
#ifndef DEBOUNCING_DELAY
# define DEBOUNCING_DELAY 5
#endif
#if (DEBOUNCING_DELAY > 0)
static uint16_t debouncing_time;
static bool debouncing = false;
#endif
#if (MATRIX_COLS <= 8)
# define print_matrix_header() print("\nr/c 01234567\n")
# define print_matrix_row(row) print_bin_reverse8(matrix_get_row(row))
# define matrix_bitpop(i) bitpop(matrix[i])
# define ROW_SHIFTER ((uint8_t)1)
#elif (MATRIX_COLS <= 16)
# define print_matrix_header() print("\nr/c 0123456789ABCDEF\n")
# define print_matrix_row(row) print_bin_reverse16(matrix_get_row(row))
# define matrix_bitpop(i) bitpop16(matrix[i])
# define ROW_SHIFTER ((uint16_t)1)
#elif (MATRIX_COLS <= 32)
# define print_matrix_header() print("\nr/c 0123456789ABCDEF0123456789ABCDEF\n")
# define print_matrix_row(row) print_bin_reverse32(matrix_get_row(row))
# define matrix_bitpop(i) bitpop32(matrix[i])
# define ROW_SHIFTER ((uint32_t)1)
#endif
#ifdef MATRIX_MASKED
extern const matrix_row_t matrix_mask[];
#endif
#if (DIODE_DIRECTION == ROW2COL) || (DIODE_DIRECTION == COL2ROW)
static const uint8_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
static const uint8_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
static const bool col_expanded[MATRIX_COLS] = COL_EXPANDED;
#endif
/* matrix state(1:on, 0:off) */
static matrix_row_t matrix[MATRIX_ROWS];
static matrix_row_t matrix_debouncing[MATRIX_ROWS];
#if (DIODE_DIRECTION == COL2ROW)
static void init_cols(void);
static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row);
static void unselect_rows(void);
static void select_row(uint8_t row);
static void unselect_row(uint8_t row);
#elif (DIODE_DIRECTION == ROW2COL)
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 unselect_col(uint8_t col);
static void select_col(uint8_t col);
#endif
__attribute__ ((weak))
void matrix_init_quantum(void) {
expander_init();
matrix_init_kb();
}
__attribute__ ((weak))
void matrix_scan_quantum(void) {
matrix_scan_kb();
}
__attribute__ ((weak))
void matrix_init_kb(void) {
matrix_init_user();
}
__attribute__ ((weak))
void matrix_scan_kb(void) {
matrix_scan_user();
}
__attribute__ ((weak))
void matrix_init_user(void) {
}
__attribute__ ((weak))
void matrix_scan_user(void) {
}
inline
uint8_t matrix_rows(void) {
return MATRIX_ROWS;
}
inline
uint8_t matrix_cols(void) {
return MATRIX_COLS;
}
void matrix_init(void) {
// initialize row and col
#if (DIODE_DIRECTION == COL2ROW)
unselect_rows();
init_cols();
#elif (DIODE_DIRECTION == ROW2COL)
unselect_cols();
init_rows();
#endif
// 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();
set_output(OUTPUT_AUTO);
}
uint8_t matrix_scan(void)
{
#if (DIODE_DIRECTION == COL2ROW)
// Set row, read cols
for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
# if (DEBOUNCING_DELAY > 0)
bool matrix_changed = read_cols_on_row(matrix_debouncing, current_row);
if (matrix_changed) {
debouncing = true;
debouncing_time = timer_read();
}
# else
read_cols_on_row(matrix, current_row);
# endif
}
#elif (DIODE_DIRECTION == ROW2COL)
// Set col, read rows
for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
# if (DEBOUNCING_DELAY > 0)
bool matrix_changed = read_rows_on_col(matrix_debouncing, current_col);
if (matrix_changed) {
debouncing = true;
debouncing_time = timer_read();
}
# else
read_rows_on_col(matrix, current_col);
# endif
}
#endif
# if (DEBOUNCING_DELAY > 0)
if (debouncing && (timer_elapsed(debouncing_time) > DEBOUNCING_DELAY)) {
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
matrix[i] = matrix_debouncing[i];
}
debouncing = false;
}
# endif
matrix_scan_quantum();
return 1;
}
bool matrix_is_modified(void)
{
#if (DEBOUNCING_DELAY > 0)
if (debouncing) return false;
#endif
return true;
}
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)
{
// Matrix mask lets you disable switches in the returned matrix data. For example, if you have a
// switch blocker installed and the switch is always pressed.
#ifdef MATRIX_MASKED
return matrix[row] & matrix_mask[row];
#else
return matrix[row];
#endif
}
void matrix_print(void)
{
print_matrix_header();
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
phex(row); print(": ");
print_matrix_row(row);
print("\n");
}
}
uint8_t matrix_key_count(void)
{
uint8_t count = 0;
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
count += matrix_bitpop(i);
}
return count;
}
#if (DIODE_DIRECTION == COL2ROW)
static void init_cols(void)
{
for(uint8_t x = 0; x < MATRIX_COLS; x++) {
uint8_t pin = col_pins[x];
_SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
_SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
}
}
static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row)
{
// Store last value of row prior to reading
matrix_row_t last_row_value = current_matrix[current_row];
// Clear data in matrix row
current_matrix[current_row] = 0;
// Select row and wait for row selecton to stabilize
select_row(current_row);
wait_us(30);
// For each col...
for(uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
// Select the col pin to read (active low)
uint8_t pin = col_pins[col_index];
uint8_t pin_state = (_SFR_IO8(pin >> 4) & _BV(pin & 0xF));
// Populate the matrix row with the state of the col pin
current_matrix[current_row] |= pin_state ? 0 : (ROW_SHIFTER << col_index);
}
// Unselect row
unselect_row(current_row);
return (last_row_value != current_matrix[current_row]);
}
static void select_row(uint8_t row)
{
uint8_t pin = row_pins[row];
_SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT
_SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
}
static void unselect_row(uint8_t row)
{
uint8_t pin = row_pins[row];
_SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
_SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
}
static void unselect_rows(void)
{
for(uint8_t x = 0; x < MATRIX_ROWS; x++) {
uint8_t pin = row_pins[x];
_SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
_SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
}
}
#elif (DIODE_DIRECTION == ROW2COL)
static void init_rows(void)
{
for(uint8_t x = 0; x < MATRIX_ROWS; x++) {
uint8_t pin = row_pins[x];
_SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
_SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
}
}
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
if ((_SFR_IO8(row_pins[row_index] >> 4) & _BV(row_pins[row_index] & 0xF)) == 0)
{
// Pin LO, set col bit
current_matrix[row_index] |= (ROW_SHIFTER << current_col);
}
else
{
// Pin HI, clear col bit
current_matrix[row_index] &= ~(ROW_SHIFTER << current_col);
}
// Determine if the matrix changed state
if ((last_row_value != current_matrix[row_index]) && !(matrix_changed))
{
matrix_changed = true;
}
}
// Unselect col
unselect_col(current_col);
return matrix_changed;
}
static void select_col(uint8_t col)
{
uint8_t pin = col_pins[col];
if (col_expanded[col])
{
expander_select(pin);
}
else
{
_SFR_IO8((pin >> 4) + 1) |= _BV(pin & 0xF); // OUT
_SFR_IO8((pin >> 4) + 2) &= ~_BV(pin & 0xF); // LOW
}
}
static void unselect_col(uint8_t col)
{
uint8_t pin = col_pins[col];
if (col_expanded[col])
{
expander_unselect_all();
}
else
{
_SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
_SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
}
}
static void unselect_cols(void)
{
expander_unselect_all();
for(uint8_t col = 0; col < MATRIX_COLS; col++) {
uint8_t pin = col_pins[col];
if (!col_expanded[col])
{
_SFR_IO8((pin >> 4) + 1) &= ~_BV(pin & 0xF); // IN
_SFR_IO8((pin >> 4) + 2) |= _BV(pin & 0xF); // HI
}
}
}
#endif

View file

@ -0,0 +1,107 @@
/* Copyright 2018 Mike Roberts
*
* 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 <stdbool.h>
#include "action.h"
#include "lib/lufa/LUFA/Drivers/Peripheral/TWI.h"
#include "lib/lufa/LUFA/Drivers/Peripheral/AVR8/TWI_AVR8.c"
#include "mcp23017.h"
#include "debug.h"
#include "wait.h"
uint8_t bit_for_pin(uint8_t pin);
uint8_t expander_write(uint8_t reg, uint8_t data);
uint8_t expander_read(uint8_t reg, uint8_t *data);
void expander_config(void);
static const char *twi_err_str(uint8_t res) {
switch (res) {
case TWI_ERROR_NoError:
return "OK";
case TWI_ERROR_BusFault:
return "BUSFAULT";
case TWI_ERROR_BusCaptureTimeout:
return "BUSTIMEOUT";
case TWI_ERROR_SlaveResponseTimeout:
return "SLAVETIMEOUT";
case TWI_ERROR_SlaveNotReady:
return "SLAVENOTREADY";
case TWI_ERROR_SlaveNAK:
return "SLAVENAK";
default:
return "UNKNOWN";
}
}
void expander_init(void) {
TWI_Init(TWI_BIT_PRESCALE_1, TWI_BITLENGTH_FROM_FREQ(1, 400000));
}
// set IN and HI
void expander_unselect_all() {
expander_write(EXPANDER_REG_IODIRA, 0xff);
expander_write(EXPANDER_REG_IODIRB, 0xff);
expander_write(EXPANDER_REG_OLATA, 0xff);
expander_write(EXPANDER_REG_OLATB, 0xff);
wait_us(EXPANDER_PAUSE);
}
// set OUT and LOW
void expander_select(uint8_t pin) {
const uint8_t mask = 0xff & ~(1 << bit_for_pin(pin));
if (pin < 8) {
expander_write(EXPANDER_REG_IODIRA, mask);
expander_write(EXPANDER_REG_OLATA, mask);
} else {
expander_write(EXPANDER_REG_IODIRB, mask);
expander_write(EXPANDER_REG_OLATB, mask);
}
wait_us(EXPANDER_PAUSE);
}
void expander_config() {
// set everything to input
expander_write(EXPANDER_REG_IODIRA, 0xff);
expander_write(EXPANDER_REG_IODIRB, 0xff);
// turn on pull-ups
expander_write(EXPANDER_REG_GPPUA, 0xff);
expander_write(EXPANDER_REG_GPPUB, 0xff);
// disable interrupts
expander_write(EXPANDER_REG_GPINTENA, 0x0);
expander_write(EXPANDER_REG_GPINTENB, 0x0);
// polarity
expander_write(EXPANDER_REG_IPOLA, 0x0);
expander_write(EXPANDER_REG_IPOLB, 0x0);
}
uint8_t bit_for_pin(uint8_t pin) {
return pin % 8;
}
uint8_t expander_write(uint8_t reg, unsigned char val) {
uint8_t addr = reg;
uint8_t result = TWI_WritePacket(EXPANDER_ADDR << 1, I2C_TIMEOUT, &addr, sizeof(addr), &val, sizeof(val));
if (result) {
xprintf("mcp: set_register %d = %d failed: %s\n", reg, val, twi_err_str(result));
}
return result == 0;
}

View file

@ -0,0 +1,71 @@
/* Copyright 2018 Mike Roberts
*
* 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 MAP23017_H
#define MAP23017_H
#define EXPANDER_ADDR 0x27
#define I2C_TIMEOUT 200 // milliseconds
#define EXPANDER_PAUSE 0 // microseconds
enum EXPANDER_REGISTERS {
EXPANDER_REG_IODIRA = 0x00,
EXPANDER_REG_IODIRB = 0x01,
EXPANDER_REG_IPOLA = 0x02,
EXPANDER_REG_IPOLB = 0x03,
EXPANDER_REG_GPINTENA = 0x04,
EXPANDER_REG_GPINTENB = 0x05,
EXPANDER_REG_DEFVALA = 0x06,
EXPANDER_REG_DEFVALB = 0x07,
EXPANDER_REG_INTCONA = 0x08,
EXPANDER_REG_INTCONB = 0x09,
EXPANDER_REG_IOCONA = 0x0A,
EXPANDER_REG_IOCONB = 0x0B,
EXPANDER_REG_GPPUA = 0x0C,
EXPANDER_REG_GPPUB = 0x0D,
EXPANDER_REG_INTFA = 0x0E,
EXPANDER_REG_INTFB = 0x0F,
EXPANDER_REG_INTCAPA = 0x10,
EXPANDER_REG_INTCAPB = 0x11,
EXPANDER_REG_GPIOA = 0x12,
EXPANDER_REG_GPIOB = 0x13,
EXPANDER_REG_OLATA = 0x14,
EXPANDER_REG_OLATB = 0x15
};
#define GPA0 0x0
#define GPA1 0x1
#define GPA2 0x2
#define GPA3 0x3
#define GPA4 0x4
#define GPA5 0x5
#define GPA6 0x6
#define GPA7 0x7
#define GPB0 0x8
#define GPB1 0x9
#define GPB2 0xA
#define GPB3 0xB
#define GPB4 0xC
#define GPB5 0xD
#define GPB6 0xE
#define GPB7 0xF
void expander_init(void);
void expander_select(uint8_t pin);
void expander_unselect(uint8_t pin);
void expander_unselect_all(void);
#endif

View file

@ -0,0 +1,43 @@
/* Copyright 2018 Mike Roberts
*
* 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 "nek_type_a.h"
void matrix_init_kb(void) {
// put your keyboard start-up code here
// runs once when the firmware starts up
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_set_kb(uint8_t usb_led) {
// put your keyboard LED indicator (ex: Caps Lock LED) toggling code here
led_set_user(usb_led);
}

View file

@ -0,0 +1,58 @@
/* Copyright 2018 REPLACE_WITH_YOUR_NAME
*
* 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 NEK_TYPE_A_H
#define NEK_TYPE_A_H
#include "quantum.h"
#include <stdint.h>
#include <stdbool.h>
#include <util/delay.h>
#define I2C_ADDR 0b0100000
#define I2C_ADDR_WRITE ( (I2C_ADDR<<1) | I2C_WRITE )
#define I2C_ADDR_READ ( (I2C_ADDR<<1) | I2C_READ )
#define IODIRA 0x00 // i/o direction register
#define IODIRB 0x01
#define GPPUA 0x0C // GPIO pull-up resistor register
#define GPPUB 0x0D
#define GPIOA 0x12 // general purpose i/o port register (write modifies OLAT)
#define GPIOB 0x13
#define OLATA 0x14 // output latch register
#define OLATB 0x15
extern uint8_t expander_status;
extern uint8_t expander_input_pin_mask;
extern bool i2c_initialized;
void init_expander(void);
#define LAYOUT( \
L12, L14, L15, L16, L17, R11, R12, R13, R14, R15, R16, R17, R18, R19, R1A, R1B, \
L21, L22, L23, L24, L25, L26, L27, R21, R22, R23, R24, R25, R26, R28, R29, R2A, R2B, \
L31, L32, L33, L34, L35, L36, R31, R32, R33, R34, R35, R36, R37, R38, R39, R3A, R3B, \
L41, L42, L43, L44, L45, L46, R41, R42, R43, R44, R45, R46, R48, \
L51, L52, L53, L54, L55, L56, R51, R52, R53, R54, R55, R58, R5A, \
L61, L62, L63, L65, R61, R63, R65, R66, R68, R69, R6A, R6B \
) \
{ \
{ KC_NO, L12, KC_NO, L14, L15, L16, L17, R11, R12, R13, R14, R15, R16, R17, R18, R19, R1A, R1B }, \
{ L21, L22, L23, L24, L25, L26, L27, R21, R22, R23, R24, R25, R26, KC_NO, R28, R29, R2A, R2B }, \
{ L31, L32, L33, L34, L35, L36, KC_NO, R31, R32, R33, R34, R35, R36, R37, R38, R39, R3A, R3B }, \
{ L41, L42, L43, L44, L45, L46, KC_NO, R41, R42, R43, R44, R45, R46, KC_NO, R48, KC_NO, KC_NO, KC_NO }, \
{ L51, L52, L53, L54, L55, L56, KC_NO, R51, R52, R53, R54, R55, KC_NO, KC_NO, R58, KC_NO, R5A, KC_NO }, \
{ L61, L62, L63, KC_NO, L65, KC_NO, KC_NO, R61, KC_NO, R63, KC_NO, R65, R66, KC_NO, R68, R69, R6A, R6B }, \
}
#endif

View file

@ -0,0 +1,30 @@
# nek_type_a
![NEK Type A Keyboard](https://i.imgur.com/XFnjlQ9.jpg)
Natural Ergonomic Keyboard, Type A
Keyboard Maintainer: [Mike Roberts](https://github.com/ecopoesis)
Hardware Supported: Custom PCBs from https://github.com/ecopoesis/nek-type-a
Hardware Availability: https://github.com/ecopoesis/nek-type-a
## Design
This is a column-driven split keyboard using three custom PCBs connected with ribbon cables. The left and right PCBs are
passive: they only have the diodes and switches needed to make the matrix. The center PCB has an Adafruit Feather 32u4 and
MCP23017 expander.
The left matrix has its rows and columns directly connected to the Feather. The right matrix has its rows connect to the
Feather (using the same pins as the left matrix) and its columns connected to the expander. The expander uses the LUFA
hardware TWI driver.
Bluetooth is enabled.
## Building
Make and install this keyboard (after setting up your build environment):
```
make nek_type_a:default:avrdude
```
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).

View file

@ -0,0 +1,33 @@
SRC = matrix.c mcp23017.c
MCU = atmega32u4
F_CPU = 8000000
ARCH = AVR8
F_USB = $(F_CPU)
# Interrupt driven control endpoint task(+60)
OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT
BOOTLOADER = caterina
BOOTMAGIC_ENABLE = no # Virtual DIP switch configuration(+1000)
MOUSEKEY_ENABLE = no # Mouse keys(+4700)
EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
CONSOLE_ENABLE = yes # Console for debug(+400)
COMMAND_ENABLE = yes # Commands for debug and configuration
# 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 = no # USB Nkey Rollover
BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality on B7 by default
RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
MIDI_ENABLE = no # MIDI support (+2400 to 4200, depending on config)
UNICODE_ENABLE = no # Unicode
BLUETOOTH_ENABLE = yes # 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
HD44780_ENABLE = no # Enable support for HD44780 based LCDs (+400)
CUSTOM_MATRIX = yes
DEBUG_ENABLE = yes
BLUETOOTH = AdafruitBLE