From 19de9d82c15c1cea2512f84d1af723ba10afd3a1 Mon Sep 17 00:00:00 2001 From: Ben Z Yuan <bzy@mit.edu> Date: Thu, 25 Oct 2018 16:02:55 -0400 Subject: [PATCH] add proto0 schematic and firmware --- README.md | 8 +- fabscope_proto0.pdf | Bin 0 -> 45235 bytes firmware/Config/LUFAConfig.h | 126 ++++++++++++++++ firmware/Descriptors.c | 245 ++++++++++++++++++++++++++++++++ firmware/Descriptors.h | 110 ++++++++++++++ firmware/LUFA VirtualSerial.inf | 66 +++++++++ firmware/main.c | 239 +++++++++++++++++++++++++++++++ firmware/main.h | 65 +++++++++ firmware/makefile | 51 +++++++ 9 files changed, 909 insertions(+), 1 deletion(-) create mode 100644 fabscope_proto0.pdf create mode 100644 firmware/Config/LUFAConfig.h create mode 100644 firmware/Descriptors.c create mode 100644 firmware/Descriptors.h create mode 100644 firmware/LUFA VirtualSerial.inf create mode 100644 firmware/main.c create mode 100644 firmware/main.h create mode 100644 firmware/makefile diff --git a/README.md b/README.md index ea569cb..cd02818 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ # FabScope -Coordination and discussion for the FabScope project. \ No newline at end of file +Coordination and discussion for the FabScope project. + +## Requirements + +* LUFA 170418 (http://www.fourwalledcubicle.com/LUFA.php) +* a PDI programmer (e.g. avrisp2) +* optionally, the Atmel DFU bootloader (AVR1916) diff --git a/fabscope_proto0.pdf b/fabscope_proto0.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9ea2f326dac5f114b8bdced5cf66a4c803c775ea GIT binary patch literal 45235 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�n(Kb{ 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 Q#KgkXgiBS`)!&T^0Mj}S&Hw-a literal 0 HcmV?d00001 diff --git a/firmware/Config/LUFAConfig.h b/firmware/Config/LUFAConfig.h new file mode 100644 index 0000000..0ec4635 --- /dev/null +++ b/firmware/Config/LUFAConfig.h @@ -0,0 +1,126 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2017. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + 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 + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * \brief LUFA Library Configuration Header File + * + * This header file is used to configure LUFA's compile time options, + * as an alternative to the compile time constants supplied through + * a makefile. + * + * For information on what each token does, refer to the LUFA + * manual section "Summary of Compile Tokens". + */ + +#ifndef _LUFA_CONFIG_H_ +#define _LUFA_CONFIG_H_ + + #if (ARCH == ARCH_AVR8) + + /* Non-USB Related Configuration Tokens: */ +// #define DISABLE_TERMINAL_CODES + + /* USB Class Driver Related Tokens: */ +// #define HID_HOST_BOOT_PROTOCOL_ONLY +// #define HID_STATETABLE_STACK_DEPTH {Insert Value Here} +// #define HID_USAGE_STACK_DEPTH {Insert Value Here} +// #define HID_MAX_COLLECTIONS {Insert Value Here} +// #define HID_MAX_REPORTITEMS {Insert Value Here} +// #define HID_MAX_REPORT_IDS {Insert Value Here} +// #define NO_CLASS_DRIVER_AUTOFLUSH + + /* General USB Driver Related Tokens: */ +// #define ORDERED_EP_CONFIG + #define USE_STATIC_OPTIONS (USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL) + #define USB_DEVICE_ONLY +// #define USB_HOST_ONLY +// #define USB_STREAM_TIMEOUT_MS {Insert Value Here} +// #define NO_LIMITED_CONTROLLER_CONNECT +// #define NO_SOF_EVENTS + + /* USB Device Mode Driver Related Tokens: */ +// #define USE_RAM_DESCRIPTORS + #define USE_FLASH_DESCRIPTORS +// #define USE_EEPROM_DESCRIPTORS +// #define NO_INTERNAL_SERIAL + #define FIXED_CONTROL_ENDPOINT_SIZE 8 +// #define DEVICE_STATE_AS_GPIOR {Insert Value Here} + #define FIXED_NUM_CONFIGURATIONS 1 +// #define CONTROL_ONLY_DEVICE + #define INTERRUPT_CONTROL_ENDPOINT +// #define NO_DEVICE_REMOTE_WAKEUP +// #define NO_DEVICE_SELF_POWER + + /* USB Host Mode Driver Related Tokens: */ +// #define HOST_STATE_AS_GPIOR {Insert Value Here} +// #define USB_HOST_TIMEOUT_MS {Insert Value Here} +// #define HOST_DEVICE_SETTLE_DELAY_MS {Insert Value Here} +// #define NO_AUTO_VBUS_MANAGEMENT +// #define INVERTED_VBUS_ENABLE_LINE + + #elif (ARCH == ARCH_XMEGA) + + /* Non-USB Related Configuration Tokens: */ +// #define DISABLE_TERMINAL_CODES + + /* USB Class Driver Related Tokens: */ +// #define HID_HOST_BOOT_PROTOCOL_ONLY +// #define HID_STATETABLE_STACK_DEPTH {Insert Value Here} +// #define HID_USAGE_STACK_DEPTH {Insert Value Here} +// #define HID_MAX_COLLECTIONS {Insert Value Here} +// #define HID_MAX_REPORTITEMS {Insert Value Here} +// #define HID_MAX_REPORT_IDS {Insert Value Here} +// #define NO_CLASS_DRIVER_AUTOFLUSH + + /* General USB Driver Related Tokens: */ + #define USE_STATIC_OPTIONS (USB_DEVICE_OPT_FULLSPEED | USB_OPT_RC32MCLKSRC | USB_OPT_BUSEVENT_PRIHIGH) +// #define USB_STREAM_TIMEOUT_MS {Insert Value Here} +// #define NO_LIMITED_CONTROLLER_CONNECT +// #define NO_SOF_EVENTS + + /* USB Device Mode Driver Related Tokens: */ +// #define USE_RAM_DESCRIPTORS + #define USE_FLASH_DESCRIPTORS +// #define USE_EEPROM_DESCRIPTORS +// #define NO_INTERNAL_SERIAL + #define FIXED_CONTROL_ENDPOINT_SIZE 8 +// #define DEVICE_STATE_AS_GPIOR {Insert Value Here} + #define FIXED_NUM_CONFIGURATIONS 1 +// #define CONTROL_ONLY_DEVICE + #define MAX_ENDPOINT_INDEX 4 +// #define NO_DEVICE_REMOTE_WAKEUP +// #define NO_DEVICE_SELF_POWER + + #else + + #error Unsupported architecture for this LUFA configuration file. + + #endif +#endif diff --git a/firmware/Descriptors.c b/firmware/Descriptors.c new file mode 100644 index 0000000..5ec042c --- /dev/null +++ b/firmware/Descriptors.c @@ -0,0 +1,245 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2017. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + 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 + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * USB Device Descriptors, for library use when in USB device mode. Descriptors are special + * computer-readable structures which the host requests upon device enumeration, to determine + * the device's capabilities and functions. + */ + +#include "Descriptors.h" + + +/** Device descriptor structure. This descriptor, located in FLASH memory, describes the overall + * device characteristics, including the supported USB version, control endpoint size and the + * number of device configurations. The descriptor is read out by the USB host when the enumeration + * process begins. + */ +const USB_Descriptor_Device_t PROGMEM DeviceDescriptor = +{ + .Header = {.Size = sizeof(USB_Descriptor_Device_t), .Type = DTYPE_Device}, + + .USBSpecification = VERSION_BCD(1,1,0), + .Class = CDC_CSCP_CDCClass, + .SubClass = CDC_CSCP_NoSpecificSubclass, + .Protocol = CDC_CSCP_NoSpecificProtocol, + + .Endpoint0Size = FIXED_CONTROL_ENDPOINT_SIZE, + + .VendorID = 0x03EB, + .ProductID = 0x2044, + .ReleaseNumber = VERSION_BCD(0,0,1), + + .ManufacturerStrIndex = STRING_ID_Manufacturer, + .ProductStrIndex = STRING_ID_Product, + .SerialNumStrIndex = USE_INTERNAL_SERIAL, + + .NumberOfConfigurations = FIXED_NUM_CONFIGURATIONS +}; + +/** Configuration descriptor structure. This descriptor, located in FLASH memory, describes the usage + * of the device in one of its supported configurations, including information about any device interfaces + * and endpoints. The descriptor is read out by the USB host during the enumeration process when selecting + * a configuration so that the host may correctly communicate with the USB device. + */ +const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = +{ + .Config = + { + .Header = {.Size = sizeof(USB_Descriptor_Configuration_Header_t), .Type = DTYPE_Configuration}, + + .TotalConfigurationSize = sizeof(USB_Descriptor_Configuration_t), + .TotalInterfaces = 2, + + .ConfigurationNumber = 1, + .ConfigurationStrIndex = NO_DESCRIPTOR, + + .ConfigAttributes = (USB_CONFIG_ATTR_RESERVED | USB_CONFIG_ATTR_SELFPOWERED), + + .MaxPowerConsumption = USB_CONFIG_POWER_MA(100) + }, + + .CDC_CCI_Interface = + { + .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, + + .InterfaceNumber = INTERFACE_ID_CDC_CCI, + .AlternateSetting = 0, + + .TotalEndpoints = 1, + + .Class = CDC_CSCP_CDCClass, + .SubClass = CDC_CSCP_ACMSubclass, + .Protocol = CDC_CSCP_ATCommandProtocol, + + .InterfaceStrIndex = NO_DESCRIPTOR + }, + + .CDC_Functional_Header = + { + .Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalHeader_t), .Type = DTYPE_CSInterface}, + .Subtype = CDC_DSUBTYPE_CSInterface_Header, + + .CDCSpecification = VERSION_BCD(1,1,0), + }, + + .CDC_Functional_ACM = + { + .Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalACM_t), .Type = DTYPE_CSInterface}, + .Subtype = CDC_DSUBTYPE_CSInterface_ACM, + + .Capabilities = 0x06, + }, + + .CDC_Functional_Union = + { + .Header = {.Size = sizeof(USB_CDC_Descriptor_FunctionalUnion_t), .Type = DTYPE_CSInterface}, + .Subtype = CDC_DSUBTYPE_CSInterface_Union, + + .MasterInterfaceNumber = INTERFACE_ID_CDC_CCI, + .SlaveInterfaceNumber = INTERFACE_ID_CDC_DCI, + }, + + .CDC_NotificationEndpoint = + { + .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = CDC_NOTIFICATION_EPADDR, + .Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = CDC_NOTIFICATION_EPSIZE, + .PollingIntervalMS = 0xFF + }, + + .CDC_DCI_Interface = + { + .Header = {.Size = sizeof(USB_Descriptor_Interface_t), .Type = DTYPE_Interface}, + + .InterfaceNumber = INTERFACE_ID_CDC_DCI, + .AlternateSetting = 0, + + .TotalEndpoints = 2, + + .Class = CDC_CSCP_CDCDataClass, + .SubClass = CDC_CSCP_NoDataSubclass, + .Protocol = CDC_CSCP_NoDataProtocol, + + .InterfaceStrIndex = NO_DESCRIPTOR + }, + + .CDC_DataOutEndpoint = + { + .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = CDC_RX_EPADDR, + .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = CDC_TXRX_EPSIZE, + .PollingIntervalMS = 0x05 + }, + + .CDC_DataInEndpoint = + { + .Header = {.Size = sizeof(USB_Descriptor_Endpoint_t), .Type = DTYPE_Endpoint}, + + .EndpointAddress = CDC_TX_EPADDR, + .Attributes = (EP_TYPE_BULK | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA), + .EndpointSize = CDC_TXRX_EPSIZE, + .PollingIntervalMS = 0x05 + } +}; + +/** Language descriptor structure. This descriptor, located in FLASH memory, is returned when the host requests + * the string descriptor with index 0 (the first index). It is actually an array of 16-bit integers, which indicate + * via the language ID table available at USB.org what languages the device supports for its string descriptors. + */ +const USB_Descriptor_String_t PROGMEM LanguageString = USB_STRING_DESCRIPTOR_ARRAY(LANGUAGE_ID_ENG); + +/** Manufacturer descriptor string. This is a Unicode string containing the manufacturer's details in human readable + * form, and is read out upon request by the host when the appropriate string ID is requested, listed in the Device + * Descriptor. + */ +const USB_Descriptor_String_t PROGMEM ManufacturerString = USB_STRING_DESCRIPTOR(L"Dean Camera"); + +/** Product descriptor string. This is a Unicode string containing the product's details in human readable form, + * and is read out upon request by the host when the appropriate string ID is requested, listed in the Device + * Descriptor. + */ +const USB_Descriptor_String_t PROGMEM ProductString = USB_STRING_DESCRIPTOR(L"LUFA CDC Demo"); + +/** This function is called by the library when in device mode, and must be overridden (see library "USB Descriptors" + * documentation) by the application code so that the address and size of a requested descriptor can be given + * to the USB library. When the device receives a Get Descriptor request on the control endpoint, this function + * is called so that the descriptor details can be passed back and the appropriate descriptor sent back to the + * USB host. + */ +uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, + const uint16_t wIndex, + const void** const DescriptorAddress) +{ + const uint8_t DescriptorType = (wValue >> 8); + const uint8_t DescriptorNumber = (wValue & 0xFF); + + const void* Address = NULL; + uint16_t Size = NO_DESCRIPTOR; + + switch (DescriptorType) + { + case DTYPE_Device: + Address = &DeviceDescriptor; + Size = sizeof(USB_Descriptor_Device_t); + break; + case DTYPE_Configuration: + Address = &ConfigurationDescriptor; + Size = sizeof(USB_Descriptor_Configuration_t); + break; + case DTYPE_String: + switch (DescriptorNumber) + { + case STRING_ID_Language: + Address = &LanguageString; + Size = pgm_read_byte(&LanguageString.Header.Size); + break; + case STRING_ID_Manufacturer: + Address = &ManufacturerString; + Size = pgm_read_byte(&ManufacturerString.Header.Size); + break; + case STRING_ID_Product: + Address = &ProductString; + Size = pgm_read_byte(&ProductString.Header.Size); + break; + } + + break; + } + + *DescriptorAddress = Address; + return Size; +} + diff --git a/firmware/Descriptors.h b/firmware/Descriptors.h new file mode 100644 index 0000000..5b4bf2a --- /dev/null +++ b/firmware/Descriptors.h @@ -0,0 +1,110 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2017. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + 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 + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for Descriptors.c. + */ + +#ifndef _DESCRIPTORS_H_ +#define _DESCRIPTORS_H_ + + /* Includes: */ + #include <avr/pgmspace.h> + + #include <LUFA/Drivers/USB/USB.h> + + /* Macros: */ + /** Endpoint address of the CDC device-to-host notification IN endpoint. */ + #define CDC_NOTIFICATION_EPADDR (ENDPOINT_DIR_IN | 2) + + /** Endpoint address of the CDC device-to-host data IN endpoint. */ + #define CDC_TX_EPADDR (ENDPOINT_DIR_IN | 3) + + /** Endpoint address of the CDC host-to-device data OUT endpoint. */ + #define CDC_RX_EPADDR (ENDPOINT_DIR_OUT | 4) + + /** Size in bytes of the CDC device-to-host notification IN endpoint. */ + #define CDC_NOTIFICATION_EPSIZE 8 + + /** Size in bytes of the CDC data IN and OUT endpoints. */ + #define CDC_TXRX_EPSIZE 16 + + /* Type Defines: */ + /** Type define for the device configuration descriptor structure. This must be defined in the + * application code, as the configuration descriptor contains several sub-descriptors which + * vary between devices, and which describe the device's usage to the host. + */ + typedef struct + { + USB_Descriptor_Configuration_Header_t Config; + + // CDC Control Interface + USB_Descriptor_Interface_t CDC_CCI_Interface; + USB_CDC_Descriptor_FunctionalHeader_t CDC_Functional_Header; + USB_CDC_Descriptor_FunctionalACM_t CDC_Functional_ACM; + USB_CDC_Descriptor_FunctionalUnion_t CDC_Functional_Union; + USB_Descriptor_Endpoint_t CDC_NotificationEndpoint; + + // CDC Data Interface + USB_Descriptor_Interface_t CDC_DCI_Interface; + USB_Descriptor_Endpoint_t CDC_DataOutEndpoint; + USB_Descriptor_Endpoint_t CDC_DataInEndpoint; + } USB_Descriptor_Configuration_t; + + /** Enum for the device interface descriptor IDs within the device. Each interface descriptor + * should have a unique ID index associated with it, which can be used to refer to the + * interface from other descriptors. + */ + enum InterfaceDescriptors_t + { + INTERFACE_ID_CDC_CCI = 0, /**< CDC CCI interface descriptor ID */ + INTERFACE_ID_CDC_DCI = 1, /**< CDC DCI interface descriptor ID */ + }; + + /** Enum for the device string descriptor IDs within the device. Each string descriptor should + * have a unique ID index associated with it, which can be used to refer to the string from + * other descriptors. + */ + enum StringDescriptors_t + { + STRING_ID_Language = 0, /**< Supported Languages string descriptor ID (must be zero) */ + STRING_ID_Manufacturer = 1, /**< Manufacturer string ID */ + STRING_ID_Product = 2, /**< Product string ID */ + }; + + /* Function Prototypes: */ + uint16_t CALLBACK_USB_GetDescriptor(const uint16_t wValue, + const uint16_t wIndex, + const void** const DescriptorAddress) + ATTR_WARN_UNUSED_RESULT ATTR_NON_NULL_PTR_ARG(3); + +#endif + diff --git a/firmware/LUFA VirtualSerial.inf b/firmware/LUFA VirtualSerial.inf new file mode 100644 index 0000000..21d2d12 --- /dev/null +++ b/firmware/LUFA VirtualSerial.inf @@ -0,0 +1,66 @@ +;************************************************************ +; Windows USB CDC ACM Setup File +; Copyright (c) 2000 Microsoft Corporation +;************************************************************ + +[DefaultInstall] +CopyINF="LUFA VirtualSerial.inf" + +[Version] +Signature="$Windows NT$" +Class=Ports +ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} +Provider=%MFGNAME% +DriverVer=7/1/2012,10.0.0.0 + +[Manufacturer] +%MFGNAME%=DeviceList, NTx86, NTamd64, NTia64 + +[SourceDisksNames] + +[SourceDisksFiles] + +[DestinationDirs] +DefaultDestDir=12 + +[DriverInstall] +Include=mdmcpq.inf +CopyFiles=FakeModemCopyFileSection +AddReg=DriverInstall.AddReg + +[DriverInstall.Services] +Include=mdmcpq.inf +AddService=usbser, 0x00000002, LowerFilter_Service_Inst + +[DriverInstall.AddReg] +HKR,,EnumPropPages32,,"msports.dll,SerialPortPropPageProvider" + +;------------------------------------------------------------------------------ +; Vendor and Product ID Definitions +;------------------------------------------------------------------------------ +; When developing your USB device, the VID and PID used in the PC side +; application program and the firmware on the microcontroller must match. +; Modify the below line to use your VID and PID. Use the format as shown below. +; Note: One INF file can be used for multiple devices with different VID and PIDs. +; For each supported device, append ",USB\VID_xxxx&PID_yyyy" to the end of the line. +;------------------------------------------------------------------------------ +[DeviceList] +%DESCRIPTION%=DriverInstall, USB\VID_03EB&PID_2044 + +[DeviceList.NTx86] +%DESCRIPTION%=DriverInstall, USB\VID_03EB&PID_2044 + +[DeviceList.NTamd64] +%DESCRIPTION%=DriverInstall, USB\VID_03EB&PID_2044 + +[DeviceList.NTia64] +%DESCRIPTION%=DriverInstall, USB\VID_03EB&PID_2044 + +;------------------------------------------------------------------------------ +; String Definitions +;------------------------------------------------------------------------------ +;Modify these strings to customize your device +;------------------------------------------------------------------------------ +[Strings] +MFGNAME="http://www.lufa-lib.org" +DESCRIPTION="LUFA CDC-ACM Virtual Serial Port" \ No newline at end of file diff --git a/firmware/main.c b/firmware/main.c new file mode 100644 index 0000000..6b58f5e --- /dev/null +++ b/firmware/main.c @@ -0,0 +1,239 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2017. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + 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 + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Main source file for the FabScope firmware, derived from the LUFA + * VirtualSerial demo. + */ + +#include "main.h" + +#define BUTTONPORT PORTC +#define BUTTONPINOFFSET 3 +#define BUTTONPINCTRL PORTC_PIN3CTRL + +/** 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. + */ +USB_ClassInfo_CDC_Device_t VirtualSerial_CDC_Interface = + { + .Config = + { + .ControlInterfaceNumber = INTERFACE_ID_CDC_CCI, + .DataINEndpoint = + { + .Address = CDC_TX_EPADDR, + .Size = CDC_TXRX_EPSIZE, + .Banks = 1, + }, + .DataOUTEndpoint = + { + .Address = CDC_RX_EPADDR, + .Size = CDC_TXRX_EPSIZE, + .Banks = 1, + }, + .NotificationEndpoint = + { + .Address = CDC_NOTIFICATION_EPADDR, + .Size = CDC_NOTIFICATION_EPSIZE, + .Banks = 1, + }, + }, + }; + +/** Standard file stream for the CDC interface when set up, so that the virtual CDC COM port can be + * used like any regular character stream in the C APIs. + */ +static FILE USBSerialStream; + + +/* button latch state variable */ +static bool buttonState; +static uint16_t buttonDebounce; + +#define BUTTONDEBOUNCETHRESH 10 + + +/** Main program entry point. This routine contains the overall program flow, including initial + * setup of all components and the main program loop. + */ +int main(void) +{ + buttonState = false; + buttonDebounce = 0; + + SetupHardware(); + + /* Create a regular character stream for the interface so that it can be used with the stdio.h functions */ + CDC_Device_CreateStream(&VirtualSerial_CDC_Interface, &USBSerialStream); + + GlobalInterruptEnable(); + + for (;;) + { + + // consume input bytes to prevent blocking (don't do anything with them yet) + CDC_Device_ReceiveByte(&VirtualSerial_CDC_Interface); + + // take an ADC reading and emit it over serial + int16_t adcReading = ADC_Read(); + fprintf(&USBSerialStream, "%d\r\n", adcReading); + + CDC_Device_USBTask(&VirtualSerial_CDC_Interface); + USB_USBTask(); + } +} + +uint8_t ReadSignatureByte(uint16_t Address) +{ + NVM_CMD = NVM_CMD_READ_CALIB_ROW_gc; + uint8_t Result; + Result = pgm_read_byte((uint8_t *)Address); + NVM_CMD = NVM_CMD_NO_OPERATION_gc; + return Result; +} + +void ADC_Init() +{ + // Based on advice from http://barefootelectronics.com/xMegaADC.aspx + + // Configure PA0 as input + PORTA.DIR &= ~(1 << 0); + // Configure PA0 as non-inverting totem pole with disabled digital input buf + PORTA_PIN0CTRL = 7; + + ADCA.CTRLA = ADC_ENABLE_bm; // enabled, no DMA, no started conversion, no flush + ADCA.CTRLB = (1<<4); // high impedance, no limit, signed, non-freerunning, 12-bit right + ADCA.REFCTRL = ADC_BANDGAP_bm; // Internal 1v ref + ADCA.EVCTRL = 0 ; // no events + ADCA.PRESCALER = ADC_PRESCALER_DIV4_gc ; + ADCA.CALL = ReadSignatureByte(0x20) ; //ADC Calibration Byte 0 + ADCA.CALH = ReadSignatureByte(0x21) ; //ADC Calibration Byte 1 + + _delay_us(400); // Wait at least 25 clocks + + ADCA.CH0.CTRL = ADC_CH_GAIN_1X_gc | 1; + ADCA.CH0.MUXCTRL = 0; // ADC0 + ADCA.CH0.INTCTRL = 0; // no interrupt +} + +int32_t ADC_Read(void) +{ + int32_t res = 0; + + // throw away 5 readings and average the next 128 (software denoising attempt) + + for(uint8_t i = 0; i < 5; i++) { + ADCA.CH0.CTRL |= ADC_CH_START_bm; // Start conversion + while (ADCA.INTFLAGS==0) ; // Wait for complete + ADCA.INTFLAGS = ADCA.INTFLAGS ; // writing 1 to INTFLAGS clears it + } + + for(uint8_t i = 0; i<128; i++) + { + ADCA.CH0.CTRL |= ADC_CH_START_bm; // Start conversion + while (ADCA.INTFLAGS==0) ; // Wait for complete + ADCA.INTFLAGS = ADCA.INTFLAGS ; // writing 1 to INTFLAGS clears it + res += ADCA.CH0RES; + } + return res >> 7; +} + +/** Configures the board hardware and chip peripherals for the demo's functionality. */ +void SetupHardware(void) +{ + /* Start the PLL to multiply the 2MHz RC oscillator to 32MHz and switch the CPU core to run from it */ + XMEGACLK_StartPLL(CLOCK_SRC_INT_RC2MHZ, 2000000, F_CPU); + XMEGACLK_SetCPUClockSource(CLOCK_SRC_PLL); + + /* Start the 32MHz internal RC oscillator and start the DFLL to increase it to 48MHz using the USB SOF as a reference */ + XMEGACLK_StartInternalOscillator(CLOCK_SRC_INT_RC32MHZ); + XMEGACLK_StartDFLL(CLOCK_SRC_INT_RC32MHZ, DFLL_REF_INT_USBSOF, F_USB); + + PMIC.CTRL = PMIC_LOLVLEN_bm | PMIC_MEDLVLEN_bm | PMIC_HILVLEN_bm; + + /* Hardware Initialization */ + USB_Init(); + ADC_Init(); + + /* turn on main LED */ + PORTC.DIR |= (1 << 5); + PORTC.OUT |= (1 << 5); + + /* set up button as input */ + BUTTONPORT.DIR &= ~(1 << BUTTONPINOFFSET); + PORTC_PIN3CTRL = (1 << 6) | PORT_OPC_PULLUP_gc | PORT_ISC_BOTHEDGES_gc; +} + +/** Event handler for the library USB Connection event. */ +void EVENT_USB_Device_Connect(void) +{ + //LEDs_SetAllLEDs(LEDMASK_USB_ENUMERATING); +} + +/** Event handler for the library USB Disconnection event. */ +void EVENT_USB_Device_Disconnect(void) +{ + //LEDs_SetAllLEDs(LEDMASK_USB_NOTREADY); +} + +/** Event handler for the library USB Configuration Changed event. */ +void EVENT_USB_Device_ConfigurationChanged(void) +{ + bool ConfigSuccess = true; + + ConfigSuccess &= CDC_Device_ConfigureEndpoints(&VirtualSerial_CDC_Interface); + + //LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR); +} + +/** Event handler for the library USB Control Request reception event. */ +void EVENT_USB_Device_ControlRequest(void) +{ + CDC_Device_ProcessControlRequest(&VirtualSerial_CDC_Interface); +} + +/** CDC class driver callback function the processing of changes to the virtual + * control lines sent from the host.. + * + * \param[in] CDCInterfaceInfo Pointer to the CDC class interface configuration structure being referenced + */ +void EVENT_CDC_Device_ControLineStateChanged(USB_ClassInfo_CDC_Device_t *const CDCInterfaceInfo) +{ + /* You can get changes to the virtual CDC lines in this callback; a common + use-case is to use the Data Terminal Ready (DTR) flag to enable and + disable CDC communications in your application when set to avoid the + application blocking while waiting for a host to become ready and read + in the pending data from the USB endpoints. + */ + bool HostReady = (CDCInterfaceInfo->State.ControlLineStates.HostToDevice & CDC_CONTROL_LINE_OUT_DTR) != 0; +} diff --git a/firmware/main.h b/firmware/main.h new file mode 100644 index 0000000..99b0783 --- /dev/null +++ b/firmware/main.h @@ -0,0 +1,65 @@ +/* + LUFA Library + Copyright (C) Dean Camera, 2017. + + dean [at] fourwalledcubicle [dot] com + www.lufa-lib.org +*/ + +/* + Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com) + + 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 + all copies and that both that the copyright notice and this + permission notice and warranty disclaimer appear in supporting + documentation, and that the name of the author not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + + The author disclaims all warranties with regard to this + software, including all implied warranties of merchantability + and fitness. In no event shall the author be liable for any + special, indirect or consequential damages or any damages + whatsoever resulting from loss of use, data or profits, whether + in an action of contract, negligence or other tortious action, + arising out of or in connection with the use or performance of + this software. +*/ + +/** \file + * + * Header file for main.c. + */ + +#ifndef _MAIN_H_ +#define _MAIN_H_ + + /* Includes: */ + #include <avr/io.h> + #include <avr/wdt.h> + #include <avr/power.h> + #include <avr/interrupt.h> + #include <string.h> + #include <stdio.h> + + #include "Descriptors.h" + + #include <LUFA/Drivers/USB/USB.h> + #include <LUFA/Platform/Platform.h> + + /* Function Prototypes: */ + uint8_t ReadSignatureByte(uint16_t); + + void ADC_Init(void); + int32_t ADC_Read(void); + + void SetupHardware(void); + + void EVENT_USB_Device_Connect(void); + void EVENT_USB_Device_Disconnect(void); + void EVENT_USB_Device_ConfigurationChanged(void); + void EVENT_USB_Device_ControlRequest(void); + +#endif diff --git a/firmware/makefile b/firmware/makefile new file mode 100644 index 0000000..01c39de --- /dev/null +++ b/firmware/makefile @@ -0,0 +1,51 @@ +# +# LUFA Library +# Copyright (C) Dean Camera, 2017. +# +# dean [at] fourwalledcubicle [dot] com +# www.lufa-lib.org +# +# -------------------------------------- +# LUFA Project Makefile. +# -------------------------------------- + +# Run "make help" for target help. + +MCU = atxmega16a4u +ARCH = XMEGA +BOARD = USBKEY +F_CPU = 32000000 +F_USB = 48000000 +OPTIMIZATION = s +TARGET = main +SRC = $(TARGET).c Descriptors.c $(LUFA_SRC_USB) $(LUFA_SRC_USBCLASS) +LUFA_PATH = /PATH/TO/LUFA +CC_FLAGS = -DUSE_LUFA_CONFIG_HEADER -IConfig/ +LD_FLAGS = + +# Default target +all: + +# Include LUFA-specific DMBS extension modules +DMBS_LUFA_PATH ?= $(LUFA_PATH)/Build/LUFA +include $(DMBS_LUFA_PATH)/lufa-sources.mk +include $(DMBS_LUFA_PATH)/lufa-gcc.mk + +# Include common DMBS build system modules +DMBS_PATH ?= $(LUFA_PATH)/Build/DMBS/DMBS +include $(DMBS_PATH)/core.mk +include $(DMBS_PATH)/cppcheck.mk +include $(DMBS_PATH)/doxygen.mk +include $(DMBS_PATH)/dfu.mk +include $(DMBS_PATH)/gcc.mk +include $(DMBS_PATH)/hid.mk +include $(DMBS_PATH)/avrdude.mk +include $(DMBS_PATH)/atprogram.mk + +program-dfu: $(TARGET).hex + sudo dfu-programmer atxmega16a4u erase + sudo dfu-programmer atxmega16a4u flash $(TARGET).hex + sudo dfu-programmer atxmega16a4u launch + +program-avrisp2: $(TARGET).hex + avrdude -p $(MCU) -c avrisp2 -U flash:w:$(TARGET).hex -- GitLab