parent
8f23161d19
commit
b25b9b02f4
@ -0,0 +1,21 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Kaleidoscope-Hardware-Keyboardio-Atreus -- Keyboardio Atreus hardware support for Kaleidoscope
|
||||||
|
* Copyright (C) 2019 Keyboard.io, Inc
|
||||||
|
*
|
||||||
|
* 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 3 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 "kaleidoscope/device/keyboardio/SAMDTestbed.h"
|
@ -0,0 +1,58 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* device::ATmega32U4Keyboard -- Generic ATmega32U4 keyboard base class
|
||||||
|
* Copyright (C) 2019 Keyboard.io, Inc
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of version 3 of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
#if defined(__SAMD51__) || defined(__SAMD21__) || defined(KALEIDOSCOPE_VIRTUAL_BUILD)
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "kaleidoscope/device/Base.h"
|
||||||
|
|
||||||
|
#include "kaleidoscope/driver/mcu/SAMD.h"
|
||||||
|
#include "kaleidoscope/driver/keyscanner/SAMD.h"
|
||||||
|
#include "kaleidoscope/driver/storage/Flash.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace device {
|
||||||
|
|
||||||
|
struct SAMDStorageProps : public kaleidoscope::driver::storage::FlashProps {
|
||||||
|
static constexpr uint16_t length = EEPROM_EMULATION_SIZE;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SAMDKeyboardProps : kaleidoscope::device::BaseProps {
|
||||||
|
typedef kaleidoscope::driver::mcu::SAMD MCU;
|
||||||
|
typedef SAMDStorageProps StorageProps;
|
||||||
|
typedef kaleidoscope::driver::storage::Flash<StorageProps> Storage;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
|
||||||
|
template <typename _DeviceProps>
|
||||||
|
class SAMDKeyboard : public kaleidoscope::device::Base<_DeviceProps> {
|
||||||
|
public:
|
||||||
|
auto serialPort() -> decltype(Serial) & {
|
||||||
|
return Serial;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
|
||||||
|
template <typename _DeviceProps>
|
||||||
|
class SAMDKeyboard;
|
||||||
|
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,67 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Keyboardio SAMD Testbed hardware support for Kaleidoscope
|
||||||
|
* Copyright (C) 2019, 2020 Keyboard.io, Inc
|
||||||
|
*
|
||||||
|
* 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 3 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 KALEIDOSCOPE_VIRTUAL_BUILD
|
||||||
|
#ifdef KEYBOARDIO_SAMD_TESTBED
|
||||||
|
|
||||||
|
#include "kaleidoscope/Runtime.h"
|
||||||
|
#include "kaleidoscope/driver/keyscanner/Base_Impl.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Here, we set up aliases to the device's KeyScanner and KeyScannerProps
|
||||||
|
// in the global namespace within the scope of this file. We'll use these
|
||||||
|
// aliases to simplify some template initialization code below.
|
||||||
|
using KeyScannerProps = typename kaleidoscope::device::keyboardio::SAMDTestbedProps::KeyScannerProps;
|
||||||
|
using KeyScanner = typename kaleidoscope::device::keyboardio::SAMDTestbedProps::KeyScanner;
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace device {
|
||||||
|
namespace keyboardio {
|
||||||
|
|
||||||
|
// `KeyScannerProps` here refers to the alias set up above. We do not need to
|
||||||
|
// prefix the `matrix_rows` and `matrix_columns` names within the array
|
||||||
|
// declaration, because those are resolved within the context of the class, so
|
||||||
|
// the `matrix_rows` in `KeyScannerProps::matrix_row_pins[matrix_rows]` gets
|
||||||
|
// resolved as `KeyScannerProps::matrix_rows`.
|
||||||
|
const uint8_t KeyScannerProps::matrix_rows;
|
||||||
|
const uint8_t KeyScannerProps::matrix_columns;
|
||||||
|
constexpr uint8_t KeyScannerProps::matrix_row_pins[matrix_rows];
|
||||||
|
constexpr uint8_t KeyScannerProps::matrix_col_pins[matrix_columns];
|
||||||
|
|
||||||
|
// `KeyScanner` here refers to the alias set up above, just like in the
|
||||||
|
// `KeyScannerProps` case above.
|
||||||
|
template<> KeyScanner::row_state_t KeyScanner::matrix_state_[KeyScannerProps::matrix_rows] = {};
|
||||||
|
|
||||||
|
// We set up the TIMER1 interrupt vector here. Due to dependency reasons, this
|
||||||
|
// cannot be in a header-only driver, and must be placed here.
|
||||||
|
//
|
||||||
|
// Timer1 is responsible for setting a property on the KeyScanner, which will
|
||||||
|
// tell it to do a scan. We use this to make sure that scans happen at roughly
|
||||||
|
// the intervals we want. We do the scan outside of the interrupt scope for
|
||||||
|
// practical reasons: guarding every codepath against interrupts that can be
|
||||||
|
// reached from the scan is far too tedious, for very little gain.
|
||||||
|
ISR(TIMER1_OVF_vect) {
|
||||||
|
Runtime.device().keyScanner().do_scan_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
|
@ -0,0 +1,97 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Keyboardio SAMD Testbed hardware support for Kaleidoscope
|
||||||
|
* Copyright (C) 2019 Keyboard.io, Inc
|
||||||
|
*
|
||||||
|
* 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 3 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
|
||||||
|
|
||||||
|
#ifdef KEYBOARDIO_SAMD_TESTBED
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include "kaleidoscope/driver/bootloader/samd/Bossac.h"
|
||||||
|
#include "kaleidoscope/device/SAMDKeyboard.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace device {
|
||||||
|
namespace keyboardio {
|
||||||
|
|
||||||
|
|
||||||
|
struct SAMDTestbedProps : kaleidoscope::device::SAMDKeyboardProps {
|
||||||
|
struct KeyScannerProps : public kaleidoscope::driver::keyscanner::SAMDProps {
|
||||||
|
|
||||||
|
|
||||||
|
static constexpr uint8_t matrix_rows = 4;
|
||||||
|
static constexpr uint8_t matrix_columns = 12;
|
||||||
|
typedef MatrixAddr<matrix_rows, matrix_columns> KeyAddr;
|
||||||
|
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
|
||||||
|
static constexpr uint8_t matrix_row_pins[matrix_rows] = {PIN_F6, PIN_F5, PIN_F4, PIN_F1};
|
||||||
|
static constexpr uint8_t matrix_col_pins[matrix_columns] = {PIN_F7, PIN_E2, PIN_C7, PIN_C6, PIN_B6, PIN_B5, PIN_D7, PIN_D6, PIN_D4, PIN_D5, PIN_D3, PIN_D2};
|
||||||
|
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef kaleidoscope::driver::keyscanner::SAMD<KeyScannerProps> KeyScanner;
|
||||||
|
typedef kaleidoscope::driver::bootloader::samd::Bossac BootLoader;
|
||||||
|
static constexpr const char *short_name = "testbed";
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
|
||||||
|
class SAMDTestbed: public kaleidoscope::device::SAMDKeyboard<SAMDTestbedProps> {};
|
||||||
|
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
|
||||||
|
/* Device definition omitted for virtual device builds.
|
||||||
|
* We need to forward declare the device name, though, as there are
|
||||||
|
* some legacy extern references to boards whose definition
|
||||||
|
* depends on this.
|
||||||
|
*/
|
||||||
|
class SAMDTestbed;
|
||||||
|
|
||||||
|
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
|
||||||
|
|
||||||
|
|
||||||
|
#define PER_KEY_DATA(dflt, \
|
||||||
|
R0C0, R0C1, R0C2, R0C3, R0C4, R0C7, R0C8, R0C9, R0C10, R0C11, \
|
||||||
|
R1C0, R1C1, R1C2, R1C3, R1C4, R1C7, R1C8, R1C9, R1C10, R1C11, \
|
||||||
|
R2C0, R2C1, R2C2, R2C3, R2C4, R2C5, R2C6, R2C7, R2C8, R2C9, R2C10, R2C11, \
|
||||||
|
R3C0, R3C1, R3C2, R3C3, R3C4, R3C5, R3C6, R3C7, R3C8, R3C9, R3C10, R3C11 \
|
||||||
|
) \
|
||||||
|
R0C0, R0C1, R0C2, R0C3, R0C4, XXX, XXX, R0C7, R0C8, R0C9, R0C10, R0C11, \
|
||||||
|
R1C0, R1C1, R1C2, R1C3, R1C4, XXX, XXX, R1C7, R1C8, R1C9, R1C10, R1C11, \
|
||||||
|
R2C0, R2C1, R2C2, R2C3, R2C4, R2C5, R2C6, R2C7, R2C8, R2C9, R2C10, R2C11, \
|
||||||
|
R3C0, R3C1, R3C2, R3C3, R3C4, R3C5, R3C6, R3C7, R3C8, R3C9, R3C10, R3C11
|
||||||
|
|
||||||
|
#define PER_KEY_DATA_STACKED(dflt, \
|
||||||
|
R0C0, R0C1, R0C2, R0C3, R0C4, \
|
||||||
|
R1C0, R1C1, R1C2, R1C3, R1C4, \
|
||||||
|
R2C0, R2C1, R2C2, R2C3, R2C4, R2C5, \
|
||||||
|
R3C0, R3C1, R3C2, R3C3, R3C4, R3C5, \
|
||||||
|
\
|
||||||
|
R0C7, R0C8, R0C9, R0C10, R0C11, \
|
||||||
|
R1C7, R1C8, R1C9, R1C10, R1C11, \
|
||||||
|
R2C6, R2C7, R2C8, R2C9, R2C10, R2C11, \
|
||||||
|
R3C6, R3C7, R3C8, R3C9, R3C10, R3C11 \
|
||||||
|
) \
|
||||||
|
R0C0, R0C1, R0C2, R0C3, R0C4, XXX, XXX, R0C7, R0C8, R0C9, R0C10, R0C11, \
|
||||||
|
R1C0, R1C1, R1C2, R1C3, R1C4, XXX, XXX, R1C7, R1C8, R1C9, R1C10, R1C11, \
|
||||||
|
R2C0, R2C1, R2C2, R2C3, R2C4, R2C5, R2C6, R2C7, R2C8, R2C9, R2C10, R2C11, \
|
||||||
|
R3C0, R3C1, R3C2, R3C3, R3C4, R3C5, R3C6, R3C7, R3C8, R3C9, R3C10, R3C11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT_DEVICE(kaleidoscope::device::keyboardio::SAMDTestbed)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,144 @@
|
|||||||
|
/* This file originated in QMK. https://github.com/qmk/qmk_firmware
|
||||||
|
* quantum/config_common.h 73e634482ea8f57d1f1a5f1e16bc3ffd74f84b8e
|
||||||
|
*
|
||||||
|
* Original copyright statement:
|
||||||
|
*
|
||||||
|
* Copyright 2015-2018 Jack Humbert
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
#if !defined(__ASSEMBLER__) && !defined(KALEIDOSCOPE_VIRTUAL_BUILD)
|
||||||
|
//#include <avr/io.h>
|
||||||
|
#endif
|
||||||
|
#define PORT_SHIFTER 4 // this may be 4 for all AVR chips
|
||||||
|
|
||||||
|
// If you want to add more to this list, reference the PINx definitions in these header
|
||||||
|
// files: https://github.com/vancegroup-mirrors/avr-libc/tree/master/avr-libc/include/avr
|
||||||
|
|
||||||
|
#if defined(__SAMD21__) || defined(__SAMD51__)
|
||||||
|
// TODO - these numbers aren't right
|
||||||
|
#define ADDRESS_BASE 0x00
|
||||||
|
#define PINA_ADDRESS 0x9
|
||||||
|
#define PINB_ADDRESS 0x3
|
||||||
|
#define PINC_ADDRESS 0x6
|
||||||
|
#define PIND_ADDRESS 0x9
|
||||||
|
#define PINE_ADDRESS 0xC
|
||||||
|
#define PINF_ADDRESS 0xF
|
||||||
|
#elif !defined(KALEIDOSCOPE_VIRTUAL_BUILD)
|
||||||
|
#error "Pins are not defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* I/O pins */
|
||||||
|
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
|
||||||
|
#define PINDEF(port, pin) ((PIN##port##_ADDRESS << PORT_SHIFTER) | pin)
|
||||||
|
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
|
||||||
|
#define PINDEF(port, pin) 0
|
||||||
|
#define PORTA
|
||||||
|
#define PORTB
|
||||||
|
#define PORTC
|
||||||
|
#define PORTD
|
||||||
|
#define PORTE
|
||||||
|
#define PORTF
|
||||||
|
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
|
||||||
|
|
||||||
|
#ifdef PORTA
|
||||||
|
#define PIN_A0 PINDEF(A, 0)
|
||||||
|
#define PIN_A1 PINDEF(A, 1)
|
||||||
|
#define PIN_A2 PINDEF(A, 2)
|
||||||
|
#define PIN_A3 PINDEF(A, 3)
|
||||||
|
#define PIN_A4 PINDEF(A, 4)
|
||||||
|
#define PIN_A5 PINDEF(A, 5)
|
||||||
|
#define PIN_A6 PINDEF(A, 6)
|
||||||
|
#define PIN_A7 PINDEF(A, 7)
|
||||||
|
#endif
|
||||||
|
#ifdef PORTB
|
||||||
|
#define PIN_B0 PINDEF(B, 0)
|
||||||
|
#define PIN_B1 PINDEF(B, 1)
|
||||||
|
#define PIN_B2 PINDEF(B, 2)
|
||||||
|
#define PIN_B3 PINDEF(B, 3)
|
||||||
|
#define PIN_B4 PINDEF(B, 4)
|
||||||
|
#define PIN_B5 PINDEF(B, 5)
|
||||||
|
#define PIN_B6 PINDEF(B, 6)
|
||||||
|
#define PIN_B7 PINDEF(B, 7)
|
||||||
|
#endif
|
||||||
|
#ifdef PORTC
|
||||||
|
#define PIN_C0 PINDEF(C, 0)
|
||||||
|
#define PIN_C1 PINDEF(C, 1)
|
||||||
|
#define PIN_C2 PINDEF(C, 2)
|
||||||
|
#define PIN_C3 PINDEF(C, 3)
|
||||||
|
#define PIN_C4 PINDEF(C, 4)
|
||||||
|
#define PIN_C5 PINDEF(C, 5)
|
||||||
|
#define PIN_C6 PINDEF(C, 6)
|
||||||
|
#define PIN_C7 PINDEF(C, 7)
|
||||||
|
#endif
|
||||||
|
#ifdef PORTD
|
||||||
|
#define PIN_D0 PINDEF(D, 0)
|
||||||
|
#define PIN_D1 PINDEF(D, 1)
|
||||||
|
#define PIN_D2 PINDEF(D, 2)
|
||||||
|
#define PIN_D3 PINDEF(D, 3)
|
||||||
|
#define PIN_D4 PINDEF(D, 4)
|
||||||
|
#define PIN_D5 PINDEF(D, 5)
|
||||||
|
#define PIN_D6 PINDEF(D, 6)
|
||||||
|
#define PIN_D7 PINDEF(D, 7)
|
||||||
|
#endif
|
||||||
|
#ifdef PORTE
|
||||||
|
#define PIN_E0 PINDEF(E, 0)
|
||||||
|
#define PIN_E1 PINDEF(E, 1)
|
||||||
|
#define PIN_E2 PINDEF(E, 2)
|
||||||
|
#define PIN_E3 PINDEF(E, 3)
|
||||||
|
#define PIN_E4 PINDEF(E, 4)
|
||||||
|
#define PIN_E5 PINDEF(E, 5)
|
||||||
|
#define PIN_E6 PINDEF(E, 6)
|
||||||
|
#define PIN_E7 PINDEF(E, 7)
|
||||||
|
#endif
|
||||||
|
#ifdef PORTF
|
||||||
|
#define PIN_F0 PINDEF(F, 0)
|
||||||
|
#define PIN_F1 PINDEF(F, 1)
|
||||||
|
#define PIN_F2 PINDEF(F, 2)
|
||||||
|
#define PIN_F3 PINDEF(F, 3)
|
||||||
|
#define PIN_F4 PINDEF(F, 4)
|
||||||
|
#define PIN_F5 PINDEF(F, 5)
|
||||||
|
#define PIN_F6 PINDEF(F, 6)
|
||||||
|
#define PIN_F7 PINDEF(F, 7)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* converting pins to ports */
|
||||||
|
enum { PIN_OFFSET, DDR_OFFSET, PORT_OFFSET};
|
||||||
|
|
||||||
|
#define PIN_ADDRESS_MASK 0xF
|
||||||
|
|
||||||
|
#define PIN_ADDRESS(p, offset) _SFR_IO8(ADDRESS_BASE + (p >> PORT_SHIFTER) + offset)
|
||||||
|
#define PIN_REG_FOR_PIN(pin) PIN_ADDRESS(pin, PIN_OFFSET )
|
||||||
|
#define DDR_REG_FOR_PIN(pin) PIN_ADDRESS(pin, DDR_OFFSET )
|
||||||
|
#define PORT_REG_FOR_PIN(pin) PIN_ADDRESS(pin, PORT_OFFSET )
|
||||||
|
#define PIN_NUM_FOR_PIN(pin) ( pin & PIN_ADDRESS_MASK )
|
||||||
|
#define PIN_MASK_FOR_PIN(pin) _BV(PIN_NUM_FOR_PIN(pin))
|
||||||
|
|
||||||
|
#define DDR_INPUT(pin) (DDR_REG_FOR_PIN(pin) &= ~(PIN_MASK_FOR_PIN(pin)))
|
||||||
|
#define DDR_OUTPUT(pin) (DDR_REG_FOR_PIN(pin) |= (PIN_MASK_FOR_PIN(pin)))
|
||||||
|
|
||||||
|
|
||||||
|
#define ENABLE_PULLUP(pin) (PORT_REG_FOR_PIN(pin) |= (PIN_MASK_FOR_PIN(pin)))
|
||||||
|
#define DISABLE_PULLUP(pin) (PORT_REG_FOR_PIN(pin) &= ~(PIN_MASK_FOR_PIN(pin)))
|
||||||
|
|
||||||
|
|
||||||
|
#define OUTPUT_HIGH(pin) (PORT_REG_FOR_PIN(pin) |= (PIN_MASK_FOR_PIN(pin)))
|
||||||
|
#define OUTPUT_LOW(pin) (PORT_REG_FOR_PIN(pin) &= ~(PIN_MASK_FOR_PIN(pin)))
|
||||||
|
#define OUTPUT_TOGGLE(pin) (PORT_REG_FOR_PIN(pin) ^= (PIN_MASK_FOR_PIN(pin)))
|
||||||
|
|
||||||
|
#define READ_PIN(pin) (!!(PIN_REG_FOR_PIN(pin) & PIN_MASK_FOR_PIN(pin)))
|
||||||
|
|
@ -0,0 +1,265 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* kaleidoscope::driver::keyscanner::SAMD -- Microchip SAMD-based keyscanner component
|
||||||
|
* Copyright (C) 2018-2020 Keyboard.io, Inc
|
||||||
|
*
|
||||||
|
* 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, version 3.
|
||||||
|
*
|
||||||
|
* 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 <Arduino.h>
|
||||||
|
|
||||||
|
#include "kaleidoscope/macro_helpers.h"
|
||||||
|
#include "kaleidoscope/driver/keyscanner/Base.h"
|
||||||
|
#include "kaleidoscope/driver/keyscanner/None.h"
|
||||||
|
|
||||||
|
#include "kaleidoscope/device/samd/pins_and_ports.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace driver {
|
||||||
|
namespace keyscanner {
|
||||||
|
|
||||||
|
struct SAMDProps: kaleidoscope::driver::keyscanner::BaseProps {
|
||||||
|
static const uint16_t keyscan_interval = 1500;
|
||||||
|
typedef uint16_t RowState;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following two lines declare an empty array. Both of these must be
|
||||||
|
* shadowed by the descendant keyscanner description class.
|
||||||
|
*/
|
||||||
|
static constexpr uint8_t matrix_row_pins[] = {};
|
||||||
|
static constexpr uint8_t matrix_col_pins[] = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef KALEIDOSCOPE_VIRTUAL_BUILD
|
||||||
|
template <typename _KeyScannerProps>
|
||||||
|
class SAMD: public kaleidoscope::driver::keyscanner::Base<_KeyScannerProps> {
|
||||||
|
private:
|
||||||
|
typedef SAMD<_KeyScannerProps> ThisType;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setup() {
|
||||||
|
static_assert(
|
||||||
|
sizeof(_KeyScannerProps::matrix_row_pins) > 0,
|
||||||
|
"The key scanner description has an empty array of matrix row pins."
|
||||||
|
);
|
||||||
|
static_assert(
|
||||||
|
sizeof(_KeyScannerProps::matrix_col_pins) > 0,
|
||||||
|
"The key scanner description has an empty array of matrix column pins."
|
||||||
|
);
|
||||||
|
|
||||||
|
//TODO XXX WDT_Disable(WDT);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < _KeyScannerProps::matrix_columns; i++) {
|
||||||
|
DDR_INPUT(_KeyScannerProps::matrix_col_pins[i]);
|
||||||
|
ENABLE_PULLUP(_KeyScannerProps::matrix_col_pins[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < _KeyScannerProps::matrix_rows; i++) {
|
||||||
|
DDR_OUTPUT(_KeyScannerProps::matrix_row_pins[i]);
|
||||||
|
OUTPUT_HIGH(_KeyScannerProps::matrix_row_pins[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
setScanCycleTime(_KeyScannerProps::keyscan_interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* setScanCycleTime takes a value of between 0 and 8192. This corresponds (roughly) to the number of microseconds to wait between scanning the key matrix. Our debouncing algorithm does four checks before deciding that a result is valid. Most normal mechanical switches specify a 5ms debounce period. On an ATMega32U4, 1700 gets you about 5ms of debouncing.
|
||||||
|
|
||||||
|
Because keycanning is triggered by an interrupt but not run in that interrupt, the actual amount of time between scans is prone to a little bit of jitter.
|
||||||
|
|
||||||
|
*/
|
||||||
|
void setScanCycleTime(uint16_t c) {
|
||||||
|
/* TODO
|
||||||
|
TCCR1B = _BV(WGM13);
|
||||||
|
TCCR1A = 0;
|
||||||
|
*/
|
||||||
|
|
||||||
|
const uint32_t cycles = (F_CPU / 2000000) * c;
|
||||||
|
/* TODO
|
||||||
|
ICR1 = cycles;
|
||||||
|
TCCR1B = _BV(WGM13) | _BV(CS10);
|
||||||
|
TIMSK1 = _BV(TOIE1);
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((optimize(3)))
|
||||||
|
void readMatrix(void) {
|
||||||
|
typename _KeyScannerProps::RowState any_debounced_changes = 0;
|
||||||
|
|
||||||
|
for (uint8_t current_row = 0; current_row < _KeyScannerProps::matrix_rows; current_row++) {
|
||||||
|
OUTPUT_TOGGLE(_KeyScannerProps::matrix_row_pins[current_row]);
|
||||||
|
typename _KeyScannerProps::RowState hot_pins = readCols();
|
||||||
|
|
||||||
|
OUTPUT_TOGGLE(_KeyScannerProps::matrix_row_pins[current_row]);
|
||||||
|
|
||||||
|
any_debounced_changes |= debounce(hot_pins, &matrix_state_[current_row].debouncer);
|
||||||
|
|
||||||
|
if (any_debounced_changes) {
|
||||||
|
for (uint8_t current_row = 0; current_row < _KeyScannerProps::matrix_rows; current_row++) {
|
||||||
|
matrix_state_[current_row].current = matrix_state_[current_row].debouncer.debounced_state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void scanMatrix() {
|
||||||
|
if (do_scan_) {
|
||||||
|
do_scan_ = false;
|
||||||
|
readMatrix();
|
||||||
|
}
|
||||||
|
actOnMatrixScan();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __attribute__((optimize(3))) actOnMatrixScan() {
|
||||||
|
for (byte row = 0; row < _KeyScannerProps::matrix_rows; row++) {
|
||||||
|
for (byte col = 0; col < _KeyScannerProps::matrix_columns; col++) {
|
||||||
|
uint8_t keyState = (bitRead(matrix_state_[row].previous, col) << 0) | (bitRead(matrix_state_[row].current, col) << 1);
|
||||||
|
if (keyState) {
|
||||||
|
ThisType::handleKeyswitchEvent(Key_NoKey, typename _KeyScannerProps::KeyAddr(row, col), keyState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
matrix_state_[row].previous = matrix_state_[row].current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t pressedKeyswitchCount() {
|
||||||
|
uint8_t count = 0;
|
||||||
|
|
||||||
|
for (int8_t r = 0; r < _KeyScannerProps::matrix_rows; r++) {
|
||||||
|
count += __builtin_popcount(matrix_state_[r].current);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
bool isKeyswitchPressed(typename _KeyScannerProps::KeyAddr key_addr) {
|
||||||
|
return (bitRead(matrix_state_[key_addr.row()].current, key_addr.col()) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t previousPressedKeyswitchCount() {
|
||||||
|
uint8_t count = 0;
|
||||||
|
|
||||||
|
for (int8_t r = 0; r < _KeyScannerProps::matrix_rows; r++) {
|
||||||
|
count += __builtin_popcount(matrix_state_[r].previous);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
bool wasKeyswitchPressed(typename _KeyScannerProps::KeyAddr key_addr) {
|
||||||
|
return (bitRead(matrix_state_[key_addr.row()].previous,
|
||||||
|
key_addr.col()) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void maskKey(typename _KeyScannerProps::KeyAddr key_addr) {
|
||||||
|
if (!key_addr.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
bitWrite(matrix_state_[key_addr.row()].masks, key_addr.col(), 1);
|
||||||
|
}
|
||||||
|
void unMaskKey(typename _KeyScannerProps::KeyAddr key_addr) {
|
||||||
|
if (!key_addr.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
bitWrite(matrix_state_[key_addr.row()].masks, key_addr.col(), 0);
|
||||||
|
}
|
||||||
|
bool isKeyMasked(typename _KeyScannerProps::KeyAddr key_addr) {
|
||||||
|
if (!key_addr.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return bitRead(matrix_state_[key_addr.row()].masks,
|
||||||
|
key_addr.col());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool do_scan_;
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*
|
||||||
|
each of these variables are storing the state for a row of keys
|
||||||
|
|
||||||
|
so for key 0, the counter is represented by db0[0] and db1[0]
|
||||||
|
and the state in debounced_state[0].
|
||||||
|
*/
|
||||||
|
struct debounce_t {
|
||||||
|
typename _KeyScannerProps::RowState db0; // counter bit 0
|
||||||
|
typename _KeyScannerProps::RowState db1; // counter bit 1
|
||||||
|
typename _KeyScannerProps::RowState debounced_state; // debounced state
|
||||||
|
};
|
||||||
|
|
||||||
|
struct row_state_t {
|
||||||
|
typename _KeyScannerProps::RowState previous;
|
||||||
|
typename _KeyScannerProps::RowState current;
|
||||||
|
typename _KeyScannerProps::RowState masks;
|
||||||
|
debounce_t debouncer;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef _KeyScannerProps KeyScannerProps_;
|
||||||
|
static row_state_t matrix_state_[_KeyScannerProps::matrix_rows];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function has loop unrolling disabled on purpose: we want to give the
|
||||||
|
* hardware enough time to produce stable PIN reads for us. If we unroll the
|
||||||
|
* loop, we will not have that, because even with the NOP, the codepath is too
|
||||||
|
* fast. If we don't have stable reads, then entire rows or columns will behave
|
||||||
|
* erratically.
|
||||||
|
*
|
||||||
|
* For this reason, we ask the compiler to not unroll our loop, which in turn,
|
||||||
|
* gives hardware enough time to produce stable reads, at the cost of a little
|
||||||
|
* bit of speed.
|
||||||
|
*
|
||||||
|
* Do not remove the attribute!
|
||||||
|
*/
|
||||||
|
__attribute__((optimize("no-unroll-loops")))
|
||||||
|
typename _KeyScannerProps::RowState readCols() {
|
||||||
|
typename _KeyScannerProps::RowState hot_pins = 0;
|
||||||
|
for (uint8_t i = 0; i < _KeyScannerProps::matrix_columns; i++) {
|
||||||
|
asm("NOP"); // We need to pause a beat before reading or we may read before the pin is hot
|
||||||
|
hot_pins |= (!READ_PIN(_KeyScannerProps::matrix_col_pins[i]) << i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hot_pins;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline typename _KeyScannerProps::RowState debounce(
|
||||||
|
typename _KeyScannerProps::RowState sample, debounce_t *debouncer
|
||||||
|
) {
|
||||||
|
typename _KeyScannerProps::RowState delta, changes;
|
||||||
|
|
||||||
|
// Use xor to detect changes from last stable state:
|
||||||
|
// if a key has changed, it's bit will be 1, otherwise 0
|
||||||
|
delta = sample ^ debouncer->debounced_state;
|
||||||
|
|
||||||
|
// Increment counters and reset any unchanged bits:
|
||||||
|
// increment bit 1 for all changed keys
|
||||||
|
debouncer->db1 = ((debouncer->db1) ^ (debouncer->db0)) & delta;
|
||||||
|
// increment bit 0 for all changed keys
|
||||||
|
debouncer->db0 = ~(debouncer->db0) & delta;
|
||||||
|
|
||||||
|
// Calculate returned change set: if delta is still true
|
||||||
|
// and the counter has wrapped back to 0, the key is changed.
|
||||||
|
|
||||||
|
changes = ~(~delta | (debouncer->db0) | (debouncer->db1));
|
||||||
|
// Update state: in this case use xor to flip any bit that is true in changes.
|
||||||
|
debouncer->debounced_state ^= changes;
|
||||||
|
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#else // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
|
||||||
|
template <typename _KeyScannerProps>
|
||||||
|
class SAMD : public keyscanner::None {};
|
||||||
|
#endif // ifndef KALEIDOSCOPE_VIRTUAL_BUILD
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue