diff --git a/epicardium/cdcacm.c b/epicardium/cdcacm.c new file mode 100644 index 0000000000000000000000000000000000000000..a11d38e05ecc4475bbc3b3c3a809b87c6c9b753c --- /dev/null +++ b/epicardium/cdcacm.c @@ -0,0 +1,350 @@ +/******************************************************************************* + * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of Maxim Integrated + * Products, Inc. shall not be used except as stated in the Maxim Integrated + * Products, Inc. Branding Policy. + * + * The mere transfer of this software does not imply any licenses + * of trade secrets, proprietary technology, copyrights, patents, + * trademarks, maskwork rights, or any other form of intellectual + * property whatsoever. Maxim Integrated Products, Inc. retains all + * ownership rights. + * + * $Id: main.c 32120 2017-11-28 23:51:11Z lorne.smith $ + * + ******************************************************************************* + */ + +/** + * @file main.c + * @brief USB CDC-ACM example + * @details This project creates a virtual COM port, which loops back data sent to it. + * Load the project, connect a cable from the PC to the USB connector + * on the Evaluation Kit, and observe that the PC now recognizes a new COM port. + * A driver for the COM port, if needed, is located in the Driver/ subdirectory. + * + */ + +#include <stdio.h> +#include <stddef.h> +#include "mxc_config.h" +#include "mxc_sys.h" +#include "mxc_delay.h" +#include "board.h" +#include "led.h" +#include "usb.h" +#include "usb_event.h" +#include "enumerate.h" +#include "cdc_acm.h" +#include "descriptors.h" + + +/***** Definitions *****/ +#define EVENT_ENUM_COMP MAXUSB_NUM_EVENTS + +#define BUFFER_SIZE 64 + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) + +/***** Global Data *****/ +volatile int configured; +volatile int suspended; +volatile unsigned int event_flags; +int remote_wake_en; + +/***** Function Prototypes *****/ +static int setconfig_callback(usb_setup_pkt *sud, void *cbdata); +static int setfeature_callback(usb_setup_pkt *sud, void *cbdata); +static int clrfeature_callback(usb_setup_pkt *sud, void *cbdata); +static int event_callback(maxusb_event_t evt, void *data); +static void usb_app_sleep(void); +static void usb_app_wakeup(void); +static int usb_read_callback(void); +//static void echo_usb(void); + +/***** File Scope Variables *****/ + +/* This EP assignment must match the Configuration Descriptor */ +static const acm_cfg_t acm_cfg = { + 1, /* EP OUT */ + MXC_USBHS_MAX_PACKET, /* OUT max packet size */ + 2, /* EP IN */ + MXC_USBHS_MAX_PACKET, /* IN max packet size */ + 3, /* EP Notify */ + MXC_USBHS_MAX_PACKET, /* Notify max packet size */ +}; + +static volatile int usb_read_complete; + +int usb_startup_cb() +{ + const sys_cfg_usbhs_t sys_usbhs_cfg = NULL; + return SYS_USBHS_Init(&sys_usbhs_cfg); +} + +int usb_shutdown_cb() +{ + return SYS_USBHS_Shutdown(); +} + +/* User-supplied function to delay usec micro-seconds */ +void delay_us(unsigned int usec) +{ + /* mxc_delay() takes unsigned long, so can't use it directly */ + mxc_delay(usec); +} + + +/******************************************************************************/ +void cdcacm_init(void) +{ + maxusb_cfg_options_t usb_opts; + + /* Initialize state */ + configured = 0; + suspended = 0; + event_flags = 0; + remote_wake_en = 0; + + /* Start out in full speed */ + usb_opts.enable_hs = 0; + usb_opts.delay_us = delay_us; /* Function which will be used for delays */ + usb_opts.init_callback = usb_startup_cb; + usb_opts.shutdown_callback = usb_shutdown_cb; + + /* Initialize the usb module */ + if (usb_init(&usb_opts) != 0) { + printf("usb_init() failed\n"); + while (1); + } + + /* Initialize the enumeration module */ + if (enum_init() != 0) { + printf("enum_init() failed\n"); + while (1); + } + + /* Register enumeration data */ + enum_register_descriptor(ENUM_DESC_DEVICE, (uint8_t*)&device_descriptor, 0); + enum_register_descriptor(ENUM_DESC_CONFIG, (uint8_t*)&config_descriptor, 0); + enum_register_descriptor(ENUM_DESC_STRING, lang_id_desc, 0); + enum_register_descriptor(ENUM_DESC_STRING, mfg_id_desc, 1); + enum_register_descriptor(ENUM_DESC_STRING, prod_id_desc, 2); + + /* Handle configuration */ + enum_register_callback(ENUM_SETCONFIG, setconfig_callback, NULL); + + /* Handle feature set/clear */ + enum_register_callback(ENUM_SETFEATURE, setfeature_callback, NULL); + enum_register_callback(ENUM_CLRFEATURE, clrfeature_callback, NULL); + + /* Initialize the class driver */ + if (acm_init(&config_descriptor.comm_interface_descriptor) != 0) { + printf("acm_init() failed\n"); + while (1); + } + + /* Register callbacks */ + usb_event_enable(MAXUSB_EVENT_NOVBUS, event_callback, NULL); + usb_event_enable(MAXUSB_EVENT_VBUS, event_callback, NULL); + acm_register_callback(ACM_CB_READ_READY, usb_read_callback); + usb_read_complete = 0; + + /* Start with USB in low power mode */ + usb_app_sleep(); + NVIC_EnableIRQ(USB_IRQn); +} + +int cdcacm_num_read_avail(void) +{ + return acm_canread(); +} + +uint8_t cdcacm_read(void) +{ + while(acm_canread() <= 0) { + } + + uint8_t buf; + acm_read(&buf, 1); + return buf; +} + +void cdcacm_write(uint8_t *data, int len) +{ + while (acm_present()) { + // TODO: This might fail horribly + if (acm_write(data, len) == len) { + break; + } + } +} + + +/******************************************************************************/ +#if 0 +static void echo_usb(void) +{ + int chars; + uint8_t buffer[BUFFER_SIZE]; + + if ((chars = acm_canread()) > 0) { + + if (chars > BUFFER_SIZE) { + chars = BUFFER_SIZE; + } + + // Read the data from USB + if (acm_read(buffer, chars) != chars) { + printf("acm_read() failed\n"); + return; + } + + // Echo it back + if (acm_present()) { + if (acm_write(buffer, chars) != chars) { + printf("acm_write() failed\n"); + } + } + } +} +#endif +/******************************************************************************/ +static int setconfig_callback(usb_setup_pkt *sud, void *cbdata) +{ + /* Confirm the configuration value */ + if (sud->wValue == config_descriptor.config_descriptor.bConfigurationValue) { + configured = 1; + MXC_SETBIT(&event_flags, EVENT_ENUM_COMP); + return acm_configure(&acm_cfg); /* Configure the device class */ + } else if (sud->wValue == 0) { + configured = 0; + return acm_deconfigure(); + } + + return -1; +} + +/******************************************************************************/ +static int setfeature_callback(usb_setup_pkt *sud, void *cbdata) +{ + if(sud->wValue == FEAT_REMOTE_WAKE) { + remote_wake_en = 1; + } else { + // Unknown callback + return -1; + } + + return 0; +} + +/******************************************************************************/ +static int clrfeature_callback(usb_setup_pkt *sud, void *cbdata) +{ + if(sud->wValue == FEAT_REMOTE_WAKE) { + remote_wake_en = 0; + } else { + // Unknown callback + return -1; + } + + return 0; +} + +/******************************************************************************/ +static void usb_app_sleep(void) +{ + /* TODO: Place low-power code here */ + suspended = 1; +} + +/******************************************************************************/ +static void usb_app_wakeup(void) +{ + /* TODO: Place low-power code here */ + suspended = 0; +} + +/******************************************************************************/ +static int event_callback(maxusb_event_t evt, void *data) +{ + /* Set event flag */ + MXC_SETBIT(&event_flags, evt); + + switch (evt) { + case MAXUSB_EVENT_NOVBUS: + usb_event_disable(MAXUSB_EVENT_BRST); + usb_event_disable(MAXUSB_EVENT_SUSP); + usb_event_disable(MAXUSB_EVENT_DPACT); + usb_disconnect(); + configured = 0; + enum_clearconfig(); + acm_deconfigure(); + usb_app_sleep(); + break; + case MAXUSB_EVENT_VBUS: + usb_event_clear(MAXUSB_EVENT_BRST); + usb_event_enable(MAXUSB_EVENT_BRST, event_callback, NULL); + usb_event_clear(MAXUSB_EVENT_SUSP); + usb_event_enable(MAXUSB_EVENT_SUSP, event_callback, NULL); + usb_connect(); + usb_app_sleep(); + break; + case MAXUSB_EVENT_BRST: + usb_app_wakeup(); + enum_clearconfig(); + acm_deconfigure(); + configured = 0; + suspended = 0; + break; + case MAXUSB_EVENT_SUSP: + usb_app_sleep(); + break; + case MAXUSB_EVENT_DPACT: + usb_app_wakeup(); + break; + default: + break; + } + + return 0; +} + +/******************************************************************************/ +static int usb_read_callback(void) +{ + usb_read_complete = 1; + return 0; +} + +/******************************************************************************/ +void USB_IRQHandler(void) +{ + usb_event_handler(); +} + +/******************************************************************************/ +void SysTick_Handler(void) +{ + mxc_delay_handler(); +} diff --git a/epicardium/cdcacm.h b/epicardium/cdcacm.h new file mode 100644 index 0000000000000000000000000000000000000000..b398f260c8b44e1a47ea8fea10ca0b54c06c17a2 --- /dev/null +++ b/epicardium/cdcacm.h @@ -0,0 +1,9 @@ +#ifndef CDCACM_H +#define CDCACM_H + +void cdcacm_init(void); +int cdcacm_num_read_avail(void); +uint8_t cdcacm_read(void); +void cdcacm_write(uint8_t *data, int len); + +#endif diff --git a/epicardium/descriptors.h b/epicardium/descriptors.h new file mode 100644 index 0000000000000000000000000000000000000000..c081c4010e65c7c86980ad94a096a81febb69f61 --- /dev/null +++ b/epicardium/descriptors.h @@ -0,0 +1,227 @@ +/******************************************************************************* + * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of Maxim Integrated + * Products, Inc. shall not be used except as stated in the Maxim Integrated + * Products, Inc. Branding Policy. + * + * The mere transfer of this software does not imply any licenses + * of trade secrets, proprietary technology, copyrights, patents, + * trademarks, maskwork rights, or any other form of intellectual + * property whatsoever. Maxim Integrated Products, Inc. retains all + * ownership rights. + * + * Description: Communications Device Class ACM (Serial Port) over USB + * $Id: descriptors.h 36682 2018-08-06 21:14:03Z michael.bayern $ + * + ******************************************************************************* + */ + +#ifndef _DESCRIPTORS_H_ +#define _DESCRIPTORS_H_ + +#include <stdint.h> +#include "usb.h" +#include "hid_kbd.h" + +usb_device_descriptor_t __attribute__((aligned(4))) device_descriptor = { + 0x12, /* bLength = 18 */ + 0x01, /* bDescriptorType = Device */ + 0x0110, /* bcdUSB USB spec rev (BCD) */ + 0x02, /* bDeviceClass = comm class (2) */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 is 64 bytes */ + 0x0B6A, /* idVendor (Maxim Integrated) */ + 0x003C, /* idProduct */ + 0x0100, /* bcdDevice */ + 0x01, /* iManufacturer Descriptor ID */ + 0x02, /* iProduct Descriptor ID */ + 0x00, /* iSerialNumber = (0) No string */ + 0x01 /* bNumConfigurations */ +}; + +__attribute__((aligned(4))) +struct __attribute__((packed)) { + usb_configuration_descriptor_t config_descriptor; + usb_interface_descriptor_t comm_interface_descriptor; + uint8_t header_functional_descriptor[5]; + uint8_t call_management_descriptor[5]; + uint8_t acm_functional_descriptor[4]; + uint8_t union_functional_descriptor[5]; + usb_endpoint_descriptor_t endpoint_descriptor_3; + usb_interface_descriptor_t data_interface_descriptor; + usb_endpoint_descriptor_t endpoint_descriptor_1; + usb_endpoint_descriptor_t endpoint_descriptor_2; +} config_descriptor = +{ + { + 0x09, /* bLength = 9 */ + 0x02, /* bDescriptorType = Config (2) */ + 0x0043, /* wTotalLength(L/H) */ + 0x02, /* bNumInterfaces */ + 0x01, /* bConfigValue */ + 0x00, /* iConfiguration */ + 0xE0, /* bmAttributes (self-powered, remote wakeup) */ + 0x01, /* MaxPower is 2ma (units are 2ma/bit) */ + }, + { /* First Interface Descriptor For Comm Class Interface */ + 0x09, /* bLength = 9 */ + 0x04, /* bDescriptorType = Interface (4) */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x01, /* bNumEndpoints (one for OUT) */ + 0x02, /* bInterfaceClass = Communications Interface Class (2) */ + 0x02, /* bInterfaceSubClass = Abstract Control Model (2) */ + 0x01, /* bInterfaceProtocol = Common "AT" commands (1), no class specific protocol (0) */ + 0x00, /* iInterface */ + }, + { /* Header Functional Descriptor */ + 0x05, /* bFunctionalLength = 5 */ + 0x24, /* bDescriptorType */ + 0x00, /* bDescriptorSubtype */ + 0x10, 0x01, /* bcdCDC */ + }, + { /* Call Management Descriptor */ + 0x05, /* bFunctionalLength = 5 */ + 0x24, /* bDescriptorType */ + 0x01, /* bDescriptorSubtype */ + 0x03, /* bmCapabilities = Device handles call management itself (0x01), management over data class (0x02) */ + 0x01, /* bmDataInterface */ + }, + { /* Abstract Control Management Functional Descriptor */ + 0x04, /* bFunctionalLength = 4 */ + 0x24, /* bDescriptorType */ + 0x02, /* bDescriptorSubtype */ + 0x02, /* bmCapabilities */ + }, + { /* Union Functional Descriptor */ + 0x05, /* bFunctionalLength = 5 */ + 0x24, /* bDescriptorType */ + 0x06, /* bDescriptorSubtype */ + 0x00, /* bmMasterInterface */ + 0x01, /* bmSlaveInterface0 */ + }, + { /* IN Endpoint 3 (Descriptor #1) */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType (Endpoint) */ + 0x83, /* bEndpointAddress (EP3-IN) */ + 0x03, /* bmAttributes (interrupt) */ + 0x0040, /* wMaxPacketSize */ + 0xff, /* bInterval (milliseconds) */ + }, + { /* Second Interface Descriptor For Data Interface */ + 0x09, /* bLength */ + 0x04, /* bDescriptorType (Interface) */ + 0x01, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x02, /* bNumEndpoints */ + 0x0a, /* bInterfaceClass = Data Interface (10) */ + 0x00, /* bInterfaceSubClass = none (0) */ + 0x00, /* bInterfaceProtocol = No class specific protocol (0) */ + 0x00, /* biInterface = No Text String (0) */ + }, + { /* OUT Endpoint 1 (Descriptor #2) */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType (Endpoint) */ + 0x01, /* bEndpointAddress (EP1-OUT) */ + 0x02, /* bmAttributes (bulk) */ + 0x0040, /* wMaxPacketSize */ + 0x00, /* bInterval (N/A) */ + }, + { /* IN Endpoint 2 (Descriptor #3) */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType (Endpoint) */ + 0x82, /* bEndpointAddress (EP2-IN) */ + 0x02, /* bmAttributes (bulk) */ + 0x0040, /* wMaxPacketSize */ + 0x00 /* bInterval (N/A) */ + } +}; + +__attribute__((aligned(4))) +uint8_t lang_id_desc[] = { + 0x04, /* bLength */ + 0x03, /* bDescriptorType */ + 0x09, 0x04 /* bString = wLANGID (see usb_20.pdf 9.6.7 String) */ +}; + +__attribute__((aligned(4))) +uint8_t mfg_id_desc[] = { + 0x22, /* bLength */ + 0x03, /* bDescriptorType */ + 'M', 0, + 'a', 0, + 'x', 0, + 'i', 0, + 'm', 0, + ' ', 0, + 'I', 0, + 'n', 0, + 't', 0, + 'e', 0, + 'g', 0, + 'r', 0, + 'a', 0, + 't', 0, + 'e', 0, + 'd', 0, +}; + +__attribute__((aligned(4))) +uint8_t prod_id_desc[] = { + 0x22, /* bLength */ + 0x03, /* bDescriptorType */ + 'M', 0, + 'A', 0, + 'X', 0, + '3', 0, + '2', 0, + '6', 0, + '6', 0, + '5', 0, + ' ', 0, + 'C', 0, + 'D', 0, + 'C', 0, + '-', 0, + 'A', 0, + 'C', 0, + 'M', 0, +}; + +/* Not currently used (see device descriptor), but could be enabled if desired */ +__attribute__((aligned(4))) +uint8_t serial_id_desc[] = { + 0x14, /* bLength */ + 0x03, /* bDescriptorType */ + '0', 0, + '0', 0, + '0', 0, + '0', 0, + '0', 0, + '0', 0, + '0', 0, + '0', 0, + '1', 0 +}; + +#endif /* _DESCRIPTORS_H_ */ diff --git a/epicardium/main.c b/epicardium/main.c index 96656afd7a6a65bde33101a14ae4dffdff650493..a3906b0afbe0da3269a5a7ea0f14c469997b9cdd 100644 --- a/epicardium/main.c +++ b/epicardium/main.c @@ -1,6 +1,7 @@ #include <stdio.h> #include "card10.h" #include "uart.h" +#include "cdcacm.h" #include "api/dispatcher.h" extern mxc_uart_regs_t * ConsoleUart; @@ -8,11 +9,20 @@ extern mxc_uart_regs_t * ConsoleUart; void epic_uart_write_str(char*str, intptr_t length) { UART_Write(ConsoleUart, (uint8_t*)str, length); + cdcacm_write((uint8_t*)str, length); } char epic_uart_read_chr(void) { - return UART_ReadByte(ConsoleUart); + while(1) { + if(UART_NumReadAvail(ConsoleUart) > 0) { + return UART_ReadByte(ConsoleUart); + } + + if(cdcacm_num_read_avail() > 0) { + return cdcacm_read(); + } + } } void epic_leds_set(int led, uint8_t r, uint8_t g, uint8_t b) @@ -26,6 +36,8 @@ int main(void) card10_init(); card10_diag(); + cdcacm_init(); + printf("Initializing dispatcher ...\n"); api_dispatcher_init(); diff --git a/epicardium/meson.build b/epicardium/meson.build index c999871cbaf7a7da65011e40e3332523755ca93c..f84abbe791d3f466268890c7daefd41537d3661a 100644 --- a/epicardium/meson.build +++ b/epicardium/meson.build @@ -48,7 +48,8 @@ api_dispatcher_lib = static_library( elf = executable( name + '.elf', 'main.c', - dependencies: [libcard10, max32665_startup_core0], + 'cdcacm.c', + dependencies: [libcard10, max32665_startup_core0, maxusb], link_with: api_dispatcher_lib, link_whole: [max32665_startup_core0_lib, board_card10_lib], link_args: [