parent
31e4a54e3c
commit
0926aba479
@ -0,0 +1,48 @@
|
|||||||
|
# This makefile for a Kaleidoscope sketch pulls in all the targets
|
||||||
|
# required to build the example
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ifneq ($(KALEIDOSCOPE_DIR),)
|
||||||
|
search_path += $(KALEIDOSCOPE_DIR)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(ARDUINO_DIRECTORIES_USER),)
|
||||||
|
search_path += $(ARDUINO_DIRECTORIES_USER)/hardware/keyboardio/avr/libraries/Kaleidoscope
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(shell uname -s),Darwin)
|
||||||
|
search_path += $(HOME)/Documents/Arduino/hardware/keyboardio/avr/libraries/Kaleidoscope
|
||||||
|
else
|
||||||
|
search_path += $(HOME)/Arduino/hardware/keyboardio/avr/libraries/Kaleidoscope
|
||||||
|
endif
|
||||||
|
|
||||||
|
sketch_makefile := etc/makefiles/sketch.mk
|
||||||
|
|
||||||
|
$(foreach candidate, $(search_path), $(if $(wildcard $(candidate)/$(sketch_makefile)), $(eval ks_dir ?= $(candidate))))
|
||||||
|
|
||||||
|
ifneq ($(ks_dir),)
|
||||||
|
|
||||||
|
$(info Using Kaleidoscope from $(ks_dir))
|
||||||
|
|
||||||
|
export KALEIDOSCOPE_DIR := $(ks_dir)
|
||||||
|
include $(ks_dir)/$(sketch_makefile)
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
$(info I can't find your Kaleidoscope installation.)
|
||||||
|
$(info )
|
||||||
|
$(info I tried looking in:)
|
||||||
|
$(info )
|
||||||
|
$(foreach candidate, $(search_path), $(info $(candidate)))
|
||||||
|
$(info )
|
||||||
|
$(info The easiest way to fix this is to set the 'KALEIDOSCOPE_DIR' environment)
|
||||||
|
$(info variable to the location of your Kaleidoscope directory.)
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
null-target:
|
||||||
|
$(info You should never see this message)
|
||||||
|
@:
|
@ -0,0 +1,103 @@
|
|||||||
|
// -*- mode: c++ -*-
|
||||||
|
|
||||||
|
#include <stdint.h> // for uint16_t, uint8_t
|
||||||
|
|
||||||
|
#include "pins_and_ports.h" // IWYU pragma: keep
|
||||||
|
#include <avr/wdt.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "adns5050.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BOOTLOADER_RESET_KEY 0xB007B007
|
||||||
|
static uint32_t reset_key __attribute__((section(".noinit")));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function runs before main(), and jumps to the bootloader after a reset
|
||||||
|
* initiated by .resetDevice().
|
||||||
|
*/
|
||||||
|
static void _bootloader_jump_after_watchdog_reset()
|
||||||
|
__attribute__((used, naked, section(".init3")));
|
||||||
|
static void _bootloader_jump_after_watchdog_reset() {
|
||||||
|
if ((MCUSR & (1 << WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
|
||||||
|
reset_key = 0;
|
||||||
|
|
||||||
|
((void (*)(void))(((FLASHEND + 1L) - 4096) >> 1))();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rebootBootloader() {
|
||||||
|
reset_key = BOOTLOADER_RESET_KEY;
|
||||||
|
wdt_enable(WDTO_250MS);
|
||||||
|
while (true) {} // This infinite loop ensures nothing else
|
||||||
|
// happens before the watchdog reboots us
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint8_t direct_pins[5] = {PIN_D4, PIN_D2, PIN_E6, PIN_B6, PIN_D7};
|
||||||
|
static constexpr uint8_t unused_pins[12] = {PIN_B5, PIN_C7, PIN_D0, PIN_D1, PIN_D3, PIN_D5, PIN_D6, PIN_F1, PIN_F3, PIN_F5, PIN_F6, PIN_F7};
|
||||||
|
|
||||||
|
void mcuSetup() {
|
||||||
|
wdt_disable();
|
||||||
|
|
||||||
|
// disable jtag
|
||||||
|
MCUCR |= (1 << JTD);
|
||||||
|
MCUCR |= (1 << JTD);
|
||||||
|
|
||||||
|
// disable clock division
|
||||||
|
CLKPR = (1 << CLKPCE);
|
||||||
|
CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void buttonSetup() {
|
||||||
|
// Initialize keyscanner
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < sizeof(unused_pins); i++) {
|
||||||
|
DDR_OUTPUT(unused_pins[i]);
|
||||||
|
DISABLE_PULLUP(unused_pins[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < sizeof(direct_pins); i++) {
|
||||||
|
DDR_INPUT(direct_pins[i]);
|
||||||
|
ENABLE_PULLUP(direct_pins[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
mcuSetup();
|
||||||
|
Serial.begin(9600);
|
||||||
|
buttonSetup();
|
||||||
|
|
||||||
|
adns5050_init();
|
||||||
|
adns5050_sync();
|
||||||
|
|
||||||
|
while (!Serial);
|
||||||
|
|
||||||
|
uint8_t pid = adns5050_read_reg(0x00);
|
||||||
|
uint8_t rid = adns5050_read_reg(0x01);
|
||||||
|
uint8_t pid2 = adns5050_read_reg(0x3e);
|
||||||
|
|
||||||
|
Serial.print("pid=");
|
||||||
|
Serial.print(pid, HEX);
|
||||||
|
Serial.print("; rid=");
|
||||||
|
Serial.print(rid, HEX);
|
||||||
|
Serial.print("; pid2=");
|
||||||
|
Serial.println(pid2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleSerial() {
|
||||||
|
if (Serial.available() == 0) return;
|
||||||
|
|
||||||
|
uint8_t b = Serial.read();
|
||||||
|
|
||||||
|
if (b == 'r') rebootBootloader();
|
||||||
|
|
||||||
|
Serial.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
handleSerial();
|
||||||
|
|
||||||
|
//report_adns5050_t r = adns505
|
||||||
|
|
||||||
|
delay(250);
|
||||||
|
}
|
@ -0,0 +1,214 @@
|
|||||||
|
/* Copyright 2021 Colin Lam (Ploopy Corporation)
|
||||||
|
* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
|
||||||
|
* Copyright 2019 Sunjun Kim
|
||||||
|
* Copyright 2019 Hiroyuki Okada
|
||||||
|
*
|
||||||
|
* 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 "adns5050.h"
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include "pins_and_ports.h"
|
||||||
|
|
||||||
|
// Registers
|
||||||
|
// clang-format off
|
||||||
|
#define REG_PRODUCT_ID 0x00
|
||||||
|
#define REG_REVISION_ID 0x01
|
||||||
|
#define REG_MOTION 0x02
|
||||||
|
#define REG_DELTA_X 0x03
|
||||||
|
#define REG_DELTA_Y 0x04
|
||||||
|
#define REG_SQUAL 0x05
|
||||||
|
#define REG_SHUTTER_UPPER 0x06
|
||||||
|
#define REG_SHUTTER_LOWER 0x07
|
||||||
|
#define REG_MAXIMUM_PIXEL 0x08
|
||||||
|
#define REG_PIXEL_SUM 0x09
|
||||||
|
#define REG_MINIMUM_PIXEL 0x0a
|
||||||
|
#define REG_PIXEL_GRAB 0x0b
|
||||||
|
#define REG_MOUSE_CONTROL 0x0d
|
||||||
|
#define REG_MOUSE_CONTROL2 0x19
|
||||||
|
#define REG_LED_DC_MODE 0x22
|
||||||
|
#define REG_CHIP_RESET 0x3a
|
||||||
|
#define REG_PRODUCT_ID2 0x3e
|
||||||
|
#define REG_INV_REV_ID 0x3f
|
||||||
|
#define REG_MOTION_BURST 0x63
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
void adns5050_init(void) {
|
||||||
|
// Initialize the ADNS serial pins.
|
||||||
|
DDR_OUTPUT(ADNS5050_SCLK_PIN);
|
||||||
|
DDR_OUTPUT(ADNS5050_SDIO_PIN);
|
||||||
|
DDR_OUTPUT(ADNS5050_CS_PIN);
|
||||||
|
|
||||||
|
// reboot the adns.
|
||||||
|
// if the adns hasn't initialized yet, this is harmless.
|
||||||
|
adns5050_write_reg(REG_CHIP_RESET, 0x5a);
|
||||||
|
|
||||||
|
// wait maximum time before adns is ready.
|
||||||
|
// this ensures that the adns is actuall ready after reset.
|
||||||
|
delay(55);
|
||||||
|
|
||||||
|
// read a burst from the adns and then discard it.
|
||||||
|
// gets the adns ready for write commands
|
||||||
|
// (for example, setting the dpi).
|
||||||
|
adns5050_read_burst();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform a synchronization with the ADNS.
|
||||||
|
// Just as with the serial protocol, this is used by the slave to send a
|
||||||
|
// synchronization signal to the master.
|
||||||
|
void adns5050_sync(void) {
|
||||||
|
OUTPUT_LOW(ADNS5050_CS_PIN);
|
||||||
|
delayMicroseconds(1);
|
||||||
|
OUTPUT_HIGH(ADNS5050_CS_PIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void adns5050_cs_select(void) {
|
||||||
|
OUTPUT_LOW(ADNS5050_CS_PIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void adns5050_cs_deselect(void) {
|
||||||
|
OUTPUT_HIGH(ADNS5050_CS_PIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t adns5050_serial_read(void) {
|
||||||
|
DDR_INPUT(ADNS5050_SDIO_PIN);
|
||||||
|
DISABLE_PULLUP(ADNS5050_SDIO_PIN);
|
||||||
|
|
||||||
|
uint8_t byte = 0;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 8; ++i) {
|
||||||
|
OUTPUT_LOW(ADNS5050_SCLK_PIN);
|
||||||
|
delayMicroseconds(1);
|
||||||
|
|
||||||
|
byte = (byte << 1) | READ_PIN(ADNS5050_SDIO_PIN);
|
||||||
|
|
||||||
|
OUTPUT_HIGH(ADNS5050_SCLK_PIN);
|
||||||
|
delayMicroseconds(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
void adns5050_serial_write(uint8_t data) {
|
||||||
|
DDR_OUTPUT(ADNS5050_SDIO_PIN);
|
||||||
|
|
||||||
|
for (int8_t b = 7; b >= 0; b--) {
|
||||||
|
OUTPUT_LOW(ADNS5050_SCLK_PIN);
|
||||||
|
|
||||||
|
if (data & (1 << b))
|
||||||
|
OUTPUT_HIGH(ADNS5050_SDIO_PIN);
|
||||||
|
else
|
||||||
|
OUTPUT_LOW(ADNS5050_SDIO_PIN);
|
||||||
|
|
||||||
|
delayMicroseconds(2);
|
||||||
|
|
||||||
|
OUTPUT_HIGH(ADNS5050_SCLK_PIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tSWR. See page 15 of the ADNS spec sheet.
|
||||||
|
// Technically, this is only necessary if the next operation is an SDIO
|
||||||
|
// read. This is not guaranteed to be the case, but we're being lazy.
|
||||||
|
delayMicroseconds(4);
|
||||||
|
|
||||||
|
// Note that tSWW is never necessary. All write operations require at
|
||||||
|
// least 32us, which exceeds tSWW, so there's never a need to wait for it.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a byte of data from a register on the ADNS.
|
||||||
|
// Don't forget to use the register map (as defined in the header file).
|
||||||
|
uint8_t adns5050_read_reg(uint8_t reg_addr) {
|
||||||
|
adns5050_cs_select();
|
||||||
|
|
||||||
|
adns5050_serial_write(reg_addr);
|
||||||
|
|
||||||
|
// We don't need a minimum tSRAD here. That's because a 4ms wait time is
|
||||||
|
// already included in adns5050_serial_write(), so we're good.
|
||||||
|
// See page 10 and 15 of the ADNS spec sheet.
|
||||||
|
// delayMicroseconds(4);
|
||||||
|
|
||||||
|
uint8_t byte = adns5050_serial_read();
|
||||||
|
|
||||||
|
// tSRW & tSRR. See page 15 of the ADNS spec sheet.
|
||||||
|
// Technically, this is only necessary if the next operation is an SDIO
|
||||||
|
// read or write. This is not guaranteed to be the case.
|
||||||
|
// Honestly, this wait could probably be removed.
|
||||||
|
delayMicroseconds(1);
|
||||||
|
|
||||||
|
adns5050_cs_deselect();
|
||||||
|
|
||||||
|
return byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
void adns5050_write_reg(uint8_t reg_addr, uint8_t data) {
|
||||||
|
adns5050_cs_select();
|
||||||
|
adns5050_serial_write(0b10000000 | reg_addr);
|
||||||
|
adns5050_serial_write(data);
|
||||||
|
adns5050_cs_deselect();
|
||||||
|
}
|
||||||
|
|
||||||
|
report_adns5050_t adns5050_read_burst(void) {
|
||||||
|
adns5050_cs_select();
|
||||||
|
|
||||||
|
report_adns5050_t data;
|
||||||
|
data.dx = 0;
|
||||||
|
data.dy = 0;
|
||||||
|
|
||||||
|
adns5050_serial_write(REG_MOTION_BURST);
|
||||||
|
|
||||||
|
// We don't need a minimum tSRAD here. That's because a 4ms wait time is
|
||||||
|
// already included in adns5050_serial_write(), so we're good.
|
||||||
|
// See page 10 and 15 of the ADNS spec sheet.
|
||||||
|
// delayMicroseconds(4);
|
||||||
|
|
||||||
|
uint8_t x = adns5050_serial_read();
|
||||||
|
uint8_t y = adns5050_serial_read();
|
||||||
|
|
||||||
|
// Burst mode returns a bunch of other shit that we don't really need.
|
||||||
|
// Setting CS to high ends burst mode early.
|
||||||
|
adns5050_cs_deselect();
|
||||||
|
|
||||||
|
data.dx = convert_twoscomp(x);
|
||||||
|
data.dy = convert_twoscomp(y);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert a two's complement byte from an unsigned data type into a signed
|
||||||
|
// data type.
|
||||||
|
int8_t convert_twoscomp(uint8_t data) {
|
||||||
|
if ((data & 0x80) == 0x80)
|
||||||
|
return -128 + (data & 0x7F);
|
||||||
|
else
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't forget to use the definitions for CPI in the header file.
|
||||||
|
void adns5050_set_cpi(uint16_t cpi) {
|
||||||
|
uint8_t cpival = constrain((cpi / 125), 0x1, 0xD); // limits to 0--119
|
||||||
|
|
||||||
|
adns5050_write_reg(REG_MOUSE_CONTROL2, 0b10000 | cpival);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t adns5050_get_cpi(void) {
|
||||||
|
uint8_t cpival = adns5050_read_reg(REG_MOUSE_CONTROL2);
|
||||||
|
return (uint16_t)((cpival & 0b10000) * 125);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool adns5050_check_signature(void) {
|
||||||
|
uint8_t pid = adns5050_read_reg(REG_PRODUCT_ID);
|
||||||
|
uint8_t rid = adns5050_read_reg(REG_REVISION_ID);
|
||||||
|
uint8_t pid2 = adns5050_read_reg(REG_PRODUCT_ID2);
|
||||||
|
|
||||||
|
return (pid == 0x12 && rid == 0x01 && pid2 == 0x26);
|
||||||
|
}
|
@ -0,0 +1,79 @@
|
|||||||
|
/* Copyright 2021 Colin Lam (Ploopy Corporation)
|
||||||
|
* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
|
||||||
|
* Copyright 2019 Sunjun Kim
|
||||||
|
* Copyright 2019 Hiroyuki Okada
|
||||||
|
*
|
||||||
|
* 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 <stdbool.h>
|
||||||
|
#include "pins_and_ports.h"
|
||||||
|
|
||||||
|
// CPI values
|
||||||
|
// clang-format off
|
||||||
|
#define CPI125 0x11
|
||||||
|
#define CPI250 0x12
|
||||||
|
#define CPI375 0x13
|
||||||
|
#define CPI500 0x14
|
||||||
|
#define CPI625 0x15
|
||||||
|
#define CPI750 0x16
|
||||||
|
#define CPI875 0x17
|
||||||
|
#define CPI1000 0x18
|
||||||
|
#define CPI1125 0x19
|
||||||
|
#define CPI1250 0x1a
|
||||||
|
#define CPI1375 0x1b
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Definitions for the ADNS serial line.
|
||||||
|
#ifndef ADNS5050_SCLK_PIN
|
||||||
|
# error "No clock pin defined -- missing ADNS5050_SCLK_PIN"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ADNS5050_SDIO_PIN
|
||||||
|
# error "No data pin defined -- missing ADNS5050_SDIO_PIN"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ADNS5050_CS_PIN
|
||||||
|
# error "No chip select pin defined -- missing ADNS5050_CS_PIN"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ADNS5050_SCLK_PIN PIN_B7
|
||||||
|
#define ADNS5050_SDIO_PIN PIN_C6
|
||||||
|
#define ADNS5050_CS_PIN PIN_B4
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int8_t dx;
|
||||||
|
int8_t dy;
|
||||||
|
} report_adns5050_t;
|
||||||
|
|
||||||
|
// A bunch of functions to implement the ADNS5050-specific serial protocol.
|
||||||
|
// Note that the "serial.h" driver is insufficient, because it does not
|
||||||
|
// manually manipulate a serial clock signal.
|
||||||
|
void adns5050_init(void);
|
||||||
|
void adns5050_sync(void);
|
||||||
|
uint8_t adns5050_serial_read(void);
|
||||||
|
void adns5050_serial_write(uint8_t data);
|
||||||
|
uint8_t adns5050_read_reg(uint8_t reg_addr);
|
||||||
|
void adns5050_write_reg(uint8_t reg_addr, uint8_t data);
|
||||||
|
report_adns5050_t adns5050_read_burst(void);
|
||||||
|
void adns5050_set_cpi(uint16_t cpi);
|
||||||
|
uint16_t adns5050_get_cpi(void);
|
||||||
|
int8_t convert_twoscomp(uint8_t data);
|
||||||
|
bool adns5050_check_signature(void);
|
@ -0,0 +1,12 @@
|
|||||||
|
#! /bin/sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "* Building"
|
||||||
|
make OUTPUT_PATH=$(pwd)/_build >/dev/null 2>LOG
|
||||||
|
|
||||||
|
echo "* Jumping to bootloader..."
|
||||||
|
DEVICE=/dev/ttyACM1 focus r
|
||||||
|
sleep 2s
|
||||||
|
|
||||||
|
echo "* Flashing..."
|
||||||
|
dfu-programmer atmega32u4 erase && dfu-programmer atmega32u4 flash _build/*-latest.hex && dfu-programmer atmega32u4 start
|
@ -0,0 +1,164 @@
|
|||||||
|
/* 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(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
|
||||||
|
#define ADDRESS_BASE 0x00
|
||||||
|
#define PINB_ADDRESS 0x3
|
||||||
|
#define PINC_ADDRESS 0x6
|
||||||
|
#define PIND_ADDRESS 0x9
|
||||||
|
#define PINE_ADDRESS 0xC
|
||||||
|
#define PINF_ADDRESS 0xF
|
||||||
|
#elif defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__)
|
||||||
|
#define ADDRESS_BASE 0x00
|
||||||
|
#define PINB_ADDRESS 0x3
|
||||||
|
#define PINC_ADDRESS 0x6
|
||||||
|
#define PIND_ADDRESS 0x9
|
||||||
|
#elif defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__)
|
||||||
|
#define ADDRESS_BASE 0x00
|
||||||
|
#define PINA_ADDRESS 0x0
|
||||||
|
#define PINB_ADDRESS 0x3
|
||||||
|
#define PINC_ADDRESS 0x6
|
||||||
|
#define PIND_ADDRESS 0x9
|
||||||
|
#define PINE_ADDRESS 0xC
|
||||||
|
#define PINF_ADDRESS 0xF
|
||||||
|
#elif defined(__AVR_ATmega32A__)
|
||||||
|
#define ADDRESS_BASE 0x10
|
||||||
|
#define PIND_ADDRESS 0x0
|
||||||
|
#define PINC_ADDRESS 0x3
|
||||||
|
#define PINB_ADDRESS 0x6
|
||||||
|
#define PINA_ADDRESS 0x9
|
||||||
|
#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)))
|
||||||
|
|
||||||
|
#define NO_PIN (uint8_t)(~0)
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"cpu": {
|
||||||
|
"fqbn": "keyboardio:avr:ploopy_mini",
|
||||||
|
"port": ""
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue