Updated VirtualSerial for loopback and added throughput testing scripts.

This commit is contained in:
opendous
2011-11-23 05:22:48 +00:00
parent e34abd3593
commit d4838af0a2
7 changed files with 257 additions and 91 deletions

View File

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

View File

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

View File

@@ -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], "<port> <transferSize> <testSize>"
print " Where <port> = 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 <transferSize> = the size of each transfer, this value should match"
print " CDC_TXRX_EPSIZE in Descriptors.h for maximum throughput"
print " Where <testSize> = 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]))

View File

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

View File

@@ -48,7 +48,7 @@
#include <LUFA/Version.h>
#include <LUFA/Drivers/Board/LEDs.h>
#include <LUFA/Drivers/Board/Joystick.h>
#include <LUFA/Drivers/Board/BoardSupport.h>
#include <LUFA/Drivers/USB/USB.h>
/* 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);

View File

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

View File

@@ -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], "<port>"
print " Where <port> = 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])