~ruther/qmk_firmware

2f5bb2506a6c3079ef58f2576ff48e42f0876202 — Balz Guenat 7 years ago 3e2fd64
QMK port of Hasu's fc980c alt controller (#2043)

* fc980c port, builds but yet untested.

* add my own keymap
A keyboards/fc980c/config.h => keyboards/fc980c/config.h +84 -0
@@ 0,0 1,84 @@
/*
Copyright 2017 Balz Guenat

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      0x980C
#define DEVICE_VER      0x0100
#define MANUFACTURER    QMK
#define PRODUCT         Leopold FC980C with QMK
#define DESCRIPTION     Leopold FC980C with Hasu alternative controller using QMK

/* key matrix size */
#define MATRIX_ROWS 8
#define MATRIX_COLS 16

// #define MATRIX_ROW_PINS { B0, B2, B4, B5, B6 }
// #define MATRIX_COL_PINS { F5, B1, F0, F1, F4, B3, D7, D6, D4, D5, D3, D2, D1, D0 }
// #define UNUSED_PINS

#define DIODE_DIRECTION CUSTOM_MATRIX

/* define if matrix has ghost */
//#define MATRIX_HAS_GHOST

/* number of backlight levels */
// #define BACKLIGHT_LEVELS  1

/* mapping backlight LEDs to correct Pin */
// #define BACKLIGHT_PIN B7

/* Set 0 if debouncing isn't needed */
#define DEBOUNCING_DELAY  0
#define TAPPING_TERM      175

/* 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 command */
#define IS_COMMAND() ( \
    keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \
)



/*
 * Feature disable options
 *  These options are also useful to firmware size reduction.
 */

/* disable debug print */
//#define NO_DEBUG

/* disable print */
//#define NO_PRINT

/* disable action features */
//#define NO_ACTION_LAYER
//#define NO_ACTION_TAPPING
//#define NO_ACTION_ONESHOT
//#define NO_ACTION_MACRO
//#define NO_ACTION_FUNCTION

#endif

A keyboards/fc980c/fc980c.c => keyboards/fc980c/fc980c.c +58 -0
@@ 0,0 1,58 @@
/*
Copyright 2017 Balz Guenat

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 "fc980c.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) {
    if (usb_led & (1<<USB_LED_NUM_LOCK)) {
        PORTB |=  (1<<4);
    } else {
        PORTB &= ~(1<<4);
    }
    if (usb_led & (1<<USB_LED_CAPS_LOCK)) {
        PORTB |=  (1<<5);
    } else {
        PORTB &= ~(1<<5);
    }
    if (usb_led & (1<<USB_LED_SCROLL_LOCK)) {
        PORTB |=  (1<<6);
    } else {
        PORTB &= ~(1<<6);
    }

	led_set_user(usb_led);
}

A keyboards/fc980c/fc980c.h => keyboards/fc980c/fc980c.h +76 -0
@@ 0,0 1,76 @@
/*
Copyright 2017 Balz Guenat

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 FC980C_H
#define FC980C_H

#include "quantum.h"
// #include "quantum_keycodes.h"

/*
----------------------------------------------------------------------------------------------------------------------
| K0D |     | K2D | K5D | K3D | K6D |  | K7D | K7F | K7E | K7C |  | K72 | K71 | K70 | K73 |  | K74 | K76 | K77 | K75 |
----------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------
| K0A | K69 | K59 | K58 | K5B | K6F | K5F | K5E | K6C | K5C | K52 | K51 | K50 |    K55    |  | K54 | K56 | K57 | K65 |
----------------------------------------------------------------------------------------------------------------------
|  K6A   | K39 | K68 | K6B | K3B | K3F | K6E | K3E | K3C | K62 | K61 | K60 | K33 |  K53   |  | K64 | K66 | K67 |     |
---------------------------------------------------------------------------------------------------------------| K25 |
|   K3A   | K29 | K38 | K28 | K2B | K2F | K2E | K2C | K1C | K32 | K31 | K20 |     K63     |  | K24 | K26 | K27 |     |
----------------------------------------------------------------------------------------------------------------------
|     K2A    | K18 | K08 | K1B | K0B | K1F | K1E | K0E | K22 | K11 | K21 |    K30    || K34 || K14 | K16 | K17 |     |
---------------------------------------------------------------------------------------------------------------| K15 |
| K1A  | K09 | K19  |                   K0F                | K02  | K01 | K10  || K00 | K04 | K06 || K07 | K05 |     |
----------------------------------------------------------------------------------------------------------------------
*/

#define KEYMAP(                                                                           \
    K0D,    K2D,K5D,K3D,K6D,K7D,K7F,K7E,K7C,K72,K71,K70,K73,             K74,K76,K77,K75, \
    K0A,K69,K59,K58,K5B,K6F,K5F,K5E,K6C,K5C,K52,K51,K50,K55,             K54,K56,K57,K65, \
    K6A,K39,K68,K6B,K3B,K3F,K6E,K3E,K3C,K62,K61,K60,K33,K53,             K64,K66,K67,K25, \
    K3A,K29,K38,K28,K2B,K2F,K2E,K2C,K1C,K32,K31,K20,    K63,             K24,K26,K27,     \
    K2A,    K18,K08,K1B,K0B,K1F,K1E,K0E,K22,K11,K21,    K30,     K34,    K14,K16,K17,K15, \
    K1A,K09,K19,            K0F,                K02,K01,K10, K00,K04,K06,    K07,K05      \
) {                                                                                       \
    { K00,  K01,  K02,  KC_NO,K04,  K05,  K06,  K07   ,  \
      K08,  K09,  K0A,  K0B,  KC_NO,K0D,  K0E,  K0F   }, \
    { K10,  K11,  KC_NO,KC_NO,K14,  K15,  K16,  K17   ,  \
      K18,  K19,  K1A,  K1B,  K1C,  KC_NO,K1E,  K1F   }, \
    { K20,  K21,  K22,  KC_NO,K24,  K25,  K26,  K27   ,  \
      K28,  K29,  K2A,  K2B,  K2C,  K2D,  K2E,  K2F   }, \
    { K30,  K31,  K32,  K33,  K34,  KC_NO,KC_NO,KC_NO ,  \
      K38,  K39,  K3A,  K3B,  K3C,  K3D,  K3E,  K3F   }, \
    { KC_NO,KC_NO,KC_NO,KC_NO,KC_NO,KC_NO,KC_NO,KC_NO ,  \
      KC_NO,KC_NO,KC_NO,KC_NO,KC_NO,KC_NO,KC_NO,KC_NO }, \
    { K50,  K51,  K52,  K53,  K54,  K55,  K56,  K57   ,  \
      K58,  K59,  KC_NO,K5B,  K5C,  K5D,  K5E,  K5F   }, \
    { K60,  K61,  K62,  K63,  K64,  K65,  K66,  K67   ,  \
      K68,  K69,  K6A,  K6B,  K6C,  K6D,  K6E,  K6F   }, \
    { K70,  K71,  K72,  K73,  K74,  K75,  K76,  K77   ,  \
      KC_NO,KC_NO,KC_NO,KC_NO,K7C,  K7D,  K7E,  K7F   }  \
}
/*
KEYMAP(
    _______,        _______,_______,_______,_______,_______,_______,_______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,
    _______,_______,_______,_______,_______,_______,_______,_______,_______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,
    _______,_______,_______,_______,_______,_______,_______,_______,_______,_______,_______,_______,_______,_______,                         _______,_______,_______,_______,
    _______,_______,_______,_______,_______,_______,_______,_______,_______,_______,_______,_______,        _______,                         _______,_______,_______,    
    _______,        _______,_______,_______,_______,_______,_______,_______,_______,_______,_______,        _______,         _______,        _______,_______,_______,_______,
    _______,_______,_______,                           _______,                             _______,_______,_______, _______,_______,_______,        _______,_______     
)
*/

#endif

A keyboards/fc980c/keymaps/coloneljesus/README.md => keyboards/fc980c/keymaps/coloneljesus/README.md +1 -0
@@ 0,0 1,1 @@
# My FC980C keymap

A keyboards/fc980c/keymaps/coloneljesus/config.h => keyboards/fc980c/keymaps/coloneljesus/config.h +24 -0
@@ 0,0 1,24 @@
/* Copyright 2017 Balz Guenat
 *
 * 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_USER_H
#define CONFIG_USER_H

#include "config_common.h"

// place overrides here

#endif

A keyboards/fc980c/keymaps/coloneljesus/keymap.c => keyboards/fc980c/keymaps/coloneljesus/keymap.c +39 -0
@@ 0,0 1,39 @@
/*
Copyright 2017 Balz Guenat

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 "fc980c.h"

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
  [0] = KEYMAP(
    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_DEL, KC_INS, KC_PGUP,KC_PGDN,
    KC_GRV, 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_NLCK,KC_PSLS,KC_PAST,KC_PMNS,
    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_P7,  KC_P8,  KC_P9,  KC_PPLS,
    MO(1) , 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_P4,  KC_P5,  KC_P6,
    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_P1,  KC_P2,  KC_P3,  KC_PENT,
    KC_LCTL,KC_LGUI,KC_LALT,                     KC_SPC,                   KC_RALT,KC_RCTL,MO(1),   KC_LEFT,KC_DOWN,KC_RGHT,        KC_P0,  KC_PDOT
    ),
  [1] = KEYMAP(
    _______,        _______,_______,_______,_______,_______,_______,      _______,      _______,_______,_______,_______,_______,                        _______,_______,KC_HOME,KC_END,
    _______,_______,_______,_______,_______,_______,_______,_______,      _______,      _______,_______,_______,_______,_______,                        _______,_______,_______,_______,
    KC_CAPS,KC_MPRV,KC_VOLU,KC_MNXT,KC_PGUP,KC_INS,KC_HOME, LCTL(KC_LEFT),LCTL(KC_RGHT),KC_END, KC_PSCR,KC_SLCK,KC_PAUS,_______,                        _______,_______,_______,_______,
    _______,KC_MUTE,KC_VOLD,KC_MPLY,KC_PGDN,KC_DEL,KC_LEFT, KC_DOWN,      KC_UP,        KC_RGHT,_______,_______,        _______,                        _______,_______,_______,
    _______,        _______,_______,_______,_______,_______,LCTL(KC_BSPC),LCTL(KC_DEL), _______,_______,_______,        _______,         KC_PGUP,       _______,_______,_______,_______,
    _______,_______,_______,                           _______,                                         _______,KC_APP, _______, KC_HOME,KC_PGDN,KC_END,        _______,_______     
    ),
};

const uint16_t PROGMEM fn_actions[] = {
};

A keyboards/fc980c/keymaps/default/README.md => keyboards/fc980c/keymaps/default/README.md +5 -0
@@ 0,0 1,5 @@
# The default keymap for the FC980C

Emulates original keymap.

![](https://i.imgur.com/bQBXPkY.jpg)

A keyboards/fc980c/keymaps/default/config.h => keyboards/fc980c/keymaps/default/config.h +24 -0
@@ 0,0 1,24 @@
/* Copyright 2017 Balz Guenat
 *
 * 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_USER_H
#define CONFIG_USER_H

#include "config_common.h"

// place overrides here

#endif

A keyboards/fc980c/keymaps/default/keymap.c => keyboards/fc980c/keymaps/default/keymap.c +39 -0
@@ 0,0 1,39 @@
/*
Copyright 2017 Balz Guenat

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 "fc980c.h"

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
  [0] = KEYMAP(
    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_DEL, KC_INS, KC_PGUP,KC_PGDN,
    KC_GRV, 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_NLCK,KC_PSLS,KC_PAST,KC_PMNS,
    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_P7,  KC_P8,  KC_P9,  KC_PPLS,
    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_P4,  KC_P5,  KC_P6,
    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_P1,  KC_P2,  KC_P3,  KC_PENT,
    KC_LCTL,KC_LGUI,KC_LALT,                     KC_SPC,                   KC_RALT,KC_RCTL,MO(1),   KC_LEFT,KC_DOWN,KC_RGHT,        KC_P0,  KC_PDOT
    ),
  [1] = KEYMAP(
    _______,        _______,_______,_______,_______,_______,_______,_______, _______, _______, _______,_______,_______,                        _______,_______,KC_HOME,KC_END,
    _______,_______,_______,_______,_______,_______,_______,_______,_______, _______, _______, _______,_______,_______,                        _______,_______,_______,_______,
    _______,_______,_______,_______,_______,_______,_______,_______,KC_PSCR, KC_SLCK, KC_PAUS, _______,_______,_______,                        _______,_______,_______,_______,
    _______,_______,_______,_______,_______,_______,_______,_______,_______, _______, _______, _______,        _______,                        _______,_______,_______,
    _______,        _______,_______,_______,_______,_______,_______,_______, _______, _______, _______,        _______,         KC_PGUP,       _______,_______,_______,_______,
    _______,_______,_______,                           _______,                                _______,KC_APP, _______, KC_HOME,KC_PGDN,KC_END,        _______,_______     
    ),
};

const uint16_t PROGMEM fn_actions[] = {
};

A keyboards/fc980c/matrix.c => keyboards/fc980c/matrix.c +228 -0
@@ 0,0 1,228 @@
/*
Copyright 2017 Balz Guenat
based on work by Jun Wako <wakojun@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/>.
*/

/*
 * scan matrix
 */
#include <stdint.h>
#include <stdbool.h>
#include <util/delay.h>
#include "print.h"
#include "debug.h"
#include "util.h"
#include "timer.h"
#include "matrix.h"
#include "led.h"
// #include "fc980c.h"


// Timer resolution check
#if (1000000/TIMER_RAW_FREQ > 20)
#   error "Timer resolution(>20us) is not enough for HHKB matrix scan tweak on V-USB."
#endif


/*
 * Pin configuration for ATMega32U4
 *
 * Row:     PD4-6, PD7(~EN)
 * Col:     PB0-3
 * Key:     PC6(pull-uped)
 * Hys:     PC7
 */
static inline void KEY_ENABLE(void) { (PORTD &= ~(1<<7)); }
static inline void KEY_UNABLE(void) { (PORTD |=  (1<<7)); }
static inline bool KEY_STATE(void) { return (PINC & (1<<6)); }
static inline void KEY_HYS_ON(void) { (PORTC |=  (1<<7)); }
static inline void KEY_HYS_OFF(void) { (PORTC &= ~(1<<7)); }
static inline void KEY_INIT(void)
{
    /* Col */
    DDRB  |=  0x0F;
    /* Key: input with pull-up */
    DDRC  &= ~(1<<6);
    PORTC |=  (1<<6);
    /* Hys */
    DDRC  |=  (1<<7);
    /* Row */
    DDRD  |=  0xF0;

    KEY_UNABLE();
    KEY_HYS_OFF();
}
static inline void SET_ROW(uint8_t ROW)
{
    // PD4-6
    PORTD = (PORTD & 0x8F) | ((ROW & 0x07) << 4);
}
static inline void SET_COL(uint8_t COL)
{
    // PB0-3
    PORTB = (PORTB & 0xF0) | (COL & 0x0F);
}

static uint32_t matrix_last_modified = 0;

// matrix state buffer(1:on, 0:off)
static matrix_row_t *matrix;
static matrix_row_t *matrix_prev;
static matrix_row_t _matrix0[MATRIX_ROWS];
static matrix_row_t _matrix1[MATRIX_ROWS];


__attribute__ ((weak))
void matrix_init_quantum(void) {
    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) {
}


void matrix_init(void)
{
    debug_enable = true;
    debug_matrix = true;

    KEY_INIT();

    // LEDs on NumLock, CapsLock and ScrollLock(PB4, PB5, PB6)
    DDRB  |= (1<<4) | (1<<5) | (1<<6);
    PORTB |= (1<<4) | (1<<5) | (1<<6);

    // initialize matrix state: all keys off
    for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
    for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00;
    matrix = _matrix0;
    matrix_prev = _matrix1;
    matrix_init_quantum();
}

uint8_t matrix_scan(void)
{
    matrix_row_t *tmp;

    tmp = matrix_prev;
    matrix_prev = matrix;
    matrix = tmp;

    uint8_t row, col;
    for (col = 0; col < MATRIX_COLS; col++) {
        SET_COL(col);
        for (row = 0; row < MATRIX_ROWS; row++) {
            //KEY_SELECT(row, col);
            SET_ROW(row);
            _delay_us(2);

            // Not sure this is needed. This just emulates HHKB controller's behaviour.
            if (matrix_prev[row] & (1<<col)) {
                KEY_HYS_ON();
            }
            _delay_us(10);

            // NOTE: KEY_STATE is valid only in 20us after KEY_ENABLE.
            // If V-USB interrupts in this section we could lose 40us or so
            // and would read invalid value from KEY_STATE.
            uint8_t last = TIMER_RAW;

            KEY_ENABLE();

            // Wait for KEY_STATE outputs its value.
            _delay_us(2);

            if (KEY_STATE()) {
                matrix[row] &= ~(1<<col);
            } else {
                matrix[row] |= (1<<col);
            }

            // Ignore if this code region execution time elapses more than 20us.
            // MEMO: 20[us] * (TIMER_RAW_FREQ / 1000000)[count per us]
            // MEMO: then change above using this rule: a/(b/c) = a*1/(b/c) = a*(c/b)
            if (TIMER_DIFF_RAW(TIMER_RAW, last) > 20/(1000000/TIMER_RAW_FREQ)) {
                matrix[row] = matrix_prev[row];
            }

            _delay_us(5);
            KEY_HYS_OFF();
            KEY_UNABLE();

            // NOTE: KEY_STATE keep its state in 20us after KEY_ENABLE.
            // This takes 25us or more to make sure KEY_STATE returns to idle state.
            _delay_us(75);
        }
        if (matrix[row] ^ matrix_prev[row]) {
            matrix_last_modified = timer_read32();
        }
    }
    matrix_scan_quantum();
    return 1;
}

inline
matrix_row_t matrix_get_row(uint8_t row) {
    return matrix[row];
}

void matrix_print(void)
{
#if (MATRIX_COLS <= 8)
    print("r/c 01234567\n");
#elif (MATRIX_COLS <= 16)
    print("r/c 0123456789ABCDEF\n");
#elif (MATRIX_COLS <= 32)
    print("r/c 0123456789ABCDEF0123456789ABCDEF\n");
#endif

    for (uint8_t row = 0; row < MATRIX_ROWS; row++) {

#if (MATRIX_COLS <= 8)
        xprintf("%02X: %08b%s\n", row, bitrev(matrix_get_row(row)),
#elif (MATRIX_COLS <= 16)
        xprintf("%02X: %016b%s\n", row, bitrev16(matrix_get_row(row)),
#elif (MATRIX_COLS <= 32)
        xprintf("%02X: %032b%s\n", row, bitrev32(matrix_get_row(row)),
#endif
#ifdef MATRIX_HAS_GHOST
        matrix_has_ghost_in_row(row) ?  " <ghost" : ""
#else
        ""
#endif
        );
    }
}

A keyboards/fc980c/rules.mk => keyboards/fc980c/rules.mk +64 -0
@@ 0,0 1,64 @@
# 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 = 16000000



# 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
#   comment out to disable the options.
#
# 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 = yes	# Console for debug(+400)
COMMAND_ENABLE = yes    # Commands for debug and configuration
NKRO_ENABLE = yes		# USB Nkey Rollover - not yet supported in LUFA

# Optimize size but this may cause error "relocation truncated to fit"
#EXTRALDFLAGS = -Wl,--relax

CUSTOM_MATRIX = yes
SRC += matrix.c