Merge remote-tracking branch 'upstream/develop' into xap
This commit is contained in:
commit
bf66b91433
5591 changed files with 131128 additions and 54530 deletions
|
@ -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;
|
179
tmk_core/avr.mk
179
tmk_core/avr.mk
|
@ -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
|
|
@ -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;
|
|
@ -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)
|
|
@ -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
|
|
@ -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()
|
|
@ -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)
|
|
@ -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
|
||||
}
|
|
@ -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++);
|
||||
}
|
||||
}
|
|
@ -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))
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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); }
|
|
@ -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
|
|
@ -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__)
|
|
@ -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
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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))
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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>
|
|
@ -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); }
|
|
@ -1,2 +0,0 @@
|
|||
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/xprintf.S
|
||||
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/printf.c
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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++; }
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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)
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
@ -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_LAST─┴─WRITE_BASE │
|
||||
* WRITE_LAST ┘
|
||||
*
|
||||
* Compacted contents are the 1's complement of the actual EEPROM contents.
|
||||
* e.g. An 'FFFF' represents a '0000' value.
|
||||
*
|
||||
* The size of the 'compacted' area is equal to the size of the 'emulated' eeprom.
|
||||
* The size of the compacted-area and write log are configurable, and the combined
|
||||
* size of Compacted + WriteLog is a multiple FEE_PAGE_SIZE, which is MCU dependent.
|
||||
* Simulated Eeprom contents are located at the end of available flash space.
|
||||
*
|
||||
* The following configuration defines can be set:
|
||||
*
|
||||
* FEE_PAGE_COUNT # Total number of pages to use for eeprom simulation (Compact + Write log)
|
||||
* FEE_DENSITY_BYTES # Size of simulated eeprom. (Defaults to half the space allocated by FEE_PAGE_COUNT)
|
||||
* NOTE: The current implementation does not include page swapping,
|
||||
* and FEE_DENSITY_BYTES will consume that amount of RAM as a cached view of actual EEPROM contents.
|
||||
*
|
||||
* The maximum size of FEE_DENSITY_BYTES is currently 16384. The write log size equals
|
||||
* FEE_PAGE_COUNT * FEE_PAGE_SIZE - FEE_DENSITY_BYTES.
|
||||
* The larger the write log, the less frequently the compacted area needs to be rewritten.
|
||||
*
|
||||
*
|
||||
* *** General Algorithm ***
|
||||
*
|
||||
* During initialization:
|
||||
* The contents of the Compacted-flash area are loaded and the 1's complement value
|
||||
* is cached into memory (e.g. 0xFFFF in Flash represents 0x0000 in cache).
|
||||
* Write log entries are processed until a 0xFFFF is reached.
|
||||
* Each log entry updates a byte or word in the cache.
|
||||
*
|
||||
* During reads:
|
||||
* EEPROM contents are given back directly from the cache in memory.
|
||||
*
|
||||
* During writes:
|
||||
* The contents of the cache is updated first.
|
||||
* If the Compacted-flash area corresponding to the write address is unprogrammed, the 1's complement of the value is written directly into Compacted-flash
|
||||
* Otherwise:
|
||||
* If the write log is full, erase both the Compacted-flash area and the Write log, then write cached contents to the Compacted-flash area.
|
||||
* Otherwise a Write log entry is constructed and appended to the next free position in the Write log.
|
||||
*
|
||||
*
|
||||
* *** Write Log Structure ***
|
||||
*
|
||||
* Write log entries allow for optimized byte writes to addresses below 128. Writing 0 or 1 words are also optimized when word-aligned.
|
||||
*
|
||||
* === WRITE LOG ENTRY FORMATS ===
|
||||
*
|
||||
* ╔═══ Byte-Entry ══╗
|
||||
* ║0XXXXXXX║YYYYYYYY║
|
||||
* ║ └──┬──┘║└──┬───┘║
|
||||
* ║ Address║ Value ║
|
||||
* ╚════════╩════════╝
|
||||
* 0 <= Address < 0x80 (128)
|
||||
*
|
||||
* ╔ Word-Encoded 0 ╗
|
||||
* ║100XXXXXXXXXXXXX║
|
||||
* ║ │└─────┬─────┘║
|
||||
* ║ │Address >> 1 ║
|
||||
* ║ └── Value: 0 ║
|
||||
* ╚════════════════╝
|
||||
* 0 <= Address <= 0x3FFE (16382)
|
||||
*
|
||||
* ╔ Word-Encoded 1 ╗
|
||||
* ║101XXXXXXXXXXXXX║
|
||||
* ║ │└─────┬─────┘║
|
||||
* ║ │Address >> 1 ║
|
||||
* ║ └── Value: 1 ║
|
||||
* ╚════════════════╝
|
||||
* 0 <= Address <= 0x3FFE (16382)
|
||||
*
|
||||
* ╔═══ Reserved ═══╗
|
||||
* ║110XXXXXXXXXXXXX║
|
||||
* ╚════════════════╝
|
||||
*
|
||||
* ╔═══════════ Word-Next ═══════════╗
|
||||
* ║111XXXXXXXXXXXXX║YYYYYYYYYYYYYYYY║
|
||||
* ║ └─────┬─────┘║└───────┬──────┘║
|
||||
* ║(Address-128)>>1║ ~Value ║
|
||||
* ╚════════════════╩════════════════╝
|
||||
* ( 0 <= Address < 0x0080 (128): Reserved)
|
||||
* 0x80 <= Address <= 0x3FFE (16382)
|
||||
*
|
||||
* Write Log entry ranges:
|
||||
* 0x0000 ... 0x7FFF - Byte-Entry; address is (Entry & 0x7F00) >> 4; value is (Entry & 0xFF)
|
||||
* 0x8000 ... 0x9FFF - Word-Encoded 0; address is (Entry & 0x1FFF) << 1; value is 0
|
||||
* 0xA000 ... 0xBFFF - Word-Encoded 1; address is (Entry & 0x1FFF) << 1; value is 1
|
||||
* 0xC000 ... 0xDFFF - Reserved
|
||||
* 0xE000 ... 0xFFBF - Word-Next; address is (Entry & 0x1FFF) << 1 + 0x80; value is ~(Next_Entry)
|
||||
* 0xFFC0 ... 0xFFFE - Reserved
|
||||
* 0xFFFF - Unprogrammed
|
||||
*
|
||||
*/
|
||||
|
||||
#include "eeprom_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);
|
||||
}
|
||||
}
|
|
@ -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);
|
|
@ -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
|
|
@ -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++);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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))
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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"
|
|
@ -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 */
|
|
@ -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();
|
||||
}
|
|
@ -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
|
|
@ -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); }
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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) {}
|
|
@ -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++);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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; }
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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/>.
|
||||
*/
|
|
@ -1 +0,0 @@
|
|||
TEST_LIST += eeprom_stm32_tiny eeprom_stm32_large
|
|
@ -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); }
|
|
@ -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
|
|
@ -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);
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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 Bit’s 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
|
||||
*/
|
|
@ -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);
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_
|
||||
|
|
118
tmk_core/protocol/arm_atsam/shift_register.c
Normal file
118
tmk_core/protocol/arm_atsam/shift_register.c
Normal 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();
|
||||
}
|
|
@ -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_
|
|
@ -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);
|
||||
}
|
109
tmk_core/protocol/arm_atsam/spi_master.c
Normal file
109
tmk_core/protocol/arm_atsam/spi_master.c
Normal 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);
|
48
tmk_core/protocol/arm_atsam/spi_master.h
Normal file
48
tmk_core/protocol/arm_atsam/spi_master.h
Normal 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
|
|
@ -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_
|
|
@ -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;
|
||||
|
51
tmk_core/protocol/arm_atsam/usb/usb_hub.h
Normal file
51
tmk_core/protocol/arm_atsam/usb/usb_hub.h
Normal 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
Loading…
Add table
Add a link
Reference in a new issue