Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — README 1 USB support for Atmels AT90USB microcontroller Enumeration (with Linux host) and basic data transfer (LibUSB) works fine now! A simple example program for Linux console is included now. Basic documentation should be available on my homepage, see http :// www.ssalewski.de/Misc.html License: GPL— 2 S. Salewski 2006/2007 USB Documentation: H.J. Kelm, USB 2.0, LRANZIS J . Axelson, USB Complete, Lakeview Research www.beyondlogic.org/usbnutshell/usb— in— a— nutshell.pdf Atmel: Datasheet for AT90USB Atmel: AVR329, USB Lirmware Architecture Piles : AT90USB-Errata.txt com_def.h daq_dev.c daq dcv.li defines .h macros, h Makefile README ringbuffer .c ringbuffer .h SUDAP.c SUDD.c usart_debug . c usart_debug . h usart.drv .c usart.drv .h usb_api .c usb_api . h usb_drv . c usb.drv . h usbJsr .c usb .requests .c usb requests . h usb.spec . c usb spec . h gen.postscript . txt Script for generating postscript from sources for printout using enscript gen_pdf.tex Small LaTeX file using listings package for pretty —printing sources AT90USB— 20070xyz.tar.gz All source files in compressed form AT90USB-20070xyz.zip All source files in zip compressed form sources .ps .gz All source files preformated for printout (enscript) sources . pdf All source files preformated for printout ( pdflatex ) Some remarks about errors or unclear statements in AT90USB datasheet Constants which are used by firmware and host application program Function for data acquisition using the intern ADC (port ADCO) Project specific constants Some general macros Makefile : type ’’make” to generate all binary files and ’’make dfu” to upload firmware This file Simple ring buffer (FIFO) for buffering ADC data Example firmware application : Data acquisition ( port ADCO) and control of digital port B Example host application : Console based data acquisition and control of digital port B Functions for debugging over serial port Access to serial port This file contains constants and functions which need modifications to customize the software for a specific device Basic USB functions for AT90USB controller USB macros, basic low level register stuff Interrupt service routines USB (standard) requests , enumeration USB datastructures and constants Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — SUDAP.c 2 // AT90USB/SUDAP.C // Simple Usb Data Acquisition Program // Sampling an analog voltage using the intern ADC of AT90USB chip and // sending data to host (Linux PC) over USB in real time. // Sampling inten’al and number of samples is selected with command line options . // Additionally you can set output pins of digital port B. // The mam purpose of this tiny program is to demonstrate the functionality of my // USB firmware written for Atmels AT90USB controller. // Licence: GPL— 2 // Build: gcc —l usb SUDAP.c // Usage: see function usage)) below. // S. Salewski, 24— MAR— 2007 #include #include #include #include #include #include ’’com.def.h” #include ’’daq.dev.h” #define TimeOut 2000 // ms const char trstr [] = ’’Use 1ms, 500us, 200us, lOOus, 50us or 20us for time resolution !”; static struct option long_options [] = { {’’timeres”, required.argument , 0, ’t’}, {’’samples”, required.argument , 0, ’s’}, {’’columns”, required argument , 0, ’c’}, {’’portb”, required.argument , 0- *p’}, {’’help”, {0, 0, 0, 0} no .argument. 0, ’h’}, }; static void us age (void) { puts (’’Usage: — t lOOus — s 100 —c 1 — p 10001101”); printf (”— t or timeres: ”); puts ( trstr ) ; puts(”— s or samples: number of samples (1 up to 65535)”); puts (”— cor columns: number of columns for output, default is 32”); puts (”— p or portb: output value for digital port b, use a 8— bit dual number”); } static struct usb_device vUshFind Device) void ) { struct usb_bus *bus; struct usb device *dev; usbJnit () ; usb_find_busses () ; usb_find_devices () ; for (bus = usb .busses; bus; bus = bus— >next) { for (dev = bus— >devices; dev; dev = dev— >next) { Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — SUDAP.c 3 if ((dev— >descriptor.idVendor == MyUSBJVendorlD) && (dev— >descriptor.idProduct == MyUSB_ProductID)) return dev; } } return NULL; } // We use EP2 for DAQ static void dodaq( struct usb_dev_handle ^handle, uintl6_t timeres , uintl6_t samples, int columns) { unsigned char buf[EP2_FIFO_Size]; unsigned char *b; unsigned int m; unsigned int c = 0; if (usb_control_msg(handle, USBJVendorRequestCode, UC_ADC_Read, (int) timeres, (int) samples, NULL, 0, TimeOut) ) < 0 ) puts (”USB_control_msg error !”) ; // should never occur while (samples) { if (samples > (EP2_FIFO_Size/2)) m = (EP2_FIFO_Size/2); else m = samples; if (usb_bulk_read (handle, 2, (char*) buf, m * 2, TimeOut) < (m * 2)) puts (”USB_bulk_read error!”); // should never occur b = buf; samples — = m; while (m ) { unsigned int k; k = (unsigned int) *b++; k += (unsigned int) *b++ * 256; C++; if ( c == columns) { c = 0; printf (”%u\n", k); } else printf (”%u ”, k) ; } } if (c) putchar(’\n’); } int main(int argc, char **argv) { struct usb.device *dev; struct usb dev handle ^handle; int port = — 1; uintl6_t samples = 0; uintl6_t timeres = 0; int columns = 32; uint8_t status ; if (argc == 1) { Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — SUDAP.c 4 usage (); exit (EXIT_FAILURE); } while (1) { char * tail ; long int 1 ; int option Jndex = 0; int c; c = getopt Jong ( argc , argv, ”t:s:p:c:h”, long .options , &option Jndex) ; if (c == —1) break; switch (c) { case ’h’: usage () ; exit ( EXIT JFAILURE) ; case ’p’: errno = 0; 1 = strtol (optarg, &tail, 2); if ((errno == 0) && (*tail == ’\0’) && (1 >= 0) && (1 < 256)) port = ( int ) 1 ; else { puts (’’Use a 8— bit binary number for setting port pins!”); exit (EXIT FAILURE); } break; case ’c’ : errno = 0; 1 = strtol (optarg, &tail, 0); if ((errno == 0) && (*tail == ’\0’) && (1 > 0) && (1 <= 256)) columns = ( int ) 1 ; else { puts (’’Use a positive integer <= 256 for number of columns!”); exit (EXITJFAILURE); } break; case ’ t ’ : if (( optarg [0]==' 1’) && (optarg[l ]==’m’) && (optarg[2]==V ) && (optarg[3]==0)) timeres = ADC lms; else if (( optarg [0]==’ 5 ’ ) && (optarg[l]==’0’) && (optarg[2]==’0’) && (optarg[3]=='u’) && (optarg[4]==’s’ ) ) && (optarg[5]==0)) timeres = ADC500us; else if (( optarg [0]==’2’) && (optarg[l]==’0’) && (optarg[2]==’0’) && (optarg[3]=='u’) && (optarg[4]==’s’ ) i> && (optarg [5 ]==0)) timeres = ADC200us; else if ((optarg[0]==’l’) && (optarg[l ]==’0’) && (optarg[2]==’0’) && (optarg[3]=='u’) && (optarg[4]==’s’ ) 2 && (optarg[5]==0)) timeres = ADClOOus; else if (( optarg [0]==’ 5 ’ ) && (optarg[l]==’0’) && (optarg[2]==’u’) && (optarg[3]=='s’ ) && (optarg[4]==0)) timeres = ADC50us; else if (( optarg [0]==’ 2’) && (optarg[l]==’0’) && (optarg[2]==’u’) && (optarg[3]=='s’ ) && (optarg[4]==0)) timeres = ADC20us; else { puts ( trstr ) ; exit (EXIT JFAILURE); Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — SUDAP.c 5 } break; case ’s’: errno = 0; 1 = strtol (optarg, &tail, 0); if ((errno == 0) && (*tail == ’\0’) && (1 > 0) && (1 <= MaxSamples)) samples = ( uintl6_t ) 1 ; else { puts (’’Use 0 < samples < 65536!”); exit (EXIT_FAILURE); } break; case ’?’ : exit (EXIT_FAILURE); break; default : abort () ; } } if (optind < argc) { printf (’’Unsupported arguments: ”); while (optind < argc) printf (”%s ”, argv[ optind ++]); putchar ( ’ \n’ ) ; exit ( EXIT JFAILURE) ; } if ((! samples) && (timeres)) { puts (’’Required option: — s or samples”); exit ( EXIT .FAILURE) ; } if ((samples) && (Itimeres)) { puts (’’Required option : — t or timeres”); exit ( EXIT .FAILURE) ; } dev = UsbFindDevice(); if (dev == NULL) { puts (’’USB device not found!”) ; exit (EXIT_FAILURE); } handle = usb_open(dev) ; if (handle == NULL) { puts (’’USB device handle not found!”); exit (EXIT JFAILURE); } if ( usb claim interface (handle, 0) < 0) { puts (’’Can not claim interface !”); usb_close (handle) ; exit ( EXIT ^FAILURE) ; } if (port != -1) { Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — SUDAP.c status = ( uint8_t ) port; if ( usb_bulk_write (handle, 3, (char*) & status, 1, TimeOut) < 1) puts (’’Can not set digital port B!”); } if (samples && timeres) { dodaq(handle, timeres, samples, columns); usb_bulk_read (handle, 1, (char*) &status, 1, TimeOut); switch ( status ) { case (UsbDevStatusOK): break; case ( U sbDevS tatusD AQ B ufferOverflow) : putsC’DAQ Buffer Overflow!”); break; case ( U sbDevS tatusD AQ _TimerOverflow) : putsC’DAQ Timer Overflow!”); break; case (UsbDevStatusDAQ.ConversionNotFinished): puts (”DAQ Conversion was not finished when reading result!”); break; default : puts (’’Unknown error has occurred ! ”) ; } } usb .release -interface (handle, 0); usb .close (handle) ; exit (EXIT.SUCCESS); Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — SUDD.c 1 // AT90USB/SUDD.C // Simple Usb Data— acquisition Device // S. Salewski 23— MAR— 2007 // Start minicom with 8N1 configuration to see debug messages // The real work happens inside of interrupt —service— routines #include #include #include ” us art drv . h” #include ”usb_drv.h” static void blinkforever (void) ; int main(void) { cli 0 ; CLKPR = (1<<7); CLKPR = 0; // clock prescaler == 0, so we have 16 MHz mpu frequency with our 16 MHz crystal USART Tnit(); USART_WriteString(”\r\n ) \r\n”); U sbDevLaunchDevice( false) ; // UsbDevWaitStartupFinislied(); // no reason to wait blinkforever () ; return 0; } // a LED connected to PORTAO will toggle to indicate the unused processing power static void blinkforever (void) { _ int i = 0; // to suppress warning of avr—gcc DDRA |=(1«DDA0); while (1) { while (i++); PORTA "= (1«PORTAO); } } Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — daq dev.h // AT90USB/daq_dev.h // Very simple data — acquisition device // S. Salewski 19— MAR— 2007 #ifndef _DAQ_DEV_H_ #define _DAQ_DEV_H_ #include // user commands #define UC_ADC_Read 1 // sampling time #define ADC20us 1 #define ADC50us 2 #define ADClOOus 3 #define ADC200us 4 #define ADC500us 5 #define ADC lms 6 extern uint8_t DAQ_Result; void ProcessUserCommand(uint8_t command, uintl6_t pari , uintl6_t par2); #endif Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — daq dev.c 9 // AT90USB/daq_dev.c // This file implements basic functionality of a simple data— acquisition device // S. Salewski 23— MAR— 2007 #include #include #include ’’macros. h” #include ”usb drv.h” #include ’’usart debug . h” #include ” ringbuffer . h” #include ”daq_dev.h” #include ”com_def.h” uint8 t DAQ Result; static uintl6_t SamplesToRead; void ProcessUserCommand(uint8_t command, uintl6_t pari , uintl6_t par2) { uint8 t prescalerADC; uint8_t prescalerTO ; uint8_t counterTOMax; switch (command) { case UC ADC Read: switch (( uint8_t ) pari) { case ADC20us: prescalerADC = ((1< 0) { while (ADCSRA & (1< 0) { if (RBJsFullO) { DAQ .Result = IJsbDcvStatusDAQ Bu fferOverflow; } else { if (DAQ .Result == UsbDevStatusOK) RB.Write(w); else RB.Write(OxFFFF); SamplesToRead ; } } UsbDevSelectEndpoint(2); if (UsbDevTransmitterReadyO) { uint8_t i; if (( SamplesToRead == 0) && (RB Entries == 0)) { TIMSKO = 0; Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — daq dev.c 11 i = 64; } else i = UsbDevGetByteCountLow(); switch (i) { default : w = RB_Read(); //w = cut; dump counter to FIFO for testing UsbDevWriteByte(LSB(w)); UsbDevWriteByte(MSB(w)); case 62; if (RB Entries > 0) { w = RB_Read(); UsbDevWriteByte(LSB(w)); UsbDevWriteByte(MSB(w)); } break; case 64: U sbDevClearTransmitterReady () ; UsbDevSendInData(); } } if (TIFRO &(1< #include #include ”usb_spec . h” // USB Vendor ID is assigned by www.usb.org // Vendor— and product id is defined in coniudefh, because we need it in our host program too! //# define MyUSB _VendorID 0x03eb // Atmel code //# define MyUSB _Pro due tID 0x0001 #define MyUSB_DeviceBCD 0x0001 // modify these values for your application ! #define USB_NumConfigurations 1 // 1 or more #define USB_MaxConfigurations 4 // our device can have multiple configuration with different number of j interfaces #define USB_MaxInterfaces 4 // each interface of a configuration has a number of endpoints #define USB MaxStringDescriptorLength 22 // An interface can have multiple alternate settings , but number of endpoints of this interface is fix . // To ensure that reallocation of endpoints with new FIFO size of one interface will not interfere with other D interfaces , // only the interface with highest number should use multiple alternate settings with different endpoint FIFO D sizes #define EPO_FIFO_Size 8 // 8, 16, 32 or 64 byte // FIFO size of EP1 upto EP6 is defined in conudef.h // These macros are called if an endpoint interrupt is triggered ( if enabled ) // and may be used to fill ( IN— Endpoint) or read ( OUT— Endpoint) the FIFO. #define UsbDevEP lint Action!) UsbDevFillEPlFIFO() //send status to host #define UsbDevEP2Int Action!) // EP2, used for DAQ data, is filled by timer— ISR #define UsbDevEP3IntAction!) UsbDevReadEP3FIFO() // read data byte for digital port B #define UsbDevEP4Int Action!) #define UsbDevEP5Int Action!) #define UsbDevEP6Int Action!) // These functions provides the host with device specific USB descriptors during the enumeration process void UsbGetDeviccDcscriptor!USB DeviceDescriptor *d); bool UsbGetConfigurationDescriptor(USB_ConfigurationDescriptor *c, uint8_t conflndex); Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb api.h 13 bool UsbGetlnterfaceDescriptor ( USB JnterfaceDescriptor *i, uint8_t conflndex, uint8_t intlndex , uint8_t altSetting ) ); bool UsbGetEndpointDescriptor(USB_EndpointDescriptor *e, uint8 t conflndex, uint8 t intlndex, uint8 t altSetting , ) uint8 t endlndex); void UsbGetStringDescriptorfchar s [], uint8_t index); // These functions allocate FIFO memory and setup all used endpoints bool UsbDevSetConfiguration( uint8_t c); bool UsbDevSetInterface( uint8_t conf, uint8 t inf, uint8 t as); // User defined function , used in our application to start data acquisition void UsbDevProcessVendorRequest(USB_DeviceRequest *req); // These functions are called from within ISR and fill or read FIFO void UsbDevFillEPlFIFO(void); void UsbDevReadEP3FIFO(void); #endif Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb api.c 14 // AT90USB/usb_api.c // This file contains functions which are project specific and should be modified // to customize the USB— driver. // S. Salewski 21— MAR— 2007 #include #include #include ” defines . h” #include ”com_def.h” #include ”usart_debug .h” #include ”usb_spec . h” #include ”usb_drv.h” #include ”daq_dev.h” // ProcessU serCommand(), DAQJlesult #include ”usb api . h” #include ” usb .requests .h” // The behavior of USB devices is specified by different descriptors defined by www.usb.org. // In the simplest case a device has one Device— Descriptor, one Configuration —Descriptor, // one Interface — Descriptor and a few Endpoint— Descriptors . For more advanced devices // there may exist multiple Configuration — and Interface — Descriptors , each with multiple Endpoint— // Descriptors . We may store all these structures in arrays or linked lists , which takes // much storage in RAM and is not easy to handle. // My currently preferred solution to handle the descriptors is to generate them on the fly if // they are requested by the host. This is simple and consumes very few RAM. // If a descriptor is needed during enumeration process, one of the functions // of this file is called to initialize the structure according to specific parameters, // and then the structure is passed to the USB host. The user has to modify the constants // and the functions of this file for a specific device . For simple devices this is very // easy for devices with multiple configurations / interfaces it is more demanding. // You may add constants , variables or functions to this file, i.e. to remember the state of an ep. // First let us write down the parameters of the endpoints which we want to use. // We have to remember these facts during enumeration, when filling or reading the FIFO, // and for the communication of the host with our device . // The current version of this file is adapted to a simple Data— Acquisition— Device. // Our DAQ device has only one configuration with one single interface . // Numbers of configurations , interfaces , alternate settings and endpoints start with 0, // configuration 0 indicates unconfigured (addressed) state, and endpoint 0 is the control endpoint. // Our device use control endpoint 0 and data endpoints 1, 2 and 3 of interface 0. // Commands are send to our device by vendor— requests using endpoint 0. // Endpoint 1 is configured as Bulk— IN— endpoint and used to transfer status information // from device to the host. Whenever the host tries to read data from empty endpoint 1, // a NAK— interrupt is generated, causing firmware to write status information to this ep. // Endpoint 2 is configured as Bulk— IN— Endpoint and used to send DAQ— data to the host . // DAQ operation starts when host sends a vendor request . Controlled by a periodically // activated timer interrupt , daq data is put to the FIFO of endpoint 2. // Endpoint 3 is configured as Bulk— OUT— Endpoint and used to send a single byte from the // host to the device . This byte sets the pins of digital port B of our AT90USB. // To keep it simple: Only one configuration, only one interface. // EP1: Bulk— IN, 8 bytes FIFO, one bank. // EP2: Bulk— IN, 64 bytes FIFO, dual bank. // EP3: Bulk— OUT, 8 bytes FIFO, one bank. const uint8 t USBJnterfaces[USBJVlaxConfigurations] = {1, 0, 0, 0}; // number of interfaces in each configuration const uint8 t USB JMaxPower_2mA[USB JVIaxConfigurations] = {50, 0, 0, 0}; //power consumption of each configuration 2 in 2mA units Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb api.c 15 const uint8_t USB_AltSettings[USB_MaxConfigurations][USB_MaxInterfaces] = {{1, 0, 0, 0}, // number of alt . settings of interfaces of first configuration {0, 0, 0, 0}, // number of alt . settings of interfaces of second configuration { 0 , 0 , 0 , 0 }, { 0 , 0 , 0 , 0 }}; const uint8_t USB_Endpoints[USB_MaxConfigurations][USB_MaxInterfaces] = {{3, 0, 0, 0}, // number of endpoints of interfaces of first configuration {0, 0, 0, 0}, // number of endpoints of interfaces of second configuration { 0 , 0 , 0 , 0 }, {0, 0, 0, 0}}; static void UsbDevDisableAndFreeEndpoint(uint8_t i) ; static void UsbDevSetUnconfiguredState(void); void U sbGetDeviceDescriptor(USB _DeviceDescriptor *d) { d— >bLength = USB_DeviceDescriptorLength; d— >bDescriptorType = US B DeviceDescriptorType; d - >bcdUSB = USB _Spec 1_1 ; d— >bDeviceClass = UsbNoDeviceClass; d— >bDeviceSubClass = UsbNoDeviceSubClass; d— >bDeviceProtocoll = UsbNoDeviceProtokoll; d— >bMaxPacketSizeO = EP0 FIFO Size; d— >idVendor = MyUSBJVendorlD; d— >idProduct = MyUSB_ProductID; d— >bcdDevice = MyUSB_DeviceBCD; d— >iManufacturer = USB_ManufacturerStringIndex; d— >iProduct = USB_ProductStringIndex; d— >iSerialNumber = USB S erialNumber S tringlndex ; d— >bNumConfigurations = USB_NumConfigurations; } bool UsbGetConfigurationDescriptor(USB_ConfigurationDescriptor *c, uint8 t conflndex) { uint8_t i; if (conflndex >= USB_NumConfigurations) return false; c— >bLength = USB_ConfigurationDescriptorLength; c— >bDescriptorType = USB_ConfigurationDescriptorType; c— >wTotalLength = USB_ConfigurationDescriptorLength; i = USBJnterfaces [conflndex]; c — >bNumInterfaces = i; while ( i — >0) c— >wTotalLength += (USB JnterfaceDescriptorLength+USB_EndpointDescriptorLength*USB_Endpoints[confIndex][i])* ) USB A]tSettings[confTndex][i]; c — >bConfiguration Value = UsbConfigurationValue(conflndex) ; c— >iConfiguration = UsbNoDescriptionString; //no textual configuration description c— >bmAttributes = UsbConfDesAttrBusPowered; // bus— powered, no remote wakeup c — >MaxPower = US B_MaxPower_2m A [conflndex]; return true ; } bool UsbGetlnterfaceDescriptor ( USBJnterfaceDescriptor *i, uint8_t conflndex, uint8_t intlndex , uint8_t altSetting ) { if (( conflndex >=USB NumConfigurations)||(intIndex>=USB Interfaces [cont'I ndex])| ( altSetting ;>=USB AltSettings[ ) conflndex] [intlndex ]) ) return false; Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb api.c 16 i — >bLength = USBJnterfaceDescriptorLength; i — >bDescriptorType = USB JnterfaceDescriptorType; i — >bInterfaceNumber = intlndex; i — >bAlternateSetting = altSetting ; i — >bNumEndpoints = USB_Endpoints[confIndex][intIndex]; i — >bInterfaceClass = UsbNoInterfaceClass; i — >bInterfaceSubClass = UsbNoInterfaceSubClass; i — >bInterfaceProtocol = UsbNoInterfaceProtokoll ; i — >ilnterface = UsbNoDescriptionString; // no textual interface description return true ; } // Not used for EPO, so 1 <= endlndex <= USB NumEndpoints <= 6 bool UsbGetEndpointDescriptor(USB JEndpointDescriptor *e, uint8_t conflndex, uint8_t intlndex, uint8_t altSetting , ) uint8_t endlndex) { if ((conflndex>=USB_NumConfigurations)||(intIndex>=USB_Interfaces[confIndex])||( altSetting >=USB_AltSettings[ ) conflndex] [intlndex ]) || (endIndex>USBJEndpoints[conf!ndex] [intlndex])) return false ; // components identical for all of our endpoints e— >bLength = USB_EndpointDescriptorLength; e— >bDescriptorType = USB_EndpointDescriptorType; e— >bmAttributes = USB BulkTransfer; e— >blnterval = 0; // bulk endpoint, no polling // components which differ switch (endlndex) // only endpoints for interface 0 in our application { case 1: e— >bEndpoint Address = UsblnEndpointAdress(l); e— >wMaxPacketSize = EPl_FIFO_Size; break; case 2: e— >bEndpoint Address = UsblnEndpointAdress(2); e— >wMaxPacketSize = EP2 FIFO Size; break; case 3; e— >bEndpoint Address = UsbOutEndpointAdress(3); e— >wMaxPacketSize = EP3_FIFO_Size; break; } return true ; } void UsbGetStringDescriptor(char s [], uint8 t index) { uint8_t i; #if (USB_MaxStringDescriptorLength < 18) #error USB_MaxStringDescriptorLength too small! #endif i = USBJdaxStringDescriptorLength; while (i — )*s++=’\0’; s — = USB JVlaxStringDescriptorLength; s [1] = USB_StringDescriptorType; switch (index) { case USB_LanguageDescriptorIndex: // == 0 Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb api.c 17 s [0] = 4; s [2] = 9; // two byte language code, only support for English s [3] = 4; break; case USB _ManufacturerStringIndex: s [2] = ’S’; s [4] = ’A’; s [6] = ’L’; s [8] = ’E’; s [10] = ’W’; s [12] = ’S’; s [14] = ’K’; s [16] = ’I’; s [0] = 18; // length of descriptor break; case USB_ProductStringIndex: s [2] = ’A’; s[4] = ’T’; s [6] = ’9’; s [8] = ’O’; s [10] = ’U’; s [12] = ’S’; s [14] = ’B’; s [0] = 16; break; case US B _S erialN umberS tringlndex : s [2] = ’O’; s [4] = ’O’; s[6] = ’ 1’ ; s [0] = 8; break; default : s[2] = ’?’ ; s [0] = 4; } } static void U sbDevDisable AndFreeEndpointl uint8 _t i ) { UsbDevSelectEndpoint(i) ; U sbDevDisableEndpoint() ; UsbDevClearEndpointAllocBit(); } static void UsbDevSetUnconfiguredState(void) { uint8_t i; UsbDevConfValue = UsbUnconfiguredState; i = UsbNumEndpointsAT90USB; while ( i > 0) // free all endpoints but EP0 U sbDevDisable AndFreeEndpoint(i) ; UsbAllocatedEPs = 1; } // A device can have multiple configurations . In the simplest case configurations may differ only in power D consumption. Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb api.c 18 // But configurations can be totally different ( differ in number of interfaces, endpoints, ... bool UsbDevSetConfiguration( uint8 t c) { uint8_t i; switch (c) { case 0: // go back to unconfigured ( addressed ) state U sbDevSetUnconfiguredState() ; return true ; break; case 1: // set configuration 1 if (UsbDevConfValue != c) { i = USB_MaxInterfaces; while (i >0) AltSettingOflnterface [i] = UsblnterfaceUnconfigured ; } for (i = 0; i < USB_Interfaces[c— 1]; i++) { if (! UsbDevSetInterface(c, i , 0)) { UsbDevSetUnconfiguredState() ; return false ; } } UsbDevConfValue = c; return true ; break; default : Debug(”UsbDevSetConfiguration(): configuration does not exist !\r\n”); return false ; } } // Multiple interfaces can exist at the same time! These interfaces have to use different endpoints. // For example interface 1 can use epl and ep2, and interface 2 can use some of the other endpoints ( ep3, ep4, ep5 D , ep6). // A special problem occurs from FIFO memory management of AT90USB: Memory for FIFO has to be allocated in growing D order. // If we use multiple interfaces with multiple alternate settings there may occur memory conflicts concerning D FIFO memory: // If we allocate memory for endpoint i, there may be an overlap with FIFO of endpoint i + 1 or memory of endpoint i D +1 may slide . // This is a result of internal design of AT90USB, see section 21.7 in datasheet. // But from USB design interfaces should be independent , changes of interface i should not affect interface j#i // To prevent conflicts , following strategy is useful : // Use endpoints 1 to n for interface 1, endpoints n+1 to mfor interface 2, and endpoints m+1, m+2 ... for D interface 3. // Give only more than one alternate setting to the interface with the highest number. So changes of alternate D setting // with new FIFO sizes can not disturb other interfaces . // If you really need more than one interface with different alternate settings ( endpoint FIFO sizes ) you may try D to // insert unused dummy endpoints to prevent memory slides or overlaps . Or use different configurations or force D reallocation of all endpoints . // Our application uses only interface 0 with endpoints epl, ep2, ep3. But the code is designed to support more D interfaces . bool Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb api.c 19 UsbDevSetInterface( uint8_t conf, uint8_t inf, uint8_t as) { uint8 _t i; if (conf == UsbUnconfiguredState) // each interface should be bound to a configuration { Debug(”UsbDevSetInterface(): called from unconfigured (addressed) state !\r\n”); return false ; } if ((inf >= USB -Interfaces [conf ]) || (as >= USB A ItSetti ngs [conf | [ inf ])) { Debug(”UsbDevSetInterface(): interface not supported !\r\n”); return false ; } if ((as > 0) && (inf != (USB -Interfaces [conf] — 1))) { Debug(”UsbDevSetInterface(): Multiple interfaces with more than one alternate setting => FIFO memory conflicts ) may occur!\r\n”) ; return false ; } if ( AltSettingOflnterface | inf ] == as) // no changes, reset toggle bits of endpoints of this interface { if (conf == 0) { _ if (inf == 0) // first interface of first configuration { for (i = 1; i < 4; i++) // reset toggle bit of all endpoints of this interface ; an endpoint reset may be 2 necessary too { UsbDevSelectEndpoint(i) ; UsbDevResetEndpoint(i); UsbDevResetDataToggleBit(); } } else if (inf == 1) // second interface of first configuration { // reset endpoints of second interface } } else if (conf == 2) // similar operations { } return true ; } if (conf == 0) { _ if ( inf == 0) // first allocation or reallocation with new alternate setting { UsbDevDisableAndFreeEndpoint(3); UsbDevDisableAndFreeEndpoint(2); U sbDevDisable AndFreeEndpoint( 1 ); UsbAllocatedEPs = 1; AltSettingOflnterface [0] = UsblnterfaceUnconfigured ; if (as == 0) // use alternate setting 0 { if (UsbDevEP_Setup(l, UsbEP.TypeBulk, EPl_FIFO_Size, 1, UsbEP_DirIn)) { Debug(”H! Successful set up EPl!\r\n”); //UsbDevSelectEndpoint(l); this ep is already selected by UsbDevEPSetupO Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb api.c 20 UsbDevEnableNAKJN_Int(); // trigger interrupt when host got a NAK as a result of a read request } else { Debug(”!!! Setup of EP1 failed !\r\n”); // should not occur ;—) return false ; } if (UsbDevEP_Setup(2, UsbEP TypeBulk, EP2 FIFO Size, 2, UsbEP Dirln)) { Debug(”H! Successful set up EP2!\r\n”); } else { Debug(”!!! Setup of EP2 failed !\r\n”); return false ; } if (UsbDevEP_Setup(3, UsbEP.TypeBulk, EP3_FIFO_Size, 1, UsbEP_DirOut)) { Debug(”!!! Successful set up EP3!\r\n”); UsbDcvEnableReceivcdOUT DA'I’A Inti);// trimmer interrupt when out data is available } else { Debug(”H! Setup of EP3 failed !\r\n”); return false ; } } else if (as == 1) // alternate setting 1 { // set up same endpoints with different parameters (FIFO— size) } AltSettingOflnterface [0] = as; UsbStartupFinished = 1; return true ; } else if ( inf == 1) // setup interface 1 { } } else if (conf == 1) // similar setup if configuration 2 with other interfaces is selected { } return false ; // dummy to suppress compiler warning } void UsbDevProcessVendorRequest(USB_DeviceRequest *req) { ProcessUserCommand(req— >bRequest, req ->wValue, req— >wlndex); } // This function is called whenever host tries to read data from epl // We send a status byte which indicates success of DAQ operation void U sbDevFillEP 1 FIFO(void) { if UsbDevTransmitterReadyO { Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb api.c 21 U sbDevClearTransmitterReady () ; UsbDevClearNAK_ResponseInBit(); U sbDevW riteByte(D AQ Result) ; U sbDevS endInData() ; } // This function is called whenever OUT FIFO has data for us void UsbDevReadEP3FIFO(void) { if (UsbDevHasReceivedOUT_Data()) { U sbDe vC learHa sReeeivedOUT D at a( ) ; if (UsbDevReadAllowedO) { DDRB = OxFF; PORTB = UsbDevReadByte(); UsbDevClearFifoControllBit() ; // mavbe we should use an alias for this } } } macro Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb requests.!! 22 // AT90USB/usb _requests. h // Handling of USB (standard) requests // S. Salewski 22— MAR— 2007 #ifndef JJSB .REQUESTS _H_ #define _USB .REQUESTS _H_ #include #include #include ”usb_spec . h” #include ”usb_api.h” // USB_MaxInterfaces // USB— Standard— Device— Requests, H.J. Kelm USB 2.0, section 2.9.1, page 108 #define USB StdDcvRcqGET STATUS 0x00 #define USB.StdDcvRcqCLEAR J’EA'I URE 0x01 #define USB_StdDevReqSET_FEATURE 0x03 #define USB_StdDevReqSET_ADDRESS 0x05 #define USB_StdDevReqGET_DESCRIPTOR 0x06 #define USB StdDevReqSET DESCRIPTOR 0x07 #define USB StdDcvRcqGET CONFIGURATION 0x08 #define USB_StdDevReqSET_CONFIGURATION 0x09 #define USB .StdDevReqGETJNTER FACE OxOA #define USB_StdDevReqSET_INTERFACE OxOB #define USB Std DevReqS YNC H FRAME OxOC // Meaning of bmRequestType, H.J. Kelm #define UsblsDataHostToDevice(bm) #define UsblsDataDeviceToHost(bm) #define UsblsStandardRequest(bm) #define UsblsClassRequest(bm) #define UsbIsVendorRequest(bm) #define UsblsRequestForDevice(bm) #define UsblsRequestForlnterface (bm) #define U sblsRequestForEndpoint(bm) #define UsblsRequestForOther(bm) USB 2.0, section 2.9.1, page 107 (!(bm&(l«7))) (bm & (1<<7)) (bm & (3«5)) == 0 (bm&(3«5)) == (1«5) (bm&(3«5)) == (1«6) (bm & (31) == 0 (bm & (31) == 1 (bm & (31) == 2 (bm & (31) == 3 extern uint8_t UsbDevConfValue; // current configuration of our device; 0 is unconfigured state extern uint8 t AltSettingOflnterface [USBJMaxInterfaces]; // current alternate setting of active interfaces void UsbProcessSetupRequest(void); //void UsbDevWriteDescriptor(void *d, uint8j * written , uint8_t requested); //void UsbDevReadBytesN(void *c, uint8_t n); // void WaitZLP JFromHost(void); // void UsbProcessSetupRequest(void); //bool UsbSendDescriptorsf uint8j cdi, uint8_t * written , uint8j requested); //bool UsbDevSetInterface( uint8j inf, uint8_t as); //bool UsbDevSetConfigurationf uint8j c); #endif Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb requests.e 23 // AT90USB/usb _requests. c // Handling of USB (standard) requests // S. Salewski 22— MAR— 2007 #include #include ’’macros. h” #include ”usb_spec.h” #include ”usb drv.h” #include ”usart debug . h” #include ”usb_api.h” // EPO-FIFO-Size and USBJVumlnterfaces #include ” usb .requests .h” uint8 t UsbDevConfValue = UsbUnconfiguredState; uint8 t AltSettingOflnterface [4] = { UsblnterfaceUnconfigured , UsblnterfaceUnconfigured, UsblnterfaceUnconfigured , ) UsblnterfaceUnconfigured }; uint8_t RemoteWakeup Active = 0; static void UsbDevWriteDescriptorlvoid *d, uint8_t * written, uint8_t requested); static void UsbDevReadBytesN(void *c, uint8_t n); static bool UsbSendDescriptors( uint8_t cdi, uint8 t * written, uint8 t requested); // Send descriptor to host, but don’t send more total bytes than requested. // Stop if there is a ZLP ( abort ) from host or if all bytes are send, else // fill FIFO and send FIFO if FIFO is full . static void UsbDevWriteDescriptor(void *d, uint8_t * written, uint8_t requested) { uint8_t 1; 1 = requested — * written; // we may send l bytes more if (1 > *( uint8 _t *)d) 1 = *( uint8_t *)d; // clip to size of this descriptor while (1 — ) { if UsbDevHasReceivedOUT_Data() // ZLP from host abort { * written = requested; // prevent further writes return; } UsbDevWriteByte(*(uint8_t*)d++); // put byte to FIFO if (((* written +=1) % EPO .FIFO .Size) == 0) // if FIFO full { UsbDevSendControlIn(); // send FIFO //while (!( UsbDevHasReceivedOUTJData() || UsbDevTransmitterReadyO)); while (!(UEINTX&((l«RXOUTI) | (1«TXINI)))); //the same saves a few bytes } } } // Read n bytes from FIFO; FIFO should contain exactly n bytes // Limited to n < 256 static void UsbDevReadBytesN(void *c, uint8 t n) { Assert (UsbDevGetByteCountLow() == n); while (n ) *(uint8_t*)c++ = UsbDevReadByte(); } static void WaitZLP_FromHost(void) Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb requests.e 24 { while (! UsbDevHasReceivedOUT_Data()); UsbDcvCIearHasReceivetlOUT Data(); } void UsbProcessSetupRequest(void) { USB DeviceRequest req; union // we can use the same piece of memory for these descriptors { USB_DeviceDescriptor devDes; USB Con figuration Descriptor confDes; char strDes [USB MaxStriiigDcscriptorLength |; } u; uint8_t b; UsbDevSelectEndpoint(O); UsbDevReadBytesN(&req, 8); // Caution: We have to delay the AcknowledgeSETUPf) if request is a 3 stage — transfer with out data // because host may send out data immediately after our acknowledge and may not see our stall request! if (!( req.bRequest == USB_StdDevReqSET_DESCRIPTOR)) /// 3 stage— transfer with out data UsbDevAcknowledgeSETUP(); UsbDumpSetupRequest(&req); if (UsblsVendorRequest(req.bmRequestType)) { ReqDebugC’Received UsbVendorRequest”); UsbDevProcessVendorRequest(&req); U sbDevS electEndpoint( 0) ; UsbDevSendControlInO; // send ZLP } else if (UsbIsStandardRequest(req . bmRequestType)) { ReqDebugC’Received UsbStandardRequest”); switch (req.bRequest) { case USB StdDcvRcqGET STATUS: // 3 stages with 2 byte IN— data not tested yet ReqDebug(”USB_StdDevReqGET_STATUS”); Assert ( req . w Value == 0) ; Assert ( req . wLength == 2); switch ( req . bmRequestType) < case 128: // device: Self —Power— Bit, Remote— Wakeup— Bit set? Assert ( req . wlndex == 0) ; if (UsbDevConfValue == UsbUnconfiguredState) { ReqDebugC’Error: USB.StdDevReqGET .STATUS device in unconfigured state!”); UsbDevRequestStallHandshake(); return; } UsbGetConfigurationDescriptorl&u.confDes, UsbDevConfValue); if (u. confDes. bmAttributes &(l<<6))b=l; else b = 0; // self powered? if ((u. confDes. bmAttributes & (1<<5)) && (RemoteWakeupActive)) b |= (1 << 1); UsbDevWriteByte(b); break; case 129: // interface : Always return 0 if (UsbDevConfValue == UsbUnconfiguredState) { ReqDebugC’Error: USB_StdDevReqGET .STATUS interface in unconfigured state!”); Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb requests.e 25 UsbDevRequestStallHandshake(); return; } // Assert (req.wlndex < USB Jnterfaces[U sbDevConjValue]); UsbDevWriteByte(O); break; case 130: // endpoint: is this endpoint stalled? Assert ((MSB(req.wIndex) == 0)); b = LSB(req.wIndex) & 127; // endpoint number if (b >= U sbNumEndpointsAT90U SB) { ReqDebugC’Error: USB_StdDevReqGET .STATUS endpoint does not exist!”); UsbDevRequestStallHandshake(); return; } if ((UsbDevConfValue == UsbUnconfiguredState) && (b > 0)) { ReqDebugC’Error: USB.StdDevReqGET .STATUS for ep > 0 in unconfigured state!”); UsbDevRequestStallHandshake(); return; } UsbDevSelectEndpoint(b); if ( UsbDevIsEndpointStalled () ) // stalled bit is marked write— only in datasheet do we need a ) separate state variable ? UsbDev WriteBy tel 1 ) ; else U sbDev WriteBy te(0) ; UsbDevSelectEndpoint(O); break; default : ReqDebugC’Error; USB.StdDevReqGET.STATUS !”); UsbDevRequestStallHandshakel); return; } UsbDevWriteByte(O); UsbDevSendControlIn(); Wai tZLP .From Host() ; break; case USB.StdDevReqCLEARJFEATURE; // 2 stages (no data— stage) not tested yet case USB_StdDevReqSET_FEATURE: ReqDebug(”USB_StdDevReqCLEAR/SETJFEATURE”); Assert ( req . wLength == 0); switch 1 req . bmRequestType) { case 0: // device Assert 1 req . wlndex == 0) ; if ( req. w Value != 1) // Feature selector != DEVICE .REMOTE J/VAKEUP { ReqDebugC’Error: USB_StdDevReqSET/CLEAR_FEATURE wrong feature selector for device!”); UsbDevRequestStallHandshakel); return; } if (req .bRequest == USB_StdDevReqCLEAR_FEATURE) { RemoteWakeupActive = 0; } else { Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb requests.e 26 UsbGetConfigurationDescriptor(&u.confDes, UsbDevConfValue); if (!(u.confDes.bmAttributes &(1<<5)))// Remote— Wakeup support set in configuration descriptor? { ReqDebugC’Error: USB StdDcvRcqSET FEATURE, Remote— Wakeup not supported!”); UsbDevRequestStallHandshake(); return; I RemoteWakeupActive = 1 ; // here we only set a flag of course this is not enough to reactivate the sleeping bus } break; case 1: // interface nothing to do. Should we request a stall handshake? ReqDebugC’Error: USB StdDevReqSET/CLEAR FEATURE with receiver == interface!”); UsbDevRequestStallHandshake(); return; break; case 2: // endpoint Assert (MSB(req.wIndex) == 0); if (req.wValue != 0) // Feature selector != ENDPOINT STALL { ReqDebugC’Error: USB_StdDevReqSET/CLEAR_FEATURE wrong feature selector for endpoint!”); UsbDevRequestStallHandshake(); return; } b = LSB(req.wIndex) & 127; // endpoint address if (b >= U sbNumEndpointsAT90U SB) { ReqDebugC’Error: USB_StdDevReqSET/CLEAR_FEATURE endpoint does not exist!”); UsbDevRequestStallHandshake(); return; } if ((UsbDevConfValue == UsbUnconfiguredState) && (b > 0)) { ReqDebug(”Error: USB_StdDevReqClearSetFeature forep > 0 in unconfigured state !”); UsbDevRequestStallHandshake(); return; } // Caution: what shall we do if (b == 0)? UsbDevSelectEndpoint(b); if ( req . bRequest == USB StdDcvRcqCLEAR FEATURE) { UsbDevClearStallRequest() ; UsbDevResetEndpoint(b); // should we do an endpoint reset ? UsbDevResetDataToggleBit(); } else { UsbDevRequestStallHandshake(); // for endpoint b } UsbDevSelectEndpoint(O); break; default : ReqDebugC’Error: USB_StdDevReqClearSetFeature!”); UsbDevRequestStallHandshake(); return; } UsbDevSendControlIn(); // send ZLP break; Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb requests.e 21 case USB_StdDevReqSET_ADDRESS: //2 stages (no data— stage) ReqDebug(”USB_StdDevReqSET_ADDRESS”); if ((LSB(req.wValue) == 0) && (UsbDevConfValue != UsbUnconfiguredState)) { ReqDebug(”Error: USB_StdDevReqSET .ADDRESS address 0 in configured state!”); UsbDevRequestStallHandshake(); return; } Assert (req.bmRequestType == 0); Assert (MSB(req.wValue) == 0); Assert (req . wlndex == 0) ; Assert (req . wLength == 0); UsbDevSetAddress(LSB(req.wValue)); UsbDevSendControlInO; // send ZLP UsbDevWaitTransmitterReadyO; UsbDevEnableAddress(); break; case USB_StdDevReqSET_DESCRIPTOR: // 3 stage— transfer with out data ReqDebugf’Error: USB.StdDevReqSET .DESCRIPTOR currently not supported!”); UsbDevRequestStallHandshake(); // RequestStalIHandshake() before UsbDevAcknowledgeSETUP() UsbDev AcknowledgeSETUP(); //to ensure that host will not send out data! // you may implement this request if you have any idea for what you can use it break; case USB StdDevReqGET CONFIGURATION: // 3 stages with 1 byte IN— data not tested yet ReqDebug(”USB_StdDevReqGET_CONFIGURATION”); Assert (req.bmRequestType == 128); Assert ( req . w Value == 0) ; Assert ( req . wlndex == 0) ; Assert (req. wLength == 1); U sbDev WriteBy te(U sbDevConfValue) ; UsbDevSendControlInO; W a i t Z L P .Fro m H o s t () ; break; case USB_StdDevReqSET_CONFIGURATION: // 2 stages (no data— stage) ReqDebug(”USB_StdDevReqSET_CONFIGURATK)N”); Assert (req.bmRequestType == 0); Assert (MSB(req.wValue) == 0); Assert ( req . wlndex == 0) ; Assert ( req . wLength == 0); if (UsbDevSetConfiguration(LSB(req.wValue))) { UsbDevSelectEndpoint(O); // UsbDevSetConfigurationf) may select other ep UsbDevSendControlInO; // send ZLP } else { ReqDebugf’Error: USB.StdDevReqSET .CONFIGURATION unsupported configuration!”); UsbDevSelectEndpoint(O); UsbDevRequestStallHandshake(); } break; case USB.StdDevReqGETJNTERFACE: // 3 stages with 1 byte IN— data not tested yet ReqDebug(”USB_StdDevReqGET_INTERFACE”); if (UsbDevConfValue == UsbUnconfiguredState) { ReqDebugf’Error: USB.StdDevReqGETJNTERFACE in unconfigured state!”); UsbDevRequestStallHandshake(); return; Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb requests.e 28 } Assert (req.bmRequestType == 129); Assert (req . w Value == 0) ; Assert (MSB(req.wIndex) == 0); Assert (req. wLength == 1); UsbDevWriteByte(AltSettingOfInterface [( uint8_t ) LSB(req.wIndex)]); UsbDevSendControlIn(); WaitZLP FromHostf); break; case USB_StdDevReqSET_INTERFACE: // 2 stages (no data— stage) ReqDebug(”USB_StdDevReqSET_INTERFACE”); if (UsbDevConfValue == UsbUnconfiguredState) { ReqDebugf’Error: USB StdDcvReqSET INTERFACE in unconfigured state!”); UsbDevRequestStallHandshake(); return; } Assert (req.bmRequestType == 1); Assert (MSB(req.wValue) == 0); Assert (MSB(req.wIndex) == 0); Assert (req . wLength == 0); if (UsbDevSetInterface(UsbDevConfValue, LSB(req.wIndex), LSB(req.wValue))) { UsbDevSelectEndpoint(O); // UsbDevSetlnterface () may select other ep UsbDevSendControlIn(); // send ZLP } else { UsbDevSelectEndpoint(O); ReqDebug(”Error: USB.StdDevReqSET .INTERFACE alt. setting does not exist!”); UsbDevRequestStallHandshake(); } break; case USB_StdDevReqSYNCH_FRAME; // 3 stages with 2 byte IN— data not supported ReqDcbugf’ljSB StdDevRcqSYNCH FRAME not supported!”); UsbDevRequestStallHandshake(); return; case USB_StdDevReqGET_DESCRIPTOR: // 3 stages transfer ReqDebug(”USB_StdDevReqGET_DESCRIPTOR”); Assert (req.bmRequestType == 128); { uint8_t requested ; uint8_t written = 0; if (MSB(req. wLength)) requested = 255; else requested = LSB(req. wLength); // we will never send more ) than 255 bytes switch (MSB(req.wValue)) { case 1: // Device— Descriptor Assert ( req . wlndex == 0) ; Assert (LSB(req.wValue) == 0); UsbGetDeviceDescriptor(&u.devDes); U sbDumpDeviceDescriptor( &u .devDes) ; UsbDevWriteDescriptorl&u.devDes, &written, requested ) ; break; case 2: // Configuration — Descriptor if (! UsbSendDescriptors(LSB(req.wValue), &written, requested)) { ReqDebug(”Error: USB.StdDevReqGET .DESCRIPTOR: can not sent Configuration— Descriptor!”); Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb requests.e 29 UsbDevRequestStallHandshake(); return; } break; case 3: // String —Descriptor UsbGetStringDescriptor(u. strDes , LSB(req.wValue)); // strDes is an array, so no & is necessary! UsbDumpStringDescriptor(u.strDes) ; UsbDevWriteDescriptor(u. strDes , &written, requested); break; default : ReqDebug(”USB_StdDevReqGET_DESCRIPTOR: Unknown type!”); return; } if UsbDevHasReceivedOUT_Data() // got ZLP from host abort! { UsbDevClearHasReceivedOUT_Data(); ReqDebug(”USB_StdDevReqGET .DESCRIPTOR: Abort from host!”); return; } if (((written % EPCLFIFO.Size) != 0) || (written < requested)) U sbDevSendControlIn() ; WaitZLP_FromHost(); } break; default : ReqDebugf’Received unsupported UsbStandardRequest!”); UsbDevRequestStallHandshake(); } } else { ReqDebug(”Unsupported nonstandard request!”) ; UsbDevRequestStallHandshake(); } } static bool UsbSendDescriptors( uint8_t cdi, uint8_t * written, uint8_t requested) { union // we can use the same piece of memory for these descriptors { USB .Configuration Descriptor confDes; USBJnterfaceDescriptor intDes; USB_EndpointDescriptor endDes; } u; // uint8J cdi; // configuration descriptor index uint8_t idi ; // interface descriptor index uint8_t as; // alternate setting of interface uint8_t edi ; // endpoint descriptor index if ( UsbGetConfigurationDescriptor(&u.confDes, cdi)) { UsbDumpConfigurationDescriptor(&u.confDes); UsbDevWriteDescriptor(&u.confDes, written , requested ) ; idi =0; do { as = 0; while ( UsbGetlnterfaceDescriptor (&u.intDes, cdi, idi, as)) Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb requests.e { UsbDumpInterfaceDescriptor(&u.intDes); UsbDevWriteDescriptor(&u.intDes, written, requested); for (edi = 1; edi < UsbNumEndpointsAT90USB; edi++) { if (UsbGetEndpointDescriptor(&u.endDes, edi, idi , as, edi)) { UsbDumpEndpointDescriptor(&u.endDes); UsbDevWriteDescriptor(&u.endDes, written , requested ) ; } } as++; } idi ++; } while (as >0); return true ; } else return false ; } Free (GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor usbjspec.h 31 // AT90USB/usb_spec.h // USB datastructures as defined by www.usb.org // S. Salewski 27— FEB— 2007 #ifndef _USB_SPEC_H_ #define _USB_SPEC_H_ #include #define USB_Specl_l 0x0110 #define USB_Spec2_0 0x0200 #define USB_ControlTransfer 0 #define USB JsochronousTransfer 1 #define USB BulkTransfer 2 #define USBJnterruptTransfer 3 #define USB_DeviceDescriptorType #define USB_ConfigurationDescriptorType #define USB StringDcscriptor Iype #define USB JnterfaceDescriptorType #define USB_EndpointDescriptorType // #define USBJJeviceQualifierDescriptorType 0x06 // only used for high speed devices // # define USBJDtherSpeedConfigurationDescriptorType 0x07 // only used for high speed devices #define USB DeviceDescriptorLength 0x12 #define USB -Configuration DescriptorUength 0x09 #define USBJnterfaceDescriptorLength 0x09 #define USB_EndpointDescriptorLength 0x07 #define USBXanguageDescriptorlndex 0 #define USB_ManufacturerStringIndex 1 #define USB_ProductStringIndex 2 #define USB.SerialNumberStringlndex 3 // USB uses little endian format, avr—gcc too, so no byte— swap is necessary for 16 bit data // USB— Device— Request, H.J. Kelm USB 2.0, section 2.9.1, page 107 typedef struct { uint8_t bmRequestType; uint8_t bRequest; uintl6_t wValue; uintl6_t wlndex; uintl6_t wLength; } USB_DeviceRequest; // Device— Descriptor, H.J. Kelm, USB 2.0, section 2.8.2 (page 98) and section 9.4.7 (page 296) typedef struct { uint8_t bLength; uint8_t bDescriptorType ; uintl6_t bcdUSB; uint8_t bDeviceClass; uint8_t bDeviceSubClass; uint8_t bDeviceProtocoll ; uint8_t bMaxPacketSizeO; uintl6_t idVendor; uintl6_t idProduct ; 0x01 0x02 0x03 0x04 0x05 Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usbjspec.h 32 uintl6_t bcdDevice; uint8_t iManufacturer ; uint8_t iProduct ; uint8_t iSerialNumber; uint8_t bNumConfigurations; } USB_DeviceDescriptor; // Configuration— Descriptor, H.J. Kelm, USB 2.0, section 2.8.3 (page 100) and section 9.4.7 (page 297) typedef struct { uint8_t bLength; uint8_t bDescriptorType ; uintl6_t wTotal Length; uint8_t bNumlnterfaces ; uint8_t bConfigurationValue ; uint8_t iConfiguration ; uint8_t bm Attributes ; uint8_t MaxPower; } USB_ConfigurationDescriptor; // Interface —Descriptor, H.J. Kelm, USB 2.0, section 2.8.4 (page 101) and section 9.4.7 (page 297) typedef struct { uint8_t bLength; uint8_t bDescriptorType ; uint8_t blnterfaceNumber; uint8_t bAlternateSetting ; uint8_t bNumEndpoints; uint8_t blnterfaceClass ; uint8_t blnterfaceSubClass uint8_t blnterfaceProtocol uint8_t ilnterface ; } USBJnterfaceDescriptor ; // Endpoint— Descriptor, H.J. Kelm, USB 2.0, section 2.8.5 (page 102) and section 9.4.7 (page 298) typedef struct { uint8_t bLength; uint8_t bDescriptorType ; uint8_t bEndpointAddress; uint8_t bm Attributes ; uintl6_t wMaxPacketSize; uint8_t blnterval ; } USB_EndpointDescriptor; /* not used typedef char USBStringDescriptor[USB-MaxStringDescriptorLength ]; void InitDeviceDes ( USB _DeviceDescriptor *d); void InitConfigurationDes (USB_ConfigurationDescriptor *c); void InitInterfaceDes(USBJnterfaceDescriptor *i); void InitEndpointDes ( USB JEndpointDescriptor *e); */ #endif Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb spec.c 33 // AT90USB/usb_spec.c // Initialization of USB datastructures // S. Salewski 27— FEB— 2007 #include ”usb_spec.h” #include ”usb_api.h” // USB uses little endian format, avr—gcc too, so no byte— swap is necessary for 16 bit data /* set defaults, we don’t really need this void InitDeviceDes ( USB DeviceDescriptor *d ) { d—>bLength = USB JOeviceDescriptorLength; d—>bDescriptorType = USBJDeviceDescriptorType; d—>bcdUSB = USBSpeclJ; d—>bDeviceClass = 0; d—>bDeviceSubClass = 0; d—>bDeviceProtocoll = 0; d—>bMaxPacketSizeO = EPO _FIFO Size; d—>idVendor = MyUSB _VendorID; d—>idProduct = MyUSB _ProductID; d—>bcdDevice = My USB De viceB CD ; d—>iManufacturer = USB JdanufacturerStringlndex; d—>iProduct = USB -/‘roductSt ring Index; d—>iSeriaINumber = USBSerialNumberStringlndex; d—>bNumConfiqurations = 1; } void InitConfigurationDes (USB_ConfigurationDescriptor *c) { c—>bLength = USB _Configu ration Descri/)torLength; c—>bDescriptorType = USBJSonfigurationDescriptorType; c—>wTotalLength = 0; // this and the following fields must be filled with correct values! c—>bNumInterfaces = 0; c—>bConfigurationValue = 0; c—>iConfiguration = 0; c—>bmAttributes = 0; c—>MaxPower = 0; } void InitlnterfaceDes (USBJnterfaceDescriptor *i) { i—>bLength = USBJnterfaceDescriptorLength; i — >bDescriptorType = USB JnterfaceDescriptorType; i->bInterfaceNumber = 0;// this and the following fields must be filled with correct values! i — >bAlternateSetting = 0; i — >bNumEndpoints = 0; i — >bInterfaceClass = 0; i — >bInterfaceSubClass = 0; i — >bInterfaceProtocol = 0; i — >ilnterface = 0; } void Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usbjspec.c InitEndpointDes ( USB _EndpointDescriptor *e) { e—>bLength = USB Endpoint Descriptor Length; e—>bDescriptorType = USB Endpoint DescriptorType; e->bEndpointAddress = 0;// this and the following fields must be filled with correct values e—>bmAttributes = 0; e—>wMaxPacketSize = 0; e—>blnter\’al = 0; } Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb drv.h 35 // AT90USB/usb_drv.h // Macros for access to USB registers of Atmels AT90USB microcontrollers // This file contains low level register stuff as described in // Atmels AT90USB datasheet 7593D—AVR— 07/06 // S. Salewski 21— MAR— 2007 #ifndef _USB_DRV_H_ #define USB DRV H #include #include #include #include ” defines . h” #define UsbNumEndpointsAT90USB 7 #define UsbEP_TypeControl 0 #define UsbEP.Typelso 1 #define UsbEP TypeBulk 2 #define UsbEP _TypeInterrupt 3 #define UsbEP _DirOut 0 #define UsbEP _DirControl 0 #define UsbEP _DirIn 1 #define UsbUnconfiguredState 0 #define UsblnterfaceUnconfigured OxFF #define UsbNoInterfaceClass OxFF #define UsbNoInterfaceSubClass OxFF #define UsbNoInterfaceProtokoll OxFF #define UsbNoDeviceClass OxFF #define UsbNoDeviceSubClass OxFF #define UsbNoDeviceProtokoll OxFF #define UsbNoDescriptionString 0 extern uintS t UsbAllocatedEPs; extern volatile uintS t UsbStartupFinished ; void UsbDevFaunchDevice(bool lowspeed); bool UsbDevEP_Setup(uint8_t num, uint8_t type, uintl6_t size, uint8_t banks, uint8_t dir); void UsblnitialReset (void); void UsbStartPFF(void); void UsbDevStartDeviceEPO(void); // A few macros for bit fiddling #define SetBit(adr, bit) #define ClearBit(adr, bit) #define BitlsSet (adr, bit) #define BitlsClear ( adr , bit ) (adr |= (l«bit)) (adr &=~(l< #include #include // sei () #include ”usb_drv.h” #include ”usart_debug .h” #include ”usb_api.h” // EPO_FIFOASize uint8 t UsbAllocatedEPs = 0; volatile uint8 t UsbStartupFinished = 0; // Set some registers to their initial (reset) value. // Reason: Atmels bootloader activates some interrupts . // This function deactivates it , so we have clean start // conditions if our program is started from bootloader . void UsblnitialReset (void) { USBCON = (1«FRZCLK); OTGIEN = 0; UDIEN = 0; UHIEN = 0; UEIENX = 0; UPIENX = 0; UHWCON = (l«UIMOD); } // Start PLL and enable clock void UsbStartPLL(void) { UsbSetPLL XTAL FrequencyO; UsbEnablePLL(); UsbWaitPLLXocked(); U sbEnableClockO ; } // Basic USB activation necessary to trigger a wakeup interrupt // Wakeup ISR will start PLL clock, then USB— END— OF— RESET interrupts are recognized void UsbDevLaunchDevice(bool lowspeed) { UsblnitialReset () ; if (1) // set it to (1) if you need very small code size (i.e. bootloader, saves 78 bytes) { UHWCON = ((l«UIMOD) | (1«UVREGE)); USBCON = ((1«USBE) | (l«OTGPADE) | (1«FRZCLK)); asm volatile (”nop”); // nop may be are necessary if mpu is clocked with 16 MHz (deactivated prescaler) // asm volatile ("nop”); if (lowspeed) UDCON = (1«LSM); USBCON = ((1«USBE) | (l«OTGPADE)); USBCON = ((1< 6) || (dir >1) || (banks >1) || (type >3) || (size & 0xFC07)) return false ; i = ( uint8_t ) ( size / 8) ; if ((UsbDevIsLowSpeedSelectedQ) && ((type == UsbEP _TypeBulk) 1 1 (type == UsbEP _TypeIso) || (i >1))) return ) false ; if (!(( i == 1) || (i == 2) || (i == 4) || (i =8))) if (!((( i ==16) || (i ==32) || (i ==64)) && (type == UsbEP _TypeIso))) return false; if ((type == UsbEP _TypeControl) && ((dir != UsbEP _DirControl) || (banks >0))) return false; Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usb drv.c 44 if (num == 0) { if ((dir != UsbEP DirControl) || (type != UsbEP _TypeControl)) return false; // EPO is always control ep } else { .. if ((num != UsbAllocatedEPs) || // allocate eps in growing order, see section 21.7 (type == UsbEP _TypeControl)) return false; // more than one control ep may be ok? } U sbDevSelectEndpoint( num) ; UsbDevEnableEndpoint(); // enable ep before memory is allocated? Yes, see figure 22—2 j = 0; while ((i = (i >> 1))) j++; UECFGOX = ((type « 6) | (dir)) ; UECFG1X = ((j « 4) | (banks « 2)); UECFG1X |= (1 « ALLOC); if (UESTAOX & (1 « CFGOK)) { U sb AllocatedEPs++ ; return true ; } else { U sbDevDisableEndpoint() ; return false ; } } Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usart drv.h 45 // AT90USB/usart_drv.h // Basic output routines for USART, adapted to Atmels AT90USB microcontrollers // Based on AT90USB datasheet (7593D—AVR— 07/06), chapter 18 and examples from // http :// www.mikrocontroller . net/ articles / AVR—GCC— Tutorial and // http :// www.roboternetz.de/wissen/index . php/UART jnit_avr— gcc // S. Salewski 29-JAN-2007 #ifndef USART DRV H #define USART DRV H #include #include ” defines . h” #ifndef NOUART void USART Jnit(void); // initialize USART, 8N1 mode void USART _WriteChar(char c); void USART _WriteHex(unsigned char c); void USART _WriteHexW(uintl6_t w); void USART _WriteString(char *s); void USART_NewLine(void); #else #define USART_Init() #define USART_WriteChar(c) #define USAR'I WritcHcxfcj #define USAR'I WritcHexW(w) #define USART_WriteString(s) #define USART_NewLine() #endif #endif Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usart drv.c 46 // AT90USB/usartjdrv.c // Basic output routines for USART, adapted to Atmels AT90USB microcontrollers // Based on AT90USB Datasheet (7593D—AVR— 07/06), chapter 18 and examples from // http :// www.mikrocontroller . net/ articles / AVR—GCC— Tutorial and // http :// www.roboternetz.de/wissen/index . php/UART jnit_avr— gcc // S. Salewski 27— FEB— 2007 #include #include ” defines . h” #include ” usart.drv . h” #include ’’macros. h” #ifndef NOUART #define Wait_USART_Ready() while (!(UCSR1A & (1«UDRE1))) #define UART.UBRR (F_CPU/(16L*USART_BAUD)-1) // initialize USART, 8N1 mode void USART Jnit(void) { UBRR1 = UARTJUBRR; UCSR1C = (1«UCSZ10) | (1«UCSZ11); UCSR1B = (1<>4); if (nibble < 10) nibble +=’0’; else nibble += (’A’ -10); Wait JUS ART _Ready(); UDR1 = nibble; nibble = (c & OxOF); if (nibble < 10) nibble +=’0’; else nibble += (’A’ — 10); Wait_US ART .Ready () ; UDR1 = nibble; } void USART_WriteHexW(uintl6_t w) { USART_WriteHex(MSB(w)); USART_WriteHex(LSB(w)); } void USART JWriteString(char *s) { while (*s) USART_WriteChar(*s++); Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usart drv.c } void USART _Ne wLine ( void) { WaitJJS ART .Ready () ; udri = V; Wait JJS ART .Ready () ; UDRI = ’\n’; } #endif Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usart debug.h 48 // AT90USB/usart_debug.h // A few macros for debugging by sending messages over the serial port // S. Salewski 22— MAR— 2007 #ifndef _USART_DEBUG_H_ #define _USART_DEBUG_H_ #include ” defines . h” #include ” usart drv . h” #include ”usb_spec . h” #ifdef DEBUG #define Debug(msg) USART WriteString(msg) //#define ReqDebug(msg) USART Write St ring) msg ” (” JFILE ”)\r\n”) #define ReqDebug(msg) USART_WriteString(”|” msg ”\r\n”) #else #define Debug(msg) #define ReqDebug(msg) #endif #ifdef DEBUG #define Assert(exp) if (exp == 0) USART_WriteString(”Error: ” #exp ” == 0 (” __FILE__ ”)\r\n”); #else #define Assert (exp) #endif #ifdef DEBUG void UsbDumpDeviceDescriptor(USB_DeviceDescriptor *d); void UsbDumpConfigurationDescriptor(USB_ConfigurationDescriptor *c) ; void UsbDumpInterfaceDescriptor(USB JnterfaceDescriptor *i ) ; void UsbDumpEndpointDescriptor(USB_EndpointDescriptor *e); void UsbDumpStringDescriptor(char *s); void UsbDumpSetupRequest(USB_DeviceRequest *rcq); #else #define UsbDumpDeviceDescriptor(d) #define UsbDumpConfigurationDescriptor(c) #define U sbDumpInterfaceDescriptor( i ) #define UsbDumpEndpointDescriptor(e) #define UsbDumpStringDescriptor(s) #define UsbDumpSetupRequest(req) #endif #endif Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usart debug.c 49 // AT90USB/iisart_debug.c // Debugging by sending messages over the serial port // S. Salewski 22— MAR— 2007 #include ” defines . h” #ifdef DEBUG #include ''usart debug . h” #include ”usb_spec . h” #include ”usart_drv .h” void UsbDumpDevieeDescriptor(USB DeviccDcscriptor *d) { USART_WriteString(”USB Device— Descriptor:”); USART _WriteString(”\r\n d— >bLength: ”); USART_WriteHex(d— >bLength); USART_WriteString(”\r\n d— >bDescriptorType: ”); USART_WriteHex(d— >bDescriptorType); USART WriteString(”\r\n d->bcdUSB: ”); USART_WriteHexW(d->bcdUSB); USART _WriteString(”\r\n d— >bDeviceClass: ”); USART WriteHex(d- ->bDevieeClass); USART_WriteString(”\r\n d— >bDeviceSubClass: ”); USART_WriteHex(d— >bDeviceSubClass); USART _WriteString(”\r\n d— >bDeviceProtocoll: ”); USART _WriteHexfd—>bDeviceProtocoll); USART _WriteString(”\r\n d— >bMaxPacketSizeO: ”); USART JWriteHexfd— >bMaxPacketSizeO); USART _WriteString(”\r\n d— >idVendor: ”); USART_WriteHexW(d— >idVendor); USART _WriteString(”\r\n d— >idProduct: ”); USART WriteHexWfd — >idPmduct); USART _WriteString(”\r\n d— >bcdDevice: ”); USART_WriteHexW(d— >bcdDevice); USART_WriteString(”\r\n d— >iManufacturer: ”); USART_WriteHex(d— >iManufacturer); USART _WriteString(”\r\n d— >iProduct: ”); USART _WriteHex(d— >iProduct); USART_WriteString(”\r\n d— >iSerialNumber: ”); USART_WriteHex(d— >iSerialNumber); USART WriteStringf ’\r\n d— >bNumConfigurations: ”); USAR'I WritcHcxfd — >bNumCoufigurations); USART_NewLine(); } void UsbDumpCoufiguratioiiDcscriptorfUSB ConfigurationDcscriptor *c) { USART _WriteString(” —USB Configuration— Descriptor:”); USART _WriteString(”\r\n c— >bLength: ”); USART_WriteHex(c— >bLength); USART_WriteString(”\r\n c— >bDescriptorType: ”); USART_WriteHex(c— >bDescriptorType); USART _WriteString(”\r\n c— >wTotalLength: ”); USART_WriteHexW(c— >wTotalLength); USAR'I’ WriteStri ng(”\r\ n c— >bNumInterfaces: ”); USART_WriteHex(c— >bNumInterfaces); USART _WriteString(”\r\n c—>bConfiguration Value: ”); USART_WriteHex(c—>bConfiguration Value); USART _WriteString(”\r\n c— >iConfiguration: ”); USART _WriteHex(c— >iConfiguration); USART_WriteString(”\r\n c— >bmAttributes: ”); USART_WriteHex(c— >bmAttributes); USART_WriteString(”\r\n c— >MaxPower: ”); USART_WriteHex(c— >MaxPower); USART_NewLine(); } void U sbDumpInterfaceDescriptorf USB JnterfaceDescriptor * i ) { USAR'I WriteStringf’ —USB Interface— Descriptor:”); USART_WriteString(”\r\n i — >bLength: ”); USART_WriteHex(i— >bLength); USART_WriteString(”\r\n i — >bDescriptorType: ”); USART_WriteHex(i— >bDescriptorType); USART_WriteString(”\r\n i — >bInterfaceNumber: ”); USART_WriteHex(i— >bInterfaceNumber); USART _WriteString(”\r\n i — >bAlternateSetting: ”); USART WriteHexii — >bAltcrnateSetting); USART _WriteString(”\r\n i — >bNumEndpoints: ”); USAR'I WriteHexii — >bNumEndpoints); USART _WriteString(”\r\n i — >b!nterfaceClass: ”); USART _WriteHex(i— >b!nterfaceClass); Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usart debug.c 50 USART _WriteString(”\r\n i — >bInterfaceSubClass: ”); USART _WriteHex(i— >bInterfaceSubClass); USART_WriteString(”\r\n i — >bInterfaceProtocol: ”); USART _WriteHex(i— >bInterfaceProtocol); USART WriteString(”\r\n i — >ilnterface: ”); USART_WriteHex(i— >ilnterface); USART_NewLine(); } void UsbDumpEndpointDescriptor(USB _EndpointDescriptor *e) { USART _WriteString(” —USB Endpoint— Descriptor:”); USART _WriteString(”\r\n e— >bLength: ”); USART _WriteHex(e— >bLength); USART_WriteString(”\r\n e— >bDescriptorType: ”); USART_WriteHex(e— >bDescriptorType); USART WriteString(”\r\n e— >bEndpointAddress: ”); USART WritcHexie—>bEndpoi lit Address); USART _WriteString(”\r\n e— >bmAttributes: ”); US AR'I WriteHex(e— >bmAttributes); USART _WriteString(”\r\n e— >wMaxPacketSize: ”); USART_WriteHexW(e— >wMaxPacketSize); USART _WriteString(”\r\n e— >blnterval: ”); USART_WriteHex(e— >blnterval); USART_NewLine(); } void U sbDumpS tringDescriptorl char * s) { uint8_t i; i = *s; US AR'I WriteString(”USB String— Descriptor:\r\n”); while (i ) USART_WriteHex(*s++); USART_NewLine(); } void UsbDumpSetupRequest(USB_DeviceRequest *req) { U S ART _ W riteS tring(” S etup Reque st :”) ; USART_WriteString(” \r\nbmRequestType: ”); USART_WriteHex(req— >bmRequestType); USART WriteStringi” \r\nbRequest: ”); USART WritcHexireq — >bRequest); USART WriteStringi” \r\nwValue: ”); USART WritcHexWireq ->wValue); USART_WriteString(” \r\nwlndex: ”); USART_WriteHexW(req— >wlndex); USART _WriteString(” \r\nwLength: ”); USART _WriteHexW(req— >wLength); USART_NewLine(); } #endif Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — ringbuffer.h 51 // AT90USB/ringbuffer.h // Simple Ring— Buffer (FIFO) for Elements of type Q // S. Salewski, 20— MAR— 2007 #ifndef _RINGJBUFFER_H_ #define _RINGJBUFFER_H_ #include #define BufElements 1024 #define Q uintl6_t extern u inti 6 t RB Entries; #define RB_FreeSpace() (BufElements — RB_Entries) #define RBJsFulH) (RB .Entries == BufElements) #define RB JsEmptyO (RBJEntries == 0) void RB Jnit(void) ; void RB_Write(Q el); Q RB Jlead(void); #endif Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — ringbuffer.c 52 // AT90USB/ringbuffer.c // Simple Ring— Buffer (FIFO) for Elements of type Q // S. Salewski, 19— MAR— 2007 /* t—> o o <— w X x <—r b—> x */ #include #include ” ringbuffer . h” static Q buf[BufElements]; uintl6_t RBJEntries; #define t &buf[BufElements — 1] #define b &buf[0] // Q *t = &buf[ BufElements — 1 ]; //Q *b = &buf[0]; Q *r; // position from where we can read ( if RB JEntries >0) Q *w; // next free position ( if RBJEntries < BufElements)) void RBJnit(void) { r = b; w = b; RB .Entries = 0; } Q RB Read(void) { // Assert ( RB_Entries > 0); RB .Entries ; if (r > t) r = b; return *r++; } void RB_Write(Q el) { // Assert ( RB -Entries < BufElements ); RB _Entries++; if (w > t) w = b; *w++ = el; } Free ( GPL) USB Firmware for Atmels AT90USB 8-bit microprocessor — usbJsr.c 53 // AT90USB/usb_isr.c // USB Interrupt Service Routines // S. Salewski 22— MAR— 2007 #include #include #include ”usb_drv.h” #include ’’usart debug . h” #include ’’usb.api.h” #include ”usb .requests .h” // USB General Interrupt Handler (Figure 21.11) // USB Registers: USBINT.O, USBINT.l, UDINT ISR(USB_GEN_vect) { Debug(”ISR(USB_GEN_vect)\r\n”); if UsbIsIDTI_FlagSet() { UsbClearlDTI JFlagO ; Debug(”=== IDTIJFlagSet\r\n”); } if UsbIsVBUSTI_FlagSet() { UsbClearVBUSTLFlag(); Debug(”=== VBUSTLFlagSet\r\n”); } if UsbDevIsEndOfResetFlagSet() { UsbDevClearEndOfResetFlagO; U sbDevS tartDeviceEPO() ; Debug(”=== EndOfResetFlagSet\r\n”); } if UsbDevIsWakeupCPU JlagSetO { U sbDevDisable WakeupCPU _Int() ; U s b D c vC lea r Wa l< e u p C P U Flag() ; UsbStartPLL(); Debug(”=== WakeupCPU _FlagSet\r\n”); } // USB Endpoint/Pipe Interrupt Handler (Figure 21.12) // Endpoint Registers : UEINTX, UESTAX.6 and UESTAX.5 // Setup— Request may reset endpoints, so we process data endpoints first ! // User defined actions have to acknowledge the interrupt ! ISR(USB_COM_vect) { uint8_t mask; uint8_t ep; Debug(”ISR(USB_COM_vect)\r\n”); mask = UsbDevGetEndpointIntBits(); ep = UsbNumEndpointsAT90USB; while (ep — > 0) { if (mask & (l<