Created
August 14, 2014 23:33
-
-
Save korczis/4b6911b15dea32171ccb to your computer and use it in GitHub Desktop.
USB Keyboard - https://www.pjrc.com/teensy/usb_keyboard.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Keyboard example with debug channel, for Teensy USB Development Board | |
* http://www.pjrc.com/teensy/usb_keyboard.html | |
* Copyright (c) 2008 PJRC.COM, LLC | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
* THE SOFTWARE. | |
*/ | |
#include <avr/io.h> | |
#include <avr/pgmspace.h> | |
#include <avr/interrupt.h> | |
#include <util/delay.h> | |
#include "usb_keyboard_debug.h" | |
#include "print.h" | |
#define LED_CONFIG (DDRD |= (1<<6)) | |
#define LED_ON (PORTD &= ~(1<<6)) | |
#define LED_OFF (PORTD |= (1<<6)) | |
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n)) | |
uint8_t number_keys[10]= | |
{KEY_0,KEY_1,KEY_2,KEY_3,KEY_4,KEY_5,KEY_6,KEY_7,KEY_8,KEY_9}; | |
uint16_t idle_count=0; | |
int main(void) | |
{ | |
uint8_t b, d, mask, i, reset_idle; | |
uint8_t b_prev=0xFF, d_prev=0xFF; | |
// set for 16 MHz clock | |
CPU_PRESCALE(0); | |
// Configure all port B and port D pins as inputs with pullup resistors. | |
// See the "Using I/O Pins" page for details. | |
// http://www.pjrc.com/teensy/pins.html | |
DDRD = 0x00; | |
DDRB = 0x00; | |
PORTB = 0xFF; | |
PORTD = 0xFF; | |
// Initialize the USB, and then wait for the host to set configuration. | |
// If the Teensy is powered without a PC connected to the USB port, | |
// this will wait forever. | |
usb_init(); | |
while (!usb_configured()) /* wait */ ; | |
// Wait an extra second for the PC's operating system to load drivers | |
// and do whatever it does to actually be ready for input | |
_delay_ms(1000); | |
// Configure timer 0 to generate a timer overflow interrupt every | |
// 256*1024 clock cycles, or approx 61 Hz when using 16 MHz clock | |
// This demonstrates how to use interrupts to implement a simple | |
// inactivity timeout. | |
TCCR0A = 0x00; | |
TCCR0B = 0x05; | |
TIMSK0 = (1<<TOIE0); | |
print("Begin keyboard example program\n"); | |
print("All Port B or Port D pins are inputs with pullup resistors.\n"); | |
print("Any connection to ground on Port B or D pins will result in\n"); | |
print("keystrokes sent to the PC (and debug messages here).\n"); | |
while (1) { | |
// read all port B and port D pins | |
b = PINB; | |
d = PIND; | |
// check if any pins are low, but were high previously | |
mask = 1; | |
reset_idle = 0; | |
for (i=0; i<8; i++) { | |
if (((b & mask) == 0) && (b_prev & mask) != 0) { | |
usb_keyboard_press(KEY_B, KEY_SHIFT); | |
usb_keyboard_press(number_keys[i], 0); | |
print("Port B, bit "); | |
phex(i); | |
print("\n"); | |
reset_idle = 1; | |
} | |
if (((d & mask) == 0) && (d_prev & mask) != 0) { | |
usb_keyboard_press(KEY_D, KEY_SHIFT); | |
usb_keyboard_press(number_keys[i], 0); | |
print("Port D, bit "); | |
phex(i); | |
print("\n"); | |
reset_idle = 1; | |
} | |
mask = mask << 1; | |
} | |
// if any keypresses were detected, reset the idle counter | |
if (reset_idle) { | |
// variables shared with interrupt routines must be | |
// accessed carefully so the interrupt routine doesn't | |
// try to use the variable in the middle of our access | |
cli(); | |
idle_count = 0; | |
sei(); | |
} | |
// now the current pins will be the previous, and | |
// wait a short delay so we're not highly sensitive | |
// to mechanical "bounce". | |
b_prev = b; | |
d_prev = d; | |
_delay_ms(2); | |
} | |
} | |
// This interrupt routine is run approx 61 times per second. | |
// A very simple inactivity timeout is implemented, where we | |
// will send a space character and print a message to the | |
// hid_listen debug message window. | |
ISR(TIMER0_OVF_vect) | |
{ | |
idle_count++; | |
if (idle_count > 61 * 8) { | |
idle_count = 0; | |
print("Timer Event :)\n"); | |
usb_keyboard_press(KEY_SPACE, 0); | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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". | |
#---------------------------------------------------------------------------- | |
# Target file name (without extension). | |
TARGET = example | |
# List C source files here. (C dependencies are automatically generated.) | |
SRC = $(TARGET).c \ | |
usb_keyboard_debug.c \ | |
print.c | |
# MCU name, you MUST set this to match the board you are using | |
# type "make clean" after changing this, so all files will be rebuilt | |
#MCU = at90usb162 # Teensy 1.0 | |
MCU = atmega32u4 # Teensy 2.0 | |
#MCU = at90usb646 # Teensy++ 1.0 | |
#MCU = at90usb1286 # Teensy++ 2.0 | |
# Processor frequency. | |
# Normally the first thing your program should do is set the clock prescaler, | |
# so your program will run at the correct speed. You should also set this | |
# variable to same clock speed. The _delay_ms() macro uses this, and many | |
# examples use this variable to calculate timings. Do not add a "UL" here. | |
F_CPU = 16000000 | |
# Output format. (can be srec, ihex, binary) | |
FORMAT = ihex | |
# Object files directory | |
# To put object files in current directory, use a dot (.), do NOT make | |
# this an empty or blank macro! | |
OBJDIR = . | |
# 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 = | |
# 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=gnu99 | |
# 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 += -ffunction-sections | |
CFLAGS += -fpack-struct | |
CFLAGS += -fshort-enums | |
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) | |
#---------------- 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 | |
CPPFLAGS += -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 = $(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 = $(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 += -Wl,--relax | |
LDFLAGS += -Wl,--gc-sections | |
LDFLAGS += $(EXTMEMOPTS) | |
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS)) | |
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) | |
#LDFLAGS += -T linker_script.x | |
#---------------- Programming Options (avrdude) ---------------- | |
# Programming hardware | |
# Type: avrdude -c ? | |
# to get a full listing. | |
# | |
AVRDUDE_PROGRAMMER = stk500v2 | |
# com1 = serial port. Use lpt1 to connect to parallel port. | |
AVRDUDE_PORT = com1 # programmer connected to serial device | |
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) -P $(AVRDUDE_PORT) -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 eep lss sym | |
#build: lib | |
elf: $(TARGET).elf | |
hex: $(TARGET).hex | |
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) --mcu=$(MCU) --format=avr $(TARGET).elf | |
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 -R .fuse -R .lock -R .signature $< $@ | |
%.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 -z $< > $@ | |
# 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).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 eep lss sym coff extcoff \ | |
clean clean_list program debug gdb-config |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Very basic print functions, intended to be used with usb_debug_only.c | |
* http://www.pjrc.com/teensy/ | |
* Copyright (c) 2008 PJRC.COM, LLC | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
* THE SOFTWARE. | |
*/ | |
// Version 1.0: Initial Release | |
#include <avr/io.h> | |
#include <avr/pgmspace.h> | |
#include "print.h" | |
void print_P(const char *s) | |
{ | |
char c; | |
while (1) { | |
c = pgm_read_byte(s++); | |
if (!c) break; | |
if (c == '\n') usb_debug_putchar('\r'); | |
usb_debug_putchar(c); | |
} | |
} | |
void phex1(unsigned char c) | |
{ | |
usb_debug_putchar(c + ((c < 10) ? '0' : 'A' - 10)); | |
} | |
void phex(unsigned char c) | |
{ | |
phex1(c >> 4); | |
phex1(c & 15); | |
} | |
void phex16(unsigned int i) | |
{ | |
phex(i >> 8); | |
phex(i); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef print_h__ | |
#define print_h__ | |
#include <avr/pgmspace.h> | |
#include "usb_keyboard_debug.h" | |
// this macro allows you to write print("some text") and | |
// the string is automatically placed into flash memory :) | |
#define print(s) print_P(PSTR(s)) | |
#define pchar(c) usb_debug_putchar(c) | |
void print_P(const char *s); | |
void phex(unsigned char c); | |
void phex16(unsigned int i); | |
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* USB Keyboard Plus Debug Channel Example for Teensy USB Development Board | |
* http://www.pjrc.com/teensy/usb_keyboard.html | |
* Copyright (c) 2009 PJRC.COM, LLC | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
* THE SOFTWARE. | |
*/ | |
// Version 1.0: Initial Release | |
// Version 1.1: Add support for Teensy 2.0 | |
#define USB_SERIAL_PRIVATE_INCLUDE | |
#include "usb_keyboard_debug.h" | |
/************************************************************************** | |
* | |
* Configurable Options | |
* | |
**************************************************************************/ | |
// You can change these to give your code its own name. | |
#define STR_MANUFACTURER L"MfgName" | |
#define STR_PRODUCT L"Keyboard" | |
// Mac OS-X and Linux automatically load the correct drivers. On | |
// Windows, even though the driver is supplied by Microsoft, an | |
// INF file is needed to load the driver. These numbers need to | |
// match the INF file. | |
#define VENDOR_ID 0x16C0 | |
#define PRODUCT_ID 0x047D | |
// USB devices are supposed to implment a halt feature, which is | |
// rarely (if ever) used. If you comment this line out, the halt | |
// code will be removed, saving 102 bytes of space (gcc 4.3.0). | |
// This is not strictly USB compliant, but works with all major | |
// operating systems. | |
#define SUPPORT_ENDPOINT_HALT | |
/************************************************************************** | |
* | |
* Endpoint Buffer Configuration | |
* | |
**************************************************************************/ | |
#define ENDPOINT0_SIZE 32 | |
#define KEYBOARD_INTERFACE 0 | |
#define KEYBOARD_ENDPOINT 3 | |
#define KEYBOARD_SIZE 8 | |
#define KEYBOARD_BUFFER EP_DOUBLE_BUFFER | |
#define DEBUG_INTERFACE 1 | |
#define DEBUG_TX_ENDPOINT 4 | |
#define DEBUG_TX_SIZE 32 | |
#define DEBUG_TX_BUFFER EP_DOUBLE_BUFFER | |
static const uint8_t PROGMEM endpoint_config_table[] = { | |
0, | |
0, | |
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER, | |
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER | |
}; | |
/************************************************************************** | |
* | |
* Descriptor Data | |
* | |
**************************************************************************/ | |
// Descriptors are the data that your computer reads when it auto-detects | |
// this USB device (called "enumeration" in USB lingo). The most commonly | |
// changed items are editable at the top of this file. Changing things | |
// in here should only be done by those who've read chapter 9 of the USB | |
// spec and relevant portions of any USB class specifications! | |
static uint8_t PROGMEM device_descriptor[] = { | |
18, // bLength | |
1, // bDescriptorType | |
0x00, 0x02, // bcdUSB | |
0, // bDeviceClass | |
0, // bDeviceSubClass | |
0, // bDeviceProtocol | |
ENDPOINT0_SIZE, // bMaxPacketSize0 | |
LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor | |
LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct | |
0x00, 0x01, // bcdDevice | |
1, // iManufacturer | |
2, // iProduct | |
0, // iSerialNumber | |
1 // bNumConfigurations | |
}; | |
// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60 | |
static uint8_t PROGMEM keyboard_hid_report_desc[] = { | |
0x05, 0x01, // Usage Page (Generic Desktop), | |
0x09, 0x06, // Usage (Keyboard), | |
0xA1, 0x01, // Collection (Application), | |
0x75, 0x01, // Report Size (1), | |
0x95, 0x08, // Report Count (8), | |
0x05, 0x07, // Usage Page (Key Codes), | |
0x19, 0xE0, // Usage Minimum (224), | |
0x29, 0xE7, // Usage Maximum (231), | |
0x15, 0x00, // Logical Minimum (0), | |
0x25, 0x01, // Logical Maximum (1), | |
0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte | |
0x95, 0x01, // Report Count (1), | |
0x75, 0x08, // Report Size (8), | |
0x81, 0x03, // Input (Constant), ;Reserved byte | |
0x95, 0x05, // Report Count (5), | |
0x75, 0x01, // Report Size (1), | |
0x05, 0x08, // Usage Page (LEDs), | |
0x19, 0x01, // Usage Minimum (1), | |
0x29, 0x05, // Usage Maximum (5), | |
0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report | |
0x95, 0x01, // Report Count (1), | |
0x75, 0x03, // Report Size (3), | |
0x91, 0x03, // Output (Constant), ;LED report padding | |
0x95, 0x06, // Report Count (6), | |
0x75, 0x08, // Report Size (8), | |
0x15, 0x00, // Logical Minimum (0), | |
0x25, 0x68, // Logical Maximum(104), | |
0x05, 0x07, // Usage Page (Key Codes), | |
0x19, 0x00, // Usage Minimum (0), | |
0x29, 0x68, // Usage Maximum (104), | |
0x81, 0x00, // Input (Data, Array), | |
0xc0 // End Collection | |
}; | |
static uint8_t PROGMEM debug_hid_report_desc[] = { | |
0x06, 0x31, 0xFF, // Usage Page 0xFF31 (vendor defined) | |
0x09, 0x74, // Usage 0x74 | |
0xA1, 0x53, // Collection 0x53 | |
0x75, 0x08, // report size = 8 bits | |
0x15, 0x00, // logical minimum = 0 | |
0x26, 0xFF, 0x00, // logical maximum = 255 | |
0x95, DEBUG_TX_SIZE, // report count | |
0x09, 0x75, // usage | |
0x81, 0x02, // Input (array) | |
0xC0 // end collection | |
}; | |
#define CONFIG1_DESC_SIZE (9+9+9+7+9+9+7) | |
#define KEYBOARD_HID_DESC_OFFSET (9+9) | |
#define DEBUG_HID_DESC_OFFSET (9+9+9+7+9) | |
static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { | |
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 | |
9, // bLength; | |
2, // bDescriptorType; | |
LSB(CONFIG1_DESC_SIZE), // wTotalLength | |
MSB(CONFIG1_DESC_SIZE), | |
2, // bNumInterfaces | |
1, // bConfigurationValue | |
0, // iConfiguration | |
0xC0, // bmAttributes | |
50, // bMaxPower | |
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |
9, // bLength | |
4, // bDescriptorType | |
KEYBOARD_INTERFACE, // bInterfaceNumber | |
0, // bAlternateSetting | |
1, // bNumEndpoints | |
0x03, // bInterfaceClass (0x03 = HID) | |
0x01, // bInterfaceSubClass (0x01 = Boot) | |
0x01, // bInterfaceProtocol (0x01 = Keyboard) | |
0, // iInterface | |
// HID interface descriptor, HID 1.11 spec, section 6.2.1 | |
9, // bLength | |
0x21, // bDescriptorType | |
0x11, 0x01, // bcdHID | |
0, // bCountryCode | |
1, // bNumDescriptors | |
0x22, // bDescriptorType | |
sizeof(keyboard_hid_report_desc), // wDescriptorLength | |
0, | |
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |
7, // bLength | |
5, // bDescriptorType | |
KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress | |
0x03, // bmAttributes (0x03=intr) | |
KEYBOARD_SIZE, 0, // wMaxPacketSize | |
1, // bInterval | |
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |
9, // bLength | |
4, // bDescriptorType | |
DEBUG_INTERFACE, // bInterfaceNumber | |
0, // bAlternateSetting | |
1, // bNumEndpoints | |
0x03, // bInterfaceClass (0x03 = HID) | |
0x00, // bInterfaceSubClass | |
0x00, // bInterfaceProtocol | |
0, // iInterface | |
// HID interface descriptor, HID 1.11 spec, section 6.2.1 | |
9, // bLength | |
0x21, // bDescriptorType | |
0x11, 0x01, // bcdHID | |
0, // bCountryCode | |
1, // bNumDescriptors | |
0x22, // bDescriptorType | |
sizeof(debug_hid_report_desc), // wDescriptorLength | |
0, | |
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 | |
7, // bLength | |
5, // bDescriptorType | |
DEBUG_TX_ENDPOINT | 0x80, // bEndpointAddress | |
0x03, // bmAttributes (0x03=intr) | |
DEBUG_TX_SIZE, 0, // wMaxPacketSize | |
1 // bInterval | |
}; | |
// If you're desperate for a little extra code memory, these strings | |
// can be completely removed if iManufacturer, iProduct, iSerialNumber | |
// in the device desciptor are changed to zeros. | |
struct usb_string_descriptor_struct { | |
uint8_t bLength; | |
uint8_t bDescriptorType; | |
int16_t wString[]; | |
}; | |
static struct usb_string_descriptor_struct PROGMEM string0 = { | |
4, | |
3, | |
{0x0409} | |
}; | |
static struct usb_string_descriptor_struct PROGMEM string1 = { | |
sizeof(STR_MANUFACTURER), | |
3, | |
STR_MANUFACTURER | |
}; | |
static struct usb_string_descriptor_struct PROGMEM string2 = { | |
sizeof(STR_PRODUCT), | |
3, | |
STR_PRODUCT | |
}; | |
// This table defines which descriptor data is sent for each specific | |
// request from the host (in wValue and wIndex). | |
static struct descriptor_list_struct { | |
uint16_t wValue; | |
uint16_t wIndex; | |
const uint8_t *addr; | |
uint8_t length; | |
} PROGMEM descriptor_list[] = { | |
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)}, | |
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)}, | |
{0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)}, | |
{0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9}, | |
{0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)}, | |
{0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9}, | |
{0x0300, 0x0000, (const uint8_t *)&string0, 4}, | |
{0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)}, | |
{0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)} | |
}; | |
#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct)) | |
/************************************************************************** | |
* | |
* Variables - these are the only non-stack RAM usage | |
* | |
**************************************************************************/ | |
// zero when we are not configured, non-zero when enumerated | |
static volatile uint8_t usb_configuration=0; | |
// the time remaining before we transmit any partially full | |
// packet, or send a zero length packet. | |
static volatile uint8_t debug_flush_timer=0; | |
// which modifier keys are currently pressed | |
// 1=left ctrl, 2=left shift, 4=left alt, 8=left gui | |
// 16=right ctrl, 32=right shift, 64=right alt, 128=right gui | |
uint8_t keyboard_modifier_keys=0; | |
// which keys are currently pressed, up to 6 keys may be down at once | |
uint8_t keyboard_keys[6]={0,0,0,0,0,0}; | |
// protocol setting from the host. We use exactly the same report | |
// either way, so this variable only stores the setting since we | |
// are required to be able to report which setting is in use. | |
static uint8_t keyboard_protocol=1; | |
// the idle configuration, how often we send the report to the | |
// host (ms * 4) even when it hasn't changed | |
static uint8_t keyboard_idle_config=125; | |
// count until idle timeout | |
static uint8_t keyboard_idle_count=0; | |
// 1=num lock, 2=caps lock, 4=scroll lock, 8=compose, 16=kana | |
volatile uint8_t keyboard_leds=0; | |
/************************************************************************** | |
* | |
* Public Functions - these are the API intended for the user | |
* | |
**************************************************************************/ | |
// initialize USB | |
void usb_init(void) | |
{ | |
HW_CONFIG(); | |
USB_FREEZE(); // enable USB | |
PLL_CONFIG(); // config PLL | |
while (!(PLLCSR & (1<<PLOCK))) ; // wait for PLL lock | |
USB_CONFIG(); // start USB clock | |
UDCON = 0; // enable attach resistor | |
usb_configuration = 0; | |
UDIEN = (1<<EORSTE)|(1<<SOFE); | |
sei(); | |
} | |
// return 0 if the USB is not configured, or the configuration | |
// number selected by the HOST | |
uint8_t usb_configured(void) | |
{ | |
return usb_configuration; | |
} | |
// perform a single keystroke | |
int8_t usb_keyboard_press(uint8_t key, uint8_t modifier) | |
{ | |
int8_t r; | |
keyboard_modifier_keys = modifier; | |
keyboard_keys[0] = key; | |
r = usb_keyboard_send(); | |
if (r) return r; | |
keyboard_modifier_keys = 0; | |
keyboard_keys[0] = 0; | |
return usb_keyboard_send(); | |
} | |
// send the contents of keyboard_keys and keyboard_modifier_keys | |
int8_t usb_keyboard_send(void) | |
{ | |
uint8_t i, intr_state, timeout; | |
if (!usb_configuration) return -1; | |
intr_state = SREG; | |
cli(); | |
UENUM = KEYBOARD_ENDPOINT; | |
timeout = UDFNUML + 50; | |
while (1) { | |
// are we ready to transmit? | |
if (UEINTX & (1<<RWAL)) break; | |
SREG = intr_state; | |
// has the USB gone offline? | |
if (!usb_configuration) return -1; | |
// have we waited too long? | |
if (UDFNUML == timeout) return -1; | |
// get ready to try checking again | |
intr_state = SREG; | |
cli(); | |
UENUM = KEYBOARD_ENDPOINT; | |
} | |
UEDATX = keyboard_modifier_keys; | |
UEDATX = 0; | |
for (i=0; i<6; i++) { | |
UEDATX = keyboard_keys[i]; | |
} | |
UEINTX = 0x3A; | |
keyboard_idle_count = 0; | |
SREG = intr_state; | |
return 0; | |
} | |
// transmit a character. 0 returned on success, -1 on error | |
int8_t usb_debug_putchar(uint8_t c) | |
{ | |
static uint8_t previous_timeout=0; | |
uint8_t timeout, intr_state; | |
// if we're not online (enumerated and configured), error | |
if (!usb_configuration) return -1; | |
// interrupts are disabled so these functions can be | |
// used from the main program or interrupt context, | |
// even both in the same program! | |
intr_state = SREG; | |
cli(); | |
UENUM = DEBUG_TX_ENDPOINT; | |
// if we gave up due to timeout before, don't wait again | |
if (previous_timeout) { | |
if (!(UEINTX & (1<<RWAL))) { | |
SREG = intr_state; | |
return -1; | |
} | |
previous_timeout = 0; | |
} | |
// wait for the FIFO to be ready to accept data | |
timeout = UDFNUML + 4; | |
while (1) { | |
// are we ready to transmit? | |
if (UEINTX & (1<<RWAL)) break; | |
SREG = intr_state; | |
// have we waited too long? | |
if (UDFNUML == timeout) { | |
previous_timeout = 1; | |
return -1; | |
} | |
// has the USB gone offline? | |
if (!usb_configuration) return -1; | |
// get ready to try checking again | |
intr_state = SREG; | |
cli(); | |
UENUM = DEBUG_TX_ENDPOINT; | |
} | |
// actually write the byte into the FIFO | |
UEDATX = c; | |
// if this completed a packet, transmit it now! | |
if (!(UEINTX & (1<<RWAL))) { | |
UEINTX = 0x3A; | |
debug_flush_timer = 0; | |
} else { | |
debug_flush_timer = 2; | |
} | |
SREG = intr_state; | |
return 0; | |
} | |
// immediately transmit any buffered output. | |
void usb_debug_flush_output(void) | |
{ | |
uint8_t intr_state; | |
intr_state = SREG; | |
cli(); | |
if (debug_flush_timer) { | |
UENUM = DEBUG_TX_ENDPOINT; | |
while ((UEINTX & (1<<RWAL))) { | |
UEDATX = 0; | |
} | |
UEINTX = 0x3A; | |
debug_flush_timer = 0; | |
} | |
SREG = intr_state; | |
} | |
/************************************************************************** | |
* | |
* Private Functions - not intended for general user consumption.... | |
* | |
**************************************************************************/ | |
// USB Device Interrupt - handle all device-level events | |
// the transmit buffer flushing is triggered by the start of frame | |
// | |
ISR(USB_GEN_vect) | |
{ | |
uint8_t intbits, t, i; | |
static uint8_t div4=0; | |
intbits = UDINT; | |
UDINT = 0; | |
if (intbits & (1<<EORSTI)) { | |
UENUM = 0; | |
UECONX = 1; | |
UECFG0X = EP_TYPE_CONTROL; | |
UECFG1X = EP_SIZE(ENDPOINT0_SIZE) | EP_SINGLE_BUFFER; | |
UEIENX = (1<<RXSTPE); | |
usb_configuration = 0; | |
} | |
if ((intbits & (1<<SOFI)) && usb_configuration) { | |
t = debug_flush_timer; | |
if (t) { | |
debug_flush_timer = -- t; | |
if (!t) { | |
UENUM = DEBUG_TX_ENDPOINT; | |
while ((UEINTX & (1<<RWAL))) { | |
UEDATX = 0; | |
} | |
UEINTX = 0x3A; | |
} | |
} | |
if (keyboard_idle_config && (++div4 & 3) == 0) { | |
UENUM = KEYBOARD_ENDPOINT; | |
if (UEINTX & (1<<RWAL)) { | |
keyboard_idle_count++; | |
if (keyboard_idle_count == keyboard_idle_config) { | |
keyboard_idle_count = 0; | |
UEDATX = keyboard_modifier_keys; | |
UEDATX = 0; | |
for (i=0; i<6; i++) { | |
UEDATX = keyboard_keys[i]; | |
} | |
UEINTX = 0x3A; | |
} | |
} | |
} | |
} | |
} | |
// Misc functions to wait for ready and send/receive packets | |
static inline void usb_wait_in_ready(void) | |
{ | |
while (!(UEINTX & (1<<TXINI))) ; | |
} | |
static inline void usb_send_in(void) | |
{ | |
UEINTX = ~(1<<TXINI); | |
} | |
static inline void usb_wait_receive_out(void) | |
{ | |
while (!(UEINTX & (1<<RXOUTI))) ; | |
} | |
static inline void usb_ack_out(void) | |
{ | |
UEINTX = ~(1<<RXOUTI); | |
} | |
// USB Endpoint Interrupt - endpoint 0 is handled here. The | |
// other endpoints are manipulated by the user-callable | |
// functions, and the start-of-frame interrupt. | |
// | |
ISR(USB_COM_vect) | |
{ | |
uint8_t intbits; | |
const uint8_t *list; | |
const uint8_t *cfg; | |
uint8_t i, n, len, en; | |
uint8_t bmRequestType; | |
uint8_t bRequest; | |
uint16_t wValue; | |
uint16_t wIndex; | |
uint16_t wLength; | |
uint16_t desc_val; | |
const uint8_t *desc_addr; | |
uint8_t desc_length; | |
UENUM = 0; | |
intbits = UEINTX; | |
if (intbits & (1<<RXSTPI)) { | |
bmRequestType = UEDATX; | |
bRequest = UEDATX; | |
wValue = UEDATX; | |
wValue |= (UEDATX << 8); | |
wIndex = UEDATX; | |
wIndex |= (UEDATX << 8); | |
wLength = UEDATX; | |
wLength |= (UEDATX << 8); | |
UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI)); | |
if (bRequest == GET_DESCRIPTOR) { | |
list = (const uint8_t *)descriptor_list; | |
for (i=0; ; i++) { | |
if (i >= NUM_DESC_LIST) { | |
UECONX = (1<<STALLRQ)|(1<<EPEN); //stall | |
return; | |
} | |
desc_val = pgm_read_word(list); | |
if (desc_val != wValue) { | |
list += sizeof(struct descriptor_list_struct); | |
continue; | |
} | |
list += 2; | |
desc_val = pgm_read_word(list); | |
if (desc_val != wIndex) { | |
list += sizeof(struct descriptor_list_struct)-2; | |
continue; | |
} | |
list += 2; | |
desc_addr = (const uint8_t *)pgm_read_word(list); | |
list += 2; | |
desc_length = pgm_read_byte(list); | |
break; | |
} | |
len = (wLength < 256) ? wLength : 255; | |
if (len > desc_length) len = desc_length; | |
do { | |
// wait for host ready for IN packet | |
do { | |
i = UEINTX; | |
} while (!(i & ((1<<TXINI)|(1<<RXOUTI)))); | |
if (i & (1<<RXOUTI)) return; // abort | |
// send IN packet | |
n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE; | |
for (i = n; i; i--) { | |
UEDATX = pgm_read_byte(desc_addr++); | |
} | |
len -= n; | |
usb_send_in(); | |
} while (len || n == ENDPOINT0_SIZE); | |
return; | |
} | |
if (bRequest == SET_ADDRESS) { | |
usb_send_in(); | |
usb_wait_in_ready(); | |
UDADDR = wValue | (1<<ADDEN); | |
return; | |
} | |
if (bRequest == SET_CONFIGURATION && bmRequestType == 0) { | |
usb_configuration = wValue; | |
usb_send_in(); | |
cfg = endpoint_config_table; | |
for (i=1; i<5; i++) { | |
UENUM = i; | |
en = pgm_read_byte(cfg++); | |
UECONX = en; | |
if (en) { | |
UECFG0X = pgm_read_byte(cfg++); | |
UECFG1X = pgm_read_byte(cfg++); | |
} | |
} | |
UERST = 0x1E; | |
UERST = 0; | |
return; | |
} | |
if (bRequest == GET_CONFIGURATION && bmRequestType == 0x80) { | |
usb_wait_in_ready(); | |
UEDATX = usb_configuration; | |
usb_send_in(); | |
return; | |
} | |
if (bRequest == GET_STATUS) { | |
usb_wait_in_ready(); | |
i = 0; | |
#ifdef SUPPORT_ENDPOINT_HALT | |
if (bmRequestType == 0x82) { | |
UENUM = wIndex; | |
if (UECONX & (1<<STALLRQ)) i = 1; | |
UENUM = 0; | |
} | |
#endif | |
UEDATX = i; | |
UEDATX = 0; | |
usb_send_in(); | |
return; | |
} | |
#ifdef SUPPORT_ENDPOINT_HALT | |
if ((bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE) | |
&& bmRequestType == 0x02 && wValue == 0) { | |
i = wIndex & 0x7F; | |
if (i >= 1 && i <= MAX_ENDPOINT) { | |
usb_send_in(); | |
UENUM = i; | |
if (bRequest == SET_FEATURE) { | |
UECONX = (1<<STALLRQ)|(1<<EPEN); | |
} else { | |
UECONX = (1<<STALLRQC)|(1<<RSTDT)|(1<<EPEN); | |
UERST = (1 << i); | |
UERST = 0; | |
} | |
return; | |
} | |
} | |
#endif | |
if (wIndex == KEYBOARD_INTERFACE) { | |
if (bmRequestType == 0xA1) { | |
if (bRequest == HID_GET_REPORT) { | |
usb_wait_in_ready(); | |
UEDATX = keyboard_modifier_keys; | |
UEDATX = 0; | |
for (i=0; i<6; i++) { | |
UEDATX = keyboard_keys[i]; | |
} | |
usb_send_in(); | |
return; | |
} | |
if (bRequest == HID_GET_IDLE) { | |
usb_wait_in_ready(); | |
UEDATX = keyboard_idle_config; | |
usb_send_in(); | |
return; | |
} | |
if (bRequest == HID_GET_PROTOCOL) { | |
usb_wait_in_ready(); | |
UEDATX = keyboard_protocol; | |
usb_send_in(); | |
return; | |
} | |
} | |
if (bmRequestType == 0x21) { | |
if (bRequest == HID_SET_REPORT) { | |
usb_wait_receive_out(); | |
keyboard_leds = UEDATX; | |
usb_ack_out(); | |
usb_send_in(); | |
return; | |
} | |
if (bRequest == HID_SET_IDLE) { | |
keyboard_idle_config = (wValue >> 8); | |
keyboard_idle_count = 0; | |
//usb_wait_in_ready(); | |
usb_send_in(); | |
return; | |
} | |
if (bRequest == HID_SET_PROTOCOL) { | |
keyboard_protocol = wValue; | |
//usb_wait_in_ready(); | |
usb_send_in(); | |
return; | |
} | |
} | |
} | |
if (wIndex == DEBUG_INTERFACE) { | |
if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) { | |
len = wLength; | |
do { | |
// wait for host ready for IN packet | |
do { | |
i = UEINTX; | |
} while (!(i & ((1<<TXINI)|(1<<RXOUTI)))); | |
if (i & (1<<RXOUTI)) return; // abort | |
// send IN packet | |
n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE; | |
for (i = n; i; i--) { | |
UEDATX = 0; | |
} | |
len -= n; | |
usb_send_in(); | |
} while (len || n == ENDPOINT0_SIZE); | |
return; | |
} | |
} | |
} | |
UECONX = (1<<STALLRQ) | (1<<EPEN); // stall | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef usb_serial_h__ | |
#define usb_serial_h__ | |
#include <stdint.h> | |
void usb_init(void); // initialize everything | |
uint8_t usb_configured(void); // is the USB port configured | |
int8_t usb_keyboard_press(uint8_t key, uint8_t modifier); | |
int8_t usb_keyboard_send(void); | |
extern uint8_t keyboard_modifier_keys; | |
extern uint8_t keyboard_keys[6]; | |
extern volatile uint8_t keyboard_leds; | |
int8_t usb_debug_putchar(uint8_t c); // transmit a character | |
void usb_debug_flush_output(void); // immediately transmit any buffered output | |
#define USB_DEBUG_HID | |
#define KEY_CTRL 0x01 | |
#define KEY_SHIFT 0x02 | |
#define KEY_ALT 0x04 | |
#define KEY_GUI 0x08 | |
#define KEY_LEFT_CTRL 0x01 | |
#define KEY_LEFT_SHIFT 0x02 | |
#define KEY_LEFT_ALT 0x04 | |
#define KEY_LEFT_GUI 0x08 | |
#define KEY_RIGHT_CTRL 0x10 | |
#define KEY_RIGHT_SHIFT 0x20 | |
#define KEY_RIGHT_ALT 0x40 | |
#define KEY_RIGHT_GUI 0x80 | |
#define KEY_A 4 | |
#define KEY_B 5 | |
#define KEY_C 6 | |
#define KEY_D 7 | |
#define KEY_E 8 | |
#define KEY_F 9 | |
#define KEY_G 10 | |
#define KEY_H 11 | |
#define KEY_I 12 | |
#define KEY_J 13 | |
#define KEY_K 14 | |
#define KEY_L 15 | |
#define KEY_M 16 | |
#define KEY_N 17 | |
#define KEY_O 18 | |
#define KEY_P 19 | |
#define KEY_Q 20 | |
#define KEY_R 21 | |
#define KEY_S 22 | |
#define KEY_T 23 | |
#define KEY_U 24 | |
#define KEY_V 25 | |
#define KEY_W 26 | |
#define KEY_X 27 | |
#define KEY_Y 28 | |
#define KEY_Z 29 | |
#define KEY_1 30 | |
#define KEY_2 31 | |
#define KEY_3 32 | |
#define KEY_4 33 | |
#define KEY_5 34 | |
#define KEY_6 35 | |
#define KEY_7 36 | |
#define KEY_8 37 | |
#define KEY_9 38 | |
#define KEY_0 39 | |
#define KEY_ENTER 40 | |
#define KEY_ESC 41 | |
#define KEY_BACKSPACE 42 | |
#define KEY_TAB 43 | |
#define KEY_SPACE 44 | |
#define KEY_MINUS 45 | |
#define KEY_EQUAL 46 | |
#define KEY_LEFT_BRACE 47 | |
#define KEY_RIGHT_BRACE 48 | |
#define KEY_BACKSLASH 49 | |
#define KEY_NUMBER 50 | |
#define KEY_SEMICOLON 51 | |
#define KEY_QUOTE 52 | |
#define KEY_TILDE 53 | |
#define KEY_COMMA 54 | |
#define KEY_PERIOD 55 | |
#define KEY_SLASH 56 | |
#define KEY_CAPS_LOCK 57 | |
#define KEY_F1 58 | |
#define KEY_F2 59 | |
#define KEY_F3 60 | |
#define KEY_F4 61 | |
#define KEY_F5 62 | |
#define KEY_F6 63 | |
#define KEY_F7 64 | |
#define KEY_F8 65 | |
#define KEY_F9 66 | |
#define KEY_F10 67 | |
#define KEY_F11 68 | |
#define KEY_F12 69 | |
#define KEY_PRINTSCREEN 70 | |
#define KEY_SCROLL_LOCK 71 | |
#define KEY_PAUSE 72 | |
#define KEY_INSERT 73 | |
#define KEY_HOME 74 | |
#define KEY_PAGE_UP 75 | |
#define KEY_DELETE 76 | |
#define KEY_END 77 | |
#define KEY_PAGE_DOWN 78 | |
#define KEY_RIGHT 79 | |
#define KEY_LEFT 80 | |
#define KEY_DOWN 81 | |
#define KEY_UP 82 | |
#define KEY_NUM_LOCK 83 | |
#define KEYPAD_SLASH 84 | |
#define KEYPAD_ASTERIX 85 | |
#define KEYPAD_MINUS 86 | |
#define KEYPAD_PLUS 87 | |
#define KEYPAD_ENTER 88 | |
#define KEYPAD_1 89 | |
#define KEYPAD_2 90 | |
#define KEYPAD_3 91 | |
#define KEYPAD_4 92 | |
#define KEYPAD_5 93 | |
#define KEYPAD_6 94 | |
#define KEYPAD_7 95 | |
#define KEYPAD_8 96 | |
#define KEYPAD_9 97 | |
#define KEYPAD_0 98 | |
#define KEYPAD_PERIOD 99 | |
// Everything below this point is only intended for usb_serial.c | |
#ifdef USB_SERIAL_PRIVATE_INCLUDE | |
#include <avr/io.h> | |
#include <avr/pgmspace.h> | |
#include <avr/interrupt.h> | |
#define EP_TYPE_CONTROL 0x00 | |
#define EP_TYPE_BULK_IN 0x81 | |
#define EP_TYPE_BULK_OUT 0x80 | |
#define EP_TYPE_INTERRUPT_IN 0xC1 | |
#define EP_TYPE_INTERRUPT_OUT 0xC0 | |
#define EP_TYPE_ISOCHRONOUS_IN 0x41 | |
#define EP_TYPE_ISOCHRONOUS_OUT 0x40 | |
#define EP_SINGLE_BUFFER 0x02 | |
#define EP_DOUBLE_BUFFER 0x06 | |
#define EP_SIZE(s) ((s) == 64 ? 0x30 : \ | |
((s) == 32 ? 0x20 : \ | |
((s) == 16 ? 0x10 : \ | |
0x00))) | |
#define MAX_ENDPOINT 4 | |
#define LSB(n) (n & 255) | |
#define MSB(n) ((n >> 8) & 255) | |
#if defined(__AVR_AT90USB162__) | |
#define HW_CONFIG() | |
#define PLL_CONFIG() (PLLCSR = ((1<<PLLE)|(1<<PLLP0))) | |
#define USB_CONFIG() (USBCON = (1<<USBE)) | |
#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK))) | |
#elif defined(__AVR_ATmega32U4__) | |
#define HW_CONFIG() (UHWCON = 0x01) | |
#define PLL_CONFIG() (PLLCSR = 0x12) | |
#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE))) | |
#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK))) | |
#elif defined(__AVR_AT90USB646__) | |
#define HW_CONFIG() (UHWCON = 0x81) | |
#define PLL_CONFIG() (PLLCSR = 0x1A) | |
#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE))) | |
#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK))) | |
#elif defined(__AVR_AT90USB1286__) | |
#define HW_CONFIG() (UHWCON = 0x81) | |
#define PLL_CONFIG() (PLLCSR = 0x16) | |
#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE))) | |
#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK))) | |
#endif | |
// standard control endpoint request types | |
#define GET_STATUS 0 | |
#define CLEAR_FEATURE 1 | |
#define SET_FEATURE 3 | |
#define SET_ADDRESS 5 | |
#define GET_DESCRIPTOR 6 | |
#define GET_CONFIGURATION 8 | |
#define SET_CONFIGURATION 9 | |
#define GET_INTERFACE 10 | |
#define SET_INTERFACE 11 | |
// HID (human interface device) | |
#define HID_GET_REPORT 1 | |
#define HID_GET_IDLE 2 | |
#define HID_GET_PROTOCOL 3 | |
#define HID_SET_REPORT 9 | |
#define HID_SET_IDLE 10 | |
#define HID_SET_PROTOCOL 11 | |
// CDC (communication class device) | |
#define CDC_SET_LINE_CODING 0x20 | |
#define CDC_GET_LINE_CODING 0x21 | |
#define CDC_SET_CONTROL_LINE_STATE 0x22 | |
#endif | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment