Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b201093456 |
||
|
|
55a7482e07 |
||
|
|
973c4588d7 |
||
|
|
bd702ab642 | ||
|
|
464ccfbc66 | ||
|
|
b059dfddb5 | ||
|
|
cbf19a1303 | ||
|
|
bfa233584e | ||
|
|
4e6a1f9acc | ||
|
|
2328012e48 | ||
|
|
f22ffd6816 | ||
|
|
04d147dc5c | ||
|
|
8fd79c3475 | ||
|
|
a0fd310399 | ||
|
|
f280e180a3 | ||
|
|
ec3375e040 | ||
|
|
537195a16b | ||
|
|
85e002d319 | ||
|
|
d5d74632cc | ||
|
|
5ddfbe7cf3 | ||
|
|
746bb85e8a | ||
|
|
15251c37af | ||
|
|
80a5d9b727 | ||
|
|
d2f854f89b |
98 changed files with 5818 additions and 10 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
|
@ -18,3 +18,6 @@
|
||||||
[submodule "lib/printf"]
|
[submodule "lib/printf"]
|
||||||
path = lib/printf
|
path = lib/printf
|
||||||
url = https://github.com/qmk/printf
|
url = https://github.com/qmk/printf
|
||||||
|
[submodule "lib/pico-sdk"]
|
||||||
|
path = lib/pico-sdk
|
||||||
|
url = https://github.com/raspberrypi/pico-sdk
|
||||||
|
|
|
||||||
1
Makefile
1
Makefile
|
|
@ -401,6 +401,7 @@ ifndef SKIP_GIT
|
||||||
if [ ! -e lib/lufa ]; then git submodule sync lib/lufa && git submodule update --depth 50 --init lib/lufa; fi
|
if [ ! -e lib/lufa ]; then git submodule sync lib/lufa && git submodule update --depth 50 --init lib/lufa; fi
|
||||||
if [ ! -e lib/vusb ]; then git submodule sync lib/vusb && git submodule update --depth 50 --init lib/vusb; fi
|
if [ ! -e lib/vusb ]; then git submodule sync lib/vusb && git submodule update --depth 50 --init lib/vusb; fi
|
||||||
if [ ! -e lib/printf ]; then git submodule sync lib/printf && git submodule update --depth 50 --init lib/printf; fi
|
if [ ! -e lib/printf ]; then git submodule sync lib/printf && git submodule update --depth 50 --init lib/printf; fi
|
||||||
|
if [ ! -e lib/pico-sdk ]; then git submodule sync lib/pico-sdk && git submodule update --depth 50 --init lib/pico-sdk; fi
|
||||||
git submodule status --recursive 2>/dev/null | \
|
git submodule status --recursive 2>/dev/null | \
|
||||||
while IFS= read -r x; do \
|
while IFS= read -r x; do \
|
||||||
case "$$x" in \
|
case "$$x" in \
|
||||||
|
|
|
||||||
|
|
@ -213,6 +213,10 @@ ifeq ($(strip $(BOOTLOADER)), md-boot)
|
||||||
OPT_DEFS += -DBOOTLOADER_MD_BOOT
|
OPT_DEFS += -DBOOTLOADER_MD_BOOT
|
||||||
BOOTLOADER_TYPE = md_boot
|
BOOTLOADER_TYPE = md_boot
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(strip $(BOOTLOADER)), RP2040)
|
||||||
|
OPT_DEFS += -DBOOTLOADER_RP2040
|
||||||
|
BOOTLOADER_TYPE = RP2040
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(BOOTLOADER_TYPE)),)
|
ifeq ($(strip $(BOOTLOADER_TYPE)),)
|
||||||
$(call CATASTROPHIC_ERROR,Invalid BOOTLOADER,No bootloader specified. Please set an appropriate 'BOOTLOADER' in your keyboard's 'rules.mk' file.)
|
$(call CATASTROPHIC_ERROR,Invalid BOOTLOADER,No bootloader specified. Please set an appropriate 'BOOTLOADER' in your keyboard's 'rules.mk' file.)
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,18 @@ ifeq ($(strip $(CONVERT_TO_PROTON_C)), yes)
|
||||||
include platforms/chibios/boards/QMK_PROTON_C/convert_to_proton_c.mk
|
include platforms/chibios/boards/QMK_PROTON_C/convert_to_proton_c.mk
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(CTPIM)), yes)
|
||||||
|
CONVERT_TO_PICO_MICRO=yes
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(CONVERT_TO_PICO_MICRO)), yes)
|
||||||
|
include platforms/pico/convert_to_pico_micro.mk
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(FORCE_LAYOUT),)
|
||||||
|
TARGET := $(TARGET)_$(FORCE_LAYOUT)
|
||||||
|
endif
|
||||||
|
|
||||||
include $(BUILDDEFS_PATH)/mcu_selection.mk
|
include $(BUILDDEFS_PATH)/mcu_selection.mk
|
||||||
|
|
||||||
# Find all the C source files to be compiled in subfolders.
|
# Find all the C source files to be compiled in subfolders.
|
||||||
|
|
@ -261,6 +273,13 @@ ifdef MCU_FAMILY
|
||||||
PLATFORM_KEY=chibios
|
PLATFORM_KEY=chibios
|
||||||
FIRMWARE_FORMAT?=bin
|
FIRMWARE_FORMAT?=bin
|
||||||
OPT_DEFS += -DMCU_$(MCU_FAMILY)
|
OPT_DEFS += -DMCU_$(MCU_FAMILY)
|
||||||
|
ifeq ($(MCU_FAMILY),PICO)
|
||||||
|
$(info "PLATFORM RP2040")
|
||||||
|
PLATFORM=PICO_SDK
|
||||||
|
PLATFORM_KEY=pico
|
||||||
|
FIRMWARE_FORMAT=uf2
|
||||||
|
UF2_FAMILY=RP2040
|
||||||
|
endif
|
||||||
else ifdef ARM_ATSAM
|
else ifdef ARM_ATSAM
|
||||||
PLATFORM=ARM_ATSAM
|
PLATFORM=ARM_ATSAM
|
||||||
PLATFORM_KEY=arm_atsam
|
PLATFORM_KEY=arm_atsam
|
||||||
|
|
|
||||||
|
|
@ -211,6 +211,11 @@ else
|
||||||
# arm_atsam EEPROM
|
# arm_atsam EEPROM
|
||||||
OPT_DEFS += -DEEPROM_SAMD
|
OPT_DEFS += -DEEPROM_SAMD
|
||||||
SRC += $(PLATFORM_COMMON_DIR)/eeprom_samd.c
|
SRC += $(PLATFORM_COMMON_DIR)/eeprom_samd.c
|
||||||
|
SRC += $(PLATFORM_COMMON_DIR)/eeprom.c
|
||||||
|
else ifeq ($(PLATFORM),PICO_SDK)
|
||||||
|
OPT_DEFS += -DEEPROM_PICO
|
||||||
|
SRC += $(PLATFORM_COMMON_DIR)/eeprom.c
|
||||||
|
SRC += $(PLATFORM_COMMON_DIR)/flash_pico.c
|
||||||
else ifeq ($(PLATFORM),TEST)
|
else ifeq ($(PLATFORM),TEST)
|
||||||
# Test harness "EEPROM"
|
# Test harness "EEPROM"
|
||||||
OPT_DEFS += -DEEPROM_TEST_HARNESS
|
OPT_DEFS += -DEEPROM_TEST_HARNESS
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ OPT ?= s
|
||||||
# gnu89 = c89 plus GCC extensions
|
# gnu89 = c89 plus GCC extensions
|
||||||
# c99 = ISO C99 standard (not yet fully implemented)
|
# c99 = ISO C99 standard (not yet fully implemented)
|
||||||
# gnu99 = c99 plus GCC extensions
|
# gnu99 = c99 plus GCC extensions
|
||||||
CSTANDARD = -std=gnu99
|
CSTANDARD = -std=gnu11
|
||||||
|
|
||||||
|
|
||||||
# Place -D or -U options here for C sources
|
# Place -D or -U options here for C sources
|
||||||
|
|
@ -86,8 +86,12 @@ ifeq ($(strip $(LTO_ENABLE)), yes)
|
||||||
$(info Enabling LTO on ChibiOS-targeting boards is known to have a high likelihood of failure.)
|
$(info Enabling LTO on ChibiOS-targeting boards is known to have a high likelihood of failure.)
|
||||||
$(info If unsure, set LTO_ENABLE = no.)
|
$(info If unsure, set LTO_ENABLE = no.)
|
||||||
endif
|
endif
|
||||||
CDEFS += -flto
|
ifeq ($(PLATFORM),PICO_SDK)
|
||||||
CDEFS += -DLTO_ENABLE
|
$(info LTO is not available for this platform. Disabled automatically.)
|
||||||
|
else
|
||||||
|
CDEFS += -flto
|
||||||
|
CDEFS += -DLTO_ENABLE
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
DEBUG_ENABLE ?= yes
|
DEBUG_ENABLE ?= yes
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,10 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^LINE_PIN\\d{1,2}$"
|
"pattern": "^LINE_PIN\\d{1,2}$"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^\\d{1,2}$"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"multipleOf": 1
|
"multipleOf": 1
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@
|
||||||
},
|
},
|
||||||
"bootloader": {
|
"bootloader": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["atmel-dfu", "bootloadhid", "bootloadHID", "custom", "caterina", "halfkay", "kiibohd", "lufa-dfu", "lufa-ms", "md-boot", "qmk-dfu", "qmk-hid", "stm32-dfu", "stm32duino", "gd32v-dfu", "wb32-dfu", "unknown", "usbasploader", "USBasp", "tinyuf2", "vibl"],
|
"enum": ["atmel-dfu", "bootloadhid", "bootloadHID", "custom", "caterina", "halfkay", "kiibohd", "lufa-dfu", "lufa-ms", "md-boot", "qmk-dfu", "qmk-hid", "stm32-dfu", "stm32duino", "gd32v-dfu", "wb32-dfu", "unknown", "usbasploader", "USBasp", "tinyuf2", "vibl", "RP2040"],
|
||||||
},
|
},
|
||||||
"bootloader_instructions": {
|
"bootloader_instructions": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|
|
||||||
155
keyboards/rp2040_example/config.h
Normal file
155
keyboards/rp2040_example/config.h
Normal file
|
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 sekigon-gonnoc
|
||||||
|
|
||||||
|
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 sekigon-gonnoc
|
||||||
|
#define PRODUCT rp2040_example
|
||||||
|
|
||||||
|
/* key matrix size */
|
||||||
|
#define MATRIX_ROWS 2
|
||||||
|
#define MATRIX_COLS 3
|
||||||
|
|
||||||
|
#define DEBUG_MATRIX_SCAN_RATE
|
||||||
|
#define DEBUG_ACTION
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Keyboard Matrix Assignments
|
||||||
|
*
|
||||||
|
* Change this to how you wired your keyboard
|
||||||
|
* COLS: AVR pins used for columns, left to right
|
||||||
|
* ROWS: AVR pins used for rows, top to bottom
|
||||||
|
* DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode)
|
||||||
|
* ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define MATRIX_ROW_PINS { 0, 1 }
|
||||||
|
#define MATRIX_COL_PINS { 2, 3, 4 }
|
||||||
|
#define UNUSED_PINS
|
||||||
|
|
||||||
|
/* COL2ROW, ROW2COL */
|
||||||
|
#define DIODE_DIRECTION COL2ROW
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Split Keyboard specific options, make sure you have 'SPLIT_KEYBOARD = yes' in your rules.mk, and define SOFT_SERIAL_PIN.
|
||||||
|
*/
|
||||||
|
#define SOFT_SERIAL_PIN D0 // or D1, D2, D3, E6
|
||||||
|
|
||||||
|
//#define LED_NUM_LOCK_PIN B0
|
||||||
|
//#define LED_CAPS_LOCK_PIN B1
|
||||||
|
//#define LED_SCROLL_LOCK_PIN B2
|
||||||
|
//#define LED_COMPOSE_PIN B3
|
||||||
|
//#define LED_KANA_PIN B4
|
||||||
|
|
||||||
|
//#define BACKLIGHT_PIN B7
|
||||||
|
//#define BACKLIGHT_LEVELS 3
|
||||||
|
//#define BACKLIGHT_BREATHING
|
||||||
|
|
||||||
|
//#define RGB_DI_PIN E2
|
||||||
|
//#ifdef RGB_DI_PIN
|
||||||
|
//# define RGBLED_NUM 16
|
||||||
|
//# define RGBLIGHT_HUE_STEP 8
|
||||||
|
//# define RGBLIGHT_SAT_STEP 8
|
||||||
|
//# define RGBLIGHT_VAL_STEP 8
|
||||||
|
//# define RGBLIGHT_LIMIT_VAL 255 /* The maximum brightness level */
|
||||||
|
//# define RGBLIGHT_SLEEP /* If defined, the RGB lighting will be switched off when the host goes to sleep */
|
||||||
|
/*== all animations enable ==*/
|
||||||
|
//# define RGBLIGHT_ANIMATIONS
|
||||||
|
/*== or choose animations ==*/
|
||||||
|
//# define RGBLIGHT_EFFECT_BREATHING
|
||||||
|
//# define RGBLIGHT_EFFECT_RAINBOW_MOOD
|
||||||
|
//# define RGBLIGHT_EFFECT_RAINBOW_SWIRL
|
||||||
|
//# define RGBLIGHT_EFFECT_SNAKE
|
||||||
|
//# define RGBLIGHT_EFFECT_KNIGHT
|
||||||
|
//# define RGBLIGHT_EFFECT_CHRISTMAS
|
||||||
|
//# define RGBLIGHT_EFFECT_STATIC_GRADIENT
|
||||||
|
//# define RGBLIGHT_EFFECT_RGB_TEST
|
||||||
|
//# define RGBLIGHT_EFFECT_ALTERNATING
|
||||||
|
/*== customize breathing effect ==*/
|
||||||
|
/*==== (DEFAULT) use fixed table instead of exp() and sin() ====*/
|
||||||
|
//# define RGBLIGHT_BREATHE_TABLE_SIZE 256 // 256(default) or 128 or 64
|
||||||
|
/*==== use exp() and sin() ====*/
|
||||||
|
//# define RGBLIGHT_EFFECT_BREATHE_CENTER 1.85 // 1 to 2.7
|
||||||
|
//# define RGBLIGHT_EFFECT_BREATHE_MAX 255 // 0 to 255
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
|
||||||
|
#define DEBOUNCE 5
|
||||||
|
|
||||||
|
/* define if matrix has ghost (lacks anti-ghosting diodes) */
|
||||||
|
//#define MATRIX_HAS_GHOST
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
/* If defined, GRAVE_ESC will always act as ESC when CTRL is held.
|
||||||
|
* This is useful for the Windows task manager shortcut (ctrl+shift+esc).
|
||||||
|
*/
|
||||||
|
//#define GRAVE_ESC_CTRL_OVERRIDE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Force NKRO
|
||||||
|
*
|
||||||
|
* Force NKRO (nKey Rollover) to be enabled by default, regardless of the saved
|
||||||
|
* state in the bootmagic EEPROM settings. (Note that NKRO must be enabled in the
|
||||||
|
* makefile for this to work.)
|
||||||
|
*
|
||||||
|
* If forced on, NKRO can be disabled via magic key (default = LShift+RShift+N)
|
||||||
|
* until the next keyboard reset.
|
||||||
|
*
|
||||||
|
* NKRO may prevent your keystrokes from being detected in the BIOS, but it is
|
||||||
|
* fully operational during normal computer usage.
|
||||||
|
*
|
||||||
|
* For a less heavy-handed approach, enable NKRO via magic key (LShift+RShift+N)
|
||||||
|
* or via bootmagic (hold SPACE+N while plugging in the keyboard). Once set by
|
||||||
|
* bootmagic, NKRO mode will always be enabled until it is toggled again during a
|
||||||
|
* power-up.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//#define FORCE_NKRO
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
/* disable these deprecated features by default */
|
||||||
|
#define NO_ACTION_MACRO
|
||||||
|
#define NO_ACTION_FUNCTION
|
||||||
|
|
||||||
|
/* Bootmagic Lite key configuration */
|
||||||
|
//#define BOOTMAGIC_LITE_ROW 0
|
||||||
|
//#define BOOTMAGIC_LITE_COLUMN 0
|
||||||
19
keyboards/rp2040_example/info.json
Normal file
19
keyboards/rp2040_example/info.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"keyboard_name": "rp2040_example",
|
||||||
|
"url": "",
|
||||||
|
"maintainer": "sekigon-gonnoc",
|
||||||
|
"width": 3,
|
||||||
|
"height": 2,
|
||||||
|
"layouts": {
|
||||||
|
"LAYOUT": {
|
||||||
|
"layout": [
|
||||||
|
{"label": "k00", "x": 0, "y": 0},
|
||||||
|
{"label": "k01", "x": 1, "y": 0},
|
||||||
|
{"label": "k02", "x": 2, "y": 0},
|
||||||
|
|
||||||
|
{"label": "k10", "x": 0, "y": 1, "w": 1.5},
|
||||||
|
{"label": "k12", "x": 1.5, "y": 1, "w": 1.5}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
73
keyboards/rp2040_example/keymaps/adc/keymap.c
Normal file
73
keyboards/rp2040_example/keymaps/adc/keymap.c
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
#include "pico_eeprom.h"
|
||||||
|
#include "analog.h"
|
||||||
|
|
||||||
|
// Defines names for use in layer keycodes and the keymap
|
||||||
|
enum layer_names {
|
||||||
|
_BASE,
|
||||||
|
_FN
|
||||||
|
};
|
||||||
|
|
||||||
|
// Defines the keycodes used by our macros in process_record_user
|
||||||
|
enum custom_keycodes {
|
||||||
|
QMKBEST = SAFE_RANGE,
|
||||||
|
QMKURL
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
|
/* Base */
|
||||||
|
[_BASE] = LAYOUT(
|
||||||
|
KC_A, KC_1, MO(_FN),
|
||||||
|
KC_TAB, KC_SPC
|
||||||
|
),
|
||||||
|
[_FN] = LAYOUT(
|
||||||
|
QMKBEST, QMKURL, _______,
|
||||||
|
RESET, XXXXXXX
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||||
|
switch (keycode) {
|
||||||
|
case QMKBEST:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
// when keycode QMKBEST is pressed
|
||||||
|
SEND_STRING("QMK is the best thing ever!");
|
||||||
|
} else {
|
||||||
|
// when keycode QMKBEST is released
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QMKURL:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
// when keycode QMKURL is pressed
|
||||||
|
SEND_STRING("https://qmk.fm/\n");
|
||||||
|
} else {
|
||||||
|
// when keycode QMKURL is released
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void matrix_scan_user(void) {
|
||||||
|
static int cnt = 0;
|
||||||
|
if (++cnt == 1000) {
|
||||||
|
cnt = 0;
|
||||||
|
int16_t ad = analogReadPin(26);
|
||||||
|
printf("ADC:%d\n", ad);
|
||||||
|
}
|
||||||
|
}
|
||||||
1
keyboards/rp2040_example/keymaps/adc/readme.md
Normal file
1
keyboards/rp2040_example/keymaps/adc/readme.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
# The default keymap for rp2040_example
|
||||||
2
keyboards/rp2040_example/keymaps/adc/rules.mk
Normal file
2
keyboards/rp2040_example/keymaps/adc/rules.mk
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
SRC += analog.c
|
||||||
62
keyboards/rp2040_example/keymaps/default/keymap.c
Normal file
62
keyboards/rp2040_example/keymaps/default/keymap.c
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
// Defines names for use in layer keycodes and the keymap
|
||||||
|
enum layer_names {
|
||||||
|
_BASE,
|
||||||
|
_FN
|
||||||
|
};
|
||||||
|
|
||||||
|
// Defines the keycodes used by our macros in process_record_user
|
||||||
|
enum custom_keycodes {
|
||||||
|
QMKBEST = SAFE_RANGE,
|
||||||
|
QMKURL
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
|
/* Base */
|
||||||
|
[_BASE] = LAYOUT(
|
||||||
|
KC_A, KC_1, MO(_FN),
|
||||||
|
KC_TAB, KC_SPC
|
||||||
|
),
|
||||||
|
[_FN] = LAYOUT(
|
||||||
|
QMKBEST, QMKURL, _______,
|
||||||
|
RESET, XXXXXXX
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||||
|
switch (keycode) {
|
||||||
|
case QMKBEST:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
// when keycode QMKBEST is pressed
|
||||||
|
SEND_STRING("QMK is the best thing ever!");
|
||||||
|
} else {
|
||||||
|
// when keycode QMKBEST is released
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QMKURL:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
// when keycode QMKURL is pressed
|
||||||
|
SEND_STRING("https://qmk.fm/\n");
|
||||||
|
} else {
|
||||||
|
// when keycode QMKURL is released
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
1
keyboards/rp2040_example/keymaps/default/readme.md
Normal file
1
keyboards/rp2040_example/keymaps/default/readme.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
# The default keymap for rp2040_example
|
||||||
6
keyboards/rp2040_example/keymaps/rgblight/config.h
Normal file
6
keyboards/rp2040_example/keymaps/rgblight/config.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define RGB_DI_PIN 5
|
||||||
|
#define RGBLED_NUM 1
|
||||||
|
#define RGBLIGHT_ANIMATIONS
|
||||||
71
keyboards/rp2040_example/keymaps/rgblight/keymap.c
Normal file
71
keyboards/rp2040_example/keymaps/rgblight/keymap.c
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
#include "pico_eeprom.h"
|
||||||
|
|
||||||
|
// Defines names for use in layer keycodes and the keymap
|
||||||
|
enum layer_names {
|
||||||
|
_BASE,
|
||||||
|
_FN
|
||||||
|
};
|
||||||
|
|
||||||
|
// Defines the keycodes used by our macros in process_record_user
|
||||||
|
enum custom_keycodes {
|
||||||
|
QMKBEST = SAFE_RANGE,
|
||||||
|
QMKURL
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
|
/* Base */
|
||||||
|
[_BASE] = LAYOUT(
|
||||||
|
KC_A, KC_1, MO(_FN),
|
||||||
|
KC_TAB, KC_SPC
|
||||||
|
),
|
||||||
|
[_FN] = LAYOUT(
|
||||||
|
QMKBEST, QMKURL, _______,
|
||||||
|
RESET, XXXXXXX
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||||
|
switch (keycode) {
|
||||||
|
case QMKBEST:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
// when keycode QMKBEST is pressed
|
||||||
|
SEND_STRING("QMK is the best thing ever!");
|
||||||
|
} else {
|
||||||
|
// when keycode QMKBEST is released
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QMKURL:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
// when keycode QMKURL is pressed
|
||||||
|
SEND_STRING("https://qmk.fm/\n");
|
||||||
|
} else {
|
||||||
|
// when keycode QMKURL is released
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "rgblight.h"
|
||||||
|
|
||||||
|
void keyboard_post_init_user(void) {
|
||||||
|
rgblight_enable();
|
||||||
|
rgblight_mode_noeeprom(35);
|
||||||
|
}
|
||||||
|
|
||||||
1
keyboards/rp2040_example/keymaps/rgblight/readme.md
Normal file
1
keyboards/rp2040_example/keymaps/rgblight/readme.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
# The default keymap for rp2040_example
|
||||||
2
keyboards/rp2040_example/keymaps/rgblight/rules.mk
Normal file
2
keyboards/rp2040_example/keymaps/rgblight/rules.mk
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
RGBLIGHT_ENABLE = yes
|
||||||
24
keyboards/rp2040_example/readme.md
Normal file
24
keyboards/rp2040_example/readme.md
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# rp2040_example
|
||||||
|
|
||||||
|
* Sample implementation for RP2040.
|
||||||
|
|
||||||
|
* Keyboard Maintainer: [sekigon-gonnoc](https://github.com/sekigon-gonnoc)
|
||||||
|
|
||||||
|
Make example for this keyboard (after setting up your build environment):
|
||||||
|
|
||||||
|
make rp2040_example:default
|
||||||
|
|
||||||
|
Flashing example for this keyboard by `picotool`:
|
||||||
|
|
||||||
|
make rp2040_example:default:flash
|
||||||
|
|
||||||
|
Convert firmware into uf2 format:
|
||||||
|
|
||||||
|
make rp2040_example:default:uf2
|
||||||
|
|
||||||
|
To replace Pro Micro to Pico Micro, use `CTPIM=yes` (`CONVERT_TO_PICO_MICRO=yes`):
|
||||||
|
|
||||||
|
make <your_keyboard>:<your_keyamp>:<output option> CTPIM=yes
|
||||||
|
|
||||||
|
|
||||||
|
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).
|
||||||
24
keyboards/rp2040_example/rp2040_example.c
Normal file
24
keyboards/rp2040_example/rp2040_example.c
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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 "rp2040_example.h"
|
||||||
|
|
||||||
|
void keyboard_post_init_kb(void) {
|
||||||
|
debug_enable = true;
|
||||||
|
debug_keyboard = true;
|
||||||
|
|
||||||
|
keyboard_post_init_user();
|
||||||
|
}
|
||||||
35
keyboards/rp2040_example/rp2040_example.h
Normal file
35
keyboards/rp2040_example/rp2040_example.h
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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 "quantum.h"
|
||||||
|
|
||||||
|
/* This is a shortcut to help you visually see your layout.
|
||||||
|
*
|
||||||
|
* The first section contains all of the arguments representing the physical
|
||||||
|
* layout of the board and position of the keys.
|
||||||
|
*
|
||||||
|
* The second converts the arguments into a two-dimensional array which
|
||||||
|
* represents the switch matrix.
|
||||||
|
*/
|
||||||
|
#define LAYOUT( \
|
||||||
|
k00, k01, k02, \
|
||||||
|
k10, k12 \
|
||||||
|
) { \
|
||||||
|
{ k00, k01, k02 }, \
|
||||||
|
{ k10, KC_NO, k12 } \
|
||||||
|
}
|
||||||
23
keyboards/rp2040_example/rules.mk
Normal file
23
keyboards/rp2040_example/rules.mk
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# MCU name
|
||||||
|
MCU_FAMILY = PICO
|
||||||
|
MCU_SERIES = RP2040
|
||||||
|
MCU = cortex-m0plus
|
||||||
|
|
||||||
|
VIA_ENABLE = yes
|
||||||
|
|
||||||
|
# Build Options
|
||||||
|
# change yes to no to disable
|
||||||
|
#
|
||||||
|
BOOTMAGIC_ENABLE = lite # Virtual DIP switch configuration
|
||||||
|
MOUSEKEY_ENABLE = yes # Mouse keys
|
||||||
|
EXTRAKEY_ENABLE = yes # Audio control and System control
|
||||||
|
CONSOLE_ENABLE = yes # Console for debug
|
||||||
|
COMMAND_ENABLE = no # 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
|
||||||
|
RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
|
||||||
|
BLUETOOTH_ENABLE = no # Enable Bluetooth
|
||||||
|
AUDIO_ENABLE = no # Audio output
|
||||||
157
keyboards/rp2040_split/config.h
Normal file
157
keyboards/rp2040_split/config.h
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 sekigon-gonnoc
|
||||||
|
|
||||||
|
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 sekigon-gonnoc
|
||||||
|
#define PRODUCT rp2040_split
|
||||||
|
|
||||||
|
/* key matrix size */
|
||||||
|
#define MATRIX_ROWS 4
|
||||||
|
#define MATRIX_COLS 3
|
||||||
|
|
||||||
|
#define DEBUG_MATRIX_SCAN_RATE
|
||||||
|
#define DEBUG_ACTION
|
||||||
|
|
||||||
|
#define MASTER_LEFT
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Keyboard Matrix Assignments
|
||||||
|
*
|
||||||
|
* Change this to how you wired your keyboard
|
||||||
|
* COLS: AVR pins used for columns, left to right
|
||||||
|
* ROWS: AVR pins used for rows, top to bottom
|
||||||
|
* DIODE_DIRECTION: COL2ROW = COL = Anode (+), ROW = Cathode (-, marked on diode)
|
||||||
|
* ROW2COL = ROW = Anode (+), COL = Cathode (-, marked on diode)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define MATRIX_ROW_PINS { 0, 1 }
|
||||||
|
#define MATRIX_COL_PINS { 2, 3, 4 }
|
||||||
|
#define UNUSED_PINS
|
||||||
|
|
||||||
|
/* COL2ROW, ROW2COL */
|
||||||
|
#define DIODE_DIRECTION COL2ROW
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Split Keyboard specific options, make sure you have 'SPLIT_KEYBOARD = yes' in your rules.mk, and define SOFT_SERIAL_PIN.
|
||||||
|
*/
|
||||||
|
#define SOFT_SERIAL_PIN 6
|
||||||
|
|
||||||
|
//#define LED_NUM_LOCK_PIN B0
|
||||||
|
//#define LED_CAPS_LOCK_PIN B1
|
||||||
|
//#define LED_SCROLL_LOCK_PIN B2
|
||||||
|
//#define LED_COMPOSE_PIN B3
|
||||||
|
//#define LED_KANA_PIN B4
|
||||||
|
|
||||||
|
//#define BACKLIGHT_PIN B7
|
||||||
|
//#define BACKLIGHT_LEVELS 3
|
||||||
|
//#define BACKLIGHT_BREATHING
|
||||||
|
|
||||||
|
//#define RGB_DI_PIN E2
|
||||||
|
//#ifdef RGB_DI_PIN
|
||||||
|
//# define RGBLED_NUM 16
|
||||||
|
//# define RGBLIGHT_HUE_STEP 8
|
||||||
|
//# define RGBLIGHT_SAT_STEP 8
|
||||||
|
//# define RGBLIGHT_VAL_STEP 8
|
||||||
|
//# define RGBLIGHT_LIMIT_VAL 255 /* The maximum brightness level */
|
||||||
|
//# define RGBLIGHT_SLEEP /* If defined, the RGB lighting will be switched off when the host goes to sleep */
|
||||||
|
/*== all animations enable ==*/
|
||||||
|
//# define RGBLIGHT_ANIMATIONS
|
||||||
|
/*== or choose animations ==*/
|
||||||
|
//# define RGBLIGHT_EFFECT_BREATHING
|
||||||
|
//# define RGBLIGHT_EFFECT_RAINBOW_MOOD
|
||||||
|
//# define RGBLIGHT_EFFECT_RAINBOW_SWIRL
|
||||||
|
//# define RGBLIGHT_EFFECT_SNAKE
|
||||||
|
//# define RGBLIGHT_EFFECT_KNIGHT
|
||||||
|
//# define RGBLIGHT_EFFECT_CHRISTMAS
|
||||||
|
//# define RGBLIGHT_EFFECT_STATIC_GRADIENT
|
||||||
|
//# define RGBLIGHT_EFFECT_RGB_TEST
|
||||||
|
//# define RGBLIGHT_EFFECT_ALTERNATING
|
||||||
|
/*== customize breathing effect ==*/
|
||||||
|
/*==== (DEFAULT) use fixed table instead of exp() and sin() ====*/
|
||||||
|
//# define RGBLIGHT_BREATHE_TABLE_SIZE 256 // 256(default) or 128 or 64
|
||||||
|
/*==== use exp() and sin() ====*/
|
||||||
|
//# define RGBLIGHT_EFFECT_BREATHE_CENTER 1.85 // 1 to 2.7
|
||||||
|
//# define RGBLIGHT_EFFECT_BREATHE_MAX 255 // 0 to 255
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
/* Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed */
|
||||||
|
#define DEBOUNCE 5
|
||||||
|
|
||||||
|
/* define if matrix has ghost (lacks anti-ghosting diodes) */
|
||||||
|
//#define MATRIX_HAS_GHOST
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
/* If defined, GRAVE_ESC will always act as ESC when CTRL is held.
|
||||||
|
* This is useful for the Windows task manager shortcut (ctrl+shift+esc).
|
||||||
|
*/
|
||||||
|
//#define GRAVE_ESC_CTRL_OVERRIDE
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Force NKRO
|
||||||
|
*
|
||||||
|
* Force NKRO (nKey Rollover) to be enabled by default, regardless of the saved
|
||||||
|
* state in the bootmagic EEPROM settings. (Note that NKRO must be enabled in the
|
||||||
|
* makefile for this to work.)
|
||||||
|
*
|
||||||
|
* If forced on, NKRO can be disabled via magic key (default = LShift+RShift+N)
|
||||||
|
* until the next keyboard reset.
|
||||||
|
*
|
||||||
|
* NKRO may prevent your keystrokes from being detected in the BIOS, but it is
|
||||||
|
* fully operational during normal computer usage.
|
||||||
|
*
|
||||||
|
* For a less heavy-handed approach, enable NKRO via magic key (LShift+RShift+N)
|
||||||
|
* or via bootmagic (hold SPACE+N while plugging in the keyboard). Once set by
|
||||||
|
* bootmagic, NKRO mode will always be enabled until it is toggled again during a
|
||||||
|
* power-up.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
//#define FORCE_NKRO
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
/* disable these deprecated features by default */
|
||||||
|
#define NO_ACTION_MACRO
|
||||||
|
#define NO_ACTION_FUNCTION
|
||||||
|
|
||||||
|
/* Bootmagic Lite key configuration */
|
||||||
|
//#define BOOTMAGIC_LITE_ROW 0
|
||||||
|
//#define BOOTMAGIC_LITE_COLUMN 0
|
||||||
19
keyboards/rp2040_split/info.json
Normal file
19
keyboards/rp2040_split/info.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"keyboard_name": "rp2040_split",
|
||||||
|
"url": "",
|
||||||
|
"maintainer": "sekigon-gonnoc",
|
||||||
|
"width": 3,
|
||||||
|
"height": 2,
|
||||||
|
"layouts": {
|
||||||
|
"LAYOUT": {
|
||||||
|
"layout": [
|
||||||
|
{"label": "k00", "x": 0, "y": 0},
|
||||||
|
{"label": "k01", "x": 1, "y": 0},
|
||||||
|
{"label": "k02", "x": 2, "y": 0},
|
||||||
|
|
||||||
|
{"label": "k10", "x": 0, "y": 1, "w": 1.5},
|
||||||
|
{"label": "k12", "x": 1.5, "y": 1, "w": 1.5}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
67
keyboards/rp2040_split/keymaps/default/keymap.c
Normal file
67
keyboards/rp2040_split/keymaps/default/keymap.c
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
// Defines names for use in layer keycodes and the keymap
|
||||||
|
enum layer_names {
|
||||||
|
_BASE,
|
||||||
|
_FN
|
||||||
|
};
|
||||||
|
|
||||||
|
// Defines the keycodes used by our macros in process_record_user
|
||||||
|
enum custom_keycodes {
|
||||||
|
QMKBEST = SAFE_RANGE,
|
||||||
|
QMKURL
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
|
/* Base */
|
||||||
|
[_BASE] = LAYOUT(
|
||||||
|
KC_A, KC_B, MO(_FN),
|
||||||
|
KC_TAB, KC_SPC, KC_ENT,
|
||||||
|
KC_C, KC_D, MO(_FN),
|
||||||
|
KC_TAB, KC_SPC, KC_ENT
|
||||||
|
),
|
||||||
|
[_FN] = LAYOUT(
|
||||||
|
QMKBEST, QMKURL, _______,
|
||||||
|
RESET, XXXXXXX, XXXXXXX,
|
||||||
|
QMKBEST, QMKURL, _______,
|
||||||
|
RESET, XXXXXXX, XXXXXXX
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||||
|
switch (keycode) {
|
||||||
|
case QMKBEST:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
// when keycode QMKBEST is pressed
|
||||||
|
SEND_STRING("QMK is the best thing ever!");
|
||||||
|
} else {
|
||||||
|
// when keycode QMKBEST is released
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case QMKURL:
|
||||||
|
if (record->event.pressed) {
|
||||||
|
// when keycode QMKURL is pressed
|
||||||
|
SEND_STRING("https://qmk.fm/\n");
|
||||||
|
} else {
|
||||||
|
// when keycode QMKURL is released
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
1
keyboards/rp2040_split/keymaps/default/readme.md
Normal file
1
keyboards/rp2040_split/keymaps/default/readme.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
# The default keymap for rp2040_split
|
||||||
26
keyboards/rp2040_split/readme.md
Normal file
26
keyboards/rp2040_split/readme.md
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
# rp2040_split
|
||||||
|
|
||||||
|
* Sample implementation for RP2040.
|
||||||
|
|
||||||
|
* Keyboard Maintainer: [sekigon-gonnoc](https://github.com/sekigon-gonnoc)
|
||||||
|
|
||||||
|
Since RP2040 does not have VBUS detect ports, `SPLIT_USB_DETECT` is enabled automatically.
|
||||||
|
|
||||||
|
Make split for this keyboard (after setting up your build environment):
|
||||||
|
|
||||||
|
make rp2040_split:default
|
||||||
|
|
||||||
|
Flashing split for this keyboard by `picotool`:
|
||||||
|
|
||||||
|
make rp2040_split:default:flash
|
||||||
|
|
||||||
|
Convert firmware into uf2 format:
|
||||||
|
|
||||||
|
make rp2040_split:default:uf2
|
||||||
|
|
||||||
|
To replace Pro Micro to Pico Micro, use `CTPIM=yes` (`CONVERT_TO_PICO_MICRO=yes`):
|
||||||
|
|
||||||
|
make <your_keyboard>:<your_keyamp>:<output option> CTPIM=yes
|
||||||
|
|
||||||
|
|
||||||
|
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).
|
||||||
23
keyboards/rp2040_split/rp2040_split.c
Normal file
23
keyboards/rp2040_split/rp2040_split.c
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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 "rp2040_split.h"
|
||||||
|
|
||||||
|
void keyboard_post_init_kb(void) {
|
||||||
|
debug_enable = true;
|
||||||
|
debug_matrix = true;
|
||||||
|
keyboard_post_init_user();
|
||||||
|
}
|
||||||
39
keyboards/rp2040_split/rp2040_split.h
Normal file
39
keyboards/rp2040_split/rp2040_split.h
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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 "quantum.h"
|
||||||
|
|
||||||
|
/* This is a shortcut to help you visually see your layout.
|
||||||
|
*
|
||||||
|
* The first section contains all of the arguments representing the physical
|
||||||
|
* layout of the board and position of the keys.
|
||||||
|
*
|
||||||
|
* The second converts the arguments into a two-dimensional array which
|
||||||
|
* represents the switch matrix.
|
||||||
|
*/
|
||||||
|
#define LAYOUT( \
|
||||||
|
k00, k01, k02, \
|
||||||
|
k10, k11, k12, \
|
||||||
|
k20, k21, k22, \
|
||||||
|
k30, k31, k32 \
|
||||||
|
) { \
|
||||||
|
{ k00, k01, k02 }, \
|
||||||
|
{ k10, k11, k12 }, \
|
||||||
|
{ k20, k21, k22 }, \
|
||||||
|
{ k30, k31, k32 }, \
|
||||||
|
}
|
||||||
24
keyboards/rp2040_split/rules.mk
Normal file
24
keyboards/rp2040_split/rules.mk
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# MCU name
|
||||||
|
MCU_FAMILY = PICO
|
||||||
|
MCU_SERIES = RP2040
|
||||||
|
MCU = cortex-m0plus
|
||||||
|
|
||||||
|
SPLIT_KEYBOARD = yes
|
||||||
|
VIA_ENABLE = yes
|
||||||
|
|
||||||
|
# Build Options
|
||||||
|
# change yes to no to disable
|
||||||
|
#
|
||||||
|
BOOTMAGIC_ENABLE = lite # Virtual DIP switch configuration
|
||||||
|
MOUSEKEY_ENABLE = yes # Mouse keys
|
||||||
|
EXTRAKEY_ENABLE = yes # Audio control and System control
|
||||||
|
CONSOLE_ENABLE = yes # Console for debug
|
||||||
|
COMMAND_ENABLE = no # 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
|
||||||
|
RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
|
||||||
|
BLUETOOTH_ENABLE = no # Enable Bluetooth
|
||||||
|
AUDIO_ENABLE = no # Audio output
|
||||||
27
keyboards/vial_example/vial_rp2040/config.h
Normal file
27
keyboards/vial_example/vial_rp2040/config.h
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/* USB Device descriptor parameter */
|
||||||
|
#define VENDOR_ID 0xFEED
|
||||||
|
#define PRODUCT_ID 0x0000
|
||||||
|
#define DEVICE_VER 0x0001
|
||||||
|
#define MANUFACTURER Vial
|
||||||
|
#define PRODUCT RP2040 example
|
||||||
|
|
||||||
|
/* key matrix size */
|
||||||
|
#define MATRIX_ROWS 2
|
||||||
|
#define MATRIX_COLS 2
|
||||||
|
|
||||||
|
#define MATRIX_ROW_PINS { 0, 1 }
|
||||||
|
#define MATRIX_COL_PINS { 2, 3 }
|
||||||
|
|
||||||
|
#define DIODE_DIRECTION COL2ROW
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
/* Use 1000hz polling */
|
||||||
|
#define USB_POLLING_INTERVAL_MS 1
|
||||||
15
keyboards/vial_example/vial_rp2040/keymaps/default/keymap.c
Normal file
15
keyboards/vial_example/vial_rp2040/keymaps/default/keymap.c
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#include QMK_KEYBOARD_H
|
||||||
|
|
||||||
|
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
|
[0] = LAYOUT(
|
||||||
|
KC_1, KC_2,
|
||||||
|
KC_3, KC_4
|
||||||
|
),
|
||||||
|
|
||||||
|
[1] = LAYOUT(
|
||||||
|
KC_A, KC_B,
|
||||||
|
KC_C, KC_D
|
||||||
|
)
|
||||||
|
};
|
||||||
7
keyboards/vial_example/vial_rp2040/keymaps/vial/config.h
Normal file
7
keyboards/vial_example/vial_rp2040/keymaps/vial/config.h
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define VIAL_KEYBOARD_UID {0x03, 0x35, 0x69, 0xE1, 0x5C, 0x42, 0xD9, 0x5E}
|
||||||
|
#define VIAL_UNLOCK_COMBO_ROWS {0, 1}
|
||||||
|
#define VIAL_UNLOCK_COMBO_COLS {0, 1}
|
||||||
25
keyboards/vial_example/vial_rp2040/keymaps/vial/keymap.c
Normal file
25
keyboards/vial_example/vial_rp2040/keymaps/vial/keymap.c
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#include QMK_KEYBOARD_H
|
||||||
|
|
||||||
|
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
|
[0] = LAYOUT(
|
||||||
|
KC_1, KC_2,
|
||||||
|
KC_3, KC_4
|
||||||
|
),
|
||||||
|
|
||||||
|
[1] = LAYOUT(
|
||||||
|
KC_A, KC_B,
|
||||||
|
KC_C, KC_D
|
||||||
|
),
|
||||||
|
|
||||||
|
[2] = LAYOUT(
|
||||||
|
KC_TRNS, KC_TRNS,
|
||||||
|
KC_TRNS, KC_TRNS
|
||||||
|
),
|
||||||
|
|
||||||
|
[3] = LAYOUT(
|
||||||
|
KC_TRNS, KC_TRNS,
|
||||||
|
KC_TRNS, KC_TRNS
|
||||||
|
)
|
||||||
|
};
|
||||||
2
keyboards/vial_example/vial_rp2040/keymaps/vial/rules.mk
Normal file
2
keyboards/vial_example/vial_rp2040/keymaps/vial/rules.mk
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
VIA_ENABLE = yes
|
||||||
|
VIAL_ENABLE = yes
|
||||||
19
keyboards/vial_example/vial_rp2040/keymaps/vial/vial.json
Normal file
19
keyboards/vial_example/vial_rp2040/keymaps/vial/vial.json
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"name": "Vial RP2040 Example",
|
||||||
|
"matrix": {
|
||||||
|
"rows": 2,
|
||||||
|
"cols": 2
|
||||||
|
},
|
||||||
|
"layouts": {
|
||||||
|
"keymap": [
|
||||||
|
[
|
||||||
|
"0,0",
|
||||||
|
"0,1"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"1,0",
|
||||||
|
"1,1"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
22
keyboards/vial_example/vial_rp2040/rules.mk
Normal file
22
keyboards/vial_example/vial_rp2040/rules.mk
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# MCU name
|
||||||
|
MCU_FAMILY = PICO
|
||||||
|
MCU_SERIES = RP2040
|
||||||
|
BOOTLOADER = RP2040
|
||||||
|
MCU = cortex-m0plus
|
||||||
|
|
||||||
|
# Build Options
|
||||||
|
# change yes to no to disable
|
||||||
|
#
|
||||||
|
BOOTMAGIC_ENABLE = yes
|
||||||
|
MOUSEKEY_ENABLE = yes # Mouse keys
|
||||||
|
EXTRAKEY_ENABLE = yes # Audio control and System control
|
||||||
|
CONSOLE_ENABLE = no # Console for debug
|
||||||
|
COMMAND_ENABLE = no # 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
|
||||||
|
RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
|
||||||
|
BLUETOOTH_ENABLE = no # Enable Bluetooth
|
||||||
|
AUDIO_ENABLE = no # Audio output
|
||||||
3
keyboards/vial_example/vial_rp2040/vial_rp2040.c
Normal file
3
keyboards/vial_example/vial_rp2040/vial_rp2040.c
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#include "vial_rp2040.h"
|
||||||
13
keyboards/vial_example/vial_rp2040/vial_rp2040.h
Normal file
13
keyboards/vial_example/vial_rp2040/vial_rp2040.h
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "quantum.h"
|
||||||
|
|
||||||
|
#define LAYOUT( \
|
||||||
|
K00, K01, \
|
||||||
|
K10, K11 \
|
||||||
|
) { \
|
||||||
|
{ K00, K01 }, \
|
||||||
|
{ K10, K11 } \
|
||||||
|
}
|
||||||
1
lib/pico-sdk
Submodule
1
lib/pico-sdk
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 2062372d203b372849d573f252cf7c6dc2800c0a
|
||||||
|
|
@ -48,6 +48,9 @@ void eeprom_update_block(const void *__src, void *__dst, size_t __n);
|
||||||
#elif defined(EEPROM_SAMD)
|
#elif defined(EEPROM_SAMD)
|
||||||
# include "eeprom_samd.h"
|
# include "eeprom_samd.h"
|
||||||
# define TOTAL_EEPROM_BYTE_COUNT (EEPROM_SIZE)
|
# define TOTAL_EEPROM_BYTE_COUNT (EEPROM_SIZE)
|
||||||
|
#elif defined(EEPROM_PICO)
|
||||||
|
# include "eeprom_pico_defs.h"
|
||||||
|
# define TOTAL_EEPROM_BYTE_COUNT (FEE_DENSITY_BYTES)
|
||||||
#elif defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATtiny85__)
|
#elif defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATtiny85__)
|
||||||
# define TOTAL_EEPROM_BYTE_COUNT 512
|
# define TOTAL_EEPROM_BYTE_COUNT 512
|
||||||
#elif defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32A__)
|
#elif defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32A__)
|
||||||
|
|
|
||||||
36
platforms/pico/_print.h
Normal file
36
platforms/pico/_print.h
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* Copyright 2012 Jun Wako <wakojun@gmail.com> */
|
||||||
|
/* Very basic print functions, intended to be used with usb_debug_only.c
|
||||||
|
* http://www.pjrc.com/teensy/
|
||||||
|
* Copyright (c) 2008 PJRC.COM, LLC
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
// Create user & normal print defines
|
||||||
|
#define xprintf(...) printf(__VA_ARGS__)
|
||||||
|
#define xputc(c) putc(c, stdout)
|
||||||
|
#define print(s) printf(PSTR(s))
|
||||||
|
#define println(s) printf(PSTR(s "\r\n"))
|
||||||
|
#define uprint(s) printf(s)
|
||||||
|
#define uprintln(s) printf(s)
|
||||||
|
#define uprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
|
||||||
89
platforms/pico/_wait.c
Normal file
89
platforms/pico/_wait.c
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
/* Copyright 2021 QMK
|
||||||
|
*
|
||||||
|
* 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 __OPTIMIZE__
|
||||||
|
# pragma message "Compiler optimizations disabled; wait_cpuclock() won't work as designed"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CLOCK_DELAY_NOP8 "nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t nop\n\t"
|
||||||
|
|
||||||
|
__attribute__((always_inline)) static inline void wait_cpuclock(unsigned int n) { /* n: 1..135 */
|
||||||
|
/* The argument n must be a constant expression.
|
||||||
|
* That way, compiler optimization will remove unnecessary code. */
|
||||||
|
if (n < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (n > 8) {
|
||||||
|
unsigned int n8 = n / 8;
|
||||||
|
n = n - n8 * 8;
|
||||||
|
switch (n8) {
|
||||||
|
case 16:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 15:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 14:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 13:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 12:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 11:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 10:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 9:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 8:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 7:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 6:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 5:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 4:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 3:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 2:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 1:
|
||||||
|
asm volatile(CLOCK_DELAY_NOP8::: "memory");
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (n) {
|
||||||
|
case 8:
|
||||||
|
asm volatile("nop" ::: "memory");
|
||||||
|
case 7:
|
||||||
|
asm volatile("nop" ::: "memory");
|
||||||
|
case 6:
|
||||||
|
asm volatile("nop" ::: "memory");
|
||||||
|
case 5:
|
||||||
|
asm volatile("nop" ::: "memory");
|
||||||
|
case 4:
|
||||||
|
asm volatile("nop" ::: "memory");
|
||||||
|
case 3:
|
||||||
|
asm volatile("nop" ::: "memory");
|
||||||
|
case 2:
|
||||||
|
asm volatile("nop" ::: "memory");
|
||||||
|
case 1:
|
||||||
|
asm volatile("nop" ::: "memory");
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
platforms/pico/_wait.h
Normal file
24
platforms/pico/_wait.h
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
/* Copyright 2021 QMK
|
||||||
|
*
|
||||||
|
* 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 "pico/stdlib.h"
|
||||||
|
|
||||||
|
#define wait_ms(ms) busy_wait_ms(ms)
|
||||||
|
#define wait_us(us) busy_wait_us(us)
|
||||||
|
#define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY)
|
||||||
|
|
||||||
|
#include "_wait.c"
|
||||||
35
platforms/pico/atomic_util.h
Normal file
35
platforms/pico/atomic_util.h
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
/* Copyright 2021 QMK
|
||||||
|
*
|
||||||
|
* 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 "hardware/sync.h"
|
||||||
|
|
||||||
|
extern uint32_t interrupts;
|
||||||
|
|
||||||
|
static __inline__ uint8_t __interrupt_disable__(void) {
|
||||||
|
interrupts = save_and_disable_interrupts();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline__ void __interrupt_enable__(const uint8_t *__s) {
|
||||||
|
restore_interrupts(interrupts);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ATOMIC_BLOCK(type) for (type, __ToDo = __interrupt_disable__(); __ToDo; __ToDo = 0)
|
||||||
|
#define ATOMIC_FORCEON uint8_t sreg_save __attribute__((__cleanup__(__interrupt_enable__))) = 0
|
||||||
|
|
||||||
|
#define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE not implemented")
|
||||||
|
#define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK(ATOMIC_FORCEON)
|
||||||
7
platforms/pico/boards/pico_boards.h
Normal file
7
platforms/pico/boards/pico_boards.h
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// #if defined(PICO_BOARD_PROMICRO)
|
||||||
|
#include "pico_pro_micro.h"
|
||||||
|
// #endif
|
||||||
36
platforms/pico/boards/pico_pro_micro.h
Normal file
36
platforms/pico/boards/pico_pro_micro.h
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
#define D3 0
|
||||||
|
#define D2 1
|
||||||
|
#define D1 2
|
||||||
|
#define D0 3
|
||||||
|
#define D4 4
|
||||||
|
#define C6 5
|
||||||
|
#define D7 6
|
||||||
|
#define E6 7
|
||||||
|
#define B4 8
|
||||||
|
#define B5 9
|
||||||
|
#define B6 21
|
||||||
|
#define B2 23
|
||||||
|
#define B3 20
|
||||||
|
#define B1 22
|
||||||
|
#define F7 26
|
||||||
|
#define F6 27
|
||||||
|
#define F5 28
|
||||||
|
#define F4 29
|
||||||
28
platforms/pico/bootloader.c
Normal file
28
platforms/pico/bootloader.c
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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 "pico/stdlib.h"
|
||||||
|
#include "pico/bootrom.h"
|
||||||
|
|
||||||
|
#define FLASH_SIZE (FLASHEND + 1L)
|
||||||
|
|
||||||
|
#if !defined(BOOTLOADER_SIZE)
|
||||||
|
uint16_t bootloader_start;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__attribute__((weak)) void bootloader_jump(void) {
|
||||||
|
reset_usb_boot(0, 0);
|
||||||
|
}
|
||||||
14
platforms/pico/bootloaders/RP2040.c
Normal file
14
platforms/pico/bootloaders/RP2040.c
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#include "bootloader.h"
|
||||||
|
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "pico/bootrom.h"
|
||||||
|
|
||||||
|
#define FLASH_SIZE (FLASHEND + 1L)
|
||||||
|
|
||||||
|
#if !defined(BOOTLOADER_SIZE)
|
||||||
|
uint16_t bootloader_start;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__attribute__((weak)) void bootloader_jump(void) {
|
||||||
|
reset_usb_boot(0, 0);
|
||||||
|
}
|
||||||
7
platforms/pico/convert_to_pico_micro.mk
Normal file
7
platforms/pico/convert_to_pico_micro.mk
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
TARGET := $(TARGET)_pico_micro
|
||||||
|
MCU_FAMILY := PICO
|
||||||
|
MCU_SERIES := RP2040
|
||||||
|
MCU := cortex-m0plus
|
||||||
|
|
||||||
|
OPT_DEFS += -DCONVERT_TO_PICO_MICRO
|
||||||
23
platforms/pico/drivers/analog.c
Normal file
23
platforms/pico/drivers/analog.c
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#include "quantum.h"
|
||||||
|
#include "boards/pico_boards.h"
|
||||||
|
#include "analog.h"
|
||||||
|
#undef adc_read
|
||||||
|
|
||||||
|
#include "hardware/adc.h"
|
||||||
|
|
||||||
|
int16_t analogReadPin(pin_t pin) { return adc_read_pico(pinToMux(pin)); }
|
||||||
|
|
||||||
|
__attribute__((weak)) adc_mux pinToMux(pin_t pin) {
|
||||||
|
switch (pin) {
|
||||||
|
case 26 ... 29:
|
||||||
|
return TO_MUX(pin, pin - 26);
|
||||||
|
default:
|
||||||
|
return TO_MUX(0, 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t adc_read_pico(adc_mux mux) {
|
||||||
|
adc_gpio_init(mux.pin);
|
||||||
|
adc_select_input(mux.adc);
|
||||||
|
return adc_read();
|
||||||
|
}
|
||||||
19
platforms/pico/drivers/analog.h
Normal file
19
platforms/pico/drivers/analog.h
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "quantum.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
pin_t pin;
|
||||||
|
uint8_t adc;
|
||||||
|
} adc_mux;
|
||||||
|
|
||||||
|
#define TO_MUX(i, a) \
|
||||||
|
(adc_mux) { i, a }
|
||||||
|
|
||||||
|
int16_t analogReadPin(pin_t pin);
|
||||||
|
adc_mux pinToMux(pin_t pin);
|
||||||
|
|
||||||
|
#define adc_read(mux) adc_read_pico(mux)
|
||||||
|
int16_t adc_read_pico(adc_mux mux);
|
||||||
111
platforms/pico/drivers/i2c_master.c
Normal file
111
platforms/pico/drivers/i2c_master.c
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
|
||||||
|
#include "quantum.h"
|
||||||
|
#include "i2c_master.h"
|
||||||
|
#undef i2c_init
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "pico/binary_info.h"
|
||||||
|
#include "hardware/i2c.h"
|
||||||
|
|
||||||
|
#ifndef I2C1_SCL_PIN
|
||||||
|
# define I2C1_SCL_PIN 3
|
||||||
|
#endif
|
||||||
|
#ifndef I2C1_SDA_PIN
|
||||||
|
# define I2C1_SDA_PIN 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef I2C_DRIVER
|
||||||
|
# define I2C_DRIVER i2c1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static uint8_t i2c_address;
|
||||||
|
|
||||||
|
static i2c_status_t pico_status_to_qmk(int res) {
|
||||||
|
if (res == PICO_ERROR_GENERIC) {
|
||||||
|
return I2C_STATUS_ERROR;
|
||||||
|
} else if (res == PICO_ERROR_TIMEOUT) {
|
||||||
|
return I2C_STATUS_TIMEOUT;
|
||||||
|
} else {
|
||||||
|
return I2C_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void i2c_init_pico(void) {
|
||||||
|
static bool is_initialised = false;
|
||||||
|
if (!is_initialised) {
|
||||||
|
is_initialised = true;
|
||||||
|
|
||||||
|
i2c_init(I2C_DRIVER, 50 * 1000);
|
||||||
|
gpio_set_function(I2C1_SCL_PIN, GPIO_FUNC_I2C);
|
||||||
|
gpio_set_function(I2C1_SDA_PIN, GPIO_FUNC_I2C);
|
||||||
|
gpio_pull_up(I2C1_SCL_PIN);
|
||||||
|
gpio_pull_up(I2C1_SDA_PIN);
|
||||||
|
// Make the I2C pins available to picotool
|
||||||
|
bi_decl(bi_2pins_with_func(I2C1_SDA_PIN, I2C1_SCL_PIN, GPIO_FUNC_I2C));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_status_t i2c_start(uint8_t address, uint16_t timeout) {
|
||||||
|
i2c_address = address;
|
||||||
|
return I2C_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length,
|
||||||
|
uint16_t timeout) {
|
||||||
|
i2c_address = address;
|
||||||
|
|
||||||
|
int res = i2c_write_timeout_us(I2C_DRIVER, i2c_address >> 1, data, length,
|
||||||
|
true, timeout * 1000);
|
||||||
|
|
||||||
|
return pico_status_to_qmk(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length,
|
||||||
|
uint16_t timeout) {
|
||||||
|
i2c_address = address;
|
||||||
|
|
||||||
|
int res = i2c_read_timeout_us(I2C_DRIVER, i2c_address >> 1, data, length,
|
||||||
|
true, timeout * 1000);
|
||||||
|
|
||||||
|
return pico_status_to_qmk(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data,
|
||||||
|
uint16_t length, uint16_t timeout) {
|
||||||
|
i2c_address = devaddr;
|
||||||
|
|
||||||
|
uint8_t complete_packet[length + 1];
|
||||||
|
for (uint8_t i = 0; i < length; i++) {
|
||||||
|
complete_packet[i + 1] = data[i];
|
||||||
|
}
|
||||||
|
complete_packet[0] = regaddr;
|
||||||
|
|
||||||
|
int res =
|
||||||
|
i2c_write_timeout_us(I2C_DRIVER, (i2c_address >> 1), complete_packet,
|
||||||
|
length + 1, true, timeout * 1000);
|
||||||
|
|
||||||
|
return pico_status_to_qmk(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data,
|
||||||
|
uint16_t length, uint16_t timeout) {
|
||||||
|
i2c_address = devaddr;
|
||||||
|
i2c_write_timeout_us(I2C_DRIVER, (i2c_address >> 1), ®addr, 1, true,
|
||||||
|
timeout * 1000);
|
||||||
|
|
||||||
|
int res = i2c_read_timeout_us(I2C_DRIVER, i2c_address >> 1, data, length,
|
||||||
|
true, timeout * 1000);
|
||||||
|
|
||||||
|
return pico_status_to_qmk(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void i2c_stop(void) {
|
||||||
|
// Abort
|
||||||
|
I2C_DRIVER->hw->enable |= (1 << 1);
|
||||||
|
I2C_DRIVER->restart_on_next = false;
|
||||||
|
while (I2C_DRIVER->hw->enable & (1 << 1)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// clear abort bit
|
||||||
|
I2C_DRIVER->hw->clr_tx_abrt;
|
||||||
|
}
|
||||||
47
platforms/pico/drivers/i2c_master.h
Normal file
47
platforms/pico/drivers/i2c_master.h
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
/* Copyright 2018 Jack Humbert
|
||||||
|
* Copyright 2018 Yiancar
|
||||||
|
*
|
||||||
|
* 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 library follows the convention of the AVR i2c_master library.
|
||||||
|
* As a result addresses are expected to be already shifted (addr << 1).
|
||||||
|
* I2CD1 is the default driver which corresponds to pins B6 and B7. This
|
||||||
|
* can be changed.
|
||||||
|
* Please ensure that HAL_USE_I2C is TRUE in the halconf.h file and that
|
||||||
|
* STM32_I2C_USE_I2C1 is TRUE in the mcuconf.h file.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef int16_t i2c_status_t;
|
||||||
|
|
||||||
|
#define I2C_STATUS_SUCCESS (0)
|
||||||
|
#define I2C_STATUS_ERROR (-1)
|
||||||
|
#define I2C_STATUS_TIMEOUT (-2)
|
||||||
|
|
||||||
|
/* collides with:
|
||||||
|
* pico-sdk/src/rp2_comon/hardware_i2c/include/hardware/i2c.h::i2c_init
|
||||||
|
* hence the bodge...
|
||||||
|
*/
|
||||||
|
#define i2c_init() i2c_init_pico()
|
||||||
|
void i2c_init_pico(void);
|
||||||
|
|
||||||
|
i2c_status_t i2c_start(uint8_t address, uint16_t timeout);
|
||||||
|
i2c_status_t i2c_transmit(uint8_t address, const uint8_t* data, uint16_t length, uint16_t timeout);
|
||||||
|
i2c_status_t i2c_receive(uint8_t address, uint8_t* data, uint16_t length, uint16_t timeout);
|
||||||
|
i2c_status_t i2c_writeReg(uint8_t devaddr, uint8_t regaddr, const uint8_t* data, uint16_t length, uint16_t timeout);
|
||||||
|
i2c_status_t i2c_readReg(uint8_t devaddr, uint8_t regaddr, uint8_t* data, uint16_t length, uint16_t timeout);
|
||||||
|
void i2c_stop(void);
|
||||||
431
platforms/pico/drivers/serial.c
Normal file
431
platforms/pico/drivers/serial.c
Normal file
|
|
@ -0,0 +1,431 @@
|
||||||
|
/*
|
||||||
|
* WARNING: be careful changing this code, it is very timing dependent
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "quantum.h"
|
||||||
|
#include "serial.h"
|
||||||
|
#include "wait.h"
|
||||||
|
|
||||||
|
#include "uart_tx.pio.h"
|
||||||
|
#include "uart_rx.pio.h"
|
||||||
|
#include "pio_manager.h"
|
||||||
|
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
#include "hardware/timer.h"
|
||||||
|
#include "hardware/gpio.h"
|
||||||
|
#include "hardware/sync.h"
|
||||||
|
#include "hardware/irq.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifndef SELECT_SOFT_SERIAL_SPEED
|
||||||
|
# define SELECT_SOFT_SERIAL_SPEED 1
|
||||||
|
// TODO: correct speeds...
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Serial pulse period in microseconds. At the moment, going lower than 12
|
||||||
|
// causes communication failure
|
||||||
|
#if SELECT_SOFT_SERIAL_SPEED == 0
|
||||||
|
# define SERIAL_DELAY 16
|
||||||
|
# define SERIAL_BAUD 921600
|
||||||
|
#elif SELECT_SOFT_SERIAL_SPEED == 1
|
||||||
|
# define SERIAL_DELAY 16
|
||||||
|
# define SERIAL_BAUD 230400
|
||||||
|
#elif SELECT_SOFT_SERIAL_SPEED == 2
|
||||||
|
# define SERIAL_DELAY 24
|
||||||
|
# define SERIAL_BAUD 115200
|
||||||
|
#elif SELECT_SOFT_SERIAL_SPEED == 3
|
||||||
|
# define SERIAL_DELAY 32
|
||||||
|
# define SERIAL_BAUD 57600
|
||||||
|
#elif SELECT_SOFT_SERIAL_SPEED == 4
|
||||||
|
# define SERIAL_DELAY 48
|
||||||
|
# define SERIAL_BAUD 9600
|
||||||
|
#elif SELECT_SOFT_SERIAL_SPEED == 5
|
||||||
|
# define SERIAL_DELAY 64
|
||||||
|
# define SERIAL_BAUD 4800
|
||||||
|
#else
|
||||||
|
# error invalid SELECT_SOFT_SERIAL_SPEED value
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SOFT_SERIAL_PIN == 15
|
||||||
|
# error GPIO15 cannot be used as SOFT_SERIAL_PIN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline static void serial_delay(void) { wait_us(SERIAL_DELAY); }
|
||||||
|
inline static void serial_delay_half(void) { wait_us(SERIAL_DELAY / 2); }
|
||||||
|
inline static void serial_delay_blip(void) { wait_us(1); }
|
||||||
|
inline static void serial_output(void) {
|
||||||
|
gpio_set_function(SOFT_SERIAL_PIN, GPIO_FUNC_SIO);
|
||||||
|
setPinOutput(SOFT_SERIAL_PIN);
|
||||||
|
|
||||||
|
gpio_set_slew_rate(SOFT_SERIAL_PIN, GPIO_SLEW_RATE_FAST);
|
||||||
|
gpio_set_drive_strength(SOFT_SERIAL_PIN, GPIO_DRIVE_STRENGTH_12MA);
|
||||||
|
}
|
||||||
|
inline static void serial_input(void) {
|
||||||
|
gpio_set_function(SOFT_SERIAL_PIN, GPIO_FUNC_SIO);
|
||||||
|
setPinInputHigh(SOFT_SERIAL_PIN);
|
||||||
|
}
|
||||||
|
inline static bool serial_read_pin(void) { return readPin(SOFT_SERIAL_PIN); }
|
||||||
|
inline static void serial_low(void) { writePinLow(SOFT_SERIAL_PIN); }
|
||||||
|
inline static void serial_high(void) { writePinHigh(SOFT_SERIAL_PIN); }
|
||||||
|
|
||||||
|
static void interrupt_handler(uint gpio, uint32_t events);
|
||||||
|
|
||||||
|
static PIO pio = pio0;
|
||||||
|
static uint sm_tx, sm_rx;
|
||||||
|
|
||||||
|
inline static void soft_serial_disable_rx(void) {
|
||||||
|
pio_sm_set_enabled(pio, sm_rx, false);
|
||||||
|
pio_sm_restart(pio, sm_rx);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static void soft_serial_enable_rx(void) {
|
||||||
|
serial_input();
|
||||||
|
// pio_gpio_init is not needed
|
||||||
|
pio_sm_clear_fifos(pio, sm_rx);
|
||||||
|
pio_sm_set_enabled(pio, sm_rx, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static void soft_serial_disable_tx(void) {
|
||||||
|
pio_sm_set_enabled(pio, sm_tx, false);
|
||||||
|
pio_sm_restart(pio, sm_tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void soft_serial_enable_tx(void) {
|
||||||
|
writePinHigh(SOFT_SERIAL_PIN);
|
||||||
|
serial_output();
|
||||||
|
pio_sm_clear_fifos(pio, sm_tx);
|
||||||
|
pio_gpio_init(pio, SOFT_SERIAL_PIN);
|
||||||
|
pio_sm_set_enabled(pio, sm_tx, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static int soft_serial_pio_init(void) {
|
||||||
|
sm_rx = pio_manager_get_empty_sm(pio);
|
||||||
|
|
||||||
|
if (sm_rx < 0) return -1;
|
||||||
|
|
||||||
|
int32_t offset = pio_manager_add_program(pio, sm_rx, &uart_rx_mini_program);
|
||||||
|
|
||||||
|
if (offset < 0) return -1;
|
||||||
|
|
||||||
|
uart_rx_mini_program_init(pio, sm_rx, offset, SOFT_SERIAL_PIN, SERIAL_BAUD);
|
||||||
|
soft_serial_disable_rx();
|
||||||
|
|
||||||
|
sm_tx = pio_manager_get_empty_sm(pio);
|
||||||
|
|
||||||
|
if (sm_tx < 0) return -1;
|
||||||
|
|
||||||
|
offset = pio_manager_add_program(pio, sm_tx, &uart_tx_program);
|
||||||
|
|
||||||
|
if (offset < 0) return -1;
|
||||||
|
|
||||||
|
writePinHigh(SOFT_SERIAL_PIN);
|
||||||
|
uart_tx_program_init(pio, sm_tx, offset, SOFT_SERIAL_PIN, SERIAL_BAUD);
|
||||||
|
soft_serial_disable_tx();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize master
|
||||||
|
void soft_serial_initiator_init(void) {
|
||||||
|
soft_serial_pio_init();
|
||||||
|
|
||||||
|
serial_output();
|
||||||
|
serial_high();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize slave
|
||||||
|
void soft_serial_target_init(void) {
|
||||||
|
soft_serial_pio_init();
|
||||||
|
|
||||||
|
serial_input();
|
||||||
|
gpio_set_irq_enabled_with_callback(SOFT_SERIAL_PIN, GPIO_IRQ_EDGE_FALL,
|
||||||
|
true, interrupt_handler);
|
||||||
|
irq_set_priority(IO_IRQ_BANK0, PICO_HIGHEST_IRQ_PRIORITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by the master to synchronize timing with the slave.
|
||||||
|
static int __no_inline_not_in_flash_func(sync_recv)(void) {
|
||||||
|
serial_input();
|
||||||
|
|
||||||
|
volatile uint64_t timeout = time_us_64() + 10000;
|
||||||
|
while (!serial_read_pin() && time_us_64() < timeout) {
|
||||||
|
// tight_loop_contents();
|
||||||
|
}
|
||||||
|
if (time_us_64() >= timeout) {
|
||||||
|
// dprintf("serial::NO_RESPONSE0\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout = time_us_64() + 10000;
|
||||||
|
while (serial_read_pin() && time_us_64() < timeout) {
|
||||||
|
// tight_loop_contents();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time_us_64() >= timeout) {
|
||||||
|
// dprintf("serial::NO_RESPONSE1\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout = time_us_64() + 10000;
|
||||||
|
while (!serial_read_pin() && time_us_64() < timeout) {
|
||||||
|
// tight_loop_contents();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time_us_64() >= timeout) {
|
||||||
|
// dprintf("serial::NO_RESPONSE2\n");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by the slave to send a synchronization signal to the master.
|
||||||
|
static void __no_inline_not_in_flash_func(sync_send)(void) {
|
||||||
|
serial_output();
|
||||||
|
|
||||||
|
serial_low();
|
||||||
|
serial_delay();
|
||||||
|
|
||||||
|
serial_high();
|
||||||
|
while (!serial_read_pin()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reads a byte from the serial line
|
||||||
|
static uint16_t __attribute__((noinline)) serial_read_byte(void) {
|
||||||
|
uint64_t timeout = time_us_64() + 10000;
|
||||||
|
while (pio_sm_is_rx_fifo_empty(pio, sm_rx) && (time_us_64() < timeout)) {
|
||||||
|
tight_loop_contents();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time_us_64() >= timeout) {
|
||||||
|
// dprintf("serial: pio_rx timeout\n");
|
||||||
|
return 0xffff;
|
||||||
|
} else {
|
||||||
|
return uart_rx_program_getc(pio, sm_rx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sends a byte with MSB ordering
|
||||||
|
static void __attribute__((noinline)) serial_write_byte(uint8_t data) {
|
||||||
|
uart_tx_program_putc(pio, sm_tx, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void serial_wait_send_complete(void) {
|
||||||
|
while (pio_sm_get_tx_fifo_level(pio, sm_tx) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
wait_us(1000000 * 12 / (SERIAL_BAUD));
|
||||||
|
}
|
||||||
|
|
||||||
|
// interrupt handle to be used by the slave device
|
||||||
|
static void __no_inline_not_in_flash_func(interrupt_handler)(uint gpio, uint32_t events) {
|
||||||
|
if (gpio != SOFT_SERIAL_PIN || events != GPIO_IRQ_EDGE_FALL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t interrupt_status = save_and_disable_interrupts();
|
||||||
|
|
||||||
|
gpio_set_irq_enabled_with_callback(SOFT_SERIAL_PIN, GPIO_IRQ_EDGE_FALL,
|
||||||
|
false, interrupt_handler);
|
||||||
|
|
||||||
|
while (!serial_read_pin()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
serial_delay_blip();
|
||||||
|
|
||||||
|
sync_send();
|
||||||
|
|
||||||
|
uint8_t checksum_computed = 0;
|
||||||
|
int sstd_index = 0;
|
||||||
|
int receive_res = 0;
|
||||||
|
uint8_t checksum_received = 0xff;
|
||||||
|
|
||||||
|
split_transaction_desc_t *trans;
|
||||||
|
|
||||||
|
serial_input();
|
||||||
|
while (!serial_read_pin()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// activate receive
|
||||||
|
soft_serial_enable_rx();
|
||||||
|
|
||||||
|
do {
|
||||||
|
sstd_index = serial_read_byte();
|
||||||
|
if (sstd_index > NUM_TOTAL_TRANSACTIONS) {
|
||||||
|
printf("invalid sstd_index:%d\n", sstd_index);
|
||||||
|
receive_res = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
soft_serial_disable_rx();
|
||||||
|
|
||||||
|
serial_delay();
|
||||||
|
sync_send();
|
||||||
|
|
||||||
|
soft_serial_enable_rx();
|
||||||
|
|
||||||
|
trans = &split_transaction_table[sstd_index];
|
||||||
|
for (int i = 0; i < trans->initiator2target_buffer_size; ++i) {
|
||||||
|
split_trans_initiator2target_buffer(trans)[i] = serial_read_byte();
|
||||||
|
checksum_computed += split_trans_initiator2target_buffer(trans)[i];
|
||||||
|
}
|
||||||
|
checksum_computed ^= 7;
|
||||||
|
checksum_received = serial_read_byte();
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
soft_serial_disable_rx();
|
||||||
|
|
||||||
|
if (receive_res < 0) {
|
||||||
|
// receive timeout error
|
||||||
|
serial_input();
|
||||||
|
gpio_set_irq_enabled_with_callback(SOFT_SERIAL_PIN, GPIO_IRQ_EDGE_FALL,
|
||||||
|
true, interrupt_handler);
|
||||||
|
restore_interrupts(interrupt_status);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
serial_delay();
|
||||||
|
sync_send();
|
||||||
|
|
||||||
|
soft_serial_enable_tx();
|
||||||
|
|
||||||
|
// wait for the sync to finish sending
|
||||||
|
serial_delay();
|
||||||
|
|
||||||
|
// Allow any slave processing to occur
|
||||||
|
if (trans->slave_callback) {
|
||||||
|
trans->slave_callback(trans->initiator2target_buffer_size,
|
||||||
|
split_trans_initiator2target_buffer(trans),
|
||||||
|
trans->target2initiator_buffer_size,
|
||||||
|
split_trans_target2initiator_buffer(trans));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
for (int i = 0; i < trans->target2initiator_buffer_size; ++i) {
|
||||||
|
uint8_t b = split_trans_target2initiator_buffer(trans)[i];
|
||||||
|
serial_write_byte(b);
|
||||||
|
checksum += b;
|
||||||
|
}
|
||||||
|
serial_write_byte(checksum ^ 7);
|
||||||
|
serial_wait_send_complete();
|
||||||
|
|
||||||
|
|
||||||
|
*trans->status = (checksum_computed == checksum_received)
|
||||||
|
? TRANSACTION_ACCEPTED
|
||||||
|
: TRANSACTION_DATA_ERROR;
|
||||||
|
|
||||||
|
|
||||||
|
// end transaction
|
||||||
|
serial_input();
|
||||||
|
|
||||||
|
//
|
||||||
|
gpio_set_irq_enabled_with_callback(SOFT_SERIAL_PIN, GPIO_IRQ_EDGE_FALL,
|
||||||
|
true, interrupt_handler);
|
||||||
|
|
||||||
|
restore_interrupts(interrupt_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////
|
||||||
|
// start transaction by initiator
|
||||||
|
//
|
||||||
|
// int soft_serial_transaction(int sstd_index)
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// TRANSACTION_END
|
||||||
|
// TRANSACTION_NO_RESPONSE
|
||||||
|
// TRANSACTION_DATA_ERROR
|
||||||
|
// this code is very time dependent, so we need to disable interrupts
|
||||||
|
int __no_inline_not_in_flash_func(soft_serial_transaction)(int sstd_index) {
|
||||||
|
if (sstd_index > NUM_TOTAL_TRANSACTIONS) return TRANSACTION_TYPE_ERROR;
|
||||||
|
split_transaction_desc_t *trans = &split_transaction_table[sstd_index];
|
||||||
|
if (!trans->status) return TRANSACTION_TYPE_ERROR; // not registered
|
||||||
|
|
||||||
|
// TODO: remove extra delay between transactions
|
||||||
|
serial_delay();
|
||||||
|
|
||||||
|
// this code is very time dependent, so we need to disable interrupts
|
||||||
|
uint32_t interrupt_status = save_and_disable_interrupts();
|
||||||
|
|
||||||
|
// signal to the slave that we want to start a transaction
|
||||||
|
serial_output();
|
||||||
|
serial_low();
|
||||||
|
serial_delay_blip();
|
||||||
|
serial_high();
|
||||||
|
|
||||||
|
// wait for the slaves response
|
||||||
|
if (sync_recv() != 0) {
|
||||||
|
// dprintf("NACK 1\n");
|
||||||
|
restore_interrupts(interrupt_status);
|
||||||
|
return TRANSACTION_NO_RESPONSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the slave is present syncronize with it
|
||||||
|
soft_serial_enable_tx();
|
||||||
|
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
// send data to the slave
|
||||||
|
serial_write_byte(sstd_index); // first chunk is transaction id
|
||||||
|
serial_wait_send_complete();
|
||||||
|
|
||||||
|
soft_serial_disable_tx();
|
||||||
|
|
||||||
|
if (sync_recv() != 0) {
|
||||||
|
// dprintf("NACK 1.5\n");
|
||||||
|
restore_interrupts(interrupt_status);
|
||||||
|
return TRANSACTION_NO_RESPONSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
soft_serial_enable_tx();
|
||||||
|
serial_delay();
|
||||||
|
|
||||||
|
for (int i = 0; i < trans->initiator2target_buffer_size; ++i) {
|
||||||
|
serial_write_byte(split_trans_initiator2target_buffer(trans)[i]);
|
||||||
|
checksum += split_trans_initiator2target_buffer(trans)[i];
|
||||||
|
}
|
||||||
|
serial_write_byte(checksum ^ 7);
|
||||||
|
|
||||||
|
serial_wait_send_complete();
|
||||||
|
|
||||||
|
soft_serial_disable_tx();
|
||||||
|
|
||||||
|
if (sync_recv() != 0) {
|
||||||
|
// dprintf("NACK 2\n");
|
||||||
|
restore_interrupts(interrupt_status);
|
||||||
|
return TRANSACTION_NO_RESPONSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
soft_serial_enable_rx();
|
||||||
|
|
||||||
|
// receive data from the slave
|
||||||
|
uint8_t checksum_computed = 0;
|
||||||
|
uint8_t receive_bytes = trans->target2initiator_buffer_size;
|
||||||
|
for (int i = 0; i < receive_bytes; ++i) {
|
||||||
|
split_trans_target2initiator_buffer(trans)[i] = serial_read_byte();
|
||||||
|
checksum_computed += split_trans_target2initiator_buffer(trans)[i];
|
||||||
|
}
|
||||||
|
checksum_computed ^= 7;
|
||||||
|
uint8_t checksum_received = serial_read_byte();
|
||||||
|
|
||||||
|
soft_serial_disable_rx();
|
||||||
|
|
||||||
|
if ((checksum_computed) != (checksum_received)) {
|
||||||
|
dprintf("serial::FAIL[%u,%u,%u]\n", checksum_computed,
|
||||||
|
checksum_received, sstd_index);
|
||||||
|
serial_output();
|
||||||
|
serial_high();
|
||||||
|
|
||||||
|
restore_interrupts(interrupt_status);
|
||||||
|
return TRANSACTION_DATA_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// always, release the line when not in use
|
||||||
|
serial_high();
|
||||||
|
serial_output();
|
||||||
|
|
||||||
|
restore_interrupts(interrupt_status);
|
||||||
|
return TRANSACTION_END;
|
||||||
|
}
|
||||||
237
platforms/pico/drivers/serial_usart.c
Normal file
237
platforms/pico/drivers/serial_usart.c
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
#include "quantum.h"
|
||||||
|
#include "serial.h"
|
||||||
|
#include "print.h"
|
||||||
|
|
||||||
|
#include <ch.h>
|
||||||
|
#include <hal.h>
|
||||||
|
|
||||||
|
#ifndef USART_CR1_M0
|
||||||
|
# define USART_CR1_M0 USART_CR1_M // some platforms (f1xx) dont have this so
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef USE_GPIOV1
|
||||||
|
// The default PAL alternate modes are used to signal that the pins are used for USART
|
||||||
|
# ifndef SERIAL_USART_TX_PAL_MODE
|
||||||
|
# define SERIAL_USART_TX_PAL_MODE 7
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SERIAL_USART_DRIVER
|
||||||
|
# define SERIAL_USART_DRIVER SD1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SERIAL_USART_CR1
|
||||||
|
# define SERIAL_USART_CR1 (USART_CR1_PCE | USART_CR1_PS | USART_CR1_M0) // parity enable, odd parity, 9 bit length
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SERIAL_USART_CR2
|
||||||
|
# define SERIAL_USART_CR2 (USART_CR2_STOP_1) // 2 stop bits
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SERIAL_USART_CR3
|
||||||
|
# define SERIAL_USART_CR3 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SOFT_SERIAL_PIN
|
||||||
|
# define SERIAL_USART_TX_PIN SOFT_SERIAL_PIN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SELECT_SOFT_SERIAL_SPEED
|
||||||
|
# define SELECT_SOFT_SERIAL_SPEED 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SERIAL_USART_SPEED
|
||||||
|
// Allow advanced users to directly set SERIAL_USART_SPEED
|
||||||
|
#elif SELECT_SOFT_SERIAL_SPEED == 0
|
||||||
|
# define SERIAL_USART_SPEED 460800
|
||||||
|
#elif SELECT_SOFT_SERIAL_SPEED == 1
|
||||||
|
# define SERIAL_USART_SPEED 230400
|
||||||
|
#elif SELECT_SOFT_SERIAL_SPEED == 2
|
||||||
|
# define SERIAL_USART_SPEED 115200
|
||||||
|
#elif SELECT_SOFT_SERIAL_SPEED == 3
|
||||||
|
# define SERIAL_USART_SPEED 57600
|
||||||
|
#elif SELECT_SOFT_SERIAL_SPEED == 4
|
||||||
|
# define SERIAL_USART_SPEED 38400
|
||||||
|
#elif SELECT_SOFT_SERIAL_SPEED == 5
|
||||||
|
# define SERIAL_USART_SPEED 19200
|
||||||
|
#else
|
||||||
|
# error invalid SELECT_SOFT_SERIAL_SPEED value
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SERIAL_USART_TIMEOUT
|
||||||
|
# define SERIAL_USART_TIMEOUT 100
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HANDSHAKE_MAGIC 7
|
||||||
|
|
||||||
|
static inline msg_t sdWriteHalfDuplex(SerialDriver* driver, uint8_t* data, uint8_t size) {
|
||||||
|
msg_t ret = sdWrite(driver, data, size);
|
||||||
|
|
||||||
|
// Half duplex requires us to read back the data we just wrote - just throw it away
|
||||||
|
uint8_t dump[size];
|
||||||
|
sdRead(driver, dump, size);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#undef sdWrite
|
||||||
|
#define sdWrite sdWriteHalfDuplex
|
||||||
|
|
||||||
|
static inline msg_t sdWriteTimeoutHalfDuplex(SerialDriver* driver, uint8_t* data, uint8_t size, uint32_t timeout) {
|
||||||
|
msg_t ret = sdWriteTimeout(driver, data, size, timeout);
|
||||||
|
|
||||||
|
// Half duplex requires us to read back the data we just wrote - just throw it away
|
||||||
|
uint8_t dump[size];
|
||||||
|
sdReadTimeout(driver, dump, size, timeout);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#undef sdWriteTimeout
|
||||||
|
#define sdWriteTimeout sdWriteTimeoutHalfDuplex
|
||||||
|
|
||||||
|
static inline void sdClear(SerialDriver* driver) {
|
||||||
|
while (sdGetTimeout(driver, TIME_IMMEDIATE) != MSG_TIMEOUT) {
|
||||||
|
// Do nothing with the data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static SerialConfig sdcfg = {
|
||||||
|
(SERIAL_USART_SPEED), // speed - mandatory
|
||||||
|
(SERIAL_USART_CR1), // CR1
|
||||||
|
(SERIAL_USART_CR2), // CR2
|
||||||
|
(SERIAL_USART_CR3) // CR3
|
||||||
|
};
|
||||||
|
|
||||||
|
void handle_soft_serial_slave(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This thread runs on the slave and responds to transactions initiated
|
||||||
|
* by the master
|
||||||
|
*/
|
||||||
|
static THD_WORKING_AREA(waSlaveThread, 2048);
|
||||||
|
static THD_FUNCTION(SlaveThread, arg) {
|
||||||
|
(void)arg;
|
||||||
|
chRegSetThreadName("slave_transport");
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
handle_soft_serial_slave();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((weak)) void usart_init(void) {
|
||||||
|
#if defined(USE_GPIOV1)
|
||||||
|
palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_STM32_ALTERNATE_OPENDRAIN);
|
||||||
|
#else
|
||||||
|
palSetLineMode(SERIAL_USART_TX_PIN, PAL_MODE_ALTERNATE(SERIAL_USART_TX_PAL_MODE) | PAL_STM32_OTYPE_OPENDRAIN);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void usart_master_init(void) {
|
||||||
|
usart_init();
|
||||||
|
|
||||||
|
sdcfg.cr3 |= USART_CR3_HDSEL;
|
||||||
|
sdStart(&SERIAL_USART_DRIVER, &sdcfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usart_slave_init(void) {
|
||||||
|
usart_init();
|
||||||
|
|
||||||
|
sdcfg.cr3 |= USART_CR3_HDSEL;
|
||||||
|
sdStart(&SERIAL_USART_DRIVER, &sdcfg);
|
||||||
|
|
||||||
|
// Start transport thread
|
||||||
|
chThdCreateStatic(waSlaveThread, sizeof(waSlaveThread), HIGHPRIO, SlaveThread, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SSTD_t* Transaction_table = NULL;
|
||||||
|
static uint8_t Transaction_table_size = 0;
|
||||||
|
|
||||||
|
void soft_serial_initiator_init(SSTD_t* sstd_table, int sstd_table_size) {
|
||||||
|
Transaction_table = sstd_table;
|
||||||
|
Transaction_table_size = (uint8_t)sstd_table_size;
|
||||||
|
|
||||||
|
usart_master_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void soft_serial_target_init(SSTD_t* sstd_table, int sstd_table_size) {
|
||||||
|
Transaction_table = sstd_table;
|
||||||
|
Transaction_table_size = (uint8_t)sstd_table_size;
|
||||||
|
|
||||||
|
usart_slave_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_soft_serial_slave(void) {
|
||||||
|
uint8_t sstd_index = sdGet(&SERIAL_USART_DRIVER); // first chunk is always transaction id
|
||||||
|
SSTD_t* trans = &Transaction_table[sstd_index];
|
||||||
|
|
||||||
|
// Always write back the sstd_index as part of a basic handshake
|
||||||
|
sstd_index ^= HANDSHAKE_MAGIC;
|
||||||
|
sdWrite(&SERIAL_USART_DRIVER, &sstd_index, sizeof(sstd_index));
|
||||||
|
|
||||||
|
if (trans->initiator2target_buffer_size) {
|
||||||
|
sdRead(&SERIAL_USART_DRIVER, trans->initiator2target_buffer, trans->initiator2target_buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trans->target2initiator_buffer_size) {
|
||||||
|
sdWrite(&SERIAL_USART_DRIVER, trans->target2initiator_buffer, trans->target2initiator_buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trans->status) {
|
||||||
|
*trans->status = TRANSACTION_ACCEPTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////
|
||||||
|
// start transaction by initiator
|
||||||
|
//
|
||||||
|
// int soft_serial_transaction(int sstd_index)
|
||||||
|
//
|
||||||
|
// Returns:
|
||||||
|
// TRANSACTION_END
|
||||||
|
// TRANSACTION_NO_RESPONSE
|
||||||
|
// TRANSACTION_DATA_ERROR
|
||||||
|
#ifndef SERIAL_USE_MULTI_TRANSACTION
|
||||||
|
int soft_serial_transaction(void) {
|
||||||
|
uint8_t sstd_index = 0;
|
||||||
|
#else
|
||||||
|
int soft_serial_transaction(int index) {
|
||||||
|
uint8_t sstd_index = index;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (sstd_index > Transaction_table_size) return TRANSACTION_TYPE_ERROR;
|
||||||
|
SSTD_t* trans = &Transaction_table[sstd_index];
|
||||||
|
msg_t res = 0;
|
||||||
|
|
||||||
|
sdClear(&SERIAL_USART_DRIVER);
|
||||||
|
|
||||||
|
// First chunk is always transaction id
|
||||||
|
sdWriteTimeout(&SERIAL_USART_DRIVER, &sstd_index, sizeof(sstd_index), TIME_MS2I(SERIAL_USART_TIMEOUT));
|
||||||
|
|
||||||
|
uint8_t sstd_index_shake = 0xFF;
|
||||||
|
|
||||||
|
// Which we always read back first so that we can error out correctly
|
||||||
|
// - due to the half duplex limitations on return codes, we always have to read *something*
|
||||||
|
// - without the read, write only transactions *always* succeed, even during the boot process where the slave is not ready
|
||||||
|
res = sdReadTimeout(&SERIAL_USART_DRIVER, &sstd_index_shake, sizeof(sstd_index_shake), TIME_MS2I(SERIAL_USART_TIMEOUT));
|
||||||
|
if (res < 0 || (sstd_index_shake != (sstd_index ^ HANDSHAKE_MAGIC))) {
|
||||||
|
dprintf("serial::usart_shake NO_RESPONSE\n");
|
||||||
|
return TRANSACTION_NO_RESPONSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trans->initiator2target_buffer_size) {
|
||||||
|
res = sdWriteTimeout(&SERIAL_USART_DRIVER, trans->initiator2target_buffer, trans->initiator2target_buffer_size, TIME_MS2I(SERIAL_USART_TIMEOUT));
|
||||||
|
if (res < 0) {
|
||||||
|
dprintf("serial::usart_transmit NO_RESPONSE\n");
|
||||||
|
return TRANSACTION_NO_RESPONSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trans->target2initiator_buffer_size) {
|
||||||
|
res = sdReadTimeout(&SERIAL_USART_DRIVER, trans->target2initiator_buffer, trans->target2initiator_buffer_size, TIME_MS2I(SERIAL_USART_TIMEOUT));
|
||||||
|
if (res < 0) {
|
||||||
|
dprintf("serial::usart_receive NO_RESPONSE\n");
|
||||||
|
return TRANSACTION_NO_RESPONSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRANSACTION_END;
|
||||||
|
}
|
||||||
15
platforms/pico/drivers/uart.h
Normal file
15
platforms/pico/drivers/uart.h
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
// void uart_init(uint32_t baud);
|
||||||
|
|
||||||
|
void uart_putchar(uint8_t c);
|
||||||
|
|
||||||
|
uint8_t uart_getchar(void);
|
||||||
|
|
||||||
|
bool uart_available(void);
|
||||||
120
platforms/pico/drivers/uart_rx.pio.h
Normal file
120
platforms/pico/drivers/uart_rx.pio.h
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
// -------------------------------------------------- //
|
||||||
|
// This file is autogenerated by pioasm; do not edit! //
|
||||||
|
// -------------------------------------------------- //
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !PICO_NO_HARDWARE
|
||||||
|
#include "hardware/pio.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ------------ //
|
||||||
|
// uart_rx_mini //
|
||||||
|
// ------------ //
|
||||||
|
|
||||||
|
#define uart_rx_mini_wrap_target 0
|
||||||
|
#define uart_rx_mini_wrap 3
|
||||||
|
|
||||||
|
static const uint16_t uart_rx_mini_program_instructions[] = {
|
||||||
|
// .wrap_target
|
||||||
|
0x2020, // 0: wait 0 pin, 0
|
||||||
|
0xea27, // 1: set x, 7 [10]
|
||||||
|
0x4001, // 2: in pins, 1
|
||||||
|
0x0642, // 3: jmp x--, 2 [6]
|
||||||
|
// .wrap
|
||||||
|
};
|
||||||
|
|
||||||
|
#if !PICO_NO_HARDWARE
|
||||||
|
static const struct pio_program uart_rx_mini_program = {
|
||||||
|
.instructions = uart_rx_mini_program_instructions,
|
||||||
|
.length = 4,
|
||||||
|
.origin = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline pio_sm_config uart_rx_mini_program_get_default_config(uint offset) {
|
||||||
|
pio_sm_config c = pio_get_default_sm_config();
|
||||||
|
sm_config_set_wrap(&c, offset + uart_rx_mini_wrap_target, offset + uart_rx_mini_wrap);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "hardware/clocks.h"
|
||||||
|
#include "hardware/gpio.h"
|
||||||
|
static inline void uart_rx_mini_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
|
||||||
|
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
|
||||||
|
pio_gpio_init(pio, pin);
|
||||||
|
gpio_pull_up(pin);
|
||||||
|
pio_sm_config c = uart_rx_mini_program_get_default_config(offset);
|
||||||
|
sm_config_set_in_pins(&c, pin); // for WAIT, IN
|
||||||
|
// Shift to right, autopush enabled
|
||||||
|
sm_config_set_in_shift(&c, true, true, 8);
|
||||||
|
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
|
||||||
|
// SM transmits 1 bit per 8 execution cycles.
|
||||||
|
float div = (float)clock_get_hz(clk_sys) / (8 * baud);
|
||||||
|
sm_config_set_clkdiv(&c, div);
|
||||||
|
pio_sm_init(pio, sm, offset, &c);
|
||||||
|
pio_sm_set_enabled(pio, sm, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ------- //
|
||||||
|
// uart_rx //
|
||||||
|
// ------- //
|
||||||
|
|
||||||
|
#define uart_rx_wrap_target 0
|
||||||
|
#define uart_rx_wrap 8
|
||||||
|
|
||||||
|
static const uint16_t uart_rx_program_instructions[] = {
|
||||||
|
// .wrap_target
|
||||||
|
0x2020, // 0: wait 0 pin, 0
|
||||||
|
0xea27, // 1: set x, 7 [10]
|
||||||
|
0x4001, // 2: in pins, 1
|
||||||
|
0x0642, // 3: jmp x--, 2 [6]
|
||||||
|
0x00c8, // 4: jmp pin, 8
|
||||||
|
0xc014, // 5: irq nowait 4 rel
|
||||||
|
0x20a0, // 6: wait 1 pin, 0
|
||||||
|
0x0000, // 7: jmp 0
|
||||||
|
0x8020, // 8: push block
|
||||||
|
// .wrap
|
||||||
|
};
|
||||||
|
|
||||||
|
#if !PICO_NO_HARDWARE
|
||||||
|
static const struct pio_program uart_rx_program = {
|
||||||
|
.instructions = uart_rx_program_instructions,
|
||||||
|
.length = 9,
|
||||||
|
.origin = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline pio_sm_config uart_rx_program_get_default_config(uint offset) {
|
||||||
|
pio_sm_config c = pio_get_default_sm_config();
|
||||||
|
sm_config_set_wrap(&c, offset + uart_rx_wrap_target, offset + uart_rx_wrap);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void uart_rx_program_init(PIO pio, uint sm, uint offset, uint pin, uint baud) {
|
||||||
|
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, false);
|
||||||
|
pio_gpio_init(pio, pin);
|
||||||
|
gpio_pull_up(pin);
|
||||||
|
pio_sm_config c = uart_rx_program_get_default_config(offset);
|
||||||
|
sm_config_set_in_pins(&c, pin); // for WAIT, IN
|
||||||
|
sm_config_set_jmp_pin(&c, pin); // for JMP
|
||||||
|
// Shift to right, autopull disabled
|
||||||
|
sm_config_set_in_shift(&c, true, false, 32);
|
||||||
|
// Deeper FIFO as we're not doing any TX
|
||||||
|
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
|
||||||
|
// SM transmits 1 bit per 8 execution cycles.
|
||||||
|
float div = (float)clock_get_hz(clk_sys) / (8 * baud);
|
||||||
|
sm_config_set_clkdiv(&c, div);
|
||||||
|
pio_sm_init(pio, sm, offset, &c);
|
||||||
|
pio_sm_set_enabled(pio, sm, true);
|
||||||
|
}
|
||||||
|
static inline char uart_rx_program_getc(PIO pio, uint sm) {
|
||||||
|
// 8-bit read from the uppermost byte of the FIFO, as data is left-justified
|
||||||
|
io_rw_8 *rxfifo_shift = (io_rw_8*)&pio->rxf[sm] + 3;
|
||||||
|
while (pio_sm_is_rx_fifo_empty(pio, sm))
|
||||||
|
tight_loop_contents();
|
||||||
|
return (char)*rxfifo_shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
73
platforms/pico/drivers/uart_tx.pio.h
Normal file
73
platforms/pico/drivers/uart_tx.pio.h
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
// -------------------------------------------------- //
|
||||||
|
// This file is autogenerated by pioasm; do not edit! //
|
||||||
|
// -------------------------------------------------- //
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !PICO_NO_HARDWARE
|
||||||
|
#include "hardware/pio.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ------- //
|
||||||
|
// uart_tx //
|
||||||
|
// ------- //
|
||||||
|
|
||||||
|
#define uart_tx_wrap_target 0
|
||||||
|
#define uart_tx_wrap 3
|
||||||
|
|
||||||
|
static const uint16_t uart_tx_program_instructions[] = {
|
||||||
|
// .wrap_target
|
||||||
|
0x9fa0, // 0: pull block side 1 [7]
|
||||||
|
0xf727, // 1: set x, 7 side 0 [7]
|
||||||
|
0x6001, // 2: out pins, 1
|
||||||
|
0x0642, // 3: jmp x--, 2 [6]
|
||||||
|
// .wrap
|
||||||
|
};
|
||||||
|
|
||||||
|
#if !PICO_NO_HARDWARE
|
||||||
|
static const struct pio_program uart_tx_program = {
|
||||||
|
.instructions = uart_tx_program_instructions,
|
||||||
|
.length = 4,
|
||||||
|
.origin = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline pio_sm_config uart_tx_program_get_default_config(uint offset) {
|
||||||
|
pio_sm_config c = pio_get_default_sm_config();
|
||||||
|
sm_config_set_wrap(&c, offset + uart_tx_wrap_target, offset + uart_tx_wrap);
|
||||||
|
sm_config_set_sideset(&c, 2, true, false);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "hardware/clocks.h"
|
||||||
|
static inline void uart_tx_program_init(PIO pio, uint sm, uint offset, uint pin_tx, uint baud) {
|
||||||
|
// Tell PIO to initially drive output-high on the selected pin, then map PIO
|
||||||
|
// onto that pin with the IO muxes.
|
||||||
|
pio_sm_set_pins_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
|
||||||
|
pio_sm_set_pindirs_with_mask(pio, sm, 1u << pin_tx, 1u << pin_tx);
|
||||||
|
pio_gpio_init(pio, pin_tx);
|
||||||
|
pio_sm_config c = uart_tx_program_get_default_config(offset);
|
||||||
|
// OUT shifts to right, no autopull
|
||||||
|
sm_config_set_out_shift(&c, true, false, 32);
|
||||||
|
// We are mapping both OUT and side-set to the same pin, because sometimes
|
||||||
|
// we need to assert user data onto the pin (with OUT) and sometimes
|
||||||
|
// assert constant values (start/stop bit)
|
||||||
|
sm_config_set_out_pins(&c, pin_tx, 1);
|
||||||
|
sm_config_set_sideset_pins(&c, pin_tx);
|
||||||
|
// We only need TX, so get an 8-deep FIFO!
|
||||||
|
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||||
|
// SM transmits 1 bit per 8 execution cycles.
|
||||||
|
float div = (float)clock_get_hz(clk_sys) / (8 * baud);
|
||||||
|
sm_config_set_clkdiv(&c, div);
|
||||||
|
pio_sm_init(pio, sm, offset, &c);
|
||||||
|
pio_sm_set_enabled(pio, sm, true);
|
||||||
|
}
|
||||||
|
static inline void uart_tx_program_putc(PIO pio, uint sm, char c) {
|
||||||
|
pio_sm_put_blocking(pio, sm, (uint32_t)c);
|
||||||
|
}
|
||||||
|
static inline void uart_tx_program_puts(PIO pio, uint sm, const char *s) {
|
||||||
|
while (*s)
|
||||||
|
uart_tx_program_putc(pio, sm, *s++);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
56
platforms/pico/drivers/ws2812.c
Normal file
56
platforms/pico/drivers/ws2812.c
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright 2022 sekigon-gonnoc
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "ws2812.h"
|
||||||
|
#include "ws2812.pio.h"
|
||||||
|
|
||||||
|
#include "atomic_util.h"
|
||||||
|
#include "pio_manager.h"
|
||||||
|
#include "boards/pico_boards.h"
|
||||||
|
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
static PIO pio = pio0;
|
||||||
|
static int sm = 0;
|
||||||
|
|
||||||
|
static int ws2812_init(void) {
|
||||||
|
sm = pio_manager_get_empty_sm(pio);
|
||||||
|
|
||||||
|
if (sm < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t offset = pio_manager_add_program(pio, sm, &ws2812_program);
|
||||||
|
|
||||||
|
if (offset < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ws2812_program_init(pio, sm, offset, RGB_DI_PIN, 800000, false);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_setleds(LED_TYPE *ledarray, uint16_t number_of_leds) {
|
||||||
|
static bool s_init = false;
|
||||||
|
if (!s_init) {
|
||||||
|
if (ws2812_init() == 0) {
|
||||||
|
s_init = true;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__interrupt_disable__();
|
||||||
|
|
||||||
|
for (int i = 0; i < number_of_leds; i++) {
|
||||||
|
pio_sm_put_blocking(pio, sm,
|
||||||
|
(((uint32_t)ledarray[i].r) << 16) |
|
||||||
|
(((uint32_t)ledarray[i].g) << 24) |
|
||||||
|
((uint32_t)ledarray[i].b << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
__interrupt_enable__(NULL);
|
||||||
|
}
|
||||||
114
platforms/pico/drivers/ws2812.pio.h
Normal file
114
platforms/pico/drivers/ws2812.pio.h
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
// -------------------------------------------------- //
|
||||||
|
// This file is autogenerated by pioasm; do not edit! //
|
||||||
|
// -------------------------------------------------- //
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !PICO_NO_HARDWARE
|
||||||
|
#include "hardware/pio.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ------ //
|
||||||
|
// ws2812 //
|
||||||
|
// ------ //
|
||||||
|
|
||||||
|
#define ws2812_wrap_target 0
|
||||||
|
#define ws2812_wrap 3
|
||||||
|
|
||||||
|
#define ws2812_T1 2
|
||||||
|
#define ws2812_T2 5
|
||||||
|
#define ws2812_T3 3
|
||||||
|
|
||||||
|
static const uint16_t ws2812_program_instructions[] = {
|
||||||
|
// .wrap_target
|
||||||
|
0x6221, // 0: out x, 1 side 0 [2]
|
||||||
|
0x1123, // 1: jmp !x, 3 side 1 [1]
|
||||||
|
0x1400, // 2: jmp 0 side 1 [4]
|
||||||
|
0xa442, // 3: nop side 0 [4]
|
||||||
|
// .wrap
|
||||||
|
};
|
||||||
|
|
||||||
|
#if !PICO_NO_HARDWARE
|
||||||
|
static const struct pio_program ws2812_program = {
|
||||||
|
.instructions = ws2812_program_instructions,
|
||||||
|
.length = 4,
|
||||||
|
.origin = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline pio_sm_config ws2812_program_get_default_config(uint offset) {
|
||||||
|
pio_sm_config c = pio_get_default_sm_config();
|
||||||
|
sm_config_set_wrap(&c, offset + ws2812_wrap_target, offset + ws2812_wrap);
|
||||||
|
sm_config_set_sideset(&c, 1, false, false);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "hardware/clocks.h"
|
||||||
|
static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin, float freq, bool rgbw) {
|
||||||
|
pio_gpio_init(pio, pin);
|
||||||
|
pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true);
|
||||||
|
pio_sm_config c = ws2812_program_get_default_config(offset);
|
||||||
|
sm_config_set_sideset_pins(&c, pin);
|
||||||
|
sm_config_set_out_shift(&c, false, true, rgbw ? 32 : 24);
|
||||||
|
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||||
|
int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3;
|
||||||
|
float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
|
||||||
|
sm_config_set_clkdiv(&c, div);
|
||||||
|
pio_sm_init(pio, sm, offset, &c);
|
||||||
|
pio_sm_set_enabled(pio, sm, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// --------------- //
|
||||||
|
// ws2812_parallel //
|
||||||
|
// --------------- //
|
||||||
|
|
||||||
|
#define ws2812_parallel_wrap_target 0
|
||||||
|
#define ws2812_parallel_wrap 3
|
||||||
|
|
||||||
|
#define ws2812_parallel_T1 2
|
||||||
|
#define ws2812_parallel_T2 5
|
||||||
|
#define ws2812_parallel_T3 3
|
||||||
|
|
||||||
|
static const uint16_t ws2812_parallel_program_instructions[] = {
|
||||||
|
// .wrap_target
|
||||||
|
0x6020, // 0: out x, 32
|
||||||
|
0xa10b, // 1: mov pins, !null [1]
|
||||||
|
0xa401, // 2: mov pins, x [4]
|
||||||
|
0xa103, // 3: mov pins, null [1]
|
||||||
|
// .wrap
|
||||||
|
};
|
||||||
|
|
||||||
|
#if !PICO_NO_HARDWARE
|
||||||
|
static const struct pio_program ws2812_parallel_program = {
|
||||||
|
.instructions = ws2812_parallel_program_instructions,
|
||||||
|
.length = 4,
|
||||||
|
.origin = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline pio_sm_config ws2812_parallel_program_get_default_config(uint offset) {
|
||||||
|
pio_sm_config c = pio_get_default_sm_config();
|
||||||
|
sm_config_set_wrap(&c, offset + ws2812_parallel_wrap_target, offset + ws2812_parallel_wrap);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "hardware/clocks.h"
|
||||||
|
static inline void ws2812_parallel_program_init(PIO pio, uint sm, uint offset, uint pin_base, uint pin_count, float freq) {
|
||||||
|
for(uint i=pin_base; i<pin_base+pin_count; i++) {
|
||||||
|
pio_gpio_init(pio, i);
|
||||||
|
}
|
||||||
|
pio_sm_set_consecutive_pindirs(pio, sm, pin_base, pin_count, true);
|
||||||
|
pio_sm_config c = ws2812_parallel_program_get_default_config(offset);
|
||||||
|
sm_config_set_out_shift(&c, true, true, 32);
|
||||||
|
sm_config_set_out_pins(&c, pin_base, pin_count);
|
||||||
|
sm_config_set_set_pins(&c, pin_base, pin_count);
|
||||||
|
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
|
||||||
|
int cycles_per_bit = ws2812_parallel_T1 + ws2812_parallel_T2 + ws2812_parallel_T3;
|
||||||
|
float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit);
|
||||||
|
sm_config_set_clkdiv(&c, div);
|
||||||
|
pio_sm_init(pio, sm, offset, &c);
|
||||||
|
pio_sm_set_enabled(pio, sm, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
748
platforms/pico/eeprom.c
Normal file
748
platforms/pico/eeprom.c
Normal file
|
|
@ -0,0 +1,748 @@
|
||||||
|
/*
|
||||||
|
* This software is experimental and a work in progress.
|
||||||
|
* Under no circumstances should these files be used in relation to any critical system(s).
|
||||||
|
* Use of these files is at your own risk.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* This files are free to use from http://engsta.com/stm32-flash-memory-eeprom-emulator/ by
|
||||||
|
* Artur F.
|
||||||
|
*
|
||||||
|
* Modifications for QMK and STM32F303 by Yiancar
|
||||||
|
* Modifications to add flash wear leveling by Ilya Zhuravlev
|
||||||
|
* Modifications to increase flash density by Don Kjer
|
||||||
|
* Modifications for QMK and RP2040 by sekigon-gonnoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "util.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "platforms/pico/flash_pico.h"
|
||||||
|
#include "hardware/watchdog.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We emulate eeprom by writing a snapshot compacted view of eeprom contents,
|
||||||
|
* followed by a write log of any change since that snapshot:
|
||||||
|
*
|
||||||
|
* === SIMULATED EEPROM CONTENTS ===
|
||||||
|
*
|
||||||
|
* ┌─ Compacted ┬ Write Log ─┐
|
||||||
|
* │............│[BYTE][BYTE]│
|
||||||
|
* │FFFF....FFFF│[WRD0][WRD1]│
|
||||||
|
* │FFFFFFFFFFFF│[WORD][NEXT]│
|
||||||
|
* │....FFFFFFFF│[BYTE][WRD0]│
|
||||||
|
* ├────────────┼────────────┤
|
||||||
|
* └──PAGE_BASE │ │
|
||||||
|
* PAGE_LAST─┴─WRITE_BASE │
|
||||||
|
* WRITE_LAST ┘
|
||||||
|
*
|
||||||
|
* Compacted contents are the 1's complement of the actual EEPROM contents.
|
||||||
|
* e.g. An 'FFFF' represents a '0000' value.
|
||||||
|
*
|
||||||
|
* The size of the 'compacted' area is equal to the size of the 'emulated' eeprom.
|
||||||
|
* The size of the compacted-area and write log are configurable, and the combined
|
||||||
|
* size of Compacted + WriteLog is a multiple FEE_PAGE_SIZE, which is MCU dependent.
|
||||||
|
* Simulated Eeprom contents are located at the end of available flash space.
|
||||||
|
*
|
||||||
|
* The following configuration defines can be set:
|
||||||
|
*
|
||||||
|
* FEE_PAGE_COUNT # Total number of pages to use for eeprom simulation (Compact + Write log)
|
||||||
|
* FEE_DENSITY_BYTES # Size of simulated eeprom. (Defaults to half the space allocated by FEE_PAGE_COUNT)
|
||||||
|
* NOTE: The current implementation does not include page swapping,
|
||||||
|
* and FEE_DENSITY_BYTES will consume that amount of RAM as a cached view of actual EEPROM contents.
|
||||||
|
*
|
||||||
|
* The maximum size of FEE_DENSITY_BYTES is currently 16384. The write log size equals
|
||||||
|
* FEE_PAGE_COUNT * FEE_PAGE_SIZE - FEE_DENSITY_BYTES.
|
||||||
|
* The larger the write log, the less frequently the compacted area needs to be rewritten.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* *** General Algorithm ***
|
||||||
|
*
|
||||||
|
* During initialization:
|
||||||
|
* The contents of the Compacted-flash area are loaded and the 1's complement value
|
||||||
|
* is cached into memory (e.g. 0xFFFF in Flash represents 0x0000 in cache).
|
||||||
|
* Write log entries are processed until a 0xFFFF is reached.
|
||||||
|
* Each log entry updates a byte or word in the cache.
|
||||||
|
*
|
||||||
|
* During reads:
|
||||||
|
* EEPROM contents are given back directly from the cache in memory.
|
||||||
|
*
|
||||||
|
* During writes:
|
||||||
|
* The contents of the cache is updated first.
|
||||||
|
* If the Compacted-flash area corresponding to the write address is unprogrammed, the 1's complement of the value is written directly into Compacted-flash
|
||||||
|
* Otherwise:
|
||||||
|
* If the write log is full, erase both the Compacted-flash area and the Write log, then write cached contents to the Compacted-flash area.
|
||||||
|
* Otherwise a Write log entry is constructed and appended to the next free position in the Write log.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* *** Write Log Structure ***
|
||||||
|
*
|
||||||
|
* Write log entries allow for optimized byte writes to addresses below 128. Writing 0 or 1 words are also optimized when word-aligned.
|
||||||
|
*
|
||||||
|
* === WRITE LOG ENTRY FORMATS ===
|
||||||
|
*
|
||||||
|
* ╔═══ Byte-Entry ══╗
|
||||||
|
* ║0XXXXXXX║YYYYYYYY║
|
||||||
|
* ║ └──┬──┘║└──┬───┘║
|
||||||
|
* ║ Address║ Value ║
|
||||||
|
* ╚════════╩════════╝
|
||||||
|
* 0 <= Address < 0x80 (128)
|
||||||
|
*
|
||||||
|
* ╔ Word-Encoded 0 ╗
|
||||||
|
* ║100XXXXXXXXXXXXX║
|
||||||
|
* ║ │└─────┬─────┘║
|
||||||
|
* ║ │Address >> 1 ║
|
||||||
|
* ║ └── Value: 0 ║
|
||||||
|
* ╚════════════════╝
|
||||||
|
* 0 <= Address <= 0x3FFE (16382)
|
||||||
|
*
|
||||||
|
* ╔ Word-Encoded 1 ╗
|
||||||
|
* ║101XXXXXXXXXXXXX║
|
||||||
|
* ║ │└─────┬─────┘║
|
||||||
|
* ║ │Address >> 1 ║
|
||||||
|
* ║ └── Value: 1 ║
|
||||||
|
* ╚════════════════╝
|
||||||
|
* 0 <= Address <= 0x3FFE (16382)
|
||||||
|
*
|
||||||
|
* ╔═══ Reserved ═══╗
|
||||||
|
* ║110XXXXXXXXXXXXX║
|
||||||
|
* ╚════════════════╝
|
||||||
|
*
|
||||||
|
* ╔═══════════ Word-Next ═══════════╗
|
||||||
|
* ║111XXXXXXXXXXXXX║YYYYYYYYYYYYYYYY║
|
||||||
|
* ║ └─────┬─────┘║└───────┬──────┘║
|
||||||
|
* ║(Address-128)>>1║ ~Value ║
|
||||||
|
* ╚════════════════╩════════════════╝
|
||||||
|
* ( 0 <= Address < 0x0080 (128): Reserved)
|
||||||
|
* 0x80 <= Address <= 0x3FFE (16382)
|
||||||
|
*
|
||||||
|
* Write Log entry ranges:
|
||||||
|
* 0x0000 ... 0x7FFF - Byte-Entry; address is (Entry & 0x7F00) >> 4; value is (Entry & 0xFF)
|
||||||
|
* 0x8000 ... 0x9FFF - Word-Encoded 0; address is (Entry & 0x1FFF) << 1; value is 0
|
||||||
|
* 0xA000 ... 0xBFFF - Word-Encoded 1; address is (Entry & 0x1FFF) << 1; value is 1
|
||||||
|
* 0xC000 ... 0xDFFF - Reserved
|
||||||
|
* 0xE000 ... 0xFFBF - Word-Next; address is (Entry & 0x1FFF) << 1 + 0x80; value is ~(Next_Entry)
|
||||||
|
* 0xFFC0 ... 0xFFFE - Reserved
|
||||||
|
* 0xFFFF - Unprogrammed
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "eeprom_pico_defs.h"
|
||||||
|
#if !defined(FEE_PAGE_SIZE) || !defined(FEE_PAGE_COUNT) || !defined(FEE_MCU_FLASH_SIZE) || !defined(FEE_PAGE_BASE_ADDRESS)
|
||||||
|
# error "not implemented."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* These bits are used for optimizing encoding of bytes, 0 and 1 */
|
||||||
|
#define FEE_WORD_ENCODING 0x8000
|
||||||
|
#define FEE_VALUE_NEXT 0x6000
|
||||||
|
#define FEE_VALUE_RESERVED 0x4000
|
||||||
|
#define FEE_VALUE_ENCODED 0x2000
|
||||||
|
#define FEE_BYTE_RANGE 0x80
|
||||||
|
|
||||||
|
/* Addressable range 16KByte: 0 <-> (0x1FFF << 1) */
|
||||||
|
#define FEE_ADDRESS_MAX_SIZE 0x4000
|
||||||
|
|
||||||
|
/* Flash word value after erase */
|
||||||
|
#define FEE_EMPTY_WORD ((uint16_t)0xFFFF)
|
||||||
|
|
||||||
|
/* Magic number indicating the page is used for FEE */
|
||||||
|
#define FEE_MAGIC_DWORD ((uint32_t)0x20400FEE)
|
||||||
|
|
||||||
|
/* Size of combined compacted eeprom and write log pages */
|
||||||
|
#define FEE_DENSITY_MAX_SIZE (FEE_PAGE_COUNT * FEE_PAGE_SIZE)
|
||||||
|
|
||||||
|
#ifndef FEE_MCU_FLASH_SIZE_IGNORE_CHECK /* *TODO: Get rid of this check */
|
||||||
|
# if FEE_DENSITY_MAX_SIZE > (FEE_MCU_FLASH_SIZE * 1024)
|
||||||
|
# pragma message STR(FEE_DENSITY_MAX_SIZE) " > " STR(FEE_MCU_FLASH_SIZE * 1024)
|
||||||
|
# error emulated eeprom: FEE_DENSITY_MAX_SIZE is greater than available flash size
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Size of emulated eeprom */
|
||||||
|
#ifdef FEE_DENSITY_BYTES
|
||||||
|
# if (FEE_DENSITY_BYTES > FEE_DENSITY_MAX_SIZE)
|
||||||
|
# pragma message STR(FEE_DENSITY_BYTES) " > " STR(FEE_DENSITY_MAX_SIZE)
|
||||||
|
# error emulated eeprom: FEE_DENSITY_BYTES exceeds FEE_DENSITY_MAX_SIZE
|
||||||
|
# endif
|
||||||
|
# if (FEE_DENSITY_BYTES == FEE_DENSITY_MAX_SIZE)
|
||||||
|
# pragma message STR(FEE_DENSITY_BYTES) " == " STR(FEE_DENSITY_MAX_SIZE)
|
||||||
|
# warning emulated eeprom: FEE_DENSITY_BYTES leaves no room for a write log. This will greatly increase the flash wear rate!
|
||||||
|
# endif
|
||||||
|
# if FEE_DENSITY_BYTES > FEE_ADDRESS_MAX_SIZE
|
||||||
|
# pragma message STR(FEE_DENSITY_BYTES) " > " STR(FEE_ADDRESS_MAX_SIZE)
|
||||||
|
# error emulated eeprom: FEE_DENSITY_BYTES is greater than FEE_ADDRESS_MAX_SIZE allows
|
||||||
|
# endif
|
||||||
|
# if ((FEE_DENSITY_BYTES) % 2) == 1
|
||||||
|
# error emulated eeprom: FEE_DENSITY_BYTES must be even
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
/* Default to half of allocated space used for emulated eeprom, half for write log */
|
||||||
|
# define FEE_DENSITY_BYTES (FEE_PAGE_COUNT * FEE_PAGE_SIZE / 2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Size of write log */
|
||||||
|
#ifdef FEE_WRITE_LOG_BYTES
|
||||||
|
# if ((FEE_DENSITY_BYTES + FEE_WRITE_LOG_BYTES) > FEE_DENSITY_MAX_SIZE)
|
||||||
|
# pragma message STR(FEE_DENSITY_BYTES) " + " STR(FEE_WRITE_LOG_BYTES) " > " STR(FEE_DENSITY_MAX_SIZE)
|
||||||
|
# error emulated eeprom: FEE_WRITE_LOG_BYTES exceeds remaining FEE_DENSITY_MAX_SIZE
|
||||||
|
# endif
|
||||||
|
# if ((FEE_WRITE_LOG_BYTES) % 2) == 1
|
||||||
|
# error emulated eeprom: FEE_WRITE_LOG_BYTES must be even
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
/* Default to use all remaining space */
|
||||||
|
# define FEE_WRITE_LOG_BYTES (FEE_PAGE_COUNT * FEE_PAGE_SIZE - FEE_DENSITY_BYTES)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Start of the emulated eeprom compacted flash area */
|
||||||
|
#define FEE_COMPACTED_BASE_ADDRESS FEE_PAGE_BASE_ADDRESS
|
||||||
|
/* End of the emulated eeprom compacted flash area */
|
||||||
|
#define FEE_COMPACTED_LAST_ADDRESS (FEE_COMPACTED_BASE_ADDRESS + FEE_DENSITY_BYTES)
|
||||||
|
/* Start of the emulated eeprom write log */
|
||||||
|
#define FEE_WRITE_LOG_BASE_ADDRESS FEE_COMPACTED_LAST_ADDRESS
|
||||||
|
/* End of the emulated eeprom write log */
|
||||||
|
#define FEE_WRITE_LOG_LAST_ADDRESS (FEE_WRITE_LOG_BASE_ADDRESS + FEE_WRITE_LOG_BYTES)
|
||||||
|
|
||||||
|
#if defined(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR) && (DYNAMIC_KEYMAP_EEPROM_MAX_ADDR >= FEE_DENSITY_BYTES)
|
||||||
|
# error emulated eeprom: DYNAMIC_KEYMAP_EEPROM_MAX_ADDR is greater than the FEE_DENSITY_BYTES available
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* In-memory contents of emulated eeprom for faster access */
|
||||||
|
/* *TODO: Implement page swapping */
|
||||||
|
static uint16_t WordBuf[FEE_DENSITY_BYTES / 2];
|
||||||
|
static uint8_t *DataBuf = (uint8_t *)WordBuf;
|
||||||
|
|
||||||
|
/* Pointer to the first available slot within the write log */
|
||||||
|
static uint16_t *empty_slot;
|
||||||
|
|
||||||
|
static void eeprom_clear(void);
|
||||||
|
|
||||||
|
// #define DEBUG_EEPROM_OUTPUT
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Debug print utils
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(DEBUG_EEPROM_OUTPUT)
|
||||||
|
|
||||||
|
# define debug_eeprom debug_enable
|
||||||
|
# define eeprom_println(s) dprintln(s)
|
||||||
|
# define eeprom_printf(fmt, ...) dprintf(fmt, ##__VA_ARGS__);
|
||||||
|
|
||||||
|
#else /* NO_DEBUG */
|
||||||
|
|
||||||
|
# define debug_eeprom false
|
||||||
|
# define eeprom_println(s)
|
||||||
|
# define eeprom_printf(fmt, ...)
|
||||||
|
|
||||||
|
#endif /* NO_DEBUG */
|
||||||
|
|
||||||
|
void print_eeprom(void) {
|
||||||
|
#ifndef NO_DEBUG
|
||||||
|
int empty_rows = 0;
|
||||||
|
for (uint16_t i = 0; i < FEE_DENSITY_BYTES; i++) {
|
||||||
|
if (i % 16 == 0) {
|
||||||
|
if (i >= FEE_DENSITY_BYTES - 16) {
|
||||||
|
/* Make sure we display the last row */
|
||||||
|
empty_rows = 0;
|
||||||
|
}
|
||||||
|
/* Check if this row is uninitialized */
|
||||||
|
++empty_rows;
|
||||||
|
for (uint16_t j = 0; j < 16; j++) {
|
||||||
|
if (DataBuf[i + j]) {
|
||||||
|
empty_rows = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (empty_rows > 1) {
|
||||||
|
/* Repeat empty row */
|
||||||
|
if (empty_rows == 2) {
|
||||||
|
/* Only display the first repeat empty row */
|
||||||
|
println("*");
|
||||||
|
}
|
||||||
|
i += 15;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
xprintf("%04x", i);
|
||||||
|
}
|
||||||
|
if (i % 8 == 0) print(" ");
|
||||||
|
|
||||||
|
xprintf(" %02x", DataBuf[i]);
|
||||||
|
if ((i + 1) % 16 == 0) {
|
||||||
|
println("");
|
||||||
|
}
|
||||||
|
|
||||||
|
watchdog_update();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t EEPROM_Init(void) {
|
||||||
|
/* Load emulated eeprom contents from compacted flash into memory */
|
||||||
|
uint16_t *src = (uint16_t *)FEE_COMPACTED_BASE_ADDRESS;
|
||||||
|
uint16_t *dest = (uint16_t *)DataBuf;
|
||||||
|
for (; src < (uint16_t *)FEE_COMPACTED_LAST_ADDRESS; ++src, ++dest) {
|
||||||
|
*dest = ~*(uint16_t*)((void*)src + XIP_BASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug_eeprom) {
|
||||||
|
println("EEPROM_Init Compacted Pages:");
|
||||||
|
print_eeprom();
|
||||||
|
println("EEPROM_Init Write Log:");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(uint32_t*)(FEE_WRITE_LOG_BASE_ADDRESS + XIP_BASE) != FEE_MAGIC_DWORD) {
|
||||||
|
eeprom_clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Replay write log */
|
||||||
|
uint16_t *log_addr;
|
||||||
|
for (log_addr = (uint16_t *)(FEE_WRITE_LOG_BASE_ADDRESS + 4); log_addr < (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS; ++log_addr) {
|
||||||
|
|
||||||
|
watchdog_update();
|
||||||
|
|
||||||
|
uint16_t address = *(uint16_t*)((void*)log_addr + XIP_BASE);
|
||||||
|
if (address == FEE_EMPTY_WORD) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Check for lowest 128-bytes optimization */
|
||||||
|
if (!(address & FEE_WORD_ENCODING)) {
|
||||||
|
uint8_t bvalue = (uint8_t)address;
|
||||||
|
address >>= 8;
|
||||||
|
DataBuf[address] = bvalue;
|
||||||
|
eeprom_printf("DataBuf[0x%02x] = 0x%02x;\n", address, bvalue);
|
||||||
|
} else {
|
||||||
|
uint16_t wvalue;
|
||||||
|
/* Check if value is in next word */
|
||||||
|
if ((address & FEE_VALUE_NEXT) == FEE_VALUE_NEXT) {
|
||||||
|
/* Read value from next word */
|
||||||
|
if (++log_addr >= (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
wvalue = ~*(uint16_t *)((void *)log_addr + XIP_BASE);
|
||||||
|
if (!wvalue) {
|
||||||
|
eeprom_printf("Incomplete write at log_addr: 0x%04x;\n", (uint32_t)log_addr);
|
||||||
|
/* Possibly incomplete write. Ignore and continue */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
address &= 0x1FFF;
|
||||||
|
address <<= 1;
|
||||||
|
/* Writes to addresses less than 128 are byte log entries */
|
||||||
|
address += FEE_BYTE_RANGE;
|
||||||
|
} else {
|
||||||
|
/* Reserved for future use */
|
||||||
|
if (address & FEE_VALUE_RESERVED) {
|
||||||
|
eeprom_printf("Reserved encoded value at log_addr: 0x%04x;\n", (uint32_t)log_addr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Optimization for 0 or 1 values. */
|
||||||
|
wvalue = (address & FEE_VALUE_ENCODED) >> 13;
|
||||||
|
address &= 0x1FFF;
|
||||||
|
address <<= 1;
|
||||||
|
}
|
||||||
|
if (address < FEE_DENSITY_BYTES) {
|
||||||
|
eeprom_printf("DataBuf[0x%04x] = 0x%04x;\n", address, wvalue);
|
||||||
|
*(uint16_t *)(&DataBuf[address]) = wvalue;
|
||||||
|
} else {
|
||||||
|
eeprom_printf("DataBuf[0x%04x] cannot be set to 0x%04x [BAD ADDRESS]\n", address, wvalue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
empty_slot = log_addr;
|
||||||
|
|
||||||
|
if (debug_eeprom) {
|
||||||
|
println("EEPROM_Init Final DataBuf:");
|
||||||
|
print_eeprom();
|
||||||
|
eeprom_printf("Write Log Usage: %d/%d bytes\n ",
|
||||||
|
(uint32_t)empty_slot - FEE_WRITE_LOG_BASE_ADDRESS,
|
||||||
|
FEE_WRITE_LOG_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
return FEE_DENSITY_BYTES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear flash contents (doesn't touch in-memory DataBuf) */
|
||||||
|
static void eeprom_clear(void) {
|
||||||
|
FLASH_Unlock();
|
||||||
|
|
||||||
|
for (uint16_t page_num = 0; page_num < FEE_PAGE_COUNT; ++page_num) {
|
||||||
|
eeprom_printf("FLASH_ErasePage(0x%04x)\n", (uint32_t)(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE)));
|
||||||
|
FLASH_ErasePage(FEE_PAGE_BASE_ADDRESS + (page_num * FEE_PAGE_SIZE));
|
||||||
|
}
|
||||||
|
|
||||||
|
FLASH_ProgramHalfWord(FEE_WRITE_LOG_BASE_ADDRESS, FEE_MAGIC_DWORD & 0xffff);
|
||||||
|
FLASH_ProgramHalfWord(FEE_WRITE_LOG_BASE_ADDRESS + 2,
|
||||||
|
FEE_MAGIC_DWORD >> 16);
|
||||||
|
|
||||||
|
FLASH_Lock();
|
||||||
|
|
||||||
|
empty_slot = (uint16_t *)FEE_WRITE_LOG_BASE_ADDRESS;
|
||||||
|
eeprom_printf("eeprom_clear empty_slot: 0x%08x\n", (uint32_t)empty_slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Erase emulated eeprom */
|
||||||
|
void EEPROM_Erase(void) {
|
||||||
|
eeprom_println("EEPROM_Erase");
|
||||||
|
/* Erase compacted pages and write log */
|
||||||
|
eeprom_clear();
|
||||||
|
/* re-initialize to reset DataBuf */
|
||||||
|
EEPROM_Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compact write log */
|
||||||
|
static uint8_t eeprom_compact(void) {
|
||||||
|
/* Erase compacted pages and write log */
|
||||||
|
eeprom_clear();
|
||||||
|
|
||||||
|
FLASH_Unlock();
|
||||||
|
|
||||||
|
FLASH_Status final_status = FLASH_COMPLETE;
|
||||||
|
|
||||||
|
/* Write emulated eeprom contents from memory to compacted flash */
|
||||||
|
uint16_t *src = (uint16_t *)DataBuf;
|
||||||
|
uintptr_t dest = FEE_COMPACTED_BASE_ADDRESS;
|
||||||
|
uint16_t value;
|
||||||
|
for (; dest < FEE_COMPACTED_LAST_ADDRESS; ++src, dest += 2) {
|
||||||
|
value = *src;
|
||||||
|
if (value) {
|
||||||
|
eeprom_printf("FLASH_ProgramHalfWord(0x%04x, 0x%04x)\n", (uint32_t)dest, ~value);
|
||||||
|
FLASH_Status status = FLASH_ProgramHalfWord(dest, ~value);
|
||||||
|
if (status != FLASH_COMPLETE) final_status = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FLASH_Lock();
|
||||||
|
|
||||||
|
if (debug_eeprom) {
|
||||||
|
println("eeprom_compacted:");
|
||||||
|
print_eeprom();
|
||||||
|
}
|
||||||
|
|
||||||
|
return final_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t eeprom_write_direct_entry(uint16_t Address) {
|
||||||
|
/* Check if we can just write this directly to the compacted flash area */
|
||||||
|
uintptr_t directAddress = FEE_COMPACTED_BASE_ADDRESS + (Address & 0xFFFE);
|
||||||
|
if (*(uint16_t *)((void *)directAddress + XIP_BASE) == FEE_EMPTY_WORD) {
|
||||||
|
/* Write the value directly to the compacted area without a log entry */
|
||||||
|
uint16_t value = ~*(uint16_t *)(&DataBuf[Address & 0xFFFE]);
|
||||||
|
/* Early exit if a write isn't needed */
|
||||||
|
if (value == FEE_EMPTY_WORD) return FLASH_COMPLETE;
|
||||||
|
|
||||||
|
FLASH_Unlock();
|
||||||
|
|
||||||
|
eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x) [DIRECT]\n", (uint32_t)directAddress, value);
|
||||||
|
FLASH_Status status = FLASH_ProgramHalfWord(directAddress, value);
|
||||||
|
|
||||||
|
FLASH_Lock();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t eeprom_write_log_word_entry(uint16_t Address) {
|
||||||
|
FLASH_Status final_status = FLASH_COMPLETE;
|
||||||
|
|
||||||
|
uint16_t value = *(uint16_t *)(&DataBuf[Address]);
|
||||||
|
eeprom_printf("eeprom_write_log_word_entry(0x%04x): 0x%04x\n", Address, value);
|
||||||
|
|
||||||
|
/* MSB signifies the lowest 128-byte optimization is not in effect */
|
||||||
|
uint16_t encoding = FEE_WORD_ENCODING;
|
||||||
|
uint8_t entry_size;
|
||||||
|
if (value <= 1) {
|
||||||
|
encoding |= value << 13;
|
||||||
|
entry_size = 2;
|
||||||
|
} else {
|
||||||
|
encoding |= FEE_VALUE_NEXT;
|
||||||
|
entry_size = 4;
|
||||||
|
/* Writes to addresses less than 128 are byte log entries */
|
||||||
|
Address -= FEE_BYTE_RANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we can't find an empty spot, we must compact emulated eeprom */
|
||||||
|
if (empty_slot > (uint16_t *)(FEE_WRITE_LOG_LAST_ADDRESS - entry_size)) {
|
||||||
|
/* compact the write log into the compacted flash area */
|
||||||
|
return eeprom_compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Word log writes should be word-aligned. Take back a bit */
|
||||||
|
Address >>= 1;
|
||||||
|
Address |= encoding;
|
||||||
|
|
||||||
|
/* ok we found a place let's write our data */
|
||||||
|
FLASH_Unlock();
|
||||||
|
|
||||||
|
/* address */
|
||||||
|
eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, Address);
|
||||||
|
final_status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, Address);
|
||||||
|
|
||||||
|
/* value */
|
||||||
|
if (encoding == (FEE_WORD_ENCODING | FEE_VALUE_NEXT)) {
|
||||||
|
eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, ~value);
|
||||||
|
FLASH_Status status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, ~value);
|
||||||
|
if (status != FLASH_COMPLETE) final_status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLASH_Lock();
|
||||||
|
|
||||||
|
return final_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t eeprom_write_log_byte_entry(uint16_t Address) {
|
||||||
|
eeprom_printf("eeprom_write_log_byte_entry(0x%04x): 0x%02x\n", Address, DataBuf[Address]);
|
||||||
|
|
||||||
|
/* if couldn't find an empty spot, we must compact emulated eeprom */
|
||||||
|
if (empty_slot >= (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS) {
|
||||||
|
/* compact the write log into the compacted flash area */
|
||||||
|
return eeprom_compact();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ok we found a place let's write our data */
|
||||||
|
FLASH_Unlock();
|
||||||
|
|
||||||
|
/* Pack address and value into the same word */
|
||||||
|
uint16_t value = (Address << 8) | DataBuf[Address];
|
||||||
|
|
||||||
|
/* write to flash */
|
||||||
|
eeprom_printf("FLASH_ProgramHalfWord(0x%08x, 0x%04x)\n", (uint32_t)empty_slot, value);
|
||||||
|
FLASH_Status status = FLASH_ProgramHalfWord((uintptr_t)empty_slot++, value);
|
||||||
|
|
||||||
|
FLASH_Lock();
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte) {
|
||||||
|
/* if the address is out-of-bounds, do nothing */
|
||||||
|
if (Address >= FEE_DENSITY_BYTES) {
|
||||||
|
eeprom_printf("EEPROM_WriteDataByte(0x%04x, 0x%02x) [BAD ADDRESS]\n", Address, DataByte);
|
||||||
|
return FLASH_BAD_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if the value is the same, don't bother writing it */
|
||||||
|
if (DataBuf[Address] == DataByte) {
|
||||||
|
eeprom_printf("EEPROM_WriteDataByte(0x%04x, 0x%02x) [SKIP SAME]\n", Address, DataByte);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* keep DataBuf cache in sync */
|
||||||
|
DataBuf[Address] = DataByte;
|
||||||
|
eeprom_printf("EEPROM_WriteDataByte DataBuf[0x%04x] = 0x%02x\n", Address, DataBuf[Address]);
|
||||||
|
|
||||||
|
/* perform the write into flash memory */
|
||||||
|
/* First, attempt to write directly into the compacted flash area */
|
||||||
|
FLASH_Status status = eeprom_write_direct_entry(Address);
|
||||||
|
if (!status) {
|
||||||
|
/* Otherwise append to the write log */
|
||||||
|
if (Address < FEE_BYTE_RANGE) {
|
||||||
|
status = eeprom_write_log_byte_entry(Address);
|
||||||
|
} else {
|
||||||
|
status = eeprom_write_log_word_entry(Address & 0xFFFE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (status != 0 && status != FLASH_COMPLETE) {
|
||||||
|
eeprom_printf("EEPROM_WriteDataByte [STATUS == %d]\n", status);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t EEPROM_WriteDataWord(uint16_t Address, uint16_t DataWord) {
|
||||||
|
/* if the address is out-of-bounds, do nothing */
|
||||||
|
if (Address >= FEE_DENSITY_BYTES) {
|
||||||
|
eeprom_printf("EEPROM_WriteDataWord(0x%04x, 0x%04x) [BAD ADDRESS]\n", Address, DataWord);
|
||||||
|
return FLASH_BAD_ADDRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for word alignment */
|
||||||
|
FLASH_Status final_status = FLASH_COMPLETE;
|
||||||
|
if (Address % 2) {
|
||||||
|
final_status = EEPROM_WriteDataByte(Address, DataWord);
|
||||||
|
FLASH_Status status = EEPROM_WriteDataByte(Address + 1, DataWord >> 8);
|
||||||
|
if (status != FLASH_COMPLETE) final_status = status;
|
||||||
|
if (final_status != 0 && final_status != FLASH_COMPLETE) {
|
||||||
|
eeprom_printf("EEPROM_WriteDataWord [STATUS == %d]\n", final_status);
|
||||||
|
}
|
||||||
|
return final_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if the value is the same, don't bother writing it */
|
||||||
|
uint16_t oldValue = *(uint16_t *)(&DataBuf[Address]);
|
||||||
|
if (oldValue == DataWord) {
|
||||||
|
eeprom_printf("EEPROM_WriteDataWord(0x%04x, 0x%04x) [SKIP SAME]\n", Address, DataWord);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* keep DataBuf cache in sync */
|
||||||
|
*(uint16_t *)(&DataBuf[Address]) = DataWord;
|
||||||
|
eeprom_printf("EEPROM_WriteDataWord DataBuf[0x%04x] = 0x%04x\n", Address, *(uint16_t *)(&DataBuf[Address]));
|
||||||
|
|
||||||
|
/* perform the write into flash memory */
|
||||||
|
/* First, attempt to write directly into the compacted flash area */
|
||||||
|
final_status = eeprom_write_direct_entry(Address);
|
||||||
|
if (!final_status) {
|
||||||
|
/* Otherwise append to the write log */
|
||||||
|
/* Check if we need to fall back to byte write */
|
||||||
|
if (Address < FEE_BYTE_RANGE) {
|
||||||
|
final_status = FLASH_COMPLETE;
|
||||||
|
/* Only write a byte if it has changed */
|
||||||
|
if ((uint8_t)oldValue != (uint8_t)DataWord) {
|
||||||
|
final_status = eeprom_write_log_byte_entry(Address);
|
||||||
|
}
|
||||||
|
FLASH_Status status = FLASH_COMPLETE;
|
||||||
|
/* Only write a byte if it has changed */
|
||||||
|
if ((oldValue >> 8) != (DataWord >> 8)) {
|
||||||
|
status = eeprom_write_log_byte_entry(Address + 1);
|
||||||
|
}
|
||||||
|
if (status != FLASH_COMPLETE) final_status = status;
|
||||||
|
} else {
|
||||||
|
final_status = eeprom_write_log_word_entry(Address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (final_status != 0 && final_status != FLASH_COMPLETE) {
|
||||||
|
eeprom_printf("EEPROM_WriteDataWord [STATUS == %d]\n", final_status);
|
||||||
|
}
|
||||||
|
return final_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t EEPROM_ReadDataByte(uint16_t Address) {
|
||||||
|
uint8_t DataByte = 0xFF;
|
||||||
|
|
||||||
|
if (Address < FEE_DENSITY_BYTES) {
|
||||||
|
DataByte = DataBuf[Address];
|
||||||
|
}
|
||||||
|
|
||||||
|
eeprom_printf("EEPROM_ReadDataByte(0x%04x): 0x%02x\n", Address, DataByte);
|
||||||
|
|
||||||
|
return DataByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t EEPROM_ReadDataWord(uint16_t Address) {
|
||||||
|
uint16_t DataWord = 0xFFFF;
|
||||||
|
|
||||||
|
if (Address < FEE_DENSITY_BYTES - 1) {
|
||||||
|
/* Check word alignment */
|
||||||
|
if (Address % 2) {
|
||||||
|
DataWord = DataBuf[Address] | (DataBuf[Address + 1] << 8);
|
||||||
|
} else {
|
||||||
|
DataWord = *(uint16_t *)(&DataBuf[Address]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eeprom_printf("EEPROM_ReadDataWord(0x%04x): 0x%04x\n", Address, DataWord);
|
||||||
|
|
||||||
|
return DataWord;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Wrap library in AVR style functions.
|
||||||
|
*******************************************************************************/
|
||||||
|
uint8_t eeprom_read_byte(const uint8_t *Address) { return EEPROM_ReadDataByte((const uintptr_t)Address); }
|
||||||
|
|
||||||
|
void eeprom_write_byte(uint8_t *Address, uint8_t Value) { EEPROM_WriteDataByte((uintptr_t)Address, Value); }
|
||||||
|
|
||||||
|
void eeprom_update_byte(uint8_t *Address, uint8_t Value) { EEPROM_WriteDataByte((uintptr_t)Address, Value); }
|
||||||
|
|
||||||
|
uint16_t eeprom_read_word(const uint16_t *Address) { return EEPROM_ReadDataWord((const uintptr_t)Address); }
|
||||||
|
|
||||||
|
void eeprom_write_word(uint16_t *Address, uint16_t Value) { EEPROM_WriteDataWord((uintptr_t)Address, Value); }
|
||||||
|
|
||||||
|
void eeprom_update_word(uint16_t *Address, uint16_t Value) { EEPROM_WriteDataWord((uintptr_t)Address, Value); }
|
||||||
|
|
||||||
|
uint32_t eeprom_read_dword(const uint32_t *Address) {
|
||||||
|
const uint16_t p = (const uintptr_t)Address;
|
||||||
|
/* Check word alignment */
|
||||||
|
if (p % 2) {
|
||||||
|
/* Not aligned */
|
||||||
|
return (uint32_t)EEPROM_ReadDataByte(p) | (uint32_t)(EEPROM_ReadDataWord(p + 1) << 8) | (uint32_t)(EEPROM_ReadDataByte(p + 3) << 24);
|
||||||
|
} else {
|
||||||
|
/* Aligned */
|
||||||
|
return EEPROM_ReadDataWord(p) | (EEPROM_ReadDataWord(p + 2) << 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void eeprom_write_dword(uint32_t *Address, uint32_t Value) {
|
||||||
|
uint16_t p = (const uintptr_t)Address;
|
||||||
|
/* Check word alignment */
|
||||||
|
if (p % 2) {
|
||||||
|
/* Not aligned */
|
||||||
|
EEPROM_WriteDataByte(p, (uint8_t)Value);
|
||||||
|
EEPROM_WriteDataWord(p + 1, (uint16_t)(Value >> 8));
|
||||||
|
EEPROM_WriteDataByte(p + 3, (uint8_t)(Value >> 24));
|
||||||
|
} else {
|
||||||
|
/* Aligned */
|
||||||
|
EEPROM_WriteDataWord(p, (uint16_t)Value);
|
||||||
|
EEPROM_WriteDataWord(p + 2, (uint16_t)(Value >> 16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void eeprom_update_dword(uint32_t *Address, uint32_t Value) { eeprom_write_dword(Address, Value); }
|
||||||
|
|
||||||
|
void eeprom_read_block(void *buf, const void *addr, size_t len) {
|
||||||
|
const uint8_t *src = (const uint8_t *)addr;
|
||||||
|
uint8_t * dest = (uint8_t *)buf;
|
||||||
|
|
||||||
|
/* Check word alignment */
|
||||||
|
if (len && (uintptr_t)src % 2) {
|
||||||
|
/* Read the unaligned first byte */
|
||||||
|
*dest++ = eeprom_read_byte(src++);
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t value;
|
||||||
|
bool aligned = ((uintptr_t)dest % 2 == 0);
|
||||||
|
while (len > 1) {
|
||||||
|
value = eeprom_read_word((uint16_t *)src);
|
||||||
|
if (aligned) {
|
||||||
|
*(uint16_t *)dest = value;
|
||||||
|
dest += 2;
|
||||||
|
} else {
|
||||||
|
*dest++ = value;
|
||||||
|
*dest++ = value >> 8;
|
||||||
|
}
|
||||||
|
src += 2;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
if (len) {
|
||||||
|
*dest = eeprom_read_byte(src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void eeprom_write_block(const void *buf, void *addr, size_t len) {
|
||||||
|
uint8_t * dest = (uint8_t *)addr;
|
||||||
|
const uint8_t *src = (const uint8_t *)buf;
|
||||||
|
|
||||||
|
/* Check word alignment */
|
||||||
|
if (len && (uintptr_t)dest % 2) {
|
||||||
|
/* Write the unaligned first byte */
|
||||||
|
eeprom_write_byte(dest++, *src++);
|
||||||
|
--len;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t value;
|
||||||
|
bool aligned = ((uintptr_t)src % 2 == 0);
|
||||||
|
while (len > 1) {
|
||||||
|
if (aligned) {
|
||||||
|
value = *(uint16_t *)src;
|
||||||
|
} else {
|
||||||
|
value = *(uint8_t *)src | (*(uint8_t *)(src + 1) << 8);
|
||||||
|
}
|
||||||
|
eeprom_write_word((uint16_t *)dest, value);
|
||||||
|
dest += 2;
|
||||||
|
src += 2;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len) {
|
||||||
|
eeprom_write_byte(dest, *src);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void eeprom_update_block(const void *buf, void *addr, size_t len) { eeprom_write_block(buf, addr, len); }
|
||||||
33
platforms/pico/eeprom_pico.h
Normal file
33
platforms/pico/eeprom_pico.h
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* This software is experimental and a work in progress.
|
||||||
|
* Under no circumstances should these files be used in relation to any critical system(s).
|
||||||
|
* Use of these files is at your own risk.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* This files are free to use from http://engsta.com/stm32-flash-memory-eeprom-emulator/ by
|
||||||
|
* Artur F.
|
||||||
|
*
|
||||||
|
* Modifications for QMK and STM32F303 by Yiancar
|
||||||
|
*
|
||||||
|
* This library assumes 8-bit data locations. To add a new MCU, please provide the flash
|
||||||
|
* page size and the total flash size in Kb. The number of available pages must be a multiple
|
||||||
|
* of 2. Only half of the pages account for the total EEPROM size.
|
||||||
|
* This library also assumes that the pages are not used by the firmware.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
uint16_t EEPROM_Init(void);
|
||||||
|
void EEPROM_Erase(void);
|
||||||
|
uint8_t EEPROM_WriteDataByte(uint16_t Address, uint8_t DataByte);
|
||||||
|
uint8_t EEPROM_WriteDataWord(uint16_t Address, uint16_t DataWord);
|
||||||
|
uint8_t EEPROM_ReadDataByte(uint16_t Address);
|
||||||
|
uint16_t EEPROM_ReadDataWord(uint16_t Address);
|
||||||
|
|
||||||
|
void print_eeprom(void);
|
||||||
13
platforms/pico/eeprom_pico_defs.h
Normal file
13
platforms/pico/eeprom_pico_defs.h
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hardware/flash.h"
|
||||||
|
#include "hardware/structs/ssi.h"
|
||||||
|
|
||||||
|
#define FEE_PAGE_SIZE FLASH_SECTOR_SIZE
|
||||||
|
#define FEE_PAGE_COUNT 2
|
||||||
|
#define FEE_MCU_FLASH_SIZE (PICO_FLASH_SIZE_BYTES / 1024)
|
||||||
|
#define FEE_PAGE_BASE_ADDRESS \
|
||||||
|
(PICO_FLASH_SIZE_BYTES - FEE_PAGE_SIZE * FEE_PAGE_COUNT)
|
||||||
|
|
||||||
|
#define FEE_DENSITY_BYTES (FEE_PAGE_COUNT * FEE_PAGE_SIZE / 2)
|
||||||
201
platforms/pico/flash_pico.c
Normal file
201
platforms/pico/flash_pico.c
Normal file
|
|
@ -0,0 +1,201 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "flash_pico.h"
|
||||||
|
|
||||||
|
#include "pico/bootrom.h"
|
||||||
|
#include "hardware/flash.h"
|
||||||
|
#include "hardware/sync.h"
|
||||||
|
#include "hardware/structs/ssi.h"
|
||||||
|
#include "hardware/structs/ioqspi.h"
|
||||||
|
|
||||||
|
#define BOOT2_SIZE_WORDS 64
|
||||||
|
#define FLASHCMD_PAGE_PROGRAM 0x02
|
||||||
|
#define FLASHCMD_READ_STATUS 0x05
|
||||||
|
#define FLASHCMD_WRITE_ENABLE 0x06
|
||||||
|
|
||||||
|
static ssi_hw_t *const ssi = (ssi_hw_t *)XIP_SSI_BASE;
|
||||||
|
|
||||||
|
// Sanity check
|
||||||
|
#undef static_assert
|
||||||
|
#define static_assert(cond, x) extern int static_assert[(cond) ? 1 : -1]
|
||||||
|
check_hw_layout(ssi_hw_t, ssienr, SSI_SSIENR_OFFSET);
|
||||||
|
check_hw_layout(ssi_hw_t, spi_ctrlr0, SSI_SPI_CTRLR0_OFFSET);
|
||||||
|
|
||||||
|
static uint32_t boot2_copyout[BOOT2_SIZE_WORDS];
|
||||||
|
static bool boot2_copyout_valid = false;
|
||||||
|
|
||||||
|
static void __no_inline_not_in_flash_func(flash_init_boot2_copyout)(void) {
|
||||||
|
if (boot2_copyout_valid) return;
|
||||||
|
for (int i = 0; i < BOOT2_SIZE_WORDS; ++i)
|
||||||
|
boot2_copyout[i] = ((uint32_t *)XIP_BASE)[i];
|
||||||
|
__compiler_memory_barrier();
|
||||||
|
boot2_copyout_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __no_inline_not_in_flash_func(flash_enable_xip_via_boot2)(void) {
|
||||||
|
((void (*)(void))boot2_copyout + 1)();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bitbanging the chip select using IO overrides, in case RAM-resident IRQs
|
||||||
|
// are still running, and the FIFO bottoms out. (the bootrom does the same)
|
||||||
|
static void __no_inline_not_in_flash_func(flash_cs_force)(bool high) {
|
||||||
|
uint32_t field_val = high ? IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH
|
||||||
|
: IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW;
|
||||||
|
hw_write_masked(&ioqspi_hw->io[1].ctrl,
|
||||||
|
field_val << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB,
|
||||||
|
IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also allow any unbounded loops to check whether the above abort condition
|
||||||
|
// was asserted, and terminate early
|
||||||
|
static int __no_inline_not_in_flash_func(flash_was_aborted)(void) {
|
||||||
|
return *(io_rw_32 *)(IO_QSPI_BASE + IO_QSPI_GPIO_QSPI_SD1_CTRL_OFFSET) &
|
||||||
|
IO_QSPI_GPIO_QSPI_SD1_CTRL_INOVER_BITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put bytes from one buffer, and get bytes into another buffer.
|
||||||
|
// These can be the same buffer.
|
||||||
|
// If tx is NULL then send zeroes.
|
||||||
|
// If rx is NULL then all read data will be dropped.
|
||||||
|
//
|
||||||
|
// If rx_skip is nonzero, this many bytes will first be consumed from the FIFO,
|
||||||
|
// before reading a further count bytes into *rx.
|
||||||
|
// E.g. if you have written a command+address just before calling this function.
|
||||||
|
static void __no_inline_not_in_flash_func(flash_put_get)(const uint8_t *tx,
|
||||||
|
uint8_t * rx,
|
||||||
|
size_t count,
|
||||||
|
size_t rx_skip) {
|
||||||
|
// Make sure there is never more data in flight than the depth of the RX
|
||||||
|
// FIFO. Otherwise, when we are interrupted for long periods, hardware
|
||||||
|
// will overflow the RX FIFO.
|
||||||
|
const uint max_in_flight = 16 - 2; // account for data internal to SSI
|
||||||
|
size_t tx_count = count;
|
||||||
|
size_t rx_count = count;
|
||||||
|
while (tx_count || rx_skip || rx_count) {
|
||||||
|
// NB order of reads, for pessimism rather than optimism
|
||||||
|
uint32_t tx_level = ssi_hw->txflr;
|
||||||
|
uint32_t rx_level = ssi_hw->rxflr;
|
||||||
|
bool did_something =
|
||||||
|
false; // Expect this to be folded into control flow, not register
|
||||||
|
if (tx_count && tx_level + rx_level < max_in_flight) {
|
||||||
|
ssi->dr0 = (uint32_t)(tx ? *tx++ : 0);
|
||||||
|
--tx_count;
|
||||||
|
did_something = true;
|
||||||
|
}
|
||||||
|
if (rx_level) {
|
||||||
|
uint8_t rxbyte = ssi->dr0;
|
||||||
|
did_something = true;
|
||||||
|
if (rx_skip) {
|
||||||
|
--rx_skip;
|
||||||
|
} else {
|
||||||
|
if (rx) *rx++ = rxbyte;
|
||||||
|
--rx_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// APB load costs 4 cycles, so only do it on idle loops (our budget is
|
||||||
|
// 48 cyc/byte)
|
||||||
|
if (!did_something && __builtin_expect(flash_was_aborted(), 0)) break;
|
||||||
|
}
|
||||||
|
flash_cs_force(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convenience wrapper for above
|
||||||
|
// (And it's hard for the debug host to get the tight timing between
|
||||||
|
// cmd DR0 write and the remaining data)
|
||||||
|
static void __no_inline_not_in_flash_func(_flash_do_cmd)(uint8_t cmd,
|
||||||
|
const uint8_t *tx,
|
||||||
|
uint8_t * rx,
|
||||||
|
size_t count) {
|
||||||
|
flash_cs_force(0);
|
||||||
|
ssi->dr0 = cmd;
|
||||||
|
flash_put_get(tx, rx, count, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timing of this one is critical, so do not expose the symbol to debugger etc
|
||||||
|
static void __no_inline_not_in_flash_func(flash_put_cmd_addr)(uint8_t cmd,
|
||||||
|
uint32_t addr) {
|
||||||
|
flash_cs_force(0);
|
||||||
|
addr |= cmd << 24;
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
ssi->dr0 = addr >> 24;
|
||||||
|
addr <<= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Poll the flash status register until the busy bit (LSB) clears
|
||||||
|
static void __no_inline_not_in_flash_func(flash_wait_ready)(void) {
|
||||||
|
uint8_t stat;
|
||||||
|
do {
|
||||||
|
_flash_do_cmd(FLASHCMD_READ_STATUS, NULL, &stat, 1);
|
||||||
|
} while (stat & 0x1 && !flash_was_aborted());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the WEL bit (needed before any program/erase operation)
|
||||||
|
static void __no_inline_not_in_flash_func(flash_enable_write)(void) {
|
||||||
|
_flash_do_cmd(FLASHCMD_WRITE_ENABLE, NULL, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __no_inline_not_in_flash_func(pico_program_half_word)(
|
||||||
|
uint32_t flash_offs, uint16_t data) {
|
||||||
|
rom_connect_internal_flash_fn connect_internal_flash =
|
||||||
|
(rom_connect_internal_flash_fn)rom_func_lookup_inline(
|
||||||
|
ROM_FUNC_CONNECT_INTERNAL_FLASH);
|
||||||
|
rom_flash_exit_xip_fn flash_exit_xip =
|
||||||
|
(rom_flash_exit_xip_fn)rom_func_lookup_inline(ROM_FUNC_FLASH_EXIT_XIP);
|
||||||
|
rom_flash_range_program_fn flash_range_program =
|
||||||
|
(rom_flash_range_program_fn)rom_func_lookup_inline(
|
||||||
|
ROM_FUNC_FLASH_RANGE_PROGRAM);
|
||||||
|
rom_flash_flush_cache_fn flash_flush_cache =
|
||||||
|
(rom_flash_flush_cache_fn)rom_func_lookup_inline(
|
||||||
|
ROM_FUNC_FLASH_FLUSH_CACHE);
|
||||||
|
assert(connect_internal_flash && flash_exit_xip && flash_range_program &&
|
||||||
|
flash_flush_cache);
|
||||||
|
flash_init_boot2_copyout();
|
||||||
|
|
||||||
|
__compiler_memory_barrier();
|
||||||
|
|
||||||
|
connect_internal_flash();
|
||||||
|
flash_exit_xip();
|
||||||
|
|
||||||
|
flash_enable_write();
|
||||||
|
flash_put_cmd_addr(FLASHCMD_PAGE_PROGRAM, flash_offs);
|
||||||
|
flash_put_get((uint8_t *)&data, NULL, 2, 4);
|
||||||
|
flash_wait_ready();
|
||||||
|
|
||||||
|
flash_flush_cache(); // Note this is needed to remove CSn IO force as well
|
||||||
|
// as cache flushing
|
||||||
|
flash_enable_xip_via_boot2();
|
||||||
|
}
|
||||||
|
|
||||||
|
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout) {
|
||||||
|
return FLASH_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLASH_Status FLASH_ErasePage(uint32_t Page_Address) {
|
||||||
|
flash_range_erase(Page_Address, FLASH_SECTOR_SIZE);
|
||||||
|
return FLASH_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) {
|
||||||
|
pico_program_half_word(Address, Data);
|
||||||
|
return FLASH_COMPLETE;
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((weak)) void pico_before_flash_operation(void) {}
|
||||||
|
__attribute__((weak)) void pico_after_flash_operation(void) {}
|
||||||
|
|
||||||
|
static int intr_stat;
|
||||||
|
|
||||||
|
void FLASH_Lock(void) {
|
||||||
|
restore_interrupts(intr_stat);
|
||||||
|
pico_after_flash_operation();
|
||||||
|
}
|
||||||
|
void FLASH_Unlock(void) {
|
||||||
|
intr_stat = save_and_disable_interrupts();
|
||||||
|
pico_before_flash_operation();
|
||||||
|
}
|
||||||
44
platforms/pico/flash_pico.h
Normal file
44
platforms/pico/flash_pico.h
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* This software is experimental and a work in progress.
|
||||||
|
* Under no circumstances should these files be used in relation to any critical system(s).
|
||||||
|
* Use of these files is at your own risk.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* This files are free to use from https://github.com/rogerclarkmelbourne/Arduino_STM32 and
|
||||||
|
* https://github.com/leaflabs/libmaple
|
||||||
|
*
|
||||||
|
* Modifications for QMK and STM32F303 by Yiancar
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef FLASH_STM32_MOCKED
|
||||||
|
extern uint8_t FlashBuf[MOCK_FLASH_SIZE];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum { FLASH_BUSY = 1, FLASH_ERROR_PG, FLASH_ERROR_WRP, FLASH_ERROR_OPT, FLASH_COMPLETE, FLASH_TIMEOUT, FLASH_BAD_ADDRESS } FLASH_Status;
|
||||||
|
|
||||||
|
#define IS_FLASH_ADDRESS(ADDRESS) (((ADDRESS) >= 0x08000000) && ((ADDRESS) < 0x0807FFFF))
|
||||||
|
|
||||||
|
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout);
|
||||||
|
FLASH_Status FLASH_ErasePage(uint32_t Page_Address);
|
||||||
|
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data);
|
||||||
|
|
||||||
|
void FLASH_Unlock(void);
|
||||||
|
void FLASH_Lock(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
34
platforms/pico/gpio.h
Normal file
34
platforms/pico/gpio.h
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
/* Copyright 2021 QMK
|
||||||
|
*
|
||||||
|
* 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 "pico/stdlib.h"
|
||||||
|
#include "pin_defs.h"
|
||||||
|
|
||||||
|
typedef uint8_t pin_t;
|
||||||
|
|
||||||
|
#define setPinInput(pin) (gpio_disable_pulls(pin), gpio_set_dir(pin, GPIO_IN))
|
||||||
|
#define setPinInputHigh(pin) (gpio_set_dir(pin, GPIO_IN), gpio_pull_up(pin))
|
||||||
|
#define setPinInputLow(pin) (gpio_init(pin), gpio_set_dir(pin, GPIO_IN), gpio_pull_down(pin))
|
||||||
|
#define setPinOutput(pin) (gpio_set_dir(pin, GPIO_OUT))
|
||||||
|
|
||||||
|
#define writePinHigh(pin) (gpio_put(pin, 1))
|
||||||
|
#define writePinLow(pin) (gpio_put(pin, 0))
|
||||||
|
#define writePin(pin, level) ((level) ? writePinHigh(pin) : writePinLow(pin))
|
||||||
|
|
||||||
|
#define readPin(pin) (gpio_get(pin))
|
||||||
|
|
||||||
|
#define togglePin(pin) (gpio_out(pin, !gpio_get(pin)))
|
||||||
17
platforms/pico/pin_defs.h
Normal file
17
platforms/pico/pin_defs.h
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
/* Copyright 2021 QMK
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
30
platforms/pico/platform.c
Normal file
30
platforms/pico/platform.c
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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 "platform_deps.h"
|
||||||
|
#include "quantum.h"
|
||||||
|
#include "hardware/adc.h"
|
||||||
|
|
||||||
|
uint32_t interrupts;
|
||||||
|
|
||||||
|
void platform_setup(void) {
|
||||||
|
for (int i = 0; i < 32; i++) {
|
||||||
|
gpio_init(i);
|
||||||
|
setPinInputHigh(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
adc_init();
|
||||||
|
}
|
||||||
404
platforms/pico/platform.mk
Normal file
404
platforms/pico/platform.mk
Normal file
|
|
@ -0,0 +1,404 @@
|
||||||
|
|
||||||
|
CC = arm-none-eabi-gcc
|
||||||
|
OBJCOPY = arm-none-eabi-objcopy
|
||||||
|
OBJDUMP = arm-none-eabi-objdump
|
||||||
|
SIZE = arm-none-eabi-size
|
||||||
|
AR = arm-none-eabi-ar
|
||||||
|
NM = arm-none-eabi-nm
|
||||||
|
HEX = $(OBJCOPY) -O $(FORMAT)
|
||||||
|
EEP =
|
||||||
|
BIN = $(OBJCOPY) -O binary
|
||||||
|
|
||||||
|
ALLOW_WARNINGS := yes
|
||||||
|
OPT_DEFS += -DPROTOCOL_PICO
|
||||||
|
OPT_DEFS += -DSPLIT_USB_DETECT
|
||||||
|
PICOTOOL ?= picotool
|
||||||
|
RP2BOOT_ID ?= "2e8a:0003"
|
||||||
|
LSUSB ?= lsusb
|
||||||
|
|
||||||
|
PICO_SDK_PATH = lib/pico-sdk
|
||||||
|
|
||||||
|
PICO_SDK_EXIST = $(shell test -d $(PICO_SDK_PATH)/src && echo true)
|
||||||
|
ifneq ($(PICO_SDK_EXIST),true)
|
||||||
|
$(error pico-sdk does not found at PICO_SDK_PATH. Please setup pico-sdk.)
|
||||||
|
endif
|
||||||
|
|
||||||
|
GIT_DESCRIBE = $(shell git describe --tags --long --dirty="\\*")
|
||||||
|
|
||||||
|
ifneq ($(PICO_FLASH_SPI_CLKDIV),)
|
||||||
|
CFLAGS += -DPICO_FLASH_SPI_CLKDIV=$(PICO_FLASH_SPI_CLKDIV)
|
||||||
|
else
|
||||||
|
CFLAGS += -DPICO_FLASH_SPI_CLKDIV=4
|
||||||
|
endif
|
||||||
|
|
||||||
|
CFLAGS += -DCFG_TUSB_DEBUG=0
|
||||||
|
CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_RP2040
|
||||||
|
CFLAGS += -DCFG_TUSB_OS=OPT_OS_PICO
|
||||||
|
CFLAGS += -DLIB_PICO_BIT_OPS=1
|
||||||
|
CFLAGS += -DLIB_PICO_BIT_OPS_PICO=1
|
||||||
|
CFLAGS += -DLIB_PICO_BOOTSEL_VIA_DOUBLE_RESET=1
|
||||||
|
CFLAGS += -DLIB_PICO_DIVIDER=1
|
||||||
|
CFLAGS += -DLIB_PICO_DIVIDER_HARDWARE=1
|
||||||
|
CFLAGS += -DLIB_PICO_DOUBLE=1
|
||||||
|
CFLAGS += -DLIB_PICO_DOUBLE_PICO=1
|
||||||
|
CFLAGS += -DLIB_PICO_FIX_RP2040_USB_DEVICE_ENUMERATION=1
|
||||||
|
CFLAGS += -DLIB_PICO_FLOAT=1
|
||||||
|
CFLAGS += -DLIB_PICO_FLOAT_PICO=1
|
||||||
|
CFLAGS += -DLIB_PICO_INT64_OPS=1
|
||||||
|
CFLAGS += -DLIB_PICO_INT64_OPS_PICO=1
|
||||||
|
CFLAGS += -DLIB_PICO_MALLOC=1
|
||||||
|
CFLAGS += -DLIB_PICO_MEM_OPS=1
|
||||||
|
CFLAGS += -DLIB_PICO_MEM_OPS_PICO=1
|
||||||
|
CFLAGS += -DLIB_PICO_PLATFORM=1
|
||||||
|
CFLAGS += -DLIB_PICO_PRINTF=1
|
||||||
|
CFLAGS += -DLIB_PICO_PRINTF_PICO=1
|
||||||
|
CFLAGS += -DLIB_PICO_RUNTIME=1
|
||||||
|
CFLAGS += -DLIB_PICO_STANDARD_LINK=1
|
||||||
|
CFLAGS += -DLIB_PICO_STDIO=1
|
||||||
|
CFLAGS += -DLIB_PICO_STDIO_UART=1
|
||||||
|
CFLAGS += -DLIB_PICO_STDLIB=1
|
||||||
|
CFLAGS += -DLIB_PICO_SYNC=1
|
||||||
|
CFLAGS += -DLIB_PICO_SYNC_CORE=1
|
||||||
|
CFLAGS += -DLIB_PICO_SYNC_CRITICAL_SECTION=1
|
||||||
|
CFLAGS += -DLIB_PICO_SYNC_MUTEX=1
|
||||||
|
CFLAGS += -DLIB_PICO_SYNC_SEM=1
|
||||||
|
CFLAGS += -DLIB_PICO_TIME=1
|
||||||
|
CFLAGS += -DLIB_PICO_UTIL=1
|
||||||
|
CFLAGS += -DLIB_TINYUSB_BOARD=1
|
||||||
|
CFLAGS += -DLIB_TINYUSB_DEVICE=1
|
||||||
|
CFLAGS += -DPICO_BOARD=\"pico\"
|
||||||
|
CFLAGS += -DPICO_BUILD=1
|
||||||
|
CFLAGS += -DPICO_COPY_TO_RAM=0
|
||||||
|
CFLAGS += -DPICO_CXX_ENABLE_EXCEPTIONS=0
|
||||||
|
CFLAGS += -DPICO_NO_FLASH=0
|
||||||
|
CFLAGS += -DPICO_NO_HARDWARE=0
|
||||||
|
CFLAGS += -DPICO_ON_DEVICE=1
|
||||||
|
CFLAGS += -DPICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1
|
||||||
|
CFLAGS += -DPICO_TARGET_NAME=\"$(TARGET)\"
|
||||||
|
CFLAGS += -DPICO_PROGRAM_VERSION_STRING=\"$(GIT_DESCRIBE)\"
|
||||||
|
CFLAGS += -DPICO_USE_BLOCKED_RAM=0
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/common/pico_stdlib/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_flash/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_gpio/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/common/pico_base/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/boards/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/pico_platform/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2040/hardware_regs/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_base/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2040/hardware_structs/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_adc/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_claim/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_dma/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_sync/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_uart/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_i2c/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_spi/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_pio/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_pwm/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_divider/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/common/pico_time/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_timer/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/common/pico_sync/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/common/pico_util/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/pico_runtime/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_clocks/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_irq/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_resets/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_pll/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_vreg/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_watchdog/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/hardware_xosc/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/pico_printf/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/pico_bootrom/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/common/pico_bit_ops/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/common/pico_divider/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/pico_double/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/pico_int64_ops/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/pico_float/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/pico_malloc/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/boot_stage2/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/common/pico_binary_info/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/pico_stdio/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/pico_stdio_uart/include
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/lib/tinyusb/src
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/lib/tinyusb/src/common
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/lib/tinyusb/hw
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/lib/tinyusb/src/class/hid
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/lib/tinyusb/src/class/cdc
|
||||||
|
CFLAGS += -I$(PICO_SDK_PATH)/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/include
|
||||||
|
CFLAGS += -mcpu=cortex-m0plus
|
||||||
|
CFLAGS += -mthumb
|
||||||
|
CFLAGS += -O0 -g3
|
||||||
|
# CFLAGS += -DNDEBUG
|
||||||
|
CFLAGS += -Wall
|
||||||
|
CFLAGS += -Wno-format
|
||||||
|
CFLAGS += -Wno-unused-function
|
||||||
|
CFLAGS += -Wno-maybe-uninitialized
|
||||||
|
CFLAGS += -ffunction-sections
|
||||||
|
CFLAGS += -fdata-sections
|
||||||
|
CFLAGS += -std=gnu11
|
||||||
|
|
||||||
|
ASFLAGS += $(CFLAGS)
|
||||||
|
|
||||||
|
LDFLAGS += -Wl,--build-id=none
|
||||||
|
LDFLAGS += --specs=nosys.specs
|
||||||
|
LDFLAGS += -Wl,--wrap=sprintf
|
||||||
|
LDFLAGS += -Wl,--wrap=snprintf
|
||||||
|
LDFLAGS += -Wl,--wrap=vsnprintf
|
||||||
|
LDFLAGS += -Wl,--wrap=__clzsi2
|
||||||
|
LDFLAGS += -Wl,--wrap=__clzdi2
|
||||||
|
LDFLAGS += -Wl,--wrap=__ctzsi2
|
||||||
|
LDFLAGS += -Wl,--wrap=__ctzdi2
|
||||||
|
LDFLAGS += -Wl,--wrap=__popcountsi2
|
||||||
|
LDFLAGS += -Wl,--wrap=__popcountdi2
|
||||||
|
LDFLAGS += -Wl,--wrap=__clz
|
||||||
|
LDFLAGS += -Wl,--wrap=__clzl
|
||||||
|
LDFLAGS += -Wl,--wrap=__clzll
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_idiv
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_idivmod
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_ldivmod
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_uidiv
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_uidivmod
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_uldivmod
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_dadd
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_ddiv
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_dmul
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_drsub
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_dsub
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_cdcmpeq
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_cdrcmple
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_cdcmple
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_dcmpeq
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_dcmplt
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_dcmple
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_dcmpge
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_dcmpgt
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_dcmpun
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_i2d
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_l2d
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_ui2d
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_ul2d
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_d2iz
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_d2lz
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_d2uiz
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_d2ulz
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_d2f
|
||||||
|
LDFLAGS += -Wl,--wrap=sqrt
|
||||||
|
LDFLAGS += -Wl,--wrap=cos
|
||||||
|
LDFLAGS += -Wl,--wrap=sin
|
||||||
|
LDFLAGS += -Wl,--wrap=tan
|
||||||
|
LDFLAGS += -Wl,--wrap=atan2
|
||||||
|
LDFLAGS += -Wl,--wrap=exp
|
||||||
|
LDFLAGS += -Wl,--wrap=log
|
||||||
|
LDFLAGS += -Wl,--wrap=ldexp
|
||||||
|
LDFLAGS += -Wl,--wrap=copysign
|
||||||
|
LDFLAGS += -Wl,--wrap=trunc
|
||||||
|
LDFLAGS += -Wl,--wrap=floor
|
||||||
|
LDFLAGS += -Wl,--wrap=ceil
|
||||||
|
LDFLAGS += -Wl,--wrap=round
|
||||||
|
LDFLAGS += -Wl,--wrap=sincos
|
||||||
|
LDFLAGS += -Wl,--wrap=asin
|
||||||
|
LDFLAGS += -Wl,--wrap=acos
|
||||||
|
LDFLAGS += -Wl,--wrap=atan
|
||||||
|
LDFLAGS += -Wl,--wrap=sinh
|
||||||
|
LDFLAGS += -Wl,--wrap=cosh
|
||||||
|
LDFLAGS += -Wl,--wrap=tanh
|
||||||
|
LDFLAGS += -Wl,--wrap=asinh
|
||||||
|
LDFLAGS += -Wl,--wrap=acosh
|
||||||
|
LDFLAGS += -Wl,--wrap=atanh
|
||||||
|
LDFLAGS += -Wl,--wrap=exp2
|
||||||
|
LDFLAGS += -Wl,--wrap=log2
|
||||||
|
LDFLAGS += -Wl,--wrap=exp10
|
||||||
|
LDFLAGS += -Wl,--wrap=log10
|
||||||
|
LDFLAGS += -Wl,--wrap=pow
|
||||||
|
LDFLAGS += -Wl,--wrap=powint
|
||||||
|
LDFLAGS += -Wl,--wrap=hypot
|
||||||
|
LDFLAGS += -Wl,--wrap=cbrt
|
||||||
|
LDFLAGS += -Wl,--wrap=fmod
|
||||||
|
LDFLAGS += -Wl,--wrap=drem
|
||||||
|
LDFLAGS += -Wl,--wrap=remainder
|
||||||
|
LDFLAGS += -Wl,--wrap=remquo
|
||||||
|
LDFLAGS += -Wl,--wrap=expm1
|
||||||
|
LDFLAGS += -Wl,--wrap=log1p
|
||||||
|
LDFLAGS += -Wl,--wrap=fma
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_lmul
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_fadd
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_fdiv
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_fmul
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_frsub
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_fsub
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_cfcmpeq
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_cfrcmple
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_cfcmple
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_fcmpeq
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_fcmplt
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_fcmple
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_fcmpge
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_fcmpgt
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_fcmpun
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_i2f
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_l2f
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_ui2f
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_ul2f
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_f2iz
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_f2lz
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_f2uiz
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_f2ulz
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_f2d
|
||||||
|
LDFLAGS += -Wl,--wrap=sqrtf
|
||||||
|
LDFLAGS += -Wl,--wrap=cosf
|
||||||
|
LDFLAGS += -Wl,--wrap=sinf
|
||||||
|
LDFLAGS += -Wl,--wrap=tanf
|
||||||
|
LDFLAGS += -Wl,--wrap=atan2f
|
||||||
|
LDFLAGS += -Wl,--wrap=expf
|
||||||
|
LDFLAGS += -Wl,--wrap=logf
|
||||||
|
LDFLAGS += -Wl,--wrap=ldexpf
|
||||||
|
LDFLAGS += -Wl,--wrap=copysignf
|
||||||
|
LDFLAGS += -Wl,--wrap=truncf
|
||||||
|
LDFLAGS += -Wl,--wrap=floorf
|
||||||
|
LDFLAGS += -Wl,--wrap=ceilf
|
||||||
|
LDFLAGS += -Wl,--wrap=roundf
|
||||||
|
LDFLAGS += -Wl,--wrap=sincosf
|
||||||
|
LDFLAGS += -Wl,--wrap=asinf
|
||||||
|
LDFLAGS += -Wl,--wrap=acosf
|
||||||
|
LDFLAGS += -Wl,--wrap=atanf
|
||||||
|
LDFLAGS += -Wl,--wrap=sinhf
|
||||||
|
LDFLAGS += -Wl,--wrap=coshf
|
||||||
|
LDFLAGS += -Wl,--wrap=tanhf
|
||||||
|
LDFLAGS += -Wl,--wrap=asinhf
|
||||||
|
LDFLAGS += -Wl,--wrap=acoshf
|
||||||
|
LDFLAGS += -Wl,--wrap=atanhf
|
||||||
|
LDFLAGS += -Wl,--wrap=exp2f
|
||||||
|
LDFLAGS += -Wl,--wrap=log2f
|
||||||
|
LDFLAGS += -Wl,--wrap=exp10f
|
||||||
|
LDFLAGS += -Wl,--wrap=log10f
|
||||||
|
LDFLAGS += -Wl,--wrap=powf
|
||||||
|
LDFLAGS += -Wl,--wrap=powintf
|
||||||
|
LDFLAGS += -Wl,--wrap=hypotf
|
||||||
|
LDFLAGS += -Wl,--wrap=cbrtf
|
||||||
|
LDFLAGS += -Wl,--wrap=fmodf
|
||||||
|
LDFLAGS += -Wl,--wrap=dremf
|
||||||
|
LDFLAGS += -Wl,--wrap=remainderf
|
||||||
|
LDFLAGS += -Wl,--wrap=remquof
|
||||||
|
LDFLAGS += -Wl,--wrap=expm1f
|
||||||
|
LDFLAGS += -Wl,--wrap=log1pf
|
||||||
|
LDFLAGS += -Wl,--wrap=fmaf
|
||||||
|
LDFLAGS += -Wl,--wrap=malloc
|
||||||
|
LDFLAGS += -Wl,--wrap=calloc
|
||||||
|
LDFLAGS += -Wl,--wrap=free
|
||||||
|
LDFLAGS += -Wl,--wrap=memcpy
|
||||||
|
LDFLAGS += -Wl,--wrap=memset
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_memcpy
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_memset
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_memcpy4
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_memset4
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_memcpy8
|
||||||
|
LDFLAGS += -Wl,--wrap=__aeabi_memset8
|
||||||
|
LDFLAGS += -Wl,-Map=$(TARGET).elf.map
|
||||||
|
LDFLAGS += -Wl,--script=$(LDSCRIPT)
|
||||||
|
LDFLAGS += -Wl,--gc-sections
|
||||||
|
LDFLAGS += -Wl,--wrap=printf
|
||||||
|
LDFLAGS += -Wl,--wrap=vprintf
|
||||||
|
LDFLAGS += -Wl,--wrap=puts
|
||||||
|
LDFLAGS += -Wl,--wrap=putchar
|
||||||
|
LDFLAGS += -Wl,--wrap=getchar
|
||||||
|
LDFLAGS += -Wl,--print-memory-usage
|
||||||
|
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_stdlib/stdlib.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_adc/adc.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_sync/sync.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_flash/flash.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_gpio/gpio.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_claim/claim.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_dma/dma.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_platform/platform.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_sync/sync.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_uart/uart.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_i2c/i2c.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_spi/spi.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_pio/pio.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_divider/divider.S
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/common/pico_time/time.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/common/pico_time/timeout_helper.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_timer/timer.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/common/pico_sync/sem.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/common/pico_sync/lock_core.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/common/pico_sync/mutex.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/common/pico_sync/critical_section.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/common/pico_util/datetime.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/common/pico_util/pheap.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/common/pico_util/queue.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_runtime/runtime.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_clocks/clocks.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_irq/irq.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_irq/irq_handler_chain.S
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_pll/pll.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_vreg/vreg.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_watchdog/watchdog.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/hardware_xosc/xosc.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_printf/printf.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_bit_ops/bit_ops_aeabi.S
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_bootrom/bootrom.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_divider/divider.S
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_double/double_aeabi.S
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_double/double_init_rom.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_double/double_math.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_double/double_v1_rom_shim.S
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_float/float_aeabi.S
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_float/float_init_rom.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_float/float_math.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_float/float_v1_rom_shim.S
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_malloc/pico_malloc.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_mem_ops/mem_ops_aeabi.S
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_standard_link/crt0.S
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_standard_link/new_delete.cpp
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_standard_link/binary_info.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_stdio/stdio.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_stdio_uart/stdio_uart.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_bootsel_via_double_reset/pico_bootsel_via_double_reset.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/hw/bsp/rp2040/family.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/src/portable/raspberrypi/rp2040/dcd_rp2040.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/src/portable/raspberrypi/rp2040/rp2040_usb.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/src/device/usbd.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/src/device/usbd_control.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/src/class/audio/audio_device.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/src/class/cdc/cdc_device.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/src/class/dfu/dfu_device.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/src/class/dfu/dfu_rt_device.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/src/class/hid/hid_device.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/src/class/midi/midi_device.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/src/class/msc/msc_device.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/src/class/usbtmc/usbtmc_device.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/src/class/vendor/vendor_device.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/src/tusb.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/lib/tinyusb/src/common/tusb_fifo.c
|
||||||
|
SRC += $(PICO_SDK_PATH)/src/rp2_common/pico_fix/rp2040_usb_device_enumeration/rp2040_usb_device_enumeration.c
|
||||||
|
|
||||||
|
BOOT2INC_DIR += -I$(TMK_PATH)/$(PICO_DIR)
|
||||||
|
BOOT2INC_DIR += -I$(PICO_SDK_PATH)/src/rp2_common/boot_stage2/include
|
||||||
|
BOOT2INC_DIR += -I$(PICO_SDK_PATH)/src/rp2_common/boot_stage2/asminclude
|
||||||
|
|
||||||
|
$(KEYBOARD_OUTPUT)/src/bs2_default.o: $(PICO_SDK_PATH)/src/rp2_common/boot_stage2/compile_time_choice.S $(KEYBOARD_OUTPUT)/cflags.txt
|
||||||
|
@mkdir -p $(KEYBOARD_OUTPUT)/src
|
||||||
|
$(CC) $(CFLAGS) $(BOOT2INC_DIR) -c -o $@ $^
|
||||||
|
|
||||||
|
$(KEYBOARD_OUTPUT)/src/bs2_default.elf: $(KEYBOARD_OUTPUT)/src/bs2_default.o
|
||||||
|
$(CC) $(CFLAGS) -Wl,--build-id=none -nostartfiles -Wl,--script=$(PICO_SDK_PATH)/src/rp2_common/boot_stage2/boot_stage2.ld $^ -o $@
|
||||||
|
|
||||||
|
|
||||||
|
$(KEYBOARD_OUTPUT)/src/bs2_default.bin: $(KEYBOARD_OUTPUT)/src/bs2_default.elf
|
||||||
|
$(OBJCOPY) -Obinary $^ $@
|
||||||
|
|
||||||
|
$(KEYBOARD_OUTPUT)/src/bs2_default_padded_checksummed.S: $(KEYBOARD_OUTPUT)/src/bs2_default.bin
|
||||||
|
$(PICO_SDK_PATH)/src/rp2_common/boot_stage2/pad_checksum -s 0xffffffff $^ $@
|
||||||
|
|
||||||
|
|
||||||
|
flash: $(BUILD_DIR)/$(TRAGET).elf cpfirmware sizeafter
|
||||||
|
until $(LSUSB) | grep -q $(RP2BOOT_ID); do\
|
||||||
|
printf "$(MSG_BOOTLOADER_NOT_FOUND)" ;\
|
||||||
|
sleep 5 ;\
|
||||||
|
done
|
||||||
|
$(PICOTOOL) load $(BUILD_DIR)/$(TARGET).elf && $(PICOTOOL) reboot
|
||||||
18
platforms/pico/platform_deps.h
Normal file
18
platforms/pico/platform_deps.h
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
/* Copyright 2021 QMK
|
||||||
|
*
|
||||||
|
* 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 "platforms/pico/boards/pico_boards.h"
|
||||||
6
platforms/pico/print.c
Normal file
6
platforms/pico/print.c
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
#include "sendchar.h"
|
||||||
|
|
||||||
|
void print_set_sendchar(sendchar_func_t func) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
136
platforms/pico/suspend.c
Normal file
136
platforms/pico/suspend.c
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "matrix.h"
|
||||||
|
#include "action.h"
|
||||||
|
#include "suspend.h"
|
||||||
|
#include "timer.h"
|
||||||
|
#include "led.h"
|
||||||
|
#include "host.h"
|
||||||
|
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
|
#ifdef BACKLIGHT_ENABLE
|
||||||
|
# include "backlight.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef AUDIO_ENABLE
|
||||||
|
# include "audio.h"
|
||||||
|
#endif /* AUDIO_ENABLE */
|
||||||
|
|
||||||
|
#if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE)
|
||||||
|
# include "rgblight.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** \brief Suspend idle
|
||||||
|
*
|
||||||
|
* FIXME: needs doc
|
||||||
|
*/
|
||||||
|
void suspend_idle(uint8_t time) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This needs some cleanup
|
||||||
|
|
||||||
|
/** \brief Run keyboard level Power down
|
||||||
|
*
|
||||||
|
* FIXME: needs doc
|
||||||
|
*/
|
||||||
|
__attribute__((weak)) void suspend_power_down_user(void) {}
|
||||||
|
/** \brief Run keyboard level Power down
|
||||||
|
*
|
||||||
|
* FIXME: needs doc
|
||||||
|
*/
|
||||||
|
__attribute__((weak)) void suspend_power_down_kb(void) { suspend_power_down_user(); }
|
||||||
|
|
||||||
|
|
||||||
|
/** \brief Suspend power down
|
||||||
|
*
|
||||||
|
* FIXME: needs doc
|
||||||
|
*/
|
||||||
|
void suspend_power_down(void) {
|
||||||
|
if (!tud_suspended()) return;
|
||||||
|
|
||||||
|
suspend_power_down_kb();
|
||||||
|
|
||||||
|
#ifndef NO_SUSPEND_POWER_DOWN
|
||||||
|
// Turn off backlight
|
||||||
|
# ifdef BACKLIGHT_ENABLE
|
||||||
|
backlight_set(0);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Turn off LED indicators
|
||||||
|
uint8_t leds_off = 0;
|
||||||
|
# if defined(BACKLIGHT_CAPS_LOCK) && defined(BACKLIGHT_ENABLE)
|
||||||
|
if (is_backlight_enabled()) {
|
||||||
|
// Don't try to turn off Caps Lock indicator as it is backlight and backlight is already off
|
||||||
|
leds_off |= (1 << USB_LED_CAPS_LOCK);
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
led_set(leds_off);
|
||||||
|
|
||||||
|
// Turn off audio
|
||||||
|
# ifdef AUDIO_ENABLE
|
||||||
|
stop_all_notes();
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Turn off underglow
|
||||||
|
# if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE)
|
||||||
|
rgblight_suspend();
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// Enter sleep state if possible (ie, the MCU has a watchdog timeout interrupt)
|
||||||
|
# if defined(WDT_vect)
|
||||||
|
power_down(WDTO_15MS);
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((weak)) void matrix_power_up(void) {}
|
||||||
|
__attribute__((weak)) void matrix_power_down(void) {}
|
||||||
|
|
||||||
|
/** \brief run user level code immediately after wakeup
|
||||||
|
*
|
||||||
|
* FIXME: needs doc
|
||||||
|
*/
|
||||||
|
__attribute__((weak)) void suspend_wakeup_init_user(void) {}
|
||||||
|
|
||||||
|
/** \brief run keyboard level code immediately after wakeup
|
||||||
|
*
|
||||||
|
* FIXME: needs doc
|
||||||
|
*/
|
||||||
|
__attribute__((weak)) void suspend_wakeup_init_kb(void) { suspend_wakeup_init_user(); }
|
||||||
|
|
||||||
|
/** \brief run immediately after wakeup
|
||||||
|
*
|
||||||
|
* FIXME: needs doc
|
||||||
|
*/
|
||||||
|
void suspend_wakeup_init(void) {
|
||||||
|
// clear keyboard state
|
||||||
|
clear_keyboard();
|
||||||
|
|
||||||
|
// Turn on backlight
|
||||||
|
#ifdef BACKLIGHT_ENABLE
|
||||||
|
backlight_init();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Restore LED indicators
|
||||||
|
led_set(host_keyboard_leds());
|
||||||
|
|
||||||
|
// Wake up underglow
|
||||||
|
#if defined(RGBLIGHT_SLEEP) && defined(RGBLIGHT_ENABLE)
|
||||||
|
rgblight_wakeup();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
suspend_wakeup_init_kb();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect)
|
||||||
|
/* watchdog timeout */
|
||||||
|
ISR(WDT_vect) {
|
||||||
|
// compensate timer for sleep
|
||||||
|
switch (wdt_timeout) {
|
||||||
|
case WDTO_15MS:
|
||||||
|
timer_count += 15 + 2; // WDTO_15MS + 2(from observation)
|
||||||
|
break;
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
67
platforms/pico/timer.c
Normal file
67
platforms/pico/timer.c
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
Copyright 2011 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "timer.h"
|
||||||
|
#include "pico/stdlib.h"
|
||||||
|
|
||||||
|
/** \brief timer initialization
|
||||||
|
*
|
||||||
|
* FIXME: needs doc
|
||||||
|
*/
|
||||||
|
void timer_init(void) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief timer read
|
||||||
|
*
|
||||||
|
* FIXME: needs doc
|
||||||
|
*/
|
||||||
|
inline uint16_t timer_read(void) {
|
||||||
|
|
||||||
|
return (to_ms_since_boot(get_absolute_time()) & 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief timer read32
|
||||||
|
*
|
||||||
|
* FIXME: needs doc
|
||||||
|
*/
|
||||||
|
inline uint32_t timer_read32(void) {
|
||||||
|
return (to_ms_since_boot(get_absolute_time()) & 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief timer elapsed
|
||||||
|
*
|
||||||
|
* FIXME: needs doc
|
||||||
|
*/
|
||||||
|
inline uint16_t timer_elapsed(uint16_t last) {
|
||||||
|
uint32_t t;
|
||||||
|
|
||||||
|
t = timer_read32();
|
||||||
|
|
||||||
|
return TIMER_DIFF_16((t & 0xFFFF), last);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief timer elapsed32
|
||||||
|
*
|
||||||
|
* FIXME: needs doc
|
||||||
|
*/
|
||||||
|
inline uint32_t timer_elapsed32(uint32_t last) {
|
||||||
|
uint32_t t;
|
||||||
|
|
||||||
|
t = timer_read32();
|
||||||
|
|
||||||
|
return TIMER_DIFF_32(t, last);
|
||||||
|
}
|
||||||
2
quantum/audio/driver_pico_pwm.h
Normal file
2
quantum/audio/driver_pico_pwm.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
108
quantum/audio/driver_pico_pwm_hardware.c
Normal file
108
quantum/audio/driver_pico_pwm_hardware.c
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
Audio Driver: PWM
|
||||||
|
|
||||||
|
the duty-cycle is always kept at 50%, and the pwm-period is adjusted to match
|
||||||
|
the frequency of a note to be played back.
|
||||||
|
|
||||||
|
this driver uses the chibios-PWM system to produce a square-wave on specific
|
||||||
|
output pins that are connected to the PWM hardware. The hardware directly
|
||||||
|
toggles the pin via its alternate function. see your MCUs data-sheet for which
|
||||||
|
pin can be driven by what timer - looking for TIMx_CHy and the corresponding
|
||||||
|
alternate function.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "audio.h"
|
||||||
|
|
||||||
|
#include "hardware/pwm.h"
|
||||||
|
#include "hardware/irq.h"
|
||||||
|
#include "hardware/clocks.h"
|
||||||
|
|
||||||
|
#if !defined(AUDIO_PIN)
|
||||||
|
# error \
|
||||||
|
"Audio feature enabled, but no pin selected - see docs/feature_audio under the ARM PWM settings"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern bool playing_note;
|
||||||
|
extern bool playing_melody;
|
||||||
|
extern uint8_t note_timbre;
|
||||||
|
|
||||||
|
#define WRAP_MAX 65534
|
||||||
|
#define CLOCK_DIV 100
|
||||||
|
|
||||||
|
static void pwm_callback(void);
|
||||||
|
|
||||||
|
static uint pwm_clock = 12000000 / CLOCK_DIV;
|
||||||
|
static volatile uint32_t isr_counter = 0;
|
||||||
|
|
||||||
|
static float channel_1_frequency = 0.0f;
|
||||||
|
void channel_1_set_frequency(float freq) {
|
||||||
|
channel_1_frequency = freq;
|
||||||
|
|
||||||
|
if (freq <= 0.0) // a pause/rest has freq=0
|
||||||
|
return;
|
||||||
|
|
||||||
|
// enable channel
|
||||||
|
|
||||||
|
uint slice = pwm_gpio_to_slice_num(AUDIO_PIN);
|
||||||
|
uint16_t wrap = pwm_clock / freq;
|
||||||
|
pwm_set_wrap(slice, wrap);
|
||||||
|
pwm_set_gpio_level(AUDIO_PIN, wrap * note_timbre / 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
float channel_1_get_frequency(void) { return channel_1_frequency; }
|
||||||
|
|
||||||
|
void channel_1_start(void) {
|
||||||
|
uint slice = pwm_gpio_to_slice_num(AUDIO_PIN);
|
||||||
|
pwm_set_enabled(slice, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void channel_1_stop(void) {
|
||||||
|
uint slice = pwm_gpio_to_slice_num(AUDIO_PIN);
|
||||||
|
pwm_set_enabled(slice, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void audio_driver_initialize(void) {
|
||||||
|
channel_1_stop();
|
||||||
|
gpio_set_function(AUDIO_PIN, GPIO_FUNC_PWM);
|
||||||
|
uint slice = pwm_gpio_to_slice_num(AUDIO_PIN);
|
||||||
|
|
||||||
|
pwm_clear_irq(slice);
|
||||||
|
pwm_set_irq_enabled(slice, true);
|
||||||
|
irq_set_exclusive_handler(PWM_IRQ_WRAP, pwm_callback);
|
||||||
|
irq_set_enabled(PWM_IRQ_WRAP, true);
|
||||||
|
|
||||||
|
pwm_set_clkdiv(slice, CLOCK_DIV);
|
||||||
|
pwm_clock = clock_get_hz(clk_sys) / CLOCK_DIV;
|
||||||
|
pwm_set_wrap(slice, WRAP_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void audio_driver_start(void) {
|
||||||
|
channel_1_stop();
|
||||||
|
channel_1_start();
|
||||||
|
|
||||||
|
if (playing_note || playing_melody) {
|
||||||
|
channel_1_set_frequency(audio_get_processed_frequency(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void audio_driver_stop(void) { channel_1_stop(); }
|
||||||
|
|
||||||
|
static void pwm_callback(void) {
|
||||||
|
pwm_clear_irq(pwm_gpio_to_slice_num(AUDIO_PIN));
|
||||||
|
|
||||||
|
isr_counter++;
|
||||||
|
if (isr_counter < channel_1_frequency / (64)) return;
|
||||||
|
|
||||||
|
isr_counter = 0;
|
||||||
|
bool state_changed = audio_update_state();
|
||||||
|
|
||||||
|
if (!playing_note && !playing_melody) {
|
||||||
|
channel_1_stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state_changed) {
|
||||||
|
channel_1_set_frequency(audio_get_processed_frequency(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -421,6 +421,7 @@ void dynamic_keymap_set_buffer(uint16_t offset, uint16_t size, uint8_t *data) {
|
||||||
extern uint16_t g_vial_magic_keycode_override;
|
extern uint16_t g_vial_magic_keycode_override;
|
||||||
|
|
||||||
// This overrides the one in quantum/keymap_common.c
|
// This overrides the one in quantum/keymap_common.c
|
||||||
|
#ifndef OVERRIDE_KEYMAP_KEY_TO_KEYCODE
|
||||||
uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) {
|
uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) {
|
||||||
#ifdef VIAL_ENABLE
|
#ifdef VIAL_ENABLE
|
||||||
/* Disable any keycode processing while unlocking */
|
/* Disable any keycode processing while unlocking */
|
||||||
|
|
@ -437,6 +438,7 @@ uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key) {
|
||||||
return KC_NO;
|
return KC_NO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
uint8_t dynamic_keymap_macro_get_count(void) {
|
uint8_t dynamic_keymap_macro_get_count(void) {
|
||||||
return DYNAMIC_KEYMAP_MACRO_COUNT;
|
return DYNAMIC_KEYMAP_MACRO_COUNT;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,10 @@
|
||||||
#include "wait.h"
|
#include "wait.h"
|
||||||
#include "usb_util.h"
|
#include "usb_util.h"
|
||||||
|
|
||||||
|
#ifdef PROTOCOL_PICO
|
||||||
|
# include "tusb.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef EE_HANDS
|
#ifdef EE_HANDS
|
||||||
# include "eeconfig.h"
|
# include "eeconfig.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -57,7 +61,39 @@ static uint8_t connection_errors = 0;
|
||||||
volatile bool isLeftHand = true;
|
volatile bool isLeftHand = true;
|
||||||
|
|
||||||
#if defined(SPLIT_USB_DETECT)
|
#if defined(SPLIT_USB_DETECT)
|
||||||
static bool usbIsActive(void) {
|
# if defined(PROTOCOL_LUFA)
|
||||||
|
static inline bool usbHasActiveConnection(void) {
|
||||||
|
return USB_Device_IsAddressSet();
|
||||||
|
}
|
||||||
|
static inline void usbDisable(void) {
|
||||||
|
USB_Disable();
|
||||||
|
USB_DeviceState = DEVICE_STATE_Unattached;
|
||||||
|
}
|
||||||
|
# elif defined(PROTOCOL_CHIBIOS)
|
||||||
|
static inline bool usbHasActiveConnection(void) {
|
||||||
|
return usbGetDriverStateI(&USBD1) == USB_ACTIVE;
|
||||||
|
}
|
||||||
|
static inline void usbDisable(void) { usbStop(&USBD1); }
|
||||||
|
# elif defined(PROTOCOL_VUSB)
|
||||||
|
static inline bool usbHasActiveConnection(void) {
|
||||||
|
usbPoll();
|
||||||
|
return usbConfiguration;
|
||||||
|
}
|
||||||
|
static inline void usbDisable(void) { usbDeviceDisconnect(); }
|
||||||
|
# elif defined(PROTOCOL_PICO)
|
||||||
|
static inline bool usbHasActiveConnection(void) {
|
||||||
|
tud_task();
|
||||||
|
return tud_connected();
|
||||||
|
}
|
||||||
|
static inline void usbDisable(void) {
|
||||||
|
# warning "No implementation" //TODO implement
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
static inline bool usbHasActiveConnection(void) { return true; }
|
||||||
|
static inline void usbDisable(void) {}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
bool usbIsActive(void) {
|
||||||
for (uint8_t i = 0; i < (SPLIT_USB_TIMEOUT / SPLIT_USB_TIMEOUT_POLL); i++) {
|
for (uint8_t i = 0; i < (SPLIT_USB_TIMEOUT / SPLIT_USB_TIMEOUT_POLL); i++) {
|
||||||
// This will return true if a USB connection has been established
|
// This will return true if a USB connection has been established
|
||||||
if (usb_connected_state()) {
|
if (usb_connected_state()) {
|
||||||
|
|
@ -139,7 +175,8 @@ void split_pre_init(void) {
|
||||||
if (isLeftHand) {
|
if (isLeftHand) {
|
||||||
rgblight_set_clipping_range(0, num_rgb_leds_split[0]);
|
rgblight_set_clipping_range(0, num_rgb_leds_split[0]);
|
||||||
} else {
|
} else {
|
||||||
rgblight_set_clipping_range(num_rgb_leds_split[0], num_rgb_leds_split[1]);
|
rgblight_set_clipping_range(num_rgb_leds_split[0],
|
||||||
|
num_rgb_leds_split[1]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
|
PROTOCOL_COMMON_DIR = protocol
|
||||||
|
|
||||||
TMK_COMMON_SRC += \
|
TMK_COMMON_SRC += \
|
||||||
$(PROTOCOL_DIR)/host.c \
|
$(PROTOCOL_COMMON_DIR)/host.c \
|
||||||
$(PROTOCOL_DIR)/report.c \
|
$(PROTOCOL_COMMON_DIR)/report.c \
|
||||||
$(PROTOCOL_DIR)/usb_device_state.c \
|
$(PROTOCOL_COMMON_DIR)/usb_device_state.c \
|
||||||
$(PROTOCOL_DIR)/usb_util.c \
|
$(PROTOCOL_COMMON_DIR)/usb_util.c \
|
||||||
|
|
||||||
SHARED_EP_ENABLE = no
|
SHARED_EP_ENABLE = no
|
||||||
MOUSE_SHARED_EP ?= yes
|
MOUSE_SHARED_EP ?= yes
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,18 @@ interrupt_setting_t store_and_clear_interrupt(void) {
|
||||||
void restore_interrupt_setting(interrupt_setting_t setting) {
|
void restore_interrupt_setting(interrupt_setting_t setting) {
|
||||||
SREG = setting;
|
SREG = setting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined(PROTOCOL_PICO)
|
||||||
|
# include "atomic_util.h"
|
||||||
|
|
||||||
|
interrupt_setting_t store_and_clear_interrupt(void) {
|
||||||
|
return __interrupt_disable__();
|
||||||
|
}
|
||||||
|
|
||||||
|
void restore_interrupt_setting(interrupt_setting_t setting) {
|
||||||
|
__interrupt_enable__(setting);
|
||||||
|
}
|
||||||
|
|
||||||
#elif defined(__arm__)
|
#elif defined(__arm__)
|
||||||
# include <ch.h>
|
# include <ch.h>
|
||||||
|
|
||||||
|
|
|
||||||
19
tmk_core/protocol/pico.mk
Normal file
19
tmk_core/protocol/pico.mk
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
PROTOCOL_DIR = protocol
|
||||||
|
PICO_DIR = $(PROTOCOL_DIR)/pico
|
||||||
|
|
||||||
|
SRC += $(KEYBOARD_OUTPUT)/src/bs2_default_padded_checksummed.S
|
||||||
|
LDSCRIPT := $(PICO_SDK_PATH)/src/rp2_common/pico_standard_link/memmap_default.ld
|
||||||
|
|
||||||
|
SRC += $(PICO_DIR)/pico.c
|
||||||
|
SRC += $(PICO_DIR)/usb_descriptors.c
|
||||||
|
SRC += $(PICO_DIR)/iusb.c
|
||||||
|
SRC += $(PICO_DIR)/pio_manager.c
|
||||||
|
SRC += $(PICO_DIR)/usb_util.c
|
||||||
|
|
||||||
|
VPATH += $(TMK_PATH)/$(PROTOCOL_DIR)
|
||||||
|
VPATH += $(TMK_PATH)/$(PICO_DIR)
|
||||||
|
VPATH += $(TMK_PATH)/$(PICO_DIR)/lufa_utils
|
||||||
|
|
||||||
|
CFLAGS += -DPROTOCOL_PICO
|
||||||
|
CFLAGS += -DGPIO_INPUT_PIN_DELAY=100
|
||||||
|
CFLAGS += -DDYNAMIC_KEYMAP_EEPROM_MAX_ADDR=4095
|
||||||
23
tmk_core/protocol/pico/bs2_default_padded_checksummed.S
Normal file
23
tmk_core/protocol/pico/bs2_default_padded_checksummed.S
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Padded and checksummed version of: /home/sekigon/pico/pico-examples/build/pico-sdk/src/rp2_common/boot_stage2/bs2_default.bin
|
||||||
|
|
||||||
|
.cpu cortex-m0plus
|
||||||
|
.thumb
|
||||||
|
|
||||||
|
.section .boot2, "ax"
|
||||||
|
|
||||||
|
.byte 0x00, 0xb5, 0x32, 0x4b, 0x21, 0x20, 0x58, 0x60, 0x98, 0x68, 0x02, 0x21, 0x88, 0x43, 0x98, 0x60
|
||||||
|
.byte 0xd8, 0x60, 0x18, 0x61, 0x58, 0x61, 0x2e, 0x4b, 0x00, 0x21, 0x99, 0x60, 0x02, 0x21, 0x59, 0x61
|
||||||
|
.byte 0x01, 0x21, 0xf0, 0x22, 0x99, 0x50, 0x2b, 0x49, 0x19, 0x60, 0x01, 0x21, 0x99, 0x60, 0x35, 0x20
|
||||||
|
.byte 0x00, 0xf0, 0x44, 0xf8, 0x02, 0x22, 0x90, 0x42, 0x14, 0xd0, 0x06, 0x21, 0x19, 0x66, 0x00, 0xf0
|
||||||
|
.byte 0x34, 0xf8, 0x19, 0x6e, 0x01, 0x21, 0x19, 0x66, 0x00, 0x20, 0x18, 0x66, 0x1a, 0x66, 0x00, 0xf0
|
||||||
|
.byte 0x2c, 0xf8, 0x19, 0x6e, 0x19, 0x6e, 0x19, 0x6e, 0x05, 0x20, 0x00, 0xf0, 0x2f, 0xf8, 0x01, 0x21
|
||||||
|
.byte 0x08, 0x42, 0xf9, 0xd1, 0x00, 0x21, 0x99, 0x60, 0x1b, 0x49, 0x19, 0x60, 0x00, 0x21, 0x59, 0x60
|
||||||
|
.byte 0x1a, 0x49, 0x1b, 0x48, 0x01, 0x60, 0x01, 0x21, 0x99, 0x60, 0xeb, 0x21, 0x19, 0x66, 0xa0, 0x21
|
||||||
|
.byte 0x19, 0x66, 0x00, 0xf0, 0x12, 0xf8, 0x00, 0x21, 0x99, 0x60, 0x16, 0x49, 0x14, 0x48, 0x01, 0x60
|
||||||
|
.byte 0x01, 0x21, 0x99, 0x60, 0x01, 0xbc, 0x00, 0x28, 0x00, 0xd0, 0x00, 0x47, 0x12, 0x48, 0x13, 0x49
|
||||||
|
.byte 0x08, 0x60, 0x03, 0xc8, 0x80, 0xf3, 0x08, 0x88, 0x08, 0x47, 0x03, 0xb5, 0x99, 0x6a, 0x04, 0x20
|
||||||
|
.byte 0x01, 0x42, 0xfb, 0xd0, 0x01, 0x20, 0x01, 0x42, 0xf8, 0xd1, 0x03, 0xbd, 0x02, 0xb5, 0x18, 0x66
|
||||||
|
.byte 0x18, 0x66, 0xff, 0xf7, 0xf2, 0xff, 0x18, 0x6e, 0x18, 0x6e, 0x02, 0xbd, 0x00, 0x00, 0x02, 0x40
|
||||||
|
.byte 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x07, 0x00, 0x00, 0x03, 0x5f, 0x00, 0x21, 0x22, 0x00, 0x00
|
||||||
|
.byte 0xf4, 0x00, 0x00, 0x18, 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0
|
||||||
|
.byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0xb2, 0x4e, 0x7a
|
||||||
120
tmk_core/protocol/pico/iusb.c
Normal file
120
tmk_core/protocol/pico/iusb.c
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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 "iusb.h"
|
||||||
|
#include "raw_hid.h"
|
||||||
|
|
||||||
|
#ifdef MIDI_ENABLE
|
||||||
|
# include "qmk_midi.h"
|
||||||
|
#endif
|
||||||
|
#include "usb_descriptors.h"
|
||||||
|
|
||||||
|
#include "device/usbd.h"
|
||||||
|
#include "hid_device.h"
|
||||||
|
#include "class/midi/midi_device.h"
|
||||||
|
#include "device/dcd.h"
|
||||||
|
|
||||||
|
uint8_t keyboard_leds(void) {
|
||||||
|
return get_keyboard_led_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_keyboard(report_keyboard_t *report) {
|
||||||
|
if (tud_suspended()) {
|
||||||
|
tud_remote_wakeup();
|
||||||
|
busy_wait_ms(15);
|
||||||
|
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!tud_hid_n_ready(ITF_NUM_HID_KEYBOARD)) {
|
||||||
|
tud_task();
|
||||||
|
if (!tud_ready()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tud_hid_n_report(ITF_NUM_HID_KEYBOARD, 0, report, sizeof(*report));
|
||||||
|
tud_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_mouse(report_mouse_t *report) {
|
||||||
|
if (tud_suspended()) {
|
||||||
|
tud_remote_wakeup();
|
||||||
|
busy_wait_ms(15);
|
||||||
|
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!tud_hid_n_ready(ITF_NUM_HID_MOUSE)) {
|
||||||
|
tud_task();
|
||||||
|
if (!tud_ready()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Require only 5 bytes. Do not usb report->id
|
||||||
|
tud_hid_n_report(ITF_NUM_HID_MOUSE, 0, &report->buttons, 5);
|
||||||
|
tud_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_system(uint16_t data) {
|
||||||
|
while (!tud_hid_n_ready(ITF_NUM_HID_EXTRA)) {
|
||||||
|
tud_task();
|
||||||
|
if (!tud_ready()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tud_hid_n_report(ITF_NUM_HID_EXTRA, REPORT_ID_SYSTEM, &data, 2);
|
||||||
|
tud_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_consumer(uint16_t data) {
|
||||||
|
while (!tud_hid_n_ready(ITF_NUM_HID_EXTRA)) {
|
||||||
|
tud_task();
|
||||||
|
if (!tud_ready()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tud_hid_n_report(ITF_NUM_HID_EXTRA, REPORT_ID_CONSUMER, &data, 2);
|
||||||
|
tud_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
void raw_hid_send(uint8_t *data, uint8_t length) {
|
||||||
|
while (!tud_hid_n_ready(ITF_NUM_HID_RAW)) {
|
||||||
|
tud_task();
|
||||||
|
if (!tud_ready()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tud_hid_n_report(ITF_NUM_HID_RAW, 0, data, length);
|
||||||
|
tud_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MIDI_ENABLE
|
||||||
|
void send_midi_packet(MIDI_EventPacket_t *event) {
|
||||||
|
tud_midi_packet_write((uint8_t *)event);
|
||||||
|
tud_task();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool recv_midi_packet(MIDI_EventPacket_t *const event) {
|
||||||
|
if (tud_midi_available()) {
|
||||||
|
tud_midi_packet_read((uint8_t *)event);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // MIDI_ENABLE
|
||||||
27
tmk_core/protocol/pico/iusb.h
Normal file
27
tmk_core/protocol/pico/iusb.h
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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 <stdint.h>
|
||||||
|
#include "report.h"
|
||||||
|
|
||||||
|
/* declarations */
|
||||||
|
uint8_t keyboard_leds(void);
|
||||||
|
void send_keyboard(report_keyboard_t *report);
|
||||||
|
void send_mouse(report_mouse_t *report);
|
||||||
|
void send_system(uint16_t data);
|
||||||
|
void send_consumer(uint16_t data);
|
||||||
42
tmk_core/protocol/pico/lufa_utils/LUFA/Drivers/USB/USB.h
Normal file
42
tmk_core/protocol/pico/lufa_utils/LUFA/Drivers/USB/USB.h
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
#include "progmem.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define ATTR_PACKED __attribute__((packed))
|
||||||
|
/** Concatenates the given input into a single token, via the C Preprocessor.
|
||||||
|
*
|
||||||
|
* \param[in] x First item to concatenate.
|
||||||
|
* \param[in] y Second item to concatenate.
|
||||||
|
*
|
||||||
|
* \return Concatenated version of the input.
|
||||||
|
*/
|
||||||
|
#define CONCAT(x, y) x##y
|
||||||
|
|
||||||
|
/** CConcatenates the given input into a single token after macro expansion, via the C Preprocessor.
|
||||||
|
*
|
||||||
|
* \param[in] x First item to concatenate.
|
||||||
|
* \param[in] y Second item to concatenate.
|
||||||
|
*
|
||||||
|
* \return Concatenated version of the expanded input.
|
||||||
|
*/
|
||||||
|
#define CONCAT_EXPANDED(x, y) CONCAT(x, y)
|
||||||
|
#define CPU_TO_LE16(x) (x)
|
||||||
|
|
||||||
|
// We don't need anything from the following files, or we have defined it already
|
||||||
|
#define __LUFA_COMMON_H__
|
||||||
|
#define __USBMODE_H__
|
||||||
|
#define __USBEVENTS_H__
|
||||||
|
#define __HIDPARSER_H__
|
||||||
|
#define __USBCONTROLLER_AVR8_H__
|
||||||
|
|
||||||
|
#define __INCLUDE_FROM_USB_DRIVER
|
||||||
|
#define __INCLUDE_FROM_HID_DRIVER
|
||||||
|
#define __INCLUDE_FROM_CDC_DRIVER
|
||||||
|
#define __INCLUDE_FROM_AUDIO_DRIVER
|
||||||
|
#define __INCLUDE_FROM_MIDI_DRIVER
|
||||||
|
#include "lib/lufa/LUFA/Drivers/USB/Class/Common/HIDClassCommon.h"
|
||||||
|
#include "lib/lufa/LUFA/Drivers/USB/Class/Common/HIDReportData.h"
|
||||||
|
#include "lib/lufa/LUFA/Drivers/USB/Class/Common/CDCClassCommon.h"
|
||||||
|
#include "lib/lufa/LUFA/Drivers/USB/Class/Common/AudioClassCommon.h"
|
||||||
|
#include "lib/lufa/LUFA/Drivers/USB/Class/Common/MIDIClassCommon.h"
|
||||||
|
#include "lib/lufa/LUFA/Drivers/USB/Core/USBController.h"
|
||||||
259
tmk_core/protocol/pico/msc_disk.c
Normal file
259
tmk_core/protocol/pico/msc_disk.c
Normal file
|
|
@ -0,0 +1,259 @@
|
||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bsp/board.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
|
#if CFG_TUD_MSC
|
||||||
|
|
||||||
|
// whether host does safe-eject
|
||||||
|
static bool ejected = false;
|
||||||
|
|
||||||
|
// Some MCU doesn't have enough 8KB SRAM to store the whole disk
|
||||||
|
// We will use Flash as read-only disk with board that has
|
||||||
|
// CFG_EXAMPLE_MSC_READONLY defined
|
||||||
|
|
||||||
|
#define README_CONTENTS \
|
||||||
|
"This is tinyusb's MassStorage Class demo.\r\n\r\n\
|
||||||
|
If you find any bugs or get any questions, feel free to file an\r\n\
|
||||||
|
issue at github.com/hathach/tinyusb"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
DISK_BLOCK_NUM = 16, // 8KB is the smallest size that windows allow to mount
|
||||||
|
DISK_BLOCK_SIZE = 512
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef CFG_EXAMPLE_MSC_READONLY
|
||||||
|
const
|
||||||
|
#endif
|
||||||
|
uint8_t msc_disk[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
|
||||||
|
{
|
||||||
|
//------------- Block0: Boot Sector -------------//
|
||||||
|
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
|
||||||
|
// sector_per_cluster = 1; reserved_sectors = 1;
|
||||||
|
// fat_num = 1; fat12_root_entry_num = 16;
|
||||||
|
// sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0;
|
||||||
|
// drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
|
||||||
|
// filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB MSC";
|
||||||
|
// FAT magic code at offset 510-511
|
||||||
|
{
|
||||||
|
0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
|
||||||
|
0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T' , 'i' , 'n' , 'y' , 'U' ,
|
||||||
|
'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
|
||||||
|
|
||||||
|
// Zero up to 2 last bytes of FAT magic code
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
|
||||||
|
},
|
||||||
|
|
||||||
|
//------------- Block1: FAT12 Table -------------//
|
||||||
|
{
|
||||||
|
0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file
|
||||||
|
},
|
||||||
|
|
||||||
|
//------------- Block2: Root Directory -------------//
|
||||||
|
{
|
||||||
|
// first entry is volume label
|
||||||
|
'T' , 'i' , 'n' , 'y' , 'U' , 'S' , 'B' , ' ' , 'M' , 'S' , 'C' , 0x08, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
// second entry is readme file
|
||||||
|
'R' , 'E' , 'A' , 'D' , 'M' , 'E' , ' ' , ' ' , 'T' , 'X' , 'T' , 0x20, 0x00, 0xC6, 0x52, 0x6D,
|
||||||
|
0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
|
||||||
|
sizeof(README_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes)
|
||||||
|
},
|
||||||
|
|
||||||
|
//------------- Block3: Readme Content -------------//
|
||||||
|
README_CONTENTS
|
||||||
|
};
|
||||||
|
|
||||||
|
// Invoked when received SCSI_CMD_INQUIRY
|
||||||
|
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||||
|
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
|
||||||
|
{
|
||||||
|
(void) lun;
|
||||||
|
|
||||||
|
const char vid[] = "TinyUSB";
|
||||||
|
const char pid[] = "Mass Storage";
|
||||||
|
const char rev[] = "1.0";
|
||||||
|
|
||||||
|
memcpy(vendor_id , vid, strlen(vid));
|
||||||
|
memcpy(product_id , pid, strlen(pid));
|
||||||
|
memcpy(product_rev, rev, strlen(rev));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when received Test Unit Ready command.
|
||||||
|
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||||
|
bool tud_msc_test_unit_ready_cb(uint8_t lun)
|
||||||
|
{
|
||||||
|
(void) lun;
|
||||||
|
|
||||||
|
// RAM disk is ready until ejected
|
||||||
|
if (ejected) {
|
||||||
|
tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3a, 0x00);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
|
||||||
|
// Application update block count and block size
|
||||||
|
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
|
||||||
|
{
|
||||||
|
(void) lun;
|
||||||
|
|
||||||
|
*block_count = DISK_BLOCK_NUM;
|
||||||
|
*block_size = DISK_BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when received Start Stop Unit command
|
||||||
|
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
|
||||||
|
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
|
||||||
|
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
|
||||||
|
{
|
||||||
|
(void) lun;
|
||||||
|
(void) power_condition;
|
||||||
|
|
||||||
|
if ( load_eject )
|
||||||
|
{
|
||||||
|
if (start)
|
||||||
|
{
|
||||||
|
// load disk storage
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
// unload disk storage
|
||||||
|
ejected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback invoked when received READ10 command.
|
||||||
|
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
|
||||||
|
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
|
||||||
|
{
|
||||||
|
(void) lun;
|
||||||
|
|
||||||
|
uint8_t const* addr = msc_disk[lba] + offset;
|
||||||
|
memcpy(buffer, addr, bufsize);
|
||||||
|
|
||||||
|
return bufsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback invoked when received WRITE10 command.
|
||||||
|
// Process data in buffer to disk's storage and return number of written bytes
|
||||||
|
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
|
||||||
|
{
|
||||||
|
(void) lun;
|
||||||
|
|
||||||
|
#ifndef CFG_EXAMPLE_MSC_READONLY
|
||||||
|
uint8_t* addr = msc_disk[lba] + offset;
|
||||||
|
memcpy(addr, buffer, bufsize);
|
||||||
|
#else
|
||||||
|
(void) lba; (void) offset; (void) buffer;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return bufsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback invoked when received an SCSI command not in built-in list below
|
||||||
|
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
|
||||||
|
// - READ10 and WRITE10 has their own callbacks
|
||||||
|
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
|
||||||
|
{
|
||||||
|
// read10 & write10 has their own callback and MUST not be handled here
|
||||||
|
|
||||||
|
void const* response = NULL;
|
||||||
|
uint16_t resplen = 0;
|
||||||
|
|
||||||
|
// most scsi handled is input
|
||||||
|
bool in_xfer = true;
|
||||||
|
|
||||||
|
switch (scsi_cmd[0])
|
||||||
|
{
|
||||||
|
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
|
||||||
|
// Host is about to read/write etc ... better not to disconnect disk
|
||||||
|
resplen = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Set Sense = Invalid Command Operation
|
||||||
|
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
|
||||||
|
|
||||||
|
// negative means error -> tinyusb could stall and/or response with failed status
|
||||||
|
resplen = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return resplen must not larger than bufsize
|
||||||
|
if ( resplen > bufsize ) resplen = bufsize;
|
||||||
|
|
||||||
|
if ( response && (resplen > 0) )
|
||||||
|
{
|
||||||
|
if(in_xfer)
|
||||||
|
{
|
||||||
|
memcpy(buffer, response, resplen);
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
// SCSI output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resplen;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
283
tmk_core/protocol/pico/pico.c
Normal file
283
tmk_core/protocol/pico/pico.c
Normal file
|
|
@ -0,0 +1,283 @@
|
||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "raw_hid.h"
|
||||||
|
#include "bootloader.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#include "eeprom_pico.h"
|
||||||
|
#include "usb_descriptors.h"
|
||||||
|
|
||||||
|
#include "pico/stdio/driver.h"
|
||||||
|
#include "hardware/watchdog.h"
|
||||||
|
#include "hardware/structs/watchdog.h"
|
||||||
|
#include "bsp/board.h"
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
|
/* TMK includes */
|
||||||
|
#include "report.h"
|
||||||
|
#include "host.h"
|
||||||
|
#include "host_driver.h"
|
||||||
|
#include "keyboard.h"
|
||||||
|
#include "action.h"
|
||||||
|
#include "action_util.h"
|
||||||
|
#include "mousekey.h"
|
||||||
|
#include "led.h"
|
||||||
|
#include "sendchar.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "print.h"
|
||||||
|
|
||||||
|
#ifdef SLEEP_LED_ENABLE
|
||||||
|
# include "sleep_led.h"
|
||||||
|
#endif
|
||||||
|
#ifdef SERIAL_LINK_ENABLE
|
||||||
|
# include "serial_link/system/serial_link.h"
|
||||||
|
#endif
|
||||||
|
#ifdef VISUALIZER_ENABLE
|
||||||
|
# include "visualizer/visualizer.h"
|
||||||
|
#endif
|
||||||
|
#ifdef MIDI_ENABLE
|
||||||
|
# include "qmk_midi.h"
|
||||||
|
#endif
|
||||||
|
#ifdef STM32_EEPROM_ENABLE
|
||||||
|
# include "eeprom_stm32.h"
|
||||||
|
#endif
|
||||||
|
#ifdef EEPROM_DRIVER
|
||||||
|
# include "eeprom_driver.h"
|
||||||
|
#endif
|
||||||
|
#include "suspend.h"
|
||||||
|
#include "wait.h"
|
||||||
|
|
||||||
|
#include "iusb.h"
|
||||||
|
|
||||||
|
void platform_setup(void);
|
||||||
|
extern char __StackTop;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// MACRO CONSTANT TYPEDEF PROTYPES
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
static int cdc_in_chars(char* buf, int len) { return 0; }
|
||||||
|
|
||||||
|
static void cdc_write(const char* buf, int length) {
|
||||||
|
static uint64_t last_avail_time;
|
||||||
|
if (tud_cdc_connected()) {
|
||||||
|
for (int i = 0; i < length;) {
|
||||||
|
int n = length - i;
|
||||||
|
int avail = tud_cdc_write_available();
|
||||||
|
if (n > avail) n = avail;
|
||||||
|
if (n) {
|
||||||
|
int n2 = tud_cdc_write(buf + i, n);
|
||||||
|
tud_task();
|
||||||
|
tud_cdc_write_flush();
|
||||||
|
i += n2;
|
||||||
|
last_avail_time = time_us_64();
|
||||||
|
} else {
|
||||||
|
tud_task();
|
||||||
|
tud_cdc_write_flush();
|
||||||
|
if (!tud_cdc_connected() || (!tud_cdc_write_available() && time_us_64() > last_avail_time + 500000)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static stdio_driver_t stdio_driver = {.out_chars = cdc_write, .out_flush = NULL, .in_chars = cdc_in_chars, .next = NULL};
|
||||||
|
|
||||||
|
void pico_cdc_enable_printf(void) { stdio_set_driver_enabled(&stdio_driver, true); }
|
||||||
|
void pico_cdc_disable_printf(void) { stdio_set_driver_enabled(&stdio_driver, false); }
|
||||||
|
|
||||||
|
/* host struct */
|
||||||
|
host_driver_t driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer};
|
||||||
|
|
||||||
|
static void console_task(void) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
static void raw_hid_task(void) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
static void midi_ep_task(void) {}
|
||||||
|
|
||||||
|
void protocol_setup(void) { EEPROM_Init(); tusb_init(); }
|
||||||
|
|
||||||
|
void protocol_pre_init(void) {
|
||||||
|
// if (watchdog_caused_reboot() && watchdog_hw->scratch[0] == 0x2040dead) {
|
||||||
|
// bootloader_jump();
|
||||||
|
// }
|
||||||
|
watchdog_enable(8000, 1);
|
||||||
|
watchdog_hw->scratch[0] = 0x2040dead;
|
||||||
|
pico_cdc_enable_printf();
|
||||||
|
}
|
||||||
|
|
||||||
|
void protocol_post_init(void) { host_set_driver(&driver); }
|
||||||
|
|
||||||
|
void protocol_pre_task(void) {
|
||||||
|
tud_task(); // tinyusb device task
|
||||||
|
}
|
||||||
|
|
||||||
|
void protocol_post_task(void) {
|
||||||
|
#ifdef CONSOLE_ENABLE
|
||||||
|
console_task();
|
||||||
|
#endif
|
||||||
|
#ifdef MIDI_ENABLE
|
||||||
|
midi_ep_task();
|
||||||
|
#endif
|
||||||
|
#ifdef VIRTSER_ENABLE
|
||||||
|
virtser_task();
|
||||||
|
#endif
|
||||||
|
#ifdef RAW_ENABLE
|
||||||
|
raw_hid_task();
|
||||||
|
#endif
|
||||||
|
watchdog_update();
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Device callbacks
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// Invoked when device is mounted
|
||||||
|
void tud_mount_cb(void) {}
|
||||||
|
|
||||||
|
// Invoked when device is unmounted
|
||||||
|
void tud_umount_cb(void) {}
|
||||||
|
|
||||||
|
// Invoked when usb bus is suspended
|
||||||
|
// remote_wakeup_en : if host allow us to perform remote wakeup
|
||||||
|
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
|
||||||
|
void tud_suspend_cb(bool remote_wakeup_en) { (void)remote_wakeup_en; }
|
||||||
|
|
||||||
|
// Invoked when usb bus is resumed
|
||||||
|
void tud_resume_cb(void) {}
|
||||||
|
|
||||||
|
// Invoked when cdc when line state changed e.g connected/disconnected
|
||||||
|
void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {
|
||||||
|
(void)itf;
|
||||||
|
(void)rts;
|
||||||
|
|
||||||
|
// TODO set some indicator
|
||||||
|
if (dtr) {
|
||||||
|
// Terminal connected
|
||||||
|
} else {
|
||||||
|
// Terminal disconnected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((weak)) void pico_cdc_change_baudrate_cb(uint32_t baudrate) {
|
||||||
|
if (baudrate == 1200) {
|
||||||
|
bootloader_jump();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding) {
|
||||||
|
(void)itf;
|
||||||
|
pico_cdc_change_baudrate_cb(p_line_coding->bit_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((weak)) void pico_cdc_receive_cb(uint8_t const* buf, uint32_t cnt) {
|
||||||
|
tud_cdc_write(buf, cnt);
|
||||||
|
tud_cdc_write_flush();
|
||||||
|
|
||||||
|
if (buf[0] == 'b') {
|
||||||
|
bootloader_jump();
|
||||||
|
} else if (buf[0] == 'l') {
|
||||||
|
printf("init eeprom emulation\n");
|
||||||
|
EEPROM_Init();
|
||||||
|
printf("complete\n");
|
||||||
|
} else if (buf[0] == 'c') {
|
||||||
|
printf("clear eeprom emulation\n");
|
||||||
|
EEPROM_Erase();
|
||||||
|
printf("complete\n");
|
||||||
|
} else if (buf[0] == 'd') {
|
||||||
|
printf("debug print ");
|
||||||
|
if (!debug_enable) {
|
||||||
|
debug_enable = true;
|
||||||
|
dprint("true\n");
|
||||||
|
} else {
|
||||||
|
debug_enable = false;
|
||||||
|
print("false\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when CDC interface received data from host
|
||||||
|
void tud_cdc_rx_cb(uint8_t itf) {
|
||||||
|
if (tud_cdc_available()) {
|
||||||
|
// read datas
|
||||||
|
char buf[64];
|
||||||
|
uint32_t count = tud_cdc_read(buf, sizeof(buf));
|
||||||
|
(void)count;
|
||||||
|
|
||||||
|
pico_cdc_receive_cb((uint8_t*)buf, count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when sent REPORT successfully to host
|
||||||
|
// Application can use this to send the next report
|
||||||
|
// Note: For composite reports, report[0] is report ID
|
||||||
|
void tud_hid_report_complete_cb(uint8_t itf, uint8_t const* report, uint8_t len) {
|
||||||
|
(void)itf;
|
||||||
|
(void)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when received GET_REPORT control request
|
||||||
|
// Application must fill buffer report's content and return its length.
|
||||||
|
// Return zero will cause the stack to STALL request
|
||||||
|
uint16_t tud_hid_get_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) {
|
||||||
|
// TODO not Implemented
|
||||||
|
(void)itf;
|
||||||
|
(void)report_id;
|
||||||
|
(void)report_type;
|
||||||
|
(void)buffer;
|
||||||
|
(void)reqlen;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t keyboard_indicator_led;
|
||||||
|
uint8_t get_keyboard_led_status(void) { return keyboard_indicator_led; }
|
||||||
|
|
||||||
|
// Invoked when received SET_REPORT control request or
|
||||||
|
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
||||||
|
void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) {
|
||||||
|
switch (itf) {
|
||||||
|
case ITF_NUM_HID_KEYBOARD:
|
||||||
|
// LED status
|
||||||
|
keyboard_indicator_led = buffer[0];
|
||||||
|
break;
|
||||||
|
#ifdef VIA_ENABLE
|
||||||
|
case ITF_NUM_HID_RAW:
|
||||||
|
raw_hid_receive((uint8_t*)buffer, bufsize);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
tmk_core/protocol/pico/pico/config_autogen.h
Normal file
11
tmk_core/protocol/pico/pico/config_autogen.h
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
//
|
||||||
|
// TODO Generate by makefile
|
||||||
|
//
|
||||||
|
|
||||||
|
// based on PICO_CONFIG_HEADER_FILES:
|
||||||
|
|
||||||
|
#include "boards/include/boards/pico.h"
|
||||||
|
|
||||||
|
// based on PICO_RP2040_CONFIG_HEADER_FILES:
|
||||||
|
|
||||||
|
#include "rp2_common/cmsis/include/cmsis/rename_exceptions.h"
|
||||||
19
tmk_core/protocol/pico/pico/version.h
Normal file
19
tmk_core/protocol/pico/pico/version.h
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ---------------------------------------
|
||||||
|
// THIS FILE IS AUTOGENERATED; DO NOT EDIT
|
||||||
|
// ---------------------------------------
|
||||||
|
|
||||||
|
#ifndef _PICO_VERSION_H
|
||||||
|
#define _PICO_VERSION_H
|
||||||
|
|
||||||
|
#define PICO_SDK_VERSION_MAJOR 1
|
||||||
|
#define PICO_SDK_VERSION_MINOR 2
|
||||||
|
#define PICO_SDK_VERSION_REVISION 0
|
||||||
|
#define PICO_SDK_VERSION_STRING "1.2.0"
|
||||||
|
|
||||||
|
#endif
|
||||||
24
tmk_core/protocol/pico/pico_cdc.h
Normal file
24
tmk_core/protocol/pico/pico_cdc.h
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
|
void pico_cdc_enable_printf(void);
|
||||||
|
void pico_cdc_disable_printf(void);
|
||||||
|
|
||||||
|
// weak functions
|
||||||
|
void pico_cdc_change_baudrate_cb(uint32_t baudrate);
|
||||||
|
void pico_cdc_receive_cb(uint8_t const* buf, uint32_t cnt);
|
||||||
47
tmk_core/protocol/pico/pio_manager.c
Normal file
47
tmk_core/protocol/pico/pio_manager.c
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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 "pio_manager.h"
|
||||||
|
#include "hardware/pio.h"
|
||||||
|
|
||||||
|
int32_t pio_manager_get_empty_sm(PIO pio) {
|
||||||
|
check_pio_param(pio);
|
||||||
|
for (uint32_t sm = 0; sm < NUM_PIO_STATE_MACHINES; sm++) {
|
||||||
|
if (!pio_sm_is_claimed(pio, sm)) return sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t pio_manager_add_program(PIO pio, uint32_t sm,
|
||||||
|
pio_program_t const* program) {
|
||||||
|
check_pio_param(pio);
|
||||||
|
check_sm_param(sm);
|
||||||
|
|
||||||
|
if (pio_sm_is_claimed(pio, sm)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pio_can_add_program(pio, program)) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
pio_sm_claim(pio, sm);
|
||||||
|
|
||||||
|
uint32_t offset = pio_add_program(pio, program);
|
||||||
|
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
23
tmk_core/protocol/pico/pio_manager.h
Normal file
23
tmk_core/protocol/pico/pio_manager.h
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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 "hardware/pio.h"
|
||||||
|
|
||||||
|
int32_t pio_manager_get_empty_sm(PIO pio);
|
||||||
|
int32_t pio_manager_add_program(PIO pio, uint32_t sm,
|
||||||
|
pio_program_t const* program);
|
||||||
122
tmk_core/protocol/pico/tusb_config.h
Normal file
122
tmk_core/protocol/pico/tusb_config.h
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TUSB_CONFIG_H_
|
||||||
|
#define _TUSB_CONFIG_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// COMMON CONFIGURATION
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
// defined by board.mk
|
||||||
|
#ifndef CFG_TUSB_MCU
|
||||||
|
#error CFG_TUSB_MCU must be defined
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// RHPort number used for device can be defined by board.mk, default to port 0
|
||||||
|
#ifndef BOARD_DEVICE_RHPORT_NUM
|
||||||
|
#define BOARD_DEVICE_RHPORT_NUM 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// RHPort max operational speed can defined by board.mk
|
||||||
|
// Default to Highspeed for MCU with internal HighSpeed PHY (can be port specific), otherwise FullSpeed
|
||||||
|
#ifndef BOARD_DEVICE_RHPORT_SPEED
|
||||||
|
#if (CFG_TUSB_MCU == OPT_MCU_LPC18XX || CFG_TUSB_MCU == OPT_MCU_LPC43XX || CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX || \
|
||||||
|
CFG_TUSB_MCU == OPT_MCU_NUC505 || CFG_TUSB_MCU == OPT_MCU_CXD56)
|
||||||
|
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_HIGH_SPEED
|
||||||
|
#else
|
||||||
|
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Device mode with rhport and speed defined by board.mk
|
||||||
|
#if BOARD_DEVICE_RHPORT_NUM == 0
|
||||||
|
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
|
||||||
|
#elif BOARD_DEVICE_RHPORT_NUM == 1
|
||||||
|
#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
|
||||||
|
#else
|
||||||
|
#error "Incorrect RHPort configuration"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// This example doesn't use an RTOS
|
||||||
|
#ifndef CFG_TUSB_OS
|
||||||
|
#define CFG_TUSB_OS OPT_OS_NONE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// CFG_TUSB_DEBUG is defined by compiler in DEBUG build
|
||||||
|
// #define CFG_TUSB_DEBUG 0
|
||||||
|
|
||||||
|
/* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment.
|
||||||
|
* Tinyusb use follows macros to declare transferring memory so that they can be put
|
||||||
|
* into those specific section.
|
||||||
|
* e.g
|
||||||
|
* - CFG_TUSB_MEM SECTION : __attribute__ (( section(".usb_ram") ))
|
||||||
|
* - CFG_TUSB_MEM_ALIGN : __attribute__ ((aligned(4)))
|
||||||
|
*/
|
||||||
|
#ifndef CFG_TUSB_MEM_SECTION
|
||||||
|
#define CFG_TUSB_MEM_SECTION
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CFG_TUSB_MEM_ALIGN
|
||||||
|
#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
// DEVICE CONFIGURATION
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef CFG_TUD_ENDPOINT0_SIZE
|
||||||
|
#define CFG_TUD_ENDPOINT0_SIZE 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------- CLASS -------------//
|
||||||
|
#define CFG_TUD_CDC 1
|
||||||
|
#define CFG_TUD_MSC 0
|
||||||
|
#define CFG_TUD_HID 5
|
||||||
|
#define CFG_TUD_MIDI 1
|
||||||
|
#define CFG_TUD_VENDOR 0
|
||||||
|
|
||||||
|
// CDC FIFO size of TX and RX
|
||||||
|
#define CFG_TUD_CDC_RX_BUFSIZE 64
|
||||||
|
#define CFG_TUD_CDC_TX_BUFSIZE 2048
|
||||||
|
|
||||||
|
// CDC Endpoint transfer buffer size, more is faster
|
||||||
|
#define CFG_TUD_CDC_EP_BUFSIZE 64
|
||||||
|
|
||||||
|
// HID buffer size Should be sufficient to hold ID (if any) + Data
|
||||||
|
#define CFG_TUD_HID_EP_BUFSIZE 64
|
||||||
|
|
||||||
|
#define CFG_TUD_MIDI_RX_BUFSIZE 64
|
||||||
|
#define CFG_TUD_MIDI_TX_BUFSIZE 64
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _TUSB_CONFIG_H_ */
|
||||||
232
tmk_core/protocol/pico/usb_descriptors.c
Normal file
232
tmk_core/protocol/pico/usb_descriptors.c
Normal file
|
|
@ -0,0 +1,232 @@
|
||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* Modifications for QMK and RP2040 by sekigon-gonnoc
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tusb.h"
|
||||||
|
#include "report.h"
|
||||||
|
#include "usb_descriptors.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/* A combination of interfaces must have a unique product id, since PC will save
|
||||||
|
* device driver after the first plug. Same VID/PID with different interface e.g
|
||||||
|
* MSC (first), then CDC (later) will possibly cause system error on PC.
|
||||||
|
*
|
||||||
|
* Auto ProductID layout's Bitmap:
|
||||||
|
* [MSB] HID | MSC | CDC [LSB]
|
||||||
|
*/
|
||||||
|
#define _PID_MAP(itf, n) ((CFG_TUD_##itf) << (n))
|
||||||
|
#define USB_PID \
|
||||||
|
(0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
|
||||||
|
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4))
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Device Descriptors
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
tusb_desc_device_t const desc_device = {
|
||||||
|
.bLength = sizeof(tusb_desc_device_t),
|
||||||
|
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||||
|
.bcdUSB = 0x0200,
|
||||||
|
|
||||||
|
// Use Interface Association Descriptor (IAD) for CDC
|
||||||
|
// As required by USB Specs IAD's subclass must be common class (2) and
|
||||||
|
// protocol must be IAD (1)
|
||||||
|
.bDeviceClass = TUSB_CLASS_MISC,
|
||||||
|
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||||
|
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||||
|
|
||||||
|
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||||
|
|
||||||
|
.idVendor = VENDOR_ID,
|
||||||
|
.idProduct = PRODUCT_ID,
|
||||||
|
.bcdDevice = 0x0100,
|
||||||
|
|
||||||
|
.iManufacturer = 0x01,
|
||||||
|
.iProduct = 0x02,
|
||||||
|
.iSerialNumber = 0x03,
|
||||||
|
|
||||||
|
.bNumConfigurations = 0x01};
|
||||||
|
|
||||||
|
// Invoked when received GET DEVICE DESCRIPTOR
|
||||||
|
// Application return pointer to descriptor
|
||||||
|
uint8_t const* tud_descriptor_device_cb(void) {
|
||||||
|
return (uint8_t const*)&desc_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// Configuration Descriptor
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
#ifdef MIDI_ENABLE
|
||||||
|
# define MIDI_DESC_LEN TUD_MIDI_DESC_LEN
|
||||||
|
#else
|
||||||
|
# define MIDI_DESC_LEN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CONFIG_TOTAL_LEN \
|
||||||
|
(TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_HID_DESC_LEN * 4 + \
|
||||||
|
TUD_HID_INOUT_DESC_LEN + MIDI_DESC_LEN)
|
||||||
|
|
||||||
|
#define EPNUM_HID_KEYBOARD_IN 0x81
|
||||||
|
#define EPNUM_HID_MOUSE_IN 0x82
|
||||||
|
#define EPNUM_HID_EXTRA_IN 0x83
|
||||||
|
#define EPNUM_HID_RAW_IN 0x84
|
||||||
|
#define EPNUM_HID_RAW_OUT 0x04
|
||||||
|
#define EPNUM_HID_CONSOLE_IN 0x85
|
||||||
|
|
||||||
|
#define EPNUM_CDC_NOTIF 0x86
|
||||||
|
#define EPNUM_CDC_OUT 0x07
|
||||||
|
#define EPNUM_CDC_IN 0x87
|
||||||
|
|
||||||
|
#ifdef MIDI_ENABLE
|
||||||
|
# define EPNUM_MIDI_IN 0x88
|
||||||
|
# define EPNUM_MIDI_OUT 0x08
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static uint8_t const desc_keyboard[] = {TUD_HID_REPORT_DESC_KEYBOARD()};
|
||||||
|
|
||||||
|
static uint8_t const desc_mouse[] = {TUD_HID_REPORT_DESC_MOUSE()};
|
||||||
|
|
||||||
|
static uint8_t const desc_extra[] = {
|
||||||
|
TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(REPORT_ID_CONSUMER)),
|
||||||
|
TUD_HID_REPORT_DESC_SYSTEM_CONTROL(HID_REPORT_ID(REPORT_ID_SYSTEM)),
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t const desc_raw[] = {HID_REPORT_DESC_RAW()};
|
||||||
|
|
||||||
|
static uint8_t const desc_console[] = {HID_REPORT_DESC_CONSOLE()};
|
||||||
|
|
||||||
|
uint8_t const* tud_hid_descriptor_report_cb(uint8_t itf) {
|
||||||
|
switch (itf) {
|
||||||
|
case ITF_NUM_HID_KEYBOARD:
|
||||||
|
return desc_keyboard;
|
||||||
|
case ITF_NUM_HID_MOUSE:
|
||||||
|
return desc_mouse;
|
||||||
|
case ITF_NUM_HID_EXTRA:
|
||||||
|
return desc_extra;
|
||||||
|
case ITF_NUM_HID_RAW:
|
||||||
|
return desc_raw;
|
||||||
|
case ITF_NUM_HID_CONSOLE:
|
||||||
|
return desc_console;
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t const desc_fs_configuration[] = {
|
||||||
|
// Config number, interface count, string index, total length, attribute,
|
||||||
|
// power in mA
|
||||||
|
TUD_CONFIG_DESCRIPTOR(1, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN,
|
||||||
|
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
|
||||||
|
|
||||||
|
// Interface number, string index, protocol, report descriptor len, EP In
|
||||||
|
// address, size & polling interval
|
||||||
|
TUD_HID_DESCRIPTOR(ITF_NUM_HID_KEYBOARD, 2, HID_ITF_PROTOCOL_NONE,
|
||||||
|
sizeof(desc_keyboard), EPNUM_HID_KEYBOARD_IN,
|
||||||
|
CFG_TUD_HID_EP_BUFSIZE, USB_POLLING_INTERVAL_MS),
|
||||||
|
TUD_HID_INOUT_DESCRIPTOR(ITF_NUM_HID_RAW, 2, HID_ITF_PROTOCOL_NONE,
|
||||||
|
sizeof(desc_raw), EPNUM_HID_RAW_OUT,
|
||||||
|
EPNUM_HID_RAW_IN, CFG_TUD_HID_EP_BUFSIZE, 1),
|
||||||
|
TUD_HID_DESCRIPTOR(ITF_NUM_HID_MOUSE, 2, HID_ITF_PROTOCOL_NONE,
|
||||||
|
sizeof(desc_mouse), EPNUM_HID_MOUSE_IN,
|
||||||
|
CFG_TUD_HID_EP_BUFSIZE, 1),
|
||||||
|
TUD_HID_DESCRIPTOR(ITF_NUM_HID_EXTRA, 2, HID_ITF_PROTOCOL_NONE,
|
||||||
|
sizeof(desc_extra), EPNUM_HID_EXTRA_IN,
|
||||||
|
CFG_TUD_HID_EP_BUFSIZE, 10),
|
||||||
|
TUD_HID_DESCRIPTOR(ITF_NUM_HID_CONSOLE, 2, HID_ITF_PROTOCOL_NONE,
|
||||||
|
sizeof(desc_console), EPNUM_HID_CONSOLE_IN,
|
||||||
|
CFG_TUD_HID_EP_BUFSIZE, 10),
|
||||||
|
|
||||||
|
// Interface number, string index, EP notification address and size, EP data
|
||||||
|
// address (out, in) and size.
|
||||||
|
TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, 2, EPNUM_CDC_NOTIF, 8, EPNUM_CDC_OUT,
|
||||||
|
EPNUM_CDC_IN, 64),
|
||||||
|
|
||||||
|
#ifdef MIDI_ENABLE
|
||||||
|
TUD_MIDI_DESCRIPTOR(ITF_NUM_MIDI, 2, EPNUM_MIDI_OUT, EPNUM_MIDI_IN, 64)
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// Invoked when received GET CONFIGURATION DESCRIPTOR
|
||||||
|
// Application return pointer to descriptor
|
||||||
|
// Descriptor contents must exist long enough for transfer to complete
|
||||||
|
uint8_t const* tud_descriptor_configuration_cb(uint8_t index) {
|
||||||
|
(void)index; // for multiple configurations
|
||||||
|
|
||||||
|
return desc_fs_configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
// String Descriptors
|
||||||
|
//--------------------------------------------------------------------+
|
||||||
|
|
||||||
|
// array of pointer to string descriptors
|
||||||
|
char const* string_desc_arr[] = {
|
||||||
|
(const char[]){0x09, 0x04}, // 0: is supported language is English (0x0409)
|
||||||
|
STR(MANUFACTURER), // 1: Manufacturer
|
||||||
|
STR(PRODUCT), // 2: Product
|
||||||
|
#ifdef VIAL_ENABLE
|
||||||
|
SERIAL_NUMBER,
|
||||||
|
#else
|
||||||
|
"123456", // 3: Serials, should use chip ID
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint16_t _desc_str[32];
|
||||||
|
|
||||||
|
// Invoked when received GET STRING DESCRIPTOR request
|
||||||
|
// Application return pointer to descriptor, whose contents must exist long
|
||||||
|
// enough for transfer to complete
|
||||||
|
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||||
|
(void)langid;
|
||||||
|
|
||||||
|
uint8_t chr_count;
|
||||||
|
|
||||||
|
if (index == 0) {
|
||||||
|
memcpy(&_desc_str[1], string_desc_arr[0], 2);
|
||||||
|
chr_count = 1;
|
||||||
|
} else {
|
||||||
|
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
|
||||||
|
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
|
||||||
|
|
||||||
|
if (!(index < sizeof(string_desc_arr) / sizeof(string_desc_arr[0])))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
const char* str = string_desc_arr[index];
|
||||||
|
|
||||||
|
// Cap at max char
|
||||||
|
chr_count = strlen(str);
|
||||||
|
if (chr_count > 31) chr_count = 31;
|
||||||
|
|
||||||
|
// Convert ASCII string into UTF-16
|
||||||
|
for (uint8_t i = 0; i < chr_count; i++) {
|
||||||
|
_desc_str[1 + i] = str[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// first byte is length (including header), second byte is string type
|
||||||
|
_desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * chr_count + 2);
|
||||||
|
|
||||||
|
return _desc_str;
|
||||||
|
}
|
||||||
60
tmk_core/protocol/pico/usb_descriptors.h
Normal file
60
tmk_core/protocol/pico/usb_descriptors.h
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hid.h"
|
||||||
|
#include "usb_descriptor_common.h"
|
||||||
|
#define RAW_EPSIZE 32
|
||||||
|
#define CONSOLE_EPSIZE 32
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ITF_NUM_HID_KEYBOARD,
|
||||||
|
ITF_NUM_HID_RAW,
|
||||||
|
ITF_NUM_HID_MOUSE,
|
||||||
|
ITF_NUM_HID_EXTRA,
|
||||||
|
ITF_NUM_HID_CONSOLE,
|
||||||
|
ITF_NUM_CDC,
|
||||||
|
ITF_NUM_CDC_DATA,
|
||||||
|
#ifdef MIDI_ENABLE
|
||||||
|
ITF_NUM_MIDI,
|
||||||
|
ITF_NUM_MIDI_STREAMING,
|
||||||
|
#endif
|
||||||
|
ITF_NUM_TOTAL
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HID_REPORT_DESC_RAW() \
|
||||||
|
HID_USAGE_PAGE_N(RAW_USAGE_PAGE, 2), \
|
||||||
|
HID_USAGE(RAW_USAGE_ID), \
|
||||||
|
HID_COLLECTION(HID_COLLECTION_APPLICATION), \
|
||||||
|
HID_USAGE(0x62), \
|
||||||
|
HID_LOGICAL_MIN(0x00), \
|
||||||
|
HID_LOGICAL_MAX_N(0x00FF, 2), \
|
||||||
|
HID_REPORT_COUNT(RAW_EPSIZE), \
|
||||||
|
HID_REPORT_SIZE(0x08), \
|
||||||
|
HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
|
||||||
|
HID_USAGE(0x63), \
|
||||||
|
HID_LOGICAL_MIN(0x00), \
|
||||||
|
HID_LOGICAL_MAX_N(0x00FF, 2), \
|
||||||
|
HID_REPORT_COUNT(RAW_EPSIZE), \
|
||||||
|
HID_REPORT_SIZE(0x08), \
|
||||||
|
HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE | HID_NON_VOLATILE), \
|
||||||
|
HID_COLLECTION_END
|
||||||
|
|
||||||
|
#define HID_REPORT_DESC_CONSOLE() \
|
||||||
|
HID_USAGE_PAGE_N(0xFF31, 2), \
|
||||||
|
HID_USAGE(0x74), \
|
||||||
|
HID_COLLECTION(HID_COLLECTION_APPLICATION), \
|
||||||
|
HID_USAGE(0x75), \
|
||||||
|
HID_LOGICAL_MIN(0x00), \
|
||||||
|
HID_LOGICAL_MAX_N(0x00FF, 2), \
|
||||||
|
HID_REPORT_COUNT(CONSOLE_EPSIZE), \
|
||||||
|
HID_REPORT_SIZE(0x08), \
|
||||||
|
HID_INPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE), \
|
||||||
|
HID_USAGE(0x76), \
|
||||||
|
HID_LOGICAL_MIN(0x00), \
|
||||||
|
HID_LOGICAL_MAX_N(0x00FF, 2), \
|
||||||
|
HID_REPORT_COUNT(CONSOLE_EPSIZE), \
|
||||||
|
HID_REPORT_SIZE(0x08), \
|
||||||
|
HID_OUTPUT(HID_DATA | HID_VARIABLE | HID_ABSOLUTE | HID_NON_VOLATILE), \
|
||||||
|
HID_COLLECTION_END
|
||||||
|
|
||||||
|
uint8_t get_keyboard_led_status(void);
|
||||||
27
tmk_core/protocol/pico/usb_util.c
Normal file
27
tmk_core/protocol/pico/usb_util.c
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* Copyright 2021 sekigon-gonnoc
|
||||||
|
*
|
||||||
|
* 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 "usb_util.h"
|
||||||
|
|
||||||
|
#include "tusb.h"
|
||||||
|
|
||||||
|
bool usb_connected_state(void) {
|
||||||
|
tud_task();
|
||||||
|
return tud_connected();
|
||||||
|
}
|
||||||
|
void usb_disconnect(void) {
|
||||||
|
#warning "No implementation" //TODO implement
|
||||||
|
}
|
||||||
|
|
@ -291,6 +291,8 @@ enum usb_endpoints {
|
||||||
#elif defined(PROTOCOL_CHIBIOS)
|
#elif defined(PROTOCOL_CHIBIOS)
|
||||||
// ChibiOS gives us number of available user endpoints, not control
|
// ChibiOS gives us number of available user endpoints, not control
|
||||||
# define MAX_ENDPOINTS USB_MAX_ENDPOINTS
|
# define MAX_ENDPOINTS USB_MAX_ENDPOINTS
|
||||||
|
#elif defined(PROTOCOL_PICO)
|
||||||
|
# define MAX_ENDPOINTS 16
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// TODO - ARM_ATSAM
|
// TODO - ARM_ATSAM
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue