Merge remote-tracking branch 'upstream/develop' into xap

This commit is contained in:
Nick Brassel 2021-11-28 12:56:26 +11:00
commit bf66b91433
5591 changed files with 131128 additions and 54530 deletions

View file

@ -1,67 +0,0 @@
# Hey Emacs, this is a -*- makefile -*-
##############################################################################
# Compiler settings
#
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) -R .eeprom -R .fuse -R .lock -R .signature
EEP = $(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT)
BIN =
COMMON_VPATH += $(LIB_PATH)/arm_atsam/packs/atmel/SAMD51_DFP/1.0.70/include
COMMON_VPATH += $(LIB_PATH)/arm_atsam/packs/arm/cmsis/5.0.1/CMSIS/Include
COMPILEFLAGS += -funsigned-char
COMPILEFLAGS += -funsigned-bitfields
COMPILEFLAGS += -ffunction-sections
COMPILEFLAGS += -fshort-enums
COMPILEFLAGS += -fno-inline-small-functions
COMPILEFLAGS += -fno-strict-aliasing
COMPILEFLAGS += -mfloat-abi=hard
COMPILEFLAGS += -mfpu=fpv4-sp-d16
COMPILEFLAGS += -mthumb
#ALLOW_WARNINGS = yes
CFLAGS += $(COMPILEFLAGS)
CXXFLAGS += $(COMPILEFLAGS)
CXXFLAGS += -fno-exceptions -std=c++11
LDFLAGS +=-Wl,--gc-sections
LDFLAGS += -Wl,-Map="%OUT%%PROJ_NAME%.map"
LDFLAGS += -Wl,--start-group
LDFLAGS += -Wl,--end-group
LDFLAGS += --specs=rdimon.specs
LDFLAGS += -T$(LIB_PATH)/arm_atsam/packs/atmel/SAMD51_DFP/1.0.70/gcc/gcc/samd51j18a_flash.ld
OPT_DEFS += -DPROTOCOL_ARM_ATSAM
MCUFLAGS = -mcpu=$(MCU)
MCUFLAGS += -D__$(ARM_ATSAM)__
# List any extra directories to look for libraries here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRALIBDIRS =
cpfirmware: warn-arm_atsam
.INTERMEDIATE: warn-arm_atsam
warn-arm_atsam: $(FIRMWARE_FORMAT)
$(info @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@)
$(info This MCU support package has a lack of support from the upstream provider (Massdrop).)
$(info There are currently questions about valid licensing, and at this stage it's likely)
$(info their boards and supporting code will be removed from QMK in the near future. Please)
$(info contact Massdrop for support, and encourage them to align their future board design)
$(info choices to gain proper license compatibility with QMK.)
$(info @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@)
# Convert hex to bin.
bin: $(BUILD_DIR)/$(TARGET).hex
$(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
$(COPY) $(BUILD_DIR)/$(TARGET).bin $(TARGET).bin;

View file

@ -1,179 +0,0 @@
# Hey Emacs, this is a -*- makefile -*-
##############################################################################
# Compiler settings
#
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
AR = avr-ar
NM = avr-nm
HEX = $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature
EEP = $(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT)
BIN =
COMPILEFLAGS += -funsigned-char
COMPILEFLAGS += -funsigned-bitfields
COMPILEFLAGS += -ffunction-sections
COMPILEFLAGS += -fdata-sections
COMPILEFLAGS += -fpack-struct
COMPILEFLAGS += -fshort-enums
ASFLAGS += $(AVR_ASFLAGS)
CFLAGS += $(COMPILEFLAGS) $(AVR_CFLAGS)
CFLAGS += -fno-inline-small-functions
CFLAGS += -fno-strict-aliasing
CXXFLAGS += $(COMPILEFLAGS)
CXXFLAGS += -fno-exceptions -std=c++11
LDFLAGS +=-Wl,--gc-sections
OPT_DEFS += -DF_CPU=$(F_CPU)UL
MCUFLAGS = -mmcu=$(MCU)
# List any extra directories to look for libraries here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRALIBDIRS =
#---------------- External Memory Options ----------------
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# used for variables (.data/.bss) and heap (malloc()).
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# only used for heap (malloc()).
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
EXTMEMOPTS =
#---------------- Debugging Options ----------------
# Debugging format.
# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
# AVR Studio 4.10 requires dwarf-2.
# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
DEBUG = dwarf-2
# For simulavr only - target MCU frequency.
DEBUG_MFREQ = $(F_CPU)
# Set the DEBUG_UI to either gdb or insight.
# DEBUG_UI = gdb
DEBUG_UI = insight
# Set the debugging back-end to either avarice, simulavr.
DEBUG_BACKEND = avarice
#DEBUG_BACKEND = simulavr
# GDB Init Filename.
GDBINIT_FILE = __avr_gdbinit
# When using avarice settings for the JTAG
JTAG_DEV = /dev/com1
# Debugging port used to communicate between GDB / avarice / simulavr.
DEBUG_PORT = 4242
# Debugging host used to communicate between GDB / avarice / simulavr, normally
# just set to localhost unless doing some sort of crazy debugging when
# avarice is running on a different computer.
DEBUG_HOST = localhost
#============================================================================
# Convert hex to bin.
bin: $(BUILD_DIR)/$(TARGET).hex
ifeq ($(BOOTLOADER),lufa-ms)
$(eval BIN_PADDING=$(shell n=`expr 32768 - $(BOOTLOADER_SIZE)` && echo $$(($$n)) || echo 0))
$(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin --pad-to $(BIN_PADDING)
else
$(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
endif
$(COPY) $(BUILD_DIR)/$(TARGET).bin $(TARGET).bin;
# copy bin to FLASH.bin
flashbin: bin
$(COPY) $(BUILD_DIR)/$(TARGET).bin FLASH.bin;
# Generate avr-gdb config/init file which does the following:
# define the reset signal, load the target file, connect to target, and set
# a breakpoint at main().
gdb-config:
@$(REMOVE) $(GDBINIT_FILE)
@echo define reset >> $(GDBINIT_FILE)
@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
@echo end >> $(GDBINIT_FILE)
@echo file $(BUILD_DIR)/$(TARGET).elf >> $(GDBINIT_FILE)
@echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
ifeq ($(DEBUG_BACKEND),simulavr)
@echo load >> $(GDBINIT_FILE)
endif
@echo break main >> $(GDBINIT_FILE)
debug: gdb-config $(BUILD_DIR)/$(TARGET).elf
ifeq ($(DEBUG_BACKEND), avarice)
@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
$(BUILD_DIR)/$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
@$(WINSHELL) /c pause
else
@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
$(DEBUG_MFREQ) --port $(DEBUG_PORT)
endif
@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT = $(OBJCOPY) --debugging
COFFCONVERT += --change-section-address .data-0x800000
COFFCONVERT += --change-section-address .bss-0x800000
COFFCONVERT += --change-section-address .noinit-0x800000
COFFCONVERT += --change-section-address .eeprom-0x810000
coff: $(BUILD_DIR)/$(TARGET).elf
@$(SECHO) $(MSG_COFF) $(BUILD_DIR)/$(TARGET).cof
$(COFFCONVERT) -O coff-avr $< $(BUILD_DIR)/$(TARGET).cof
extcoff: $(BUILD_DIR)/$(TARGET).elf
@$(SECHO) $(MSG_EXTENDED_COFF) $(BUILD_DIR)/$(TARGET).cof
$(COFFCONVERT) -O coff-ext-avr $< $(BUILD_DIR)/$(TARGET).cof
ifeq ($(strip $(BOOTLOADER)), qmk-dfu)
QMK_BOOTLOADER_TYPE = DFU
else ifeq ($(strip $(BOOTLOADER)), qmk-hid)
QMK_BOOTLOADER_TYPE = HID
endif
bootloader:
ifeq ($(strip $(QMK_BOOTLOADER_TYPE)),)
$(error Please set BOOTLOADER to "qmk-dfu" or "qmk-hid" first!)
else
make -C lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/ clean
$(QMK_BIN) generate-dfu-header --quiet --keyboard $(KEYBOARD) --output lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/Keyboard.h
$(eval MAX_SIZE=$(shell n=`$(CC) -E -mmcu=$(MCU) -D__ASSEMBLER__ $(CFLAGS) $(OPT_DEFS) tmk_core/common/avr/bootloader_size.c 2> /dev/null | sed -ne 's/\r//;/^#/n;/^AVR_SIZE:/,$${s/^AVR_SIZE: //;p;}'` && echo $$(($$n)) || echo 0))
$(eval PROGRAM_SIZE_KB=$(shell n=`expr $(MAX_SIZE) / 1024` && echo $$(($$n)) || echo 0))
$(eval BOOT_SECTION_SIZE_KB=$(shell n=`expr $(BOOTLOADER_SIZE) / 1024` && echo $$(($$n)) || echo 0))
$(eval FLASH_SIZE_KB=$(shell n=`expr $(PROGRAM_SIZE_KB) + $(BOOT_SECTION_SIZE_KB)` && echo $$(($$n)) || echo 0))
make -C lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/ MCU=$(MCU) ARCH=$(ARCH) F_CPU=$(F_CPU) FLASH_SIZE_KB=$(FLASH_SIZE_KB) BOOT_SECTION_SIZE_KB=$(BOOT_SECTION_SIZE_KB)
printf "Bootloader$(QMK_BOOTLOADER_TYPE).hex copied to $(TARGET)_bootloader.hex\n"
cp lib/lufa/Bootloaders/$(QMK_BOOTLOADER_TYPE)/Bootloader$(QMK_BOOTLOADER_TYPE).hex $(TARGET)_bootloader.hex
endif
production: $(BUILD_DIR)/$(TARGET).hex bootloader cpfirmware
@cat $(BUILD_DIR)/$(TARGET).hex | awk '/^:00000001FF/ == 0' > $(TARGET)_production.hex
@cat $(TARGET)_bootloader.hex >> $(TARGET)_production.hex
echo "File sizes:"
$(SIZE) $(TARGET).hex $(TARGET)_bootloader.hex $(TARGET)_production.hex

View file

@ -1,332 +0,0 @@
# Hey Emacs, this is a -*- makefile -*-
##############################################################################
# Architecture or project specific options
#
# Stack size to be allocated to the Cortex-M process stack. This stack is
# the stack used by the main() thread.
ifeq ($(USE_PROCESS_STACKSIZE),)
USE_PROCESS_STACKSIZE = 0x800
endif
# Stack size to the allocated to the Cortex-M main/exceptions stack. This
# stack is used for processing interrupts and exceptions.
ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
USE_EXCEPTIONS_STACKSIZE = 0x400
endif
#
# Architecture or project specific options
##############################################################################
##############################################################################
# Project, sources and paths
#
# Imported source files and paths
OPT_OS = chibios
CHIBIOS = $(TOP_DIR)/lib/chibios
CHIBIOS_CONTRIB = $(TOP_DIR)/lib/chibios-contrib
# Startup files. Try a few different locations, for compability with old versions and
# for things hardware in the contrib repository
STARTUP_MK = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/startup_$(MCU_STARTUP).mk
ifeq ("$(wildcard $(STARTUP_MK))","")
STARTUP_MK = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_$(MCU_STARTUP).mk
ifeq ("$(wildcard $(STARTUP_MK))","")
STARTUP_MK = $(CHIBIOS_CONTRIB)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_$(MCU_STARTUP).mk
endif
endif
include $(STARTUP_MK)
# HAL-OSAL files (optional).
include $(CHIBIOS)/os/hal/hal.mk
ifeq ("$(PLATFORM_NAME)","")
PLATFORM_NAME = platform
endif
PLATFORM_MK = $(CHIBIOS)/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)/$(PLATFORM_NAME).mk
ifeq ("$(wildcard $(PLATFORM_MK))","")
PLATFORM_MK = $(CHIBIOS_CONTRIB)/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)/$(PLATFORM_NAME).mk
endif
include $(PLATFORM_MK)
BOARD_MK :=
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/boards/$(BOARD)/board.mk)","")
BOARD_PATH = $(KEYBOARD_PATH_5)
BOARD_MK += $(KEYBOARD_PATH_5)/boards/$(BOARD)/board.mk
else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/boards/$(BOARD)/board.mk)","")
BOARD_PATH = $(KEYBOARD_PATH_4)
BOARD_MK += $(KEYBOARD_PATH_4)/boards/$(BOARD)/board.mk
else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/boards/$(BOARD)/board.mk)","")
BOARD_PATH = $(KEYBOARD_PATH_3)
BOARD_MK += $(KEYBOARD_PATH_3)/boards/$(BOARD)/board.mk
else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/boards/$(BOARD)/board.mk)","")
BOARD_PATH = $(KEYBOARD_PATH_2)
BOARD_MK += $(KEYBOARD_PATH_2)/boards/$(BOARD)/board.mk
else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/boards/$(BOARD)/board.mk)","")
BOARD_PATH = $(KEYBOARD_PATH_1)
BOARD_MK += $(KEYBOARD_PATH_1)/boards/$(BOARD)/board.mk
else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/board/board.mk)","")
BOARD_PATH = $(TOP_DIR)/platforms/chibios/boards/$(BOARD)
BOARD_MK += $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/board/board.mk
KEYBOARD_PATHS += $(BOARD_PATH)/configs
ifneq ("$(wildcard $(BOARD_PATH)/rules.mk)","")
include $(BOARD_PATH)/rules.mk
endif
endif
ifeq ("$(wildcard $(BOARD_MK))","")
BOARD_MK = $(CHIBIOS)/os/hal/boards/$(BOARD)/board.mk
ifeq ("$(wildcard $(BOARD_MK))","")
BOARD_MK = $(CHIBIOS_CONTRIB)/os/hal/boards/$(BOARD)/board.mk
endif
endif
# Bootloader address
ifdef STM32_BOOTLOADER_ADDRESS
OPT_DEFS += -DSTM32_BOOTLOADER_ADDRESS=$(STM32_BOOTLOADER_ADDRESS)
endif
# Work out if we need to set up the include for the bootloader definitions
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/bootloader_defs.h)","")
OPT_DEFS += -include $(KEYBOARD_PATH_5)/bootloader_defs.h
else ifneq ("$(wildcard $(KEYBOARD_PATH_5)/boards/$(BOARD)/bootloader_defs.h)","")
OPT_DEFS += -include $(KEYBOARD_PATH_5)/boards/$(BOARD)/bootloader_defs.h
else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/bootloader_defs.h)","")
OPT_DEFS += -include $(KEYBOARD_PATH_4)/bootloader_defs.h
else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/boards/$(BOARD)/bootloader_defs.h)","")
OPT_DEFS += -include $(KEYBOARD_PATH_4)/boards/$(BOARD)/bootloader_defs.h
else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/bootloader_defs.h)","")
OPT_DEFS += -include $(KEYBOARD_PATH_3)/bootloader_defs.h
else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/boards/$(BOARD)/bootloader_defs.h)","")
OPT_DEFS += -include $(KEYBOARD_PATH_3)/boards/$(BOARD)/bootloader_defs.h
else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/bootloader_defs.h)","")
OPT_DEFS += -include $(KEYBOARD_PATH_2)/bootloader_defs.h
else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/boards/$(BOARD)/bootloader_defs.h)","")
OPT_DEFS += -include $(KEYBOARD_PATH_2)/boards/$(BOARD)/bootloader_defs.h
else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/bootloader_defs.h)","")
OPT_DEFS += -include $(KEYBOARD_PATH_1)/bootloader_defs.h
else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/boards/$(BOARD)/bootloader_defs.h)","")
OPT_DEFS += -include $(KEYBOARD_PATH_1)/boards/$(BOARD)/bootloader_defs.h
else ifneq ("$(wildcard $(BOARD_PATH)/configs/bootloader_defs.h)","")
OPT_DEFS += -include $(BOARD_PATH)/configs/bootloader_defs.h
endif
# Work out the config file directories
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/chconf.h)","")
CHCONFDIR = $(KEYBOARD_PATH_5)
else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/chconf.h)","")
CHCONFDIR = $(KEYBOARD_PATH_4)
else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/chconf.h)","")
CHCONFDIR = $(KEYBOARD_PATH_3)
else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/chconf.h)","")
CHCONFDIR = $(KEYBOARD_PATH_2)
else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/chconf.h)","")
CHCONFDIR = $(KEYBOARD_PATH_1)
else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs/chconf.h)","")
CHCONFDIR = $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs
else ifneq ("$(wildcard $(TOP_DIR)/platforms/boards/chibios/common/configs/chconf.h)","")
CHCONFDIR = $(TOP_DIR)/platforms/chibios/boards/common/configs
endif
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/halconf.h)","")
HALCONFDIR = $(KEYBOARD_PATH_5)
else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/halconf.h)","")
HALCONFDIR = $(KEYBOARD_PATH_4)
else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/halconf.h)","")
HALCONFDIR = $(KEYBOARD_PATH_3)
else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/halconf.h)","")
HALCONFDIR = $(KEYBOARD_PATH_2)
else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/halconf.h)","")
HALCONFDIR = $(KEYBOARD_PATH_1)
else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs/halconf.h)","")
HALCONFDIR = $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs
else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/common/configs/halconf.h)","")
HALCONFDIR = $(TOP_DIR)/platforms/chibios/boards/common/configs
endif
# HAL-OSAL files (optional).
include $(CHIBIOS)/os/hal/hal.mk
ifeq ("$(PLATFORM_NAME)","")
PLATFORM_NAME = platform
endif
PLATFORM_MK = $(CHIBIOS)/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)/$(PLATFORM_NAME).mk
ifeq ("$(wildcard $(PLATFORM_MK))","")
PLATFORM_MK = $(CHIBIOS_CONTRIB)/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)/$(PLATFORM_NAME).mk
endif
include $(PLATFORM_MK)
include $(BOARD_MK)
-include $(CHIBIOS)/os/hal/osal/rt/osal.mk # ChibiOS <= 19.x
-include $(CHIBIOS)/os/hal/osal/rt-nil/osal.mk # ChibiOS >= 20.x
# RTOS files (optional).
include $(CHIBIOS)/os/rt/rt.mk
# Compability with old version
PORT_V = $(CHIBIOS)/os/rt/ports/ARMCMx/compilers/GCC/mk/port_v$(ARMV)m.mk
ifeq ("$(wildcard $(PORT_V))","")
PORT_V = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v$(ARMV)m.mk
endif
include $(PORT_V)
# Other files (optional).
include $(CHIBIOS)/os/hal/lib/streams/streams.mk
RULESPATH = $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC
ifeq ("$(wildcard $(RULESPATH)/rules.mk)","")
RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC
endif
# Define linker script file here
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/ld/$(MCU_LDSCRIPT).ld)","")
LDSCRIPT = $(KEYBOARD_PATH_5)/ld/$(MCU_LDSCRIPT).ld
else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/ld/$(MCU_LDSCRIPT).ld)","")
LDSCRIPT = $(KEYBOARD_PATH_4)/ld/$(MCU_LDSCRIPT).ld
else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/ld/$(MCU_LDSCRIPT).ld)","")
LDSCRIPT = $(KEYBOARD_PATH_3)/ld/$(MCU_LDSCRIPT).ld
else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/ld/$(MCU_LDSCRIPT).ld)","")
LDSCRIPT = $(KEYBOARD_PATH_2)/ld/$(MCU_LDSCRIPT).ld
else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/ld/$(MCU_LDSCRIPT).ld)","")
LDSCRIPT = $(KEYBOARD_PATH_1)/ld/$(MCU_LDSCRIPT).ld
else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/ld/$(MCU_LDSCRIPT).ld)","")
LDFLAGS += -L$(TOP_DIR)/platforms/chibios/boards/$(BOARD)/ld
LDSCRIPT = $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/ld/$(MCU_LDSCRIPT).ld
else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/common/ld/$(MCU_LDSCRIPT).ld)","")
LDSCRIPT = $(TOP_DIR)/platforms/chibios/boards/common/ld/$(MCU_LDSCRIPT).ld
else ifneq ("$(wildcard $(STARTUPLD_CONTRIB)/$(MCU_LDSCRIPT).ld)","")
LDSCRIPT = $(STARTUPLD_CONTRIB)/$(MCU_LDSCRIPT).ld
USE_CHIBIOS_CONTRIB = yes
else
LDSCRIPT = $(STARTUPLD)/$(MCU_LDSCRIPT).ld
endif
CHIBISRC = $(STARTUPSRC) \
$(KERNSRC) \
$(PORTSRC) \
$(OSALSRC) \
$(HALSRC) \
$(PLATFORMSRC) \
$(BOARDSRC) \
$(STREAMSSRC) \
$(CHIBIOS)/os/various/syscalls.c \
$(PLATFORM_COMMON_DIR)/syscall-fallbacks.c \
$(PLATFORM_COMMON_DIR)/wait.c
# Ensure the ASM files are not subjected to LTO -- it'll strip out interrupt handlers otherwise.
QUANTUM_LIB_SRC += $(STARTUPASM) $(PORTASM) $(OSALASM) $(PLATFORMASM)
CHIBISRC := $(patsubst $(TOP_DIR)/%,%,$(CHIBISRC))
EXTRAINCDIRS += $(CHIBIOS)/os/license $(CHIBIOS)/os/oslib/include \
$(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs \
$(TOP_DIR)/platforms/chibios/boards/common/configs \
$(HALCONFDIR) $(CHCONFDIR) \
$(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \
$(HALINC) $(PLATFORMINC) $(BOARDINC) $(TESTINC) \
$(STREAMSINC) $(CHIBIOS)/os/various $(COMMON_VPATH)
#
# ChibiOS-Contrib
##############################################################################
# Work out if we're using ChibiOS-Contrib by checking if halconf_community.h exists
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/halconf_community.h)","")
USE_CHIBIOS_CONTRIB = yes
else ifneq ("$(wildcard $(KEYBOARD_PATH_4)/halconf_community.h)","")
USE_CHIBIOS_CONTRIB = yes
else ifneq ("$(wildcard $(KEYBOARD_PATH_3)/halconf_community.h)","")
USE_CHIBIOS_CONTRIB = yes
else ifneq ("$(wildcard $(KEYBOARD_PATH_2)/halconf_community.h)","")
USE_CHIBIOS_CONTRIB = yes
else ifneq ("$(wildcard $(KEYBOARD_PATH_1)/halconf_community.h)","")
USE_CHIBIOS_CONTRIB = yes
else ifneq ("$(wildcard $(TOP_DIR)/platforms/chibios/boards/$(BOARD)/configs/halconf_community.h)","")
USE_CHIBIOS_CONTRIB = yes
endif
ifeq ($(strip $(USE_CHIBIOS_CONTRIB)),yes)
include $(CHIBIOS_CONTRIB)/os/hal/hal.mk
CHIBISRC += $(PLATFORMSRC_CONTRIB) $(HALSRC_CONTRIB)
EXTRAINCDIRS += $(PLATFORMINC_CONTRIB) $(HALINC_CONTRIB) $(CHIBIOS_CONTRIB)/os/various
endif
#
# Project, sources and paths
##############################################################################
##############################################################################
# Injected configs
#
ifneq ("$(wildcard $(BOARD_PATH)/configs/config.h)","")
CONFIG_H += $(BOARD_PATH)/configs/config.h
endif
ifneq ("$(wildcard $(BOARD_PATH)/configs/post_config.h)","")
POST_CONFIG_H += $(BOARD_PATH)/configs/post_config.h
endif
##############################################################################
# Compiler settings
#
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
THUMBFLAGS = -DTHUMB_PRESENT -mno-thumb-interwork -DTHUMB_NO_INTERWORKING -mthumb -DTHUMB
COMPILEFLAGS += -fomit-frame-pointer
COMPILEFLAGS += -falign-functions=16
COMPILEFLAGS += -ffunction-sections
COMPILEFLAGS += -fdata-sections
COMPILEFLAGS += -fno-common
COMPILEFLAGS += -fshort-wchar
COMPILEFLAGS += $(THUMBFLAGS)
# FPU options default (Cortex-M4 and Cortex-M7 single precision).
USE_FPU_OPT ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16 -fsingle-precision-constant
# FPU-related options
USE_FPU ?= no
ifneq ($(USE_FPU),no)
COMPILEFLAGS += $(USE_FPU_OPT)
OPT_DEFS += -DCORTEX_USE_FPU=TRUE
else
OPT_DEFS += -DCORTEX_USE_FPU=FALSE
endif
CFLAGS += $(COMPILEFLAGS)
ASFLAGS += $(THUMBFLAGS)
CXXFLAGS += $(COMPILEFLAGS)
CXXFLAGS += -fno-rtti
LDFLAGS +=-Wl,--gc-sections
LDFLAGS +=-Wl,--no-wchar-size-warning
LDFLAGS += -mno-thumb-interwork -mthumb
LDSYMBOLS =,--defsym=__process_stack_size__=$(USE_PROCESS_STACKSIZE)
LDSYMBOLS :=$(LDSYMBOLS),--defsym=__main_stack_size__=$(USE_EXCEPTIONS_STACKSIZE)
LDFLAGS += -Wl,--script=$(LDSCRIPT)$(LDSYMBOLS)
LDFLAGS += --specs=nano.specs
OPT_DEFS += -DPROTOCOL_CHIBIOS
# Workaround to stop ChibiOS from complaining about new GCC -- it's been fixed for 7/8/9 already
OPT_DEFS += -DPORT_IGNORE_GCC_VERSION_CHECK=1
MCUFLAGS = -mcpu=$(MCU)
DEBUG = gdb
# List any extra directories to look for libraries here.
EXTRALIBDIRS = $(RULESPATH)/ld
bin: $(BUILD_DIR)/$(TARGET).bin sizeafter
$(COPY) $(BUILD_DIR)/$(TARGET).bin $(TARGET).bin;

View file

@ -1,118 +0,0 @@
COMMON_DIR = common
PLATFORM_COMMON_DIR = $(COMMON_DIR)/$(PLATFORM_KEY)
TMK_COMMON_SRC += \
$(COMMON_DIR)/host.c \
$(COMMON_DIR)/report.c \
$(COMMON_DIR)/sync_timer.c \
$(COMMON_DIR)/usb_util.c \
$(PLATFORM_COMMON_DIR)/platform.c \
$(PLATFORM_COMMON_DIR)/suspend.c \
$(PLATFORM_COMMON_DIR)/timer.c \
$(PLATFORM_COMMON_DIR)/bootloader.c \
# Use platform provided print if it exists
-include $(TMK_PATH)/$(PLATFORM_COMMON_DIR)/printf.mk
SHARED_EP_ENABLE = no
MOUSE_SHARED_EP ?= yes
ifeq ($(strip $(KEYBOARD_SHARED_EP)), yes)
TMK_COMMON_DEFS += -DKEYBOARD_SHARED_EP
SHARED_EP_ENABLE = yes
# With the current usb_descriptor.c code,
# you can't share kbd without sharing mouse;
# that would be a very unexpected use case anyway
MOUSE_SHARED_EP = yes
endif
ifeq ($(strip $(MOUSE_ENABLE)), yes)
OPT_DEFS += -DMOUSE_ENABLE
ifeq ($(strip $(MOUSE_SHARED_EP)), yes)
TMK_COMMON_DEFS += -DMOUSE_SHARED_EP
SHARED_EP_ENABLE = yes
endif
endif
ifeq ($(strip $(EXTRAKEY_ENABLE)), yes)
TMK_COMMON_DEFS += -DEXTRAKEY_ENABLE
SHARED_EP_ENABLE = yes
endif
ifeq ($(strip $(RAW_ENABLE)), yes)
TMK_COMMON_DEFS += -DRAW_ENABLE
endif
ifeq ($(strip $(CONSOLE_ENABLE)), yes)
TMK_COMMON_DEFS += -DCONSOLE_ENABLE
else
# TODO: decouple this so other print backends can exist
TMK_COMMON_DEFS += -DNO_PRINT
TMK_COMMON_DEFS += -DNO_DEBUG
endif
ifeq ($(strip $(NKRO_ENABLE)), yes)
ifeq ($(PROTOCOL), VUSB)
$(info NKRO is not currently supported on V-USB, and has been disabled.)
else ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
$(info NKRO is not currently supported with Bluetooth, and has been disabled.)
else
TMK_COMMON_DEFS += -DNKRO_ENABLE
SHARED_EP_ENABLE = yes
endif
endif
ifeq ($(strip $(USB_6KRO_ENABLE)), yes)
TMK_COMMON_DEFS += -DUSB_6KRO_ENABLE
endif
ifeq ($(strip $(SLEEP_LED_ENABLE)), yes)
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/sleep_led.c
TMK_COMMON_DEFS += -DSLEEP_LED_ENABLE
TMK_COMMON_DEFS += -DNO_SUSPEND_POWER_DOWN
endif
ifeq ($(strip $(NO_SUSPEND_POWER_DOWN)), yes)
TMK_COMMON_DEFS += -DNO_SUSPEND_POWER_DOWN
endif
ifeq ($(strip $(SWAP_HANDS_ENABLE)), yes)
TMK_COMMON_DEFS += -DSWAP_HANDS_ENABLE
endif
ifeq ($(strip $(NO_USB_STARTUP_CHECK)), yes)
TMK_COMMON_DEFS += -DNO_USB_STARTUP_CHECK
endif
ifeq ($(strip $(DIGITIZER_SHARED_EP)), yes)
TMK_COMMON_DEFS += -DDIGITIZER_SHARED_EP
SHARED_EP_ENABLE = yes
endif
ifeq ($(strip $(DIGITIZER_ENABLE)), yes)
TMK_COMMON_DEFS += -DDIGITIZER_ENABLE
ifeq ($(strip $(SHARED_EP_ENABLE)), yes)
TMK_COMMON_DEFS += -DDIGITIZER_SHARED_EP
SHARED_EP_ENABLE = yes
endif
endif
ifeq ($(strip $(SHARED_EP_ENABLE)), yes)
TMK_COMMON_DEFS += -DSHARED_EP_ENABLE
endif
ifeq ($(strip $(LTO_ENABLE)), yes)
ifeq ($(PLATFORM),CHIBIOS)
$(info Enabling LTO on ChibiOS-targeting boards is known to have a high likelihood of failure.)
$(info If unsure, set LTO_ENABLE = no.)
endif
EXTRAFLAGS += -flto
TMK_COMMON_DEFS += -DLTO_ENABLE
TMK_COMMON_DEFS += -DLINK_TIME_OPTIMIZATON_ENABLE
else ifdef LINK_TIME_OPTIMIZATION_ENABLE
$(error The LINK_TIME_OPTIMIZATION_ENABLE flag has been renamed to LTO_ENABLE.)
endif
# Search Path
VPATH += $(TMK_PATH)/$(COMMON_DIR)
VPATH += $(TMK_PATH)/$(PLATFORM_COMMON_DIR)
VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)

View file

@ -1,19 +0,0 @@
/* Copyright 2021 Simon Arlott
*
* 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
// The platform is 32-bit, so prefer 32-bit timers to avoid overflow
#define FAST_TIMER_T_SIZE 32

View file

@ -1,22 +0,0 @@
/* 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 "clks.h"
#define wait_ms(ms) CLK_delay_ms(ms)
#define wait_us(us) CLK_delay_us(us)
#define waitInputPinDelay()

View file

@ -1,37 +0,0 @@
/* 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 "samd51j18a.h"
static __inline__ uint8_t __interrupt_disable__(void) {
__disable_irq();
return 1;
}
static __inline__ void __interrupt_enable__(const uint8_t *__s) {
__enable_irq();
__asm__ volatile("" ::: "memory");
(void)__s;
}
#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)

View file

@ -1,57 +0,0 @@
/* Copyright 2017 Fred Sundvik
*
* 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 "bootloader.h"
#include "samd51j18a.h"
#include "md_bootloader.h"
// Set watchdog timer to reset. Directs the bootloader to stay in programming mode.
void bootloader_jump(void) {
#ifdef KEYBOARD_massdrop_ctrl
// CTRL keyboards released with bootloader version below must use RAM method. Otherwise use WDT method.
uint8_t ver_ram_method[] = "v2.18Jun 22 2018 17:28:08"; // The version to match (NULL terminated by compiler)
uint8_t *ver_check = ver_ram_method; // Pointer to version match string for traversal
uint8_t *ver_rom = (uint8_t *)0x21A0; // Pointer to address in ROM where this specific bootloader version would exist
while (*ver_check && *ver_rom == *ver_check) { // While there are check version characters to match and bootloader's version matches check's version
ver_check++; // Move check version pointer to next character
ver_rom++; // Move ROM version pointer to next character
}
if (!*ver_check) { // If check version pointer is NULL, all characters have matched
*MAGIC_ADDR = BOOTLOADER_MAGIC; // Set magic number into RAM
NVIC_SystemReset(); // Perform system reset
while (1) {
} // Won't get here
}
#endif
WDT->CTRLA.bit.ENABLE = 0;
while (WDT->SYNCBUSY.bit.ENABLE) {
}
while (WDT->CTRLA.bit.ENABLE) {
}
WDT->CONFIG.bit.WINDOW = 0;
WDT->CONFIG.bit.PER = 0;
WDT->EWCTRL.bit.EWOFFSET = 0;
WDT->CTRLA.bit.ENABLE = 1;
while (WDT->SYNCBUSY.bit.ENABLE) {
}
while (!WDT->CTRLA.bit.ENABLE) {
}
while (1) {
} // Wait on timeout
}

View file

@ -1,98 +0,0 @@
/* Copyright 2017 Fred Sundvik
*
* 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 "eeprom.h"
#ifndef EEPROM_SIZE
# include "eeconfig.h"
# define EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4) // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO
#endif
__attribute__((aligned(4))) static uint8_t buffer[EEPROM_SIZE];
uint8_t eeprom_read_byte(const uint8_t *addr) {
uintptr_t offset = (uintptr_t)addr;
return buffer[offset];
}
void eeprom_write_byte(uint8_t *addr, uint8_t value) {
uintptr_t offset = (uintptr_t)addr;
buffer[offset] = value;
}
uint16_t eeprom_read_word(const uint16_t *addr) {
const uint8_t *p = (const uint8_t *)addr;
return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8);
}
uint32_t eeprom_read_dword(const uint32_t *addr) {
const uint8_t *p = (const uint8_t *)addr;
return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24);
}
void eeprom_read_block(void *buf, const void *addr, size_t len) {
const uint8_t *p = (const uint8_t *)addr;
uint8_t * dest = (uint8_t *)buf;
while (len--) {
*dest++ = eeprom_read_byte(p++);
}
}
void eeprom_write_word(uint16_t *addr, uint16_t value) {
uint8_t *p = (uint8_t *)addr;
eeprom_write_byte(p++, value);
eeprom_write_byte(p, value >> 8);
}
void eeprom_write_dword(uint32_t *addr, uint32_t value) {
uint8_t *p = (uint8_t *)addr;
eeprom_write_byte(p++, value);
eeprom_write_byte(p++, value >> 8);
eeprom_write_byte(p++, value >> 16);
eeprom_write_byte(p, value >> 24);
}
void eeprom_write_block(const void *buf, void *addr, size_t len) {
uint8_t * p = (uint8_t *)addr;
const uint8_t *src = (const uint8_t *)buf;
while (len--) {
eeprom_write_byte(p++, *src++);
}
}
void eeprom_update_byte(uint8_t *addr, uint8_t value) { eeprom_write_byte(addr, value); }
void eeprom_update_word(uint16_t *addr, uint16_t value) {
uint8_t *p = (uint8_t *)addr;
eeprom_write_byte(p++, value);
eeprom_write_byte(p, value >> 8);
}
void eeprom_update_dword(uint32_t *addr, uint32_t value) {
uint8_t *p = (uint8_t *)addr;
eeprom_write_byte(p++, value);
eeprom_write_byte(p++, value >> 8);
eeprom_write_byte(p++, value >> 16);
eeprom_write_byte(p, value >> 24);
}
void eeprom_update_block(const void *buf, void *addr, size_t len) {
uint8_t * p = (uint8_t *)addr;
const uint8_t *src = (const uint8_t *)buf;
while (len--) {
eeprom_write_byte(p++, *src++);
}
}

View file

@ -1,71 +0,0 @@
/* 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 "stdint.h"
#include "samd51j18a.h"
#include "pin_defs.h"
typedef uint8_t pin_t;
#define SAMD_PORT(pin) ((pin & 0x20) >> 5)
#define SAMD_PIN(pin) (pin & 0x1f)
#define SAMD_PIN_MASK(pin) (1 << (pin & 0x1f))
#define setPinInput(pin) \
do { \
PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.INEN = 1; \
PORT->Group[SAMD_PORT(pin)].DIRCLR.reg = SAMD_PIN_MASK(pin); \
} while (0)
#define setPinInputHigh(pin) \
do { \
PORT->Group[SAMD_PORT(pin)].DIRCLR.reg = SAMD_PIN_MASK(pin); \
PORT->Group[SAMD_PORT(pin)].OUTSET.reg = SAMD_PIN_MASK(pin); \
PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.INEN = 1; \
PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.PULLEN = 1; \
} while (0)
#define setPinInputLow(pin) \
do { \
PORT->Group[SAMD_PORT(pin)].DIRCLR.reg = SAMD_PIN_MASK(pin); \
PORT->Group[SAMD_PORT(pin)].OUTCLR.reg = SAMD_PIN_MASK(pin); \
PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.INEN = 1; \
PORT->Group[SAMD_PORT(pin)].PINCFG[SAMD_PIN(pin)].bit.PULLEN = 1; \
} while (0)
#define setPinOutput(pin) \
do { \
PORT->Group[SAMD_PORT(pin)].DIRSET.reg = SAMD_PIN_MASK(pin); \
PORT->Group[SAMD_PORT(pin)].OUTCLR.reg = SAMD_PIN_MASK(pin); \
} while (0)
#define writePinHigh(pin) \
do { \
PORT->Group[SAMD_PORT(pin)].OUTSET.reg = SAMD_PIN_MASK(pin); \
} while (0)
#define writePinLow(pin) \
do { \
PORT->Group[SAMD_PORT(pin)].OUTCLR.reg = SAMD_PIN_MASK(pin); \
} while (0)
#define writePin(pin, level) ((level) ? (writePinHigh(pin)) : (writePinLow(pin)))
#define readPin(pin) ((PORT->Group[SAMD_PORT(pin)].IN.reg & SAMD_PIN_MASK(pin)) != 0)
#define togglePin(pin) (PORT->Group[SAMD_PORT(pin)].OUTTGL.reg = SAMD_PIN_MASK(pin))

View file

@ -1,84 +0,0 @@
/* 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 "samd51j18a.h"
#define A00 PIN_PA00
#define A01 PIN_PA01
#define A02 PIN_PA02
#define A03 PIN_PA03
#define A04 PIN_PA04
#define A05 PIN_PA05
#define A06 PIN_PA06
#define A07 PIN_PA07
#define A08 PIN_PA08
#define A09 PIN_PA09
#define A10 PIN_PA10
#define A11 PIN_PA11
#define A12 PIN_PA12
#define A13 PIN_PA13
#define A14 PIN_PA14
#define A15 PIN_PA15
#define A16 PIN_PA16
#define A17 PIN_PA17
#define A18 PIN_PA18
#define A19 PIN_PA19
#define A20 PIN_PA20
#define A21 PIN_PA21
#define A22 PIN_PA22
#define A23 PIN_PA23
#define A24 PIN_PA24
#define A25 PIN_PA25
#define A26 PIN_PA26
#define A27 PIN_PA27
#define A28 PIN_PA28
#define A29 PIN_PA29
#define A30 PIN_PA30
#define A31 PIN_PA31
#define B00 PIN_PB00
#define B01 PIN_PB01
#define B02 PIN_PB02
#define B03 PIN_PB03
#define B04 PIN_PB04
#define B05 PIN_PB05
#define B06 PIN_PB06
#define B07 PIN_PB07
#define B08 PIN_PB08
#define B09 PIN_PB09
#define B10 PIN_PB10
#define B11 PIN_PB11
#define B12 PIN_PB12
#define B13 PIN_PB13
#define B14 PIN_PB14
#define B15 PIN_PB15
#define B16 PIN_PB16
#define B17 PIN_PB17
#define B18 PIN_PB18
#define B19 PIN_PB19
#define B20 PIN_PB20
#define B21 PIN_PB21
#define B22 PIN_PB22
#define B23 PIN_PB23
#define B24 PIN_PB24
#define B25 PIN_PB25
#define B26 PIN_PB26
#define B27 PIN_PB27
#define B28 PIN_PB28
#define B29 PIN_PB29
#define B30 PIN_PB30
#define B31 PIN_PB31

View file

@ -1,21 +0,0 @@
/* 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/>.
*/
#include "platform_deps.h"
void platform_setup(void) {
// do nothing
}

View file

@ -1,18 +0,0 @@
/* 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
// here just to please the build

View file

@ -1,77 +0,0 @@
#include "matrix.h"
#include "i2c_master.h"
#include "md_rgb_matrix.h"
#include "suspend.h"
/** \brief Suspend idle
*
* FIXME: needs doc
*/
void suspend_idle(uint8_t time) { /* Note: Not used anywhere currently */
}
/** \brief Run user 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) {
#ifdef RGB_MATRIX_ENABLE
I2C3733_Control_Set(0); // Disable LED driver
#endif
suspend_power_down_kb();
}
__attribute__((weak)) void matrix_power_up(void) {}
__attribute__((weak)) void matrix_power_down(void) {}
bool suspend_wakeup_condition(void) {
matrix_power_up();
matrix_scan();
matrix_power_down();
for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
if (matrix_get_row(r)) return true;
}
return false;
}
/** \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) {
#ifdef RGB_MATRIX_ENABLE
# ifdef USE_MASSDROP_CONFIGURATOR
if (led_enabled) {
I2C3733_Control_Set(1);
}
# else
I2C3733_Control_Set(1);
# endif
#endif
suspend_wakeup_init_kb();
}

View file

@ -1,19 +0,0 @@
#include "samd51j18a.h"
#include "timer.h"
#include "tmk_core/protocol/arm_atsam/clks.h"
void set_time(uint64_t tset) { ms_clk = tset; }
void timer_init(void) { timer_clear(); }
uint16_t timer_read(void) { return (uint16_t)ms_clk; }
uint32_t timer_read32(void) { return (uint32_t)ms_clk; }
uint64_t timer_read64(void) { return ms_clk; }
uint16_t timer_elapsed(uint16_t tlast) { return TIMER_DIFF_16(timer_read(), tlast); }
uint32_t timer_elapsed32(uint32_t tlast) { return TIMER_DIFF_32(timer_read32(), tlast); }
void timer_clear(void) { set_time(0); }

View file

@ -1,32 +0,0 @@
/* 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
// Macro to help make GPIO and other controls atomic.
#ifndef IGNORE_ATOMIC_BLOCK
# if __has_include_next("atomic_util.h")
# include_next "atomic_util.h" /* Include the platforms atomic.h */
# else
# define ATOMIC_BLOCK _Static_assert(0, "ATOMIC_BLOCK not implemented")
# define ATOMIC_BLOCK_RESTORESTATE _Static_assert(0, "ATOMIC_BLOCK_RESTORESTATE not implemented")
# define ATOMIC_BLOCK_FORCEON _Static_assert(0, "ATOMIC_BLOCK_FORCEON not implemented")
# endif
#else /* do nothing atomic macro */
# define ATOMIC_BLOCK for (uint8_t __ToDo = 1; __ToDo; __ToDo = 0)
# define ATOMIC_BLOCK_RESTORESTATE ATOMIC_BLOCK
# define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK
#endif

View file

@ -1,33 +0,0 @@
/* 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 "avr/xprintf.h"
// Create user & normal print defines
#define print(s) xputs(PSTR(s))
#define println(s) xputs(PSTR(s "\r\n"))
#define uprint(s) xputs(PSTR(s))
#define uprintln(s) xputs(PSTR(s "\r\n"))
#define uprintf(fmt, ...) __xprintf(PSTR(fmt), ##__VA_ARGS__)

View file

@ -1,19 +0,0 @@
/* Copyright 2021 Simon Arlott
*
* 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
// The platform is 8-bit, so prefer 16-bit timers to reduce code size
#define FAST_TIMER_T_SIZE 16

View file

@ -1,49 +0,0 @@
/* 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 <util/delay.h>
#define wait_ms(ms) \
do { \
if (__builtin_constant_p(ms)) { \
_delay_ms(ms); \
} else { \
for (uint16_t i = ms; i > 0; i--) { \
_delay_ms(1); \
} \
} \
} while (0)
#define wait_us(us) \
do { \
if (__builtin_constant_p(us)) { \
_delay_us(us); \
} else { \
for (uint16_t i = us; i > 0; i--) { \
_delay_us(1); \
} \
} \
} while (0)
#define wait_cpuclock(n) __builtin_avr_delay_cycles(n)
#define CPU_CLOCK F_CPU
/* The AVR series GPIOs have a one clock read delay for changes in the digital input signal.
* But here's more margin to make it two clocks. */
#ifndef GPIO_INPUT_PIN_DELAY
# define GPIO_INPUT_PIN_DELAY 2
#endif
#define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY)

View file

@ -1,22 +0,0 @@
/* 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
/* atomic macro for AVR */
#include <util/atomic.h>
#define ATOMIC_BLOCK_RESTORESTATE ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
#define ATOMIC_BLOCK_FORCEON ATOMIC_BLOCK(ATOMIC_FORCEON)

View file

@ -1,293 +0,0 @@
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <util/delay.h>
#include "bootloader.h"
#include <avr/boot.h>
#ifdef PROTOCOL_LUFA
# include <LUFA/Drivers/USB/USB.h>
#endif
/** \brief Bootloader Size in *bytes*
*
* AVR Boot section size are defined by setting BOOTSZ fuse in fact. Consult with your MCU datasheet.
* Note that 'Word'(2 bytes) size and address are used in datasheet while TMK uses 'Byte'.
*
* Size of Bootloaders in bytes:
* Atmel DFU loader(ATmega32U4) 4096
* Atmel DFU loader(AT90USB128) 8192
* LUFA bootloader(ATmega32U4) 4096
* Arduino Caterina(ATmega32U4) 4096
* USBaspLoader(ATmega***) 2048
* Teensy halfKay(ATmega32U4) 512
* Teensy++ halfKay(AT90USB128) 1024
*
* AVR Boot section is located at the end of Flash memory like the followings.
*
* byte Atmel/LUFA(ATMega32u4) byte Atmel(AT90SUB128)
* 0x0000 +---------------+ 0x00000 +---------------+
* | | | |
* | | | |
* | Application | | Application |
* | | | |
* = = = =
* | | 32KB-4KB | | 128KB-8KB
* 0x7000 +---------------+ 0x1E000 +---------------+
* | Bootloader | 4KB | Bootloader | 8KB
* 0x7FFF +---------------+ 0x1FFFF +---------------+
*
*
* byte Teensy(ATMega32u4) byte Teensy++(AT90SUB128)
* 0x0000 +---------------+ 0x00000 +---------------+
* | | | |
* | | | |
* | Application | | Application |
* | | | |
* = = = =
* | | 32KB-512B | | 128KB-1KB
* 0x7E00 +---------------+ 0x1FC00 +---------------+
* | Bootloader | 512B | Bootloader | 1KB
* 0x7FFF +---------------+ 0x1FFFF +---------------+
*/
#define FLASH_SIZE (FLASHEND + 1L)
#if !defined(BOOTLOADER_SIZE)
uint16_t bootloader_start;
#endif
// compatibility between ATMega8 and ATMega88
#if !defined(MCUCSR)
# if defined(MCUSR)
# define MCUCSR MCUSR
# endif
#endif
/** \brief Entering the Bootloader via Software
*
* http://www.fourwalledcubicle.com/files/LUFA/Doc/120730/html/_page__software_bootloader_start.html
*/
#define BOOTLOADER_RESET_KEY 0xB007B007
uint32_t reset_key __attribute__((section(".noinit,\"aw\",@nobits;")));
/** \brief initialize MCU status by watchdog reset
*
* FIXME: needs doc
*/
__attribute__((weak)) void bootloader_jump(void) {
#if !defined(BOOTLOADER_SIZE)
uint8_t high_fuse = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS);
if (high_fuse & ~(FUSE_BOOTSZ0 & FUSE_BOOTSZ1)) {
bootloader_start = (FLASH_SIZE - 512) >> 1;
} else if (high_fuse & ~(FUSE_BOOTSZ1)) {
bootloader_start = (FLASH_SIZE - 1024) >> 1;
} else if (high_fuse & ~(FUSE_BOOTSZ0)) {
bootloader_start = (FLASH_SIZE - 2048) >> 1;
} else {
bootloader_start = (FLASH_SIZE - 4096) >> 1;
}
#endif
// Something like this might work, but it compiled larger than the block above
// bootloader_start = FLASH_SIZE - (256 << (~high_fuse & 0b110 >> 1));
#if defined(BOOTLOADER_HALFKAY)
// http://www.pjrc.com/teensy/jump_to_bootloader.html
cli();
// disable watchdog, if enabled (it's not)
// disable all peripherals
// a shutdown call might make sense here
UDCON = 1;
USBCON = (1 << FRZCLK); // disable USB
UCSR1B = 0;
_delay_ms(5);
# if defined(__AVR_AT90USB162__) // Teensy 1.0
EIMSK = 0;
PCICR = 0;
SPCR = 0;
ACSR = 0;
EECR = 0;
TIMSK0 = 0;
TIMSK1 = 0;
UCSR1B = 0;
DDRB = 0;
DDRC = 0;
DDRD = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;
asm volatile("jmp 0x3E00");
# elif defined(__AVR_ATmega32U4__) // Teensy 2.0
EIMSK = 0;
PCICR = 0;
SPCR = 0;
ACSR = 0;
EECR = 0;
ADCSRA = 0;
TIMSK0 = 0;
TIMSK1 = 0;
TIMSK3 = 0;
TIMSK4 = 0;
UCSR1B = 0;
TWCR = 0;
DDRB = 0;
DDRC = 0;
DDRD = 0;
DDRE = 0;
DDRF = 0;
TWCR = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;
PORTE = 0;
PORTF = 0;
asm volatile("jmp 0x7E00");
# elif defined(__AVR_AT90USB646__) // Teensy++ 1.0
EIMSK = 0;
PCICR = 0;
SPCR = 0;
ACSR = 0;
EECR = 0;
ADCSRA = 0;
TIMSK0 = 0;
TIMSK1 = 0;
TIMSK2 = 0;
TIMSK3 = 0;
UCSR1B = 0;
TWCR = 0;
DDRA = 0;
DDRB = 0;
DDRC = 0;
DDRD = 0;
DDRE = 0;
DDRF = 0;
PORTA = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;
PORTE = 0;
PORTF = 0;
asm volatile("jmp 0xFC00");
# elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0
EIMSK = 0;
PCICR = 0;
SPCR = 0;
ACSR = 0;
EECR = 0;
ADCSRA = 0;
TIMSK0 = 0;
TIMSK1 = 0;
TIMSK2 = 0;
TIMSK3 = 0;
UCSR1B = 0;
TWCR = 0;
DDRA = 0;
DDRB = 0;
DDRC = 0;
DDRD = 0;
DDRE = 0;
DDRF = 0;
PORTA = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;
PORTE = 0;
PORTF = 0;
asm volatile("jmp 0x1FC00");
# endif
#elif defined(BOOTLOADER_CATERINA)
// this block may be optional
// TODO: figure it out
uint16_t *const bootKeyPtr = (uint16_t *)0x0800;
// Value used by Caterina bootloader use to determine whether to run the
// sketch or the bootloader programmer.
uint16_t bootKey = 0x7777;
*bootKeyPtr = bootKey;
// setup watchdog timeout
wdt_enable(WDTO_60MS);
while (1) {
} // wait for watchdog timer to trigger
#elif defined(BOOTLOADER_USBASP)
// Taken with permission of Stephan Baerwolf from https://github.com/tinyusbboard/API/blob/master/apipage.c
wdt_enable(WDTO_15MS);
wdt_reset();
asm volatile("cli \n\t"
"ldi r29 , %[ramendhi] \n\t"
"ldi r28 , %[ramendlo] \n\t"
# if (FLASHEND > 131071)
"ldi r18 , %[bootaddrhi] \n\t"
"st Y+, r18 \n\t"
# endif
"ldi r18 , %[bootaddrme] \n\t"
"st Y+, r18 \n\t"
"ldi r18 , %[bootaddrlo] \n\t"
"st Y+, r18 \n\t"
"out %[mcucsrio], __zero_reg__ \n\t"
"bootloader_startup_loop%=: \n\t"
"rjmp bootloader_startup_loop%= \n\t"
:
: [mcucsrio] "I"(_SFR_IO_ADDR(MCUCSR)),
# if (FLASHEND > 131071)
[ramendhi] "M"(((RAMEND - 2) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 2) >> 0) & 0xff), [bootaddrhi] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 16) & 0xff),
# else
[ramendhi] "M"(((RAMEND - 1) >> 8) & 0xff), [ramendlo] "M"(((RAMEND - 1) >> 0) & 0xff),
# endif
[bootaddrme] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 8) & 0xff), [bootaddrlo] "M"((((FLASH_SIZE - BOOTLOADER_SIZE) >> 1) >> 0) & 0xff));
#else // Assume remaining boards are DFU, even if the flag isn't set
# if !(defined(__AVR_ATmega32A__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATtiny85__)) // no USB - maybe BOOTLOADER_BOOTLOADHID instead though?
UDCON = 1;
USBCON = (1 << FRZCLK); // disable USB
UCSR1B = 0;
_delay_ms(5); // 5 seems to work fine
# endif
# ifdef BOOTLOADER_BOOTLOADHID
// force bootloadHID to stay in bootloader mode, so that it waits
// for a new firmware to be flashed
eeprom_write_byte((uint8_t *)1, 0x00);
# endif
// watchdog reset
reset_key = BOOTLOADER_RESET_KEY;
wdt_enable(WDTO_250MS);
for (;;)
;
#endif
}
/* this runs before main() */
void bootloader_jump_after_watchdog_reset(void) __attribute__((used, naked, section(".init3")));
void bootloader_jump_after_watchdog_reset(void) {
#ifndef BOOTLOADER_HALFKAY
if ((MCUCSR & (1 << WDRF)) && reset_key == BOOTLOADER_RESET_KEY) {
reset_key = 0;
// My custom USBasploader requires this to come up.
MCUCSR = 0;
// Seems like Teensy halfkay loader requires clearing WDRF and disabling watchdog.
MCUCSR &= ~(1 << WDRF);
wdt_disable();
// This is compled into 'icall', address should be in word unit, not byte.
# ifdef BOOTLOADER_SIZE
((void (*)(void))((FLASH_SIZE - BOOTLOADER_SIZE) >> 1))();
# else
asm("ijmp" ::"z"(bootloader_start));
# endif
}
#endif
}

View file

@ -1,21 +0,0 @@
// Copyright 2017 Jack Humbert
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <avr/io.h>
#include <avr/boot.h>
// clang-format off
// this is not valid C - it's for computing the size available on the chip
AVR_SIZE: FLASHEND + 1 - BOOTLOADER_SIZE

View file

@ -1,49 +0,0 @@
/* 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 <avr/io.h>
#include "pin_defs.h"
typedef uint8_t pin_t;
/* Operation of GPIO by pin. */
#define setPinInput(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF))
#define setPinInputHigh(pin) (DDRx_ADDRESS(pin) &= ~_BV((pin)&0xF), PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
#define setPinInputLow(pin) _Static_assert(0, "AVR processors cannot implement an input as pull low")
#define setPinOutput(pin) (DDRx_ADDRESS(pin) |= _BV((pin)&0xF))
#define writePinHigh(pin) (PORTx_ADDRESS(pin) |= _BV((pin)&0xF))
#define writePinLow(pin) (PORTx_ADDRESS(pin) &= ~_BV((pin)&0xF))
#define writePin(pin, level) ((level) ? writePinHigh(pin) : writePinLow(pin))
#define readPin(pin) ((bool)(PINx_ADDRESS(pin) & _BV((pin)&0xF)))
#define togglePin(pin) (PORTx_ADDRESS(pin) ^= _BV((pin)&0xF))
/* Operation of GPIO by port. */
typedef uint8_t port_data_t;
#define readPort(port) PINx_ADDRESS(port)
#define setPortBitInput(port, bit) (DDRx_ADDRESS(port) &= ~_BV((bit)&0xF), PORTx_ADDRESS(port) &= ~_BV((bit)&0xF))
#define setPortBitInputHigh(port, bit) (DDRx_ADDRESS(port) &= ~_BV((bit)&0xF), PORTx_ADDRESS(port) |= _BV((bit)&0xF))
#define setPortBitOutput(port, bit) (DDRx_ADDRESS(port) |= _BV((bit)&0xF))
#define writePortBitLow(port, bit) (PORTx_ADDRESS(port) &= ~_BV((bit)&0xF))
#define writePortBitHigh(port, bit) (PORTx_ADDRESS(port) |= _BV((bit)&0xF))

View file

@ -1,128 +0,0 @@
/* 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 <avr/io.h>
#define PORT_SHIFTER 4 // this may be 4 for all AVR chips
// If you want to add more to this list, reference the PINx definitions in these header
// files: https://github.com/vancegroup-mirrors/avr-libc/tree/master/avr-libc/include/avr
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__)
# define ADDRESS_BASE 0x00
# define PINB_ADDRESS 0x3
# define PINC_ADDRESS 0x6
# define PIND_ADDRESS 0x9
# define PINE_ADDRESS 0xC
# define PINF_ADDRESS 0xF
#elif defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
# define ADDRESS_BASE 0x00
# define PINB_ADDRESS 0x3
# define PINC_ADDRESS 0x6
# define PIND_ADDRESS 0x9
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
# define ADDRESS_BASE 0x00
# define PINA_ADDRESS 0x0
# define PINB_ADDRESS 0x3
# define PINC_ADDRESS 0x6
# define PIND_ADDRESS 0x9
# define PINE_ADDRESS 0xC
# define PINF_ADDRESS 0xF
#elif defined(__AVR_ATmega32A__)
# define ADDRESS_BASE 0x10
# define PIND_ADDRESS 0x0
# define PINC_ADDRESS 0x3
# define PINB_ADDRESS 0x6
# define PINA_ADDRESS 0x9
#elif defined(__AVR_ATtiny85__)
# define ADDRESS_BASE 0x10
# define PINB_ADDRESS 0x6
#else
# error "Pins are not defined"
#endif
#define PINDEF(port, pin) ((PIN##port##_ADDRESS << PORT_SHIFTER) | pin)
#define _PIN_ADDRESS(p, offset) _SFR_IO8(ADDRESS_BASE + ((p) >> PORT_SHIFTER) + (offset))
// Port X Input Pins Address
#define PINx_ADDRESS(p) _PIN_ADDRESS(p, 0)
// Port X Data Direction Register, 0:input 1:output
#define DDRx_ADDRESS(p) _PIN_ADDRESS(p, 1)
// Port X Data Register
#define PORTx_ADDRESS(p) _PIN_ADDRESS(p, 2)
/* I/O pins */
#ifdef PORTA
# define A0 PINDEF(A, 0)
# define A1 PINDEF(A, 1)
# define A2 PINDEF(A, 2)
# define A3 PINDEF(A, 3)
# define A4 PINDEF(A, 4)
# define A5 PINDEF(A, 5)
# define A6 PINDEF(A, 6)
# define A7 PINDEF(A, 7)
#endif
#ifdef PORTB
# define B0 PINDEF(B, 0)
# define B1 PINDEF(B, 1)
# define B2 PINDEF(B, 2)
# define B3 PINDEF(B, 3)
# define B4 PINDEF(B, 4)
# define B5 PINDEF(B, 5)
# define B6 PINDEF(B, 6)
# define B7 PINDEF(B, 7)
#endif
#ifdef PORTC
# define C0 PINDEF(C, 0)
# define C1 PINDEF(C, 1)
# define C2 PINDEF(C, 2)
# define C3 PINDEF(C, 3)
# define C4 PINDEF(C, 4)
# define C5 PINDEF(C, 5)
# define C6 PINDEF(C, 6)
# define C7 PINDEF(C, 7)
#endif
#ifdef PORTD
# define D0 PINDEF(D, 0)
# define D1 PINDEF(D, 1)
# define D2 PINDEF(D, 2)
# define D3 PINDEF(D, 3)
# define D4 PINDEF(D, 4)
# define D5 PINDEF(D, 5)
# define D6 PINDEF(D, 6)
# define D7 PINDEF(D, 7)
#endif
#ifdef PORTE
# define E0 PINDEF(E, 0)
# define E1 PINDEF(E, 1)
# define E2 PINDEF(E, 2)
# define E3 PINDEF(E, 3)
# define E4 PINDEF(E, 4)
# define E5 PINDEF(E, 5)
# define E6 PINDEF(E, 6)
# define E7 PINDEF(E, 7)
#endif
#ifdef PORTF
# define F0 PINDEF(F, 0)
# define F1 PINDEF(F, 1)
# define F2 PINDEF(F, 2)
# define F3 PINDEF(F, 3)
# define F4 PINDEF(F, 4)
# define F5 PINDEF(F, 5)
# define F6 PINDEF(F, 6)
# define F7 PINDEF(F, 7)
#endif

View file

@ -1,21 +0,0 @@
/* 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/>.
*/
#include "platform_deps.h"
void platform_setup(void) {
// do nothing
}

View file

@ -1,20 +0,0 @@
/* 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 <avr/pgmspace.h>
#include <avr/io.h>
#include <avr/interrupt.h>

View file

@ -1,20 +0,0 @@
/*
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 "xprintf.h"
#include "sendchar.h"
void print_set_sendchar(sendchar_func_t func) { xdev_out(func); }

View file

@ -1,2 +0,0 @@
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/xprintf.S
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/printf.c

View file

@ -1,124 +0,0 @@
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "led.h"
#include "sleep_led.h"
#ifndef SLEEP_LED_TIMER
# define SLEEP_LED_TIMER 1
#endif
#if SLEEP_LED_TIMER == 1
# define TCCRxB TCCR1B
# define TIMERx_COMPA_vect TIMER1_COMPA_vect
# if defined(__AVR_ATmega32A__) // This MCU has only one TIMSK register
# define TIMSKx TIMSK
# else
# define TIMSKx TIMSK1
# endif
# define OCIExA OCIE1A
# define OCRxx OCR1A
#elif SLEEP_LED_TIMER == 3
# define TCCRxB TCCR3B
# define TIMERx_COMPA_vect TIMER3_COMPA_vect
# define TIMSKx TIMSK3
# define OCIExA OCIE3A
# define OCRxx OCR3A
#else
error("Invalid SLEEP_LED_TIMER config")
#endif
/* Software PWM
* ______ ______ __
* | ON |___OFF___| ON |___OFF___| ....
* |<-------------->|<-------------->|<- ....
* PWM period PWM period
*
* 256 interrupts/period[resolution]
* 64 periods/second[frequency]
* 256*64 interrupts/second
* F_CPU/(256*64) clocks/interrupt
*/
#define SLEEP_LED_TIMER_TOP F_CPU / (256 * 64)
/** \brief Sleep LED initialization
*
* FIXME: needs doc
*/
void sleep_led_init(void) {
/* Timer1 setup */
/* CTC mode */
TCCRxB |= _BV(WGM12);
/* Clock selelct: clk/1 */
TCCRxB |= _BV(CS10);
/* Set TOP value */
uint8_t sreg = SREG;
cli();
OCRxx = SLEEP_LED_TIMER_TOP;
SREG = sreg;
}
/** \brief Sleep LED enable
*
* FIXME: needs doc
*/
void sleep_led_enable(void) {
/* Enable Compare Match Interrupt */
TIMSKx |= _BV(OCIExA);
}
/** \brief Sleep LED disable
*
* FIXME: needs doc
*/
void sleep_led_disable(void) {
/* Disable Compare Match Interrupt */
TIMSKx &= ~_BV(OCIExA);
}
/** \brief Sleep LED toggle
*
* FIXME: needs doc
*/
void sleep_led_toggle(void) {
/* Disable Compare Match Interrupt */
TIMSKx ^= _BV(OCIExA);
}
/** \brief Breathing Sleep LED brighness(PWM On period) table
*
* (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
*
* https://www.wolframalpha.com/input/?i=sin%28x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
* (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
*/
static const uint8_t breathing_table[64] PROGMEM = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
ISR(TIMERx_COMPA_vect) {
/* Software PWM
* timer:1111 1111 1111 1111
* \_____/\/ \_______/____ count(0-255)
* \ \______________ duration of step(4)
* \__________________ index of step table(0-63)
*/
static union {
uint16_t row;
struct {
uint8_t count : 8;
uint8_t duration : 2;
uint8_t index : 6;
} pwm;
} timer = {.row = 0};
timer.row++;
// LED on
if (timer.pwm.count == 0) {
led_set(1 << USB_LED_CAPS_LOCK);
}
// LED off
if (timer.pwm.count == pgm_read_byte(&breathing_table[timer.pwm.index])) {
led_set(0);
}
}

View file

@ -1,152 +0,0 @@
#include <stdbool.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include "matrix.h"
#include "action.h"
#include "suspend.h"
#include "timer.h"
#include "led.h"
#include "host.h"
#ifdef PROTOCOL_LUFA
# include "lufa.h"
#endif
#ifdef PROTOCOL_VUSB
# include "vusb.h"
#endif
/** \brief Suspend idle
*
* FIXME: needs doc
*/
void suspend_idle(uint8_t time) {
cli();
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
}
// TODO: This needs some cleanup
#if !defined(NO_SUSPEND_POWER_DOWN) && defined(WDT_vect)
// clang-format off
#define wdt_intr_enable(value) \
__asm__ __volatile__ ( \
"in __tmp_reg__,__SREG__" "\n\t" \
"cli" "\n\t" \
"wdr" "\n\t" \
"sts %0,%1" "\n\t" \
"out __SREG__,__tmp_reg__" "\n\t" \
"sts %0,%2" "\n\t" \
: /* no outputs */ \
: "M" (_SFR_MEM_ADDR(_WD_CONTROL_REG)), \
"r" (_BV(_WD_CHANGE_BIT) | _BV(WDE)), \
"r" ((uint8_t) ((value & 0x08 ? _WD_PS3_MASK : 0x00) | _BV(WDIE) | (value & 0x07))) \
: "r0" \
)
// clang-format on
/** \brief Power down MCU with watchdog timer
*
* wdto: watchdog timer timeout defined in <avr/wdt.h>
* WDTO_15MS
* WDTO_30MS
* WDTO_60MS
* WDTO_120MS
* WDTO_250MS
* WDTO_500MS
* WDTO_1S
* WDTO_2S
* WDTO_4S
* WDTO_8S
*/
static uint8_t wdt_timeout = 0;
/** \brief Power down
*
* FIXME: needs doc
*/
static void power_down(uint8_t wdto) {
wdt_timeout = wdto;
// Watchdog Interrupt Mode
wdt_intr_enable(wdto);
// TODO: more power saving
// See PicoPower application note
// - I/O port input with pullup
// - prescale clock
// - BOD disable
// - Power Reduction Register PRR
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sei();
sleep_cpu();
sleep_disable();
// Disable watchdog after sleep
wdt_disable();
}
#endif
/** \brief Suspend power down
*
* FIXME: needs doc
*/
void suspend_power_down(void) {
#ifdef PROTOCOL_LUFA
if (USB_DeviceState == DEVICE_STATE_Configured) return;
#endif
#ifdef PROTOCOL_VUSB
if (!vusb_suspended) return;
#endif
suspend_power_down_quantum();
#ifndef NO_SUSPEND_POWER_DOWN
// 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) {}
bool suspend_wakeup_condition(void) {
matrix_power_up();
matrix_scan();
matrix_power_down();
for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
if (matrix_get_row(r)) return true;
}
return false;
}
/** \brief run immediately after wakeup
*
* FIXME: needs doc
*/
void suspend_wakeup_init(void) {
// clear keyboard state
clear_keyboard();
suspend_wakeup_init_quantum();
}
#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

View file

@ -1,133 +0,0 @@
/*
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 <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#include <stdint.h>
#include "timer_avr.h"
#include "timer.h"
// counter resolution 1ms
// NOTE: union { uint32_t timer32; struct { uint16_t dummy; uint16_t timer16; }}
volatile uint32_t timer_count;
/** \brief timer initialization
*
* FIXME: needs doc
*/
void timer_init(void) {
#if TIMER_PRESCALER == 1
uint8_t prescaler = _BV(CS00);
#elif TIMER_PRESCALER == 8
uint8_t prescaler = _BV(CS01);
#elif TIMER_PRESCALER == 64
uint8_t prescaler = _BV(CS00) | _BV(CS01);
#elif TIMER_PRESCALER == 256
uint8_t prescaler = _BV(CS02);
#elif TIMER_PRESCALER == 1024
uint8_t prescaler = _BV(CS00) | _BV(CS02);
#else
# error "Timer prescaler value is not valid"
#endif
#if defined(__AVR_ATmega32A__)
// Timer0 CTC mode
TCCR0 = _BV(WGM01) | prescaler;
OCR0 = TIMER_RAW_TOP;
TIMSK = _BV(OCIE0);
#elif defined(__AVR_ATtiny85__)
// Timer0 CTC mode
TCCR0A = _BV(WGM01);
TCCR0B = prescaler;
OCR0A = TIMER_RAW_TOP;
TIMSK = _BV(OCIE0A);
#else
// Timer0 CTC mode
TCCR0A = _BV(WGM01);
TCCR0B = prescaler;
OCR0A = TIMER_RAW_TOP;
TIMSK0 = _BV(OCIE0A);
#endif
}
/** \brief timer clear
*
* FIXME: needs doc
*/
inline void timer_clear(void) {
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { timer_count = 0; }
}
/** \brief timer read
*
* FIXME: needs doc
*/
inline uint16_t timer_read(void) {
uint32_t t;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
return (t & 0xFFFF);
}
/** \brief timer read32
*
* FIXME: needs doc
*/
inline uint32_t timer_read32(void) {
uint32_t t;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
return t;
}
/** \brief timer elapsed
*
* FIXME: needs doc
*/
inline uint16_t timer_elapsed(uint16_t last) {
uint32_t t;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
return TIMER_DIFF_16((t & 0xFFFF), last);
}
/** \brief timer elapsed32
*
* FIXME: needs doc
*/
inline uint32_t timer_elapsed32(uint32_t last) {
uint32_t t;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { t = timer_count; }
return TIMER_DIFF_32(t, last);
}
// excecuted once per 1ms.(excess for just timer count?)
#ifndef __AVR_ATmega32A__
# define TIMER_INTERRUPT_VECTOR TIMER0_COMPA_vect
#else
# define TIMER_INTERRUPT_VECTOR TIMER0_COMP_vect
#endif
ISR(TIMER_INTERRUPT_VECTOR, ISR_NOBLOCK) { timer_count++; }

View file

@ -1,39 +0,0 @@
/*
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/>.
*/
#pragma once
#include <stdint.h>
#ifndef TIMER_PRESCALER
# if F_CPU > 16000000
# define TIMER_PRESCALER 256
# elif F_CPU > 2000000
# define TIMER_PRESCALER 64
# elif F_CPU > 250000
# define TIMER_PRESCALER 8
# else
# define TIMER_PRESCALER 1
# endif
#endif
#define TIMER_RAW_FREQ (F_CPU / TIMER_PRESCALER)
#define TIMER_RAW TCNT0
#define TIMER_RAW_TOP (TIMER_RAW_FREQ / 1000)
#if (TIMER_RAW_TOP > 255)
# error "Timer0 can't count 1ms at this clock freq. Use larger prescaler."
#endif

View file

@ -1,498 +0,0 @@
;---------------------------------------------------------------------------;
; Extended itoa, puts, printf and atoi (C)ChaN, 2011
;---------------------------------------------------------------------------;
// Base size is 152 bytes
#define CR_CRLF 0 // Convert \n to \r\n (+10 bytes)
#define USE_XPRINTF 1 // Enable xprintf function (+194 bytes)
#define USE_XSPRINTF 0 // Add xsprintf function (+78 bytes)
#define USE_XFPRINTF 0 // Add xfprintf function (+54 bytes)
#define USE_XATOI 0 // Enable xatoi function (+182 bytes)
#if FLASHEND > 0x1FFFF
#error xitoa module does not support 256K devices
#endif
.nolist
#include <avr/io.h> // Include device specific definitions.
.list
#ifdef SPM_PAGESIZE // Recent devices have "lpm Rd,Z+" and "movw".
.macro _LPMI reg
lpm \reg, Z+
.endm
.macro _MOVW dh,dl, sh,sl
movw \dl, \sl
.endm
#else // Earlier devices do not have "lpm Rd,Z+" nor "movw".
.macro _LPMI reg
lpm
mov \reg, r0
adiw ZL, 1
.endm
.macro _MOVW dh,dl, sh,sl
mov \dl, \sl
mov \dh, \sh
.endm
#endif
;---------------------------------------------------------------------------
; Stub function to forward to user output function
;
;Prototype: void xputc (char chr // a character to be output
; );
;Size: 12/12 words
.section .bss
.global xfunc_out ; xfunc_out must be initialized before using this module.
xfunc_out: .ds.w 1
.section .text
.func xputc
.global xputc
xputc:
#if CR_CRLF
cpi r24, 10 ;LF --> CRLF
brne 1f ;
ldi r24, 13 ;
rcall 1f ;
ldi r24, 10 ;/
1:
#endif
push ZH
push ZL
lds ZL, xfunc_out+0 ;Pointer to the registered output function.
lds ZH, xfunc_out+1 ;/
sbiw ZL, 0 ;Skip if null
breq 2f ;/
icall
2: pop ZL
pop ZH
ret
.endfunc
;---------------------------------------------------------------------------
; Direct ROM string output
;
;Prototype: void xputs (const char *str_p // rom string to be output
; );
.func xputs
.global xputs
xputs:
_MOVW ZH,ZL, r25,r24 ; Z = pointer to rom string
1: _LPMI r24
cpi r24, 0
breq 2f
rcall xputc
rjmp 1b
2: ret
.endfunc
;---------------------------------------------------------------------------
; Extended direct numeral string output (32bit version)
;
;Prototype: void xitoa (long value, // value to be output
; char radix, // radix
; char width); // minimum width
;
.func xitoa
.global xitoa
xitoa:
;r25:r22 = value, r20 = base, r18 = digits
clr r31 ;r31 = stack level
ldi r30, ' ' ;r30 = sign
ldi r19, ' ' ;r19 = filler
sbrs r20, 7 ;When base indicates signd format and the value
rjmp 0f ;is minus, add a '-'.
neg r20 ;
sbrs r25, 7 ;
rjmp 0f ;
ldi r30, '-' ;
com r22 ;
com r23 ;
com r24 ;
com r25 ;
adc r22, r1 ;
adc r23, r1 ;
adc r24, r1 ;
adc r25, r1 ;/
0: sbrs r18, 7 ;When digits indicates zero filled,
rjmp 1f ;filler is '0'.
neg r18 ;
ldi r19, '0' ;/
;----- string conversion loop
1: ldi r21, 32 ;r26 = r25:r22 % r20
clr r26 ;r25:r22 /= r20
2: lsl r22 ;
rol r23 ;
rol r24 ;
rol r25 ;
rol r26 ;
cp r26, r20 ;
brcs 3f ;
sub r26, r20 ;
inc r22 ;
3: dec r21 ;
brne 2b ;/
cpi r26, 10 ;r26 is a numeral digit '0'-'F'
brcs 4f ;
subi r26, -7 ;
4: subi r26, -'0' ;/
push r26 ;Stack it
inc r31 ;/
cp r22, r1 ;Repeat until r25:r22 gets zero
cpc r23, r1 ;
cpc r24, r1 ;
cpc r25, r1 ;
brne 1b ;/
cpi r30, '-' ;Minus sign if needed
brne 5f ;
push r30 ;
inc r31 ;/
5: cp r31, r18 ;Filler
brcc 6f ;
push r19 ;
inc r31 ;
rjmp 5b ;/
6: pop r24 ;Flush stacked digits and exit
rcall xputc ;
dec r31 ;
brne 6b ;/
ret
.endfunc
;---------------------------------------------------------------------------;
; Formatted string output (16/32bit version)
;
;Prototype:
; void __xprintf (const char *format_p, ...);
; void __xsprintf(char*, const char *format_p, ...);
; void __xfprintf(void(*func)(char), const char *format_p, ...);
;
#if USE_XPRINTF
.func xvprintf
xvprintf:
ld ZL, Y+ ;Z = pointer to format string
ld ZH, Y+ ;/
0: _LPMI r24 ;Get a format char
cpi r24, 0 ;End of format string?
breq 90f ;/
cpi r24, '%' ;Is format?
breq 20f ;/
1: rcall xputc ;Put a normal character
rjmp 0b ;/
90: ret
20: ldi r18, 0 ;r18: digits
clt ;T: filler
_LPMI r21 ;Get flags
cpi r21, '%' ;Is a %?
breq 1b ;/
cpi r21, '0' ;Zero filled?
brne 23f ;
set ;/
22: _LPMI r21 ;Get width
23: cpi r21, '9'+1 ;
brcc 24f ;
subi r21, '0' ;
brcs 90b ;
lsl r18 ;
mov r0, r18 ;
lsl r18 ;
lsl r18 ;
add r18, r0 ;
add r18, r21 ;
rjmp 22b ;/
24: brtc 25f ;get value (low word)
neg r18 ;
25: ld r24, Y+ ;
ld r25, Y+ ;/
cpi r21, 'c' ;Is type character?
breq 1b ;/
cpi r21, 's' ;Is type RAM string?
breq 50f ;/
cpi r21, 'S' ;Is type ROM string?
breq 60f ;/
_MOVW r23,r22,r25,r24 ;r25:r22 = value
clr r24 ;
clr r25 ;
clt ;/
cpi r21, 'l' ;Is long int?
brne 26f ;
ld r24, Y+ ;get value (high word)
ld r25, Y+ ;
set ;
_LPMI r21 ;/
26: cpi r21, 'd' ;Is type signed decimal?
brne 27f ;/
ldi r20, -10 ;
brts 40f ;
sbrs r23, 7 ;
rjmp 40f ;
ldi r24, -1 ;
ldi r25, -1 ;
rjmp 40f ;/
27: cpi r21, 'u' ;Is type unsigned decimal?
ldi r20, 10 ;
breq 40f ;/
cpi r21, 'X' ;Is type hexdecimal?
ldi r20, 16 ;
breq 40f ;/
cpi r21, 'b' ;Is type binary?
ldi r20, 2 ;
breq 40f ;/
ret ;abort
40: push ZH ;Output the value
push ZL ;
rcall xitoa ;
42: pop ZL ;
pop ZH ;
rjmp 0b ;/
50: push ZH ;Put a string on the RAM
push ZL
_MOVW ZH,ZL, r25,r24
51: ld r24, Z+
cpi r24, 0
breq 42b
rcall xputc
rjmp 51b
60: push ZH ;Put a string on the ROM
push ZL
rcall xputs
rjmp 42b
.endfunc
.func __xprintf
.global __xprintf
__xprintf:
push YH
push YL
in YL, _SFR_IO_ADDR(SPL)
#ifdef SPH
in YH, _SFR_IO_ADDR(SPH)
#else
clr YH
#endif
adiw YL, 5 ;Y = pointer to arguments
rcall xvprintf
pop YL
pop YH
ret
.endfunc
#if USE_XSPRINTF
.func __xsprintf
putram:
_MOVW ZH,ZL, r15,r14
st Z+, r24
_MOVW r15,r14, ZH,ZL
ret
.global __xsprintf
__xsprintf:
push YH
push YL
in YL, _SFR_IO_ADDR(SPL)
#ifdef SPH
in YH, _SFR_IO_ADDR(SPH)
#else
clr YH
#endif
adiw YL, 5 ;Y = pointer to arguments
lds ZL, xfunc_out+0 ;Save registered output function
lds ZH, xfunc_out+1 ;
push ZL ;
push ZH ;/
ldi ZL, lo8(pm(putram));Set local output function
ldi ZH, hi8(pm(putram));
sts xfunc_out+0, ZL ;
sts xfunc_out+1, ZH ;/
push r15 ;Initialize pointer to string buffer
push r14 ;
ld r14, Y+ ;
ld r15, Y+ ;/
rcall xvprintf
_MOVW ZH,ZL, r15,r14 ;Terminate string
st Z, r1 ;
pop r14 ;
pop r15 ;/
pop ZH ;Restore registered output function
pop ZL ;
sts xfunc_out+0, ZL ;
sts xfunc_out+1, ZH ;/
pop YL
pop YH
ret
.endfunc
#endif
#if USE_XFPRINTF
.func __xfprintf
.global __xfprintf
__xfprintf:
push YH
push YL
in YL, _SFR_IO_ADDR(SPL)
#ifdef SPH
in YH, _SFR_IO_ADDR(SPH)
#else
clr YH
#endif
adiw YL, 5 ;Y = pointer to arguments
lds ZL, xfunc_out+0 ;Save registered output function
lds ZH, xfunc_out+1 ;
push ZL ;
push ZH ;/
ld ZL, Y+ ;Set output function
ld ZH, Y+ ;
sts xfunc_out+0, ZL ;
sts xfunc_out+1, ZH ;/
rcall xvprintf
pop ZH ;Restore registered output function
pop ZL ;
sts xfunc_out+0, ZL ;
sts xfunc_out+1, ZH ;/
pop YL
pop YH
ret
.endfunc
#endif
#endif
;---------------------------------------------------------------------------
; Extended numeral string input
;
;Prototype:
; char xatoi ( /* 1: Successful, 0: Failed */
; const char **str, /* pointer to pointer to source string */
; long *res /* result */
; );
;
#if USE_XATOI
.func xatoi
.global xatoi
xatoi:
_MOVW r1, r0, r23, r22
_MOVW XH, XL, r25, r24
ld ZL, X+
ld ZH, X+
clr r18 ;r21:r18 = 0;
clr r19 ;
clr r20 ;
clr r21 ;/
clt ;T = 0;
ldi r25, 10 ;r25 = 10;
rjmp 41f ;/
40: adiw ZL, 1 ;Z++;
41: ld r22, Z ;r22 = *Z;
cpi r22, ' ' ;if(r22 == ' ') continue
breq 40b ;/
brcs 70f ;if(r22 < ' ') error;
cpi r22, '-' ;if(r22 == '-') {
brne 42f ; T = 1;
set ; continue;
rjmp 40b ;}
42: cpi r22, '9'+1 ;if(r22 > '9') error;
brcc 70f ;/
cpi r22, '0' ;if(r22 < '0') error;
brcs 70f ;/
brne 51f ;if(r22 > '0') cv_start;
ldi r25, 8 ;r25 = 8;
adiw ZL, 1 ;r22 = *(++Z);
ld r22, Z ;/
cpi r22, ' '+1 ;if(r22 <= ' ') exit;
brcs 80f ;/
cpi r22, 'b' ;if(r22 == 'b') {
brne 43f ; r25 = 2;
ldi r25, 2 ; cv_start;
rjmp 50f ;}
43: cpi r22, 'x' ;if(r22 != 'x') error;
brne 51f ;/
ldi r25, 16 ;r25 = 16;
50: adiw ZL, 1 ;Z++;
ld r22, Z ;r22 = *Z;
51: cpi r22, ' '+1 ;if(r22 <= ' ') break;
brcs 80f ;/
cpi r22, 'a' ;if(r22 >= 'a') r22 =- 0x20;
brcs 52f ;
subi r22, 0x20 ;/
52: subi r22, '0' ;if((r22 -= '0') < 0) error;
brcs 70f ;/
cpi r22, 10 ;if(r22 >= 10) {
brcs 53f ; r22 -= 7;
subi r22, 7 ; if(r22 < 10)
cpi r22, 10 ;
brcs 70f ;}
53: cp r22, r25 ;if(r22 >= r25) error;
brcc 70f ;/
60: ldi r24, 33 ;r21:r18 *= r25;
sub r23, r23 ;
61: brcc 62f ;
add r23, r25 ;
62: lsr r23 ;
ror r21 ;
ror r20 ;
ror r19 ;
ror r18 ;
dec r24 ;
brne 61b ;/
add r18, r22 ;r21:r18 += r22;
adc r19, r24 ;
adc r20, r24 ;
adc r21, r24 ;/
rjmp 50b ;repeat
70: ldi r24, 0
rjmp 81f
80: ldi r24, 1
81: brtc 82f
clr r22
com r18
com r19
com r20
com r21
adc r18, r22
adc r19, r22
adc r20, r22
adc r21, r22
82: st -X, ZH
st -X, ZL
_MOVW XH, XL, r1, r0
st X+, r18
st X+, r19
st X+, r20
st X+, r21
clr r1
ret
.endfunc
#endif

View file

@ -1,103 +0,0 @@
/*---------------------------------------------------------------------------
Extended itoa, puts and printf (C)ChaN, 2011
-----------------------------------------------------------------------------*/
#pragma once
#include <inttypes.h>
#include <avr/pgmspace.h>
#ifdef __cplusplus
extern "C" {
#endif
extern void (*xfunc_out)(uint8_t);
#define xdev_out(func) xfunc_out = (void (*)(uint8_t))(func)
/* This is a pointer to user defined output function. It must be initialized
before using this modle.
*/
void xputc(char chr);
/* This is a stub function to forward outputs to user defined output function.
All outputs from this module are output via this function.
*/
/*-----------------------------------------------------------------------------*/
void xputs(const char *string_p);
/* The string placed in the ROM is forwarded to xputc() directly.
*/
/*-----------------------------------------------------------------------------*/
void xitoa(long value, char radix, char width);
/* Extended itoa().
value radix width output
100 10 6 " 100"
100 10 -6 "000100"
100 10 0 "100"
4294967295 10 0 "4294967295"
4294967295 -10 0 "-1"
655360 16 -8 "000A0000"
1024 16 0 "400"
0x55 2 -8 "01010101"
*/
/*-----------------------------------------------------------------------------*/
#define xprintf(format, ...) __xprintf(PSTR(format), ##__VA_ARGS__)
#define xsprintf(str, format, ...) __xsprintf(str, PSTR(format), ##__VA_ARGS__)
#define xfprintf(func, format, ...) __xfprintf(func, PSTR(format), ##__VA_ARGS__)
void __xprintf(const char *format_p, ...); /* Send formatted string to the registered device */
// void __xsprintf(char*, const char *format_p, ...); /* Put formatted string to the memory */
// void __xfprintf(void(*func)(uint8_t), const char *format_p, ...); /* Send formatted string to the specified device */
/* Format string is placed in the ROM. The format flags is similar to printf().
%[flag][width][size]type
flag
A '0' means filled with '0' when output is shorter than width.
' ' is used in default. This is effective only numeral type.
width
Minimum width in decimal number. This is effective only numeral type.
Default width is zero.
size
A 'l' means the argument is long(32bit). Default is short(16bit).
This is effective only numeral type.
type
'c' : Character, argument is the value
's' : String placed on the RAM, argument is the pointer
'S' : String placed on the ROM, argument is the pointer
'd' : Signed decimal, argument is the value
'u' : Unsigned decimal, argument is the value
'X' : Hexdecimal, argument is the value
'b' : Binary, argument is the value
'%' : '%'
*/
/*-----------------------------------------------------------------------------*/
char xatoi(char **str, long *ret);
/* Get value of the numeral string.
str
Pointer to pointer to source string
"0b11001010" binary
"0377" octal
"0xff800" hexdecimal
"1250000" decimal
"-25000" decimal
ret
Pointer to return value
*/
#ifdef __cplusplus
}
#endif

View file

@ -1,21 +0,0 @@
/*
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/>.
*/
#pragma once
/* give code for your bootloader to come up if needed */
void bootloader_jump(void);

View file

@ -1,19 +0,0 @@
/* Copyright 2021 Simon Arlott
*
* 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
// The platform is 32-bit, so prefer 32-bit timers to avoid overflow
#define FAST_TIMER_T_SIZE 32

View file

@ -1,89 +0,0 @@
/* 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;
}
}

View file

@ -1,60 +0,0 @@
/* 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 <ch.h>
#include <hal.h>
/* chThdSleepX of zero maps to infinite - so we map to a tiny delay to still yield */
#define wait_ms(ms) \
do { \
if (ms != 0) { \
chThdSleepMilliseconds(ms); \
} else { \
chThdSleepMicroseconds(1); \
} \
} while (0)
#ifdef WAIT_US_TIMER
void wait_us(uint16_t duration);
#else
# define wait_us(us) \
do { \
if (us != 0) { \
chThdSleepMicroseconds(us); \
} else { \
chThdSleepMicroseconds(1); \
} \
} while (0)
#endif
#include "_wait.c"
/* For GPIOs on ARM-based MCUs, the input pins are sampled by the clock of the bus
* to which the GPIO is connected.
* The connected buses differ depending on the various series of MCUs.
* And since the instruction execution clock of the CPU and the bus clock of GPIO are different,
* there is a delay of several clocks to read the change of the input signal.
*
* Define this delay with the GPIO_INPUT_PIN_DELAY macro.
* If the GPIO_INPUT_PIN_DELAY macro is not defined, the following default values will be used.
* (A fairly large value of 0.25 microseconds is set.)
*/
#ifndef GPIO_INPUT_PIN_DELAY
# define GPIO_INPUT_PIN_DELAY (CPU_CLOCK / 1000000L / 4)
#endif
#define waitInputPinDelay() wait_cpuclock(GPIO_INPUT_PIN_DELAY)

View file

@ -1,37 +0,0 @@
/* 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 <ch.h>
static __inline__ uint8_t __interrupt_disable__(void) {
chSysLock();
return 1;
}
static __inline__ void __interrupt_enable__(const uint8_t *__s) {
chSysUnlock();
__asm__ volatile("" ::: "memory");
(void)__s;
}
#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)

View file

@ -1,123 +0,0 @@
#include "bootloader.h"
#include <ch.h>
#include <hal.h>
#include "wait.h"
/* This code should be checked whether it runs correctly on platforms */
#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
#define BOOTLOADER_MAGIC 0xDEADBEEF
#define MAGIC_ADDR (unsigned long *)(SYMVAL(__ram0_end__) - 4)
#ifndef STM32_BOOTLOADER_DUAL_BANK
# define STM32_BOOTLOADER_DUAL_BANK FALSE
#endif
#ifdef BOOTLOADER_TINYUF2
# define DBL_TAP_MAGIC 0xf01669ef // From tinyuf2's board_api.h
// defined by linker script
extern uint32_t _board_dfu_dbl_tap[];
# define DBL_TAP_REG _board_dfu_dbl_tap[0]
void bootloader_jump(void) {
DBL_TAP_REG = DBL_TAP_MAGIC;
NVIC_SystemReset();
}
void enter_bootloader_mode_if_requested(void) { /* not needed, no two-stage reset */
}
#elif STM32_BOOTLOADER_DUAL_BANK
// Need pin definitions
# include "config_common.h"
# ifndef STM32_BOOTLOADER_DUAL_BANK_GPIO
# error "No STM32_BOOTLOADER_DUAL_BANK_GPIO defined, don't know which pin to toggle"
# endif
# ifndef STM32_BOOTLOADER_DUAL_BANK_POLARITY
# define STM32_BOOTLOADER_DUAL_BANK_POLARITY 0
# endif
# ifndef STM32_BOOTLOADER_DUAL_BANK_DELAY
# define STM32_BOOTLOADER_DUAL_BANK_DELAY 100000
# endif
extern uint32_t __ram0_end__;
__attribute__((weak)) void bootloader_jump(void) {
// For STM32 MCUs with dual-bank flash, and we're incapable of jumping to the bootloader. The first valid flash
// bank is executed unconditionally after a reset, so it doesn't enter DFU unless BOOT0 is high. Instead, we do
// it with hardware...in this case, we pull a GPIO high/low depending on the configuration, connects 3.3V to
// BOOT0's RC charging circuit, lets it charge the capacitor, and issue a system reset. See the QMK discord
// #hardware channel pins for an example circuit.
palSetPadMode(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_MODE_OUTPUT_PUSHPULL);
# if STM32_BOOTLOADER_DUAL_BANK_POLARITY
palSetPad(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO));
# else
palClearPad(PAL_PORT(STM32_BOOTLOADER_DUAL_BANK_GPIO), PAL_PAD(STM32_BOOTLOADER_DUAL_BANK_GPIO));
# endif
// Wait for a while for the capacitor to charge
wait_ms(100);
// Issue a system reset to get the ROM bootloader to execute, with BOOT0 high
NVIC_SystemReset();
}
void enter_bootloader_mode_if_requested(void) {} // not needed at all, but if anybody attempts to invoke it....
#elif defined(STM32_BOOTLOADER_ADDRESS) // STM32_BOOTLOADER_DUAL_BANK
extern uint32_t __ram0_end__;
__attribute__((weak)) void bootloader_jump(void) {
*MAGIC_ADDR = BOOTLOADER_MAGIC; // set magic flag => reset handler will jump into boot loader
NVIC_SystemReset();
}
void enter_bootloader_mode_if_requested(void) {
unsigned long *check = MAGIC_ADDR;
if (*check == BOOTLOADER_MAGIC) {
*check = 0;
__set_CONTROL(0);
__set_MSP(*(__IO uint32_t *)STM32_BOOTLOADER_ADDRESS);
__enable_irq();
typedef void (*BootJump_t)(void);
BootJump_t boot_jump = *(BootJump_t *)(STM32_BOOTLOADER_ADDRESS + 4);
boot_jump();
while (1)
;
}
}
#elif defined(KL2x) || defined(K20x) || defined(MK66F18) || defined(MIMXRT1062) // STM32_BOOTLOADER_DUAL_BANK // STM32_BOOTLOADER_ADDRESS
/* Kinetis */
# if defined(BOOTLOADER_KIIBOHD)
/* Kiibohd Bootloader (MCHCK and Infinity KB) */
# define SCB_AIRCR_VECTKEY_WRITEMAGIC 0x05FA0000
const uint8_t sys_reset_to_loader_magic[] = "\xff\x00\x7fRESET TO LOADER\x7f\x00\xff";
__attribute__((weak)) void bootloader_jump(void) {
void *volatile vbat = (void *)VBAT;
__builtin_memcpy(vbat, (const void *)sys_reset_to_loader_magic, sizeof(sys_reset_to_loader_magic));
// request reset
SCB->AIRCR = SCB_AIRCR_VECTKEY_WRITEMAGIC | SCB_AIRCR_SYSRESETREQ_Msk;
}
# else /* defined(BOOTLOADER_KIIBOHD) */
/* Default for Kinetis - expecting an ARM Teensy */
# include "wait.h"
__attribute__((weak)) void bootloader_jump(void) {
wait_ms(100);
__BKPT(0);
}
# endif /* defined(BOOTLOADER_KIIBOHD) */
#else /* neither STM32 nor KINETIS */
__attribute__((weak)) void bootloader_jump(void) {}
#endif

View file

@ -1,49 +0,0 @@
/* Copyright 2019
*
* 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
#ifndef USB_VBUS_PIN
# define SPLIT_USB_DETECT // Force this on when dedicated pin is not used
#endif
// STM32 compatibility
#if defined(MCU_STM32)
# define CPU_CLOCK STM32_SYSCLK
# if defined(STM32F1XX)
# define USE_GPIOV1
# define PAL_MODE_ALTERNATE_OPENDRAIN PAL_MODE_STM32_ALTERNATE_OPENDRAIN
# define PAL_MODE_ALTERNATE_PUSHPULL PAL_MODE_STM32_ALTERNATE_PUSHPULL
# else
# define PAL_OUTPUT_SPEED_HIGHEST PAL_STM32_OSPEED_HIGHEST
# define PAL_PUPDR_FLOATING PAL_STM32_PUPDR_FLOATING
# endif
# if defined(STM32F1XX) || defined(STM32F2XX) || defined(STM32F4XX) || defined(STM32L1XX)
# define USE_I2CV1
# endif
#endif
// teensy compatibility
#if defined(MCU_KINETIS)
# define CPU_CLOCK KINETIS_SYSCLK_FREQUENCY
# if defined(K20x) || defined(KL2x)
# define USE_I2CV1
# define USE_I2CV1_CONTRIB // for some reason a bunch of ChibiOS-Contrib boards only have clock_speed
# define USE_GPIOV1
# endif
#endif

View file

@ -1,687 +0,0 @@
/*
* 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
*/
#include <stdio.h>
#include <stdbool.h>
#include "util.h"
#include "debug.h"
#include "eeprom_stm32.h"
#include "flash_stm32.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_LASTWRITE_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
* 0XXXXXXXYYYYYYYY
*
* 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
* 111XXXXXXXXXXXXXYYYYYYYYYYYYYYYY
*
* (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_stm32_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)
/* 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;
// #define DEBUG_EEPROM_OUTPUT
/*
* Debug print utils
*/
#if defined(DEBUG_EEPROM_OUTPUT)
# define debug_eeprom debug_enable
# define eeprom_println(s) println(s)
# define eeprom_printf(fmt, ...) xprintf(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("");
}
}
#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 = ~*src;
}
if (debug_eeprom) {
println("EEPROM_Init Compacted Pages:");
print_eeprom();
println("EEPROM_Init Write Log:");
}
/* Replay write log */
uint16_t *log_addr;
for (log_addr = (uint16_t *)FEE_WRITE_LOG_BASE_ADDRESS; log_addr < (uint16_t *)FEE_WRITE_LOG_LAST_ADDRESS; ++log_addr) {
uint16_t address = *log_addr;
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 = ~*log_addr;
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();
}
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_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 *)directAddress == 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;
}
/*****************************************************************************
* Bind to eeprom_driver.c
*******************************************************************************/
void eeprom_driver_init(void) { EEPROM_Init(); }
void eeprom_driver_erase(void) { EEPROM_Erase(); }
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_ReadDataByte((const uintptr_t)src++);
--len;
}
uint16_t value;
bool aligned = ((uintptr_t)dest % 2 == 0);
while (len > 1) {
value = EEPROM_ReadDataWord((const uintptr_t)((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_ReadDataByte((const uintptr_t)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_WriteDataByte((uintptr_t)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_WriteDataWord((uintptr_t)((uint16_t *)dest), value);
dest += 2;
src += 2;
len -= 2;
}
if (len) {
EEPROM_WriteDataByte((uintptr_t)dest, *src);
}
}

View file

@ -1,33 +0,0 @@
/*
* 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);

View file

@ -1,70 +0,0 @@
/* 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 <hal.h>
#if !defined(FEE_PAGE_SIZE) || !defined(FEE_PAGE_COUNT)
# if defined(STM32F103xB) || defined(STM32F042x6)
# ifndef FEE_PAGE_SIZE
# define FEE_PAGE_SIZE 0x400 // Page size = 1KByte
# endif
# ifndef FEE_PAGE_COUNT
# define FEE_PAGE_COUNT 2 // How many pages are used
# endif
# elif defined(STM32F103xE) || defined(STM32F303xC) || defined(STM32F072xB) || defined(STM32F070xB)
# ifndef FEE_PAGE_SIZE
# define FEE_PAGE_SIZE 0x800 // Page size = 2KByte
# endif
# ifndef FEE_PAGE_COUNT
# define FEE_PAGE_COUNT 4 // How many pages are used
# endif
# elif defined(STM32F401xC) || defined(STM32F411xE)
# ifndef FEE_PAGE_SIZE
# define FEE_PAGE_SIZE 0x4000 // Page size = 16KByte
# endif
# ifndef FEE_PAGE_COUNT
# define FEE_PAGE_COUNT 1 // How many pages are used
# endif
# endif
#endif
#if !defined(FEE_MCU_FLASH_SIZE)
# if defined(STM32F042x6)
# define FEE_MCU_FLASH_SIZE 32 // Size in Kb
# elif defined(STM32F103xB) || defined(STM32F072xB) || defined(STM32F070xB)
# define FEE_MCU_FLASH_SIZE 128 // Size in Kb
# elif defined(STM32F303xC) || defined(STM32F401xC)
# define FEE_MCU_FLASH_SIZE 256 // Size in Kb
# elif defined(STM32F103xE) || defined(STM32F411xE)
# define FEE_MCU_FLASH_SIZE 512 // Size in Kb
# endif
#endif
/* Start of the emulated eeprom */
#if !defined(FEE_PAGE_BASE_ADDRESS)
# if defined(STM32F401xC) || defined(STM32F411xE)
# ifndef FEE_PAGE_BASE_ADDRESS
# define FEE_PAGE_BASE_ADDRESS 0x08004000 // bodge to force 2nd 16k page
# endif
# else
# ifndef FEE_FLASH_BASE
# define FEE_FLASH_BASE 0x8000000
# endif
/* Default to end of flash */
# define FEE_PAGE_BASE_ADDRESS ((uintptr_t)(FEE_FLASH_BASE) + FEE_MCU_FLASH_SIZE * 1024 - (FEE_PAGE_COUNT * FEE_PAGE_SIZE))
# endif
#endif

View file

@ -1,610 +0,0 @@
#include <ch.h>
#include <hal.h>
#include "eeconfig.h"
/*************************************/
/* Hardware backend */
/* */
/* Code from PJRC/Teensyduino */
/*************************************/
/* Teensyduino Core Library
* http://www.pjrc.com/teensy/
* Copyright (c) 2013 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:
*
* 1. The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* 2. If the Software is incorporated into a build system that allows
* selection among a list of target devices, then similar target
* devices manufactured by PJRC.COM must be included in the list of
* target devices and selectable in the same manner.
*
* 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.
*/
#if defined(K20x) /* chip selection */
/* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */
// The EEPROM is really RAM with a hardware-based backup system to
// flash memory. Selecting a smaller size EEPROM allows more wear
// leveling, for higher write endurance. If you edit this file,
// set this to the smallest size your application can use. Also,
// due to Freescale's implementation, writing 16 or 32 bit words
// (aligned to 2 or 4 byte boundaries) has twice the endurance
// compared to writing 8 bit bytes.
//
# ifndef EEPROM_SIZE
# define EEPROM_SIZE 32
# endif
/*
^^^ Here be dragons:
NXP AppNote AN4282 section 3.1 states that partitioning must only be done once.
Once EEPROM partitioning is done, the size is locked to this initial configuration.
Attempts to modify the EEPROM_SIZE setting may brick your board.
*/
// Writing unaligned 16 or 32 bit data is handled automatically when
// this is defined, but at a cost of extra code size. Without this,
// any unaligned write will cause a hard fault exception! If you're
// absolutely sure all 16 and 32 bit writes will be aligned, you can
// remove the extra unnecessary code.
//
# define HANDLE_UNALIGNED_WRITES
// Minimum EEPROM Endurance
// ------------------------
# if (EEPROM_SIZE == 2048) // 35000 writes/byte or 70000 writes/word
# define EEESIZE 0x33
# elif (EEPROM_SIZE == 1024) // 75000 writes/byte or 150000 writes/word
# define EEESIZE 0x34
# elif (EEPROM_SIZE == 512) // 155000 writes/byte or 310000 writes/word
# define EEESIZE 0x35
# elif (EEPROM_SIZE == 256) // 315000 writes/byte or 630000 writes/word
# define EEESIZE 0x36
# elif (EEPROM_SIZE == 128) // 635000 writes/byte or 1270000 writes/word
# define EEESIZE 0x37
# elif (EEPROM_SIZE == 64) // 1275000 writes/byte or 2550000 writes/word
# define EEESIZE 0x38
# elif (EEPROM_SIZE == 32) // 2555000 writes/byte or 5110000 writes/word
# define EEESIZE 0x39
# endif
/** \brief eeprom initialization
*
* FIXME: needs doc
*/
void eeprom_initialize(void) {
uint32_t count = 0;
uint16_t do_flash_cmd[] = {0xf06f, 0x037f, 0x7003, 0x7803, 0xf013, 0x0f80, 0xd0fb, 0x4770};
uint8_t status;
if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) {
// FlexRAM is configured as traditional RAM
// We need to reconfigure for EEPROM usage
FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command
FTFL->FCCOB4 = EEESIZE; // EEPROM Size
FTFL->FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup
__disable_irq();
// do_flash_cmd() must execute from RAM. Luckily the C syntax is simple...
(*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT));
__enable_irq();
status = FTFL->FSTAT;
if (status & (FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL)) {
FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR | FTFL_FSTAT_ACCERR | FTFL_FSTAT_FPVIOL));
return; // error
}
}
// wait for eeprom to become ready (is this really necessary?)
while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
if (++count > 20000) break;
}
}
# define FlexRAM ((uint8_t *)0x14000000)
/** \brief eeprom read byte
*
* FIXME: needs doc
*/
uint8_t eeprom_read_byte(const uint8_t *addr) {
uint32_t offset = (uint32_t)addr;
if (offset >= EEPROM_SIZE) return 0;
if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
return FlexRAM[offset];
}
/** \brief eeprom read word
*
* FIXME: needs doc
*/
uint16_t eeprom_read_word(const uint16_t *addr) {
uint32_t offset = (uint32_t)addr;
if (offset >= EEPROM_SIZE - 1) return 0;
if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
return *(uint16_t *)(&FlexRAM[offset]);
}
/** \brief eeprom read dword
*
* FIXME: needs doc
*/
uint32_t eeprom_read_dword(const uint32_t *addr) {
uint32_t offset = (uint32_t)addr;
if (offset >= EEPROM_SIZE - 3) return 0;
if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
return *(uint32_t *)(&FlexRAM[offset]);
}
/** \brief eeprom read block
*
* FIXME: needs doc
*/
void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
uint32_t offset = (uint32_t)addr;
uint8_t *dest = (uint8_t *)buf;
uint32_t end = offset + len;
if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
if (end > EEPROM_SIZE) end = EEPROM_SIZE;
while (offset < end) {
*dest++ = FlexRAM[offset++];
}
}
/** \brief eeprom is ready
*
* FIXME: needs doc
*/
int eeprom_is_ready(void) { return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0; }
/** \brief flexram wait
*
* FIXME: needs doc
*/
static void flexram_wait(void) {
while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
// TODO: timeout
}
}
/** \brief eeprom_write_byte
*
* FIXME: needs doc
*/
void eeprom_write_byte(uint8_t *addr, uint8_t value) {
uint32_t offset = (uint32_t)addr;
if (offset >= EEPROM_SIZE) return;
if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
if (FlexRAM[offset] != value) {
FlexRAM[offset] = value;
flexram_wait();
}
}
/** \brief eeprom write word
*
* FIXME: needs doc
*/
void eeprom_write_word(uint16_t *addr, uint16_t value) {
uint32_t offset = (uint32_t)addr;
if (offset >= EEPROM_SIZE - 1) return;
if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
# ifdef HANDLE_UNALIGNED_WRITES
if ((offset & 1) == 0) {
# endif
if (*(uint16_t *)(&FlexRAM[offset]) != value) {
*(uint16_t *)(&FlexRAM[offset]) = value;
flexram_wait();
}
# ifdef HANDLE_UNALIGNED_WRITES
} else {
if (FlexRAM[offset] != value) {
FlexRAM[offset] = value;
flexram_wait();
}
if (FlexRAM[offset + 1] != (value >> 8)) {
FlexRAM[offset + 1] = value >> 8;
flexram_wait();
}
}
# endif
}
/** \brief eeprom write dword
*
* FIXME: needs doc
*/
void eeprom_write_dword(uint32_t *addr, uint32_t value) {
uint32_t offset = (uint32_t)addr;
if (offset >= EEPROM_SIZE - 3) return;
if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
# ifdef HANDLE_UNALIGNED_WRITES
switch (offset & 3) {
case 0:
# endif
if (*(uint32_t *)(&FlexRAM[offset]) != value) {
*(uint32_t *)(&FlexRAM[offset]) = value;
flexram_wait();
}
return;
# ifdef HANDLE_UNALIGNED_WRITES
case 2:
if (*(uint16_t *)(&FlexRAM[offset]) != value) {
*(uint16_t *)(&FlexRAM[offset]) = value;
flexram_wait();
}
if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
*(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
flexram_wait();
}
return;
default:
if (FlexRAM[offset] != value) {
FlexRAM[offset] = value;
flexram_wait();
}
if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
*(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
flexram_wait();
}
if (FlexRAM[offset + 3] != (value >> 24)) {
FlexRAM[offset + 3] = value >> 24;
flexram_wait();
}
}
# endif
}
/** \brief eeprom write block
*
* FIXME: needs doc
*/
void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
uint32_t offset = (uint32_t)addr;
const uint8_t *src = (const uint8_t *)buf;
if (offset >= EEPROM_SIZE) return;
if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
while (len > 0) {
uint32_t lsb = offset & 3;
if (lsb == 0 && len >= 4) {
// write aligned 32 bits
uint32_t val32;
val32 = *src++;
val32 |= (*src++ << 8);
val32 |= (*src++ << 16);
val32 |= (*src++ << 24);
if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
*(uint32_t *)(&FlexRAM[offset]) = val32;
flexram_wait();
}
offset += 4;
len -= 4;
} else if ((lsb == 0 || lsb == 2) && len >= 2) {
// write aligned 16 bits
uint16_t val16;
val16 = *src++;
val16 |= (*src++ << 8);
if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
*(uint16_t *)(&FlexRAM[offset]) = val16;
flexram_wait();
}
offset += 2;
len -= 2;
} else {
// write 8 bits
uint8_t val8 = *src++;
if (FlexRAM[offset] != val8) {
FlexRAM[offset] = val8;
flexram_wait();
}
offset++;
len--;
}
}
}
/*
void do_flash_cmd(volatile uint8_t *fstat)
{
*fstat = 0x80;
while ((*fstat & 0x80) == 0) ; // wait
}
00000000 <do_flash_cmd>:
0: f06f 037f mvn.w r3, #127 ; 0x7f
4: 7003 strb r3, [r0, #0]
6: 7803 ldrb r3, [r0, #0]
8: f013 0f80 tst.w r3, #128 ; 0x80
c: d0fb beq.n 6 <do_flash_cmd+0x6>
e: 4770 bx lr
*/
#elif defined(KL2x) /* chip selection */
/* Teensy LC (emulated) */
# define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
extern uint32_t __eeprom_workarea_start__;
extern uint32_t __eeprom_workarea_end__;
# define EEPROM_SIZE 128
static uint32_t flashend = 0;
void eeprom_initialize(void) {
const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
do {
if (*p++ == 0xFFFF) {
flashend = (uint32_t)(p - 2);
return;
}
} while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__));
flashend = (uint32_t)(p - 1);
}
uint8_t eeprom_read_byte(const uint8_t *addr) {
uint32_t offset = (uint32_t)addr;
const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
uint16_t val;
uint8_t data = 0xFF;
if (!end) {
eeprom_initialize();
end = (const uint16_t *)((uint32_t)flashend);
}
if (offset < EEPROM_SIZE) {
while (p <= end) {
val = *p++;
if ((val & 255) == offset) data = val >> 8;
}
}
return data;
}
static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data) {
// with great power comes great responsibility....
uint32_t stat;
*(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC);
*(uint32_t *)&(FTFA->FCCOB7) = data;
__disable_irq();
(*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT));
__enable_irq();
stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR | FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL);
if (stat) {
FTFA->FSTAT = stat;
}
MCM->PLACR |= MCM_PLACR_CFCC;
}
void eeprom_write_byte(uint8_t *addr, uint8_t data) {
uint32_t offset = (uint32_t)addr;
const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
uint32_t i, val, flashaddr;
uint16_t do_flash_cmd[] = {0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
uint8_t buf[EEPROM_SIZE];
if (offset >= EEPROM_SIZE) return;
if (!end) {
eeprom_initialize();
end = (const uint16_t *)((uint32_t)flashend);
}
if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) {
val = (data << 8) | offset;
flashaddr = (uint32_t)end;
flashend = flashaddr;
if ((flashaddr & 2) == 0) {
val |= 0xFFFF0000;
} else {
val <<= 16;
val |= 0x0000FFFF;
}
flash_write(do_flash_cmd, flashaddr, val);
} else {
for (i = 0; i < EEPROM_SIZE; i++) {
buf[i] = 0xFF;
}
val = 0;
for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) {
val = *p;
if ((val & 255) < EEPROM_SIZE) {
buf[val & 255] = val >> 8;
}
}
buf[offset] = data;
for (flashaddr = (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) {
*(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr;
__disable_irq();
(*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT));
__enable_irq();
val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR | FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL);
;
if (val) FTFA->FSTAT = val;
MCM->PLACR |= MCM_PLACR_CFCC;
}
flashaddr = (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__);
for (i = 0; i < EEPROM_SIZE; i++) {
if (buf[i] == 0xFF) continue;
if ((flashaddr & 2) == 0) {
val = (buf[i] << 8) | i;
} else {
val = val | (buf[i] << 24) | (i << 16);
flash_write(do_flash_cmd, flashaddr, val);
}
flashaddr += 2;
}
flashend = flashaddr;
if ((flashaddr & 2)) {
val |= 0xFFFF0000;
flash_write(do_flash_cmd, flashaddr, val);
}
}
}
/*
void do_flash_cmd(volatile uint8_t *fstat)
{
*fstat = 0x80;
while ((*fstat & 0x80) == 0) ; // wait
}
00000000 <do_flash_cmd>:
0: 2380 movs r3, #128 ; 0x80
2: 7003 strb r3, [r0, #0]
4: 7803 ldrb r3, [r0, #0]
6: b25b sxtb r3, r3
8: 2b00 cmp r3, #0
a: dafb bge.n 4 <do_flash_cmd+0x4>
c: 4770 bx lr
*/
uint16_t eeprom_read_word(const uint16_t *addr) {
const uint8_t *p = (const uint8_t *)addr;
return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8);
}
uint32_t eeprom_read_dword(const uint32_t *addr) {
const uint8_t *p = (const uint8_t *)addr;
return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24);
}
void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
const uint8_t *p = (const uint8_t *)addr;
uint8_t * dest = (uint8_t *)buf;
while (len--) {
*dest++ = eeprom_read_byte(p++);
}
}
int eeprom_is_ready(void) { return 1; }
void eeprom_write_word(uint16_t *addr, uint16_t value) {
uint8_t *p = (uint8_t *)addr;
eeprom_write_byte(p++, value);
eeprom_write_byte(p, value >> 8);
}
void eeprom_write_dword(uint32_t *addr, uint32_t value) {
uint8_t *p = (uint8_t *)addr;
eeprom_write_byte(p++, value);
eeprom_write_byte(p++, value >> 8);
eeprom_write_byte(p++, value >> 16);
eeprom_write_byte(p, value >> 24);
}
void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
uint8_t * p = (uint8_t *)addr;
const uint8_t *src = (const uint8_t *)buf;
while (len--) {
eeprom_write_byte(p++, *src++);
}
}
#else
// No EEPROM supported, so emulate it
# ifndef EEPROM_SIZE
# include "eeconfig.h"
# define EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4) // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO
# endif
__attribute__((aligned(4))) static uint8_t buffer[EEPROM_SIZE];
uint8_t eeprom_read_byte(const uint8_t *addr) {
uint32_t offset = (uint32_t)addr;
return buffer[offset];
}
void eeprom_write_byte(uint8_t *addr, uint8_t value) {
uint32_t offset = (uint32_t)addr;
buffer[offset] = value;
}
uint16_t eeprom_read_word(const uint16_t *addr) {
const uint8_t *p = (const uint8_t *)addr;
return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8);
}
uint32_t eeprom_read_dword(const uint32_t *addr) {
const uint8_t *p = (const uint8_t *)addr;
return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24);
}
void eeprom_read_block(void *buf, const void *addr, size_t len) {
const uint8_t *p = (const uint8_t *)addr;
uint8_t * dest = (uint8_t *)buf;
while (len--) {
*dest++ = eeprom_read_byte(p++);
}
}
void eeprom_write_word(uint16_t *addr, uint16_t value) {
uint8_t *p = (uint8_t *)addr;
eeprom_write_byte(p++, value);
eeprom_write_byte(p, value >> 8);
}
void eeprom_write_dword(uint32_t *addr, uint32_t value) {
uint8_t *p = (uint8_t *)addr;
eeprom_write_byte(p++, value);
eeprom_write_byte(p++, value >> 8);
eeprom_write_byte(p++, value >> 16);
eeprom_write_byte(p, value >> 24);
}
void eeprom_write_block(const void *buf, void *addr, size_t len) {
uint8_t * p = (uint8_t *)addr;
const uint8_t *src = (const uint8_t *)buf;
while (len--) {
eeprom_write_byte(p++, *src++);
}
}
#endif /* chip selection */
// The update functions just calls write for now, but could probably be optimized
void eeprom_update_byte(uint8_t *addr, uint8_t value) { eeprom_write_byte(addr, value); }
void eeprom_update_word(uint16_t *addr, uint16_t value) {
uint8_t *p = (uint8_t *)addr;
eeprom_write_byte(p++, value);
eeprom_write_byte(p, value >> 8);
}
void eeprom_update_dword(uint32_t *addr, uint32_t value) {
uint8_t *p = (uint8_t *)addr;
eeprom_write_byte(p++, value);
eeprom_write_byte(p++, value >> 8);
eeprom_write_byte(p++, value >> 16);
eeprom_write_byte(p, value >> 24);
}
void eeprom_update_block(const void *buf, void *addr, size_t len) {
uint8_t * p = (uint8_t *)addr;
const uint8_t *src = (const uint8_t *)buf;
while (len--) {
eeprom_write_byte(p++, *src++);
}
}

View file

@ -1,203 +0,0 @@
/*
* 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
*/
#include <hal.h>
#include "flash_stm32.h"
#if defined(EEPROM_EMU_STM32F103xB)
# define FLASH_SR_WRPERR FLASH_SR_WRPRTERR
#endif
#if defined(EEPROM_EMU_STM32F401xC)
# define FLASH_SR_PGERR (FLASH_SR_PGSERR | FLASH_SR_PGPERR | FLASH_SR_PGAERR)
# define FLASH_KEY1 0x45670123U
# define FLASH_KEY2 0xCDEF89ABU
static uint8_t ADDR2PAGE(uint32_t Page_Address) {
switch (Page_Address) {
case 0x08000000 ... 0x08003FFF:
return 0;
case 0x08004000 ... 0x08007FFF:
return 1;
case 0x08008000 ... 0x0800BFFF:
return 2;
case 0x0800C000 ... 0x0800FFFF:
return 3;
}
// TODO: bad times...
return 7;
}
#endif
/* Delay definition */
#define EraseTimeout ((uint32_t)0x00000FFF)
#define ProgramTimeout ((uint32_t)0x0000001F)
#define ASSERT(exp) (void)((0))
/**
* @brief Inserts a time delay.
* @param None
* @retval None
*/
static void delay(void) {
__IO uint32_t i = 0;
for (i = 0xFF; i != 0; i--) {
}
}
/**
* @brief Returns the FLASH Status.
* @param None
* @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
* FLASH_ERROR_WRP or FLASH_COMPLETE
*/
FLASH_Status FLASH_GetStatus(void) {
if ((FLASH->SR & FLASH_SR_BSY) == FLASH_SR_BSY) return FLASH_BUSY;
if ((FLASH->SR & FLASH_SR_PGERR) != 0) return FLASH_ERROR_PG;
if ((FLASH->SR & FLASH_SR_WRPERR) != 0) return FLASH_ERROR_WRP;
#if defined(FLASH_OBR_OPTERR)
if ((FLASH->SR & FLASH_OBR_OPTERR) != 0) return FLASH_ERROR_OPT;
#endif
return FLASH_COMPLETE;
}
/**
* @brief Waits for a Flash operation to complete or a TIMEOUT to occur.
* @param Timeout: FLASH progamming Timeout
* @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
* FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
*/
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout) {
FLASH_Status status;
/* Check for the Flash Status */
status = FLASH_GetStatus();
/* Wait for a Flash operation to complete or a TIMEOUT to occur */
while ((status == FLASH_BUSY) && (Timeout != 0x00)) {
delay();
status = FLASH_GetStatus();
Timeout--;
}
if (Timeout == 0) status = FLASH_TIMEOUT;
/* Return the operation status */
return status;
}
/**
* @brief Erases a specified FLASH page.
* @param Page_Address: The page address to be erased.
* @retval FLASH Status: The returned value can be: FLASH_BUSY, FLASH_ERROR_PG,
* FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
*/
FLASH_Status FLASH_ErasePage(uint32_t Page_Address) {
FLASH_Status status = FLASH_COMPLETE;
/* Check the parameters */
ASSERT(IS_FLASH_ADDRESS(Page_Address));
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(EraseTimeout);
if (status == FLASH_COMPLETE) {
/* if the previous operation is completed, proceed to erase the page */
#if defined(FLASH_CR_SNB)
FLASH->CR &= ~FLASH_CR_SNB;
FLASH->CR |= FLASH_CR_SER | (ADDR2PAGE(Page_Address) << FLASH_CR_SNB_Pos);
#else
FLASH->CR |= FLASH_CR_PER;
FLASH->AR = Page_Address;
#endif
FLASH->CR |= FLASH_CR_STRT;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(EraseTimeout);
if (status != FLASH_TIMEOUT) {
/* if the erase operation is completed, disable the configured Bits */
#if defined(FLASH_CR_SNB)
FLASH->CR &= ~(FLASH_CR_SER | FLASH_CR_SNB);
#else
FLASH->CR &= ~FLASH_CR_PER;
#endif
}
FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR);
}
/* Return the Erase Status */
return status;
}
/**
* @brief Programs a half word at a specified address.
* @param Address: specifies the address to be programmed.
* @param Data: specifies the data to be programmed.
* @retval FLASH Status: The returned value can be: FLASH_ERROR_PG,
* FLASH_ERROR_WRP, FLASH_COMPLETE or FLASH_TIMEOUT.
*/
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) {
FLASH_Status status = FLASH_BAD_ADDRESS;
if (IS_FLASH_ADDRESS(Address)) {
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(ProgramTimeout);
if (status == FLASH_COMPLETE) {
/* if the previous operation is completed, proceed to program the new data */
#if defined(FLASH_CR_PSIZE)
FLASH->CR &= ~FLASH_CR_PSIZE;
FLASH->CR |= FLASH_CR_PSIZE_0;
#endif
FLASH->CR |= FLASH_CR_PG;
*(__IO uint16_t*)Address = Data;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(ProgramTimeout);
if (status != FLASH_TIMEOUT) {
/* if the program operation is completed, disable the PG Bit */
FLASH->CR &= ~FLASH_CR_PG;
}
FLASH->SR = (FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR);
}
}
return status;
}
/**
* @brief Unlocks the FLASH Program Erase Controller.
* @param None
* @retval None
*/
void FLASH_Unlock(void) {
if (FLASH->CR & FLASH_CR_LOCK) {
/* Authorize the FPEC Access */
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
}
}
/**
* @brief Locks the FLASH Program Erase Controller.
* @param None
* @retval None
*/
void FLASH_Lock(void) {
/* Set the Lock Bit to lock the FPEC and the FCR */
FLASH->CR |= FLASH_CR_LOCK;
}

View file

@ -1,44 +0,0 @@
/*
* 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

View file

@ -1,50 +0,0 @@
/* 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 <hal.h>
#include "pin_defs.h"
typedef ioline_t pin_t;
/* Operation of GPIO by pin. */
#define setPinInput(pin) palSetLineMode(pin, PAL_MODE_INPUT)
#define setPinInputHigh(pin) palSetLineMode(pin, PAL_MODE_INPUT_PULLUP)
#define setPinInputLow(pin) palSetLineMode(pin, PAL_MODE_INPUT_PULLDOWN)
#define setPinOutput(pin) palSetLineMode(pin, PAL_MODE_OUTPUT_PUSHPULL)
#define writePinHigh(pin) palSetLine(pin)
#define writePinLow(pin) palClearLine(pin)
#define writePin(pin, level) ((level) ? (writePinHigh(pin)) : (writePinLow(pin)))
#define readPin(pin) palReadLine(pin)
#define togglePin(pin) palToggleLine(pin)
/* Operation of GPIO by port. */
typedef uint16_t port_data_t;
#define readPort(pin) palReadPort(PAL_PORT(pin))
#define setPortBitInput(pin, bit) palSetPadMode(PAL_PORT(pin), bit, PAL_MODE_INPUT)
#define setPortBitInputHigh(pin, bit) palSetPadMode(PAL_PORT(pin), bit, PAL_MODE_INPUT_PULLUP)
#define setPortBitInputLow(pin, bit) palSetPadMode(PAL_PORT(pin), bit, PAL_MODE_INPUT_PULLDOWN)
#define setPortBitOutput(pin, bit) palSetPadMode(PAL_PORT(pin), bit, PAL_MODE_OUTPUT_PUSHPULL)
#define writePortBitLow(pin, bit) palClearLine(PAL_LINE(PAL_PORT(pin), bit))
#define writePortBitHigh(pin, bit) palSetLine(PAL_LINE(PAL_PORT(pin), bit))

View file

@ -1,323 +0,0 @@
/* 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
// Defines mapping for Proton C replacement
#ifdef CONVERT_TO_PROTON_C
// Left side (front)
# define D3 PAL_LINE(GPIOA, 9)
# define D2 PAL_LINE(GPIOA, 10)
// GND
// GND
# define D1 PAL_LINE(GPIOB, 7)
# define D0 PAL_LINE(GPIOB, 6)
# define D4 PAL_LINE(GPIOB, 5)
# define C6 PAL_LINE(GPIOB, 4)
# define D7 PAL_LINE(GPIOB, 3)
# define E6 PAL_LINE(GPIOB, 2)
# define B4 PAL_LINE(GPIOB, 1)
# define B5 PAL_LINE(GPIOB, 0)
// Right side (front)
// RAW
// GND
// RESET
// VCC
# define F4 PAL_LINE(GPIOA, 2)
# define F5 PAL_LINE(GPIOA, 1)
# define F6 PAL_LINE(GPIOA, 0)
# define F7 PAL_LINE(GPIOB, 8)
# define B1 PAL_LINE(GPIOB, 13)
# define B3 PAL_LINE(GPIOB, 14)
# define B2 PAL_LINE(GPIOB, 15)
# define B6 PAL_LINE(GPIOB, 9)
// LEDs (only D5/C13 uses an actual LED)
# ifdef CONVERT_TO_PROTON_C_RXLED
# define D5 PAL_LINE(GPIOC, 14)
# define B0 PAL_LINE(GPIOC, 13)
# else
# define D5 PAL_LINE(GPIOC, 13)
# define B0 PAL_LINE(GPIOC, 14)
# endif
#else
# define A0 PAL_LINE(GPIOA, 0)
# define A1 PAL_LINE(GPIOA, 1)
# define A2 PAL_LINE(GPIOA, 2)
# define A3 PAL_LINE(GPIOA, 3)
# define A4 PAL_LINE(GPIOA, 4)
# define A5 PAL_LINE(GPIOA, 5)
# define A6 PAL_LINE(GPIOA, 6)
# define A7 PAL_LINE(GPIOA, 7)
# define A8 PAL_LINE(GPIOA, 8)
# define A9 PAL_LINE(GPIOA, 9)
# define A10 PAL_LINE(GPIOA, 10)
# define A11 PAL_LINE(GPIOA, 11)
# define A12 PAL_LINE(GPIOA, 12)
# define A13 PAL_LINE(GPIOA, 13)
# define A14 PAL_LINE(GPIOA, 14)
# define A15 PAL_LINE(GPIOA, 15)
# define A16 PAL_LINE(GPIOA, 16)
# define A17 PAL_LINE(GPIOA, 17)
# define A18 PAL_LINE(GPIOA, 18)
# define A19 PAL_LINE(GPIOA, 19)
# define A20 PAL_LINE(GPIOA, 20)
# define A21 PAL_LINE(GPIOA, 21)
# define A22 PAL_LINE(GPIOA, 22)
# define A23 PAL_LINE(GPIOA, 23)
# define A24 PAL_LINE(GPIOA, 24)
# define A25 PAL_LINE(GPIOA, 25)
# define A26 PAL_LINE(GPIOA, 26)
# define A27 PAL_LINE(GPIOA, 27)
# define A28 PAL_LINE(GPIOA, 28)
# define A29 PAL_LINE(GPIOA, 29)
# define A30 PAL_LINE(GPIOA, 30)
# define A31 PAL_LINE(GPIOA, 31)
# define A32 PAL_LINE(GPIOA, 32)
# define B0 PAL_LINE(GPIOB, 0)
# define B1 PAL_LINE(GPIOB, 1)
# define B2 PAL_LINE(GPIOB, 2)
# define B3 PAL_LINE(GPIOB, 3)
# define B4 PAL_LINE(GPIOB, 4)
# define B5 PAL_LINE(GPIOB, 5)
# define B6 PAL_LINE(GPIOB, 6)
# define B7 PAL_LINE(GPIOB, 7)
# define B8 PAL_LINE(GPIOB, 8)
# define B9 PAL_LINE(GPIOB, 9)
# define B10 PAL_LINE(GPIOB, 10)
# define B11 PAL_LINE(GPIOB, 11)
# define B12 PAL_LINE(GPIOB, 12)
# define B13 PAL_LINE(GPIOB, 13)
# define B14 PAL_LINE(GPIOB, 14)
# define B15 PAL_LINE(GPIOB, 15)
# define B16 PAL_LINE(GPIOB, 16)
# define B17 PAL_LINE(GPIOB, 17)
# define B18 PAL_LINE(GPIOB, 18)
# define B19 PAL_LINE(GPIOB, 19)
# define B20 PAL_LINE(GPIOB, 20)
# define B21 PAL_LINE(GPIOB, 21)
# define B22 PAL_LINE(GPIOB, 22)
# define B23 PAL_LINE(GPIOB, 23)
# define B24 PAL_LINE(GPIOB, 24)
# define B25 PAL_LINE(GPIOB, 25)
# define B26 PAL_LINE(GPIOB, 26)
# define B27 PAL_LINE(GPIOB, 27)
# define B28 PAL_LINE(GPIOB, 28)
# define B29 PAL_LINE(GPIOB, 29)
# define B30 PAL_LINE(GPIOB, 30)
# define B31 PAL_LINE(GPIOB, 31)
# define B32 PAL_LINE(GPIOB, 32)
# define C0 PAL_LINE(GPIOC, 0)
# define C1 PAL_LINE(GPIOC, 1)
# define C2 PAL_LINE(GPIOC, 2)
# define C3 PAL_LINE(GPIOC, 3)
# define C4 PAL_LINE(GPIOC, 4)
# define C5 PAL_LINE(GPIOC, 5)
# define C6 PAL_LINE(GPIOC, 6)
# define C7 PAL_LINE(GPIOC, 7)
# define C8 PAL_LINE(GPIOC, 8)
# define C9 PAL_LINE(GPIOC, 9)
# define C10 PAL_LINE(GPIOC, 10)
# define C11 PAL_LINE(GPIOC, 11)
# define C12 PAL_LINE(GPIOC, 12)
# define C13 PAL_LINE(GPIOC, 13)
# define C14 PAL_LINE(GPIOC, 14)
# define C15 PAL_LINE(GPIOC, 15)
# define C16 PAL_LINE(GPIOC, 16)
# define C17 PAL_LINE(GPIOC, 17)
# define C18 PAL_LINE(GPIOC, 18)
# define C19 PAL_LINE(GPIOC, 19)
# define C20 PAL_LINE(GPIOC, 20)
# define C21 PAL_LINE(GPIOC, 21)
# define C22 PAL_LINE(GPIOC, 22)
# define C23 PAL_LINE(GPIOC, 23)
# define C24 PAL_LINE(GPIOC, 24)
# define C25 PAL_LINE(GPIOC, 25)
# define C26 PAL_LINE(GPIOC, 26)
# define C27 PAL_LINE(GPIOC, 27)
# define C28 PAL_LINE(GPIOC, 28)
# define C29 PAL_LINE(GPIOC, 29)
# define C30 PAL_LINE(GPIOC, 30)
# define C31 PAL_LINE(GPIOC, 31)
# define C32 PAL_LINE(GPIOC, 32)
# define D0 PAL_LINE(GPIOD, 0)
# define D1 PAL_LINE(GPIOD, 1)
# define D2 PAL_LINE(GPIOD, 2)
# define D3 PAL_LINE(GPIOD, 3)
# define D4 PAL_LINE(GPIOD, 4)
# define D5 PAL_LINE(GPIOD, 5)
# define D6 PAL_LINE(GPIOD, 6)
# define D7 PAL_LINE(GPIOD, 7)
# define D8 PAL_LINE(GPIOD, 8)
# define D9 PAL_LINE(GPIOD, 9)
# define D10 PAL_LINE(GPIOD, 10)
# define D11 PAL_LINE(GPIOD, 11)
# define D12 PAL_LINE(GPIOD, 12)
# define D13 PAL_LINE(GPIOD, 13)
# define D14 PAL_LINE(GPIOD, 14)
# define D15 PAL_LINE(GPIOD, 15)
# define D16 PAL_LINE(GPIOD, 16)
# define D17 PAL_LINE(GPIOD, 17)
# define D18 PAL_LINE(GPIOD, 18)
# define D19 PAL_LINE(GPIOD, 19)
# define D20 PAL_LINE(GPIOD, 20)
# define D21 PAL_LINE(GPIOD, 21)
# define D22 PAL_LINE(GPIOD, 22)
# define D23 PAL_LINE(GPIOD, 23)
# define D24 PAL_LINE(GPIOD, 24)
# define D25 PAL_LINE(GPIOD, 25)
# define D26 PAL_LINE(GPIOD, 26)
# define D27 PAL_LINE(GPIOD, 27)
# define D28 PAL_LINE(GPIOD, 28)
# define D29 PAL_LINE(GPIOD, 29)
# define D30 PAL_LINE(GPIOD, 30)
# define D31 PAL_LINE(GPIOD, 31)
# define D32 PAL_LINE(GPIOD, 32)
# define E0 PAL_LINE(GPIOE, 0)
# define E1 PAL_LINE(GPIOE, 1)
# define E2 PAL_LINE(GPIOE, 2)
# define E3 PAL_LINE(GPIOE, 3)
# define E4 PAL_LINE(GPIOE, 4)
# define E5 PAL_LINE(GPIOE, 5)
# define E6 PAL_LINE(GPIOE, 6)
# define E7 PAL_LINE(GPIOE, 7)
# define E8 PAL_LINE(GPIOE, 8)
# define E9 PAL_LINE(GPIOE, 9)
# define E10 PAL_LINE(GPIOE, 10)
# define E11 PAL_LINE(GPIOE, 11)
# define E12 PAL_LINE(GPIOE, 12)
# define E13 PAL_LINE(GPIOE, 13)
# define E14 PAL_LINE(GPIOE, 14)
# define E15 PAL_LINE(GPIOE, 15)
# define E16 PAL_LINE(GPIOE, 16)
# define E17 PAL_LINE(GPIOE, 17)
# define E18 PAL_LINE(GPIOE, 18)
# define E19 PAL_LINE(GPIOE, 19)
# define E20 PAL_LINE(GPIOE, 20)
# define E21 PAL_LINE(GPIOE, 21)
# define E22 PAL_LINE(GPIOE, 22)
# define E23 PAL_LINE(GPIOE, 23)
# define E24 PAL_LINE(GPIOE, 24)
# define E25 PAL_LINE(GPIOE, 25)
# define E26 PAL_LINE(GPIOE, 26)
# define E27 PAL_LINE(GPIOE, 27)
# define E28 PAL_LINE(GPIOE, 28)
# define E29 PAL_LINE(GPIOE, 29)
# define E30 PAL_LINE(GPIOE, 30)
# define E31 PAL_LINE(GPIOE, 31)
# define E32 PAL_LINE(GPIOE, 32)
# define F0 PAL_LINE(GPIOF, 0)
# define F1 PAL_LINE(GPIOF, 1)
# define F2 PAL_LINE(GPIOF, 2)
# define F3 PAL_LINE(GPIOF, 3)
# define F4 PAL_LINE(GPIOF, 4)
# define F5 PAL_LINE(GPIOF, 5)
# define F6 PAL_LINE(GPIOF, 6)
# define F7 PAL_LINE(GPIOF, 7)
# define F8 PAL_LINE(GPIOF, 8)
# define F9 PAL_LINE(GPIOF, 9)
# define F10 PAL_LINE(GPIOF, 10)
# define F11 PAL_LINE(GPIOF, 11)
# define F12 PAL_LINE(GPIOF, 12)
# define F13 PAL_LINE(GPIOF, 13)
# define F14 PAL_LINE(GPIOF, 14)
# define F15 PAL_LINE(GPIOF, 15)
# define G0 PAL_LINE(GPIOG, 0)
# define G1 PAL_LINE(GPIOG, 1)
# define G2 PAL_LINE(GPIOG, 2)
# define G3 PAL_LINE(GPIOG, 3)
# define G4 PAL_LINE(GPIOG, 4)
# define G5 PAL_LINE(GPIOG, 5)
# define G6 PAL_LINE(GPIOG, 6)
# define G7 PAL_LINE(GPIOG, 7)
# define G8 PAL_LINE(GPIOG, 8)
# define G9 PAL_LINE(GPIOG, 9)
# define G10 PAL_LINE(GPIOG, 10)
# define G11 PAL_LINE(GPIOG, 11)
# define G12 PAL_LINE(GPIOG, 12)
# define G13 PAL_LINE(GPIOG, 13)
# define G14 PAL_LINE(GPIOG, 14)
# define G15 PAL_LINE(GPIOG, 15)
# define H0 PAL_LINE(GPIOH, 0)
# define H1 PAL_LINE(GPIOH, 1)
# define H2 PAL_LINE(GPIOH, 2)
# define H3 PAL_LINE(GPIOH, 3)
# define H4 PAL_LINE(GPIOH, 4)
# define H5 PAL_LINE(GPIOH, 5)
# define H6 PAL_LINE(GPIOH, 6)
# define H7 PAL_LINE(GPIOH, 7)
# define H8 PAL_LINE(GPIOH, 8)
# define H9 PAL_LINE(GPIOH, 9)
# define H10 PAL_LINE(GPIOH, 10)
# define H11 PAL_LINE(GPIOH, 11)
# define H12 PAL_LINE(GPIOH, 12)
# define H13 PAL_LINE(GPIOH, 13)
# define H14 PAL_LINE(GPIOH, 14)
# define H15 PAL_LINE(GPIOH, 15)
# define I0 PAL_LINE(GPIOI, 0)
# define I1 PAL_LINE(GPIOI, 1)
# define I2 PAL_LINE(GPIOI, 2)
# define I3 PAL_LINE(GPIOI, 3)
# define I4 PAL_LINE(GPIOI, 4)
# define I5 PAL_LINE(GPIOI, 5)
# define I6 PAL_LINE(GPIOI, 6)
# define I7 PAL_LINE(GPIOI, 7)
# define I8 PAL_LINE(GPIOI, 8)
# define I9 PAL_LINE(GPIOI, 9)
# define I10 PAL_LINE(GPIOI, 10)
# define I11 PAL_LINE(GPIOI, 11)
# define I12 PAL_LINE(GPIOI, 12)
# define I13 PAL_LINE(GPIOI, 13)
# define I14 PAL_LINE(GPIOI, 14)
# define I15 PAL_LINE(GPIOI, 15)
# define J0 PAL_LINE(GPIOJ, 0)
# define J1 PAL_LINE(GPIOJ, 1)
# define J2 PAL_LINE(GPIOJ, 2)
# define J3 PAL_LINE(GPIOJ, 3)
# define J4 PAL_LINE(GPIOJ, 4)
# define J5 PAL_LINE(GPIOJ, 5)
# define J6 PAL_LINE(GPIOJ, 6)
# define J7 PAL_LINE(GPIOJ, 7)
# define J8 PAL_LINE(GPIOJ, 8)
# define J9 PAL_LINE(GPIOJ, 9)
# define J10 PAL_LINE(GPIOJ, 10)
# define J11 PAL_LINE(GPIOJ, 11)
# define J12 PAL_LINE(GPIOJ, 12)
# define J13 PAL_LINE(GPIOJ, 13)
# define J14 PAL_LINE(GPIOJ, 14)
# define J15 PAL_LINE(GPIOJ, 15)
// Keyboards can `#define KEYBOARD_REQUIRES_GPIOK` if they need to access GPIO-K pins. These conflict with a whole
// bunch of layout definitions, so it's intentionally left out unless absolutely required -- in that case, the
// keyboard designer should use a different symbol when defining their layout macros.
# ifdef KEYBOARD_REQUIRES_GPIOK
# define K0 PAL_LINE(GPIOK, 0)
# define K1 PAL_LINE(GPIOK, 1)
# define K2 PAL_LINE(GPIOK, 2)
# define K3 PAL_LINE(GPIOK, 3)
# define K4 PAL_LINE(GPIOK, 4)
# define K5 PAL_LINE(GPIOK, 5)
# define K6 PAL_LINE(GPIOK, 6)
# define K7 PAL_LINE(GPIOK, 7)
# define K8 PAL_LINE(GPIOK, 8)
# define K9 PAL_LINE(GPIOK, 9)
# define K10 PAL_LINE(GPIOK, 10)
# define K11 PAL_LINE(GPIOK, 11)
# define K12 PAL_LINE(GPIOK, 12)
# define K13 PAL_LINE(GPIOK, 13)
# define K14 PAL_LINE(GPIOK, 14)
# define K15 PAL_LINE(GPIOK, 15)
# endif
#endif

View file

@ -1,22 +0,0 @@
/* 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/>.
*/
#include "platform_deps.h"
void platform_setup(void) {
halInit();
chSysInit();
}

View file

@ -1,19 +0,0 @@
/* 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 <hal.h>
#include "chibios_config.h"

View file

@ -1,192 +0,0 @@
#include <ch.h>
#include <hal.h>
#include "led.h"
#include "sleep_led.h"
/* All right, we go the "software" way: timer, toggle LED in interrupt.
* Based on hasu's code for AVRs.
* Use LP timer on Kinetises, TIM14 on STM32F0.
*/
#ifndef SLEEP_LED_GPT_DRIVER
# if defined(STM32F0XX)
# define SLEEP_LED_GPT_DRIVER GPTD14
# endif
#endif
#if defined(KL2x) || defined(K20x) || defined(SLEEP_LED_GPT_DRIVER) /* common parts for timers/interrupts */
/* Breathing Sleep LED brighness(PWM On period) table
* (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
*
* http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
* (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
*/
static const uint8_t breathing_table[64] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10, 15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252, 255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23, 15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
void sleep_led_timer_callback(void) {
/* Software PWM
* timer:1111 1111 1111 1111
* \_____/\/ \_______/____ count(0-255)
* \ \______________ duration of step(4)
* \__________________ index of step table(0-63)
*/
// this works for cca 65536 irqs/sec
static union {
uint16_t row;
struct {
uint8_t count : 8;
uint8_t duration : 2;
uint8_t index : 6;
} pwm;
} timer = {.row = 0};
timer.row++;
// LED on
if (timer.pwm.count == 0) {
led_set(1 << USB_LED_CAPS_LOCK);
}
// LED off
if (timer.pwm.count == breathing_table[timer.pwm.index]) {
led_set(0);
}
}
#endif /* common parts for known platforms */
#if defined(KL2x) || defined(K20x) /* platform selection: familiar Kinetis chips */
/* Use Low Power Timer (LPTMR) */
# define TIMER_INTERRUPT_VECTOR KINETIS_LPTMR0_IRQ_VECTOR
# define RESET_COUNTER LPTMR0->CSR |= LPTMRx_CSR_TCF
/* LPTMR clock options */
# define LPTMR_CLOCK_MCGIRCLK 0 /* 4MHz clock */
# define LPTMR_CLOCK_LPO 1 /* 1kHz clock */
# define LPTMR_CLOCK_ERCLK32K 2 /* external 32kHz crystal */
# define LPTMR_CLOCK_OSCERCLK 3 /* output from OSC */
/* Work around inconsistencies in Freescale naming */
# if !defined(SIM_SCGC5_LPTMR)
# define SIM_SCGC5_LPTMR SIM_SCGC5_LPTIMER
# endif
/* interrupt handler */
OSAL_IRQ_HANDLER(TIMER_INTERRUPT_VECTOR) {
OSAL_IRQ_PROLOGUE();
sleep_led_timer_callback();
/* Reset the counter */
RESET_COUNTER;
OSAL_IRQ_EPILOGUE();
}
/* Initialise the timer */
void sleep_led_init(void) {
/* Make sure the clock to the LPTMR is enabled */
SIM->SCGC5 |= SIM_SCGC5_LPTMR;
/* Reset LPTMR settings */
LPTMR0->CSR = 0;
/* Set the compare value */
LPTMR0->CMR = 0; // trigger on counter value (i.e. every time)
/* Set up clock source and prescaler */
/* Software PWM
* ______ ______ __
* | ON |___OFF___| ON |___OFF___| ....
* |<-------------->|<-------------->|<- ....
* PWM period PWM period
*
* R interrupts/period[resolution]
* F periods/second[frequency]
* R * F interrupts/second
*/
/* === OPTION 1 === */
# if 0
// 1kHz LPO
// No prescaler => 1024 irqs/sec
// Note: this is too slow for a smooth breathe
LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_LPO)|LPTMRx_PSR_PBYP;
# endif /* OPTION 1 */
/* === OPTION 2 === */
# if 1
// nMHz IRC (n=4 on KL25Z, KL26Z and K20x; n=2 or 8 on KL27Z)
MCG->C2 |= MCG_C2_IRCS; // fast (4MHz) internal ref clock
# if defined(KL27) // divide the 8MHz IRC by 2, to have the same MCGIRCLK speed as others
MCG->MC |= MCG_MC_LIRC_DIV2_DIV2;
# endif /* KL27 */
MCG->C1 |= MCG_C1_IRCLKEN; // enable internal ref clock
// to work in stop mode, also MCG_C1_IREFSTEN
// Divide 4MHz by 2^N (N=6) => 62500 irqs/sec =>
// => approx F=61, R=256, duration = 4
LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_MCGIRCLK) | LPTMRx_PSR_PRESCALE(6);
# endif /* OPTION 2 */
/* === OPTION 3 === */
# if 0
// OSC output (external crystal), usually 8MHz or 16MHz
OSC0->CR |= OSC_CR_ERCLKEN; // enable ext ref clock
// to work in stop mode, also OSC_CR_EREFSTEN
// Divide by 2^N
LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_OSCERCLK)|LPTMRx_PSR_PRESCALE(7);
# endif /* OPTION 3 */
/* === END OPTIONS === */
/* Interrupt on TCF set (compare flag) */
nvicEnableVector(LPTMR0_IRQn, 2); // vector, priority
LPTMR0->CSR |= LPTMRx_CSR_TIE;
}
void sleep_led_enable(void) {
/* Enable the timer */
LPTMR0->CSR |= LPTMRx_CSR_TEN;
}
void sleep_led_disable(void) {
/* Disable the timer */
LPTMR0->CSR &= ~LPTMRx_CSR_TEN;
}
void sleep_led_toggle(void) {
/* Toggle the timer */
LPTMR0->CSR ^= LPTMRx_CSR_TEN;
}
#elif defined(SLEEP_LED_GPT_DRIVER)
static void gptTimerCallback(GPTDriver *gptp) {
(void)gptp;
sleep_led_timer_callback();
}
static const GPTConfig gptcfg = {1000000, gptTimerCallback, 0, 0};
/* Initialise the timer */
void sleep_led_init(void) { gptStart(&SLEEP_LED_GPT_DRIVER, &gptcfg); }
void sleep_led_enable(void) { gptStartContinuous(&SLEEP_LED_GPT_DRIVER, gptcfg.frequency / 0xFFFF); }
void sleep_led_disable(void) { gptStopTimer(&SLEEP_LED_GPT_DRIVER); }
void sleep_led_toggle(void) { (SLEEP_LED_GPT_DRIVER.state == GPT_READY) ? sleep_led_enable() : sleep_led_disable(); }
#else /* platform selection: not on familiar chips */
void sleep_led_init(void) {}
void sleep_led_enable(void) { led_set(1 << USB_LED_CAPS_LOCK); }
void sleep_led_disable(void) { led_set(0); }
void sleep_led_toggle(void) {
// not implemented
}
#endif /* platform selection */

View file

@ -1,92 +0,0 @@
/* TODO */
#include <ch.h>
#include <hal.h>
#include "matrix.h"
#include "action.h"
#include "action_util.h"
#include "mousekey.h"
#include "programmable_button.h"
#include "host.h"
#include "suspend.h"
#include "led.h"
#include "wait.h"
/** \brief suspend idle
*
* FIXME: needs doc
*/
void suspend_idle(uint8_t time) {
// TODO: this is not used anywhere - what units is 'time' in?
wait_ms(time);
}
/** \brief suspend power down
*
* FIXME: needs doc
*/
void suspend_power_down(void) {
suspend_power_down_quantum();
// on AVR, this enables the watchdog for 15ms (max), and goes to
// SLEEP_MODE_PWR_DOWN
wait_ms(17);
}
/** \brief suspend wakeup condition
*
* FIXME: needs doc
*/
__attribute__((weak)) void matrix_power_up(void) {}
__attribute__((weak)) void matrix_power_down(void) {}
bool suspend_wakeup_condition(void) {
matrix_power_up();
matrix_scan();
matrix_power_down();
for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
if (matrix_get_row(r)) return true;
}
return false;
}
/** \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 suspend wakeup condition
*
* run immediately after wakeup
* FIXME: needs doc
*/
void suspend_wakeup_init(void) {
// clear keyboard state
// need to do it manually, because we're running from ISR
// and clear_keyboard() calls print
// so only clear the variables in memory
// the reports will be sent from main.c afterwards
// or if the PC asks for GET_REPORT
clear_mods();
clear_weak_mods();
clear_keys();
#ifdef MOUSEKEY_ENABLE
mousekey_clear();
#endif /* MOUSEKEY_ENABLE */
#ifdef PROGRAMMABLE_BUTTON_ENABLE
programmable_button_clear();
#endif /* PROGRAMMABLE_BUTTON_ENABLE */
#ifdef EXTRAKEY_ENABLE
host_system_send(0);
host_consumer_send(0);
#endif /* EXTRAKEY_ENABLE */
suspend_wakeup_init_quantum();
}

View file

@ -1,104 +0,0 @@
/* Copyright 2021 Nick Brassel, 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 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 <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
__attribute__((weak, used)) int _open_r(struct _reent *r, const char *path, int flag, int m) {
__errno_r(r) = ENOENT;
return -1;
}
__attribute__((weak, used)) int _lseek_r(struct _reent *r, int file, int ptr, int dir) {
__errno_r(r) = EBADF;
return -1;
}
__attribute__((weak, used)) int _read_r(struct _reent *r, int file, char *ptr, int len) {
__errno_r(r) = EBADF;
return -1;
}
__attribute__((weak, used)) int _write_r(struct _reent *r, int file, char *ptr, int len) {
__errno_r(r) = EBADF;
return -1;
}
__attribute__((weak, used)) int _close_r(struct _reent *r, int file) {
__errno_r(r) = EBADF;
return -1;
}
__attribute__((weak, used)) int _link_r(struct _reent *r, const char *oldpath, const char *newpath) {
__errno_r(r) = EPERM;
return -1;
}
__attribute__((weak, used)) int _unlink_r(struct _reent *r, const char *path) {
__errno_r(r) = EPERM;
return -1;
}
__attribute__((weak, used)) clock_t _times_r(struct _reent *r, void *t) {
__errno_r(r) = EFAULT;
return -1;
}
__attribute__((weak, used)) int _fstat_r(struct _reent *r, int file, struct stat *st) {
__errno_r(r) = EBADF;
return -1;
}
__attribute__((weak, used)) int _isatty_r(struct _reent *r, int fd) {
__errno_r(r) = EBADF;
return 0;
}
__attribute__((weak, used)) caddr_t _sbrk_r(struct _reent *r, int incr) {
__errno_r(r) = ENOMEM;
return (caddr_t)-1;
}
__attribute__((weak, used)) int _kill(int pid, int sig) {
errno = EPERM;
return -1;
}
__attribute__((weak, used)) pid_t _getpid(void) { return 1; }
__attribute__((weak, used)) void _fini(void) { return; }
__attribute__((weak, used, noreturn)) void _exit(int i) {
while (1)
;
}
__attribute__((weak, used)) int _gettimeofday_r(struct _reent *r, struct timeval *t, void *tzp) {
__errno_r(r) = EPERM;
return -1;
}
__attribute__((weak, used)) void *__dso_handle;
__attribute__((weak, used)) void __cxa_pure_virtual(void) {
while (1)
;
}
#pragma GCC diagnostic pop

View file

@ -1,47 +0,0 @@
#include <ch.h>
#include "timer.h"
static uint32_t reset_point = 0;
#if CH_CFG_ST_RESOLUTION < 32
static uint32_t last_systime = 0;
static uint32_t overflow = 0;
#endif
void timer_init(void) { timer_clear(); }
void timer_clear(void) {
reset_point = (uint32_t)chVTGetSystemTime();
#if CH_CFG_ST_RESOLUTION < 32
last_systime = reset_point;
overflow = 0;
#endif
}
uint16_t timer_read(void) { return (uint16_t)timer_read32(); }
uint32_t timer_read32(void) {
uint32_t systime = (uint32_t)chVTGetSystemTime();
#if CH_CFG_ST_RESOLUTION < 32
// If/when we need to support 64-bit chips, this may need to be modified to match the native bit-ness of the MCU.
// At this point, the only SysTick resolution allowed other than 32 is 16 bit.
// In the 16-bit case, at:
// - CH_CFG_ST_FREQUENCY = 100000, overflow will occur every ~0.65 seconds
// - CH_CFG_ST_FREQUENCY = 10000, overflow will occur every ~6.5 seconds
// - CH_CFG_ST_FREQUENCY = 1000, overflow will occur every ~65 seconds
// With this implementation, as long as we ensure a timer read happens at least once during the overflow period, timing should be accurate.
if (systime < last_systime) {
overflow += ((uint32_t)1) << CH_CFG_ST_RESOLUTION;
}
last_systime = systime;
return (uint32_t)TIME_I2MS(systime - reset_point + overflow);
#else
return (uint32_t)TIME_I2MS(systime - reset_point);
#endif
}
uint16_t timer_elapsed(uint16_t last) { return TIMER_DIFF_16(timer_read(), last); }
uint32_t timer_elapsed32(uint32_t last) { return TIMER_DIFF_32(timer_read32(), last); }

View file

@ -1,41 +0,0 @@
/* 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/>.
*/
#include <ch.h>
#include <hal.h>
#include "_wait.h"
#ifdef WAIT_US_TIMER
void wait_us(uint16_t duration) {
static const GPTConfig gpt_cfg = {1000000, NULL, 0, 0}; /* 1MHz timer, no callback */
if (duration == 0) {
duration = 1;
}
/*
* Only use this timer on the main thread;
* other threads need to use their own timer.
*/
if (chThdGetSelfX() == &ch.mainthread && duration < (1ULL << (sizeof(gptcnt_t) * 8))) {
gptStart(&WAIT_US_TIMER, &gpt_cfg);
gptPolledDelay(&WAIT_US_TIMER, duration);
} else {
chThdSleepMicroseconds(duration);
}
}
#endif

View file

@ -1,21 +0,0 @@
#pragma once
#if defined(__AVR__) && !defined(EEPROM_DRIVER)
# include <avr/eeprom.h>
#else
# include <stdint.h>
# include <stdlib.h>
uint8_t eeprom_read_byte(const uint8_t *__p);
uint16_t eeprom_read_word(const uint16_t *__p);
uint32_t eeprom_read_dword(const uint32_t *__p);
void eeprom_read_block(void *__dst, const void *__src, size_t __n);
void eeprom_write_byte(uint8_t *__p, uint8_t __value);
void eeprom_write_word(uint16_t *__p, uint16_t __value);
void eeprom_write_dword(uint32_t *__p, uint32_t __value);
void eeprom_write_block(const void *__src, void *__dst, size_t __n);
void eeprom_update_byte(uint8_t *__p, uint8_t __value);
void eeprom_update_word(uint16_t *__p, uint16_t __value);
void eeprom_update_dword(uint32_t *__p, uint32_t __value);
void eeprom_update_block(const void *__src, void *__dst, size_t __n);
#endif

View file

@ -1,22 +0,0 @@
/* 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 "pin_defs.h"
#if __has_include_next("gpio.h")
# include_next "gpio.h" /* Include the platforms gpio.h */
#endif

View file

@ -1,23 +0,0 @@
/* 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
// useful for direct pin mapping
#define NO_PIN (pin_t)(~0)
#if __has_include_next("pin_defs.h")
# include_next "pin_defs.h" /* Include the platforms pin_defs.h */
#endif

View file

@ -1,19 +0,0 @@
#pragma once
#if defined(__AVR__)
# include <avr/pgmspace.h>
#else
# include <string.h>
# define PROGMEM
# define __flash
# define PSTR(x) x
# define PGM_P const char*
# define memcpy_P(dest, src, n) memcpy(dest, src, n)
# define pgm_read_byte(address_short) *((uint8_t*)(address_short))
# define pgm_read_word(address_short) *((uint16_t*)(address_short))
# define pgm_read_dword(address_short) *((uint32_t*)(address_short))
# define pgm_read_ptr(address_short) *((void**)(address_short))
# define strcmp_P(s1, s2) strcmp(s1, s2)
# define strcpy_P(dest, src) strcpy(dest, src)
# define strlen_P(src) strlen(src)
#endif

View file

@ -1,5 +0,0 @@
#pragma once
void raw_hid_receive(uint8_t *data, uint8_t length);
void raw_hid_send(uint8_t *data, uint8_t length);

View file

@ -1,17 +0,0 @@
#pragma once
#ifdef SLEEP_LED_ENABLE
void sleep_led_init(void);
void sleep_led_enable(void);
void sleep_led_disable(void);
void sleep_led_toggle(void);
#else
# define sleep_led_init()
# define sleep_led_enable()
# define sleep_led_disable()
# define sleep_led_toggle()
#endif

View file

@ -1,20 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
void suspend_idle(uint8_t timeout);
void suspend_power_down(void);
bool suspend_wakeup_condition(void);
void suspend_wakeup_init(void);
void suspend_wakeup_init_user(void);
void suspend_wakeup_init_kb(void);
void suspend_wakeup_init_quantum(void);
void suspend_power_down_user(void);
void suspend_power_down_kb(void);
void suspend_power_down_quantum(void);
#ifndef USB_SUSPEND_WAKEUP_DELAY
# define USB_SUSPEND_WAKEUP_DELAY 0
#endif

View file

@ -1,58 +0,0 @@
/*
Copyright (C) 2020 Ryan Caltabiano <https://github.com/XScorpion2>
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.
If you happen to meet one of the copyright holders in a bar you are obligated
to buy them one pint of beer.
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 "sync_timer.h"
#include "keyboard.h"
#if (defined(SPLIT_KEYBOARD) || defined(SERIAL_LINK_ENABLE)) && !defined(DISABLE_SYNC_TIMER)
volatile int32_t sync_timer_ms;
void sync_timer_init(void) { sync_timer_ms = 0; }
void sync_timer_update(uint32_t time) {
if (is_keyboard_master()) return;
sync_timer_ms = time - timer_read32();
}
uint16_t sync_timer_read(void) {
if (is_keyboard_master()) return timer_read();
return sync_timer_read32();
}
uint32_t sync_timer_read32(void) {
if (is_keyboard_master()) return timer_read32();
return sync_timer_ms + timer_read32();
}
uint16_t sync_timer_elapsed(uint16_t last) {
if (is_keyboard_master()) return timer_elapsed(last);
return TIMER_DIFF_16(sync_timer_read(), last);
}
uint32_t sync_timer_elapsed32(uint32_t last) {
if (is_keyboard_master()) return timer_elapsed32(last);
return TIMER_DIFF_32(sync_timer_read32(), last);
}
#endif

View file

@ -1,54 +0,0 @@
/*
Copyright (C) 2020 Ryan Caltabiano <https://github.com/XScorpion2>
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.
If you happen to meet one of the copyright holders in a bar you are obligated
to buy them one pint of beer.
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 <stdint.h>
#include "timer.h"
#ifdef __cplusplus
extern "C" {
#endif
#if (defined(SPLIT_KEYBOARD) || defined(SERIAL_LINK_ENABLE)) && !defined(DISABLE_SYNC_TIMER)
void sync_timer_init(void);
void sync_timer_update(uint32_t time);
uint16_t sync_timer_read(void);
uint32_t sync_timer_read32(void);
uint16_t sync_timer_elapsed(uint16_t last);
uint32_t sync_timer_elapsed32(uint32_t last);
#else
# define sync_timer_init()
# define sync_timer_clear()
# define sync_timer_update(t)
# define sync_timer_read() timer_read()
# define sync_timer_read32() timer_read32()
# define sync_timer_elapsed(t) timer_elapsed(t)
# define sync_timer_elapsed32(t) timer_elapsed32(t)
#endif
#ifdef __cplusplus
}
#endif

View file

@ -1,22 +0,0 @@
/* 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 <inttypes.h>
void wait_ms(uint32_t ms);
#define wait_us(us) wait_ms(us / 1000)
#define waitInputPinDelay()

View file

@ -1,19 +0,0 @@
/* Copyright 2017 Fred Sundvik
*
* 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 "bootloader.h"
void bootloader_jump(void) {}

View file

@ -1,95 +0,0 @@
/* Copyright 2017 Fred Sundvik
*
* 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 "eeprom.h"
#define EEPROM_SIZE 32
static uint8_t buffer[EEPROM_SIZE];
uint8_t eeprom_read_byte(const uint8_t *addr) {
uintptr_t offset = (uintptr_t)addr;
return buffer[offset];
}
void eeprom_write_byte(uint8_t *addr, uint8_t value) {
uintptr_t offset = (uintptr_t)addr;
buffer[offset] = value;
}
uint16_t eeprom_read_word(const uint16_t *addr) {
const uint8_t *p = (const uint8_t *)addr;
return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8);
}
uint32_t eeprom_read_dword(const uint32_t *addr) {
const uint8_t *p = (const uint8_t *)addr;
return eeprom_read_byte(p) | (eeprom_read_byte(p + 1) << 8) | (eeprom_read_byte(p + 2) << 16) | (eeprom_read_byte(p + 3) << 24);
}
void eeprom_read_block(void *buf, const void *addr, size_t len) {
const uint8_t *p = (const uint8_t *)addr;
uint8_t * dest = (uint8_t *)buf;
while (len--) {
*dest++ = eeprom_read_byte(p++);
}
}
void eeprom_write_word(uint16_t *addr, uint16_t value) {
uint8_t *p = (uint8_t *)addr;
eeprom_write_byte(p++, value);
eeprom_write_byte(p, value >> 8);
}
void eeprom_write_dword(uint32_t *addr, uint32_t value) {
uint8_t *p = (uint8_t *)addr;
eeprom_write_byte(p++, value);
eeprom_write_byte(p++, value >> 8);
eeprom_write_byte(p++, value >> 16);
eeprom_write_byte(p, value >> 24);
}
void eeprom_write_block(const void *buf, void *addr, size_t len) {
uint8_t * p = (uint8_t *)addr;
const uint8_t *src = (const uint8_t *)buf;
while (len--) {
eeprom_write_byte(p++, *src++);
}
}
void eeprom_update_byte(uint8_t *addr, uint8_t value) { eeprom_write_byte(addr, value); }
void eeprom_update_word(uint16_t *addr, uint16_t value) {
uint8_t *p = (uint8_t *)addr;
eeprom_write_byte(p++, value);
eeprom_write_byte(p, value >> 8);
}
void eeprom_update_dword(uint32_t *addr, uint32_t value) {
uint8_t *p = (uint8_t *)addr;
eeprom_write_byte(p++, value);
eeprom_write_byte(p++, value >> 8);
eeprom_write_byte(p++, value >> 16);
eeprom_write_byte(p, value >> 24);
}
void eeprom_update_block(const void *buf, void *addr, size_t len) {
uint8_t * p = (uint8_t *)addr;
const uint8_t *src = (const uint8_t *)buf;
while (len--) {
eeprom_write_byte(p++, *src++);
}
}

View file

@ -1,438 +0,0 @@
/* Copyright 2021 by Don Kjer
*
* 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 "gtest/gtest.h"
extern "C" {
#include "flash_stm32.h"
#include "eeprom_stm32.h"
#include "eeprom.h"
}
/* Mock Flash Parameters:
*
* === Large Layout ===
* flash size: 65536
* page size: 2048
* density pages: 16
* Simulated EEPROM size: 16384
*
* FlashBuf Layout:
* [Unused | Compact | Write Log ]
* [0......|32768......|49152......65535]
*
* === Tiny Layout ===
* flash size: 1024
* page size: 512
* density pages: 1
* Simulated EEPROM size: 256
*
* FlashBuf Layout:
* [Unused | Compact | Write Log ]
* [0......|512......|768......1023]
*
*/
#define EEPROM_SIZE (FEE_PAGE_SIZE * FEE_PAGE_COUNT / 2)
#define LOG_SIZE EEPROM_SIZE
#define LOG_BASE (MOCK_FLASH_SIZE - LOG_SIZE)
#define EEPROM_BASE (LOG_BASE - EEPROM_SIZE)
/* Log encoding helpers */
#define BYTE_VALUE(addr, value) (((addr) << 8) | (value))
#define WORD_ZERO(addr) (0x8000 | ((addr) >> 1))
#define WORD_ONE(addr) (0xA000 | ((addr) >> 1))
#define WORD_NEXT(addr) (0xE000 | (((addr)-0x80) >> 1))
class EepromStm32Test : public testing::Test {
public:
EepromStm32Test() {}
~EepromStm32Test() {}
protected:
void SetUp() override { EEPROM_Erase(); }
void TearDown() override {
#ifdef EEPROM_DEBUG
dumpEepromDataBuf();
#endif
}
};
TEST_F(EepromStm32Test, TestErase) {
EEPROM_WriteDataByte(0, 0x42);
EEPROM_Erase();
EXPECT_EQ(EEPROM_ReadDataByte(0), 0);
EXPECT_EQ(EEPROM_ReadDataByte(1), 0);
}
TEST_F(EepromStm32Test, TestReadGarbage) {
uint8_t garbage = 0x3c;
for (int i = 0; i < MOCK_FLASH_SIZE; ++i) {
garbage ^= 0xa3;
garbage += i;
FlashBuf[i] = garbage;
}
EEPROM_Init(); // Just verify we don't crash
}
TEST_F(EepromStm32Test, TestWriteBadAddress) {
EXPECT_EQ(EEPROM_WriteDataByte(EEPROM_SIZE, 0x42), FLASH_BAD_ADDRESS);
EXPECT_EQ(EEPROM_WriteDataWord(EEPROM_SIZE - 1, 0xbeef), FLASH_BAD_ADDRESS);
EXPECT_EQ(EEPROM_WriteDataWord(EEPROM_SIZE, 0xbeef), FLASH_BAD_ADDRESS);
}
TEST_F(EepromStm32Test, TestReadBadAddress) {
EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE), 0xFF);
EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 1), 0xFFFF);
EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE), 0xFFFF);
EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0);
EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 3)), 0xFF000000);
EXPECT_EQ(eeprom_read_dword((uint32_t*)EEPROM_SIZE), 0xFFFFFFFF);
}
TEST_F(EepromStm32Test, TestReadByte) {
/* Direct compacted-area baseline: Address < 0x80 */
FlashBuf[EEPROM_BASE + 2] = ~0xef;
FlashBuf[EEPROM_BASE + 3] = ~0xbe;
/* Direct compacted-area baseline: Address >= 0x80 */
FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2] = ~0x78;
FlashBuf[EEPROM_BASE + EEPROM_SIZE - 1] = ~0x56;
/* Check values */
EEPROM_Init();
EXPECT_EQ(EEPROM_ReadDataByte(2), 0xef);
EXPECT_EQ(EEPROM_ReadDataByte(3), 0xbe);
EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0x78);
EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x56);
/* Write Log byte value */
FlashBuf[LOG_BASE] = 0x65;
FlashBuf[LOG_BASE + 1] = 3;
/* Write Log word value */
*(uint16_t*)&FlashBuf[LOG_BASE + 2] = WORD_NEXT(EEPROM_SIZE - 2);
*(uint16_t*)&FlashBuf[LOG_BASE + 4] = ~0x9abc;
/* Check values */
EEPROM_Init();
EXPECT_EQ(EEPROM_ReadDataByte(2), 0xef);
EXPECT_EQ(EEPROM_ReadDataByte(3), 0x65);
EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0xbc);
EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x9a);
}
TEST_F(EepromStm32Test, TestWriteByte) {
/* Direct compacted-area baseline: Address < 0x80 */
EEPROM_WriteDataByte(2, 0xef);
EEPROM_WriteDataByte(3, 0xbe);
/* Direct compacted-area baseline: Address >= 0x80 */
EEPROM_WriteDataByte(EEPROM_SIZE - 2, 0x78);
EEPROM_WriteDataByte(EEPROM_SIZE - 1, 0x56);
/* Check values */
/* First write in each aligned word should have been direct */
EXPECT_EQ(FlashBuf[EEPROM_BASE + 2], (uint8_t)~0xef);
EXPECT_EQ(FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2], (uint8_t)~0x78);
/* Second write per aligned word requires a log entry */
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], BYTE_VALUE(3, 0xbe));
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 2], WORD_NEXT(EEPROM_SIZE - 1));
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 4], (uint16_t)~0x5678);
}
TEST_F(EepromStm32Test, TestByteRoundTrip) {
/* Direct compacted-area: Address < 0x80 */
EEPROM_WriteDataWord(0, 0xdead);
EEPROM_WriteDataByte(2, 0xef);
EEPROM_WriteDataByte(3, 0xbe);
/* Direct compacted-area: Address >= 0x80 */
EEPROM_WriteDataByte(EEPROM_SIZE - 2, 0x78);
EEPROM_WriteDataByte(EEPROM_SIZE - 1, 0x56);
/* Check values */
EEPROM_Init();
EXPECT_EQ(EEPROM_ReadDataByte(0), 0xad);
EXPECT_EQ(EEPROM_ReadDataByte(1), 0xde);
EXPECT_EQ(EEPROM_ReadDataByte(2), 0xef);
EXPECT_EQ(EEPROM_ReadDataByte(3), 0xbe);
EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0x78);
EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x56);
/* Write log entries */
EEPROM_WriteDataByte(2, 0x80);
EEPROM_WriteDataByte(EEPROM_SIZE - 2, 0x3c);
/* Check values */
EEPROM_Init();
EXPECT_EQ(EEPROM_ReadDataByte(2), 0x80);
EXPECT_EQ(EEPROM_ReadDataByte(3), 0xbe);
EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 2), 0x3c);
EXPECT_EQ(EEPROM_ReadDataByte(EEPROM_SIZE - 1), 0x56);
}
TEST_F(EepromStm32Test, TestReadWord) {
/* Direct compacted-area baseline: Address < 0x80 */
FlashBuf[EEPROM_BASE + 0] = ~0xad;
FlashBuf[EEPROM_BASE + 1] = ~0xde;
/* Direct compacted-area baseline: Address >= 0x80 */
FlashBuf[EEPROM_BASE + 200] = ~0xcd;
FlashBuf[EEPROM_BASE + 201] = ~0xab;
FlashBuf[EEPROM_BASE + EEPROM_SIZE - 4] = ~0x34;
FlashBuf[EEPROM_BASE + EEPROM_SIZE - 3] = ~0x12;
FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2] = ~0x78;
FlashBuf[EEPROM_BASE + EEPROM_SIZE - 1] = ~0x56;
/* Check values */
EEPROM_Init();
EXPECT_EQ(EEPROM_ReadDataWord(0), 0xdead);
EXPECT_EQ(EEPROM_ReadDataWord(200), 0xabcd);
EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 0x1234);
EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 0x5678);
/* Write Log word zero-encoded */
*(uint16_t*)&FlashBuf[LOG_BASE] = WORD_ZERO(200);
/* Write Log word one-encoded */
*(uint16_t*)&FlashBuf[LOG_BASE + 2] = WORD_ONE(EEPROM_SIZE - 4);
/* Write Log word value */
*(uint16_t*)&FlashBuf[LOG_BASE + 4] = WORD_NEXT(EEPROM_SIZE - 2);
*(uint16_t*)&FlashBuf[LOG_BASE + 6] = ~0x9abc;
/* Check values */
EEPROM_Init();
EXPECT_EQ(EEPROM_ReadDataWord(200), 0);
EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 1);
EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 0x9abc);
}
TEST_F(EepromStm32Test, TestWriteWord) {
/* Direct compacted-area: Address < 0x80 */
EEPROM_WriteDataWord(0, 0xdead); // Aligned
EEPROM_WriteDataWord(3, 0xbeef); // Unaligned
/* Direct compacted-area: Address >= 0x80 */
EEPROM_WriteDataWord(200, 0xabcd); // Aligned
EEPROM_WriteDataWord(203, 0x9876); // Unaligned
EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0x1234);
EEPROM_WriteDataWord(EEPROM_SIZE - 2, 0x5678);
/* Write Log word zero-encoded */
EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0);
/* Write Log word one-encoded */
EEPROM_WriteDataWord(EEPROM_SIZE - 2, 1);
/* Write Log word value aligned */
EEPROM_WriteDataWord(200, 0x4321); // Aligned
/* Write Log word value unaligned */
EEPROM_WriteDataByte(202, 0x3c); // Set neighboring byte
EEPROM_WriteDataWord(203, 0xcdef); // Unaligned
/* Check values */
/* Direct compacted-area */
EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE], (uint16_t)~0xdead);
EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + 3], (uint16_t)~0xbeef);
EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + 200], (uint16_t)~0xabcd);
EXPECT_EQ(FlashBuf[EEPROM_BASE + 203], (uint8_t)~0x76);
EXPECT_EQ(FlashBuf[EEPROM_BASE + 204], (uint8_t)~0x98);
EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + EEPROM_SIZE - 4], (uint16_t)~0x1234);
EXPECT_EQ(*(uint16_t*)&FlashBuf[EEPROM_BASE + EEPROM_SIZE - 2], (uint16_t)~0x5678);
/* Write Log word zero-encoded */
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], WORD_ZERO(EEPROM_SIZE - 4));
/* Write Log word one-encoded */
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 2], WORD_ONE(EEPROM_SIZE - 2));
/* Write Log word value aligned */
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 4], WORD_NEXT(200));
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 6], (uint16_t)~0x4321);
/* Write Log word value unaligned */
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 8], WORD_NEXT(202));
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 10], (uint16_t)~0x763c);
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 12], WORD_NEXT(202));
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 14], (uint16_t)~0xef3c);
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 16], WORD_NEXT(204));
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 18], (uint16_t)~0x00cd);
}
TEST_F(EepromStm32Test, TestWordRoundTrip) {
/* Direct compacted-area: Address < 0x80 */
EEPROM_WriteDataWord(0, 0xdead); // Aligned
EEPROM_WriteDataWord(3, 0xbeef); // Unaligned
/* Direct compacted-area: Address >= 0x80 */
EEPROM_WriteDataWord(200, 0xabcd); // Aligned
EEPROM_WriteDataWord(203, 0x9876); // Unaligned
EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0x1234);
EEPROM_WriteDataWord(EEPROM_SIZE - 2, 0x5678);
/* Check values */
EEPROM_Init();
EXPECT_EQ(EEPROM_ReadDataWord(0), 0xdead);
EXPECT_EQ(EEPROM_ReadDataWord(3), 0xbeef);
EXPECT_EQ(EEPROM_ReadDataWord(200), 0xabcd);
EXPECT_EQ(EEPROM_ReadDataWord(203), 0x9876);
EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 0x1234);
EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 0x5678);
/* Write Log word zero-encoded */
EEPROM_WriteDataWord(EEPROM_SIZE - 4, 0);
/* Write Log word one-encoded */
EEPROM_WriteDataWord(EEPROM_SIZE - 2, 1);
/* Write Log word value aligned */
EEPROM_WriteDataWord(200, 0x4321); // Aligned
/* Write Log word value unaligned */
EEPROM_WriteDataByte(202, 0x3c); // Set neighboring byte
EEPROM_WriteDataWord(203, 0xcdef); // Unaligned
/* Check values */
EEPROM_Init();
EXPECT_EQ(EEPROM_ReadDataWord(200), 0x4321);
EXPECT_EQ(EEPROM_ReadDataByte(202), 0x3c);
EXPECT_EQ(EEPROM_ReadDataWord(203), 0xcdef);
EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 4), 0);
EXPECT_EQ(EEPROM_ReadDataWord(EEPROM_SIZE - 2), 1);
}
TEST_F(EepromStm32Test, TestByteWordBoundary) {
/* Direct compacted-area write */
EEPROM_WriteDataWord(0x7e, 0xdead);
EEPROM_WriteDataWord(0x80, 0xbeef);
/* Byte log entry */
EEPROM_WriteDataByte(0x7f, 0x3c);
/* Word log entry */
EEPROM_WriteDataByte(0x80, 0x18);
/* Check values */
EEPROM_Init();
EXPECT_EQ(EEPROM_ReadDataWord(0x7e), 0x3cad);
EXPECT_EQ(EEPROM_ReadDataWord(0x80), 0xbe18);
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], BYTE_VALUE(0x7f, 0x3c));
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 2], WORD_NEXT(0x80));
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 4], (uint16_t)~0xbe18);
/* Byte log entries */
EEPROM_WriteDataWord(0x7e, 0xcafe);
/* Check values */
EEPROM_Init();
EXPECT_EQ(EEPROM_ReadDataWord(0x7e), 0xcafe);
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 6], BYTE_VALUE(0x7e, 0xfe));
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 8], BYTE_VALUE(0x7f, 0xca));
/* Byte and Word log entries */
EEPROM_WriteDataWord(0x7f, 0xba5e);
/* Check values */
EEPROM_Init();
EXPECT_EQ(EEPROM_ReadDataWord(0x7f), 0xba5e);
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 10], BYTE_VALUE(0x7f, 0x5e));
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 12], WORD_NEXT(0x80));
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 14], (uint16_t)~0xbeba);
/* Word log entry */
EEPROM_WriteDataWord(0x80, 0xf00d);
/* Check values */
EEPROM_Init();
EXPECT_EQ(EEPROM_ReadDataWord(0x80), 0xf00d);
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 16], WORD_NEXT(0x80));
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + 18], (uint16_t)~0xf00d);
}
TEST_F(EepromStm32Test, TestDWordRoundTrip) {
/* Direct compacted-area: Address < 0x80 */
eeprom_write_dword((uint32_t*)0, 0xdeadbeef); // Aligned
eeprom_write_dword((uint32_t*)9, 0x12345678); // Unaligned
/* Direct compacted-area: Address >= 0x80 */
eeprom_write_dword((uint32_t*)200, 0xfacef00d);
eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 4), 0xba5eba11); // Aligned
eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 9), 0xcafed00d); // Unaligned
/* Check direct values */
EEPROM_Init();
EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdeadbeef);
EXPECT_EQ(eeprom_read_dword((uint32_t*)9), 0x12345678);
EXPECT_EQ(eeprom_read_dword((uint32_t*)200), 0xfacef00d);
EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0xba5eba11); // Aligned
EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 9)), 0xcafed00d); // Unaligned
/* Write Log byte encoded */
eeprom_write_dword((uint32_t*)0, 0xdecafbad);
eeprom_write_dword((uint32_t*)9, 0x87654321);
/* Write Log word encoded */
eeprom_write_dword((uint32_t*)200, 1);
/* Write Log word value aligned */
eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 4), 0xdeadc0de); // Aligned
eeprom_write_dword((uint32_t*)(EEPROM_SIZE - 9), 0x6789abcd); // Unaligned
/* Check log values */
EEPROM_Init();
EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdecafbad);
EXPECT_EQ(eeprom_read_dword((uint32_t*)9), 0x87654321);
EXPECT_EQ(eeprom_read_dword((uint32_t*)200), 1);
EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 4)), 0xdeadc0de); // Aligned
EXPECT_EQ(eeprom_read_dword((uint32_t*)(EEPROM_SIZE - 9)), 0x6789abcd); // Unaligned
}
TEST_F(EepromStm32Test, TestBlockRoundTrip) {
char src0[] = "0123456789abcdef";
void* src1 = (void*)&src0[1];
/* Various alignments of src & dst, Address < 0x80 */
eeprom_write_block(src0, (void*)0, sizeof(src0));
eeprom_write_block(src0, (void*)21, sizeof(src0));
eeprom_write_block(src1, (void*)40, sizeof(src0) - 1);
eeprom_write_block(src1, (void*)61, sizeof(src0) - 1);
/* Various alignments of src & dst, Address >= 0x80 */
eeprom_write_block(src0, (void*)140, sizeof(src0));
eeprom_write_block(src0, (void*)161, sizeof(src0));
eeprom_write_block(src1, (void*)180, sizeof(src0) - 1);
eeprom_write_block(src1, (void*)201, sizeof(src0) - 1);
/* Check values */
EEPROM_Init();
char dstBuf[256] = {0};
char* dst0a = (char*)dstBuf;
char* dst0b = (char*)&dstBuf[20];
char* dst1a = (char*)&dstBuf[41];
char* dst1b = (char*)&dstBuf[61];
char* dst0c = (char*)&dstBuf[80];
char* dst0d = (char*)&dstBuf[100];
char* dst1c = (char*)&dstBuf[121];
char* dst1d = (char*)&dstBuf[141];
eeprom_read_block((void*)dst0a, (void*)0, sizeof(src0));
eeprom_read_block((void*)dst0b, (void*)21, sizeof(src0));
eeprom_read_block((void*)dst1a, (void*)40, sizeof(src0) - 1);
eeprom_read_block((void*)dst1b, (void*)61, sizeof(src0) - 1);
eeprom_read_block((void*)dst0c, (void*)140, sizeof(src0));
eeprom_read_block((void*)dst0d, (void*)161, sizeof(src0));
eeprom_read_block((void*)dst1c, (void*)180, sizeof(src0) - 1);
eeprom_read_block((void*)dst1d, (void*)201, sizeof(src0) - 1);
EXPECT_EQ(strcmp((char*)src0, dst0a), 0);
EXPECT_EQ(strcmp((char*)src0, dst0b), 0);
EXPECT_EQ(strcmp((char*)src0, dst0c), 0);
EXPECT_EQ(strcmp((char*)src0, dst0d), 0);
EXPECT_EQ(strcmp((char*)src1, dst1a), 0);
EXPECT_EQ(strcmp((char*)src1, dst1b), 0);
EXPECT_EQ(strcmp((char*)src1, dst1c), 0);
EXPECT_EQ(strcmp((char*)src1, dst1d), 0);
}
TEST_F(EepromStm32Test, TestCompaction) {
/* Direct writes */
eeprom_write_dword((uint32_t*)0, 0xdeadbeef);
eeprom_write_byte((uint8_t*)4, 0x3c);
eeprom_write_word((uint16_t*)6, 0xd00d);
eeprom_write_dword((uint32_t*)150, 0xcafef00d);
eeprom_write_dword((uint32_t*)200, 0x12345678);
/* Fill write log entries */
uint32_t i;
uint32_t val = 0xd8453c6b;
for (i = 0; i < (LOG_SIZE / (sizeof(uint32_t) * 2)); i++) {
val ^= 0x593ca5b3;
val += i;
eeprom_write_dword((uint32_t*)200, val);
}
/* Check values pre-compaction */
EEPROM_Init();
EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdeadbeef);
EXPECT_EQ(eeprom_read_byte((uint8_t*)4), 0x3c);
EXPECT_EQ(eeprom_read_word((uint16_t*)6), 0xd00d);
EXPECT_EQ(eeprom_read_dword((uint32_t*)150), 0xcafef00d);
EXPECT_EQ(eeprom_read_dword((uint32_t*)200), val);
EXPECT_NE(*(uint16_t*)&FlashBuf[LOG_BASE], 0xFFFF);
EXPECT_NE(*(uint16_t*)&FlashBuf[LOG_BASE + LOG_SIZE - 2], 0xFFFF);
/* Run compaction */
eeprom_write_byte((uint8_t*)4, 0x1f);
EEPROM_Init();
EXPECT_EQ(eeprom_read_dword((uint32_t*)0), 0xdeadbeef);
EXPECT_EQ(eeprom_read_byte((uint8_t*)4), 0x1f);
EXPECT_EQ(eeprom_read_word((uint16_t*)6), 0xd00d);
EXPECT_EQ(eeprom_read_dword((uint32_t*)150), 0xcafef00d);
EXPECT_EQ(eeprom_read_dword((uint32_t*)200), val);
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE], 0xFFFF);
EXPECT_EQ(*(uint16_t*)&FlashBuf[LOG_BASE + LOG_SIZE - 2], 0xFFFF);
}

View file

@ -1,49 +0,0 @@
/* Copyright 2021 by Don Kjer
*
* 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 <string.h>
#include <stdbool.h>
#include "flash_stm32.h"
uint8_t FlashBuf[MOCK_FLASH_SIZE] = {0};
static bool flash_locked = true;
FLASH_Status FLASH_ErasePage(uint32_t Page_Address) {
if (flash_locked) return FLASH_ERROR_WRP;
Page_Address -= (uintptr_t)FlashBuf;
Page_Address -= (Page_Address % FEE_PAGE_SIZE);
if (Page_Address >= MOCK_FLASH_SIZE) return FLASH_BAD_ADDRESS;
memset(&FlashBuf[Page_Address], '\xff', FEE_PAGE_SIZE);
return FLASH_COMPLETE;
}
FLASH_Status FLASH_ProgramHalfWord(uint32_t Address, uint16_t Data) {
if (flash_locked) return FLASH_ERROR_WRP;
Address -= (uintptr_t)FlashBuf;
if (Address >= MOCK_FLASH_SIZE) return FLASH_BAD_ADDRESS;
uint16_t oldData = *(uint16_t*)&FlashBuf[Address];
if (oldData == 0xFFFF || Data == 0) {
*(uint16_t*)&FlashBuf[Address] = Data;
return FLASH_COMPLETE;
} else {
return FLASH_ERROR_PG;
}
}
FLASH_Status FLASH_WaitForLastOperation(uint32_t Timeout) { return FLASH_COMPLETE; }
void FLASH_Unlock(void) { flash_locked = false; }
void FLASH_Lock(void) { flash_locked = true; }

View file

@ -1,18 +0,0 @@
/* 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
// Just here to please eeprom tests

View file

@ -1,21 +0,0 @@
/* 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/>.
*/
#include "platform_deps.h"
void platform_setup(void) {
// do nothing
}

View file

@ -1,18 +0,0 @@
/* 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
// here just to please the build

View file

@ -1,18 +0,0 @@
/* 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
// here just to please the build

View file

@ -1,24 +0,0 @@
eeprom_stm32_DEFS := -DFLASH_STM32_MOCKED -DNO_PRINT -DFEE_FLASH_BASE=FlashBuf
eeprom_stm32_tiny_DEFS := $(eeprom_stm32_DEFS) \
-DFEE_MCU_FLASH_SIZE=1 \
-DMOCK_FLASH_SIZE=1024 \
-DFEE_PAGE_SIZE=512 \
-DFEE_PAGE_COUNT=1
eeprom_stm32_large_DEFS := $(eeprom_stm32_DEFS) \
-DFEE_MCU_FLASH_SIZE=64 \
-DMOCK_FLASH_SIZE=65536 \
-DFEE_PAGE_SIZE=2048 \
-DFEE_PAGE_COUNT=16
eeprom_stm32_INC := \
$(TMK_PATH)/common/chibios/
eeprom_stm32_tiny_INC := $(eeprom_stm32_INC)
eeprom_stm32_large_INC := $(eeprom_stm32_INC)
eeprom_stm32_SRC := \
$(TOP_DIR)/drivers/eeprom/eeprom_driver.c \
$(TMK_PATH)/common/test/eeprom_stm32_tests.cpp \
$(TMK_PATH)/common/test/flash_stm32_mock.c \
$(TMK_PATH)/common/chibios/eeprom_stm32.c
eeprom_stm32_tiny_SRC := $(eeprom_stm32_SRC)
eeprom_stm32_large_SRC := $(eeprom_stm32_SRC)

View file

@ -1,15 +0,0 @@
/* Copyright 2017 Fred Sundvik
*
* 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/>.
*/

View file

@ -1 +0,0 @@
TEST_LIST += eeprom_stm32_tiny eeprom_stm32_large

View file

@ -1,33 +0,0 @@
/* Copyright 2017 Fred Sundvik
*
* 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"
static uint32_t current_time = 0;
void timer_init(void) { current_time = 0; }
void timer_clear(void) { current_time = 0; }
uint16_t timer_read(void) { return current_time & 0xFFFF; }
uint32_t timer_read32(void) { return current_time; }
uint16_t timer_elapsed(uint16_t last) { return TIMER_DIFF_16(timer_read(), last); }
uint32_t timer_elapsed32(uint32_t last) { return TIMER_DIFF_32(timer_read32(), last); }
void set_time(uint32_t t) { current_time = t; }
void advance_time(uint32_t ms) { current_time += ms; }
void wait_ms(uint32_t ms) { advance_time(ms); }

View file

@ -1,67 +0,0 @@
/*
Copyright 2011 Jun Wako <wakojun@gmail.com>
Copyright 2021 Simon Arlott
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if __has_include_next("_timer.h")
# include_next "_timer.h" /* Include the platform's _timer.h */
#endif
#include <stdint.h>
#define TIMER_DIFF(a, b, max) ((max == UINT8_MAX) ? ((uint8_t)((a) - (b))) : ((max == UINT16_MAX) ? ((uint16_t)((a) - (b))) : ((max == UINT32_MAX) ? ((uint32_t)((a) - (b))) : ((a) >= (b) ? (a) - (b) : (max) + 1 - (b) + (a)))))
#define TIMER_DIFF_8(a, b) TIMER_DIFF(a, b, UINT8_MAX)
#define TIMER_DIFF_16(a, b) TIMER_DIFF(a, b, UINT16_MAX)
#define TIMER_DIFF_32(a, b) TIMER_DIFF(a, b, UINT32_MAX)
#define TIMER_DIFF_RAW(a, b) TIMER_DIFF_8(a, b)
#ifdef __cplusplus
extern "C" {
#endif
extern volatile uint32_t timer_count;
void timer_init(void);
void timer_clear(void);
uint16_t timer_read(void);
uint32_t timer_read32(void);
uint16_t timer_elapsed(uint16_t last);
uint32_t timer_elapsed32(uint32_t last);
// Utility functions to check if a future time has expired & autmatically handle time wrapping if checked / reset frequently (half of max value)
#define timer_expired(current, future) ((uint16_t)(current - future) < UINT16_MAX / 2)
#define timer_expired32(current, future) ((uint32_t)(current - future) < UINT32_MAX / 2)
// Use an appropriate timer integer size based on architecture (16-bit will overflow sooner)
#if FAST_TIMER_T_SIZE < 32
# define TIMER_DIFF_FAST(a, b) TIMER_DIFF_16(a, b)
# define timer_expired_fast(current, future) timer_expired(current, future)
typedef uint16_t fast_timer_t;
fast_timer_t inline timer_read_fast(void) { return timer_read(); }
fast_timer_t inline timer_elapsed_fast(fast_timer_t last) { return timer_elapsed(last); }
#else
# define TIMER_DIFF_FAST(a, b) TIMER_DIFF_32(a, b)
# define timer_expired_fast(current, future) timer_expired32(current, future)
typedef uint32_t fast_timer_t;
fast_timer_t inline timer_read_fast(void) { return timer_read32(); }
fast_timer_t inline timer_elapsed_fast(fast_timer_t last) { return timer_elapsed32(last); }
#endif
#ifdef __cplusplus
}
#endif

View file

@ -1,7 +0,0 @@
#pragma once
/* Define this function in your code to process incoming bytes */
void virtser_recv(const uint8_t ch);
/* Call this to send a character over the Virtual Serial Device */
void virtser_send(const uint8_t byte);

View file

@ -1,30 +0,0 @@
/* 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 <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
#if __has_include_next("_wait.h")
# include_next "_wait.h" /* Include the platforms _wait.h */
#endif
#ifdef __cplusplus
}
#endif

View file

@ -1,34 +0,0 @@
SYSTEM_TYPE := $(shell gcc -dumpmachine)
GCC_VERSION := $(shell gcc --version 2>/dev/null)
CC = gcc
OBJCOPY =
OBJDUMP =
SIZE =
AR =
NM =
HEX =
EEP =
BIN =
COMPILEFLAGS += -funsigned-char
ifeq ($(findstring clang, ${GCC_VERSION}),)
COMPILEFLAGS += -funsigned-bitfields
endif
COMPILEFLAGS += -ffunction-sections
COMPILEFLAGS += -fdata-sections
COMPILEFLAGS += -fshort-enums
ifneq ($(findstring mingw, ${SYSTEM_TYPE}),)
COMPILEFLAGS += -mno-ms-bitfields
endif
CFLAGS += $(COMPILEFLAGS)
ifeq ($(findstring clang, ${GCC_VERSION}),)
CFLAGS += -fno-inline-small-functions
endif
CFLAGS += -fno-strict-aliasing
CXXFLAGS += $(COMPILEFLAGS)
CXXFLAGS += -fno-exceptions
CXXFLAGS += -std=gnu++11

View file

@ -1,57 +1,83 @@
PROTOCOL_DIR = protocol
TMK_COMMON_SRC += \
$(PROTOCOL_DIR)/host.c \
$(PROTOCOL_DIR)/report.c \
$(PROTOCOL_DIR)/usb_device_state.c \
$(PROTOCOL_DIR)/usb_util.c \
ifeq ($(strip $(PS2_MOUSE_ENABLE)), yes)
SRC += $(PROTOCOL_DIR)/ps2_mouse.c
OPT_DEFS += -DPS2_MOUSE_ENABLE
SHARED_EP_ENABLE = no
MOUSE_SHARED_EP ?= yes
ifeq ($(strip $(KEYBOARD_SHARED_EP)), yes)
TMK_COMMON_DEFS += -DKEYBOARD_SHARED_EP
SHARED_EP_ENABLE = yes
# With the current usb_descriptor.c code,
# you can't share kbd without sharing mouse;
# that would be a very unexpected use case anyway
MOUSE_SHARED_EP = yes
endif
ifeq ($(strip $(MOUSE_ENABLE)), yes)
OPT_DEFS += -DMOUSE_ENABLE
ifeq ($(strip $(MOUSE_SHARED_EP)), yes)
TMK_COMMON_DEFS += -DMOUSE_SHARED_EP
SHARED_EP_ENABLE = yes
endif
endif
ifeq ($(strip $(PS2_USE_BUSYWAIT)), yes)
SRC += protocol/ps2_busywait.c
SRC += protocol/ps2_io_avr.c
OPT_DEFS += -DPS2_USE_BUSYWAIT
ifeq ($(strip $(EXTRAKEY_ENABLE)), yes)
TMK_COMMON_DEFS += -DEXTRAKEY_ENABLE
SHARED_EP_ENABLE = yes
endif
ifeq ($(strip $(PS2_USE_INT)), yes)
SRC += protocol/ps2_interrupt.c
SRC += protocol/ps2_io_$(PLATFORM_KEY).c
OPT_DEFS += -DPS2_USE_INT
ifeq ($(strip $(RAW_ENABLE)), yes)
TMK_COMMON_DEFS += -DRAW_ENABLE
endif
ifeq ($(strip $(PS2_USE_USART)), yes)
SRC += protocol/ps2_usart.c
SRC += protocol/ps2_io_$(PLATFORM_KEY).c
OPT_DEFS += -DPS2_USE_USART
ifeq ($(strip $(CONSOLE_ENABLE)), yes)
TMK_COMMON_DEFS += -DCONSOLE_ENABLE
else
# TODO: decouple this so other print backends can exist
TMK_COMMON_DEFS += -DNO_PRINT
TMK_COMMON_DEFS += -DNO_DEBUG
endif
ifeq ($(strip $(SERIAL_MOUSE_MICROSOFT_ENABLE)), yes)
SRC += $(PROTOCOL_DIR)/serial_mouse_microsoft.c
OPT_DEFS += -DSERIAL_MOUSE_ENABLE -DSERIAL_MOUSE_MICROSOFT \
-DMOUSE_ENABLE
ifeq ($(strip $(NKRO_ENABLE)), yes)
ifeq ($(PROTOCOL), VUSB)
$(info NKRO is not currently supported on V-USB, and has been disabled.)
else ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
$(info NKRO is not currently supported with Bluetooth, and has been disabled.)
else
TMK_COMMON_DEFS += -DNKRO_ENABLE
SHARED_EP_ENABLE = yes
endif
endif
ifeq ($(strip $(SERIAL_MOUSE_MOUSESYSTEMS_ENABLE)), yes)
SRC += $(PROTOCOL_DIR)/serial_mouse_mousesystems.c
OPT_DEFS += -DSERIAL_MOUSE_ENABLE -DSERIAL_MOUSE_MOUSESYSTEMS \
-DMOUSE_ENABLE
ifeq ($(strip $(RING_BUFFERED_6KRO_REPORT_ENABLE)), yes)
TMK_COMMON_DEFS += -DRING_BUFFERED_6KRO_REPORT_ENABLE
endif
ifeq ($(strip $(SERIAL_MOUSE_USE_SOFT)), yes)
SRC += $(PROTOCOL_DIR)/serial_soft.c
ifeq ($(strip $(NO_SUSPEND_POWER_DOWN)), yes)
TMK_COMMON_DEFS += -DNO_SUSPEND_POWER_DOWN
endif
ifeq ($(strip $(SERIAL_MOUSE_USE_UART)), yes)
SRC += $(PROTOCOL_DIR)/serial_uart.c
ifeq ($(strip $(NO_USB_STARTUP_CHECK)), yes)
TMK_COMMON_DEFS += -DNO_USB_STARTUP_CHECK
endif
ifeq ($(strip $(ADB_MOUSE_ENABLE)), yes)
OPT_DEFS += -DADB_MOUSE_ENABLE -DMOUSE_ENABLE
ifeq ($(strip $(DIGITIZER_SHARED_EP)), yes)
TMK_COMMON_DEFS += -DDIGITIZER_SHARED_EP
SHARED_EP_ENABLE = yes
endif
ifeq ($(strip $(XT_ENABLE)), yes)
SRC += $(PROTOCOL_DIR)/xt_interrupt.c
OPT_DEFS += -DXT_ENABLE
ifeq ($(strip $(DIGITIZER_ENABLE)), yes)
TMK_COMMON_DEFS += -DDIGITIZER_ENABLE
ifeq ($(strip $(SHARED_EP_ENABLE)), yes)
TMK_COMMON_DEFS += -DDIGITIZER_SHARED_EP
SHARED_EP_ENABLE = yes
endif
endif
ifeq ($(strip $(SHARED_EP_ENABLE)), yes)
TMK_COMMON_DEFS += -DSHARED_EP_ENABLE
endif
ifeq ($(strip $(USB_HID_ENABLE)), yes)

View file

@ -1,535 +0,0 @@
/*
Copyright 2011-19 Jun WAKO <wakojun@gmail.com>
Copyright 2013 Shay Green <gblargg@gmail.com>
This software is licensed with a Modified BSD License.
All of this is supposed to be Free Software, Open Source, DFSG-free,
GPL-compatible, and OK to use in both free and proprietary applications.
Additions and corrections to this file are welcome.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdbool.h>
#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "adb.h"
#include "print.h"
// GCC doesn't inline functions normally
#define data_lo() (ADB_DDR |= (1 << ADB_DATA_BIT))
#define data_hi() (ADB_DDR &= ~(1 << ADB_DATA_BIT))
#define data_in() (ADB_PIN & (1 << ADB_DATA_BIT))
#ifdef ADB_PSW_BIT
static inline void psw_lo(void);
static inline void psw_hi(void);
static inline bool psw_in(void);
#endif
static inline void attention(void);
static inline void place_bit0(void);
static inline void place_bit1(void);
static inline void send_byte(uint8_t data);
static inline uint16_t wait_data_lo(uint16_t us);
static inline uint16_t wait_data_hi(uint16_t us);
void adb_host_init(void) {
ADB_PORT &= ~(1 << ADB_DATA_BIT);
data_hi();
#ifdef ADB_PSW_BIT
psw_hi();
#endif
}
#ifdef ADB_PSW_BIT
bool adb_host_psw(void) { return psw_in(); }
#endif
/*
* Don't call this in a row without the delay, otherwise it makes some of poor controllers
* overloaded and misses strokes. Recommended interval is 12ms.
*
* Thanks a lot, blargg!
* <http://geekhack.org/index.php?topic=14290.msg1068919#msg1068919>
* <http://geekhack.org/index.php?topic=14290.msg1070139#msg1070139>
*/
uint16_t adb_host_kbd_recv(void) { return adb_host_talk(ADB_ADDR_KEYBOARD, ADB_REG_0); }
#ifdef ADB_MOUSE_ENABLE
__attribute__((weak)) void adb_mouse_init(void) { return; }
__attribute__((weak)) void adb_mouse_task(void) { return; }
uint16_t adb_host_mouse_recv(void) { return adb_host_talk(ADB_ADDR_MOUSE, ADB_REG_0); }
#endif
// This sends Talk command to read data from register and returns length of the data.
uint8_t adb_host_talk_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len) {
for (int8_t i = 0; i < len; i++) buf[i] = 0;
cli();
attention();
send_byte((addr << 4) | ADB_CMD_TALK | reg);
place_bit0(); // Stopbit(0)
// TODO: Service Request(Srq):
// Device holds low part of comannd stopbit for 140-260us
//
// Command:
// ......._ ______________________ ___ ............_ -------
// | | | | | | |
// Command | | | | | Data bytes | |
// ........|___| | 140-260 |__| |_............|___|
// |stop0 | Tlt Stop-to-Start |start1| |stop0 |
//
// Command without data:
// ......._ __________________________
// | |
// Command | |
// ........|___| | 140-260 |
// |stop0 | Tlt Stop-to-Start |
//
// Service Request:
// ......._ ______ ___ ............_ -------
// | 140-260 | | | | | |
// Command | Service Request | | | | Data bytes | |
// ........|___________________| |__| |_............|___|
// |stop0 | |start1| |stop0 |
// ......._ __________
// | 140-260 |
// Command | Service Request |
// ........|___________________|
// |stop0 |
// This can be happened?
// ......._ ______________________ ___ ............_ -----
// | | | | | | 140-260 |
// Command | | | | | Data bytes | Service Request |
// ........|___| | 140-260 |__| |_............|_________________|
// |stop0 | Tlt Stop-to-Start |start1| |stop0 |
//
// "Service requests are issued by the devices during a very specific time at the
// end of the reception of the command packet.
// If a device in need of service issues a service request, it must do so within
// the 65 µs of the Stop Bits low time and maintain the line low for a total of 300 µs."
//
// "A device sends a Service Request signal by holding the bus low during the low
// portion of the stop bit of any command or data transaction. The device must lengthen
// the stop by a minimum of 140 J.lS beyond its normal duration, as shown in Figure 8-15."
// http://ww1.microchip.com/downloads/en/AppNotes/00591b.pdf
if (!wait_data_hi(500)) { // Service Request(310us Adjustable Keyboard): just ignored
xprintf("R");
sei();
return 0;
}
if (!wait_data_lo(500)) { // Tlt/Stop to Start(140-260us)
sei();
return 0; // No data from device(not error);
}
// start bit(1)
if (!wait_data_hi(40)) {
xprintf("S");
sei();
return 0;
}
if (!wait_data_lo(100)) {
xprintf("s");
sei();
return 0;
}
uint8_t n = 0; // bit count
do {
//
// |<- bit_cell_max(130) ->|
// | |<- lo ->|
// | | |<-hi->|
// _______
// | | |
// | 130-lo | lo-hi |
// |________| |
//
uint8_t lo = (uint8_t)wait_data_hi(130);
if (!lo) goto error; // no more bit or after stop bit
uint8_t hi = (uint8_t)wait_data_lo(lo);
if (!hi) goto error; // stop bit extedned by Srq?
if (n / 8 >= len) continue; // can't store in buf
buf[n / 8] <<= 1;
if ((130 - lo) < (lo - hi)) {
buf[n / 8] |= 1;
}
} while (++n);
error:
sei();
return n / 8;
}
uint16_t adb_host_talk(uint8_t addr, uint8_t reg) {
uint8_t len;
uint8_t buf[8];
len = adb_host_talk_buf(addr, reg, buf, 8);
if (len != 2) return 0;
return (buf[0] << 8 | buf[1]);
}
void adb_host_listen_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len) {
cli();
attention();
send_byte((addr << 4) | ADB_CMD_LISTEN | reg);
place_bit0(); // Stopbit(0)
// TODO: Service Request
_delay_us(200); // Tlt/Stop to Start
place_bit1(); // Startbit(1)
for (int8_t i = 0; i < len; i++) {
send_byte(buf[i]);
// xprintf("%02X ", buf[i]);
}
place_bit0(); // Stopbit(0);
sei();
}
void adb_host_listen(uint8_t addr, uint8_t reg, uint8_t data_h, uint8_t data_l) {
uint8_t buf[2] = {data_h, data_l};
adb_host_listen_buf(addr, reg, buf, 2);
}
void adb_host_flush(uint8_t addr) {
cli();
attention();
send_byte((addr << 4) | ADB_CMD_FLUSH);
place_bit0(); // Stopbit(0)
_delay_us(200); // Tlt/Stop to Start
sei();
}
// send state of LEDs
void adb_host_kbd_led(uint8_t led) {
// Listen Register2
// upper byte: not used
// lower byte: bit2=ScrollLock, bit1=CapsLock, bit0=NumLock
adb_host_listen(ADB_ADDR_KEYBOARD, ADB_REG_2, 0, led & 0x07);
}
#ifdef ADB_PSW_BIT
static inline void psw_lo() {
ADB_DDR |= (1 << ADB_PSW_BIT);
ADB_PORT &= ~(1 << ADB_PSW_BIT);
}
static inline void psw_hi() {
ADB_PORT |= (1 << ADB_PSW_BIT);
ADB_DDR &= ~(1 << ADB_PSW_BIT);
}
static inline bool psw_in() {
ADB_PORT |= (1 << ADB_PSW_BIT);
ADB_DDR &= ~(1 << ADB_PSW_BIT);
return ADB_PIN & (1 << ADB_PSW_BIT);
}
#endif
static inline void attention(void) {
data_lo();
_delay_us(800 - 35); // bit1 holds lo for 35 more
place_bit1();
}
static inline void place_bit0(void) {
data_lo();
_delay_us(65);
data_hi();
_delay_us(35);
}
static inline void place_bit1(void) {
data_lo();
_delay_us(35);
data_hi();
_delay_us(65);
}
static inline void send_byte(uint8_t data) {
for (int i = 0; i < 8; i++) {
if (data & (0x80 >> i))
place_bit1();
else
place_bit0();
}
}
// These are carefully coded to take 6 cycles of overhead.
// inline asm approach became too convoluted
static inline uint16_t wait_data_lo(uint16_t us) {
do {
if (!data_in()) break;
_delay_us(1 - (6 * 1000000.0 / F_CPU));
} while (--us);
return us;
}
static inline uint16_t wait_data_hi(uint16_t us) {
do {
if (data_in()) break;
_delay_us(1 - (6 * 1000000.0 / F_CPU));
} while (--us);
return us;
}
/*
ADB Protocol
============
Resources
---------
ADB - The Untold Story: Space Aliens Ate My Mouse
http://developer.apple.com/legacy/mac/library/#technotes/hw/hw_01.html
ADB Manager
http://developer.apple.com/legacy/mac/library/documentation/mac/pdf/Devices/ADB_Manager.pdf
Service request(5-17)
Apple IIgs Hardware Reference Second Edition [Chapter6 p121]
ftp://ftp.apple.asimov.net/pub/apple_II/documentation/Apple%20IIgs%20Hardware%20Reference.pdf
ADB Keycode
http://72.0.193.250/Documentation/macppc/adbkeycodes/
http://m0115.web.fc2.com/m0115.jpg
[Inside Macintosh volume V, pages 191-192]
http://www.opensource.apple.com/source/IOHIDFamily/IOHIDFamily-421.18.3/IOHIDFamily/Cosmo_USB2ADB.c
ADB Signaling
http://kbdbabel.sourceforge.net/doc/kbd_signaling_pcxt_ps2_adb.pdf
ADB Overview & History
http://en.wikipedia.org/wiki/Apple_Desktop_Bus
Microchip Application Note: ADB device(with code for PIC16C)
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1824&appnote=en011062
AVR ATtiny2131 ADB to PS/2 converter(Japanese)
http://hp.vector.co.jp/authors/VA000177/html/KeyBoardA5DEA5CBA5A2II.html
Pinouts
-------
ADB female socket from the front:
__________
| | <--- top
| 4o o3 |
|2o o1|
| == |
|________| <--- bottom
| | <--- 4pins
ADB female socket from bottom:
========== <--- front
| |
| |
|2o o1|
|4o o3|
---------- <--- back
1: Data
2: Power SW(low when press Power key)
3: Vcc(5V)
4: GND
Commands
--------
ADB command is 1byte and consists of 4bit-address, 2bit-command
type and 2bit-register. The commands are always sent by Host.
Command format:
7 6 5 4 3 2 1 0
| | | |------------ address
| |-------- command type
| |---- register
bits commands
------------------------------------------------------
- - - - 0 0 0 0 Send Reset(reset all devices)
A A A A 0 0 0 1 Flush(reset a device)
- - - - 0 0 1 0 Reserved
- - - - 0 0 1 1 Reserved
- - - - 0 1 - - Reserved
A A A A 1 0 R R Listen(write to a device)
A A A A 1 1 R R Talk(read from a device)
The command to read keycodes from keyboard is 0x2C which
consist of keyboard address 2 and Talk against register 0.
Address:
2: keyboard
3: mice
Registers:
0: application(keyboard uses this to store its data.)
1: application
2: application(keyboard uses this for LEDs and state of modifiers)
3: status and command
Communication
-------------
This is a minimum information for keyboard communication.
See "Resources" for detail.
Signaling:
~~~~____________~~||||||||||||__~~~~~_~~|||||||||||||||__~~~~
|800us | |7 Command 0| | | |15-64 Data 0|Stopbit(0)
+Attention | | | +Startbit(1)
+Startbit(1) | +Tlt(140-260us)
+stopbit(0)
Bit cells:
bit0: ______~~~
65 :35us
bit1: ___~~~~~~
35 :65us
bit0 low time: 60-70% of bit cell(42-91us)
bit1 low time: 30-40% of bit cell(21-52us)
bit cell time: 70-130us
[from Apple IIgs Hardware Reference Second Edition]
Criterion for bit0/1:
After 55us if line is low/high then bit is 0/1.
Attention & start bit:
Host asserts low in 560-1040us then places start bit(1).
Tlt(Stop to Start):
Bus stays high in 140-260us then device places start bit(1).
Global reset:
Host asserts low in 2.8-5.2ms. All devices are forced to reset.
Service request from device(Srq):
Device can request to send at commad(Global only?) stop bit.
Requesting device keeps low for 140-260us at stop bit of command.
Keyboard Data(Register0)
This 16bit data can contains two keycodes and two released flags.
First keycode is palced in upper byte. When one keyocode is sent,
lower byte is 0xFF.
Release flag is 1 when key is released.
1514 . . . . . 8 7 6 . . . . . 0
| | | | | | | | | +-+-+-+-+-+-+- Keycode2
| | | | | | | | +--------------- Released2(1 when the key is released)
| +-+-+-+-+-+-+----------------- Keycode1
+------------------------------- Released1(1 when the key is released)
Keycodes:
Scancode consists of 7bit keycode and 1bit release flag.
Device can send two keycodes at once. If just one keycode is sent
keycode1 contains it and keyocode2 is 0xFF.
Power switch:
You can read the state from PSW line(active low) however
the switch has a special scancode 0x7F7F, so you can
also read from Data line. It uses 0xFFFF for release scancode.
Keyboard LEDs & state of keys(Register2)
This register hold current state of three LEDs and nine keys.
The state of LEDs can be changed by sending Listen command.
1514 . . . . . . 7 6 5 . 3 2 1 0
| | | | | | | | | | | | | | | +- LED1(NumLock)
| | | | | | | | | | | | | | +--- LED2(CapsLock)
| | | | | | | | | | | | | +----- LED3(ScrollLock)
| | | | | | | | | | +-+-+------- Reserved
| | | | | | | | | +------------- ScrollLock
| | | | | | | | +--------------- NumLock
| | | | | | | +----------------- Apple/Command
| | | | | | +------------------- Option
| | | | | +--------------------- Shift
| | | | +----------------------- Control
| | | +------------------------- Reset/Power
| | +--------------------------- CapsLock
| +----------------------------- Delete
+------------------------------- Reserved
Address, Handler ID and bits(Register3)
1514131211 . . 8 7 . . . . . . 0
| | | | | | | | | | | | | | | |
| | | | | | | | +-+-+-+-+-+-+-+- Handler ID
| | | | +-+-+-+----------------- Address
| | | +------------------------- 0
| | +--------------------------- Service request enable(1 = enabled)
| +----------------------------- Exceptional event(alwyas 1 if not used)
+------------------------------- 0
ADB Bit Cells
bit cell time: 70-130us
low part of bit0: 60-70% of bit cell
low part of bit1: 30-40% of bit cell
bit cell time 70us 130us
--------------------------------------------
low part of bit0 42-49 78-91
high part of bit0 21-28 39-52
low part of bit1 21-28 39-52
high part of bit1 42-49 78-91
bit0:
70us bit cell:
____________~~~~~~
42-49 21-28
130us bit cell:
____________~~~~~~
78-91 39-52
bit1:
70us bit cell:
______~~~~~~~~~~~~
21-28 42-49
130us bit cell:
______~~~~~~~~~~~~
39-52 78-91
[from Apple IIgs Hardware Reference Second Edition]
Keyboard Handle ID
Apple Standard Keyboard M0116: 0x01
Apple Extended Keyboard M0115: 0x02
Apple Extended Keyboard II M3501: 0x02
Apple Adjustable Keybaord: 0x10
http://lxr.free-electrons.com/source/drivers/macintosh/adbhid.c?v=4.4#L802
END_OF_ADB
*/

View file

@ -1,106 +0,0 @@
/*
Copyright 2011-19 Jun WAKO <wakojun@gmail.com>
This software is licensed with a Modified BSD License.
All of this is supposed to be Free Software, Open Source, DFSG-free,
GPL-compatible, and OK to use in both free and proprietary applications.
Additions and corrections to this file are welcome.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#if !(defined(ADB_PORT) && defined(ADB_PIN) && defined(ADB_DDR) && defined(ADB_DATA_BIT))
# error "ADB port setting is required in config.h"
#endif
#define ADB_POWER 0x7F
#define ADB_CAPS 0x39
/* ADB commands */
// Default Address
#define ADB_ADDR_0 0
#define ADB_ADDR_DONGLE 1
#define ADB_ADDR_KEYBOARD 2
#define ADB_ADDR_MOUSE 3
#define ADB_ADDR_TABLET 4
#define ADB_ADDR_APPLIANCE 7
#define ADB_ADDR_8 8
#define ADB_ADDR_9 9
#define ADB_ADDR_10 10
#define ADB_ADDR_11 11
#define ADB_ADDR_12 12
#define ADB_ADDR_13 13
#define ADB_ADDR_14 14
#define ADB_ADDR_15 15
// for temporary purpose, do not use for polling
#define ADB_ADDR_TMP 15
#define ADB_ADDR_MOUSE_POLL 10
// Command Type
#define ADB_CMD_RESET 0
#define ADB_CMD_FLUSH 1
#define ADB_CMD_LISTEN 8
#define ADB_CMD_TALK 12
// Register
#define ADB_REG_0 0
#define ADB_REG_1 1
#define ADB_REG_2 2
#define ADB_REG_3 3
/* ADB keyboard handler id */
#define ADB_HANDLER_STD 0x01 /* IIGS, M0116 */
#define ADB_HANDLER_AEK 0x02 /* M0115, M3501 */
#define ADB_HANDLER_AEK_RMOD 0x03 /* M0115, M3501, alternate mode enableing right modifiers */
#define ADB_HANDLER_STD_ISO 0x04 /* M0118, ISO swapping keys */
#define ADB_HANDLER_AEK_ISO 0x05 /* M0115, M3501, ISO swapping keys */
#define ADB_HANDLER_M1242_ANSI 0x10 /* Adjustable keyboard */
#define ADB_HANDLER_CLASSIC1_MOUSE 0x01
#define ADB_HANDLER_CLASSIC2_MOUSE 0x02
#define ADB_HANDLER_EXTENDED_MOUSE 0x04
#define ADB_HANDLER_TURBO_MOUSE 0x32
// ADB host
void adb_host_init(void);
bool adb_host_psw(void);
uint16_t adb_host_talk(uint8_t addr, uint8_t reg);
uint8_t adb_host_talk_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len);
void adb_host_listen(uint8_t addr, uint8_t reg, uint8_t data_h, uint8_t data_l);
void adb_host_listen_buf(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t len);
void adb_host_flush(uint8_t addr);
void adb_host_kbd_led(uint8_t led);
uint16_t adb_host_kbd_recv(void);
uint16_t adb_host_mouse_recv(void);
// ADB Mouse
void adb_mouse_task(void);
void adb_mouse_init(void);

View file

@ -9,7 +9,8 @@ ifeq ($(RGB_MATRIX_DRIVER),custom)
SRC += $(ARM_ATSAM_DIR)/md_rgb_matrix.c
endif
SRC += $(ARM_ATSAM_DIR)/main_arm_atsam.c
SRC += $(ARM_ATSAM_DIR)/spi.c
SRC += $(ARM_ATSAM_DIR)/shift_register.c
SRC += $(ARM_ATSAM_DIR)/spi_master.c
SRC += $(ARM_ATSAM_DIR)/startup.c
SRC += $(ARM_ATSAM_DIR)/usb/main_usb.c
@ -19,10 +20,12 @@ SRC += $(ARM_ATSAM_DIR)/usb/udi_hid.c
SRC += $(ARM_ATSAM_DIR)/usb/udi_hid_kbd.c
SRC += $(ARM_ATSAM_DIR)/usb/udi_hid_kbd_desc.c
SRC += $(ARM_ATSAM_DIR)/usb/ui.c
SRC += $(ARM_ATSAM_DIR)/usb/usb2422.c
SRC += $(ARM_ATSAM_DIR)/usb/usb.c
SRC += $(ARM_ATSAM_DIR)/usb/usb_device_udd.c
SRC += $(ARM_ATSAM_DIR)/usb/usb_hub.c
SRC += $(ARM_ATSAM_DIR)/usb/usb_util.c
SRC += $(DRIVER_PATH)/usb2422.c
# Search Path
VPATH += $(TMK_DIR)/$(ARM_ATSAM_DIR)

View file

@ -27,9 +27,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "wait.h"
#include "adc.h"
#include "i2c_master.h"
#include "spi.h"
#include "shift_register.h"
#include "./usb/usb2422.h"
#include "./usb/usb_hub.h"
#ifndef MD_BOOTLOADER

View file

@ -564,4 +564,23 @@ uint8_t i2c_led_q_run(void) {
return 1;
}
__attribute__((weak)) void i2c_init(void) {
static bool is_initialised = false;
if (!is_initialised) {
is_initialised = true;
i2c0_init();
}
}
i2c_status_t i2c_transmit(uint8_t address, const uint8_t *data, uint16_t length, uint16_t timeout) {
uint8_t ret = i2c0_transmit(address, (uint8_t *)data, length, timeout);
SERCOM0->I2CM.CTRLB.bit.CMD = 0x03;
while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP) {
DBGC(DC_USB_WRITE2422_BLOCK_SYNC_SYSOP);
}
return ret ? I2C_STATUS_SUCCESS : I2C_STATUS_ERROR;
}
#endif // !defined(MD_BOOTLOADER) && defined(RGB_MATRIX_ENABLE)

View file

@ -101,4 +101,13 @@ void i2c0_init(void);
uint8_t i2c0_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout);
void i2c0_stop(void);
// Terrible interface compatiblity...
#define I2C_STATUS_SUCCESS (0)
#define I2C_STATUS_ERROR (-1)
typedef int16_t i2c_status_t;
void i2c_init(void);
i2c_status_t i2c_transmit(uint8_t address, const uint8_t *data, uint16_t length, uint16_t timeout);
#endif // _I2C_MASTER_H_

View file

@ -40,6 +40,10 @@ void send_mouse(report_mouse_t *report);
void send_system(uint16_t data);
void send_consumer(uint16_t data);
#ifdef DEFERRED_EXEC_ENABLE
void deferred_exec_task(void);
#endif // DEFERRED_EXEC_ENABLE
host_driver_t arm_atsam_driver = {keyboard_leds, send_keyboard, send_mouse, send_system, send_consumer};
uint8_t led_states;
@ -296,7 +300,7 @@ int main(void) {
matrix_init();
USB2422_init();
USB_Hub_init();
DBGC(DC_MAIN_UDC_START_BEGIN);
udc_start();
@ -306,7 +310,7 @@ int main(void) {
CDC_init();
DBGC(DC_MAIN_CDC_INIT_COMPLETE);
while (USB2422_Port_Detect_Init() == 0) {
while (USB_Hub_Port_Detect_Init() == 0) {
}
DBG_LED_OFF;
@ -360,6 +364,11 @@ int main(void) {
}
#endif // CONSOLE_ENABLE
#ifdef DEFERRED_EXEC_ENABLE
// Run deferred executions
deferred_exec_task();
#endif // DEFERRED_EXEC_ENABLE
// Run housekeeping
housekeeping_task();
}

View file

@ -15,6 +15,10 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define FLUSH_TIMEOUT 5000
#define EECONFIG_MD_LED ((uint8_t*)(EECONFIG_SIZE + 64))
#define MD_LED_CONFIG_VERSION 1
#ifdef RGB_MATRIX_ENABLE
# include "arm_atsam_protocol.h"
# include "led.h"
@ -23,8 +27,41 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# include <math.h>
# ifdef USE_MASSDROP_CONFIGURATOR
// TODO?: wire these up to keymap.c
md_led_config_t md_led_config = {0};
EECONFIG_DEBOUNCE_HELPER(md_led, EECONFIG_MD_LED, md_led_config);
void eeconfig_update_md_led_default(void) {
md_led_config.ver = MD_LED_CONFIG_VERSION;
gcr_desired = LED_GCR_MAX;
led_animation_orientation = 0;
led_animation_direction = 0;
led_animation_breathing = 0;
led_animation_id = 0;
led_animation_speed = 4.0f;
led_lighting_mode = LED_MODE_NORMAL;
led_enabled = 1;
led_animation_breathe_cur = BREATHE_MIN_STEP;
breathe_dir = 1;
led_animation_circular = 0;
led_edge_brightness = 1.0f;
led_ratio_brightness = 1.0f;
led_edge_mode = LED_EDGE_MODE_ALL;
eeconfig_flush_md_led(true);
}
void md_led_changed(void) { eeconfig_flag_md_led(true); }
// todo: use real task rather than this bodge
void housekeeping_task_kb(void) { eeconfig_flush_md_led_task(FLUSH_TIMEOUT); }
__attribute__((weak)) led_instruction_t led_instructions[] = {{.end = 1}};
static void md_rgb_matrix_config_override(int i);
# else
uint8_t gcr_desired;
# endif // USE_MASSDROP_CONFIGURATOR
void SERCOM1_0_Handler(void) {
@ -56,7 +93,6 @@ issi3733_driver_t issidrv[ISSI3733_DRIVER_COUNT];
issi3733_led_t led_map[ISSI3733_LED_COUNT] = ISSI3733_LED_MAP;
RGB led_buffer[ISSI3733_LED_COUNT];
uint8_t gcr_desired;
uint8_t gcr_actual;
uint8_t gcr_actual_last;
# ifdef USE_MASSDROP_CONFIGURATOR
@ -218,6 +254,13 @@ static void led_set_all(uint8_t r, uint8_t g, uint8_t b) {
static void init(void) {
DBGC(DC_LED_MATRIX_INIT_BEGIN);
# ifdef USE_MASSDROP_CONFIGURATOR
eeconfig_init_md_led();
if (md_led_config.ver != MD_LED_CONFIG_VERSION) {
eeconfig_update_md_led_default();
}
# endif
issi3733_prepare_arrays();
md_rgb_matrix_prepare();
@ -331,17 +374,6 @@ const rgb_matrix_driver_t rgb_matrix_driver = {.init = init, .flush = flush, .se
# ifdef USE_MASSDROP_CONFIGURATOR
// Ported from Massdrop QMK GitHub Repo
// TODO?: wire these up to keymap.c
uint8_t led_animation_orientation = 0;
uint8_t led_animation_direction = 0;
uint8_t led_animation_breathing = 0;
uint8_t led_animation_id = 0;
float led_animation_speed = 4.0f;
uint8_t led_lighting_mode = LED_MODE_NORMAL;
uint8_t led_enabled = 1;
uint8_t led_animation_breathe_cur = BREATHE_MIN_STEP;
uint8_t breathe_dir = 1;
static void led_run_pattern(led_setup_t* f, float* ro, float* go, float* bo, float pos) {
float po;
@ -398,16 +430,32 @@ static void led_run_pattern(led_setup_t* f, float* ro, float* go, float* bo, flo
}
}
# define RGB_MAX_DISTANCE 232.9635f
static void md_rgb_matrix_config_override(int i) {
float ro = 0;
float go = 0;
float bo = 0;
float po = (led_animation_orientation) ? (float)g_led_config.point[i].y / 64.f * 100 : (float)g_led_config.point[i].x / 224.f * 100;
float po;
uint8_t highest_active_layer = biton32(layer_state);
if (led_lighting_mode == LED_MODE_KEYS_ONLY && HAS_FLAGS(g_led_config.flags[i], LED_FLAG_UNDERGLOW)) {
if (led_animation_circular) {
// TODO: should use min/max values from LED configuration instead of
// hard-coded 224, 64
// po = sqrtf((powf(fabsf((disp.width / 2) - (led_cur->x - disp.left)), 2) + powf(fabsf((disp.height / 2) - (led_cur->y - disp.bottom)), 2))) / disp.max_distance * 100;
po = sqrtf((powf(fabsf((224 / 2) - (float)g_led_config.point[i].x), 2) + powf(fabsf((64 / 2) - (float)g_led_config.point[i].y), 2))) / RGB_MAX_DISTANCE * 100;
} else {
if (led_animation_orientation) {
po = (float)g_led_config.point[i].y / 64.f * 100;
} else {
po = (float)g_led_config.point[i].x / 224.f * 100;
}
}
if (led_edge_mode == LED_EDGE_MODE_ALTERNATE && LED_IS_EDGE_ALT(led_map[i].scan)) {
// Do not act on this LED (Edge alternate lighting mode)
} else if (led_lighting_mode == LED_MODE_KEYS_ONLY && HAS_FLAGS(g_led_config.flags[i], LED_FLAG_UNDERGLOW)) {
// Do not act on this LED
} else if (led_lighting_mode == LED_MODE_NON_KEYS_ONLY && !HAS_FLAGS(g_led_config.flags[i], LED_FLAG_UNDERGLOW)) {
// Do not act on this LED
@ -465,10 +513,30 @@ static void md_rgb_matrix_config_override(int i) {
}
}
// Adjust edge LED brightness
if (led_edge_brightness != 1 && LED_IS_EDGE(led_map[i].scan)) {
ro *= led_edge_brightness;
go *= led_edge_brightness;
bo *= led_edge_brightness;
}
// Adjust ratio of key vs. underglow (edge) LED brightness
if (LED_IS_EDGE(led_map[i].scan) && led_ratio_brightness > 1.0) {
// Decrease edge (underglow) LEDs
ro *= (2.0 - led_ratio_brightness);
go *= (2.0 - led_ratio_brightness);
bo *= (2.0 - led_ratio_brightness);
} else if (LED_IS_KEY(led_map[i].scan) && led_ratio_brightness < 1.0) {
// Decrease KEY LEDs
ro *= led_ratio_brightness;
go *= led_ratio_brightness;
bo *= led_ratio_brightness;
}
led_buffer[i].r = (uint8_t)ro;
led_buffer[i].g = (uint8_t)go;
led_buffer[i].b = (uint8_t)bo;
}
# endif // USE_MASSDROP_CONFIGURATOR
#endif // RGB_MATRIX_ENABLE
#endif // RGB_MATRIX_ENABLE

View file

@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define _LED_MATRIX_H_
#include "quantum.h"
#include "eeprom.h"
// From keyboard
#include "config_led.h"
@ -79,7 +80,6 @@ typedef struct issi3733_led_s {
extern issi3733_driver_t issidrv[ISSI3733_DRIVER_COUNT];
extern uint8_t gcr_desired;
extern uint8_t gcr_breathe;
extern uint8_t gcr_actual;
extern uint8_t gcr_actual_last;
@ -128,6 +128,8 @@ typedef struct led_instruction_s {
uint32_t id1; // Bitwise id, IDs 32-63
uint32_t id2; // Bitwise id, IDs 64-95
uint32_t id3; // Bitwise id, IDs 96-127
uint32_t id4; // Bitwise id, IDs 128-159
uint32_t id5; // Bitwise id, IDs 160-191
uint8_t layer;
uint8_t r;
uint8_t g;
@ -138,14 +140,43 @@ typedef struct led_instruction_s {
extern led_instruction_t led_instructions[];
extern uint8_t led_animation_breathing;
extern uint8_t led_animation_id;
extern float led_animation_speed;
extern uint8_t led_lighting_mode;
extern uint8_t led_enabled;
extern uint8_t led_animation_breathe_cur;
extern uint8_t led_animation_direction;
extern uint8_t breathe_dir;
typedef struct led_config_s {
uint8_t ver; // assumed to be zero on eeprom reset
uint8_t desired_gcr;
uint8_t animation_breathing;
uint8_t animation_id;
float animation_speed;
uint8_t lighting_mode;
uint8_t enabled;
uint8_t animation_breathe_cur;
uint8_t animation_direction;
uint8_t animation_breathe_dir;
uint8_t animation_orientation;
uint8_t animation_circular;
float edge_brightness;
float ratio_brightness;
uint8_t edge_mode;
} md_led_config_t;
extern md_led_config_t md_led_config;
void md_led_changed(void);
# define gcr_desired md_led_config.desired_gcr
# define led_animation_breathing md_led_config.animation_breathing
# define led_animation_id md_led_config.animation_id
# define led_animation_speed md_led_config.animation_speed
# define led_lighting_mode md_led_config.lighting_mode
# define led_enabled md_led_config.enabled
# define led_animation_breathe_cur md_led_config.animation_breathe_cur
# define led_animation_direction md_led_config.animation_direction
# define breathe_dir md_led_config.animation_breathe_dir
# define led_animation_orientation md_led_config.animation_orientation
# define led_animation_circular md_led_config.animation_circular
# define led_edge_brightness md_led_config.edge_brightness
# define led_ratio_brightness md_led_config.ratio_brightness
# define led_edge_mode md_led_config.edge_mode
# define LED_MODE_NORMAL 0 // Must be 0
# define LED_MODE_KEYS_ONLY 1
@ -153,6 +184,21 @@ extern uint8_t breathe_dir;
# define LED_MODE_INDICATORS_ONLY 3
# define LED_MODE_MAX_INDEX LED_MODE_INDICATORS_ONLY // Must be highest value
# define LED_EDGE_MODE_ALL 0 // All edge LEDs are active (Must be 0)
# define LED_EDGE_MODE_ALTERNATE 1 // Alternate mode of edge LEDs are active (Intention is for 'only every other edge LED' to be active)
# define LED_EDGE_MODE_MAX LED_EDGE_MODE_ALTERNATE // Must be the highest valued LED edge mode
# define LED_EDGE_FULL_MODE 255 // LEDs configured with this scan code will always be on for edge lighting modes
# define LED_EDGE_ALT_MODE 254 // LEDs configured with this scan code will turn off in edge alternating mode
# define LED_EDGE_MIN_SCAN 254 // LEDs configured with scan code >= to this are assigned as edge LEDs
# define LED_INDICATOR_SCAN 253 // LEDs configured as dedicated indicators
# define LED_IS_KEY(scan) (scan < LED_INDICATOR_SCAN) // Return true if an LED's scan value indicates it is a key LED
# define LED_IS_EDGE(scan) (scan >= LED_EDGE_MIN_SCAN) // Return true if an LED's scan value indicates an edge LED
# define LED_IS_EDGE_ALT(scan) (scan == LED_EDGE_ALT_MODE) // Return true if an LED's scan value indicates an alternate edge mode LED
# define LED_IS_INDICATOR(scan) (scan == LED_INDICATOR_SCAN) // Return true if an LED's scan value indicates it is a dedicated Indicator
#else
extern uint8_t gcr_desired;
#endif // USE_MASSDROP_CONFIGURATOR
#endif //_LED_MATRIX_H_

View file

@ -0,0 +1,118 @@
/*
Copyright 2018 Massdrop Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 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 "arm_atsam_protocol.h"
#include "spi_master.h"
#include "wait.h"
#include "gpio.h"
// #define SR_USE_BITBANG
// Bodge for when spi_master is not available
#ifdef SR_USE_BITBANG
# define CLOCK_DELAY 10
void shift_init_impl(void) {
setPinOutput(SR_EXP_RCLK_PIN);
setPinOutput(SPI_DATAOUT_PIN);
setPinOutput(SPI_SCLK_PIN);
}
void shift_out_impl(const uint8_t *data, uint16_t length) {
writePinLow(SR_EXP_RCLK_PIN);
for (uint16_t i = 0; i < length; i++) {
uint8_t val = data[i];
// shift out lsb first
for (uint8_t bit = 0; bit < 8; bit++) {
writePin(SPI_DATAOUT_PIN, !!(val & (1 << bit)));
writePin(SPI_SCLK_PIN, true);
wait_us(CLOCK_DELAY);
writePin(SPI_SCLK_PIN, false);
wait_us(CLOCK_DELAY);
}
}
writePinHigh(SR_EXP_RCLK_PIN);
return SPI_STATUS_SUCCESS;
}
#else
void shift_init_impl(void) { spi_init(); }
void shift_out_impl(const uint8_t *data, uint16_t length) {
spi_start(SR_EXP_RCLK_PIN, true, 0, 0);
spi_transmit(data, length);
spi_stop();
}
#endif
// ***************************************************************
void shift_out(const uint8_t *data, uint16_t length) { shift_out_impl(data, length); }
void shift_enable(void) {
setPinOutput(SR_EXP_OE_PIN);
writePinLow(SR_EXP_OE_PIN);
}
void shift_disable(void) {
setPinOutput(SR_EXP_OE_PIN);
writePinHigh(SR_EXP_OE_PIN);
}
void shift_init(void) {
shift_disable();
shift_init_impl();
}
// ***************************************************************
sr_exp_t sr_exp_data;
void SR_EXP_WriteData(void) {
uint8_t data[2] = {
sr_exp_data.reg & 0xFF, // Shift in bits 7-0
(sr_exp_data.reg >> 8) & 0xFF, // Shift in bits 15-8
};
shift_out(data, 2);
}
void SR_EXP_Init(void) {
shift_init();
sr_exp_data.reg = 0;
sr_exp_data.bit.HUB_CONNECT = 0;
sr_exp_data.bit.HUB_RESET_N = 0;
sr_exp_data.bit.S_UP = 0;
sr_exp_data.bit.E_UP_N = 1;
sr_exp_data.bit.S_DN1 = 1;
sr_exp_data.bit.E_DN1_N = 1;
sr_exp_data.bit.E_VBUS_1 = 0;
sr_exp_data.bit.E_VBUS_2 = 0;
sr_exp_data.bit.SRC_1 = 1;
sr_exp_data.bit.SRC_2 = 1;
sr_exp_data.bit.IRST = 1;
sr_exp_data.bit.SDB_N = 0;
SR_EXP_WriteData();
shift_enable();
}

View file

@ -15,28 +15,9 @@ 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 _SPI_H_
#define _SPI_H_
#pragma once
/* Macros for Shift Register control */
#define SR_EXP_RCLK_LO PORT->Group[SR_EXP_RCLK_PORT].OUTCLR.reg = (1 << SR_EXP_RCLK_PIN)
#define SR_EXP_RCLK_HI PORT->Group[SR_EXP_RCLK_PORT].OUTSET.reg = (1 << SR_EXP_RCLK_PIN)
#define SR_EXP_OE_N_ENA PORT->Group[SR_EXP_OE_N_PORT].OUTCLR.reg = (1 << SR_EXP_OE_N_PIN)
#define SR_EXP_OE_N_DIS PORT->Group[SR_EXP_OE_N_PORT].OUTSET.reg = (1 << SR_EXP_OE_N_PIN)
/* Determine bits to set for mux selection */
#if SR_EXP_DATAOUT_PIN % 2 == 0
# define SR_EXP_DATAOUT_MUX_SEL PMUXE
#else
# define SR_EXP_DATAOUT_MUX_SEL PMUXO
#endif
/* Determine bits to set for mux selection */
#if SR_EXP_SCLK_PIN % 2 == 0
# define SR_EXP_SCLK_MUX_SEL PMUXE
#else
# define SR_EXP_SCLK_MUX_SEL PMUXO
#endif
#include <stdint.h>
/* Data structure to define Shift Register output expander hardware */
/* This structure gets shifted into registers LSB first */
@ -66,5 +47,3 @@ extern sr_exp_t sr_exp_data;
void SR_EXP_WriteData(void);
void SR_EXP_Init(void);
#endif //_SPI_H_

View file

@ -1,92 +0,0 @@
/*
Copyright 2018 Massdrop Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 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 "arm_atsam_protocol.h"
sr_exp_t sr_exp_data;
void SR_EXP_WriteData(void) {
SR_EXP_RCLK_LO;
while (!(SR_EXP_SERCOM->SPI.INTFLAG.bit.DRE)) {
DBGC(DC_SPI_WRITE_DRE);
}
SR_EXP_SERCOM->SPI.DATA.bit.DATA = sr_exp_data.reg & 0xFF; // Shift in bits 7-0
while (!(SR_EXP_SERCOM->SPI.INTFLAG.bit.TXC)) {
DBGC(DC_SPI_WRITE_TXC_1);
}
SR_EXP_SERCOM->SPI.DATA.bit.DATA = (sr_exp_data.reg >> 8) & 0xFF; // Shift in bits 15-8
while (!(SR_EXP_SERCOM->SPI.INTFLAG.bit.TXC)) {
DBGC(DC_SPI_WRITE_TXC_2);
}
SR_EXP_RCLK_HI;
}
void SR_EXP_Init(void) {
DBGC(DC_SPI_INIT_BEGIN);
CLK_set_spi_freq(CHAN_SERCOM_SPI, FREQ_SPI_DEFAULT);
// Set up MCU Shift Register pins
PORT->Group[SR_EXP_RCLK_PORT].DIRSET.reg = (1 << SR_EXP_RCLK_PIN);
PORT->Group[SR_EXP_OE_N_PORT].DIRSET.reg = (1 << SR_EXP_OE_N_PIN);
// Set up MCU SPI pins
PORT->Group[SR_EXP_DATAOUT_PORT].PMUX[SR_EXP_DATAOUT_PIN / 2].bit.SR_EXP_DATAOUT_MUX_SEL = SR_EXP_DATAOUT_MUX; // MUX select for sercom
PORT->Group[SR_EXP_SCLK_PORT].PMUX[SR_EXP_SCLK_PIN / 2].bit.SR_EXP_SCLK_MUX_SEL = SR_EXP_SCLK_MUX; // MUX select for sercom
PORT->Group[SR_EXP_DATAOUT_PORT].PINCFG[SR_EXP_DATAOUT_PIN].bit.PMUXEN = 1; // MUX Enable
PORT->Group[SR_EXP_SCLK_PORT].PINCFG[SR_EXP_SCLK_PIN].bit.PMUXEN = 1; // MUX Enable
// Initialize Shift Register
SR_EXP_OE_N_DIS;
SR_EXP_RCLK_HI;
SR_EXP_SERCOM->SPI.CTRLA.bit.DORD = 1; // Data Order - LSB is transferred first
SR_EXP_SERCOM->SPI.CTRLA.bit.CPOL = 1; // Clock Polarity - SCK high when idle. Leading edge of cycle is falling. Trailing rising.
SR_EXP_SERCOM->SPI.CTRLA.bit.CPHA = 1; // Clock Phase - Leading Edge Falling, change, Trailing Edge - Rising, sample
SR_EXP_SERCOM->SPI.CTRLA.bit.DIPO = 3; // Data In Pinout - SERCOM PAD[3] is used as data input (Configure away from DOPO. Not using input.)
SR_EXP_SERCOM->SPI.CTRLA.bit.DOPO = 0; // Data Output PAD[0], Serial Clock PAD[1]
SR_EXP_SERCOM->SPI.CTRLA.bit.MODE = 3; // Operating Mode - Master operation
SR_EXP_SERCOM->SPI.CTRLA.bit.ENABLE = 1; // Enable - Peripheral is enabled or being enabled
while (SR_EXP_SERCOM->SPI.SYNCBUSY.bit.ENABLE) {
DBGC(DC_SPI_SYNC_ENABLING);
}
sr_exp_data.reg = 0;
sr_exp_data.bit.HUB_CONNECT = 0;
sr_exp_data.bit.HUB_RESET_N = 0;
sr_exp_data.bit.S_UP = 0;
sr_exp_data.bit.E_UP_N = 1;
sr_exp_data.bit.S_DN1 = 1;
sr_exp_data.bit.E_DN1_N = 1;
sr_exp_data.bit.E_VBUS_1 = 0;
sr_exp_data.bit.E_VBUS_2 = 0;
sr_exp_data.bit.SRC_1 = 1;
sr_exp_data.bit.SRC_2 = 1;
sr_exp_data.bit.IRST = 1;
sr_exp_data.bit.SDB_N = 0;
SR_EXP_WriteData();
// Enable Shift Register output
SR_EXP_OE_N_ENA;
DBGC(DC_SPI_INIT_COMPLETE);
}

View file

@ -0,0 +1,109 @@
/*
Copyright 2018 Massdrop Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 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 "arm_atsam_protocol.h"
#include "spi_master.h"
#include "gpio.h"
/* Determine bits to set for mux selection */
#if SPI_DATAOUT_PIN % 2 == 0
# define SPI_DATAOUT_MUX_SEL PMUXE
#else
# define SPI_DATAOUT_MUX_SEL PMUXO
#endif
/* Determine bits to set for mux selection */
#if SPI_SCLK_PIN % 2 == 0
# define SPI_SCLK_MUX_SEL PMUXE
#else
# define SPI_SCLK_MUX_SEL PMUXO
#endif
static pin_t currentSelectPin = NO_PIN;
__attribute__((weak)) void spi_init(void) {
static bool is_initialised = false;
if (!is_initialised) {
is_initialised = true;
DBGC(DC_SPI_INIT_BEGIN);
CLK_set_spi_freq(CHAN_SERCOM_SPI, FREQ_SPI_DEFAULT);
// Set up MCU SPI pins
PORT->Group[SAMD_PORT(SPI_DATAOUT_PIN)].PMUX[SAMD_PIN(SPI_DATAOUT_PIN) / 2].bit.SPI_DATAOUT_MUX_SEL = SPI_DATAOUT_MUX; // MUX select for sercom
PORT->Group[SAMD_PORT(SPI_SCLK_PIN)].PMUX[SAMD_PIN(SPI_SCLK_PIN) / 2].bit.SPI_SCLK_MUX_SEL = SPI_SCLK_MUX; // MUX select for sercom
PORT->Group[SAMD_PORT(SPI_DATAOUT_PIN)].PINCFG[SAMD_PIN(SPI_DATAOUT_PIN)].bit.PMUXEN = 1; // MUX Enable
PORT->Group[SAMD_PORT(SPI_SCLK_PIN)].PINCFG[SAMD_PIN(SPI_SCLK_PIN)].bit.PMUXEN = 1; // MUX Enable
DBGC(DC_SPI_INIT_COMPLETE);
}
}
bool spi_start(pin_t csPin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
if (currentSelectPin != NO_PIN || csPin == NO_PIN) {
return false;
}
currentSelectPin = csPin;
setPinOutput(currentSelectPin);
writePinLow(currentSelectPin);
SPI_SERCOM->SPI.CTRLA.bit.DORD = lsbFirst; // Data Order - LSB is transferred first
SPI_SERCOM->SPI.CTRLA.bit.CPOL = 1; // Clock Polarity - SCK high when idle. Leading edge of cycle is falling. Trailing rising.
SPI_SERCOM->SPI.CTRLA.bit.CPHA = 1; // Clock Phase - Leading Edge Falling, change, Trailing Edge - Rising, sample
SPI_SERCOM->SPI.CTRLA.bit.DIPO = 3; // Data In Pinout - SERCOM PAD[3] is used as data input (Configure away from DOPO. Not using input.)
SPI_SERCOM->SPI.CTRLA.bit.DOPO = 0; // Data Output PAD[0], Serial Clock PAD[1]
SPI_SERCOM->SPI.CTRLA.bit.MODE = 3; // Operating Mode - Master operation
SPI_SERCOM->SPI.CTRLA.bit.ENABLE = 1; // Enable - Peripheral is enabled or being enabled
while (SPI_SERCOM->SPI.SYNCBUSY.bit.ENABLE) {
DBGC(DC_SPI_SYNC_ENABLING);
}
return true;
}
spi_status_t spi_transmit(const uint8_t *data, uint16_t length) {
while (!(SPI_SERCOM->SPI.INTFLAG.bit.DRE)) {
DBGC(DC_SPI_WRITE_DRE);
}
for (uint16_t i = 0; i < length; i++) {
SPI_SERCOM->SPI.DATA.bit.DATA = data[i];
while (!(SPI_SERCOM->SPI.INTFLAG.bit.TXC)) {
DBGC(DC_SPI_WRITE_TXC_1);
}
}
return SPI_STATUS_SUCCESS;
}
void spi_stop(void) {
if (currentSelectPin != NO_PIN) {
setPinOutput(currentSelectPin);
writePinHigh(currentSelectPin);
currentSelectPin = NO_PIN;
}
}
// Not implemented yet....
spi_status_t spi_write(uint8_t data);
spi_status_t spi_read(void);
spi_status_t spi_receive(uint8_t *data, uint16_t length);

View file

@ -0,0 +1,48 @@
/* 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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdbool.h>
typedef int16_t spi_status_t;
#define SPI_STATUS_SUCCESS (0)
#define SPI_STATUS_ERROR (-1)
#define SPI_STATUS_TIMEOUT (-2)
#define SPI_TIMEOUT_IMMEDIATE (0)
#define SPI_TIMEOUT_INFINITE (0xFFFF)
#ifdef __cplusplus
extern "C" {
#endif
void spi_init(void);
bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor);
spi_status_t spi_write(uint8_t data);
spi_status_t spi_read(void);
spi_status_t spi_transmit(const uint8_t *data, uint16_t length);
spi_status_t spi_receive(uint8_t *data, uint16_t length);
void spi_stop(void);
#ifdef __cplusplus
}
#endif

View file

@ -1,402 +0,0 @@
/*
Copyright 2018 Massdrop Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _USB2422_H_
#define _USB2422_H_
#define REV_USB2422 0x100
#define USB2422_ADDR 0x58 // I2C device address, one instance
#define USB2422_HUB_ACTIVE_GROUP 0 // PA
#define USB2422_HUB_ACTIVE_PIN 18 // 18
/* -------- USB2422_VID : (USB2422L Offset: 0x00) (R/W 16) Vendor ID -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint16_t VID_LSB : 8;
uint16_t VID_MSB : 8;
} bit; /*!< Structure used for bit access */
uint16_t reg; /*!< Type used for register access */
} USB2422_VID_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_PID : (USB2422L Offset: 0x02) (R/W 16) Product ID -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint16_t PID_LSB : 8;
uint16_t PID_MSB : 8;
} bit; /*!< Structure used for bit access */
uint16_t reg; /*!< Type used for register access */
} USB2422_PID_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_DID : (USB2422L Offset: 0x04) (R/W 16) Device ID -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint16_t DID_LSB : 8;
uint16_t DID_MSB : 8;
} bit; /*!< Structure used for bit access */
uint16_t reg; /*!< Type used for register access */
} USB2422_DID_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_CFG1 : (USB2422L Offset: 0x06) (R/W 8) Configuration Data Byte 1-------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t PORT_PWR : 1;
uint8_t CURRENT_SNS : 2;
uint8_t EOP_DISABLE : 1;
uint8_t MTT_ENABLE : 1;
uint8_t HS_DISABLE : 1;
uint8_t : 1;
uint8_t SELF_BUS_PWR : 1;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_CFG1_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_CFG2 : (USB2422L Offset: 0x07) (R/W 8) Configuration Data Byte 2-------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t : 3;
uint8_t COMPOUND : 1;
uint8_t OC_TIMER : 2;
uint8_t : 1;
uint8_t DYNAMIC : 1;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_CFG2_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_CFG3 : (USB2422L Offset: 0x08) (R/W 16) Configuration Data Byte 3-------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t STRING_EN : 1;
uint8_t : 2;
uint8_t PRTMAP_EN : 1;
uint8_t : 4;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_CFG3_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_NRD : (USB2422L Offset: 0x09) (R/W 8) Non Removable Device -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t : 5;
uint8_t PORT2_NR : 1;
uint8_t PORT1_NR : 1;
uint8_t : 1;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_NRD_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_PDS : (USB2422L Offset: 0x0A) (R/W 8) Port Diable for Self-Powered Operation -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t : 1;
uint8_t PORT1_DIS : 1;
uint8_t PORT2_DIS : 1;
uint8_t : 5;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_PDS_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_PDB : (USB2422L Offset: 0x0B) (R/W 8) Port Diable for Bus-Powered Operation -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t : 1;
uint8_t PORT1_DIS : 1;
uint8_t PORT2_DIS : 1;
uint8_t : 5;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_PDB_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_MAXPS : (USB2422L Offset: 0x0C) (R/W 8) Max Power for Self-Powered Operation -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t MAX_PWR_SP : 8;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_MAXPS_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_MAXPB : (USB2422L Offset: 0x0D) (R/W 8) Max Power for Bus-Powered Operation -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t MAX_PWR_BP : 8;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_MAXPB_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_HCMCS : (USB2422L Offset: 0x0E) (R/W 8) Hub Controller Max Current for Self-Powered Operation -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t HC_MAX_C_SP : 8;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_HCMCS_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_HCMCB : (USB2422L Offset: 0x0F) (R/W 8) Hub Controller Max Current for Bus-Powered Operation -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t HC_MAX_C_BP : 8;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_HCMCB_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_PWRT : (USB2422L Offset: 0x10) (R/W 8) Power On Time -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t POWER_ON_TIME : 8;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_PWRT_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_LANGID LSB : (USB2422L Offset: 0x11) (R/W 16) Language ID -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t LANGID_LSB : 8;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_LANGID_LSB_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_LANGID MSB : (USB2422L Offset: 0x12) (R/W 16) Language ID -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t LANGID_MSB : 8;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_LANGID_MSB_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_MFRSL : (USB2422L Offset: 0x13) (R/W 8) Manufacturer String Length -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t MFR_STR_LEN : 8;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_MFRSL_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_PRDSL : (USB2422L Offset: 0x14) (R/W 8) Product String Length -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t PRD_STR_LEN : 8;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_PRDSL_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_SERSL : (USB2422L Offset: 0x15) (R/W 8) Serial String Length -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t SER_STR_LEN : 8;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_SERSL_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_MFRSTR : (USB2422L Offset: 0x16-53) (R/W 8) Maufacturer String -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef uint16_t USB2422_MFRSTR_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_PRDSTR : (USB2422L Offset: 0x54-91) (R/W 8) Product String -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef uint16_t USB2422_PRDSTR_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_SERSTR : (USB2422L Offset: 0x92-CF) (R/W 8) Serial String -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef uint16_t USB2422_SERSTR_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_BCEN : (USB2422L Offset: 0xD0) (R/W 8) Battery Charging Enable -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t : 1;
uint8_t PORT1_BCE : 1;
uint8_t PORT2_BCE : 1;
uint8_t : 5;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_BCEN_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_BOOSTUP : (USB2422L Offset: 0xF6) (R/W 8) Boost Upstream -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t BOOST : 2;
uint8_t : 6;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_BOOSTUP_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_BOOSTDOWN : (USB2422L Offset: 0xF8) (R/W 8) Boost Downstream -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t BOOST1 : 2;
uint8_t BOOST2 : 2;
uint8_t : 4;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_BOOSTDOWN_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_PRTSP : (USB2422L Offset: 0xFA) (R/W 8) Port Swap -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t : 1;
uint8_t PORT1_SP : 1;
uint8_t PORT2_SP : 1;
uint8_t : 5;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_PRTSP_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/* -------- USB2422_PRTR12 : (USB2422L Offset: 0xFB) (R/W 8) Port 1/2 Remap -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t PORT1_REMAP : 4;
uint8_t PORT2_REMAP : 4;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_PRTR12_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
#define USB2422_PRTR12_DISABLE 0
#define USB2422_PRT12_P2TOL1 1
#define USB2422_PRT12_P2XTOL2 2
#define USB2422_PRT12_P1TOL1 1
#define USB2422_PRT12_P1XTOL2 2
/* -------- USB2422_STCD : (USB2422L Offset: 0xFF) (R/W 8) Status Command -------- */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef union {
struct {
uint8_t USB_ATTACH : 1;
uint8_t RESET : 1;
uint8_t INTF_PWRDN : 1;
uint8_t : 5;
} bit; /*!< Structure used for bit access */
uint8_t reg; /*!< Type used for register access */
} USB2422_STCD_Type;
#endif /* !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__)) */
/** \brief USB2422 device hardware registers */
#if !(defined(__ASSEMBLY__) || defined(__IAR_SYSTEMS_ASM__))
typedef struct {
USB2422_VID_Type VID; /**< \brief Offset: 0x00*/
USB2422_PID_Type PID; /**< \brief Offset: 0x02*/
USB2422_DID_Type DID; /**< \brief Offset: 0x04*/
USB2422_CFG1_Type CFG1; /**< \brief Offset: 0x06*/
USB2422_CFG2_Type CFG2; /**< \brief Offset: 0x07*/
USB2422_CFG3_Type CFG3; /**< \brief Offset: 0x08*/
USB2422_NRD_Type NRD; /**< \brief Offset: 0x09*/
USB2422_PDS_Type PDS; /**< \brief Offset: 0x0A*/
USB2422_PDB_Type PDB; /**< \brief Offset: 0x0B*/
USB2422_MAXPS_Type MAXPS; /**< \brief Offset: 0x0C*/
USB2422_MAXPB_Type MAXPB; /**< \brief Offset: 0x0D*/
USB2422_HCMCS_Type HCMCS; /**< \brief Offset: 0x0E*/
USB2422_HCMCB_Type HCMCB; /**< \brief Offset: 0x0F*/
USB2422_PWRT_Type PWRT; /**< \brief Offset: 0x10*/
USB2422_LANGID_LSB_Type LANGID_LSB; /**< \brief Offset: 0x11*/
USB2422_LANGID_MSB_Type LANGID_MSB; /**< \brief Offset: 0x12*/
USB2422_MFRSL_Type MFRSL; /**< \brief Offset: 0x13*/
USB2422_PRDSL_Type PRDSL; /**< \brief Offset: 0x14*/
USB2422_SERSL_Type SERSL; /**< \brief Offset: 0x15*/
USB2422_MFRSTR_Type MFRSTR[31]; /**< \brief Offset: 0x16*/
USB2422_PRDSTR_Type PRDSTR[31]; /**< \brief Offset: 0x54*/
USB2422_SERSTR_Type SERSTR[31]; /**< \brief Offset: 0x92*/
USB2422_BCEN_Type BCEN; /**< \brief Offset: 0xD0*/
uint8_t Reserved1[0x25];
USB2422_BOOSTUP_Type BOOSTUP; /**< \brief Offset: 0xF6*/
uint8_t Reserved2[0x1];
USB2422_BOOSTDOWN_Type BOOSTDOWN; /**< \brief Offset: 0xF8*/
uint8_t Reserved3[0x1];
USB2422_PRTSP_Type PRTSP; /**< \brief Offset: 0xFA*/
USB2422_PRTR12_Type PRTR12; /**< \brief Offset: 0xFB*/
uint8_t Reserved4[0x3];
USB2422_STCD_Type STCD; /**< \brief Offset: 0xFF*/
} Usb2422;
#endif
#define PORT_DETECT_RETRY_INTERVAL 2000
#define USB_EXTRA_ADC_THRESHOLD 900
#define USB_EXTRA_STATE_DISABLED 0
#define USB_EXTRA_STATE_ENABLED 1
#define USB_EXTRA_STATE_UNKNOWN 2
#define USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG 3
#define USB_HOST_PORT_1 0
#define USB_HOST_PORT_2 1
#define USB_HOST_PORT_UNKNOWN 2
extern uint8_t usb_host_port;
extern uint8_t usb_extra_state;
extern uint8_t usb_extra_manual;
extern uint8_t usb_gcr_auto;
void USB2422_init(void);
void USB_reset(void);
void USB_configure(void);
uint16_t USB_active(void);
void USB_set_host_by_voltage(void);
uint16_t adc_get(uint8_t muxpos);
uint8_t USB2422_Port_Detect_Init(void);
void USB_HandleExtraDevice(void);
void USB_ExtraSetState(uint8_t state);
#endif //_USB2422_H_

View file

@ -16,25 +16,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "arm_atsam_protocol.h"
#include "drivers/usb2422.h"
#include <string.h>
Usb2422 USB2422_shadow;
unsigned char i2c0_buf[34];
const uint16_t MFRNAME[] = {'M', 'a', 's', 's', 'd', 'r', 'o', 'p', ' ', 'I', 'n', 'c', '.'}; // Massdrop Inc.
const uint16_t PRDNAME[] = {'M', 'a', 's', 's', 'd', 'r', 'o', 'p', ' ', 'H', 'u', 'b'}; // Massdrop Hub
#ifndef MD_BOOTLOADER
// Serial number reported stops before first found space character or at last found character
const uint16_t SERNAME[] = {'U', 'n', 'a', 'v', 'a', 'i', 'l', 'a', 'b', 'l', 'e'}; // Unavailable
#else
// In production, this field is found, modified, and offset noted as the last 32-bit word in the bootloader space
// The offset allows the application to use the factory programmed serial (which may differ from the physical serial label)
// Serial number reported stops before first found space character or when max size is reached
__attribute__((__aligned__(4))) const uint16_t SERNAME[BOOTLOADER_SERIAL_MAX_SIZE] = {'M', 'D', 'H', 'U', 'B', 'B', 'O', 'O', 'T', 'L', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0'};
// NOTE: Serial replacer will not write a string longer than given here as a precaution, so give enough
// space as needed and adjust BOOTLOADER_SERIAL_MAX_SIZE to match amount given
#endif // MD_BOOTLOADER
uint8_t usb_host_port;
#ifndef MD_BOOTLOADER
@ -47,29 +31,7 @@ uint8_t usb_gcr_auto;
uint16_t adc_extra;
void USB_write2422_block(void) {
unsigned char *dest = i2c0_buf;
unsigned char *src;
unsigned char *base = (unsigned char *)&USB2422_shadow;
DBGC(DC_USB_WRITE2422_BLOCK_BEGIN);
for (src = base; src < base + 256; src += 32) {
dest[0] = src - base;
dest[1] = 32;
memcpy(&dest[2], src, 32);
i2c0_transmit(USB2422_ADDR, dest, 34, 50000);
SERCOM0->I2CM.CTRLB.bit.CMD = 0x03;
while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP) {
DBGC(DC_USB_WRITE2422_BLOCK_SYNC_SYSOP);
}
wait_us(100);
}
DBGC(DC_USB_WRITE2422_BLOCK_COMPLETE);
}
void USB2422_init(void) {
void USB_Hub_init(void) {
Gclk * pgclk = GCLK;
Mclk * pmclk = MCLK;
Port * pport = PORT;
@ -147,9 +109,7 @@ void USB2422_init(void) {
pusb->DEVICE.QOSCTRL.bit.DQOS = 2;
pusb->DEVICE.QOSCTRL.bit.CQOS = 2;
pport->Group[USB2422_HUB_ACTIVE_GROUP].PINCFG[USB2422_HUB_ACTIVE_PIN].bit.INEN = 1;
i2c0_init(); // IC2 clk must be high at USB2422 reset release time to signal SMB configuration
USB2422_init();
sr_exp_data.bit.HUB_CONNECT = 1; // connect signal
sr_exp_data.bit.HUB_RESET_N = 1; // reset high
@ -181,62 +141,16 @@ void USB_reset(void) {
}
void USB_configure(void) {
Usb2422 *pusb2422 = &USB2422_shadow;
memset(pusb2422, 0, sizeof(Usb2422));
uint16_t *serial_use = (uint16_t *)SERNAME; // Default to use SERNAME from this file
uint8_t serial_length = sizeof(SERNAME) / sizeof(uint16_t); // Default to use SERNAME from this file
#ifndef MD_BOOTLOADER
uint32_t serial_ptrloc = (uint32_t)&_srom - 4;
#else // MD_BOOTLOADER
uint32_t serial_ptrloc = (uint32_t)&_erom - 4;
#endif // MD_BOOTLOADER
uint32_t serial_address = *(uint32_t *)serial_ptrloc; // Address of bootloader's serial number if available
DBGC(DC_USB_CONFIGURE_BEGIN);
if (serial_address != 0xFFFFFFFF && serial_address < serial_ptrloc) // Check for factory programmed serial address
{
if ((serial_address & 0xFF) % 4 == 0) // Check alignment
{
serial_use = (uint16_t *)(serial_address);
serial_length = 0;
while ((*(serial_use + serial_length) > 32 && *(serial_use + serial_length) < 127) && serial_length < BOOTLOADER_SERIAL_MAX_SIZE) {
serial_length++;
DBGC(DC_USB_CONFIGURE_GET_SERIAL);
}
}
}
// configure Usb2422 registers
pusb2422->VID.reg = 0x04D8; // from Microchip 4/19/2018
pusb2422->PID.reg = 0xEEC5; // from Microchip 4/19/2018 = Massdrop, Inc. USB Hub
pusb2422->DID.reg = 0x0101; // BCD 01.01
pusb2422->CFG1.bit.SELF_BUS_PWR = 1; // self powered for now
pusb2422->CFG1.bit.HS_DISABLE = 1; // full or high speed
// pusb2422->CFG2.bit.COMPOUND = 0; // compound device
pusb2422->CFG3.bit.STRING_EN = 1; // strings enabled
// pusb2422->NRD.bit.PORT2_NR = 0; // MCU is non-removable
pusb2422->MAXPB.reg = 20; // 0mA
pusb2422->HCMCB.reg = 20; // 0mA
pusb2422->MFRSL.reg = sizeof(MFRNAME) / sizeof(uint16_t);
pusb2422->PRDSL.reg = sizeof(PRDNAME) / sizeof(uint16_t);
pusb2422->SERSL.reg = serial_length;
memcpy(pusb2422->MFRSTR, MFRNAME, sizeof(MFRNAME));
memcpy(pusb2422->PRDSTR, PRDNAME, sizeof(PRDNAME));
memcpy(pusb2422->SERSTR, serial_use, serial_length * sizeof(uint16_t));
// pusb2422->BOOSTUP.bit.BOOST=3; //upstream port
// pusb2422->BOOSTDOWN.bit.BOOST1=0; // extra port
// pusb2422->BOOSTDOWN.bit.BOOST2=2; //MCU is close
pusb2422->STCD.bit.USB_ATTACH = 1;
USB_write2422_block();
USB2422_configure();
adc_extra = 0;
DBGC(DC_USB_CONFIGURE_COMPLETE);
}
uint16_t USB_active(void) { return (PORT->Group[USB2422_HUB_ACTIVE_GROUP].IN.reg & (1 << USB2422_HUB_ACTIVE_PIN)) != 0; }
uint16_t USB_active(void) { return USB2422_active(); }
void USB_set_host_by_voltage(void) {
// UP is upstream device (HOST)
@ -314,7 +228,7 @@ void USB_set_host_by_voltage(void) {
DBGC(DC_USB_SET_HOST_BY_VOLTAGE_COMPLETE);
}
uint8_t USB2422_Port_Detect_Init(void) {
uint8_t USB_Hub_Port_Detect_Init(void) {
uint32_t port_detect_retry_ms;
uint32_t tmod;

View file

@ -0,0 +1,51 @@
/*
Copyright 2018 Massdrop Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _USB2422_H_
#define _USB2422_H_
#define REV_USB2422 0x100
#define PORT_DETECT_RETRY_INTERVAL 2000
#define USB_EXTRA_ADC_THRESHOLD 900
#define USB_EXTRA_STATE_DISABLED 0
#define USB_EXTRA_STATE_ENABLED 1
#define USB_EXTRA_STATE_UNKNOWN 2
#define USB_EXTRA_STATE_DISABLED_UNTIL_REPLUG 3
#define USB_HOST_PORT_1 0
#define USB_HOST_PORT_2 1
#define USB_HOST_PORT_UNKNOWN 2
extern uint8_t usb_host_port;
extern uint8_t usb_extra_state;
extern uint8_t usb_extra_manual;
extern uint8_t usb_gcr_auto;
void USB_Hub_init(void);
uint8_t USB_Hub_Port_Detect_Init(void);
void USB_reset(void);
void USB_configure(void);
uint16_t USB_active(void);
void USB_set_host_by_voltage(void);
uint16_t adc_get(uint8_t muxpos);
void USB_HandleExtraDevice(void);
void USB_ExtraSetState(uint8_t state);
#endif //_USB2422_H_

Some files were not shown because too many files have changed in this diff Show more