//***************************************************************************** // // bl_usb.c - Functions to transfer data via the USB port. // // Copyright (c) 2009-2014 Texas Instruments Incorporated. All rights reserved. // Software License Agreement // // Texas Instruments (TI) is supplying this software for use solely and // exclusively on TI's microcontroller products. The software is owned by // TI and/or its suppliers, and is protected under applicable copyright // laws. You may not combine this software with "viral" open-source // software in order to form a larger program. // // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL // DAMAGES, FOR ANY REASON WHATSOEVER. // // This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package. // //***************************************************************************** #include #include #include "inc/hw_gpio.h" #include "inc/hw_memmap.h" #include "inc/hw_flash.h" #include "inc/hw_sysctl.h" #include "inc/hw_types.h" #include "inc/hw_nvic.h" #include "inc/hw_usb.h" #include "bl_config.h" #include "boot_loader/bl_crystal.h" #include "boot_loader/bl_flash.h" #include "boot_loader/bl_hooks.h" #include "boot_loader/bl_usbfuncs.h" #include "boot_loader/usbdfu.h" //***************************************************************************** // // DFU Notes: // // 1. This implementation is manifestation-tolerant and doesn't time out // waiting for a reset after a download completes. As a result, the detach // timeout in the DFU functional descriptor is set to the maximum possible // value representing a timeout of 65.536 seconds. // // 2. This implementation does not support the BUSY state. By skipping this // and remaining in DNLOAD_SYNC when we are waiting for a programming or // erase operation to complete, we save the overhead of having to support a // timeout mechanism. Host-side implementations don't seem to rely upon // the busy state so this does not appear to be a problem. // //***************************************************************************** //***************************************************************************** // //! \addtogroup bl_usb_api //! @{ // //***************************************************************************** #if defined(USB_ENABLE_UPDATE) || defined(DOXYGEN) //***************************************************************************** // // Make sure that the crystal frequency is defined. // //***************************************************************************** #if !defined(CRYSTAL_FREQ) #error ERROR: CRYSTAL_FREQ must be defined for USB update! #endif //***************************************************************************** // // Make sure that the crystal frequency is one of the ones that support USB // operation. // //***************************************************************************** #if CRYSTAL_FREQ != 4000000 && \ CRYSTAL_FREQ != 5000000 && \ CRYSTAL_FREQ != 6000000 && \ CRYSTAL_FREQ != 8000000 && \ CRYSTAL_FREQ != 10000000 && \ CRYSTAL_FREQ != 12000000 && \ CRYSTAL_FREQ != 16000000 #error ERROR: Invalid CRYSTAL_FREQ specified for USB update! #endif //***************************************************************************** // // The DFU device information structure was developed assuming flash block // sizes in the 1KB to 32KB range but large external flash devices may have // 64KB or larger blocks. If the configuration options indicate a target // device with large pages, we fake the size at 32KB to keep the client happy. // The other option would be to redefine this field as an uint32_t but that // would break existing applications using the interface. // // For normal operation, this is unlikely to cause a problem since we will not // allow a flash operation to start anywhere other than at APP_START_ADDRESS // (which must fall on a real flash page boundary) or the start of the // reserved // //***************************************************************************** #if (FLASH_PAGE_SIZE > 0x10000) #define DFU_REPORTED_PAGE_SIZE 0x8000 #else #define DFU_REPORTED_PAGE_SIZE FLASH_PAGE_SIZE #endif //***************************************************************************** // // This holds the total size of the firmware image being downloaded (which is // needed if we have a progress reporting hook function provided). // //***************************************************************************** #ifdef BL_PROGRESS_FN_HOOK uint32_t g_ui32ImageSize; #endif //***************************************************************************** // // The structure used to define a block of memory. // //***************************************************************************** typedef struct { uint8_t *pui8Start; uint32_t ui32Length; } tMemoryBlock; //***************************************************************************** // // The block of memory that is to be sent back in response to the next upload // request. // //***************************************************************************** tMemoryBlock g_sNextUpload; //***************************************************************************** // // The block of memory into which the next programming operation will write. // //***************************************************************************** volatile tMemoryBlock g_sNextDownload; //***************************************************************************** // // The block of flash to be erased. // //***************************************************************************** volatile tMemoryBlock g_sErase; //***************************************************************************** // // Information on the device we are running on. This will be returned to the // host after a download request containing command DFU_CMD_INFO. // //***************************************************************************** tDFUDeviceInfo g_sDFUDeviceInfo; //***************************************************************************** // // This variable keeps track of the last software-specific command received // from the host via a download request. // //***************************************************************************** uint8_t g_ui8LastCommand; //***************************************************************************** // // The current status of the DFU device as reported to the host in response to // USBD_DFU_REQUEST_GETSTATUS. // //***************************************************************************** tDFUGetStatusResponse g_sDFUStatus = { 0, { 5, 0, 0 }, (uint8_t)STATE_IDLE, 0 }; //***************************************************************************** // // The structure sent in response to a valid USBD_DFU_REQUEST_TIVA. // //***************************************************************************** tDFUQueryTIVAProtocol g_sDFUProtocol = { DFU_PROTOCOL_USBLIB_MARKER, DFU_PROTOCOL_USBLIB_VERSION_1 }; //***************************************************************************** // // The current state of the device. // //***************************************************************************** volatile tDFUState g_eDFUState = STATE_IDLE; //***************************************************************************** // // The current status of the device. // //***************************************************************************** volatile tDFUStatus g_eDFUStatus = STATUS_OK; //***************************************************************************** // // The buffer used to hold download data from the host prior to writing it to // flash or image data in the process of being uploaded to the host. // //***************************************************************************** uint8_t g_pui8DFUBuffer[DFU_TRANSFER_SIZE]; //***************************************************************************** // // The start of the image data within g_pui8DFUBuffer. // //***************************************************************************** uint8_t *g_pui8DFUWrite; //***************************************************************************** // // The number of bytes of valid data in the DFU buffer. // //***************************************************************************** volatile uint16_t g_ui16DFUBufferUsed; //***************************************************************************** // // Flags used to indicate that the main thread is being asked to do something. // //***************************************************************************** volatile uint32_t g_ui32CommandFlags; #define CMD_FLAG_ERASE 0 #define CMD_FLAG_WRITE 1 #define CMD_FLAG_RESET 2 //***************************************************************************** // // This global determines whether or not we add a DFU header to any uploaded // image data. If true, the binary image is sent without the header. If false // the header is included. This is a DFU requirement since uploaded images // must be able to be downloaded again and hence must have the header in place // so that the destination address is available. // //***************************************************************************** bool g_bUploadBinary = false; //***************************************************************************** // // If the upload format includes the header, we need to be able to suppress // this when replying to TIVA-specific commands such as CMD_DFU_INFO. This // global determines whether we need to suppress the header that would // otherwise be send in response to the first USBD_DFU_REQUEST_UPLOAD received // while in STATE_IDLE. // //***************************************************************************** bool g_bSuppressUploadHeader = false; //***************************************************************************** // // A flag we use to indicate when the device has been enumerated. // //***************************************************************************** bool g_bAddressSet = false; //***************************************************************************** // // The languages supported by this device. // //***************************************************************************** const uint8_t g_pui8LangDescriptor[] = { 4, USB_DTYPE_STRING, USBShort(USB_LANG_EN_US) }; //***************************************************************************** // // The jump table used to implement request handling in the DFU state machine. // //***************************************************************************** typedef void (* tHandleRequests)(tUSBRequest *psUSBRequest); extern void HandleRequestIdle(tUSBRequest *psUSBRequest); extern void HandleRequestDnloadSync(tUSBRequest *psUSBRequest); extern void HandleRequestDnloadIdle(tUSBRequest *psUSBRequest); extern void HandleRequestManifestSync(tUSBRequest *psUSBRequest); extern void HandleRequestUploadIdle(tUSBRequest *psUSBRequest); extern void HandleRequestError(tUSBRequest *psUSBRequest); tHandleRequests g_pfnRequestHandlers[] = { 0, // STATE_APP_IDLE 0, // STATE_APP_DETACH HandleRequestIdle, // STATE_IDLE HandleRequestDnloadSync, // STATE_DNLOAD_SYNC HandleRequestDnloadSync, // STATE_DNBUSY HandleRequestDnloadIdle, // STATE_DNLOAD_IDLE HandleRequestManifestSync, // STATE_MANIFEST_SYNC 0, // STATE_MANIFEST 0, // STATE_MANIFEST_WAIT_RESET HandleRequestUploadIdle, // STATE_UPLOAD_IDLE HandleRequestError // STATE_ERROR }; //***************************************************************************** // // The manufacturer string. // //***************************************************************************** const uint8_t g_pui8ManufacturerString[] = { (17 + 1) * 2, USB_DTYPE_STRING, 'T', 0, 'e', 0, 'x', 0, 'a', 0, 's', 0, ' ', 0, 'I', 0, 'n', 0, 's', 0, 't', 0, 'r', 0, 'u', 0, 'm', 0, 'e', 0, 'n', 0, 't', 0, 's', 0 }; //***************************************************************************** // // The product string. // //***************************************************************************** const uint8_t g_pui8ProductString[] = { (23 + 1) * 2, USB_DTYPE_STRING, 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, ' ', 0, 'F', 0, 'i', 0, 'r', 0, 'm', 0, 'w', 0, 'a', 0, 'r', 0, 'e', 0, ' ', 0, 'U', 0, 'p', 0, 'g', 0, 'r', 0, 'a', 0, 'd', 0, 'e', 0 }; //***************************************************************************** // // The serial number string. // //***************************************************************************** const uint8_t g_pui8SerialNumberString[] = { (3 + 1) * 2, USB_DTYPE_STRING, '0', 0, '.', 0, '1', 0 }; //***************************************************************************** // // The descriptor string table. // //***************************************************************************** const uint8_t *const g_ppui8StringDescriptors[] = { g_pui8LangDescriptor, g_pui8ManufacturerString, g_pui8ProductString, g_pui8SerialNumberString }; //***************************************************************************** // // DFU Device Descriptor. // //***************************************************************************** const uint8_t g_pui8DFUDeviceDescriptor[] = { 18, // Size of this structure. USB_DTYPE_DEVICE, // Type of this structure. USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts assume // high-speed - see USB 2.0 spec 9.2.6.6) USB_CLASS_VEND_SPECIFIC, // USB Device Class 0, // USB Device Sub-class 0, // USB Device protocol 64, // Maximum packet size for default pipe. USBShort(USB_VENDOR_ID), // Vendor ID (VID). USBShort(USB_PRODUCT_ID), // Product ID (PID). USBShort(USB_DEVICE_ID), // Device Release Number BCD. 1, // Manufacturer string identifier. 2, // Product string identifier. 3, // Product serial number. 1 // Number of configurations. }; //***************************************************************************** // // DFU device configuration descriptor. // //***************************************************************************** const uint8_t g_pui8DFUConfigDescriptor[] = { // // Configuration descriptor header. // 9, // Size of the configuration descriptor. USB_DTYPE_CONFIGURATION, // Type of this descriptor. USBShort(27), // The total size of this full structure. 1, // The number of interfaces in this // configuration. 1, // The unique value for this configuration. 0, // The string identifier that describes this // configuration. #if USB_BUS_POWERED USB_CONF_ATTR_BUS_PWR, // Bus Powered #else USB_CONF_ATTR_SELF_PWR, // Self Powered #endif (USB_MAX_POWER / 2), // The maximum power in 2mA increments. // // Interface descriptor. // 9, // Length of this descriptor. USB_DTYPE_INTERFACE, // This is an interface descriptor. 0, // Interface number . 0, // Alternate setting number. 0, // Number of endpoints (only endpoint 0 used) USB_CLASS_APP_SPECIFIC, // Application specific interface class USB_DFU_SUBCLASS, // Device Firmware Upgrade subclass USB_DFU_PROTOCOL, // DFU protocol 0, // No interface description string present. // // Device Firmware Upgrade functional descriptor. // 9, // Length of this descriptor. 0x21, // DFU Functional descriptor type (DFU_ATTR_CAN_DOWNLOAD | // DFU attributes. DFU_ATTR_CAN_UPLOAD | DFU_ATTR_MANIFEST_TOLERANT), USBShort(0xFFFF), // Detach timeout (set to maximum). USBShort(DFU_TRANSFER_SIZE),// Transfer size 1KB. USBShort(0x0110) // DFU Version 1.1 }; //***************************************************************************** // // The USB device interrupt handler. // // This function is called to process USB interrupts when in device mode. // This handler will branch the interrupt off to the appropriate application or // stack handlers depending on the current status of the USB controller. // // \return None. // //***************************************************************************** void USB0DeviceIntHandler(void) { uint32_t ui32TxStatus, ui32GenStatus; // // Get the current full USB interrupt status. // ui32TxStatus = HWREGH(USB0_BASE + USB_O_TXIS); ui32GenStatus = HWREGB(USB0_BASE + USB_O_IS); // // Received a reset from the host. // if(ui32GenStatus & USB_IS_RESET) { USBDeviceEnumResetHandler(); } // // USB device was disconnected. // if(ui32GenStatus & USB_IS_DISCON) { HandleDisconnect(); } // // Handle end point 0 interrupts. // if(ui32TxStatus & USB_TXIE_EP0) { USBDeviceEnumHandler(); } } //***************************************************************************** // // A prototype for the function (in the startup code) for a predictable length // delay. // //***************************************************************************** extern void Delay(uint32_t ui32Count); //***************************************************************************** // // Send the current state or status structure back to the host. This function // also acknowledges the request which causes us to send back this data. // //***************************************************************************** void SendDFUStatus(void) { // // Acknowledge the original request. // USBDevEndpoint0DataAck(false); // // Copy the current state into the status structure we will return. // g_sDFUStatus.bState = (uint8_t)g_eDFUState; g_sDFUStatus.bStatus = (uint8_t)g_eDFUStatus; // // Send the status structure back to the host. // USBBLSendDataEP0((uint8_t *)&g_sDFUStatus, sizeof(tDFUGetStatusResponse)); } //***************************************************************************** // // Send the next block of upload data back to the host assuming data remains // to be sent. // // \param ui16Length is the requested amount of data. // \param bAppendHeader is \b true to append a tDFUDownloadProgHeader at the // start of the uploaded data or \b false if no header is required. // // Returns \b true if a full packet containing DFU_TRANSFER_SIZE bytes // was sent and data remains to be sent following this transaction, or \b // false if no more data remains to be sent following this transaction. // //***************************************************************************** bool SendUploadData(uint16_t ui16Length, bool bAppendHeader) { uint16_t ui16ToSend; uint32_t ui32Available; // // Acknowledge the original request. // USBDevEndpoint0DataAck(false); // // How much data is available to be sent? // ui32Available = (g_sNextUpload.ui32Length + (bAppendHeader ? sizeof(tDFUDownloadProgHeader) : 0)); // // How much data can we send? This is the smallest of the maximum transfer // size, the requested length or the available data. // ui16ToSend = (ui16Length > DFU_TRANSFER_SIZE) ? DFU_TRANSFER_SIZE : ui16Length; ui16ToSend = ((uint32_t)ui16ToSend > ui32Available) ? ui32Available : ui16ToSend; // // If we have been asked to send a header, we need to copy some of the data // into a buffer and send from there. If we don't do this, we run the risk // of sending a long packet prematurely and ending the upload before it is // complete. // if(bAppendHeader) { tDFUDownloadProgHeader *psHdr; uint8_t *pui8From; uint8_t *pui8To; uint32_t ui32Loop; // // We are appending a header so write the header information into a // buffer then copy the first chunk of data from its original position // into the same buffer. // psHdr = (tDFUDownloadProgHeader *)g_pui8DFUBuffer; // // Build the header. // psHdr->ui8Command = DFU_CMD_PROG; psHdr->ui8Reserved = 0; psHdr->ui16StartAddr = ((uint32_t)(g_sNextUpload.pui8Start) / 1024); psHdr->ui32Length = g_sNextUpload.ui32Length; // // Copy the remainder of the first transfer's data from its original // position. // pui8From = g_sNextUpload.pui8Start; pui8To = (uint8_t *)(psHdr + 1); for(ui32Loop = (ui16ToSend - sizeof(tDFUDownloadProgHeader)); ui32Loop; ui32Loop--) { *pui8To++ = *pui8From++; } // // Send the data. // USBBLSendDataEP0((uint8_t *)psHdr, ui16ToSend); // // Update our upload pointer and length. // g_sNextUpload.pui8Start += ui16ToSend - sizeof(tDFUDownloadProgHeader); g_sNextUpload.ui32Length -= ui16ToSend - sizeof(tDFUDownloadProgHeader); } else { // // We are not sending a header so send the requested upload data back // to the host directly from its original position. // USBBLSendDataEP0(g_sNextUpload.pui8Start, ui16ToSend); // // Update our upload pointer and length. // g_sNextUpload.pui8Start += ui16ToSend; g_sNextUpload.ui32Length -= ui16ToSend; } // // We return true if we sent a full packet (containing the maximum transfer // size bytes) or false to indicate that a long packet was sent or no more // data remains. // return(((ui16ToSend == DFU_TRANSFER_SIZE) && g_sNextUpload.ui32Length) ? true : false); } //***************************************************************************** // // Send the current state back to the host. // //***************************************************************************** void SendDFUState(void) { // // Acknowledge the original request. // USBDevEndpoint0DataAck(false); // // Update the status structure with the current state. // g_sDFUStatus.bState = (uint8_t)g_eDFUState; // // Send the state from the status structure back to the host. // USBBLSendDataEP0((uint8_t *)&g_sDFUStatus.bState, 1); } //***************************************************************************** // //! Handle USB requests sent to the DFU device. //! //! \param psUSBRequest is a pointer to the USB request that the device has //! been sent. //! //! This function is called to handle all non-standard requests received //! by the device. This will include all the DFU endpoint 0 commands along //! with the TIVA-specific request we use to query whether the device //! supports our flavor of the DFU binary format. Incoming DFU requests are //! processed by request handlers specific to the particular state of the DFU //! connection. This state machine implementation is chosen to keep the //! software as close as possible to the USB DFU class documentation. //! //! \return None. // //***************************************************************************** void HandleRequests(tUSBRequest *psUSBRequest) { // // This request is used by the host to determine whether the connected // device supports the TIVA protocol extensions to DFU (our // DFU_CMD_xxxx command headers passed alongside DNLOAD requests). We // check the parameters and, if they are as expected, we respond with // a 4 byte structure providing a marker and the protocol version // number. // if(psUSBRequest->bRequest == USBD_DFU_REQUEST_TIVA) { // // Check that the request parameters are all as expected. We are // using the wValue value merely as a way of making it less likely // that we respond to another vendor's device-specific request. // if((psUSBRequest->wLength == sizeof(tDFUQueryTIVAProtocol)) && (psUSBRequest->wValue == REQUEST_TIVA_VALUE)) { // // Acknowledge the original request. // USBDevEndpoint0DataAck(false); // // Send the status structure back to the host. // USBBLSendDataEP0((uint8_t *)&g_sDFUProtocol, sizeof(tDFUQueryTIVAProtocol)); } else { // // The request parameters were not as expected so we assume // that this is not our request and stall the endpoint to // indicate an error. // USBBLStallEP0(); } return; } // // Pass the request to the relevant handler depending upon our current // state. If no handler is configured, we stall the endpoint since this // implies that requests can't be handled in this state. // if(g_pfnRequestHandlers[g_eDFUState]) { // // Dispatch the request to the relevant handler depending upon the // current state. // (g_pfnRequestHandlers[g_eDFUState])(psUSBRequest); } else { USBBLStallEP0(); } } //***************************************************************************** // // Handle all incoming DFU requests while in state STATE_IDLE. // //***************************************************************************** void HandleRequestIdle(tUSBRequest *psUSBRequest) { switch(psUSBRequest->bRequest) { // // This is a download request. We need to request the transaction // payload unless this is a zero length request in which case we mark // the error by stalling the endpoint. // case USBD_DFU_REQUEST_DNLOAD: { if(psUSBRequest->wLength) { USBBLRequestDataEP0(g_pui8DFUBuffer, psUSBRequest->wLength); } else { USBBLStallEP0(); return; } break; } // // This is an upload request. We send back a block of data // corresponding to the current upload pointer as held in // g_sNextUpload. // case USBD_DFU_REQUEST_UPLOAD: { // // If we have any upload data to send, send it. Make sure we append // a header if required. // if(SendUploadData(psUSBRequest->wLength, g_bSuppressUploadHeader ? false : !g_bUploadBinary)) { // // We sent a full (max packet size) frame to the host so // transition to UPLOAD_IDLE state since we expect another // upload request to continue the process. // g_eDFUState = STATE_UPLOAD_IDLE; } // // Clear the flag we use to suppress sending the DFU header. // g_bSuppressUploadHeader = false; return; } // // Return the current device status structure. // case USBD_DFU_REQUEST_GETSTATUS: { SendDFUStatus(); return; } // // Return the current device state. // case USBD_DFU_REQUEST_GETSTATE: { SendDFUState(); return; } // // Ignore the ABORT request. This returns us to IDLE state but we're // there already. // case USBD_DFU_REQUEST_ABORT: { break; } // // All other requests are illegal in this state so signal the error // by stalling the endpoint. // case USBD_DFU_REQUEST_CLRSTATUS: case USBD_DFU_REQUEST_DETACH: default: { USBBLStallEP0(); return; } } // // If we drop out of the switch, we need to ACK the received request. // USBDevEndpoint0DataAck(false); } //***************************************************************************** // // Handle all incoming DFU requests while in state STATE_DNLOAD_SYNC or // STATE_DNBUSY. // //***************************************************************************** void HandleRequestDnloadSync(tUSBRequest *psUSBRequest) { // // In this state, we have received a block of the download and are waiting // for a USBD_DFU_REQUEST_GETSTATUS which will trigger a return // to STATE_DNLOAD_IDLE assuming we have finished programming the block. // If the last command we received was not DFU_CMD_PROG, we transition // directly from this state back to STATE_IDLE once the last operation has // completed since we need to be able to accept a new command. // switch(psUSBRequest->bRequest) { // // The host is requesting the current device status. Return this and // revert to STATE_IDLE. // case USBD_DFU_REQUEST_GETSTATUS: { // // Are we finished processing whatever the last flash-operation // was? Note that we don't support DNLOAD_BUSY state in this // implementation, we merely continue to report DNLOAD_SYNC state // until we are finished with the command. // if(!g_ui32CommandFlags) { // // If we are in the middle of a programming operation, // transition back to DNLOAD_IDLE state to wait for the // next block. If not, go back to idle since we expect a // new command. // g_eDFUState = ((g_ui8LastCommand == DFU_CMD_PROG) ? STATE_DNLOAD_IDLE : STATE_IDLE); } // // Send the latest status back to the host. // SendDFUStatus(); // // Return here since we've already ACKed the request. // return; } // // The host is requesting the current device state. // case USBD_DFU_REQUEST_GETSTATE: { // // Are we currently in DNLOAD_SYNC state? // if(g_eDFUState == STATE_DNLOAD_SYNC) { // // Yes - send back the state. // SendDFUState(); } else { // // In STATE_BUSY, we can't respond to any requests so stall // the endpoint. // USBBLStallEP0(); } // // Return here since the incoming request has already been either // ACKed or stalled by the processing above. // return; } // // Any other request is ignored and causes us to stall the control // endpoint and remain in STATE_ERROR. // default: { USBBLStallEP0(); return; } } } //***************************************************************************** // // Handle all incoming DFU requests while in state STATE_DNLOAD_IDLE. // //***************************************************************************** void HandleRequestDnloadIdle(tUSBRequest *psUSBRequest) { switch(psUSBRequest->bRequest) { // // This is a download request. We need to request the transaction // payload unless this is a zero length request in which case we mark // the error by stalling the endpoint. // case USBD_DFU_REQUEST_DNLOAD: { // // Are we being passed data to program? // if(psUSBRequest->wLength) { // // Yes - request the data. // USBBLRequestDataEP0(g_pui8DFUBuffer, psUSBRequest->wLength); } else { // // No - this is the signal that a download operation is // complete. Do we agree? // if(g_sNextDownload.ui32Length) { // // We think there should still be some data to be received // so mark this as an error. // g_eDFUState = STATE_ERROR; g_eDFUStatus = STATUS_ERR_NOTDONE; } else { // // We agree that the download has completed. Enter state // STATE_MANIFEST_SYNC. // g_eDFUState = STATE_MANIFEST_SYNC; } } break; } // // Return the current device status structure. // case USBD_DFU_REQUEST_GETSTATUS: { SendDFUStatus(); return; } // // Return the current device state. // case USBD_DFU_REQUEST_GETSTATE: { SendDFUState(); return; } // // An ABORT request causes us to abort the current transfer and // return the the idle state regardless of the state of the previous // programming operation. // case USBD_DFU_REQUEST_ABORT: { // // Default to downloading the main code image. // g_sNextDownload.pui8Start = (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr; g_sNextDownload.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop - g_sDFUDeviceInfo.ui32AppStartAddr); g_eDFUState = STATE_IDLE; break; } // // All other requests are illegal in this state so signal the error // by stalling the endpoint. // case USBD_DFU_REQUEST_CLRSTATUS: case USBD_DFU_REQUEST_DETACH: case USBD_DFU_REQUEST_UPLOAD: default: { USBBLStallEP0(); return; } } // // If we drop out of the switch, we need to ACK the received request. // USBDevEndpoint0DataAck(false); } //***************************************************************************** // // Handle all incoming DFU requests while in state STATE_MANIFEST_SYNC. // //***************************************************************************** void HandleRequestManifestSync(tUSBRequest *psUSBRequest) { // // In this state, we have received the last block of a download and are // waiting for a USBD_DFU_REQUEST_GETSTATUS which will trigger a return // to STATE_IDLE. // switch(psUSBRequest->bRequest) { // // The host is requesting the current device status. Return this and // revert to STATE_IDLE. // case USBD_DFU_REQUEST_GETSTATUS: { g_eDFUState = STATE_IDLE; SendDFUStatus(); break; } // // The host is requesting the current device state. // case USBD_DFU_REQUEST_GETSTATE: { SendDFUState(); break; } // // Any other request is ignored and causes us to stall the control // endpoint and remain in STATE_MANIFEST_SYNC. // default: { USBBLStallEP0(); break; } } } //***************************************************************************** // // Handle all incoming DFU requests while in state STATE_UPLOAD_IDLE. // //***************************************************************************** void HandleRequestUploadIdle(tUSBRequest *psUSBRequest) { // // In this state, we have already received the first upload request. What // are we being asked to do now? // switch(psUSBRequest->bRequest) { // // The host is requesting more upload data. // case USBD_DFU_REQUEST_UPLOAD: { // // See if there is any more data to transfer and, if there is, // send it back to the host. // if(!SendUploadData(psUSBRequest->wLength, false)) { // // We sent less than a full packet of data so the transfer is // complete. Revert to idle state and ensure that we reset // our upload pointer and size to the default flash region. // g_eDFUState = STATE_IDLE; g_sNextUpload.pui8Start = (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr; g_sNextUpload.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop - g_sDFUDeviceInfo.ui32AppStartAddr); } break; } // // The host is requesting the current device status. // case USBD_DFU_REQUEST_GETSTATUS: { SendDFUStatus(); break; } // // The host is requesting the current device state. // case USBD_DFU_REQUEST_GETSTATE: { SendDFUState(); break; } // // The host is requesting that we abort the current upload. // case USBD_DFU_REQUEST_ABORT: { // // Default to sending the main application image for the next // upload. // g_sNextUpload.pui8Start = (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr; g_sNextUpload.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop - g_sDFUDeviceInfo.ui32AppStartAddr); g_eDFUState = STATE_IDLE; break; } // // Any other request is ignored and causes us to stall the control // endpoint and remain in STATE_ERROR. // default: { USBBLStallEP0(); break; } } } //***************************************************************************** // // Handle all incoming DFU requests while in state STATE_ERROR. // //***************************************************************************** void HandleRequestError(tUSBRequest *psUSBRequest) { // // In this state, we respond to state and status requests and also to // USBD_DFU_REQUEST_CLRSTATUS which clears the previous error condition. // switch(psUSBRequest->bRequest) { // // The host is requesting the current device status. // case USBD_DFU_REQUEST_GETSTATUS: { SendDFUStatus(); break; } // // The host is requesting the current device state. // case USBD_DFU_REQUEST_GETSTATE: { SendDFUState(); break; } // // The host is asking us to clear our previous error condition and // revert to idle state in preparation to receive new commands. // case USBD_DFU_REQUEST_CLRSTATUS: { g_eDFUState = STATE_IDLE; g_eDFUStatus = STATUS_OK; USBDevEndpoint0DataAck(false); break; } // // Any other request is ignored and causes us to stall the control // endpoint and remain in STATE_ERROR. // default: { USBBLStallEP0(); break; } } } //***************************************************************************** // // Handle cases where the host sets a new USB configuration. // //***************************************************************************** void HandleConfigChange(uint32_t ui32Info) { // // Revert to idle state. // g_eDFUState = STATE_IDLE; g_eDFUStatus = STATUS_OK; } //***************************************************************************** // // Setting the device address indicates that we are now connected to the host // and can expect some DFU communication so we use this opportunity to clean // out our state just in case we were not idle last time the host disconnected. // //***************************************************************************** void HandleSetAddress(void) { g_eDFUState = STATE_IDLE; g_eDFUStatus = STATUS_OK; g_bAddressSet = true; // // Default the download address to the app start address and valid length // to the whole of the programmable flash area. // g_sNextDownload.pui8Start = (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr; g_sNextDownload.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop - g_sDFUDeviceInfo.ui32AppStartAddr); // // Default the upload address to the app start address and valid length // to the whole of the programmable flash area. // g_sNextUpload.pui8Start = (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr; g_sNextUpload.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop - g_sDFUDeviceInfo.ui32AppStartAddr); } //***************************************************************************** // // Check that a range of addresses passed is within the region of flash that // the boot loader is allowed to access. // // Returns true if the address range is accessible or false otherwise. // //***************************************************************************** bool FlashRangeCheck(uint32_t ui32Start, uint32_t ui32Length) { #ifdef ENABLE_BL_UPDATE if((ui32Length <= (g_sDFUDeviceInfo.ui32FlashTop - g_sDFUDeviceInfo.ui32AppStartAddr)) && ((ui32Start + ui32Length) <= g_sDFUDeviceInfo.ui32FlashTop)) #else if((ui32Start >= g_sDFUDeviceInfo.ui32AppStartAddr) && (ui32Length <= (g_sDFUDeviceInfo.ui32FlashTop - g_sDFUDeviceInfo.ui32AppStartAddr)) && ((ui32Start + ui32Length) <= g_sDFUDeviceInfo.ui32FlashTop)) #endif { // // The block passed lies wholly within the flash address range of // this device. // return(true); } else { // // We were passed an address that is out of range so set the // appropriate status code. // g_eDFUStatus = STATUS_ERR_ADDRESS; return(false); } } //***************************************************************************** // //! Process TIVA-specific commands passed via DFU download requests. //! //! \param psCmd is a pointer to the first byte of the \b DFU_DNLOAD payload //! that is expected to hold a command. //! \param ui32Size is the number of bytes of data pointed to by \e psCmd. //! This function is called when a DFU download command is received while in //! \b STATE_IDLE. New downloads are assumed to contain a prefix structure //! containing one of several TIVA-specific commands and this function //! is responsible for parsing the download data and processing whichever //! command is contained within it. //! //! \return Returns \b true on success or \b false on failure. // //***************************************************************************** bool ProcessDFUDnloadCommand(tDFUDownloadHeader *psCmd, uint32_t ui32Size) { // // Make sure we got enough data to contain a valid command header. // if(ui32Size < sizeof(tDFUDownloadHeader)) { return(false); } // // Remember the command that we have been passed since we will need thi // to determine which state to transition to on exit from STATE_DNLOAD_SYNC. // g_ui8LastCommand = psCmd->ui8Command; // // Which command have we been passed? // switch(psCmd->ui8Command) { // // We are being asked to start a programming operation. // case DFU_CMD_PROG: { tDFUDownloadProgHeader *psHdr; // // Extract the address and size from the command header. // psHdr = (tDFUDownloadProgHeader *)psCmd; // // Is the passed address range valid? // if(BL_FLASH_AD_CHECK_FN_HOOK(psHdr->ui16StartAddr * 1024, psHdr->ui32Length)) { // // Yes - remember the range passed so that we will write the // passed data to the correct place. // g_sNextDownload.pui8Start = (uint8_t *)(psHdr->ui16StartAddr * 1024); g_sNextDownload.ui32Length = psHdr->ui32Length; // // If we have been provided with a progress reporting hook // function, remember the total length of the image so that // we can report this later. // #ifdef BL_PROGRESS_FN_HOOK g_ui32ImageSize = psHdr->ui32Length; #endif // // Also set the upload address and size to match this download // so that, by default, the host will get back what it just // wrote if it performs an upload without an intermediate // DFU_CMD_READ to set the address and size. // g_sNextUpload.pui8Start = (uint8_t *)(psHdr->ui16StartAddr * 1024); g_sNextUpload.ui32Length = psHdr->ui32Length; // // Also remember that we have data in this packet to write. // g_pui8DFUWrite = (uint8_t *)(psHdr + 1); g_ui16DFUBufferUsed = ui32Size - sizeof(tDFUDownloadHeader); // // If a start signal hook function has been provided, call it // here since we are about to start a new download. // #ifdef BL_START_FN_HOOK BL_START_FN_HOOK(); #endif // // If FLASH_CODE_PROTECTION is defined in bl_config.h we // erase the whole application area at this point before we // start to flash the new image. // #ifdef FLASH_CODE_PROTECTION g_sErase.pui8Start = (uint8_t *)g_sDFUDeviceInfo.ui32AppStartAddr; g_sErase.ui32Length = (g_sDFUDeviceInfo.ui32FlashTop - g_sDFUDeviceInfo.ui32AppStartAddr); HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_ERASE) = 1; #endif // // Tell the main thread to write the data we just received it. // HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_WRITE) = 1; } else { // // The flash range was invalid so switch to error state. // return(false); } break; } // // We are being passed the position and size of a block of flash to // return in a following upload operation. // case DFU_CMD_READ: { tDFUDownloadReadCheckHeader *psHdr; // // Extract the address and size from the command header. // psHdr = (tDFUDownloadReadCheckHeader *)psCmd; // // Is the passed address range valid? // if(FlashRangeCheck(psHdr->ui16StartAddr * 1024, psHdr->ui32Length)) { // // Yes - remember the range passed so that we will return // this block of flash on the next upload request. // g_sNextUpload.pui8Start = (uint8_t *)(psHdr->ui16StartAddr * 1024); g_sNextUpload.ui32Length = psHdr->ui32Length; } else { // // The flash range was invalid so switch to error state. // return(false); } break; } // // We are being passed the position and size of a block of flash which // we will check to ensure that it is erased. // case DFU_CMD_CHECK: { tDFUDownloadReadCheckHeader *psHdr; uint32_t *pui32Check; uint32_t ui32Loop; // // Extract the address and size from the command header. // psHdr = (tDFUDownloadReadCheckHeader *)psCmd; // // Make sure the range we have been passed is within the area of // flash that we are allowed to look at. // if(FlashRangeCheck(psHdr->ui16StartAddr * 1024, psHdr->ui32Length)) { // // The range is valid so perform the check here. // pui32Check = (uint32_t *)(psHdr->ui16StartAddr * 1024); // // Check each word in the range to ensure that it is erased. If // not, set the error status and return. // for(ui32Loop = 0; ui32Loop < (psHdr->ui32Length / 4); ui32Loop++) { if(*pui32Check != 0xFFFFFFFF) { g_eDFUStatus = STATUS_ERR_CHECK_ERASED; return(false); } pui32Check++; } // // If we get here, the check passed so set the status to // indicate this. // g_eDFUStatus = STATUS_OK; } else { // // The flash range was invalid so switch to error state. // return(false); } break; } // // We are being asked to erase a block of flash. // case DFU_CMD_ERASE: { tDFUDownloadEraseHeader *psHdr; // // Extract the address and size from the command header. // psHdr = (tDFUDownloadEraseHeader *)psCmd; // // Make sure the range we have been passed is within the area of // flash that we are allowed to look at. // if(FlashRangeCheck((uint32_t)psHdr->ui16StartAddr * 1024, ((uint32_t)psHdr->ui16NumBlocks * DFU_REPORTED_PAGE_SIZE ))) { // // The range is valid so tell the main loop to erase the // block. // g_sErase.pui8Start = (uint8_t *) ((uint32_t)psHdr->ui16StartAddr * 1024); g_sErase.ui32Length = ((uint32_t)psHdr->ui16NumBlocks * DFU_REPORTED_PAGE_SIZE); HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_ERASE) = 1; } else { // // The flash range was invalid so switch to error state. // return(false); } break; } // // We are being asked to send back device information on the next // upload request. // case DFU_CMD_INFO: { // // Register that we need to send the device info structure on the // next upload request. // g_sNextUpload.pui8Start = (uint8_t *)&g_sDFUDeviceInfo; g_sNextUpload.ui32Length = sizeof(tDFUDeviceInfo); // // Make sure we don't append the DFU_CMD_PROG header when we send // back the data. // g_bSuppressUploadHeader = true; break; } // // We are being asked to set the format of uploaded images. // case DFU_CMD_BIN: { tDFUDownloadBinHeader *psHdr; // // Extract the required format the command header. // psHdr = (tDFUDownloadBinHeader *)psCmd; // // Set the global format appropriately. // g_bUploadBinary = psHdr->bBinary ? true : false; break; } // // We are being asked to prepare to reset the board and, as a result, // run the main application image. // case DFU_CMD_RESET: { // // Tell the main thread that it's time to go bye-bye... // HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_RESET) = 1; break; } // // We have been passed an unrecognized command identifier so report an // error. // default: { g_eDFUStatus = STATUS_ERR_VENDOR; return(false); } } return(true); } //***************************************************************************** // // This callback function is called when data is received for the DATA phase // of an EP0 OUT transaction. This data will either be a block of download // data (if we are in STATE_DNLOAD_IDLE) or a new command (if we are in // STATE_IDLE). // //***************************************************************************** void HandleEP0Data(uint32_t ui32Size) { bool bRetcode; if(g_eDFUState == STATE_IDLE) { // // This must be a new DFU download command header so parse it and // determine what to do next. // bRetcode = ProcessDFUDnloadCommand((tDFUDownloadHeader *)g_pui8DFUBuffer, ui32Size); // // Did we receive a recognized and valid command? // if(!bRetcode) { // // No - set the error state. The status is set within the // ProcessDFUDnloadCommand() function. // g_eDFUState = STATE_ERROR; return; } } else { // // If we are not in STATE_IDLE, this must be a block of data for an // ongoing download so signal the main thread to write it to flash. // g_ui16DFUBufferUsed = (uint16_t)ui32Size; g_pui8DFUWrite = g_pui8DFUBuffer; // // Tell the main thread to write the new data. // HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_WRITE) = 1; } // // Move to STATE_DNLOAD_SYNC since we now expect USBD_DFU_REQUEST_GETSTATUS // before the next USBD_DFU_REQUEST_DNLOAD. // g_eDFUState = STATE_DNLOAD_SYNC; } //***************************************************************************** // // Handle bus resets // // This function is called if the USB controller detects a reset condition on // the bus. If we are not in the process of downloading a new image, we use // this as a signal to reboot and run the main application image. // //***************************************************************************** void HandleReset(void) { // // Are we currently in the middle of a download operation? // if((g_eDFUState != STATE_DNLOAD_IDLE) && (g_eDFUState != STATE_DNLOAD_SYNC) && (g_eDFUState != STATE_IDLE)) { // // No - tell the main thread that it should reboot the system assuming // that we are already configured. If we don't check that we are // already configured, this will cause a reset during initial // enumeration and that wouldn't be very helpful. // if(g_bAddressSet) { HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_RESET) = 1; } } } //***************************************************************************** // // Handle cases where the USB host disconnects. // //***************************************************************************** void HandleDisconnect(void) { // // For error resilience, it may be desireable to note if the host // disconnects and, if partway through a main image download, clear the // first block of the flash to ensure that the image is not considered // valid on the next boot. For now, however, we merely wait for the host // to connect again, remaining in DFU mode. // // // Remember that we are waiting for enumeration. // g_bAddressSet = false; } //***************************************************************************** // // Erase a single block of flash // // This function erases a single, 1KB block of flash, returning once the // operation has completed. // // \return None. // //***************************************************************************** static void EraseFlashBlock(uint32_t ui32Addr) { BL_FLASH_ERASE_FN_HOOK(ui32Addr); } //***************************************************************************** // //! This is the main routine for handling updating over USB. //! //! This function forms the main loop of the USB DFU updater. It polls for //! commands sent from the USB request handlers and is responsible for //! erasing flash blocks, programming data into erased blocks and resetting //! the device. //! //! \return None. // //***************************************************************************** void UpdaterUSB(void) { uint32_t ui32Idx, ui32Start, ui32Temp; uint16_t ui16Used; #ifndef FLASH_CODE_PROTECTION uint32_t ui32End; #endif // // Loop forever waiting for the USB interrupt handlers to tell us to do // something. // while(1) { while(g_ui32CommandFlags == 0) { // // Wait for something to do. // } // // Are we being asked to perform a system reset? // if(HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_RESET)) { // // Time to go bye-bye... This will cause the microcontroller // to reset; no further code will be executed. // HWREG(NVIC_APINT) = NVIC_APINT_VECTKEY | NVIC_APINT_SYSRESETREQ; // // The microcontroller should have reset, so this should never be // reached. Just in case, loop forever. // while(1) { } } // // Are we being asked to erase a range of blocks in flash? // if(HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_ERASE)) { // // Loop through the pages in the block of flash we have been asked // to erase and clear each one. // ui32Temp = g_sErase.ui32Length; for(ui32Idx = (uint32_t)g_sErase.pui8Start; ui32Idx < (uint32_t)(g_sErase.pui8Start + ui32Temp); ui32Idx += FLASH_PAGE_SIZE) { EraseFlashBlock(ui32Idx); } // // Clear the command flag to indicate that we are done. // HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_ERASE) = 0; } // // Are we being asked to program a block of flash? // if(HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_WRITE)) { // // Decrypt the data if required. // #ifdef BL_DECRYPT_FN_HOOK BL_DECRYPT_FN_HOOK(g_pui8DFUWrite, g_ui16DFUBufferUsed); #endif // // Where will the new block be written? // ui32Start = (uint32_t)(g_sNextDownload.pui8Start); #ifndef FLASH_CODE_PROTECTION // // What is the address of the last byte we will write in this // block of data? We copy g_ui16DFUBufferUsed to prevent warnings // about "undefined order of volatile accesses" from some // compilers. // ui16Used = g_ui16DFUBufferUsed; ui32End = (uint32_t)g_sNextDownload.pui8Start + ui16Used - 1; // // Are we writing data at the start of a new flash block? If so, // we need to erase the content of the block first. // if((ui32Start & (FLASH_PAGE_SIZE - 1)) == 0) { // // We are writing to the start of a block so erase it. // EraseFlashBlock(ui32Start & ~(FLASH_PAGE_SIZE - 1)); } else { // // Will this block of data straddle two flash blocks? If so, // we need to erase the following block. // if((ui32Start & ~(FLASH_PAGE_SIZE - 1)) != (ui32End & ~(FLASH_PAGE_SIZE - 1))) { EraseFlashBlock(ui32End & ~(FLASH_PAGE_SIZE - 1)); } } #endif // // Write the new block of data to the flash // BL_FLASH_PROGRAM_FN_HOOK(ui32Start, g_pui8DFUWrite, ui16Used); // // Update our position and remaining size. // g_sNextDownload.pui8Start += ui16Used; g_sNextDownload.ui32Length -= ui16Used; // // Clear the command flag to indicate that we are done. // HWREGBITW(&g_ui32CommandFlags, CMD_FLAG_WRITE) = 0; // // If a progress hook function has been provided, call // it here. // #ifdef BL_PROGRESS_FN_HOOK BL_PROGRESS_FN_HOOK(g_ui32ImageSize - g_sNextDownload.ui32Length, g_ui32ImageSize); #endif // // If we just finished the download and an end signal hook function // has been provided, call it too. // #ifdef BL_END_FN_HOOK if(g_sNextDownload.ui32Length == 0) { BL_END_FN_HOOK(); } #endif } } } //***************************************************************************** // //! Configure the USB controller and place the DFU device on the bus. //! //! This function configures the USB controller for DFU device operation, //! initializes the state machines required to control the firmware update and //! places the device on the bus in preparation for requests from the host. It //! is assumed that the main system clock has been configured at this point. //! //! \return None. // //***************************************************************************** void ConfigureUSBInterface(void) { uint32_t ui32FlashSize; // // Initialize our device information structure. // ui32FlashSize = BL_FLASH_SIZE_FN_HOOK(); g_sDFUDeviceInfo.ui16FlashBlockSize = DFU_REPORTED_PAGE_SIZE; g_sDFUDeviceInfo.ui16NumFlashBlocks = ui32FlashSize / DFU_REPORTED_PAGE_SIZE; g_sDFUDeviceInfo.ui32ClassInfo = HWREG(SYSCTL_DID0); g_sDFUDeviceInfo.ui32PartInfo = HWREG(SYSCTL_DID1); g_sDFUDeviceInfo.ui32AppStartAddr = APP_START_ADDRESS; #ifdef FLASH_RSVD_SPACE g_sDFUDeviceInfo.ui32FlashTop = ui32FlashSize - FLASH_RSVD_SPACE; #else g_sDFUDeviceInfo.ui32FlashTop = ui32FlashSize; #endif // // Publish our DFU device descriptors and place the device on the bus. // USBBLInit(); } #if (defined USB_HAS_MUX) || (defined DOXYGEN) //***************************************************************************** // //! Configures and set the mux selecting USB device-mode operation. //! //! On target boards which use a multiplexer to switch between USB host and //! device operation, this function is used to configure the relevant GPIO //! pin and drive it such that the mux selects USB device-mode operation. //! If \b USB_HAS_MUX is not defined in bl_config.h, this function is compiled //! out. //! //! \return None. // //***************************************************************************** static void SetUSBMux(void) { // // Enable the GPIO peripheral that contains the mux control pin. // HWREG(SYSCTL_RCGC2) |= USB_MUX_PERIPH; // // Delay a very short period before we access the newly-enabled peripheral. // Delay(1); // // Make the pin be an output. // HWREG(USB_MUX_PORT + GPIO_O_DIR) |= (1 << USB_MUX_PIN); HWREG(USB_MUX_PORT + GPIO_O_AFSEL) &= ~(1 << USB_MUX_PIN); // // Set the output drive strength to 2mA. // HWREG(USB_MUX_PORT + GPIO_O_DR2R) |= (1 << USB_MUX_PIN); HWREG(USB_MUX_PORT + GPIO_O_DR4R) &= ~(1 << USB_MUX_PIN); HWREG(USB_MUX_PORT + GPIO_O_DR8R) &= ~(1 << USB_MUX_PIN); HWREG(USB_MUX_PORT + GPIO_O_SLR) &= ~(1 << USB_MUX_PIN); // // Set the pin type to a normal, GPIO output. // HWREG(USB_MUX_PORT + GPIO_O_ODR) &= ~(1 << USB_MUX_PIN); HWREG(USB_MUX_PORT + GPIO_O_PUR) &= ~(1 << USB_MUX_PIN); HWREG(USB_MUX_PORT + GPIO_O_PDR) &= ~(1 << USB_MUX_PIN); HWREG(USB_MUX_PORT + GPIO_O_DEN) |= (1 << USB_MUX_PIN); // // Clear this pin's bit in the analog mode select register. // HWREG(USB_MUX_PORT + GPIO_O_AMSEL) &= ~(1 << USB_MUX_PIN); // // Write the pin to the appropriate level to select USB device mode. // HWREG(USB_MUX_PORT + (GPIO_O_DATA + ((1 << USB_MUX_PIN) << 2))) = (USB_MUX_DEVICE ? (1 << USB_MUX_PIN) : 0); } #endif //***************************************************************************** // //! Generic configuration is handled in this function. //! //! This function is called by the start up code to perform any configuration //! necessary before calling the update routine. It is responsible for setting //! the system clock to the expected rate and setting flash programming //! parameters prior to calling ConfigureUSBInterface() to set up the USB //! hardware and place the DFU device on the bus. //! //! \return None. // //***************************************************************************** void ConfigureUSB(void) { // // Enable the main oscillator. // HWREG(SYSCTL_RCC) &= ~(SYSCTL_RCC_MOSCDIS); // // Delay while the main oscillator starts up. // Delay(524288); // // Set the crystal frequency, switch to the main oscillator, and enable the // PLL. // HWREG(SYSCTL_RCC) = ((HWREG(SYSCTL_RCC) & ~(SYSCTL_RCC_PWRDN | SYSCTL_RCC_XTAL_M | SYSCTL_RCC_OSCSRC_M)) | XTAL_VALUE | SYSCTL_RCC_OSCSRC_MAIN); // // Delay while the PLL locks. // Delay(524288); // // Disable the PLL bypass so that the part is clocked from the PLL, and set // sysdiv to 8. This yields a system clock of 25MHz. // HWREG(SYSCTL_RCC) = ((HWREG(SYSCTL_RCC) & ~(SYSCTL_RCC_BYPASS | SYSCTL_RCC_SYSDIV_M)) | ((8 - 1) << SYSCTL_RCC_SYSDIV_S) | SYSCTL_RCC_USESYSDIV); // // If the target device has a mux to allow selection of USB host or // device mode, make sure this is set to device mode. // #ifdef USB_HAS_MUX SetUSBMux(); #endif // // Configure the USB interface and put the device on the bus. // ConfigureUSBInterface(); } //***************************************************************************** // //! This is the application entry point to the USB updater. //! //! This function should only be entered from a running application and not //! when running the boot loader with no application present. If the //! calling application supports any USB device function, it must remove //! itself from the USB bus prior to calling this function. This function //! assumes that the calling application has already configured the system //! clock to run from the PLL. //! //! \return None. // //***************************************************************************** void AppUpdaterUSB(void) { // // Set sysdiv to 8. This yields a system clock of 25MHz. // HWREG(SYSCTL_RCC) = ((HWREG(SYSCTL_RCC) & ~(SYSCTL_RCC_SYSDIV_M)) | ((8 - 1) << SYSCTL_RCC_SYSDIV_S)); // // If the target device has a mux to allow selection of USB host or // device mode, make sure this is set to device mode. // #ifdef USB_HAS_MUX SetUSBMux(); #endif // // Configure the USB interface and put the device on the bus. // ConfigureUSBInterface(); // // Call the main update routine. // UpdaterUSB(); } //***************************************************************************** // // Close the Doxygen group. //! @} // //***************************************************************************** #endif