Adds support for USB device functionality for AT90USB and

ATU2/U4 series devices.

Support tested on a PJRC TEENSY2++ board with AT90USB1286.

Signed-off-by: Rob Lippert <roblip@gmail.com>



git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9487 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
Rob Lippert 2016-05-15 12:15:09 +00:00 committed by Fabio Utzig
parent 5928999fd5
commit 06f9534388
14 changed files with 3448 additions and 0 deletions

View File

@ -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 <http://savannah.nongnu.org/projects/avrdude>
# 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

View File

@ -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_ */
/** @} */

View File

@ -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_ */
/** @} */

View File

@ -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);
}
}

View File

@ -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_ */

View File

@ -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.

View File

@ -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
};

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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

View File

@ -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 */
/** @} */

View File

@ -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_ */
/** @} */

View File

@ -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