diff --git a/demos/AVR/RT-TEENSY2-USB/Makefile b/demos/AVR/RT-TEENSY2-USB/Makefile new file mode 100644 index 000000000..32c4e4b76 --- /dev/null +++ b/demos/AVR/RT-TEENSY2-USB/Makefile @@ -0,0 +1,562 @@ +# Hey Emacs, this is a -*- makefile -*- +#---------------------------------------------------------------------------- +# WinAVR Makefile Template written by Eric B. Weddington, J�rg Wunsch, et al. +# +# Released to the Public Domain +# +# Additional material for this makefile was written by: +# Peter Fleury +# Tim Henigan +# Colin O'Flynn +# Reiner Patommel +# Markus Pfaff +# Sander Pool +# Frederik Rouleau +# Carlos Lamas +# +#---------------------------------------------------------------------------- +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device, using avrdude. +# Please customize the avrdude settings below first! +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + +# MCU name +MCU = at90usb1286 + +# Processor frequency. +F_CPU = 16000000 + +# Output format. (can be srec, ihex, binary) +FORMAT = ihex + +# Target file name (without extension). +TARGET = ch + +# Object files directory +# To put object files in current directory, use a dot (.), do NOT make +# this an empty or blank macro! +OBJDIR = . + +# Imported source files +CHIBIOS = ../../.. +include $(CHIBIOS)/os/hal/hal.mk +include $(CHIBIOS)/os/hal/boards/PJRC_TEENSY_2PLUSPLUS/board.mk +include $(CHIBIOS)/os/hal/ports/AVR/platform.mk +include $(CHIBIOS)/os/hal/osal/rt/osal.mk +include $(CHIBIOS)/os/rt/rt.mk +include $(CHIBIOS)/os/common/ports/AVR/compilers/GCC/mk/port.mk +include $(CHIBIOS)/os/hal/lib/streams/streams.mk +include $(CHIBIOS)/os/various/shell/shell.mk + +# List C source files here. (C dependencies are automatically generated.) +SRC = $(KERNSRC) \ + $(PORTSRC) \ + $(OSALSRC) \ + $(HALSRC) \ + $(PLATFORMSRC) \ + $(BOARDSRC) \ + $(STREAMSSRC) \ + $(SHELLSRC) \ + usbcfg.c \ + main.c + +# List C++ source files here. (C dependencies are automatically generated.) +CPPSRC = + +# List Assembler source files here. +# Make them always end in a capital .S. Files ending in a lowercase .s +# will not be considered source files but generated files (assembler +# output from the compiler), and will be deleted upon "make clean"! +# Even though the DOS/Win* filesystem matches both .s and .S the same, +# it will preserve the spelling of the filenames, and gcc itself does +# care about how the name is spelled on its command-line. +ASRC = + +# Optimization level, can be [0, 1, 2, 3, s]. +# 0 = turn off optimization. s = optimize for size. +# (Note: 3 is not always the best optimization level. See avr-libc FAQ.) +OPT = s + +# 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 + +# List any extra directories to look for include files 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. +EXTRAINCDIRS = $(CHIBIOS)/os/license $(PORTINC) $(KERNINC) $(TESTINC) \ + $(HALINC) $(OSALINC) $(PLATFORMINC) \ + $(BOARDINC) $(CHIBIOS)/os/various/shell \ + $(STREAMSINC) + +# Compiler flag to set the C Standard level. +# c89 = "ANSI" C +# gnu89 = c89 plus GCC extensions +# c99 = ISO C99 standard (not yet fully implemented) +# gnu99 = c99 plus GCC extensions +CSTANDARD = -std=gnu11 + +# Place -D or -U options here for C sources +CDEFS = -DF_CPU=$(F_CPU)UL + +# Place -D or -U options here for ASM sources +ADEFS = -DF_CPU=$(F_CPU) + +# Place -D or -U options here for C++ sources +CPPDEFS = -DF_CPU=$(F_CPU)UL +#CPPDEFS += -D__STDC_LIMIT_MACROS +#CPPDEFS += -D__STDC_CONSTANT_MACROS + +#---------------- Compiler Options C ---------------- +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CFLAGS = -g$(DEBUG) +CFLAGS += $(CDEFS) +CFLAGS += -O$(OPT) +CFLAGS += -funsigned-char +CFLAGS += -funsigned-bitfields +CFLAGS += -fpack-struct +CFLAGS += -fshort-enums +#CFLAGS += -fno-strict-aliasing +CFLAGS += -Wall +CFLAGS += -Wstrict-prototypes +#CFLAGS += -mshort-calls +#CFLAGS += -fno-unit-at-a-time +#CFLAGS += -Wundef +#CFLAGS += -Wunreachable-code +#CFLAGS += -Wsign-compare +CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst) +CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +CFLAGS += $(CSTANDARD) +CFLAGS += -mrelax + +#---------------- Compiler Options C++ ---------------- +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CPPFLAGS = -g$(DEBUG) +CPPFLAGS += $(CPPDEFS) +CPPFLAGS += -O$(OPT) +CPPFLAGS += -funsigned-char +CPPFLAGS += -funsigned-bitfields +CPPFLAGS += -fpack-struct +CPPFLAGS += -fshort-enums +CPPFLAGS += -fno-exceptions +CPPFLAGS += -Wall +CFLAGS += -Wundef +#CPPFLAGS += -mshort-calls +#CPPFLAGS += -fno-unit-at-a-time +#CPPFLAGS += -Wstrict-prototypes +#CPPFLAGS += -Wunreachable-code +#CPPFLAGS += -Wsign-compare +CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst) +CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +#CPPFLAGS += $(CSTANDARD) + +#---------------- Assembler Options ---------------- +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns: create listing +# -gstabs: have the assembler create line number information; note that +# for use in COFF files, additional information about filenames +# and function names needs to be present in the assembler source +# files -- see avr-libc docs [FIXME: not yet described there] +# -listing-cont-lines: Sets the maximum number of continuation lines of hex +# dump that will be displayed for a given single line of source input. +ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100 + +#---------------- Library Options ---------------- +# Minimalistic printf version +PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min + +# Floating point printf version (requires MATH_LIB = -lm below) +PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt + +# If this is left blank, then it will use the Standard printf version. +PRINTF_LIB = $(PRINTF_LIB_MIN) +#PRINTF_LIB = $(PRINTF_LIB_MIN) +#PRINTF_LIB = $(PRINTF_LIB_FLOAT) + +# Minimalistic scanf version +SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min + +# Floating point + %[ scanf version (requires MATH_LIB = -lm below) +SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt + +# If this is left blank, then it will use the Standard scanf version. +SCANF_LIB = $(SCANF_LIB_MIN) +#SCANF_LIB = $(SCANF_LIB_MIN) +#SCANF_LIB = $(SCANF_LIB_FLOAT) + +MATH_LIB = -lm + +# 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 = + +#---------------- Linker Options ---------------- +# -Wl,...: tell GCC to pass this to linker. +# -Map: create map file +# --cref: add cross reference to map file +LDFLAGS = -Wl,-Map=$(TARGET).map,--cref +LDFLAGS += $(EXTMEMOPTS) +LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS)) +LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) +#LDFLAGS += -T linker_script.x + +#---------------- Programming Options (avrdude) ---------------- + +# Programming hardware: alf avr910 avrisp bascom bsd +# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500 +# +# Type: avrdude -c ? +# to get a full listing. +# +AVRDUDE_PROGRAMMER = arduino + +# com1 = serial port. Use lpt1 to connect to parallel port. +AVRDUDE_PORT = /dev/tty.usbserial-A7004IPU + +AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex +#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep + +# Uncomment the following if you want avrdude's erase cycle counter. +# Note that this counter needs to be initialized first using -Yn, +# see avrdude manual. +#AVRDUDE_ERASE_COUNTER = -y + +# Uncomment the following if you do /not/ wish a verification to be +# performed after programming the device. +#AVRDUDE_NO_VERIFY = -V + +# Increase verbosity level. Please use this when submitting bug +# reports about avrdude. See +# to submit bug reports. +#AVRDUDE_VERBOSE = -v -v + +AVRDUDE_FLAGS = -p $(MCU) +AVRDUDE_FLAGS += -P $(AVRDUDE_PORT) +AVRDUDE_FLAGS += -b 57600 +AVRDUDE_FLAGS += -c $(AVRDUDE_PROGRAMMER) +AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY) +AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE) +AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER) + +#---------------- Debugging Options ---------------- + +# 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 + +#============================================================================ + +# Define programs and commands. +SHELL = sh +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +AR = avr-ar rcs +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +REMOVEDIR = rm -rf +COPY = cp +WINSHELL = cmd + +# Define Messages +# English +MSG_ERRORS_NONE = Errors: none +MSG_BEGIN = -------- begin -------- +MSG_END = -------- end -------- +MSG_SIZE_BEFORE = Size before: +MSG_SIZE_AFTER = Size after: +MSG_COFF = Converting to AVR COFF: +MSG_EXTENDED_COFF = Converting to AVR Extended COFF: +MSG_FLASH = Creating load file for Flash: +MSG_EEPROM = Creating load file for EEPROM: +MSG_EXTENDED_LISTING = Creating Extended Listing: +MSG_SYMBOL_TABLE = Creating Symbol Table: +MSG_LINKING = Linking: +MSG_COMPILING = Compiling C: +MSG_COMPILING_CPP = Compiling C++: +MSG_ASSEMBLING = Assembling: +MSG_CLEANING = Cleaning project: +MSG_CREATING_LIBRARY = Creating library: + +# Define all object files. +OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o) + +# Define all listing files. +LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst) + +# Compiler flags to generate dependency files. +GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS) +ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + +# Default target. +all: begin gccversion sizebefore build sizeafter end + +# Change the build target to build a HEX file or a library. +build: elf hex bin eep lss sym +#build: lib + +elf: $(TARGET).elf +hex: $(TARGET).hex +bin: $(TARGET).bin +eep: $(TARGET).eep +lss: $(TARGET).lss +sym: $(TARGET).sym +LIBNAME=lib$(TARGET).a +lib: $(LIBNAME) + +# Eye candy. +# AVR Studio 3.x does not check make's exit code but relies on +# the following magic strings to be generated by the compile job. +begin: + @echo + @echo $(MSG_BEGIN) + +end: + @echo $(MSG_END) + @echo + +# Display size of file. +HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex +ELFSIZE = $(SIZE) $(TARGET).elf + +sizebefore: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \ + 2>/dev/null; echo; fi + +sizeafter: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \ + 2>/dev/null; echo; fi + +# Display compiler version information. +gccversion : + @$(CC) --version + +# Program the device. +program: $(TARGET).hex $(TARGET).eep + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) + +# 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 $(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 $(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 \ + $(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: $(TARGET).elf + @echo + @echo $(MSG_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-avr $< $(TARGET).cof + +extcoff: $(TARGET).elf + @echo + @echo $(MSG_EXTENDED_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof + +# Create final output files (.hex, .eep) from ELF output file. +%.hex: %.elf + @echo + @echo $(MSG_FLASH) $@ + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +%.bin: %.elf + @echo + @echo $(MSG_FLASH) $@ + $(OBJCOPY) -O binary -R .eeprom $< $@ + +%.eep: %.elf + @echo + @echo $(MSG_EEPROM) $@ + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0 + +# Create extended listing file from ELF output file. +%.lss: %.elf + @echo + @echo $(MSG_EXTENDED_LISTING) $@ + $(OBJDUMP) -h -S $< > $@ + +# Create a symbol table from ELF output file. +%.sym: %.elf + @echo + @echo $(MSG_SYMBOL_TABLE) $@ + $(NM) -n $< > $@ + +# Create library from object files. +.SECONDARY : $(TARGET).a +.PRECIOUS : $(OBJ) +%.a: $(OBJ) + @echo + @echo $(MSG_CREATING_LIBRARY) $@ + $(AR) $@ $(OBJ) + +# Link: create ELF output file from object files. +.SECONDARY : $(TARGET).elf +.PRECIOUS : $(OBJ) +%.elf: $(OBJ) + @echo + @echo $(MSG_LINKING) $@ + $(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS) + +# Compile: create object files from C source files. +$(OBJDIR)/%.o : %.c + @echo + @echo $(MSG_COMPILING) $< + $(CC) -c $(ALL_CFLAGS) $< -o $@ + +# Compile: create object files from C++ source files. +$(OBJDIR)/%.o : %.cpp + @echo + @echo $(MSG_COMPILING_CPP) $< + $(CC) -c $(ALL_CPPFLAGS) $< -o $@ + +# Compile: create assembler files from C source files. +%.s : %.c + $(CC) -S $(ALL_CFLAGS) $< -o $@ + +# Compile: create assembler files from C++ source files. +%.s : %.cpp + $(CC) -S $(ALL_CPPFLAGS) $< -o $@ + +# Assemble: create object files from assembler source files. +$(OBJDIR)/%.o : %.S + @echo + @echo $(MSG_ASSEMBLING) $< + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + +# Create preprocessed source for use in sending a bug report. +%.i : %.c + $(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@ + +# Target: clean project. +clean: begin clean_list end + +clean_list : + @echo + @echo $(MSG_CLEANING) + $(REMOVE) $(TARGET).hex + $(REMOVE) $(TARGET).bin + $(REMOVE) $(TARGET).eep + $(REMOVE) $(TARGET).cof + $(REMOVE) $(TARGET).elf + $(REMOVE) $(TARGET).map + $(REMOVE) $(TARGET).sym + $(REMOVE) $(TARGET).lss + $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o) + $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst) + $(REMOVE) $(SRC:.c=.s) + $(REMOVE) $(SRC:.c=.d) + $(REMOVE) $(SRC:.c=.i) + $(REMOVEDIR) .dep + +# Create object files directory +$(shell mkdir $(OBJDIR) 2>/dev/null) + +# Include the dependency files. +-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) + +# Listing of phony targets. +.PHONY : all begin finish end sizebefore sizeafter gccversion \ +build elf hex bin eep lss sym coff extcoff \ +clean clean_list program debug gdb-config diff --git a/demos/AVR/RT-TEENSY2-USB/chconf.h b/demos/AVR/RT-TEENSY2-USB/chconf.h new file mode 100644 index 000000000..5aa8ecd0a --- /dev/null +++ b/demos/AVR/RT-TEENSY2-USB/chconf.h @@ -0,0 +1,549 @@ +/* + Copyright (C) 2015 Robert Lippert + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file templates/chconf.h + * @brief Configuration file template. + * @details A copy of this file must be placed in each project directory, it + * contains the application specific kernel settings. + * + * @addtogroup config + * @details Kernel related settings and hooks. + * @{ + */ + +#ifndef CHCONF_H_ +#define CHCONF_H_ + +#define _CHIBIOS_RT_CONF_ + +/*===========================================================================*/ +/** + * @name System timers settings + * @{ + */ +/*===========================================================================*/ + +/** + * @brief System time counter resolution. + * @note Allowed values are 16 or 32 bits. + */ +#define CH_CFG_ST_RESOLUTION 16 + +/** + * @brief System tick frequency. + * @details Frequency of the system timer that drives the system ticks. This + * setting also defines the system tick time unit. + */ +#define CH_CFG_ST_FREQUENCY 1000 + +/** + * @brief Time delta constant for the tick-less mode. + * @note If this value is zero then the system uses the classic + * periodic tick. This value represents the minimum number + * of ticks that is safe to specify in a timeout directive. + * The value one is not valid, timeouts are rounded up to + * this value. + */ +#define CH_CFG_ST_TIMEDELTA 0 + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel parameters and options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Round robin interval. + * @details This constant is the number of system ticks allowed for the + * threads before preemption occurs. Setting this value to zero + * disables the preemption for threads with equal priority and the + * round robin becomes cooperative. Note that higher priority + * threads can still preempt, the kernel is always preemptive. + * + * @note Disabling the round robin preemption makes the kernel more compact + * and generally faster. + */ +#define CH_CFG_TIME_QUANTUM 20 + +/** + * @brief Managed RAM size. + * @details Size of the RAM area to be managed by the OS. If set to zero + * then the whole available RAM is used. The core memory is made + * available to the heap allocator and/or can be used directly through + * the simplified core memory allocator. + * + * @note In order to let the OS manage the whole RAM the linker script must + * provide the @p __heap_base__ and @p __heap_end__ symbols. + * @note Requires @p CH_CFG_USE_MEMCORE. + */ +#define CH_CFG_MEMCORE_SIZE 1536 + +/** + * @brief Idle thread automatic spawn suppression. + * @details When this option is activated the function @p chSysInit() + * does not spawn the idle thread automatically. The application has + * then the responsibility to do one of the following: + * - Spawn a custom idle thread at priority @p IDLEPRIO. + * - Change the main() thread priority to @p IDLEPRIO then enter + * an endless loop. In this scenario the @p main() thread acts as + * the idle thread. + * . + * @note Unless an idle thread is spawned the @p main() thread must not + * enter a sleep state. + */ +#define CH_CFG_NO_IDLE_THREAD FALSE + +/** @} */ + +/*===========================================================================*/ +/** + * @name Performance options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief OS optimization. + * @details If enabled then time efficient rather than space efficient code + * is used when two possible implementations exist. + * + * @note This is not related to the compiler optimization options. + * @note The default is @p TRUE. + */ +#define CH_CFG_OPTIMIZE_SPEED TRUE + +/** @} */ + +/*===========================================================================*/ +/** + * @name Subsystem options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Time Measurement APIs. + * @details If enabled then the time measurement APIs are included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#define CH_CFG_USE_TM FALSE + +/** + * @brief Threads registry APIs. + * @details If enabled then the registry APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#define CH_CFG_USE_REGISTRY TRUE + +/** + * @brief Threads synchronization APIs. + * @details If enabled then the @p chThdWait() function is included in + * the kernel. + * + * @note The default is @p TRUE. + */ +#define CH_CFG_USE_WAITEXIT TRUE + +/** + * @brief Semaphores APIs. + * @details If enabled then the Semaphores APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#define CH_CFG_USE_SEMAPHORES TRUE + +/** + * @brief Semaphores queuing mode. + * @details If enabled then the threads are enqueued on semaphores by + * priority rather than in FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special requirements. + * @note Requires @p CH_CFG_USE_SEMAPHORES. + */ +#define CH_CFG_USE_SEMAPHORES_PRIORITY FALSE + +/** + * @brief Atomic semaphore API. + * @details If enabled then the semaphores the @p chSemSignalWait() API + * is included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_SEMAPHORES. + */ +#define CH_USE_SEMSW TRUE + +/** + * @brief Mutexes APIs. + * @details If enabled then the mutexes APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#define CH_CFG_USE_MUTEXES TRUE + +/** + * @brief Enables recursive behavior on mutexes. + * @note Recursive mutexes are heavier and have an increased + * memory footprint. + * + * @note The default is @p FALSE. + * @note Requires @p CH_CFG_USE_MUTEXES. + */ +#define CH_CFG_USE_MUTEXES_RECURSIVE FALSE + +/** + * @brief Conditional Variables APIs. + * @details If enabled then the conditional variables APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_MUTEXES. + */ +#define CH_CFG_USE_CONDVARS TRUE + +/** + * @brief Conditional Variables APIs with timeout. + * @details If enabled then the conditional variables APIs with timeout + * specification are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_CONDVARS. + */ +#define CH_CFG_USE_CONDVARS_TIMEOUT TRUE + +/** + * @brief Events Flags APIs. + * @details If enabled then the event flags APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#define CH_CFG_USE_EVENTS TRUE + +/** + * @brief Events Flags APIs with timeout. + * @details If enabled then the events APIs with timeout specification + * are included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_EVENTS. + */ +#define CH_CFG_USE_EVENTS_TIMEOUT TRUE + +/** + * @brief Synchronous Messages APIs. + * @details If enabled then the synchronous messages APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#define CH_CFG_USE_MESSAGES TRUE + +/** + * @brief Synchronous Messages queuing mode. + * @details If enabled then messages are served by priority rather than in + * FIFO order. + * + * @note The default is @p FALSE. Enable this if you have special requirements. + * @note Requires @p CH_CFG_USE_MESSAGES. + */ +#define CH_CFG_USE_MESSAGES_PRIORITY FALSE + +/** + * @brief Mailboxes APIs. + * @details If enabled then the asynchronous messages (mailboxes) APIs are + * included in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_SEMAPHORES. + */ +#define CH_CFG_USE_MAILBOXES TRUE + +/** + * @brief I/O Queues APIs. + * @details If enabled then the I/O queues APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#define CH_CFG_USE_QUEUES TRUE + +/** + * @brief Core Memory Manager APIs. + * @details If enabled then the core memory manager APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#define CH_CFG_USE_MEMCORE TRUE + +/** + * @brief Heap Allocator APIs. + * @details If enabled then the memory heap allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_MEMCORE and either @p CH_CFG_USE_MUTEXES or + * @p CH_CFG_USE_SEMAPHORES. + * @note Mutexes are recommended. + */ +#define CH_CFG_USE_HEAP TRUE + +/** + * @brief C-runtime allocator. + * @details If enabled the the heap allocator APIs just wrap the C-runtime + * @p malloc() and @p free() functions. + * + * @note The default is @p FALSE. + * @note Requires @p CH_CFG_USE_HEAP. + * @note The C-runtime may or may not require @p CH_CFG_USE_MEMCORE, see the + * appropriate documentation. + */ +#define CH_CFG_USE_MALLOC_HEAP FALSE + +/** + * @brief Memory Pools Allocator APIs. + * @details If enabled then the memory pools allocator APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + */ +#define CH_CFG_USE_MEMPOOLS FALSE + +/** + * @brief Dynamic Threads APIs. + * @details If enabled then the dynamic threads creation APIs are included + * in the kernel. + * + * @note The default is @p TRUE. + * @note Requires @p CH_CFG_USE_WAITEXIT. + * @note Requires @p CH_CFG_USE_HEAP and/or @p CH_CFG_USE_MEMPOOLS. + */ +#define CH_CFG_USE_DYNAMIC TRUE + +/** @} */ + +/*===========================================================================*/ +/** + * @name Debug options + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Debug option, kernel statistics. + * + * @note The default is @p FALSE. + */ +#define CH_DBG_STATISTICS FALSE + +/** + * @brief Debug option, system state check. + * @details If enabled the correct call protocol for system APIs is checked + * at runtime. + * + * @note The default is @p FALSE. + */ +#define CH_DBG_SYSTEM_STATE_CHECK FALSE + +/** + * @brief Debug option, parameters checks. + * @details If enabled then the checks on the API functions input + * parameters are activated. + * + * @note The default is @p FALSE. + */ +#define CH_DBG_ENABLE_CHECKS FALSE + +/** + * @brief Debug option, consistency checks. + * @details If enabled then all the assertions in the kernel code are + * activated. This includes consistency checks inside the kernel, + * runtime anomalies and port-defined checks. + * + * @note The default is @p FALSE. + */ +#define CH_DBG_ENABLE_ASSERTS FALSE + +/** + * @brief Debug option, trace buffer. + * @details If enabled then the context switch circular trace buffer is + * activated. + * + * @note The default is @p FALSE. + */ +#define CH_DBG_ENABLE_TRACE FALSE + +/** + * @brief Debug option, stack checks. + * @details If enabled then a runtime stack check is performed. + * + * @note The default is @p FALSE. + * @note The stack check is performed in a architecture/port dependent way. + * It may not be implemented or some ports. + * @note The default failure mode is to halt the system with the global + * @p panic_msg variable set to @p NULL. + */ +#define CH_DBG_ENABLE_STACK_CHECK FALSE + +/** + * @brief Debug option, stacks initialization. + * @details If enabled then the threads working area is filled with a byte + * value when a thread is created. This can be useful for the + * runtime measurement of the used stack. + * + * @note The default is @p FALSE. + */ +#define CH_DBG_FILL_THREADS FALSE + +/** + * @brief Debug option, threads profiling. + * @details If enabled then a field is added to the @p Thread structure that + * counts the system ticks occurred while executing the thread. + * + * @note The default is @p TRUE. + * @note This debug option is defaulted to TRUE because it is required by + * some test cases into the test suite. + */ +#define CH_DBG_THREADS_PROFILING FALSE + +/** @} */ + +/*===========================================================================*/ +/** + * @name Kernel hooks + * @{ + */ +/*===========================================================================*/ + +/** + * @brief Threads descriptor structure extension. + * @details User fields added to the end of the @p thread_t structure. + */ +#define CH_CFG_THREAD_EXTRA_FIELDS \ + /* Add threads custom fields here.*/ + +/** + * @brief Threads initialization hook. + * @details User initialization code added to the @p chThdInit() API. + * + * @note It is invoked from within @p chThdInit() and implicitly from all + * the threads creation APIs. + */ +#define CH_CFG_THREAD_INIT_HOOK(tp) { \ + /* Add threads initialization code here.*/ \ +} + +/** + * @brief Threads finalization hook. + * @details User finalization code added to the @p chThdExit() API. + */ +#define CH_CFG_THREAD_EXIT_HOOK(tp) { \ + /* Add threads finalization code here.*/ \ +} + +/** + * @brief Context switch hook. + * @details This hook is invoked just before switching between threads. + */ +#define CH_CFG_CONTEXT_SWITCH_HOOK(ntp, otp) { \ + /* Context switch code here.*/ \ +} + +/** + * @brief ISR enter hook. + */ +#define CH_CFG_IRQ_PROLOGUE_HOOK() { \ + /* IRQ prologue code here.*/ \ +} + +/** + * @brief ISR exit hook. + */ +#define CH_CFG_IRQ_EPILOGUE_HOOK() { \ + /* IRQ epilogue code here.*/ \ +} + +/** + * @brief Idle thread enter hook. + * @note This hook is invoked within a critical zone, no OS functions + * should be invoked from here. + * @note This macro can be used to activate a power saving mode. + */ +#define CH_CFG_IDLE_ENTER_HOOK() { \ + /* Idle-enter code here.*/ \ +} + +/** + * @brief Idle thread leave hook. + * @note This hook is invoked within a critical zone, no OS functions + * should be invoked from here. + * @note This macro can be used to deactivate a power saving mode. + */ +#define CH_CFG_IDLE_LEAVE_HOOK() { \ + /* Idle-leave code here.*/ \ +} + +/** + * @brief Idle Loop hook. + * @details This hook is continuously invoked by the idle thread loop. + */ +#define CH_CFG_IDLE_LOOP_HOOK() { \ + /* Idle loop code here.*/ \ +} + +/** + * @brief System tick event hook. + * @details This hook is invoked in the system tick handler immediately + * after processing the virtual timers queue. + */ +#define CH_CFG_SYSTEM_TICK_HOOK() { \ + /* System tick event code here.*/ \ +} + +/** + * @brief System halt hook. + * @details This hook is invoked in case to a system halting error before + * the system is halted. + */ +#define CH_CFG_SYSTEM_HALT_HOOK(reason) { \ + /* System halt code here.*/ \ +} + +/** + * @brief Trace hook. + * @details This hook is invoked each time a new record is written in the + * trace buffer. + */ +#define CH_CFG_TRACE_HOOK(tep) { \ + /* Trace code here.*/ \ +} + +/** @} */ + +/*===========================================================================*/ +/* Port-specific settings (override port settings defaulted in chcore.h). */ +/*===========================================================================*/ + +#define SHELL_CMD_TEST_ENABLED FALSE + +#endif /* CHCONF_H_ */ + +/** @} */ diff --git a/demos/AVR/RT-TEENSY2-USB/halconf.h b/demos/AVR/RT-TEENSY2-USB/halconf.h new file mode 100644 index 000000000..f2ceabe9f --- /dev/null +++ b/demos/AVR/RT-TEENSY2-USB/halconf.h @@ -0,0 +1,355 @@ +/* + Copyright (C) 2015 Robert Lippert + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file templates/halconf.h + * @brief HAL configuration header. + * @details HAL configuration file, this file allows to enable or disable the + * various device drivers from your application. You may also use + * this file in order to override the device drivers default settings. + * + * @addtogroup HAL_CONF + * @{ + */ + +#ifndef HALCONF_H_ +#define HALCONF_H_ + +#include "mcuconf.h" + +/** + * @brief Enables the TM subsystem. + */ +#if !defined(HAL_USE_TM) || defined(__DOXYGEN__) +#define HAL_USE_TM FALSE +#endif + +/** + * @brief Enables the PAL subsystem. + */ +#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__) +#define HAL_USE_PAL TRUE +#endif + +/** + * @brief Enables the ADC subsystem. + */ +#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__) +#define HAL_USE_ADC FALSE +#endif + +/** + * @brief Enables the DAC subsystem. + */ +#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__) +#define HAL_USE_DAC FALSE +#endif + +/** + * @brief Enables the CAN subsystem. + */ +#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__) +#define HAL_USE_CAN FALSE +#endif + +/** + * @brief Enables the EXT subsystem. + */ +#if !defined(HAL_USE_EXT) || defined(__DOXYGEN__) +#define HAL_USE_EXT FALSE +#endif + +/** + * @brief Enables the GPT subsystem. + */ +#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__) +#define HAL_USE_GPT FALSE +#endif + +/** + * @brief Enables the I2C subsystem. + */ +#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__) +#define HAL_USE_I2C FALSE +#endif + +/** + * @brief Enables the ICU subsystem. + */ +#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__) +#define HAL_USE_ICU FALSE +#endif + +/** + * @brief Enables the MAC subsystem. + */ +#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__) +#define HAL_USE_MAC FALSE +#endif + +/** + * @brief Enables the MMC_SPI subsystem. + */ +#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__) +#define HAL_USE_MMC_SPI FALSE +#endif + +/** + * @brief Enables the PWM subsystem. + */ +#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__) +#define HAL_USE_PWM FALSE +#endif + +/** + * @brief Enables the RTC subsystem. + */ +#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__) +#define HAL_USE_RTC FALSE +#endif + +/** + * @brief Enables the SDC subsystem. + */ +#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__) +#define HAL_USE_SDC FALSE +#endif + +/** + * @brief Enables the SERIAL subsystem. + */ +#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL FALSE +#endif + +/** + * @brief Enables the SERIAL over USB subsystem. + */ +#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__) +#define HAL_USE_SERIAL_USB TRUE +#endif + +/** + * @brief Enables the SPI subsystem. + */ +#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__) +#define HAL_USE_SPI FALSE +#endif + +/** + * @brief Enables the UART subsystem. + */ +#if !defined(HAL_USE_UART) || defined(__DOXYGEN__) +#define HAL_USE_UART FALSE +#endif + +/** + * @brief Enables the USB subsystem. + */ +#if !defined(HAL_USE_USB) || defined(__DOXYGEN__) +#define HAL_USE_USB TRUE +#endif + +/** + * @brief Enables the I2S subsystem. + */ +#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__) +#define HAL_USE_I2S FALSE +#endif + +/** + * @brief Enables the WDG subsystem. + */ +#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__) +#define HAL_USE_WDG FALSE +#endif + +/*===========================================================================*/ +/* ADC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__) +#define ADC_USE_WAIT TRUE +#endif + +/** + * @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define ADC_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* CAN driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Sleep mode related APIs inclusion switch. + */ +#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__) +#define CAN_USE_SLEEP_MODE TRUE +#endif + +/*===========================================================================*/ +/* I2C driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables the mutual exclusion APIs on the I2C bus. + */ +#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define I2C_USE_MUTUAL_EXCLUSION TRUE +#endif + +/*===========================================================================*/ +/* MAC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables an event sources for incoming packets. + */ +#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__) +#define MAC_USE_ZERO_COPY FALSE +#endif + +/** + * @brief Enables an event sources for incoming packets. + */ +#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__) +#define MAC_USE_EVENTS TRUE +#endif + +/*===========================================================================*/ +/* MMC_SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the MMC waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + * This option is recommended also if the SPI driver does not + * use a DMA channel and heavily loads the CPU. + */ +#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__) +#define MMC_NICE_WAITING TRUE +#endif + +/*===========================================================================*/ +/* SDC driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Number of initialization attempts before rejecting the card. + * @note Attempts are performed at 10mS intervals. + */ +#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__) +#define SDC_INIT_RETRY 100 +#endif + +/** + * @brief Include support for MMC cards. + * @note MMC support is not yet implemented so this option must be kept + * at @p FALSE. + */ +#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__) +#define SDC_MMC_SUPPORT FALSE +#endif + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the MMC waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + */ +#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__) +#define SDC_NICE_WAITING TRUE +#endif + +/*===========================================================================*/ +/* SERIAL driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Default bit rate. + * @details Configuration parameter, this is the baud rate selected for the + * default configuration. + */ +#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__) +#define SERIAL_DEFAULT_BITRATE 57600 +#endif + +/** + * @brief Serial buffers size. + * @details Configuration parameter, you can change the depth of the queue + * buffers depending on the requirements of your application. + * @note The default is 64 bytes for both the transmission and receive + * buffers. + */ +#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_BUFFERS_SIZE 16 +#endif + +/*===========================================================================*/ +/* SERIAL_USB driver related setting. */ +/*===========================================================================*/ + +/** + * @brief Serial over USB buffers size. + * @details Configuration parameter, the buffer size must be a multiple of + * the USB data endpoint maximum packet size. + * @note The default is 64 bytes for both the transmission and receive + * buffers. + */ +#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__) +#define SERIAL_USB_BUFFERS_SIZE 64 +#endif + +/*===========================================================================*/ +/* SPI driver related settings. */ +/*===========================================================================*/ + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__) +#define SPI_USE_WAIT FALSE +#endif + +/** + * @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define SPI_USE_MUTUAL_EXCLUSION TRUE +#endif + +/* Turn off unused community HAL support */ +#define HAL_USE_COMMUNITY FALSE +#define HAL_USE_CRC FALSE +#define HAL_USE_EICU FALSE +#define HAL_USE_NAND FALSE +#define HAL_USE_ONEWIRE FALSE + +#endif /* HALCONF_H_ */ + +/** @} */ diff --git a/demos/AVR/RT-TEENSY2-USB/main.c b/demos/AVR/RT-TEENSY2-USB/main.c new file mode 100644 index 000000000..376751852 --- /dev/null +++ b/demos/AVR/RT-TEENSY2-USB/main.c @@ -0,0 +1,84 @@ +/* + Copyright (C) 2015 Robert Lippert + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "ch.h" +#include "hal.h" +#include "shell.h" +#include "usbcfg.h" + +static THD_WORKING_AREA(waThread1, 128); +static THD_FUNCTION(Thread1, arg) { + (void)arg; + chRegSetThreadName("blinker"); + while (true) { + palTogglePad(IOPORT4, BOARD_LED1); + chThdSleepMilliseconds(1000); + } +} + +#define SHELL_WA_SIZE THD_WORKING_AREA_SIZE(512) + +static const ShellConfig shell_cfg1 = { + (BaseSequentialStream *)&SDU1, + NULL +}; + +/* + * Application entry point. + */ +int main(void) { + /* + * System initializations. + * - HAL initialization, this also initializes the configured device drivers + * and performs the board-specific initializations. + * - Kernel initialization, the main() function becomes a thread and the + * RTOS is active. + */ + halInit(); + chSysInit(); + + palClearPad(IOPORT4, BOARD_LED1); + + /* + * Shell manager initialization. + */ + shellInit(); + + /* Initializes a serial-over-USB CDC driver. */ + sduObjectInit(&SDU1); + sduStart(&SDU1, &serusbcfg); + + /* Initialize USB */ + usbStart(serusbcfg.usbp, &usbcfg); + + /* + * Starts the LED blinker thread. + */ + chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL); + + /* + * Normal main() thread activity. + */ + while (true) { + if (SDU1.config->usbp->state == USB_ACTIVE) { + thread_t *shelltp = chThdCreateFromHeap(NULL, SHELL_WA_SIZE, + "shell", NORMALPRIO + 1, + shellThread, (void *)&shell_cfg1); + chThdWait(shelltp); /* Waiting termination. */ + } + chThdSleepMilliseconds(1000); + } +} diff --git a/demos/AVR/RT-TEENSY2-USB/mcuconf.h b/demos/AVR/RT-TEENSY2-USB/mcuconf.h new file mode 100644 index 000000000..c5a784bd1 --- /dev/null +++ b/demos/AVR/RT-TEENSY2-USB/mcuconf.h @@ -0,0 +1,90 @@ +/* + Copyright (C) 2015 Robert Lippert + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef MCUCONF_H_ +#define MCUCONF_H_ + +/* + * AVR drivers configuration. + * The following settings override the default settings present in + * the various device driver implementation headers. + * Note that the settings for each driver only have effect if the driver + * is enabled in halconf.h. + */ + +/* + * ADC driver system settings. + */ +#define AVR_ADC_USE_ADC1 FALSE + +/* + * CAN driver system settings. + */ + +/* + * MAC driver system settings. + */ + +/* + * PWM driver system settings. + */ +#define AVR_PWM_USE_TIM1 FALSE +#define AVR_PWM_USE_TIM2 FALSE +#define AVR_PWM_USE_TIM3 FALSE +#define AVR_PWM_USE_TIM4 FALSE +#define AVR_PWM_USE_TIM5 FALSE + +/* + * ICU driver system settings. + */ +#define AVR_ICU_USE_TIM1 FALSE +#define AVR_ICU_USE_TIM3 FALSE +#define AVR_ICU_USE_TIM4 FALSE +#define AVR_ICU_USE_TIM5 FALSE + +/* + * GPT driver system settings. + */ +#define AVR_GPT_USE_TIM1 FALSE +#define AVR_GPT_USE_TIM2 FALSE +#define AVR_GPT_USE_TIM3 FALSE +#define AVR_GPT_USE_TIM4 FALSE +#define AVR_GPT_USE_TIM5 FALSE + +/* + * SERIAL driver system settings. + */ +#define AVR_SERIAL_USE_USART0 FALSE +#define AVR_SERIAL_USE_USART1 TRUE + +/* + * I2C driver system settings. + */ +#define AVR_I2C_USE_I2C1 FALSE + +/* + * SPI driver system settings. + */ +#define AVR_SPI_USE_SPI1 FALSE +#define AVR_SPI_USE_16BIT_POLLED_EXCHANGE FALSE + +/* + * USB driver system settings. + */ +#define AVR_USB_USE_USB1 TRUE +#define AVR_USB_USE_NAMED_ADDRESS_SPACES FALSE + +#endif /* MCUCONF_H_ */ diff --git a/demos/AVR/RT-TEENSY2-USB/readme.txt b/demos/AVR/RT-TEENSY2-USB/readme.txt new file mode 100644 index 000000000..86fb359b1 --- /dev/null +++ b/demos/AVR/RT-TEENSY2-USB/readme.txt @@ -0,0 +1,23 @@ +***************************************************************************** +** ChibiOS/RT port for Atmel AVR AT90USB128. ** +***************************************************************************** + +** TARGET ** + +The demo runs on an PJRC Teensy 2++ board. + +** The Demo ** + +The demo creates a standard serial-over-USB (CDC) slave device. The simple +ChibiOS shell is run on the USB serial connection and can be interacted +with by a standard serial port program (e.g. putty or screen). + +** Build Procedure ** + +The demo was built using the GCC AVR toolchain. It should build with WinAVR too! + +** Notes ** + +The USB driver itself is not that heavyweight but this demo requires a bit of +flash space and memory because of the nature of the ChibiOS shell code and +supporting functionality. diff --git a/demos/AVR/RT-TEENSY2-USB/usbcfg.c b/demos/AVR/RT-TEENSY2-USB/usbcfg.c new file mode 100644 index 000000000..a0c9ad258 --- /dev/null +++ b/demos/AVR/RT-TEENSY2-USB/usbcfg.c @@ -0,0 +1,353 @@ +/* + Copyright (C) 2015 Robert Lippert + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "ch.h" +#include "hal.h" +#include "usbcfg.h" + +/* Endpoints to be used. */ +#define USBD_DATA_REQUEST_EP 1 +#define USBD_DATA_AVAILABLE_EP 3 +#define USBD_INTERRUPT_REQUEST_EP 2 + +#if (AVR_USB_USE_NAMED_ADDRESS_SPACES == TRUE) && defined(__FLASH) +# undef ROMCONST +# define ROMCONST const __flash +#endif + +/* Virtual serial port over USB.*/ +SerialUSBDriver SDU1; + +/* + * USB Device Descriptor. + */ +static ROMCONST uint8_t vcom_device_descriptor_data[18] = { + USB_DESC_DEVICE (0x0110, /* bcdUSB (1.1). */ + 0x02, /* bDeviceClass (CDC). */ + 0x00, /* bDeviceSubClass. */ + 0x00, /* bDeviceProtocol. */ + 0x40, /* bMaxPacketSize. */ + 0x0483, /* idVendor (ST). */ + 0x5740, /* idProduct. */ + 0x0200, /* bcdDevice. */ + 1, /* iManufacturer. */ + 2, /* iProduct. */ + 3, /* iSerialNumber. */ + 1) /* bNumConfigurations. */ +}; + +/* Configuration Descriptor tree for a CDC.*/ +static ROMCONST uint8_t vcom_configuration_descriptor_data[67] = { + /* Configuration Descriptor.*/ + USB_DESC_CONFIGURATION(67, /* wTotalLength. */ + 0x02, /* bNumInterfaces. */ + 0x01, /* bConfigurationValue. */ + 0, /* iConfiguration. */ + 0xC0, /* bmAttributes (self powered). */ + 50), /* bMaxPower (100mA). */ + /* Interface Descriptor.*/ + USB_DESC_INTERFACE (0x00, /* bInterfaceNumber. */ + 0x00, /* bAlternateSetting. */ + 0x01, /* bNumEndpoints. */ + 0x02, /* bInterfaceClass (Communications + Interface Class, CDC section + 4.2). */ + 0x02, /* bInterfaceSubClass (Abstract + Control Model, CDC section 4.3). */ + 0x01, /* bInterfaceProtocol (AT commands, + CDC section 4.4). */ + 0), /* iInterface. */ + /* Header Functional Descriptor (CDC section 5.2.3).*/ + USB_DESC_BYTE (5), /* bLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x00), /* bDescriptorSubtype (Header + Functional Descriptor. */ + USB_DESC_BCD (0x0110), /* bcdCDC. */ + /* Call Management Functional Descriptor. */ + USB_DESC_BYTE (5), /* bFunctionLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x01), /* bDescriptorSubtype (Call Management + Functional Descriptor). */ + USB_DESC_BYTE (0x00), /* bmCapabilities (D0+D1). */ + USB_DESC_BYTE (0x01), /* bDataInterface. */ + /* ACM Functional Descriptor.*/ + USB_DESC_BYTE (4), /* bFunctionLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x02), /* bDescriptorSubtype (Abstract + Control Management Descriptor). */ + USB_DESC_BYTE (0x02), /* bmCapabilities. */ + /* Union Functional Descriptor.*/ + USB_DESC_BYTE (5), /* bFunctionLength. */ + USB_DESC_BYTE (0x24), /* bDescriptorType (CS_INTERFACE). */ + USB_DESC_BYTE (0x06), /* bDescriptorSubtype (Union + Functional Descriptor). */ + USB_DESC_BYTE (0x00), /* bMasterInterface (Communication + Class Interface). */ + USB_DESC_BYTE (0x01), /* bSlaveInterface0 (Data Class + Interface). */ + /* Endpoint 2 Descriptor.*/ + USB_DESC_ENDPOINT (USBD_INTERRUPT_REQUEST_EP|0x80, + 0x03, /* bmAttributes (Interrupt). */ + 0x0008, /* wMaxPacketSize. */ + 0xFF), /* bInterval. */ + /* Interface Descriptor.*/ + USB_DESC_INTERFACE (0x01, /* bInterfaceNumber. */ + 0x00, /* bAlternateSetting. */ + 0x02, /* bNumEndpoints. */ + 0x0A, /* bInterfaceClass (Data Class + Interface, CDC section 4.5). */ + 0x00, /* bInterfaceSubClass (CDC section + 4.6). */ + 0x00, /* bInterfaceProtocol (CDC section + 4.7). */ + 0x00), /* iInterface. */ + /* Endpoint 3 Descriptor.*/ + USB_DESC_ENDPOINT (USBD_DATA_AVAILABLE_EP, /* bEndpointAddress.*/ + 0x02, /* bmAttributes (Bulk). */ + 0x0040, /* wMaxPacketSize. */ + 0x00), /* bInterval. */ + /* Endpoint 1 Descriptor.*/ + USB_DESC_ENDPOINT (USBD_DATA_REQUEST_EP|0x80, /* bEndpointAddress.*/ + 0x02, /* bmAttributes (Bulk). */ + 0x0040, /* wMaxPacketSize. */ + 0x00) /* bInterval. */ +}; + +/* + * U.S. English language identifier. + */ +static ROMCONST uint8_t vcom_string0[] = { + USB_DESC_BYTE(4), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + USB_DESC_WORD(0x0409) /* wLANGID (U.S. English). */ +}; + +/* + * Vendor string. + */ +static ROMCONST uint8_t vcom_string1[] = { + USB_DESC_BYTE(38), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + 'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0, + 'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0, + 'c', 0, 's', 0 +}; + +/* + * Device Description string. + */ +static ROMCONST uint8_t vcom_string2[] = { + USB_DESC_BYTE(56), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + 'C', 0, 'h', 0, 'i', 0, 'b', 0, 'i', 0, 'O', 0, 'S', 0, '/', 0, + 'R', 0, 'T', 0, ' ', 0, 'V', 0, 'i', 0, 'r', 0, 't', 0, 'u', 0, + 'a', 0, 'l', 0, ' ', 0, 'C', 0, 'O', 0, 'M', 0, ' ', 0, 'P', 0, + 'o', 0, 'r', 0, 't', 0 +}; + +/* + * Serial Number string. + */ +static ROMCONST uint8_t vcom_string3[] = { + USB_DESC_BYTE(8), /* bLength. */ + USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType. */ + '0' + CH_KERNEL_MAJOR, 0, + '0' + CH_KERNEL_MINOR, 0, + '0' + CH_KERNEL_PATCH, 0 +}; + +/* + * Handles the GET_DESCRIPTOR callback. + */ +static const USBDescriptor *get_descriptor(USBDriver *usbp, + uint8_t dtype, + uint8_t dindex, + uint16_t lang) { + + (void)usbp; + (void)lang; + (void)dtype; + (void)dindex; + return NULL; +} + +/** + * @brief IN EP1 state. + */ +static USBInEndpointState ep1instate; + +/** + * @brief EP1 initialization structure + */ +static const USBEndpointConfig ep1config = { + USB_EP_MODE_TYPE_BULK, + NULL, + sduDataTransmitted, + NULL, + 0x0040, + 0, + &ep1instate, + NULL, +}; + +/** + * @brief INTR EP3 state. + */ +static USBInEndpointState ep3instate; + +/** + * @brief EP3 initialization structure (IN only). + */ +static const USBEndpointConfig ep3config = { + USB_EP_MODE_TYPE_INTR, + NULL, + sduInterruptTransmitted, + NULL, + 0x0010, + 0x0000, + &ep3instate, + NULL, +}; + +/** + * @brief OUT EP3 state. + */ +static USBOutEndpointState ep3state; + +/** + * @brief EP2 initialization structure + */ +static const USBEndpointConfig ep2config = { + USB_EP_MODE_TYPE_BULK, + NULL, + NULL, + sduDataReceived, + 0, + 0x0040, + NULL, + &ep3state, +}; + +/* + * Handles the USB driver global events. + */ +static void usb_event(USBDriver *usbp, usbevent_t event) { + extern SerialUSBDriver SDU1; + + switch (event) { + case USB_EVENT_RESET: + return; + case USB_EVENT_ADDRESS: + return; + case USB_EVENT_CONFIGURED: + chSysLockFromISR(); + + /* Enables the endpoints specified into the configuration. + Note, this callback is invoked from an ISR so I-Class functions + must be used.*/ + usbInitEndpointI(usbp, USBD_DATA_REQUEST_EP, &ep1config); + usbInitEndpointI(usbp, USBD_DATA_AVAILABLE_EP, &ep2config); + usbInitEndpointI(usbp, USBD_INTERRUPT_REQUEST_EP, &ep3config); + + /* Resetting the state of the CDC subsystem.*/ + sduConfigureHookI(&SDU1); + + chSysUnlockFromISR(); + return; + case USB_EVENT_SUSPEND: + return; + case USB_EVENT_WAKEUP: + return; + case USB_EVENT_STALLED: + return; + } + return; +} + +bool usb_setup_hook(USBDriver *usbp) { + /* Override GET_DESCRIPTOR requests to return data from program memory */ + if ((usbp->setup[0] & (USB_RTYPE_RECIPIENT_MASK | USB_RTYPE_TYPE_MASK)) == + (USB_RTYPE_RECIPIENT_DEVICE | USB_RTYPE_TYPE_STD) && + usbp->setup[1] == USB_REQ_GET_DESCRIPTOR) { + const uint8_t dtype = usbp->setup[3]; + const uint8_t dindex = usbp->setup[2]; + const AVR_USB_TX_BUF_ADDRESS_SPACE uint8_t *ddata = NULL; + size_t dsize = 0; + switch (dtype) { + case USB_DESCRIPTOR_DEVICE: + dsize = sizeof(vcom_device_descriptor_data); + ddata = vcom_device_descriptor_data; + break; + case USB_DESCRIPTOR_CONFIGURATION: + dsize = sizeof(vcom_configuration_descriptor_data); + ddata = vcom_configuration_descriptor_data; + break; + case USB_DESCRIPTOR_STRING: + if (dindex == 0) { + dsize = sizeof(vcom_string0); + ddata = vcom_string0; + } else if (dindex == 1) { + dsize = sizeof(vcom_string1); + ddata = vcom_string1; + } else if (dindex == 2) { + dsize = sizeof(vcom_string2); + ddata = vcom_string2; + } else if (dindex == 3) { + dsize = sizeof(vcom_string3); + ddata = vcom_string3; + } + break; + } + if (ddata == NULL) { + return false; + } + + usbSetupTransfer(usbp, ddata, dsize, NULL); + return true; + } + return sduRequestsHook(usbp); +} + +/* + * Handles the USB driver start of frame event. + */ +static void sof_handler(USBDriver *usbp) { + (void)usbp; + + osalSysLockFromISR(); + sduSOFHookI(&SDU1); + osalSysUnlockFromISR(); +} + +/* + * USB driver configuration. + */ +const USBConfig usbcfg = { + usb_event, + get_descriptor, + usb_setup_hook, + sof_handler +}; + +/* + * Serial over USB driver configuration. + */ +const SerialUSBConfig serusbcfg = { + &USBD1, + USBD_DATA_REQUEST_EP, + USBD_DATA_AVAILABLE_EP, + USBD_INTERRUPT_REQUEST_EP +}; diff --git a/demos/AVR/RT-TEENSY2-USB/usbcfg.h b/demos/AVR/RT-TEENSY2-USB/usbcfg.h new file mode 100644 index 000000000..0800451a7 --- /dev/null +++ b/demos/AVR/RT-TEENSY2-USB/usbcfg.h @@ -0,0 +1,26 @@ +/* + Copyright (C)2015 Robert Lippert + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef USBCFG_H_ +#define USBCFG_H_ + +extern const USBConfig usbcfg; +extern const SerialUSBConfig serusbcfg; + +/* Virtual serial port over USB.*/ +extern SerialUSBDriver SDU1; + +#endif /* USBCFG_H_ */ diff --git a/os/hal/boards/PJRC_TEENSY_2PLUSPLUS/board.c b/os/hal/boards/PJRC_TEENSY_2PLUSPLUS/board.c new file mode 100644 index 000000000..a16f25305 --- /dev/null +++ b/os/hal/boards/PJRC_TEENSY_2PLUSPLUS/board.c @@ -0,0 +1,75 @@ +/* + Copyright (C) 2015 Robert Lippert + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" + +/** + * @brief PAL setup. + * @details Digital I/O ports static configuration as defined in @p board.h. + * This variable is used by the HAL when initializing the PAL driver. + */ +#if HAL_USE_PAL || defined(__DOXYGEN__) +const PALConfig pal_default_config = +{ +#if defined(PORTA) + {VAL_PORTA, VAL_DDRA}, +#endif +#if defined(PORTB) + {VAL_PORTB, VAL_DDRB}, +#endif +#if defined(PORTC) + {VAL_PORTC, VAL_DDRC}, +#endif +#if defined(PORTD) + {VAL_PORTD, VAL_DDRD}, +#endif +#if defined(PORTE) + {VAL_PORTE, VAL_DDRE}, +#endif +#if defined(PORTF) + {VAL_PORTF, VAL_DDRF}, +#endif +#if defined(PORTG) + {VAL_PORTG, VAL_DDRG}, +#endif +#if defined(PORTH) + {VAL_PORTH, VAL_DDRH}, +#endif +#if defined(PORTJ) + {VAL_PORTJ, VAL_DDRJ}, +#endif +#if defined(PORTK) + {VAL_PORTK, VAL_DDRK}, +#endif +#if defined(PORTL) + {VAL_PORTL, VAL_DDRL}, +#endif +}; +#endif /* HAL_USE_PAL */ + +/** + * Board-specific initialization code. + */ +void boardInit(void) { + + /* + * External interrupts setup, all disabled initially. + */ + EICRA = 0x00; + EICRB = 0x00; + EIMSK = 0x00; + +} diff --git a/os/hal/boards/PJRC_TEENSY_2PLUSPLUS/board.h b/os/hal/boards/PJRC_TEENSY_2PLUSPLUS/board.h new file mode 100644 index 000000000..7b20330ee --- /dev/null +++ b/os/hal/boards/PJRC_TEENSY_2PLUSPLUS/board.h @@ -0,0 +1,86 @@ +/* + Copyright (C) 2015 Robert Lippert + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef BOARD_H_ +#define BOARD_H_ + +/* + * Setup for the PJRC Teensy2++ board. + */ + +/* + * Board identifier. + */ +#define BOARD_TEENSY_2PLUSPLUS +#define BOARD_NAME "PJRC Teensy 2++" + +/* All inputs with pull-ups */ +#define VAL_DDRA 0x00 +#define VAL_PORTA 0xFF + +/* All inputs with pull-ups */ +#define VAL_DDRB 0x00 +#define VAL_PORTB 0xFF + +/* All inputs with pull-ups */ +#define VAL_DDRC 0x00 +#define VAL_PORTC 0xFF + +/* All inputs with pull-ups, LED on D6, serial TX1 on D3 */ +#define VAL_DDRD 0x48 +#define VAL_PORTD 0xFF + +/* All inputs with pull-ups */ +#define VAL_DDRE 0x00 +#define VAL_PORTE 0xFF + +/* All inputs with pull-ups */ +#define VAL_DDRF 0x00 +#define VAL_PORTF 0xFF + +/* All inputs with pull-ups */ +#define VAL_DDRG 0x00 +#define VAL_PORTG 0xFF + +/* All inputs with pull-ups */ +#define VAL_DDRH 0x00 +#define VAL_PORTH 0xFF + +/* All inputs with pull-ups */ +#define VAL_DDRJ 0x00 +#define VAL_PORTJ 0xFF + +/* All inputs with pull-ups */ +#define VAL_DDRK 0x00 +#define VAL_PORTK 0xFF + +/* All inputs with pull-ups */ +#define VAL_DDRL 0x00 +#define VAL_PORTL 0xFF + +#define BOARD_LED1 6 + +#if !defined(_FROM_ASM_) +#ifdef __cplusplus +extern "C" { +#endif + void boardInit(void); +#ifdef __cplusplus +} +#endif +#endif /* _FROM_ASM_ */ + +#endif /* BOARD_H_ */ diff --git a/os/hal/boards/PJRC_TEENSY_2PLUSPLUS/board.mk b/os/hal/boards/PJRC_TEENSY_2PLUSPLUS/board.mk new file mode 100644 index 000000000..244324067 --- /dev/null +++ b/os/hal/boards/PJRC_TEENSY_2PLUSPLUS/board.mk @@ -0,0 +1,5 @@ +# List of all the board related files. +BOARDSRC = ${CHIBIOS}/os/hal/boards/PJRC_TEENSY_2PLUSPLUS/board.c + +# Required include directories +BOARDINC = ${CHIBIOS}/os/hal/boards/PJRC_TEENSY_2PLUSPLUS diff --git a/os/hal/ports/AVR/hal_usb_lld.c b/os/hal/ports/AVR/hal_usb_lld.c new file mode 100644 index 000000000..e6fb42f1e --- /dev/null +++ b/os/hal/ports/AVR/hal_usb_lld.c @@ -0,0 +1,841 @@ +/* + Copyright (C) 2015 Robert Lippert + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file usb_lld.c + * @brief AVR USB subsystem low level driver source. + * + * @addtogroup USB + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_USB == TRUE) || defined(__DOXYGEN__) + +#ifndef F_USB +#define F_USB F_CPU +#endif + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief USB1 driver identifier. + */ +#if (AVR_USB_USE_USB1 == TRUE) || defined(__DOXYGEN__) +USBDriver USBD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief EP0 state. + * @note It is an union because IN and OUT endpoints are never used at the + * same time for EP0. + */ +static union { + /** + * @brief IN EP0 state. + */ + USBInEndpointState in; + /** + * @brief OUT EP0 state. + */ + USBOutEndpointState out; +} ep0_state; + +/** + * @brief EP0 initialization structure. + */ +static const USBEndpointConfig ep0config = { + USB_EP_MODE_TYPE_CTRL, + _usb_ep0setup, + _usb_ep0in, + _usb_ep0out, + 0x40, + 0x40, + &ep0_state.in, + &ep0_state.out +}; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#ifdef AVR_USB_PLL_OFF_IN_SUSPEND +static __attribute__((unused)) void usb_pll_off(void) { + PLLCSR = 0; +} +#endif + +static void usb_pll_on(void) { +#if (F_USB == 8000000) + #if (defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || \ + defined(__AVR_ATmega8U2__) || defined(__AVR_ATmega16U2__) || \ + defined(__AVR_ATmega32U2__)) + #define PLL_VAL 0 + #elif (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) + #define PLL_VAL 0 + #elif (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)) + #define PLL_VAL ((0 << PLLP2) | (1 << PLLP1) | (1 << PLLP0)) + #elif (defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1287__)) + #define PLL_VAL ((0 << PLLP2) | (1 << PLLP1) | (1 << PLLP0)) + #endif +#elif (F_USB == 16000000) + #if (defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || \ + defined(__AVR_ATmega8U2__) || defined(__AVR_ATmega16U2__) || \ + defined(__AVR_ATmega32U2__)) + #define PLL_VAL ((0 << PLLP2) | (0 << PLLP1) | (1 << PLLP0)) + #elif (defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__)) + #define PLL_VAL (1 << PINDIV) + #elif (defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__)) + #define PLL_VAL ((1 << PLLP2) | (1 << PLLP1) | (0 << PLLP0)) + #elif (defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)) + #define PLL_VAL ((1 << PLLP2) | (0 << PLLP1) | (1 << PLLP0)) + #endif +#endif + +#ifndef PLL_VAL +#error Could not determine PLL value, unsupported AVR USB model type +#endif + +#ifdef PLLFRQ + /* This initializes PLL on supported devices for USB 48MHz *only* */ + PLLFRQ = (0 << PDIV3) | (1 << PDIV2) | (0 << PDIV1) | (0 << PDIV0); +#endif + + PLLCSR = PLL_VAL; + PLLCSR = PLL_VAL | (1 << PLLE); +} + +static int usb_pll_is_locked(void) { + return !!(PLLCSR & (1 << PLOCK)); +} + +/*===========================================================================*/ +/* Driver interrupt handlers and threads. */ +/*===========================================================================*/ + +/** + * @brief USB general/OTG/device management event interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(USB_GEN_vect) { + uint8_t usbint, udint; + USBDriver * const usbp = &USBD1; + + OSAL_IRQ_PROLOGUE(); + + usbint = USBINT; + udint = UDINT; + + if (usbint & (1 << VBUSTI)) { + /* Connected. */ +#ifdef AVR_USB_PLL_OFF_IN_SUSPEND + usb_pll_on(); + while (!usb_pll_is_locked()) {} +#endif /* AVR_USB_PLL_OFF_IN_SUSPEND */ + + /* Attach to bus */ + usb_lld_connect_bus(usbp); + USBINT &= ~(1 << VBUSTI); + } + + /* USB bus SUSPEND condition handling.*/ + if (udint & (1 << SUSPI)) { + /* Disable suspend interrupt, enable WAKEUP interrupt */ + UDIEN |= (1 << WAKEUPE); + UDINT &= ~(1 << WAKEUPI); + UDIEN &= ~(1 << SUSPE); + + /* Freeze the clock to reduce power consumption */ + USBCON |= (1 << FRZCLK); +#ifdef AVR_USB_PLL_OFF_IN_SUSPEND + usb_pll_off(); +#endif /* AVR_USB_PLL_OFF_IN_SUSPEND */ + + /* Clear the interrupt */ + UDINT &= ~(1 << SUSPI); + + _usb_isr_invoke_event_cb(usbp, USB_EVENT_SUSPEND); + } + + /* USB bus WAKEUP condition handling.*/ + if (udint & (1 << WAKEUPI)) { +#ifdef AVR_USB_PLL_OFF_IN_SUSPEND + usb_pll_on(); + while (!usb_pll_is_locked()) {} +#endif /* AVR_USB_PLL_OFF_IN_SUSPEND */ + + /* Unfreeze the clock */ + USBCON &= ~(1 << FRZCLK); + + /* Clear & disable wakeup interrupt, enable suspend interrupt */ + UDINT &= ~(1 << WAKEUPI); + UDIEN &= ~(1 << WAKEUPE); + UDIEN |= (1 << SUSPE); + + _usb_isr_invoke_event_cb(usbp, USB_EVENT_WAKEUP); + } + + /* USB bus RESUME condition handling.*/ + if (udint & (1 << EORSMI)) { + UDINT &= ~(1 << EORSMI); + UDIEN &= ~(1 << EORSME); + } + + /* USB bus reset condition handling.*/ + if (udint & (1 << EORSTI)) { + UDINT &= ~(1 << EORSTI); + + /* Clear & disable suspend interrupt, enable WAKEUP interrupt */ + UDINT &= ~(1 << SUSPI); + UDIEN &= ~(1 << SUSPE); + UDIEN |= (1 << WAKEUPE); + + /* Reinitialize EP0. This is not mentioned in the datasheet but + * apparently is required. */ + usb_lld_init_endpoint(usbp, 0); + + _usb_isr_invoke_event_cb(usbp, USB_EVENT_RESET); + } + + /* Start-Of-Frame handling, only if enabled */ + if ((UDIEN & (1 << SOFE)) && (udint & (1 << SOFI))) { + _usb_isr_invoke_sof_cb(usbp); + UDINT &= ~(1 << SOFI); + } + + OSAL_IRQ_EPILOGUE(); +} + +static void usb_fifo_write(USBDriver *usbp, usbep_t ep, size_t n) { + const USBEndpointConfig *epcp = usbp->epc[ep]; + USBInEndpointState *isp = epcp->in_state; + syssts_t sts; + if (n == 0) { + isp->last_tx_size = 0; + return; + } + + if (n > epcp->in_maxsize) + n = epcp->in_maxsize; + /* i is number of bytes remaining to transmit minus 1 (to handle 256b case) */ + uint8_t i = n - 1; + + /* Must lock for entire operation to ensure nothing changes the ENUM value */ + sts = osalSysGetStatusAndLockX(); + UENUM = ep & 0xf; + do { + UEDATX = *isp->txbuf++; + } while (i--); + isp->last_tx_size = n; + osalSysRestoreStatusX(sts); +} + +static void usb_fifo_read(USBDriver *usbp, usbep_t ep, size_t n) { + const USBEndpointConfig *epcp = usbp->epc[ep]; + USBOutEndpointState *osp = epcp->out_state; + syssts_t sts; + if (n == 0) + return; + if (n > epcp->out_maxsize) + n = epcp->out_maxsize; + // i is number of bytes remaining to receive minus 1 (to handle 256b case) + uint8_t i = n - 1; + + /* Must lock for entire operation to ensure nothing changes the ENUM value */ + sts = osalSysGetStatusAndLockX(); + UENUM = ep & 0xf; + do { + *osp->rxbuf++ = UEDATX; + } while (i--); + osalSysRestoreStatusX(sts); +} + +static void ep_isr(USBDriver *usbp, usbep_t ep) { + const USBEndpointConfig *epcp = usbp->epc[ep]; + size_t n; + UENUM = ep & 0xf; + + /* TODO: if stalling is needed/expected remove this check */ + osalDbgAssert(!(UEINTX & (1 << STALLEDI)), "Endpoint stalled!"); + + if ((UEIENX & (1 << TXINE)) && (UEINTX & (1 << TXINI))) { + /* Ready to accept more IN data to transmit to host */ + /* Update transaction counts to reflect newly transmitted bytes */ + epcp->in_state->txcnt += epcp->in_state->last_tx_size; + n = epcp->in_state->txsize - epcp->in_state->txcnt; + if (n > 0) { + /* Transfer not completed, there are more packets to send. */ + usb_fifo_write(usbp, ep, n); + + /* Clear FIFOCON to send the data in the FIFO and switch bank */ + UEINTX &= ~((1 << TXINI) | (1 << FIFOCON)); + /* Enable the TX complete interrupt */ + UEIENX |= (1 << TXINE); + } else { + /* Disable TXIN interrupt */ + UEIENX &= ~(1 << TXINE); + /* Handshake interrupt status */ + UEINTX &= ~(1 << TXINI); + _usb_isr_invoke_in_cb(usbp, ep); + } + } else if ((UEIENX & (1 << RXSTPE)) && (UEINTX & (1 << RXSTPI))) { + /* Received SETUP data */ + /* Reset transaction state for endpoint */ + epcp->in_state->txcnt = 0; + epcp->in_state->txsize = 0; + epcp->in_state->last_tx_size = 0; + /* Setup packets handling, setup packets are handled using a + specific callback.*/ + _usb_isr_invoke_setup_cb(usbp, ep); + } else if ((UEIENX & (1 << RXOUTE)) && (UEINTX & (1 << RXOUTI))) { + /* Received OUT data from host */ + if (ep == 0 && usbp->ep0state == USB_EP0_WAITING_STS) { + /* SETUP/control transaction complete, invoke the callback. */ + UEIENX &= ~(1 << RXOUTE); + UEINTX &= ~((1 << RXOUTI) | (1 << FIFOCON)); + _usb_isr_invoke_out_cb(usbp, ep); + } else { + /* Check the FIFO byte count to see how many bytes were received */ + n = UEBCX; + + usb_fifo_read(usbp, ep, n); + + /* Transaction state update */ + epcp->out_state->rxcnt += n; + epcp->out_state->rxsize -= n; + epcp->out_state->rxpkts -= 1; + if (n < epcp->out_maxsize || epcp->out_state->rxpkts == 0) { + /* Disable OUT interrupt */ + UEIENX &= ~(1 << RXOUTE); + /* Mark OUT FIFO processed to allow more data to be received */ + UEINTX &= ~((1 << RXOUTI) | (1 << FIFOCON)); + /* Transfer complete, invokes the callback.*/ + _usb_isr_invoke_out_cb(usbp, ep); + } else { + /* Mark OUT FIFO processed to allow more data to be received */ + UEINTX &= ~((1 << RXOUTI) | (1 << FIFOCON)); + } + } + } +} + +/** + * @brief USB communication event interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(USB_COM_vect) { + USBDriver *usbp = &USBD1; + const uint8_t epnum_orig = UENUM; + uint8_t i; + + OSAL_IRQ_PROLOGUE(); + + /* Figure out which endpoint(s) are interrupting */ + for (i = 0; i < USB_MAX_ENDPOINTS; ++i) { + if (UEINT & (1 << i)) { + ep_isr(usbp, i); + } + } + + /* Restore endpoint selector to pre-interrupt state */ + UENUM = epnum_orig; + + OSAL_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level USB driver initialization. + * + * @notapi + */ +void usb_lld_init(void) { +#if AVR_USB_USE_USB1 == TRUE + /* Driver initialization.*/ + usbObjectInit(&USBD1); + + /* Start and lock the USB 48MHz PLL (takes ~100ms) */ + usb_pll_on(); + while (!usb_pll_is_locked()) {} +#endif +} + +/** + * @brief Configures and activates the USB peripheral. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_start(USBDriver *usbp) { + if (usbp->state == USB_STOP) { + /* Enables the peripheral.*/ +#if AVR_USB_USE_USB1 == TRUE + if (&USBD1 == usbp) { + uint8_t i; + /* + * Workaround: disable pad drivers as first step in case bootloader left + * it on. Otherwise VBUS detection interrupt will not trigger later. + */ + USBCON &= ~(1 << OTGPADE); + + /* Enable the internal 3.3V pad regulator */ + UHWCON |= (1 << UVREGE); + + /* Reset and disable all endpoints */ + UERST = 0x7f; + UERST = 0; + for (i = 0; i < USB_MAX_ENDPOINTS; ++i){ + UENUM = i; + UEIENX = 0; + UEINTX = 0; + UECFG1X = 0; + UECONX &= ~(1 << EPEN); + } + } +#endif + /* Reset procedure enforced on driver start.*/ + _usb_reset(usbp); + } +} + +/** + * @brief Deactivates the USB peripheral. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_stop(USBDriver *usbp) { + if (usbp->state == USB_READY) { + /* Disables the peripheral.*/ +#if AVR_USB_USE_USB1 == TRUE + if (&USBD1 == usbp) { + /* Disable and clear transition interrupts */ + USBCON &= ~((1 << VBUSTE) | (1 << IDTE)); + USBINT = 0; + + /* Disable and clear device interrupts */ + UDIEN &= ~((1 << UPRSME) | (1 << EORSME) | (1 << WAKEUPE) | (1 << EORSTE) + | (1 << SOFE) | (1 << SUSPE)); + UDINT = 0; + + /* Freeze clock */ + USBCON |= (1 << FRZCLK); + + /* Disable USB logic */ + USBCON &= ~(1 << USBE); + } +#endif + } +} + +/** + * @brief USB low level reset routine. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_reset(USBDriver *usbp) { + /* Post-reset initialization.*/ + /* Reset and enable via toggling the USB macro logic overall enable bit */ + USBCON &= ~(1 << USBE); + USBCON |= (1 << USBE); + + /* Unfreeze clock */ + USBCON &= ~(1 << FRZCLK); + + /* Set Device mode */ + /* TODO: Support HOST/OTG mode if needed */ + UHWCON |= (1 << UIMOD); + + /* Set FULL 12mbps speed */ + UDCON &= ~(1 << LSM); + + /* Enable device pin interrupt */ + USBCON |= (1 << VBUSTE); + + /* EP0 initialization.*/ + UERST |= (1 << 0); + UERST &= ~(1 << 0); + usbp->epc[0] = &ep0config; + usb_lld_init_endpoint(usbp, 0); + + /* Enable device-level event interrupts */ + UDINT &= ~(1 << SUSPI); + UDIEN = (1 << UPRSME) | (1 << EORSME) | (1 << WAKEUPE) | (1 << EORSTE) + | (1 << SUSPE); + /* The SOF interrupt is only enabled if a callback is defined for + this service because it is a high rate source. */ + if (usbp->config->sof_cb != NULL) + UDIEN |= (1 << SOFE); + + /* Set OTG PAD to on which will trigger VBUS transition if plugged in. */ + USBCON |= (1 << OTGPADE); +} + +/** + * @brief Sets the USB address. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_set_address(USBDriver *usbp) { + UDADDR = (UDADDR & (1 << ADDEN)) | (usbp->address & 0x7F); + + UDADDR |= (1 << ADDEN); +} + +/** + * @brief Enables an endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) { + uint16_t size = 0; + const USBEndpointConfig *epcp = usbp->epc[ep]; + + /* Select this endpoint number for subsequent commands */ + UENUM = ep & 0xf; + + /* Enable endpoint to take out of reset */ + UECONX |= (1 << EPEN); + + UECFG1X = 0; + /* Set the endpoint type.*/ + switch (epcp->ep_mode & USB_EP_MODE_TYPE) { + case USB_EP_MODE_TYPE_ISOC: + UECFG0X = (0 << EPTYPE1) | (1 << EPTYPE0); + break; + case USB_EP_MODE_TYPE_BULK: + UECFG0X = (1 << EPTYPE1) | (0 << EPTYPE0); + break; + case USB_EP_MODE_TYPE_INTR: + UECFG0X = (1 << EPTYPE1) | (1 << EPTYPE0); + break; + default: + UECFG0X = (0 << EPTYPE1) | (0 << EPTYPE0); + } + if ((epcp->ep_mode & USB_EP_MODE_TYPE) == USB_EP_MODE_TYPE_CTRL) { + /* CTRL endpoint */ + osalDbgCheck(epcp->in_maxsize == epcp->out_maxsize); + size = epcp->in_maxsize; + } else { + osalDbgAssert(!(epcp->in_cb != NULL && epcp->out_cb != NULL), + "On AVR each endpoint can be IN or OUT not both"); + + /* IN endpoint? */ + if (epcp->in_cb != NULL) { + UECFG0X |= (1 << EPDIR); + size = epcp->in_maxsize; + } + + /* OUT endpoint? */ + if (epcp->out_cb != NULL) { + UECFG0X &= ~(1 << EPDIR); + size = epcp->out_maxsize; + } + } + + /* Endpoint size and address initialization. */ + switch (size) { + case 8: UECFG1X = (0 << EPSIZE0) | (1 << ALLOC); break; + case 16: UECFG1X = (1 << EPSIZE0) | (1 << ALLOC); break; + case 32: UECFG1X = (2 << EPSIZE0) | (1 << ALLOC); break; + case 64: UECFG1X = (3 << EPSIZE0) | (1 << ALLOC); break; + case 128: + osalDbgAssert(ep == 1, "Endpoint size of 128 bytes only valid for EP#1"); + UECFG1X = (4 << EPSIZE0) | (1 << ALLOC); break; + case 256: + osalDbgAssert(ep == 1, "Endpoint size of 256 bytes only valid for EP#1"); + UECFG1X = (5 << EPSIZE0) | (1 << ALLOC); break; + default: + osalDbgAssert(false, "Invalid size for USB endpoint"); + } + + UEIENX |= (1 << RXSTPE)/* | (1 << RXOUTE)*/ | (1 << STALLEDE) ; + + osalDbgAssert((UESTA0X & (1 << CFGOK)), + "Hardware reports endpoint config is INVALID"); +} + +/** + * @brief Disables all the active endpoints except the endpoint zero. + * + * @param[in] usbp pointer to the @p USBDriver object + * + * @notapi + */ +void usb_lld_disable_endpoints(USBDriver *usbp) { + uint8_t i; + for (i = 1; i <= USB_MAX_ENDPOINTS; ++i) { + UENUM = i; + UECFG1X &= ~(1 << ALLOC); + UECONX &= ~(1 << EPEN); + } +} + +/** + * @brief Returns the status of an OUT endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return The endpoint status. + * @retval EP_STATUS_DISABLED The endpoint is not active. + * @retval EP_STATUS_STALLED The endpoint is stalled. + * @retval EP_STATUS_ACTIVE The endpoint is active. + * + * @notapi + */ +usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep) { + /* Select this endpoint number for subsequent commands */ + UENUM = ep & 0xf; + + if (!(UECONX & (1 << EPEN))) + return EP_STATUS_DISABLED; + if (UECONX & (1 << STALLRQ)) + return EP_STATUS_STALLED; + return EP_STATUS_ACTIVE; +} + +/** + * @brief Returns the status of an IN endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return The endpoint status. + * @retval EP_STATUS_DISABLED The endpoint is not active. + * @retval EP_STATUS_STALLED The endpoint is stalled. + * @retval EP_STATUS_ACTIVE The endpoint is active. + * + * @notapi + */ +usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep) { + return usb_lld_get_status_out(usbp, ep); +} + +/** + * @brief Reads a setup packet from the dedicated packet buffer. + * @details This function must be invoked in the context of the @p setup_cb + * callback in order to read the received setup packet. + * @pre In order to use this function the endpoint must have been + * initialized as a control endpoint. + * @post The endpoint is ready to accept another packet. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @param[out] buf buffer where to copy the packet data + * + * @notapi + */ +void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) { + uint8_t i; + /* Select this endpoint number for subsequent commands */ + UENUM = ep & 0xf; + + for (i = 0; i < 8; ++i) { + *buf++ = UEDATX; + } + /* Clear FIFOCON and RXSTPI to drain the setup packet data from the FIFO */ + UEINTX &= ~((1 << FIFOCON) | (1 << RXSTPI)); +} + +/** + * @brief Ends a SETUP transaction + * @details This function must be invoked in the context of the @p setup_cb + * callback in order to finish an entire setup packet. + * @pre In order to use this function the endpoint must have been + * initialized as a control endpoint. + * @post The endpoint is ready to accept another packet. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_end_setup(USBDriver *usbp, usbep_t ep) { + /* Select this endpoint number for subsequent commands */ + UENUM = ep & 0xf; + + if ((usbp->setup[0] & USB_RTYPE_DIR_MASK) == USB_RTYPE_DIR_DEV2HOST) { + /* Enable interrupt and wait for OUT packet */ + usbp->epc[ep]->out_state->rxsize = 0; + usbp->epc[ep]->out_state->rxpkts = 1; + + UEINTX &= ~((1 << FIFOCON) | (1 << RXOUTI)); + UEIENX |= (1 << RXOUTE); + } else { + /* Enable interrupt and wait for IN packet */ + usbp->epc[ep]->in_state->last_tx_size = 0; + usbp->epc[ep]->in_state->txcnt = 0; + usbp->epc[ep]->in_state->txsize = 0; + + UEINTX &= ~((1 << FIFOCON) | (1 << TXINI)); + UEIENX |= (1 << TXINE); + } +} + +/** + * @brief Starts a receive operation on an OUT endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_start_out(USBDriver *usbp, usbep_t ep) { + USBOutEndpointState *osp = usbp->epc[ep]->out_state; + syssts_t sts; + + /* Initialize transfer by recording how many packets we expect to receive. */ + if (osp->rxsize == 0) /* Special case for zero sized packets.*/ + osp->rxpkts = 1; + else + osp->rxpkts = (uint8_t)((osp->rxsize + usbp->epc[ep]->out_maxsize - 1) / + usbp->epc[ep]->out_maxsize); + + /* Select this endpoint number for subsequent commands */ + /* Must lock for entire operation to ensure nothing changes the ENUM value */ + sts = osalSysGetStatusAndLockX(); + UENUM = ep & 0xf; + + UEIENX |= (1 << RXOUTE); + osalSysRestoreStatusX(sts); +} + +/** + * @brief Starts a transmit operation on an IN endpoint. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_start_in(USBDriver *usbp, usbep_t ep) { + USBInEndpointState *isp = usbp->epc[ep]->in_state; + syssts_t sts; + + /* Initialize transfer by filling FIFO with passed data. */ + usb_fifo_write(usbp, ep, isp->txsize); + + /* Select this endpoint number for subsequent commands */ + /* Must lock for entire operation to ensure nothing changes the ENUM value */ + sts = osalSysGetStatusAndLockX(); + UENUM = ep & 0xf; + + /* Clear FIFOCON to send the data in the FIFO and switch bank */ + UEINTX &= ~((1 << TXINI) | (1 << FIFOCON)); + + /* Enable the TX complete interrupt */ + UEIENX |= (1 << TXINE); + + osalSysRestoreStatusX(sts); +} + +/** + * @brief Brings an OUT endpoint in the stalled state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) { + syssts_t sts; + (void)usbp; + + /* Select this endpoint number for subsequent commands */ + /* Must lock for entire operation to ensure nothing changes the ENUM value */ + sts = osalSysGetStatusAndLockX(); + UENUM = ep & 0xf; + + UECONX |= (1 << STALLRQ); + osalSysRestoreStatusX(sts); +} + +/** + * @brief Brings an IN endpoint in the stalled state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) { + usb_lld_stall_out(usbp, ep); +} + +/** + * @brief Brings an OUT endpoint in the active state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_clear_out(USBDriver *usbp, usbep_t ep) { + syssts_t sts; + (void)usbp; + + /* Select this endpoint number for subsequent commands */ + /* Must lock for entire operation to ensure nothing changes the ENUM value */ + sts = osalSysGetStatusAndLockX(); + UENUM = ep & 0xf; + + UECONX |= (1 << STALLRQC); + osalSysRestoreStatusX(sts); +} + +/** + * @brief Brings an IN endpoint in the active state. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * + * @notapi + */ +void usb_lld_clear_in(USBDriver *usbp, usbep_t ep) { + usb_lld_clear_out(usbp, ep); +} + +#endif /* HAL_USE_USB == TRUE */ + +/** @} */ diff --git a/os/hal/ports/AVR/hal_usb_lld.h b/os/hal/ports/AVR/hal_usb_lld.h new file mode 100644 index 000000000..e47d38425 --- /dev/null +++ b/os/hal/ports/AVR/hal_usb_lld.h @@ -0,0 +1,398 @@ +/* + Copyright (C) 2015 Robert Lippert + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file usb_lld.h + * @brief AVR USB subsystem low level driver header. + * + * @addtogroup USB + * @{ + */ + +#ifndef _USB_LLD_H_ +#define _USB_LLD_H_ + +#if (HAL_USE_USB == TRUE) || defined(__DOXYGEN__) + +#include "hal_usb.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Maximum endpoint address. + */ +#define USB_MAX_ENDPOINTS 7 + +/** + * @brief Status stage handling method. + */ +#define USB_EP0_STATUS_STAGE USB_EP0_STATUS_STAGE_HW + +/** + * @brief The address is changed after IN packet is received. + */ +#define USB_SET_ADDRESS_MODE USB_LATE_SET_ADDRESS + +/** + * @brief Method for set address acknowledge. + */ +#define USB_SET_ADDRESS_ACK_HANDLING USB_SET_ADDRESS_ACK_SW + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name AVR configuration options + * @{ + */ +/** + * @brief USB driver enable switch. + * @details If set to @p TRUE the support for USB1 is included. + * @note The default is @p FALSE. + */ +#if !defined(AVR_USB_USE_USB1) || defined(__DOXYGEN__) +#define AVR_USB_USE_USB1 FALSE +#endif +/** @} */ + +/* + * If compiler supports named address spaces + * (see https://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html) + * then mark our TX buf pointer as able to cover flash or SRAM to allow + * for storing/transmitting constants like USB descriptors in flash to save + * previous RAM space. + */ +#if !defined(AVR_USB_USE_NAMED_ADDRESS_SPACES) || defined(__DOXYGEN__) +#define AVR_USB_USE_NAMED_ADDRESS_SPACES FALSE +#endif + +#if (AVR_USB_USE_NAMED_ADDRESS_SPACES == TRUE) && defined(__MEMX) +#define AVR_USB_TX_BUF_ADDRESS_SPACE volatile __memx +#else +#define AVR_USB_TX_BUF_ADDRESS_SPACE +#endif + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +typedef const AVR_USB_TX_BUF_ADDRESS_SPACE uint8_t *usbbufptr_t; + +/** + * @brief Type of an IN endpoint state structure. + */ +typedef struct { + /** + * @brief Requested transmit transfer size. + */ + size_t txsize; + /** + * @brief Transmitted bytes so far. + */ + size_t txcnt; + /** + * @brief Pointer to the transmission linear buffer. + */ + usbbufptr_t txbuf; +#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + thread_reference_t thread; +#endif + /* End of the mandatory fields.*/ + /** + * @brief Number of expected bytes in the most recent transmission. + */ + size_t last_tx_size; +} USBInEndpointState; + +/** + * @brief Type of an OUT endpoint state structure. + */ +typedef struct { + /** + * @brief Requested receive transfer size. + */ + size_t rxsize; + /** + * @brief Received bytes so far. + */ + size_t rxcnt; + /** + * @brief Pointer to the receive linear buffer. + */ + uint8_t *rxbuf; +#if (USB_USE_WAIT == TRUE) || defined(__DOXYGEN__) + /** + * @brief Waiting thread. + */ + thread_reference_t thread; +#endif + /* End of the mandatory fields.*/ + uint8_t rxpkts; +} USBOutEndpointState; + +/** + * @brief Type of an USB endpoint configuration structure. + * @note Platform specific restrictions may apply to endpoints. + */ +typedef struct { + /** + * @brief Type and mode of the endpoint. + */ + uint32_t ep_mode; + /** + * @brief Setup packet notification callback. + * @details This callback is invoked when a setup packet has been + * received. + * @post The application must immediately call @p usbReadPacket() in + * order to access the received packet. + * @note This field is only valid for @p USB_EP_MODE_TYPE_CTRL + * endpoints, it should be set to @p NULL for other endpoint + * types. + */ + usbepcallback_t setup_cb; + /** + * @brief IN endpoint notification callback. + * @details This field must be set to @p NULL if the IN endpoint is not + * used. + */ + usbepcallback_t in_cb; + /** + * @brief OUT endpoint notification callback. + * @details This field must be set to @p NULL if the OUT endpoint is not + * used. + */ + usbepcallback_t out_cb; + /** + * @brief IN endpoint maximum packet size. + * @details This field must be set to zero if the IN endpoint is not + * used. + */ + uint16_t in_maxsize; + /** + * @brief OUT endpoint maximum packet size. + * @details This field must be set to zero if the OUT endpoint is not + * used. + */ + uint16_t out_maxsize; + /** + * @brief @p USBEndpointState associated to the IN endpoint. + * @details This structure maintains the state of the IN endpoint. + */ + USBInEndpointState *in_state; + /** + * @brief @p USBEndpointState associated to the OUT endpoint. + * @details This structure maintains the state of the OUT endpoint. + */ + USBOutEndpointState *out_state; + /* End of the mandatory fields.*/ +} USBEndpointConfig; + +/** + * @brief Type of an USB driver configuration structure. + */ +typedef struct { + /** + * @brief USB events callback. + * @details This callback is invoked when an USB driver event is registered. + */ + usbeventcb_t event_cb; + /** + * @brief Device GET_DESCRIPTOR request callback. + * @note This callback is mandatory and cannot be set to @p NULL. + */ + usbgetdescriptor_t get_descriptor_cb; + /** + * @brief Requests hook callback. + * @details This hook allows to be notified of standard requests or to + * handle non standard requests. + */ + usbreqhandler_t requests_hook_cb; + /** + * @brief Start Of Frame callback. + */ + usbcallback_t sof_cb; + /* End of the mandatory fields.*/ +} USBConfig; + +/** + * @brief Structure representing an USB driver. + */ +struct USBDriver { + /** + * @brief Driver state. + */ + usbstate_t state; + /** + * @brief Current configuration data. + */ + const USBConfig *config; + /** + * @brief Bit map of the transmitting IN endpoints. + */ + uint8_t transmitting; + /** + * @brief Bit map of the receiving OUT endpoints. + */ + uint8_t receiving; + /** + * @brief Active endpoints configurations. + */ + const USBEndpointConfig *epc[USB_MAX_ENDPOINTS + 1]; + /** + * @brief Fields available to user, it can be used to associate an + * application-defined handler to an IN endpoint. + * @note The base index is one, the endpoint zero does not have a + * reserved element in this array. + */ + void *in_params[USB_MAX_ENDPOINTS]; + /** + * @brief Fields available to user, it can be used to associate an + * application-defined handler to an OUT endpoint. + * @note The base index is one, the endpoint zero does not have a + * reserved element in this array. + */ + void *out_params[USB_MAX_ENDPOINTS]; + /** + * @brief Endpoint 0 state. + */ + usbep0state_t ep0state; + /** + * @brief Next position in the buffer to be transferred through endpoint 0. + */ + const AVR_USB_TX_BUF_ADDRESS_SPACE uint8_t *ep0next; + /** + * @brief Number of bytes yet to be transferred through endpoint 0. + */ + size_t ep0n; + /** + * @brief Endpoint 0 end transaction callback. + */ + usbcallback_t ep0endcb; + /** + * @brief Setup packet buffer. + */ + uint8_t setup[8]; + /** + * @brief Current USB device status. + */ + uint16_t status; + /** + * @brief Assigned USB address. + */ + uint8_t address; + /** + * @brief Current USB device configuration. + */ + uint8_t configuration; +#if defined(USB_DRIVER_EXT_FIELDS) + USB_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Returns the current frame number. + * + * @param[in] usbp pointer to the @p USBDriver object + * @return The current frame number. + * + * @notapi + */ +#define usb_lld_get_frame_number(usbp) (UDFNUM) + +/** + * @brief Returns the exact size of a receive transaction. + * @details The received size can be different from the size specified in + * @p usbStartReceiveI() because the last packet could have a size + * different from the expected one. + * @pre The OUT endpoint must have been configured in transaction mode + * in order to use this function. + * + * @param[in] usbp pointer to the @p USBDriver object + * @param[in] ep endpoint number + * @return Received data size. + * + * @notapi + */ +#define usb_lld_get_transaction_size(usbp, ep) \ + ((usbp)->epc[ep]->out_state->rxcnt) + +/** + * @brief Connects the USB device. + * + * @api + */ +#define usb_lld_connect_bus(usbp) (UDCON &= ~(1 << DETACH)) + +/** + * @brief Disconnect the USB device. + * + * @api + */ +#define usb_lld_disconnect_bus(usbp) (UDCON |= (1 << DETACH)) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if (AVR_USB_USE_USB1 == TRUE) && !defined(__DOXYGEN__) +extern USBDriver USBD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void usb_lld_init(void); + void usb_lld_start(USBDriver *usbp); + void usb_lld_stop(USBDriver *usbp); + void usb_lld_reset(USBDriver *usbp); + void usb_lld_set_address(USBDriver *usbp); + void usb_lld_enable_address(USBDriver *usbp); + void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep); + void usb_lld_disable_endpoints(USBDriver *usbp); + usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep); + usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep); + void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf); + void usb_lld_end_setup(USBDriver *usbp, usbep_t ep); + void usb_lld_start_out(USBDriver *usbp, usbep_t ep); + void usb_lld_start_in(USBDriver *usbp, usbep_t ep); + void usb_lld_stall_out(USBDriver *usbp, usbep_t ep); + void usb_lld_stall_in(USBDriver *usbp, usbep_t ep); + void usb_lld_clear_out(USBDriver *usbp, usbep_t ep); + void usb_lld_clear_in(USBDriver *usbp, usbep_t ep); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_USB == TRUE */ + +#endif /* _USB_LLD_H_ */ + +/** @} */ diff --git a/os/hal/ports/AVR/platform.mk b/os/hal/ports/AVR/platform.mk index 7181924bc..2b20b8a80 100644 --- a/os/hal/ports/AVR/platform.mk +++ b/os/hal/ports/AVR/platform.mk @@ -8,6 +8,7 @@ PLATFORMSRC = ${CHIBIOS}/os/hal/ports/AVR/hal_lld.c \ ${CHIBIOS}/os/hal/ports/AVR/hal_gpt_lld.c \ ${CHIBIOS}/os/hal/ports/AVR/hal_pwm_lld.c \ ${CHIBIOS}/os/hal/ports/AVR/hal_icu_lld.c \ + ${CHIBIOS}/os/hal/ports/AVR/hal_usb_lld.c \ ${CHIBIOS}/os/hal/ports/AVR/hal_st_lld.c # Required include directories