From dcf2c2b808bfc75818ed2ef0487008bdd54fcf65 Mon Sep 17 00:00:00 2001 From: Epagris Date: Thu, 14 Nov 2024 13:19:09 +0100 Subject: [PATCH] - CMake target on generating descriptors from JSON added - basic flatUSB_config.h concept added - example JSONs added - CDC request replies fixed --- CMakeLists.txt | 28 +++- class/cdc.c | 64 ++++++-- class/cdc.h | 25 +-- {desc => desc-gen}/.gitignore | 0 {desc => desc-gen}/ConfigGenerator.py | 97 +++++++++--- {desc => desc-gen}/Descriptor.py | 0 {desc => desc-gen}/StructGenerator.py | 0 {desc => desc-gen}/main.py | 21 ++- desc/usb_desc.c | 149 ------------------ desc/usb_desc.h | 91 ----------- .../stm32/usb_common_defs.h | 20 +-- .../stm32/usb_core_types.h | 0 driver/stm32/usb_drv.c | 134 ++++++++++++++++ driver/stm32/usb_drv.h | 35 ++++ {desc => examples}/usb_config.json | 0 {desc => examples}/usb_config_cdc.json | 0 {desc => examples}/usb_config_eem.json | 0 usb.c | 5 +- usb_common.h | 1 - usb_descriptor_common.h | 8 + usb_driver.c | 13 +- 21 files changed, 371 insertions(+), 320 deletions(-) rename {desc => desc-gen}/.gitignore (100%) rename {desc => desc-gen}/ConfigGenerator.py (72%) rename {desc => desc-gen}/Descriptor.py (100%) rename {desc => desc-gen}/StructGenerator.py (100%) rename {desc => desc-gen}/main.py (74%) delete mode 100644 desc/usb_desc.c delete mode 100644 desc/usb_desc.h rename usb_common_defs.h => driver/stm32/usb_common_defs.h (79%) rename usb_core_types.h => driver/stm32/usb_core_types.h (100%) create mode 100644 driver/stm32/usb_drv.c create mode 100644 driver/stm32/usb_drv.h rename {desc => examples}/usb_config.json (100%) rename {desc => examples}/usb_config_cdc.json (100%) rename {desc => examples}/usb_config_eem.json (100%) create mode 100644 usb_descriptor_common.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6512d07..c9aeb90 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,13 +22,24 @@ if ("CDC_EEM" IN_LIST FLATUSB_CLASSES) ) endif() +if (FLATUSB_DESC_DIR) + AUX_SOURCE_DIRECTORY(${FLATUSB_DESC_DIR} FLATUSB_DESC_SRC) + set(FLATUSB_DESC_HEADER ${FLATUSB_DESC_DIR}/usb_desc.h) + if (FLATUSB_DESC_SRC) + message("flatUSB descriptors: " ${FLATUSB_DESC_SRC}) + else() + message("flatUSB descriptors: (empty)") + endif() +elseif(NOT FLATUSB_DESC_SRC) + message("flatUSB: No source of descriptors passed! Please either set FLATUSB_DESC_DIR to the directory containing the descriptor files OR pass descriptor files directly by defining FLATUSB_DESC_SRC and FLATUSB_DESC_HEADER!") +endif() + message("flatUSB classes selected: ${FLATUSB_CLASSES}") set(FLATUSB_SRC ${FLATUSB_CLASSES_SRC} + ${FLATUSB_DESC_SRC} - desc/usb_desc.c - desc/usb_desc.h usb.c usb_callback_event.h usb_common_defs.h @@ -45,6 +56,17 @@ set(FLATUSB_SRC ) add_library(${FLATUSB_TARGET} STATIC ${FLATUSB_SRC}) -target_include_directories(${FLATUSB_TARGET} PRIVATE ${FLATUSB_INCLUDES}) +target_include_directories(${FLATUSB_TARGET} PRIVATE ${FLATUSB_INCLUDES} ${CMAKE_CURRENT_LIST_DIR}) target_compile_options(${FLATUSB_TARGET} PRIVATE ${FLATUSB_CPU_PARAMS}) target_compile_definitions(${FLATUSB_TARGET} PRIVATE ${FLATUSB_COMPILE_DEFS}) +target_compile_definitions(${FLATUSB_TARGET} PRIVATE FLATUSB_DESCRIPTOR_HEADER="${FLATUSB_DESC_HEADER}") + +if (FLATUSB_DESC_JSON AND FLATUSB_DESC_DIR) + message("flatUSB: descriptor JSON passed: " ${FLATUSB_DESC_JSON}) + message("flatUSB: also defining flatUSB-gen-desc target") + add_custom_target( + flatUSB-gen-desc + COMMAND python3 ${CMAKE_CURRENT_LIST_DIR}/desc-gen/main.py ${FLATUSB_DESC_JSON} ${FLATUSB_DESC_DIR} + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + ) +endif() diff --git a/class/cdc.c b/class/cdc.c index 11f5513..7f7e04e 100644 --- a/class/cdc.c +++ b/class/cdc.c @@ -5,10 +5,12 @@ #include "../usb_device_types.h" #include "../usb.h" +#include "flatUSB/usb_driver.h" #include #include +#include // state static USB_CdcState cdcs = {0}; @@ -25,12 +27,15 @@ void usb_cdc_init(const USB_CdcAssignments *as) { // clear the structure memset(&cdcs, 0, sizeof(USB_CdcState)); + // set Control Line State to something invalid + cdcs.control_line_state.D = USB_CDC_INVALID_CONTROL_LINE_STATE; + // fill-in default values - USB_Cdc_LineCodingStruct *lc = &cdcs.line_coding; - lc->dwDTERate = USB_CDC_DEFAULT_BITRATE; - lc->bCharFormat = USB_CDC_DEFAULT_CHAR_FORMAT; - lc->bParityType = USB_CDC_DEFAULT_PARITY_TYPE; - lc->bDataBits = USB_CDC_DEFAULT_DATA_BITS; + // USB_Cdc_LineCodingStruct *lc = &cdcs.line_coding; + // lc->dwDTERate = USB_CDC_DEFAULT_BITRATE; + // lc->bCharFormat = USB_CDC_DEFAULT_CHAR_FORMAT; + // lc->bParityType = USB_CDC_DEFAULT_PARITY_TYPE; + // lc->bDataBits = USB_CDC_DEFAULT_DATA_BITS; // fill-in assigments cdcs.ep_assignments = *as; @@ -42,38 +47,65 @@ void usb_cdc_init(const USB_CdcAssignments *as) { cdcs.interrupt_data = 0; cdcs.interrupt_pending = true; - // from now on CDC is considered initialized - cdcs.initialized = true; + // communication parameters have not been set + cdcs.commInit = false; + + // from now on CDC module is considered initialized + cdcs.moduleInit = true; } // static uint8_t replyBuf[sizeof(USB_Cdc_LineCodingStruct)]; +static void usb_cdc_review_comm_init() { + // check if line coding was initialized + USB_Cdc_LineCodingStruct *lc = &cdcs.line_coding; + bool lcOk = (lc->dwDTERate != 0) && (lc->bDataBits != 0); + + // check if control line state was initialized + bool clsOk = cdcs.control_line_state.D != USB_CDC_INVALID_CONTROL_LINE_STATE; + + // combine the above criteria + cdcs.commInit = lcOk && clsOk; + + // wake up endpoint if initialized + if (cdcs.commInit) { + usbcore_wake_up_endpoint(cdcs.ep_assignments.data_ep, USB_IN); + } +} + int usb_cdc_process_and_return(USB_CallbackEvent *cbevt) { int ret = -1; switch (cbevt->type) { case USB_CBEVT_UNKNOWN_REQ: { + // initialize reply + cbevt->reply_data = NULL; + cbevt->reply_size = 0; + cbevt->reply_valid = true; + switch (cbevt->setup_request->bRequest) { case USB_CDC_SET_LINE_CODING: // set line coding memcpy(&cdcs.line_coding, cbevt->data, sizeof(USB_Cdc_LineCodingStruct)); + usb_cdc_review_comm_init(); // review the communcation initialization state // MSG("%u\n", cdcs.line_coding.dwDTERate); ret = 0; break; case USB_CDC_GET_LINE_CODING: // get line coding cbevt->reply_data = (const uint8_t *)&cdcs.line_coding; // expert move: pass the pointer, no copying cbevt->reply_size = sizeof(USB_Cdc_LineCodingStruct); - cbevt->reply_valid = true; // the reply has been set to something valid ret = 0; break; case USB_CDC_SEND_BREAK: // send break // do nothing ret = 0; break; - case USB_CDC_SET_CONTROL_LINE_STATE: // set control line state - memcpy(&cdcs.control_line_state, cbevt->data, sizeof(USB_Cdc_ControlLineStateStruct)); + case USB_CDC_SET_CONTROL_LINE_STATE: // set control line state + cdcs.control_line_state.D = cbevt->setup_request->wValue; // control line state is carried in wValue of the SETUP request + usb_cdc_review_comm_init(); // review the communcation initialization state // MSG("%u\n", cdcs.control_line_state.D); ret = 0; break; default: + cbevt->reply_valid = false; // this event is not processed by or not related to the CDC ACM module break; } @@ -110,10 +142,12 @@ int usb_cdc_process_and_return(USB_CallbackEvent *cbevt) { ret = 0; // read from the fifo - uint32_t readSize = bfifo_read(&fifo, tx_buffer, USB_CDC_PCKT_BUFSIZE); - if (readSize > 0) { - uint32_t writeSize = usbcore_schedule_transmission(cdcs.ep_assignments.data_ep, tx_buffer, readSize); // write data acquired from the buffer - bfifo_pop(&fifo, writeSize, 0); // pop with no blocking + if (cdcs.commInit) { + uint32_t readSize = bfifo_read(&fifo, tx_buffer, USB_CDC_PCKT_BUFSIZE); + if (readSize > 0) { + uint32_t writeSize = usbcore_schedule_transmission(cdcs.ep_assignments.data_ep, tx_buffer, readSize); // write data acquired from the buffer + bfifo_pop(&fifo, writeSize, 0); // pop with no blocking + } } } } @@ -130,7 +164,7 @@ int usb_cdc_process_and_return(USB_CallbackEvent *cbevt) { // } void usb_cdc_write(const uint8_t *data, uint32_t size) { - if (cdcs.initialized) { + if (cdcs.moduleInit) { bfifo_push_all(&fifo, data, size); usbcore_wake_up_endpoint(cdcs.ep_assignments.data_ep, USB_IN); } diff --git a/class/cdc.h b/class/cdc.h index 4abbb28..59e25b9 100644 --- a/class/cdc.h +++ b/class/cdc.h @@ -27,10 +27,10 @@ typedef enum { // CDC line coding structure typedef struct { - uint32_t dwDTERate; // data terminal rate, bits per second + uint32_t dwDTERate; // data terminal rate, bits per second uint8_t bCharFormat; // character format uint8_t bParityType; // parity type - uint8_t bDataBits; // data bits + uint8_t bDataBits; // data bits } USB_Cdc_LineCodingStruct; // CDC control line state struct @@ -43,20 +43,23 @@ typedef struct { // endpoint assignments typedef struct { uint8_t control_ep : 4; // control endpoint - uint8_t data_ep : 4; // data endpoint + uint8_t data_ep : 4; // data endpoint } USB_CdcAssignments; typedef struct { - USB_CdcAssignments ep_assignments; // endpoint assignments - USB_Cdc_LineCodingStruct line_coding; // line coding + USB_CdcAssignments ep_assignments; // endpoint assignments + USB_Cdc_LineCodingStruct line_coding; // line coding USB_Cdc_ControlLineStateStruct control_line_state; // control line state - uint16_t interrupt_data; // data sent though the next transfer on the notification element - bool interrupt_pending; // interrupt data is valid and should be send in the next cycle - bool initialized; // CDC is initialized + uint16_t interrupt_data; // data sent though the next transfer on the notification element + bool interrupt_pending; // interrupt data is valid and should be send in the next cycle + bool moduleInit; // CDC module is initialized + bool commInit; // communication is initialized } USB_CdcState; // ---------------- +#define USB_CDC_INVALID_CONTROL_LINE_STATE (0xFFFF) + #define USB_CDC_DEFAULT_BITRATE (115200) #define USB_CDC_DEFAULT_DATA_BITS (8) #define USB_CDC_DEFAULT_PARITY_TYPE (0) @@ -68,8 +71,8 @@ typedef struct { // ---------------- -void usb_cdc_init(const USB_CdcAssignments * as); -int usb_cdc_process_and_return(USB_CallbackEvent * cbevt); -void usb_cdc_write(const uint8_t * data, uint32_t size); +void usb_cdc_init(const USB_CdcAssignments *as); +int usb_cdc_process_and_return(USB_CallbackEvent *cbevt); +void usb_cdc_write(const uint8_t *data, uint32_t size); #endif /* CORE_USB_CLASS_CDC */ diff --git a/desc/.gitignore b/desc-gen/.gitignore similarity index 100% rename from desc/.gitignore rename to desc-gen/.gitignore diff --git a/desc/ConfigGenerator.py b/desc-gen/ConfigGenerator.py similarity index 72% rename from desc/ConfigGenerator.py rename to desc-gen/ConfigGenerator.py index ef9bad2..630f1be 100644 --- a/desc/ConfigGenerator.py +++ b/desc-gen/ConfigGenerator.py @@ -1,4 +1,5 @@ import subprocess +import datetime import Descriptor import Descriptor as desc @@ -74,12 +75,16 @@ class ConfigGenerator: # "serial_number" # ] - #self.str_mgr.add_placeholders(string_fields) + # self.str_mgr.add_placeholders(string_fields) self.LANG_ID_US_EN = "0x0409" - self.max_config_str_desc_size = 0 # maximal size (wLength) of config descriptors - self.max_endpoint_index = 0 # maximum endpoint index used in at least one of the configurations + self.max_config_str_desc_size = ( + 0 # maximal size (wLength) of config descriptors + ) + self.max_endpoint_index = ( + 0 # maximum endpoint index used in at least one of the configurations + ) self.max_endpoint_count = 0 # maximum endpoint count across all configurations # add macro to header file @@ -94,23 +99,36 @@ class ConfigGenerator: self.h += "\n" # save generated config - def save(self): + def save(self, target_dir): DECLARATIONS = "usb_desc.h" DEFINITIONS = "usb_desc.c" - with open(DEFINITIONS, 'w') as f_c: - f_c.write("#include \"" + DECLARATIONS + "\"\n\n") + DECLARATIONS_FULLPATH = target_dir + "/" + DECLARATIONS + DEFINITIONS_FULLPATH = target_dir + "/" + DEFINITIONS + + INFO_HEADER = "//------------\n// Descriptors generated by flatUSB Descriptor Generator by Epagris on " + (str)(datetime.date.today()) + ".\n//------------\n\n" + + with open(DEFINITIONS_FULLPATH, "w") as f_c: + f_c.write(INFO_HEADER) + f_c.write('#include "' + DECLARATIONS + '"\n\n') f_c.write(self.c) include_guard_tag = "_" + DECLARATIONS.replace(".", "_").upper() - with open(DECLARATIONS, 'w') as f_h: - f_h.writelines(("#ifndef " + include_guard_tag + "\n", "#define " + include_guard_tag + "\n\n", "#include \"../usb_device_types.h\"\n\n")) + with open(DECLARATIONS_FULLPATH, "w") as f_h: + f_h.writelines( + ( + INFO_HEADER, + "#ifndef " + include_guard_tag + "\n", + "#define " + include_guard_tag + "\n\n", + '#include "usb_descriptor_common.h"\n\n', + ) + ) f_h.write(self.h) f_h.writelines(("\n\n#endif // " + include_guard_tag)) - subprocess.run(["indent", "-linux", "-l120", "-i4", "-nut", DECLARATIONS]) - subprocess.run(["indent", "-linux", "-l120", "-i4", "-nut", DEFINITIONS]) + subprocess.run(["indent", "-linux", "-l120", "-i4", "-nut", DECLARATIONS_FULLPATH]) + subprocess.run(["indent", "-linux", "-l120", "-i4", "-nut", DEFINITIONS_FULLPATH]) # generate Device descriptor def generate_device_descriptor(self): @@ -152,35 +170,49 @@ class ConfigGenerator: # generate interface descriptor intf_varname = "intf{:d}".format(intf["id"]) ep_count = get_distinct_endpoint_count(intf["endpoints"]) - intf_struct = desc.InterfaceDescriptor(intf_varname, intf) # endpoint count is unknown + intf_struct = desc.InterfaceDescriptor( + intf_varname, intf + ) # endpoint count is unknown full_conf_struct.add_record(intf_struct) # generate additional interface descriptors for addintf in intf["additional_interfaces"]: type = addintf["type"] - addintf_struct = desc.DescriptorFactory.generate(type, intf_varname + type, addintf, self.str_mgr) + addintf_struct = desc.DescriptorFactory.generate( + type, intf_varname + type, addintf, self.str_mgr + ) full_conf_struct.add_record(addintf_struct) # generate typedef only, if not done before if addintf_tdefs.count(type) == 0: self.h += addintf_struct.print_typedef() # print typedef - addintf_tdefs.append(type) # add to already generated typedefs to avoid duplication + addintf_tdefs.append( + type + ) # add to already generated typedefs to avoid duplication # generate endpoint descriptors - self.generate_endpoint_descriptors(intf, full_conf_struct) # generate endpoints + self.generate_endpoint_descriptors( + intf, full_conf_struct + ) # generate endpoints # generate configuration descriptors and subordinate descriptor def generate_configuration_descriptors(self): # array for referencing configuration descriptors - conf_desc_array_struct = desc.Descriptor("confDescs", "USB_ConfigurationDesc *", []) + conf_desc_array_struct = desc.Descriptor( + "confDescs", "USB_ConfigurationDesc *", [] + ) conf_desc_array_struct.typedef = "ConfDescs" # generate full configurations index = 0 for conf in self.config["configurations"]: full_conf_typename = "struct _FullConfigurations{:d}".format(index) - full_conf_struct = Descriptor.Descriptor("fullConfDescs{:d}".format(index), full_conf_typename, []) - conf_struct = desc.ConfigurationDescriptor("config", conf, "sizeof({:s})".format(full_conf_typename)) # TODO: total length + full_conf_struct = Descriptor.Descriptor( + "fullConfDescs{:d}".format(index), full_conf_typename, [] + ) + conf_struct = desc.ConfigurationDescriptor( + "config", conf, "sizeof({:s})".format(full_conf_typename) + ) # TODO: total length full_conf_struct.add_record(conf_struct) self.generate_interface_descriptors(conf, full_conf_struct) @@ -188,7 +220,12 @@ class ConfigGenerator: self.h += full_conf_struct.gen_h(print_typedef=True) # add descriptor's pointer to the list - str_desc_ptr = StructGenerator.DummyRecord(full_conf_struct.name, "USB_ConfigurationDesc *", "(USB_ConfigurationDesc *) &" + full_conf_struct.name, StructGenerator.RecordFactory.PLAIN_PRINTER) + str_desc_ptr = StructGenerator.DummyRecord( + full_conf_struct.name, + "USB_ConfigurationDesc *", + "(USB_ConfigurationDesc *) &" + full_conf_struct.name, + StructGenerator.RecordFactory.PLAIN_PRINTER, + ) conf_desc_array_struct.add_record(str_desc_ptr) self.h += self.DIVIDER @@ -212,7 +249,12 @@ class ConfigGenerator: self.c += lang_id_struct.gen_c() self.h += lang_id_struct.gen_h(print_typedef=True) - str_desc_ptr = StructGenerator.DummyRecord(lang_id_struct.name, "USB_StringDesc *", "(USB_StringDesc *) &" + lang_id_struct.name, StructGenerator.RecordFactory.PLAIN_PRINTER) + str_desc_ptr = StructGenerator.DummyRecord( + lang_id_struct.name, + "USB_StringDesc *", + "(USB_StringDesc *) &" + lang_id_struct.name, + StructGenerator.RecordFactory.PLAIN_PRINTER, + ) str_desc_array_struct.add_record(str_desc_ptr) # generate individual string descriptors @@ -226,7 +268,12 @@ class ConfigGenerator: self.h += str_struct.gen_h(print_typedef=True) # add descriptor's pointer to the list - str_desc_ptr = StructGenerator.DummyRecord(text_id, "USB_StringDesc *", "(USB_StringDesc *) &" + str_struct.name, StructGenerator.RecordFactory.PLAIN_PRINTER) + str_desc_ptr = StructGenerator.DummyRecord( + text_id, + "USB_StringDesc *", + "(USB_StringDesc *) &" + str_struct.name, + StructGenerator.RecordFactory.PLAIN_PRINTER, + ) str_desc_array_struct.add_record(str_desc_ptr) self.h += self.DIVIDER @@ -237,10 +284,14 @@ class ConfigGenerator: self.c += str_desc_array_struct.gen_c() def generate_macros(self): - self.add_def_macro("USBF_NOF_CONFIGURATIONS", str(len(self.config["configurations"])), "Number of configurations") + self.add_def_macro( + "USBF_NOF_CONFIGURATIONS", + str(len(self.config["configurations"])), + "Number of configurations", + ) self.h += self.DIVIDER - def generate(self): + def generate(self, target_dir: str): self.generate_macros() # generate macro definitions self.generate_device_descriptor() # generate device descriptor self.generate_device_qualifier_descriptor() # generate device qualifier descriptor @@ -248,4 +299,4 @@ class ConfigGenerator: self.generate_string_descriptors() # generate string descriptors (should be the last one, since additional interface descriptors may add new string descriptors) # save generated files - self.save() + self.save(target_dir) diff --git a/desc/Descriptor.py b/desc-gen/Descriptor.py similarity index 100% rename from desc/Descriptor.py rename to desc-gen/Descriptor.py diff --git a/desc/StructGenerator.py b/desc-gen/StructGenerator.py similarity index 100% rename from desc/StructGenerator.py rename to desc-gen/StructGenerator.py diff --git a/desc/main.py b/desc-gen/main.py similarity index 74% rename from desc/main.py rename to desc-gen/main.py index 8498b2a..930426b 100644 --- a/desc/main.py +++ b/desc-gen/main.py @@ -8,8 +8,22 @@ from itertools import chain from ConfigGenerator import ConfigGenerator +# print welcome message +print("----\nflatUSB descriptor generator by Epagris\n----\n") + +# check number of parameters +if len(argv) < 3: + print("Insufficient parameters!\nCorrect usage: `main.py `\nExiting.") + exit(0) + # fetch USB settings usb_config_file_name = argv[1] +usb_target_dir = argv[2] + +# print input and output parameters +print("Input JSON: ", usb_config_file_name) +print("Target directory: ", usb_target_dir) + #usb_config_file_name = "/home/epagris/VCSDEV/usbt1/stws/USB-T1/Modules/flatUSB/desc/usb_config_cdc.json" with open(usb_config_file_name, 'r') as usb_config_file: usb_config_data = usb_config_file.read() @@ -26,7 +40,7 @@ if "misc" in usb_config: # generate config cfggen = ConfigGenerator(usb_config) -cfggen.generate() +cfggen.generate(usb_target_dir) # devDesc = desc.DeviceDescriptor(usb_config) # print(devDesc.print_assigment()) @@ -50,4 +64,7 @@ cfggen.generate() # print(struct2.print_typedef("struct2")) # # structrec = sg.StructRecord("object", "struct compound", [ struct1, struct2, *recs ]) -# print(structrec.print_content()) \ No newline at end of file +# print(structrec.print_content()) + +# print complete message +print("Descriptor generation complete!") \ No newline at end of file diff --git a/desc/usb_desc.c b/desc/usb_desc.c deleted file mode 100644 index 044e018..0000000 --- a/desc/usb_desc.c +++ /dev/null @@ -1,149 +0,0 @@ -#include "usb_desc.h" - -const USB_DeviceDesc devDesc = { /* Device Descriptor */ - 0x12, //bLength - UD_Device, //bDescriptorType - 0x200, //bcdUSB - 0x2, //bDeviceClass - 0x0, //bDeviceSubclass - 0x0, //bDeviceProtocol - 0x40, //bMaxPacketSize0 - 0x925, //idVendor - 0x9050, //idProduct - 0x100, //bcdDevice - 0x1, //iManufacturer - 0x2, //iProduct - 0x3, //iSerialNumber - 0x1, //bNumConfigurations -}; - -const USB_DeviceQualifierDesc devQualDesc = { /* Device Qualifier descriptor */ - 0x9, //bLength - UD_DeviceQualifier, //bDescriptorType - 0x200, //bcdUSB - 0x2, //bDeviceClass - 0x0, //bDeviceSubclass - 0x0, //bDeviceProtocol - 0x40, //bMaxPacketSize - 0x1, //bNumConfigurations -}; - -const FullConfigurations0 fullConfDescs0 = { - { /* Configuration descriptor */ - 0x9, //bLength - UD_Configuration, //bDescriptorType - sizeof(struct _FullConfigurations0), //wTotalLength - 0x2, //bNumInterfaces - 0x1, //bConfigurationValue - 0x0, //iConfiguration - USB_CONFIG_ATTR_USB1_1_FLAG, //bmAttributes - 0x32, //bMaxPower - }, //config - { /* Interface descriptor : 0 */ - 0x9, //bLength - UD_Interface, //bDescriptorType - 0x0, //bInterfaceNumber - 0x0, //bAlternateSetting - 0x1, //bNumEndpoints - 0x2, //bInterfaceClass - 0x2, //bInterfaceSubclass - 0x1, //bInterfaceProtocol - 0x0, //iInterface - }, //intf0 - { /* Header Functional descriptor */ - 0x5, //bLength - 0x24, //bDescriptorType - 0x0, //bDescriptorSubType - 0x110, //bcdCDC - }, //intf0hfd - { /* Abstract Control Management Functional descriptor */ - 0x4, //bLength - 0x24, //bDescriptorType - 0x2, //bDescriptorSubType - 0x2, //bmCapabilities - }, //intf0acmfd - { /* Union Functional descriptor */ - 0x5, //bLength - 0x24, //bDescriptorType - 0x6, //bDescriptorSubType - 0x0, //bMasterInterface - 0x1, //bSlaveInterface0 - }, //intf0ufd - { /* Call Management Functional descriptor */ - 0x5, //bLength - 0x24, //bDescriptorType - 0x1, //bDescriptorSubType - 0x0, //bmCapabilities - 0x1, //dDataInterface - }, //intf0cmfd - { /* Endpoint descriptor : 2 in */ - 0x7, //bLength - UD_Endpoint, //bDescriptorType - (USB_IN << 7) | (2), //bEndpointAddress - UT_Interrupt, //bmAttributes - 0x40, //wMaxPacketSize - 0x2, //bInterval - }, //ep2in - { /* Interface descriptor : 1 */ - 0x9, //bLength - UD_Interface, //bDescriptorType - 0x1, //bInterfaceNumber - 0x0, //bAlternateSetting - 0x2, //bNumEndpoints - 0xa, //bInterfaceClass - 0x0, //bInterfaceSubclass - 0x0, //bInterfaceProtocol - 0x0, //iInterface - }, //intf1 - { /* Endpoint descriptor : 1 in */ - 0x7, //bLength - UD_Endpoint, //bDescriptorType - (USB_IN << 7) | (1), //bEndpointAddress - UT_Bulk, //bmAttributes - 0x40, //wMaxPacketSize - 0x0, //bInterval - }, //ep1in - { /* Endpoint descriptor : 1 out */ - 0x7, //bLength - UD_Endpoint, //bDescriptorType - (USB_OUT << 7) | (1), //bEndpointAddress - UT_Bulk, //bmAttributes - 0x40, //wMaxPacketSize - 0x0, //bInterval - }, //ep1out -}; - -const ConfDescs confDescs = { - (USB_ConfigurationDesc *) & fullConfDescs0, //fullConfDescs0 -}; - -const USB_StrDesc_lang_id lang_id = { /* String descriptor */ - 0x4, //bLength - UD_String, //bDescriptorType - 0x409, //bString -}; - -const USB_StrDesc_vendor_string vendor_string = { /* String descriptor */ - 0x10, //bLength - UD_String, //bDescriptorType - {'E', 'p', 'a', 'g', 'r', 'i', 's',}, //bString -}; - -const USB_StrDesc_product_string product_string = { /* String descriptor */ - 0x16, //bLength - UD_String, //bDescriptorType - {'T', 'e', 's', 't', 'd', 'e', 'v', 'i', 'c', 'e',}, //bString -}; - -const USB_StrDesc_serial_number serial_number = { /* String descriptor */ - 0xa, //bLength - UD_String, //bDescriptorType - {'1', '5', '5', '2',}, //bString -}; - -const StringDescs strDescs = { - (USB_StringDesc *) & lang_id, //lang_id - (USB_StringDesc *) & vendor_string, //vendor_string - (USB_StringDesc *) & product_string, //product_string - (USB_StringDesc *) & serial_number, //serial_number -}; diff --git a/desc/usb_desc.h b/desc/usb_desc.h deleted file mode 100644 index 668b07b..0000000 --- a/desc/usb_desc.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef _USB_DESC_H -#define _USB_DESC_H - -#include "../usb_device_types.h" - -#define USBF_NOF_CONFIGURATIONS (1) // Number of configurations - -// --------------------------- - -extern const USB_DeviceDesc devDesc; /* Device Descriptor */ -extern const USB_DeviceQualifierDesc devQualDesc; /* Device Qualifier descriptor */ -typedef struct _USB_HeaderFunctionalDescriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint16_t bcdCDC; -} __attribute__((packed)) USB_HeaderFunctionalDescriptor; -typedef struct _USB_AbstractControlManagementFunctionalDescriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bmCapabilities; -} __attribute__((packed)) USB_AbstractControlManagementFunctionalDescriptor; -typedef struct _USB_UnionFunctionalDescriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bMasterInterface; - uint8_t bSlaveInterface0; -} __attribute__((packed)) USB_UnionFunctionalDescriptor; -typedef struct _USB_CallManagementFunctionalDescriptor { - uint8_t bLength; - uint8_t bDescriptorType; - uint8_t bDescriptorSubType; - uint8_t bmCapabilities; - uint8_t dDataInterface; -} __attribute__((packed)) USB_CallManagementFunctionalDescriptor; -typedef struct _FullConfigurations0 { - USB_ConfigurationDesc config; /* Configuration descriptor */ - USB_InterfaceDesc intf0; /* Interface descriptor : 0 */ - USB_HeaderFunctionalDescriptor intf0hfd; /* Header Functional descriptor */ - USB_AbstractControlManagementFunctionalDescriptor intf0acmfd; /* Abstract Control Management Functional descriptor */ - USB_UnionFunctionalDescriptor intf0ufd; /* Union Functional descriptor */ - USB_CallManagementFunctionalDescriptor intf0cmfd; /* Call Management Functional descriptor */ - USB_EndpointDesc ep2in; /* Endpoint descriptor : 2 in */ - USB_InterfaceDesc intf1; /* Interface descriptor : 1 */ - USB_EndpointDesc ep1in; /* Endpoint descriptor : 1 in */ - USB_EndpointDesc ep1out; /* Endpoint descriptor : 1 out */ -} __attribute__((packed)) FullConfigurations0; - -extern const FullConfigurations0 fullConfDescs0; - -// --------------------------- - -typedef USB_ConfigurationDesc *ConfDescs[1]; -extern const ConfDescs confDescs; -typedef struct _USB_StrDesc_lang_id { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t bString; -} __attribute__((packed)) USB_StrDesc_lang_id; - -extern const USB_StrDesc_lang_id lang_id; /* String descriptor */ -typedef struct _USB_StrDesc_vendor_string { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t bString[7]; -} __attribute__((packed)) USB_StrDesc_vendor_string; - -extern const USB_StrDesc_vendor_string vendor_string; /* String descriptor */ -typedef struct _USB_StrDesc_product_string { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t bString[10]; -} __attribute__((packed)) USB_StrDesc_product_string; - -extern const USB_StrDesc_product_string product_string; /* String descriptor */ -typedef struct _USB_StrDesc_serial_number { - uint8_t bLength; - uint8_t bDescriptorType; - uint16_t bString[4]; -} __attribute__((packed)) USB_StrDesc_serial_number; - -extern const USB_StrDesc_serial_number serial_number; /* String descriptor */ - -// --------------------------- - -typedef USB_StringDesc *StringDescs[4]; -extern const StringDescs strDescs; - -#endif // _USB_DESC_H diff --git a/usb_common_defs.h b/driver/stm32/usb_common_defs.h similarity index 79% rename from usb_common_defs.h rename to driver/stm32/usb_common_defs.h index 784ebd7..ff5381e 100644 --- a/usb_common_defs.h +++ b/driver/stm32/usb_common_defs.h @@ -1,28 +1,22 @@ #ifndef CORE_USB_USB_COMMON_DEFS #define CORE_USB_USB_COMMON_DEFS +#include + +// Select appropriate headers #if defined(STM32H745xx) || defined(STM32H743xx) || defined(STM32H723xx) #include #include -#if defined(STM32H745xx) || defined(STM32H743xx) -#define USBG (USB_OTG_FS) -#elif defined(STM32H723xx) -#define USBG (USB_OTG_HS) -#endif - #define USB_STM32H7 + +// ------------ + #elif defined(STM32F407xx) || defined(STM32F401xC) #include #include + #define USB_STM32F4 - -#ifdef USB_HIGH_SPEED -#define USBG (USB_OTG_HS) -#else -#define USBG (USB_OTG_FS) -#endif - #endif #define USBD ((USB_OTG_DeviceTypeDef *) (((uint32_t)(USBG)) + ((uint32_t)(USB_OTG_DEVICE_BASE)))) diff --git a/usb_core_types.h b/driver/stm32/usb_core_types.h similarity index 100% rename from usb_core_types.h rename to driver/stm32/usb_core_types.h diff --git a/driver/stm32/usb_drv.c b/driver/stm32/usb_drv.c new file mode 100644 index 0000000..09ff91a --- /dev/null +++ b/driver/stm32/usb_drv.c @@ -0,0 +1,134 @@ +#include "usb_drv.h" + +#include "flatUSB_config.h" + +#include "stm32f4xx_hal.h" + +#include "usb_common.h" +#include "usb_common_defs.h" + +// ------------------------ + +#ifdef USB_HIGH_SPEED +__weak void usbdrv_ulpi_init() { + return; +} +#endif + +// ------------------------ + +// initialize USB peripheral +void usbdrv_periph_init() { + USB_CLOCK_ENABLE(); + + // HAL_Delay(1000); + + //__HAL_RCC_USB_OTG_FS_ULPI_CLK_ENABLE(); + //__HAL_RCC_USB_OTG_FS_FORCE_RESET(); + //__HAL_RCC_USB_OTG_FS_RELEASE_RESET(); + +#if defined(USB_STM32H7) + SET_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_PHYSEL); // select the internal FS PHY + + WAIT_FOR_nBIT_DELAY(USBG->GRSTCTL, USB_OTG_GRSTCTL_AHBIDL, 1); + + SET_BIT(USBG->GRSTCTL, USB_OTG_GRSTCTL_CSRST); // reset the USB core + HAL_Delay(1); + WAIT_FOR_BIT_DELAY(USBG->GRSTCTL, USB_OTG_GRSTCTL_CSRST, 1); +#else + +#if defined(USB_HIGH_SPEED) + CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_PHYSEL); // select the external HS PHY + CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_TSDPS); + CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_ULPIFSLS); + + CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_ULPIEVBUSD); + CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_ULPIEVBUSI); + // SET_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_PHYSEL); + + SET_BIT(USBG->GRSTCTL, USB_OTG_GRSTCTL_CSRST); // reset USB core + HAL_Delay(1); + WAIT_FOR_BIT(USBG->GRSTCTL, USB_OTG_GRSTCTL_CSRST); + + usbdrv_ulpi_init(); // initialize PHY +#endif + +#endif + CLEAR_BIT(USBG->GCCFG, USB_OTG_GCCFG_PWRDWN); // power the internal transceiver peripheral + + CLEAR_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT); // mask all interrupts for now + CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_HNPCAP | USB_OTG_GUSBCFG_SRPCAP); // disable HNP and SRP + WRITE_FIELD(USBG->GUSBCFG, USB_OTG_GUSBCFG_TRDT, TRDT_VALUE); // set TRDT according to the RM + // WRITE_FIELD(USBG->GUSBCFG, USB_OTG_GUSBCFG_TOCAL, TOCAL_VALUE); // set TOCAL + CLEAR_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_FHMOD); // clear Host mode forcing + SET_BIT(USBG->GUSBCFG, USB_OTG_GUSBCFG_FDMOD); // force Device mode + + HAL_Delay(25); // wait for Device mode forcing propagation + WAIT_FOR_BIT(USBG->GINTSTS, 0b1); + + // SET_BIT(USBD->DCTL, USB_OTG_DCTL_SDIS); // soft disconnect peripheral (should be upper, but since it's controlled by a Device register, cannot be set before switching to device mode) + +#if defined(USB_STM32H7) + CLEAR_BIT(USBG->GCCFG, USB_OTG_GCCFG_VBDEN); // turn off VBUSSENSE + SET_BIT(USBG->GOTGCTL, USB_OTG_GOTGCTL_BVALOEN | USB_OTG_GOTGCTL_BVALOVAL); // force B-session +#elif defined(USB_STM32F4) + SET_BIT(USBG->GCCFG, USB_OTG_GCCFG_NOVBUSSENS); // turn off VBUSSENSE + CLEAR_BIT(USBG->GCCFG, USB_OTG_GCCFG_VBUSBSEN | USB_OTG_GCCFG_VBUSASEN); +#endif + + // HAL_Delay(50); // it takes time to forcing Device mode takes effect + +#ifdef USB_HIGH_SPEED + // WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_FULL_SPEED); + // WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_HIGH_SPEED_ULPI); + WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_FULL_SPEED_ULPI); +#else + WRITE_FIELD(USBD->DCFG, USB_OTG_DCFG_DSPD, USB_LINESPEED_FULL_SPEED); // there's no other possible option +#endif + + // allow specific interrupts + uint32_t intmask = /*USB_OTG_GINTMSK_WUIM | // Wake up */ + USB_OTG_GINTMSK_OEPINT | // OUT EP events + USB_OTG_GINTMSK_IEPINT | // IN EP events + USB_OTG_GINTMSK_ENUMDNEM | // (Linespeed) Enumeration (negotiation) done + USB_OTG_GINTMSK_USBRST | // USB Reset + USB_OTG_GINTMSK_USBSUSPM | // USB Suspend + USB_OTG_GINTMSK_RXFLVLM; // RX FIFO level (signal if non-empty) + USBG->GINTMSK = intmask; + + // set global NAK on all Endpoints + // usbdrv_set_global_NAK(USB_IN, true); + // usbdrv_set_global_NAK(USB_OUT, true); + + // flush Tx and Rx FIFOs + usbdrv_flush_rx_fifo(); + usbdrv_flush_tx_fifo(USB_FLUSH_TX_FIFO_ALL); + + // make Tx FIFO empty interrupt fire when Tx FIFO is emtpy + // SET_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_TXFELVL); + + // set masks for endpoint interrupts + SET_BIT(USBD->DIEPMSK, USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_ITTXFEMSK); // transfer complete, timeout and Tx FIFO empty while receiving IN for IN EPs + SET_BIT(USBD->DOEPMSK, USB_OTG_DOEPMSK_XFRCM | USB_OTG_DOEPMSK_STUPM); // transfer complete and SETUP complete for OUT EPs + + // mask all endpoint interrupts in both directions and also clear flags + USBD->DAINTMSK = 0; + USBD->DAINT = 0; + + // enbale global interrupts + SET_BIT(USBG->GAHBCFG, USB_OTG_GAHBCFG_GINT); +} + +// initialize USB subsystem +void usbdrv_init() { + HAL_NVIC_DisableIRQ(USB_IRQn); + + //usbdrv_init_global_state(); + usbdrv_gpio_init(); + usbdrv_periph_init(); + usbdrv_initial_ep0_setup(); + usbdrv_power_and_connect(true); + + HAL_NVIC_SetPriority(USB_IRQn, 8, 0); + HAL_NVIC_EnableIRQ(USB_IRQn); +} \ No newline at end of file diff --git a/driver/stm32/usb_drv.h b/driver/stm32/usb_drv.h new file mode 100644 index 0000000..495c188 --- /dev/null +++ b/driver/stm32/usb_drv.h @@ -0,0 +1,35 @@ +#ifndef STM32_USB_DRV +#define STM32_USB_DRV + +#include "usb_common_defs.h" + +// Select IO crossbar advanced function +#if defined(USB_STM32H7) +#ifndef STM32H723xx +#define USB_GPIO_AF (GPIO_AF10_OTG2_FS) +#else +// #define USB_GPIO_AF (GPIO_AF10_OTG1_HS) +#endif +#elif defined(USB_STM32F4) +#ifdef USB_HIGH_SPEED +#define USB_GPIO_AF (GPIO_AF10_OTG_HS) +#else +#define USB_GPIO_AF (GPIO_AF10_OTG_FS) +#endif +#endif + +// Set TOCAL and TRDT values (see Ref. Man.) +#if defined(USB_STM32H7) /*|| defined(USB_HIGH_SPEED)*/ +#define TOCAL_VALUE (0x00) +#define TRDT_VALUE (0x05) +#elif defined(USB_STM32F4) +#if !defined(USB_HIGH_SPEED) +#define TOCAL_VALUE (0x07) +#define TRDT_VALUE (0x06) +#else +#define TOCAL_VALUE (0x07) +#define TRDT_VALUE (0x09) +#endif +#endif + +#endif /* STM32_USB_DRV */ diff --git a/desc/usb_config.json b/examples/usb_config.json similarity index 100% rename from desc/usb_config.json rename to examples/usb_config.json diff --git a/desc/usb_config_cdc.json b/examples/usb_config_cdc.json similarity index 100% rename from desc/usb_config_cdc.json rename to examples/usb_config_cdc.json diff --git a/desc/usb_config_eem.json b/examples/usb_config_eem.json similarity index 100% rename from desc/usb_config_eem.json rename to examples/usb_config_eem.json diff --git a/usb.c b/usb.c index 317322b..ab65bb6 100644 --- a/usb.c +++ b/usb.c @@ -3,11 +3,10 @@ #include #include "usb_common.h" -#include "usb_core_types.h" // #include "utils/gen_queue.h" -#include "desc/usb_desc.h" +#include FLATUSB_DESCRIPTOR_HEADER #include "usb_driver.h" @@ -44,7 +43,7 @@ static uint8_t tx_assembly_buf[USB_RX_BUF_SIZE] DWORD_ALIGN; // buffer for assem // ---------------- -__weak void usb_event_callback(USB_CallbackEvent *cbevt) { +__attribute__((weak)) void usb_event_callback(USB_CallbackEvent *cbevt) { return; } diff --git a/usb_common.h b/usb_common.h index 63c9b9e..08c4573 100644 --- a/usb_common.h +++ b/usb_common.h @@ -2,7 +2,6 @@ #define CORE_USB_USB_COMMON #include "usb_common_types.h" -#include "usb_common_defs.h" #include "usb_device_types.h" #define READ_FIELD(r,f) (((r) & (f##_Msk)) >> (f##_Pos)) diff --git a/usb_descriptor_common.h b/usb_descriptor_common.h new file mode 100644 index 0000000..ea7cc62 --- /dev/null +++ b/usb_descriptor_common.h @@ -0,0 +1,8 @@ +#ifndef FLATUSB_USB_DESCRIPTOR_COMMON +#define FLATUSB_USB_DESCRIPTOR_COMMON + +#include + +#include "usb_device_types.h" + +#endif /* FLATUSB_USB_DESCRIPTOR_COMMON */ diff --git a/usb_driver.c b/usb_driver.c index 3783047..18b645e 100644 --- a/usb_driver.c +++ b/usb_driver.c @@ -3,13 +3,12 @@ #include -#include "flatUSB/usb_common_defs.h" -#include "stm32h743xx.h" +#include "usb_common_defs.h" #include "usb_common.h" -#include +#include "usb_device_types.h" -#include "desc/usb_desc.h" +#include FLATUSB_DESCRIPTOR_HEADER #include "embfmt/embformat.h" #define SNPRINTF(str, n, fmt, ...) embfmt(str, n, fmt, __VA_ARGS__) @@ -206,10 +205,6 @@ __weak void usbdrv_ulpi_init() { // --------------- -#define USB_LINESPEED_FULL_SPEED (0b11) -#define USB_LINESPEED_FULL_SPEED_ULPI (0b01) -#define USB_LINESPEED_HIGH_SPEED_ULPI (0b00) - // initialize USB peripheral void usbdrv_periph_init() { #if defined(USB_STM32H7) @@ -234,7 +229,7 @@ void usbdrv_periph_init() { #endif #endif - //HAL_Delay(1000); + // HAL_Delay(1000); //__HAL_RCC_USB_OTG_FS_ULPI_CLK_ENABLE(); //__HAL_RCC_USB_OTG_FS_FORCE_RESET();