diff --git a/bootloader/.gdbinit b/bootloader/.gdbinit new file mode 100644 index 0000000000000000000000000000000000000000..85b92cf79c0f29f412a886e093c13da55dfc1bcc --- /dev/null +++ b/bootloader/.gdbinit @@ -0,0 +1,3 @@ +file build/max32665.elf +target remote localhost:3333 + diff --git a/bootloader/Makefile b/bootloader/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f4152c78930caa23348db0e5134b54c8002923b3 --- /dev/null +++ b/bootloader/Makefile @@ -0,0 +1,121 @@ +################################################################################ + # Copyright (C) 2017 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. + # + # $Date: 2018-08-10 21:35:48 +0000 (Fri, 10 Aug 2018) $ + # $Revision: 36863 $ + # + ############################################################################### + +# This is the name of the build output file +ifeq "$(PROJECT)" "" +PROJECT=max32665 +endif + +# Specify the target processor +ifeq "$(TARGET)" "" +TARGET=MAX32665 +endif + +# Create Target name variables +TARGET_UC:=$(shell echo $(TARGET) | tr a-z A-Z) +TARGET_LC:=$(shell echo $(TARGET) | tr A-Z a-z) + +# Select 'GCC' or 'IAR' compiler +COMPILER=GCC + +# Specify the board used +ifeq "$(BOARD)" "" +BOARD=EvKit_V1 +endif + +# This is the path to the CMSIS root directory +ifeq "$(MAXIM_PATH)" "" +LIBS_DIR=../sdk/Libraries +else +LIBS_DIR=/$(subst \,/,$(subst :,,$(MAXIM_PATH))/Firmware/$(TARGET_UC)/Libraries) +endif +CMSIS_ROOT=$(LIBS_DIR)/CMSIS + +# Source files for this test (add path to VPATH below) +SRCS = main.c +SRCS += mscmem.c + +# Where to find source files for this test +VPATH = . + +# Where to find header files for this test +IPATH = . + +# Enable assertion checking for development +PROJ_CFLAGS+=-DMXC_ASSERT_ENABLE + +# Specify the target revision to override default +# "A2" in ASCII +# TARGET_REV=0x4132 + +# Use this variables to specify and alternate tool path +#TOOL_DIR=/opt/gcc-arm-none-eabi-4_8-2013q4/bin + +# Use these variables to add project specific tool options +#PROJ_CFLAGS+=--specs=nano.specs +#PROJ_LDFLAGS+=--specs=nano.specs + +# Point this variable to a startup file to override the default file +#STARTUPFILE=start.S + +# Set MXC_OPTIMIZE to override the default optimization level +#MXC_OPTIMIZE_CFLAGS=-Og + +# Point this variable to a linker file to override the default file +# LINKERFILE=$(CMSIS_ROOT)/Device/Maxim/$(TARGET_UC)/Source/GCC/$(TARGET_LC).ld + +################################################################################ +# Include external library makefiles here + +# Include the BSP +BOARD_DIR=$(LIBS_DIR)/Boards/$(BOARD) +include $(BOARD_DIR)/board.mk + +# Include the peripheral driver +PERIPH_DRIVER_DIR=$(LIBS_DIR)/$(TARGET_UC)PeriphDriver +include $(PERIPH_DRIVER_DIR)/periphdriver.mk + +MAXUSB_DIR=$(LIBS_DIR)/MAXUSB +include $(MAXUSB_DIR)/maxusb.mk + +################################################################################ +# Include the rules for building for this target. All other makefiles should be +# included before this one. +include $(CMSIS_ROOT)/Device/Maxim/$(TARGET_UC)/Source/$(COMPILER)/$(TARGET_LC).mk + +# The rule to clean out all the build products. +distclean: clean + $(MAKE) -C ${PERIPH_DRIVER_DIR} clean diff --git a/bootloader/descriptors.h b/bootloader/descriptors.h new file mode 100644 index 0000000000000000000000000000000000000000..c61b25a551eca30502bb7a5b4b0dcc7930422523 --- /dev/null +++ b/bootloader/descriptors.h @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright (C) 2017 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 31172 2017-10-05 19:05:57Z zach.metzinger $ + * + ******************************************************************************* + */ + +#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) */ + 0x00, /* bDeviceClass = mass storage (0) */ + 0x00, /* bDeviceSubClass */ + 0x00, /* bDeviceProtocol */ + 0x40, /* bMaxPacketSize0 is 64 bytes */ + 0x0B6A, /* idVendor (Maxim Integrated) */ + 0x4402, /* idProduct */ + 0x0100, /* bcdDevice */ + 0x01, /* iManufacturer Descriptor ID */ + 0x02, /* iProduct Descriptor ID */ + 0x03, /* iSerialNumber = (0) No string */ + 0x01 /* bNumConfigurations */ +}; + +__attribute__((aligned(4))) +struct __attribute__((packed)) { + usb_configuration_descriptor_t config_descriptor; + usb_interface_descriptor_t msc_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) */ + 0x0020, /* wTotalLength(L/H) */ + 0x01, /* bNumInterfaces */ + 0x01, /* bConfigValue */ + 0x00, /* iConfiguration */ + 0xC0, /* bmAttributes (self-powered, no remote wakeup) */ + 0x01, /* MaxPower is 2ma (units are 2ma/bit) */ + }, + { /* First Interface Descriptor For MSC Interface */ + 0x09, /* bLength = 9 */ + 0x04, /* bDescriptorType = Interface (4) */ + 0x00, /* bInterfaceNumber */ + 0x00, /* bAlternateSetting */ + 0x02, /* bNumEndpoints (one for INm one for OUT) */ + 0x08, /* bInterfaceClass = Mass Storage (8) */ + 0x06, /* bInterfaceSubClass = SCSI Transparent Command Set */ + 0x50, /* bInterfaceProtocol = Bulk-Only Transport */ + 0x00, /* iInterface */ + }, + { /* OUT Endpoint 1 (Descriptor #1) */ + 0x07, /* bLength */ + 0x05, /* bDescriptorType (Endpoint) */ + 0x01, /* bEndpointAddress (EP1-OUT) */ + 0x02, /* bmAttributes (bulk) */ + 0x0040, /* wMaxPacketSize */ + 0x00, /* bInterval (N/A) */ + }, + { /* IN Endpoint 2 (Descriptor #2) */ + 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[] = { + 0x38, /* bLength */ + 0x03, /* bDescriptorType */ + 'M', 0, + 'A', 0, + 'X', 0, + 'U', 0, + 'S', 0, + 'B', 0, + ' ', 0, + 'M', 0, + 'a', 0, + 's', 0, + 's', 0, + ' ', 0, + 'S', 0, + 't', 0, + 'o', 0, + 'r', 0, + 'a', 0, + 'g', 0, + 'e', 0, + ' ', 0, + 'E', 0, + 'x', 0, + 'a', 0, + 'm', 0, + 'p', 0, + 'l', 0, + 'e', 0, +}; + +/* Not currently used (see device descriptor), but could be enabled if desired */ +__attribute__((aligned(4))) +uint8_t serial_id_desc[] = { + 26, /* bLength */ + 0x03, /* bDescriptorType */ + '0',0, + '0',0, + '0',0, + '0',0, + '0',0, + '0',0, + '0',0, + '0',0, + '0',0, + '0',0, + '0',0, + '1',0 +}; + +#endif /* _DESCRIPTORS_H_ */ diff --git a/bootloader/main.c b/bootloader/main.c new file mode 100644 index 0000000000000000000000000000000000000000..0c3250fe1e87c678db7662e95b1c280a6f9c0895 --- /dev/null +++ b/bootloader/main.c @@ -0,0 +1,340 @@ +/******************************************************************************* + * 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 31505 2017-10-20 21:16:29Z zach.metzinger $ + * + ******************************************************************************* + */ + +/** + * @file main.c + * @brief USB Mass Storage Class example + * @details This project creates a mass storage device using either on-board RAM or + * external SPI flash memory. Load the project, connect a cable from the PC + * to the USB connector. A new external drive should appear than can be read + * and written. + */ + +#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 "msc.h" +#include "descriptors.h" +#include "mscmem.h" + + +/***** Definitions *****/ +#define EVENT_ENUM_COMP MAXUSB_NUM_EVENTS +#define EVENT_REMOTE_WAKE (EVENT_ENUM_COMP + 1) + +#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); + +/***** File Scope Variables *****/ + +/* This EP assignment must match the Configuration Descriptor */ +static const msc_cfg_t msc_cfg = { + 1, /* EP OUT */ + MXC_USBHS_MAX_PACKET, /* OUT max packet size */ + 2, /* EP IN */ + MXC_USBHS_MAX_PACKET, /* IN max packet size */ +}; + +static const msc_idstrings_t ids = { + "MAXIM", /* Vendor string. Maximum of 8 bytes */ + "MSC Example", /* Product string. Maximum of 16 bytes */ + "1.0" /* Version string. Maximum of 4 bytes */ +}; + +/* Functions to control "disk" memory. See msc.h for definitions. */ +static const msc_mem_t mem = { + mscmem_init, + mscmem_start, + mscmem_stop, + mscmem_ready, + mscmem_size, + mscmem_read, + mscmem_write, +}; + +/* This callback is used to allow the driver to call part specific initialization functions. */ +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); +} + + +/******************************************************************************/ +int main(void) +{ + maxusb_cfg_options_t usb_opts; + + printf("\n\n***** " TOSTRING(TARGET) " USB Mass Storage Example *****\n"); + printf("Waiting for VBUS...\n"); + + /* 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); + enum_register_descriptor(ENUM_DESC_STRING, serial_id_desc, 3); + + /* 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 (msc_init(&config_descriptor.msc_interface_descriptor, &ids, &mem) != 0) { + printf("msc_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); + + /* Start with USB in low power mode */ + usb_app_sleep(); + NVIC_EnableIRQ(USB_IRQn); + + /* Wait for events */ + while (1) { + + if (suspended || !configured) { + LED_Off(0); + } else { + LED_On(0); + } + + if (event_flags) { + /* Display events */ + if (MXC_GETBIT(&event_flags, MAXUSB_EVENT_NOVBUS)) { + MXC_CLRBIT(&event_flags, MAXUSB_EVENT_NOVBUS); + printf("VBUS Disconnect\n"); + } else if (MXC_GETBIT(&event_flags, MAXUSB_EVENT_VBUS)) { + MXC_CLRBIT(&event_flags, MAXUSB_EVENT_VBUS); + printf("VBUS Connect\n"); + } else if (MXC_GETBIT(&event_flags, MAXUSB_EVENT_BRST)) { + MXC_CLRBIT(&event_flags, MAXUSB_EVENT_BRST); + printf("Bus Reset\n"); + } else if (MXC_GETBIT(&event_flags, MAXUSB_EVENT_SUSP)) { + MXC_CLRBIT(&event_flags, MAXUSB_EVENT_SUSP); + printf("Suspended\n"); + } else if (MXC_GETBIT(&event_flags, MAXUSB_EVENT_DPACT)) { + MXC_CLRBIT(&event_flags, MAXUSB_EVENT_DPACT); + printf("Resume\n"); + } else if (MXC_GETBIT(&event_flags, EVENT_ENUM_COMP)) { + MXC_CLRBIT(&event_flags, EVENT_ENUM_COMP); + printf("Enumeration complete.\n"); + } else if (MXC_GETBIT(&event_flags, EVENT_REMOTE_WAKE)) { + MXC_CLRBIT(&event_flags, EVENT_REMOTE_WAKE); + printf("Remote Wakeup\n"); + } + } + } +} + +/******************************************************************************/ +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 msc_configure(&msc_cfg); /* Configure the device class */ + } else if (sud->wValue == 0) { + configured = 0; + return msc_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(); + msc_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(); + msc_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; +} + +/******************************************************************************/ +void USB_IRQHandler(void) +{ + usb_event_handler(); +} + +/******************************************************************************/ +void SysTick_Handler(void) +{ + mxc_delay_handler(); +} diff --git a/bootloader/mscmem.c b/bootloader/mscmem.c new file mode 100644 index 0000000000000000000000000000000000000000..0b56e0bd8857004061fcd5305b375314816c82fe --- /dev/null +++ b/bootloader/mscmem.c @@ -0,0 +1,313 @@ +/******************************************************************************* + * Copyright (C) 2017 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 31172 2017-10-05 19:05:57Z zach.metzinger $ + * + ******************************************************************************* + */ + +/** + * @file mscmem.h + * @brief Memory routines used by the USB Mass Storage Class example. + * See the msc_mem_t structure in msc.h for function details. + * @details Functions are provided for using the internal RAM of the + * device or the external SPI flash memory. Use the SPIXF_DISK + * and RAM_DISK defines to select the desired memory at compile + * time. + */ + +#include "mscmem.h" +#include <string.h> +#include <stdio.h> +#include "mx25.h" + +/***** Definitions *****/ + +#define SPIXF_DISK 1 +#define RAM_DISK 0 + +#define LBA_SIZE 512 /* Size of "logical blocks" in bytes */ +#define LBA_SIZE_SHIFT 9 /* The shift value used to convert between addresses and block numbers */ + +/***** Global Data *****/ + +/***** File Scope Variables *****/ + +static int initialized = 0; +static int running = 0; + +#if SPIXF_DISK + +#define MX25_BAUD 5000000 /* SPI clock rate to communicate with the MX25 */ + +#define MX25_SECTOR_SIZE 4096 /* Number of bytes in one sector of the MX25 */ +#define MX25_SECTOR_SIZE_SHIFT 12 /* The shift value used to convert between addresses and block numbers */ +#define MX25_NUM_SECTORS 2048 /* Total number of sectors in the MX25 */ + +#define LBA_PER_SECTOR (MX25_SECTOR_SIZE >> LBA_SIZE_SHIFT) +#define INVALID_SECTOR MX25_NUM_SECTORS /* Use a sector number past the end of memory to indicate invalid */ + +/***** File Scope Variables *****/ +static uint32_t sectorNum = INVALID_SECTOR; +static uint8_t sector[MX25_SECTOR_SIZE]; +static int sectorDirty = 0; + +/***** Function Prototypes *****/ +static uint32_t getSectorNum(uint32_t lba); +static uint32_t getSectorAddr(uint32_t lba); +static uint32_t getSector(uint32_t num); + +/******************************************************************************/ +static uint32_t getSectorNum(uint32_t lba) +{ + /* Absolute_address = lba * LBA_SIZE */ + /* Sector_num = Absolute_address / MX25_SECTOR_SIZE */ + /* Sector_num = lba * 512 / 4096 */ + return lba >> (MX25_SECTOR_SIZE_SHIFT - LBA_SIZE_SHIFT); +} + +/******************************************************************************/ +static uint32_t getSectorAddr(uint32_t lba) +{ + /* eight 512 byte blocks in each sector */ + return (lba & (LBA_PER_SECTOR - 1)) << LBA_SIZE_SHIFT; +} + +/******************************************************************************/ +static uint32_t getSector(uint32_t num) +{ + /* New sector requested? */ + if(sectorNum != num) { + /* Is the current sector real? */ + if(sectorNum != INVALID_SECTOR) { + /* Was it written to after it was read from memory? */ + if(sectorDirty) { + /* Erase the old data. */ + MX25_Erase(sectorNum << MX25_SECTOR_SIZE_SHIFT, MX25_Erase_4K); + /* Write the new */ + MX25_Program_Page(sectorNum << MX25_SECTOR_SIZE_SHIFT, sector, MX25_SECTOR_SIZE, SPIXFC_WIDTH_4); + /* Mark data as clean */ + sectorDirty = 0; + } + } + + /* Requesting a new valid sector? */ + if(num != INVALID_SECTOR) { + MX25_Read(num << MX25_SECTOR_SIZE_SHIFT, sector, MX25_SECTOR_SIZE, SPIXFC_WIDTH_4); + sectorDirty = 0; + sectorNum = num; + } + } + + return 0; +} + +/******************************************************************************/ +int mscmem_init() +{ + + if(!initialized) { + MX25_Init(); + MX25_Reset(); + MX25_Quad(1); + initialized = 1; + } + return 0; +} + +/******************************************************************************/ +uint32_t mscmem_size(void) +{ + /* Get number of 512 byte chunks the MX25 contains. */ + return (MX25_SECTOR_SIZE >> LBA_SIZE_SHIFT) * MX25_NUM_SECTORS; +} + +/******************************************************************************/ +int mscmem_read(uint32_t lba, uint8_t* buffer) +{ + uint32_t addr; + + /* Convert to MX25 sector number. */ + uint32_t sNum = getSectorNum(lba); + + if(getSector(sNum)) { + /* Failed to write/read from MX25 */ + return 1; + } + + /* Get the offset into the current sector */ + addr = getSectorAddr(lba); + + memcpy(buffer, sector + addr, LBA_SIZE); + + return 0; +} + +/******************************************************************************/ +int mscmem_write(uint32_t lba, uint8_t* buffer) +{ + uint32_t addr; + + /* Convert to MX25 sector number. */ + uint32_t sNum = getSectorNum(lba); + + if(getSector(sNum)) { + /* Failed to write/read from MX25 */ + return 1; + } + + /* Get the offset into the current sector */ + addr = getSectorAddr(lba); + + memcpy(sector + addr, buffer, LBA_SIZE); + sectorDirty = 1; + + return 0; +} + +/******************************************************************************/ +int mscmem_start() +{ + /* Turn on the MX25 if it is not already. */ + if(!initialized) { + mscmem_init(); + } + + /* Check if the initialization succeeded. If it has, start running. */ + if(initialized) { + running = 1; + } + + /* Start should return fail (non-zero) if the memory cannot be initialized. */ + return !initialized; +} + +/******************************************************************************/ +int mscmem_stop() +{ + /* TODO - could shut down XIPF interface here. */ + + /* Flush the currently cached sector if necessary. */ + if(getSector(INVALID_SECTOR)) { + return 1; + } + + running = 0; + return 0; +} + +/******************************************************************************/ +int mscmem_ready() +{ + return running; +} + +#elif RAM_DISK + +#define NUM_PAGES 0x100 +static uint8_t mem[NUM_PAGES][LBA_SIZE]; + +/******************************************************************************/ +int mscmem_init() +{ + if(!initialized) { + initialized = 1; +#if (ERASE_MEMORY_ON_INIT) + memset(mem, 0, sizeof(mem)); +#endif + } + return 0; +} + +/******************************************************************************/ +uint32_t mscmem_size(void) +{ + return NUM_PAGES; +} + +/******************************************************************************/ +int mscmem_read(uint32_t lba, uint8_t* buffer) +{ + if(lba >= NUM_PAGES) { + return 1; + } + + memcpy(buffer, mem[lba], LBA_SIZE); + return 0; +} + +/******************************************************************************/ +int mscmem_write(uint32_t lba, uint8_t* buffer) +{ + if(lba >= NUM_PAGES) { + return 1; + } + + memcpy(mem[lba], buffer, LBA_SIZE); + return 0; +} + +/******************************************************************************/ +int mscmem_start() +{ + /* Not much to do for this implementation. The RAM is always ready. */ + if(!initialized) { + mscmem_init(); + } + + /* Check if the RAM has been initialized. If it has, start running. */ + if(initialized) { + running = 1; + } + + /* Start should return fail (non-zero) if the memory cannot be initialized. */ + return !initialized; +} + +/******************************************************************************/ +int mscmem_stop() +{ + /* Nothing to do for this implementation. All data is written as it is */ + /* received so there are no pending writes that need to be flushed. */ + running = 0; + return 0; +} + +/******************************************************************************/ +int mscmem_ready() +{ + return running; +} + +#else + #error "You must assign either RAM_DISK or SPIXF_DISK to 1." +#endif diff --git a/bootloader/mscmem.h b/bootloader/mscmem.h new file mode 100644 index 0000000000000000000000000000000000000000..681e95e5d740092116c1362be227cfe14d8b57be --- /dev/null +++ b/bootloader/mscmem.h @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (C) 2017 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 31172 2017-10-05 19:05:57Z zach.metzinger $ + * + ******************************************************************************* + */ + +/** + * @file mscmem.h + * @brief Memory routines used by the USB Mass Storage Class example. + * See the msc_mem_t structure in msc.h for function details. + */ + +#ifndef __MSC_MEM_H__ +#define __MSC_MEM_H__ + +#include <stdint.h> + +#define ERASE_MEMORY_ON_INIT 1 /* Configuration option to clear the memory (to 0s) on initialization. */ + /* Use 1 to clear or 0 to leave untouched. */ + +int mscmem_init(void); +int mscmem_start(void); +int mscmem_stop(void); +uint32_t mscmem_size(void); +int mscmem_read(uint32_t lba, uint8_t* buffer); +int mscmem_write(uint32_t lba, uint8_t* buffer); +int mscmem_ready(void); + +#endif /* __MSC_MEM_H__ */