diff --git a/Micropendous/Firmware/VirtualSerial/Descriptors.c b/Micropendous/Firmware/VirtualSerial/Descriptors.c index ba374ebf..c4b4b363 100644 --- a/Micropendous/Firmware/VirtualSerial/Descriptors.c +++ b/Micropendous/Firmware/VirtualSerial/Descriptors.c @@ -203,9 +203,9 @@ const USB_Descriptor_String_t PROGMEM LanguageString = */ const USB_Descriptor_String_t PROGMEM ManufacturerString = { - .Header = {.Size = USB_STRING_LEN(11), .Type = DTYPE_String}, + .Header = {.Size = USB_STRING_LEN(20), .Type = DTYPE_String}, - .UnicodeString = L"Dean Camera" + .UnicodeString = L"www.Micropendous.org" }; /** Product descriptor string. This is a Unicode string containing the product's details in human readable form, @@ -214,9 +214,9 @@ const USB_Descriptor_String_t PROGMEM ManufacturerString = */ const USB_Descriptor_String_t PROGMEM ProductString = { - .Header = {.Size = USB_STRING_LEN(13), .Type = DTYPE_String}, + .Header = {.Size = USB_STRING_LEN(35), .Type = DTYPE_String}, - .UnicodeString = L"LUFA CDC Demo" + .UnicodeString = L"LUFA-lib.org CDC VirtualSerial Demo" }; /** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors" diff --git a/Micropendous/Firmware/VirtualSerial/Descriptors.h b/Micropendous/Firmware/VirtualSerial/Descriptors.h index c6c378e3..cae44485 100644 --- a/Micropendous/Firmware/VirtualSerial/Descriptors.h +++ b/Micropendous/Firmware/VirtualSerial/Descriptors.h @@ -55,6 +55,7 @@ #define CDC_NOTIFICATION_EPSIZE 8 /** Size in bytes of the CDC data IN and OUT endpoints. */ + // 32 is maximum size compatible with all USB AVRs #define CDC_TXRX_EPSIZE 16 /* Type Defines: */ diff --git a/Micropendous/Firmware/VirtualSerial/TestThroughputOfVirtualSerial.py b/Micropendous/Firmware/VirtualSerial/TestThroughputOfVirtualSerial.py new file mode 100644 index 00000000..570edc6b --- /dev/null +++ b/Micropendous/Firmware/VirtualSerial/TestThroughputOfVirtualSerial.py @@ -0,0 +1,64 @@ +# Purpose: Test the throughput of a Micropendous board loaded with Virtual Serial Port loopback firmware +# Visit www.Micropendous.org/Serial for more info. +# Created: 2008-09-30 by Opendous Inc. +# Last Edit: 2009-10-03 by Opendous Inc. +# Released under the MIT License +import serial # for accessing the serial port on multiple platforms +import time, sys + +# test Serial Port throughput by sending and receiving transfersToComplete number +# of transferSize sized strings +# comport is a string - the Serial Port name to use +# transferSize is an integer - the string lenght +# transfersToComplete is an integer - the number of transfers to test with +def SerialThroughputTest(comport, transferSize, transfersToComplete): + + ser = serial.Serial(comport) # open serial port for communication + + print ser # dump all info regarding serial port being used + + ScriptStartTime = time.time() + + # create a transferSize length string + i = 0 + s = '' + while (i < (transferSize - 1)): + s = s + 'A' + i = i + 1 + # want last letter to be X + s = s + 'X' + + # complete a series of transfers + i = 0 + while (i < transfersToComplete): + # send one string to device then get back the string + ser.write(s) + receivedData = ser.read(transferSize) + #print receivedData + i = i + 1 + + ScriptEndTime = time.time() + print "\nIt took", (ScriptEndTime - ScriptStartTime), "seconds to transfer", \ + (transfersToComplete * transferSize), "bytes for a throughput of", \ + (((transfersToComplete * transferSize) / (ScriptEndTime - ScriptStartTime)) / 1000), "kbytes/second" + # be careful using readline as it will block until a newline character is received + + ser.close() # release/close the serial port + + +# if this file is the program actually being run, print usage info or run SerialThroughputTest +if __name__ == '__main__': + if (len(sys.argv) != 4): + print "Serial Communication Throughput Testing" + print " Usage:" + print " python", sys.argv[0], " " + print " Where = serial port; COM? on Windows, '/dev/ttyACM0 on Linux'" + print " Enumerated serial port can be found on Linux using dmesg" + print " look for something like cdc_acm 2-1:1.0: ttyACM0: USB ACM device" + print " Where = the size of each transfer, this value should match" + print " CDC_TXRX_EPSIZE in Descriptors.h for maximum throughput" + print " Where = how many transfers to complete, 100 is usually enough" + print " " + print " python", sys.argv[0], "COM5 64 100" + exit() + SerialThroughputTest(sys.argv[1], int(sys.argv[2]), int(sys.argv[3])) \ No newline at end of file diff --git a/Micropendous/Firmware/VirtualSerial/VirtualSerial.c b/Micropendous/Firmware/VirtualSerial/VirtualSerial.c index 7f1a3ce3..cf6c1563 100644 --- a/Micropendous/Firmware/VirtualSerial/VirtualSerial.c +++ b/Micropendous/Firmware/VirtualSerial/VirtualSerial.c @@ -9,6 +9,9 @@ /* Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com) + Updated for Loopback by Opendous Inc. 2011-11-22 + www.Micropendous.org/VirtualSerial + Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in @@ -36,6 +39,9 @@ #include "VirtualSerial.h" +// Global buffer for use with STDIO functions +volatile char buffer[CDC_TXRX_EPSIZE]; + /** LUFA CDC Class driver interface configuration and state information. This structure is * passed to all CDC Class driver functions, so that multiple instances of the same class * within a device can be differentiated from one another. @@ -81,16 +87,18 @@ int main(void) for (;;) { - CheckJoystickMovement(); + MainTask(); - /* Must throw away unused bytes from the host, or it will lock up while waiting for the device */ - CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface); + // Must throw away unused bytes from the host, or it will lock up while waiting for the device + // TODO: this causes loopback to fail + //CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface); CDC_Device_USBTask(&VirtualSerial_CDC_Interface); USB_USBTask(); } } + /** Configures the board hardware and chip peripherals for the demo's functionality. */ void SetupHardware(void) { @@ -98,51 +106,20 @@ void SetupHardware(void) MCUSR &= ~(1 << WDRF); wdt_disable(); + // TODO: disabling JTAG allows PF4, PF5, PF6, and PF7 to be used as GPIO pins + JTAG_DISABLE(); + /* Disable clock division */ clock_prescale_set(clock_div_1); /* Hardware Initialization */ - Joystick_Init(); - LEDs_Init(); + Board_Init(); + DISABLE_VOLTAGE_TXRX; + DISABLE_EXT_SRAM; + SELECT_USB_B; USB_Init(); } -#define BUTTONS_BUTTON1 (1 << 2) - -/** Checks for changes in the position of the board joystick, sending strings to the host upon each change. */ -void CheckJoystickMovement(void) -{ - uint8_t JoyStatus_LCL = Joystick_GetStatus(); - char* ReportString = NULL; - static bool ActionSent = false; - - if (JoyStatus_LCL & JOY_UP) - ReportString = "Joystick Up\r\n"; - else if (JoyStatus_LCL & JOY_DOWN) - ReportString = "Joystick Down\r\n"; - else if (JoyStatus_LCL & JOY_LEFT) - ReportString = "Joystick Left\r\n"; - else if (JoyStatus_LCL & JOY_RIGHT) - ReportString = "Joystick Right\r\n"; - else if (JoyStatus_LCL & JOY_PRESS) - ReportString = "Joystick Pressed\r\n"; - else - ActionSent = false; - - if (((PINE & BUTTONS_BUTTON1) ^ BUTTONS_BUTTON1)) - { - DDRE &= ~BUTTONS_BUTTON1; - PORTE |= BUTTONS_BUTTON1; - - ActionSent = true; - ReportString = "Joystick Pressed\r\n"; - /* Write the string to the virtual COM port via the created character stream */ - fputs(ReportString, &USBSerialStream); - - /* Alternatively, without the stream: */ - // CDC_Device_SendString(&VirtualSerial_CDC_Interface, ReportString); - } -} /** Event handler for the library USB Connection event. */ void EVENT_USB_Device_Connect(void) @@ -172,3 +149,24 @@ void EVENT_USB_Device_ControlRequest(void) CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface); } + + +void MainTask(void) +{ + int count = 0; + + // If the host has sent data then echo it back + // Throughput is maximized if the full EP buffer is read and sent each time + // Throughput approaches CDC_TXRX_EPSIZE kbytes/second and depends on transfer size from host + if ((count = fread(&buffer, 1, CDC_TXRX_EPSIZE, &USBSerialStream)) > 0) { + fwrite(&buffer, 1, count, &USBSerialStream); + } + + + // If HWB Button is pressed then send formatted strings + if (Buttons_GetStatus()) { + fprintf_P(&USBSerialStream, PSTR("\r\nHWB has been pressed!\r\n")); // send a constant string stored in FLASH + fprintf(&USBSerialStream, "PORTD = %3x\r\n", PIND); // send a string that is dynamic and stored in SRAM + } + +} diff --git a/Micropendous/Firmware/VirtualSerial/VirtualSerial.h b/Micropendous/Firmware/VirtualSerial/VirtualSerial.h index af8f0533..f35c2fb4 100644 --- a/Micropendous/Firmware/VirtualSerial/VirtualSerial.h +++ b/Micropendous/Firmware/VirtualSerial/VirtualSerial.h @@ -48,7 +48,7 @@ #include #include - #include + #include #include /* Macros: */ @@ -66,7 +66,7 @@ /* Function Prototypes: */ void SetupHardware(void); - void CheckJoystickMovement(void); + void MainTask(void); void EVENT_USB_Device_Connect(void); void EVENT_USB_Device_Disconnect(void); diff --git a/Micropendous/Firmware/VirtualSerial/makefile b/Micropendous/Firmware/VirtualSerial/makefile index 6c52a371..ec9d34cb 100644 --- a/Micropendous/Firmware/VirtualSerial/makefile +++ b/Micropendous/Firmware/VirtualSerial/makefile @@ -30,61 +30,96 @@ # 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! +# Assumes the target is connected through an AVR ISP mkII programmer +# +# make cdc = Download the hex file to the device, using avrdude. +# Assumes the target device is running the LUFA CDC Bootloader +# Make sure to set the CDC_BOOTLOADER_PORT variable # # make dfu = Download the hex file to the device, using dfu-programmer (must -# have dfu-programmer installed). +# have dfu-programmer installed). # # make flip = Download the hex file to the device, using Atmel FLIP (must -# have Atmel FLIP installed). +# have Atmel FLIP installed). # # make dfu-ee = Download the eeprom file to the device, using dfu-programmer -# (must have dfu-programmer installed). +# (must have dfu-programmer installed). # # make flip-ee = Download the eeprom file to the device, using Atmel FLIP -# (must have Atmel FLIP installed). +# (must have Atmel FLIP installed). # # make doxygen = Generate DoxyGen documentation for the project (must have -# DoxyGen installed) +# DoxyGen installed) # # make debug = Start either simulavr or avarice as specified for debugging, -# with avr-gdb or avr-insight as the front end 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. +# bug reports to the GCC project. # # To rebuild project do "make clean" then "make all". #---------------------------------------------------------------------------- -# MCU name -MCU = atmega32u4 +# MCU name - uncomment _ONE_ of the following +#MCU = at90usb82 +#MCU = at90usb162 +#MCU = atmega16u2 +#MCU = atmega32u2 +#MCU = atmega32u4 +#MCU = at90usb646 +#MCU = at90usb647 +#MCU = at90usb1286 +MCU = at90usb1287 # Target architecture (see library "Board Types" documentation). ARCH = AVR8 -# Target board (see library "Board Types" documentation, NONE for projects not requiring -# LUFA board drivers). If USER is selected, put custom board drivers in a directory called -# "Board" inside the application directory. -BOARD = USBKEY +# Target board: +# - USER for custom board drivers in LUFA/LUFA/Drivers/Board/Board/* +# - NONE for projects not requiring LUFA board drivers such as boards +# with no LEDs and just an HWB button such as: Micropendous1, Micropendous2, +# Micropendous3 or Micropendous4 without external SRAM +# - MICROPENDOUS_32U2 for Micropendous-32U2 which has 1 user LED on PD6 +# http://www.Micropendous.org/Micropendous-32U2 +# - MICROPENDOUS_A for Micropendous-A, Micropendous3, or Micropendous3 boards with external SRAM +# where PE6 is the external SRAM Chip Enable Pin and PE7 is Address Bit 17/Bank Selector Pin +# http://www.Micropendous.org/Micropendous-A +# - MICROPENDOUS_REV1 for the Micropendous Arduino-like board with the +# CY7C1019D external SRAM IC or its DIP variant: +# http://www.Micropendous.org/Micropendous-REV1 +# http://www.Micropendous.org/Micropendous-DIP +# - MICROPENDOUS_REV2 for the Micropendous Arduino-like board with the +# IS61C1024AL external SRAM IC: +# http://www.Micropendous.org/Micropendous +# Typical values are: +# BOARD = NONE +# BOARD = USER +# BOARD = MICROPENDOUS_A +# BOARD = MICROPENDOUS_32U2 +# BOARD = MICROPENDOUS_REV1 +# BOARD = MICROPENDOUS_REV2 +BOARD = MICROPENDOUS_REV2 + + +# Enable External SRAM: Defining to YES will enable external SRAM use +# via the linker. For more info visit www.Micropendous.org/SRAM +ENABLE_EXTERNAL_SRAM = NO # Processor frequency. -# This will define a symbol, F_CPU, in all source code files equal to the -# processor frequency in Hz. You can then use this symbol in your source code to +# This will define a symbol, F_CPU, in all source code files equal to the +# crystal frequency. You can then use this symbol in your source code to # calculate timings. Do NOT tack on a 'UL' at the end, this will be done # automatically to create a 32-bit value in your source code. -# -# This will be an integer division of F_USB below, as it is sourced by -# F_USB after it has run through any CPU prescalers. Note that this value -# does not *change* the processor frequency - it should merely be updated to -# reflect the processor speed set externally so that the code can use accurate -# software delays. -F_CPU = 8000000 +# USB AVR possible values are: +# F_CPU = 8000000 +# F_CPU = 16000000 +F_CPU = 16000000 # Input clock frequency. @@ -101,6 +136,13 @@ F_CPU = 8000000 F_USB = $(F_CPU) +# When using the LUFA CDC AVR109-compatible bootloader, you need to set this +# to the port under which your device enumerated. Under Windows it will be +# something like COM5 (Start->Control Panel->System->Hardware->Device Manager->Ports (COM and LPT)) +# Under Linux it will be something like /dev/ttyACM0 which you can find with dmesg +CDC_BOOTLOADER_PORT = COM5 + + # Output format. (can be srec, ihex, binary) FORMAT = ihex @@ -116,15 +158,24 @@ OBJDIR = . # Path to the LUFA library -LUFA_PATH = ../../../.. +LUFA_PATH = ../../libs/LUFA +AVRLIB_PATH = ../../libs/avrlib +ARDUINO_PATH = ../../libs/Arduino1 # LUFA library compile-time options and predefined tokens LUFA_OPTS = -D USB_DEVICE_ONLY +LUFA_OPTS += -D DEVICE_STATE_AS_GPIOR=0 +LUFA_OPTS += -D ORDERED_EP_CONFIG LUFA_OPTS += -D FIXED_CONTROL_ENDPOINT_SIZE=8 LUFA_OPTS += -D FIXED_NUM_CONFIGURATIONS=1 LUFA_OPTS += -D USE_FLASH_DESCRIPTORS LUFA_OPTS += -D USE_STATIC_OPTIONS="(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)" +LUFA_OPTS += -D INTERRUPT_CONTROL_ENDPOINT +# All Micropendous boards except Rev.2 require manual VBUS management to select USB connector appropriately or have control of PE7 +ifneq ($(BOARD),MICROPENDOUS_REV2) + LUFA_OPTS += -D NO_AUTO_VBUS_MANAGEMENT +endif # Create the LUFA source path variables by including the LUFA root makefile @@ -132,9 +183,9 @@ include $(LUFA_PATH)/LUFA/makefile # List C source files here. (C dependencies are automatically generated.) -SRC = $(TARGET).c \ - Descriptors.c \ - $(LUFA_SRC_USB) \ +SRC = $(TARGET).c \ + Descriptors.c \ + $(LUFA_SRC_USB) \ $(LUFA_SRC_USBCLASS) @@ -152,6 +203,28 @@ CPPSRC = ASRC = +#---------------- External Memory Options ---------------- +EXTMEMOPTS = + +# for the AT90USB1287 with its 8KB of SRAM, external addresses start at 0x20FF +# 0xFFFF(65535) - 0x2100(8448) = 0xDEFF(57087) --> 58KB of available external SRAM +# SAFEST OPTION: +#EXTMEMOPTS +=-Wl,--defsym=__stack=0x802000,--section-start,.data=0x802100,--defsym=__heap_start=0x80DFFF,--defsym=__heap_end=0x80FFFF + +ifeq ($(ENABLE_EXTERNAL_SRAM), YES) + # The following will leave the stack in internal memory, place .data+.bss in external memory, and + # leave the final (0x80FFFF-0x80DFFF)=0x2000= 8192 bytes for the heap (which malloc() will use) + # Alter __heap_start to leave more space for the heap + EXTMEMOPTS +=-Wl,--defsym=__stack=0x8020FC,--section-start,.data=0x802100,--defsym=__heap_start=0x80DFFF,--defsym=__heap_end=0x80FFFF + + # the following would place .data+.bss and the stack in internal SRAM and only the heap in external SRAM using an AT90USB1287: + #EXTMEMOPTS +=-Wl,--defsym=__stack=0x8020FC,--section-start,.data=0x800100,--defsym=__heap_start=0x802100,--defsym=__heap_end=0x80FFFF + + # the following would place .data+.bss such that it overlaps internal and external SRAM with the first 1024 bytes in internal SRAM: + #EXTMEMOPTS +=-Wl,--defsym=__stack=0x801C00,--section-start,.data=0x801D00,--defsym=__heap_start=0x80DFFF,--defsym=__heap_end=0x80FFFF +endif + + # 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.) @@ -169,7 +242,7 @@ DEBUG = dwarf-2 # 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 = $(LUFA_PATH)/ +EXTRAINCDIRS = $(LUFA_PATH)/ $(AVRLIB_PATH)/ $(ARDUINO_PATH)/ # Compiler flag to set the C Standard level. @@ -307,20 +380,6 @@ 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 @@ -341,7 +400,7 @@ LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) # Type: avrdude -c ? # to get a full listing. # -AVRDUDE_PROGRAMMER = jtagmkII +AVRDUDE_PROGRAMMER = avrispmkII # com1 = serial port. Use lpt1 to connect to parallel port. AVRDUDE_PORT = usb @@ -362,7 +421,7 @@ AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex # Increase verbosity level. Please use this when submitting bug # reports about avrdude. See # to submit bug reports. -#AVRDUDE_VERBOSE = -v -v +AVRDUDE_VERBOSE = -v -v AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY) @@ -518,6 +577,9 @@ gccversion : program: $(TARGET).hex $(TARGET).eep $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) +cdc: $(TARGET).hex + $(AVRDUDE) $(AVRDUDE_VERBOSE) -c avr109 -P $(CDC_BOOTLOADER_PORT) -p $(MCU) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) + flip: $(TARGET).hex batchisp -hardware usb -device $(MCU) -operation erase f batchisp -hardware usb -device $(MCU) -operation loadbuffer $(TARGET).hex program diff --git a/Micropendous/Firmware/VirtualSerial/serialpy.py b/Micropendous/Firmware/VirtualSerial/serialpy.py new file mode 100644 index 00000000..db26c2f4 --- /dev/null +++ b/Micropendous/Firmware/VirtualSerial/serialpy.py @@ -0,0 +1,41 @@ +# Purpose: Write then read characters from a serial port loopback device +# Visit www.Micropendous.org/Serial for more info. +# Created: 2009-09-31 by Opendous Inc. +# Last Edit: 2009-10-02 by Opendous Inc. +# Released to the Public Domain +import serial # PySerial for accessing the serial port on multiple platforms +import sys # command-line argument handling + +# function which sends then reads data from the given serial port +# comport should be a string +def SerialSendReceive(comport): + # open the given serial port for communication + ser = serial.Serial(comport) + ser.setTimeout(2000) + ser.setWriteTimeout(2000) + + print ser # dump all info regarding serial port being used + + ser.write('www.Micropendous.org') # send these characters to the serial port + print ser.read(20) # read the above characters back, assuming loopback + + ser.write('www.Micropendous.org\n') # send this line to the serial port + print ser.readline() # read the returned line + + # be careful using readline() as it will block until a newline character is received + + ser.close() # release/close the serial port + + +# if this file is the program actually being run, print usage info or run SerialSendReceive +if __name__ == '__main__': + if (len(sys.argv) != 2): + print "Serial Communication Example" + print " Usage:" + print " python", sys.argv[0], "" + print " Where = serial port; COM? on Windows, '/dev/ttyACM0 on Linux'" + print " Enumerated serial port can be found on Linux using dmesg" + print " look for something like cdc_acm 2-1:1.0: ttyACM0: USB ACM device" + print " python", sys.argv[0], "COM5" + exit() + SerialSendReceive(sys.argv[1]) \ No newline at end of file