This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Good day,
We refer to the "USB Serial Device Firmware Upgrade" to try to build the bootloader,
/cfs-file/__key/communityserver-discussions-components-files/908/USB_5F00_Serial_5F00_DFU.pdf
except for modifying the chip type to fit our board (TM4C129), all other steps are done according to the manual instructions,
and encountered a problem with the USB device not being recognized.
We don't know where the problem is, please give me advice, thanks.
Ray Yang
Hello Ray,
The drivers referenced by that document are out dated and may not work for Windows 10.
Please use our updated USB drivers from here: https://software-dl.ti.com/tiva-c/SW-TM4C/2.1.4.178/exports/SW-TM4C-2.1.4.178.PATCH-1.0.zip
Alternatively if you have TivaWare 2.2.0.295 installed on your local machine, you can use the drivers located at [Install Path]\TivaWare_C_Series-2.2.0.295\windows_drivers
Best Regards.
Ralph Jacobi
Hello Ray,
That is expected because ProcessorInit is copying the code into SRAM and then executing within SRAM. Therefore the IDE does not have the symbols to debug further. It is possible to load these but I don't think we need to go to that step yet.
I had time to review your project in much more detail and I see that you set USB_PRODUCT_ID to be 0xFE. Please try setting it to be 0xFF. That could impact the enumeration of the device as our USB drivers are valid only for specific Vendor and Product ID's. This is documented on Page 22 of the app note you are referencing.
Best Regards,
Ralph Jacobi
Hi Ralph ,
In the past, I tried to change the USB_PRODUCT_ID to 0xff or 0xfe, but the situation did not improve.
Best Regards,
Ray Yang
Hello Ray,
You say 'in the past' - have you tried 0xFF with the latest USB drivers I directed you to before? Because if you used 0xFF with the old drivers, then it is very likely it would not have enumerated correctly.
Best Regards,
Ralph Jacobi
Hello Ray,
This afternoon I had the time to build and test the project you attached and re-create the issue. After a brief investigation this is due to an issue with the boot loader file provided for USB as part of the TivaWare library which is setting the wrong clock divisor.
Please use the attached updated bl_usbfuncs.c file. With the update I am getting the proper enumeration in Windows 10:
//***************************************************************************** // // bl_usbfuncs.c - The subset of USB library functions required by the USB DFU // boot loader. // // Copyright (c) 2008-2020 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.2.0.295 of the Tiva Firmware Development Package. // //***************************************************************************** #include <stdbool.h> #include <stdint.h> #include "inc/hw_types.h" #include "inc/hw_memmap.h" #include "inc/hw_usb.h" #include "inc/hw_sysctl.h" #include "inc/hw_nvic.h" #include "inc/hw_ints.h" #include "inc/hw_gpio.h" #include "bl_config.h" #include "boot_loader/bl_usbfuncs.h" //***************************************************************************** // //! \addtogroup bl_usb_api //! @{ // //***************************************************************************** #if defined(USB_ENABLE_UPDATE) || defined(DOXYGEN) //***************************************************************************** // // Local functions prototypes. // //***************************************************************************** static void USBDGetStatus(tUSBRequest *pUSBRequest); static void USBDClearFeature(tUSBRequest *pUSBRequest); static void USBDSetFeature(tUSBRequest *pUSBRequest); static void USBDSetAddress(tUSBRequest *pUSBRequest); static void USBDGetDescriptor(tUSBRequest *pUSBRequest); static void USBDSetDescriptor(tUSBRequest *pUSBRequest); static void USBDGetConfiguration(tUSBRequest *pUSBRequest); static void USBDSetConfiguration(tUSBRequest *pUSBRequest); static void USBDGetInterface(tUSBRequest *pUSBRequest); static void USBDSetInterface(tUSBRequest *pUSBRequest); static void USBDEP0StateTx(void); static int32_t USBDStringIndexFromRequest(uint16_t ui16Lang, uint16_t ui16Index); //***************************************************************************** // // This structure holds the full state for the device enumeration. // //***************************************************************************** typedef struct { // // The devices current address, this also has a change pending bit in the // MSB of this value specified by DEV_ADDR_PENDING. // volatile uint32_t ui32DevAddress; // // This holds the current active configuration for this device. // uint32_t ui32Configuration; // // This holds the current alternate interface for this device. We only have // 1 interface so only need to hold 1 setting. // uint8_t ui8AltSetting; // // This is the pointer to the current data being sent out or received // on endpoint zero. // uint8_t *pui8EP0Data; // // This is the number of bytes that remain to be sent from or received // into the g_sUSBDeviceState.pui8EP0Data data buffer. // volatile uint32_t ui32EP0DataRemain; // // The amount of data being sent/received due to a custom request. // uint32_t ui32OUTDataSize; // // Holds the current device status. // uint8_t ui8Status; // // This flag indicates whether or not remote wakeup signalling is in // progress. // bool bRemoteWakeup; // // During remote wakeup signalling, this counter is used to track the // number of milliseconds since the signalling was initiated. // uint8_t ui8RemoteWakeupCount; } tDeviceState; //***************************************************************************** // // The states for endpoint zero during enumeration. // //***************************************************************************** typedef enum { // // The USB device is waiting on a request from the host controller on // endpoint zero. // USB_STATE_IDLE, // // The USB device is sending data back to the host due to an IN request. // USB_STATE_TX, // // The USB device is receiving data from the host due to an OUT // request from the host. // USB_STATE_RX, // // The USB device has completed the IN or OUT request and is now waiting // for the host to acknowledge the end of the IN/OUT transaction. This // is the status phase for a USB control transaction. // USB_STATE_STATUS, // // This endpoint has signaled a stall condition and is waiting for the // stall to be acknowledged by the host controller. // USB_STATE_STALL } tEP0State; //***************************************************************************** // // Define the max packet size for endpoint zero. // //***************************************************************************** #define EP0_MAX_PACKET_SIZE 64 //***************************************************************************** // // This is a flag used with g_sUSBDeviceState.ui32DevAddress to indicate that a // device address change is pending. // //***************************************************************************** #define DEV_ADDR_PENDING 0x80000000 //***************************************************************************** // // This label defines the default configuration number to use after a bus // reset. // //***************************************************************************** #define DEFAULT_CONFIG_ID 1 //***************************************************************************** // // This label defines the number of milliseconds that the remote wakeup signal // must remain asserted before removing it. Section 7.1.7.7 of the USB 2.0 spec // states that "the remote wakeup device must hold the resume signaling for at // least 1ms but for no more than 15ms" so 10mS seems a reasonable choice. // //***************************************************************************** #define REMOTE_WAKEUP_PULSE_MS 10 //***************************************************************************** // // This label defines the number of milliseconds between the point where we // assert the remote wakeup signal and calling the client back to tell it that // bus operation has been resumed. This value is based on the timings provided // in section 7.1.7.7 of the USB 2.0 specification which indicates that the host // (which takes over resume signalling when the device's initial signal is // detected) must hold the resume signalling for at least 20mS. // //***************************************************************************** #define REMOTE_WAKEUP_READY_MS 20 //***************************************************************************** // // The buffer for reading data coming into EP0 // //***************************************************************************** static uint8_t g_pui8DataBufferIn[EP0_MAX_PACKET_SIZE]; //***************************************************************************** // // This global holds the current state information for the USB device. // //***************************************************************************** static volatile tDeviceState g_sUSBDeviceState; //***************************************************************************** // // This global holds the current state of endpoint zero. // //***************************************************************************** static volatile tEP0State g_eUSBDEP0State = USB_STATE_IDLE; //***************************************************************************** // // Function table to handle standard requests. // //***************************************************************************** static const tStdRequest g_ppfnUSBDStdRequests[] = { USBDGetStatus, USBDClearFeature, 0, USBDSetFeature, 0, USBDSetAddress, USBDGetDescriptor, USBDSetDescriptor, USBDGetConfiguration, USBDSetConfiguration, USBDGetInterface, USBDSetInterface, }; //***************************************************************************** // // Amount to shift the RX interrupt sources by in the flags used in the // interrupt calls. // //***************************************************************************** #define USB_INT_RX_SHIFT 8 //***************************************************************************** // // Amount to shift the status interrupt sources by in the flags used in the // interrupt calls. // //***************************************************************************** #define USB_INT_STATUS_SHIFT 24 //***************************************************************************** // // Amount to shift the RX endpoint status sources by in the flags used in the // calls. // //***************************************************************************** #define USB_RX_EPSTATUS_SHIFT 16 //***************************************************************************** // // Converts from an endpoint specifier to the offset of the endpoint's // control/status registers. // //***************************************************************************** #define EP_OFFSET(Endpoint) (Endpoint - 0x10) //***************************************************************************** // // Retrieves data from endpoint 0's FIFO. // // \param pui8Data is a pointer to the data area used to return the data from // the FIFO. // \param pui32Size is initially the size of the buffer passed into this call // via the \e pui8Data parameter. It will be set to the amount of data // returned in the buffer. // // This function will return the data from the FIFO for endpoint 0. // The \e pui32Size parameter should indicate the size of the buffer passed in // the \e pui32Data parameter. The data in the \e pui32Size parameter will be // changed to match the amount of data returned in the \e pui8Data parameter. // If a zero byte packet was received this call will not return a error but // will instead just return a zero in the \e pui32Size parameter. The only // error case occurs when there is no data packet available. // // \return This call will return 0, or -1 if no packet was received. // //***************************************************************************** int32_t USBEndpoint0DataGet(uint8_t *pui8Data, uint32_t *pui32Size) { uint32_t ui32ByteCount; // // Don't allow reading of data if the RxPktRdy bit is not set. // if((HWREGH(USB0_BASE + USB_O_CSRL0) & USB_CSRL0_RXRDY) == 0) { // // Can't read the data because none is available. // *pui32Size = 0; // // Return a failure since there is no data to read. // return(-1); } // // Get the byte count in the FIFO. // ui32ByteCount = HWREGH(USB0_BASE + USB_O_COUNT0 + USB_EP_0); // // Determine how many bytes we will actually copy. // ui32ByteCount = (ui32ByteCount < *pui32Size) ? ui32ByteCount : *pui32Size; // // Return the number of bytes we are going to read. // *pui32Size = ui32ByteCount; // // Read the data out of the FIFO. // for(; ui32ByteCount > 0; ui32ByteCount--) { // // Read a byte at a time from the FIFO. // *pui8Data++ = HWREGB(USB0_BASE + USB_O_FIFO0 + (USB_EP_0 >> 2)); } // // Success. // return(0); } //***************************************************************************** // // Acknowledge that data was read from endpoint 0's FIFO. // // \param bIsLastPacket indicates if this is the last packet. // // This function acknowledges that the data was read from the endpoint 0's // FIFO. The \e bIsLastPacket parameter is set to a \b true value if this is // the last in a series of data packets. This call can be used if processing // is required between reading the data and acknowledging that the data has // been read. // // \return None. // //***************************************************************************** void USBDevEndpoint0DataAck(bool bIsLastPacket) { // // Clear RxPktRdy, and optionally DataEnd, on endpoint zero. // HWREGB(USB0_BASE + USB_O_CSRL0) = USB_CSRL0_RXRDYC | (bIsLastPacket ? USB_CSRL0_DATAEND : 0); } //***************************************************************************** // // Puts data into endpoint 0's FIFO. // // \param pui8Data is a pointer to the data area used as the source for the // data to put into the FIFO. // \param ui32Size is the amount of data to put into the FIFO. // // This function will put the data from the \e pui8Data parameter into the FIFO // for endpoint 0. If a packet is already pending for transmission then // this call will not put any of the data into the FIFO and will return -1. // // \return This call will return 0 on success, or -1 to indicate that the FIFO // is in use and cannot be written. // //***************************************************************************** int32_t USBEndpoint0DataPut(uint8_t *pui8Data, uint32_t ui32Size) { // // Don't allow transmit of data if the TxPktRdy bit is already set. // if(HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) & USB_CSRL0_TXRDY) { return(-1); } // // Write the data to the FIFO. // for(; ui32Size > 0; ui32Size--) { HWREGB(USB0_BASE + USB_O_FIFO0 + (USB_EP_0 >> 2)) = *pui8Data++; } // // Success. // return(0); } //***************************************************************************** // // Starts the transfer of data from endpoint 0's FIFO. // // \param ui32TransType is set to indicate what type of data is being sent. // // This function will start the transfer of data from the FIFO for // endpoint 0. This is necessary if the \b USB_EP_AUTO_SET bit was not enabled // for the endpoint. Setting the \e ui32TransType parameter will allow the // appropriate signaling on the USB bus for the type of transaction being // requested. The \e ui32TransType parameter should be one of the following: // // - USB_TRANS_OUT for OUT transaction on any endpoint in host mode. // - USB_TRANS_IN for IN transaction on any endpoint in device mode. // - USB_TRANS_IN_LAST for the last IN transactions on endpoint zero in a // sequence of IN transactions. // - USB_TRANS_SETUP for setup transactions on endpoint zero. // - USB_TRANS_STATUS for status results on endpoint zero. // // \return This call will return 0 on success, or -1 if a transmission is // already in progress. // //***************************************************************************** int32_t USBEndpoint0DataSend(uint32_t ui32TransType) { // // Don't allow transmit of data if the TxPktRdy bit is already set. // if(HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) & USB_CSRL0_TXRDY) { return(-1); } // // Set TxPktRdy in order to send the data. // HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) = ui32TransType & 0xff; // // Success. // return(0); } #if defined(USB_VBUS_CONFIG) || defined(USB_ID_CONFIG) || \ defined(USB_DP_CONFIG) || defined(USB_DM_CONFIG) || defined(DOXYGEN) //***************************************************************************** // //! Initialize the pins used by USB functions. //! //! This function configures the pins for USB functions depending on defines //! from the bl_config.h file. //! //! \return None. // //***************************************************************************** void USBConfigurePins(void) { // // Enable the clocks to the GPIOs. // HWREG(SYSCTL_RCGCGPIO) |= (0x0 | #if defined(USB_VBUS_CONFIG) USB_VBUS_PERIPH | #endif #if defined(USB_ID_CONFIG) USB_ID_PERIPH | #endif #if defined(USB_DP_CONFIG) USB_DP_PERIPH | #endif #if defined(USB_DM_CONFIG) USB_DM_PERIPH #endif ); // // Wait for the Peripherals to be Ready before accessing the register // address space. // while((HWREG(SYSCTL_PRGPIO) & (0x0 | #if defined(USB_VBUS_CONFIG) USB_VBUS_PERIPH | #endif #if defined(USB_ID_CONFIG) USB_ID_PERIPH | #endif #if defined(USB_DP_CONFIG) USB_DP_PERIPH | #endif #if defined(USB_DM_CONFIG) USB_DM_PERIPH #endif )) != (0x0 | #if defined(USB_VBUS_CONFIG) USB_VBUS_PERIPH | #endif #if defined(USB_ID_CONFIG) USB_ID_PERIPH | #endif #if defined(USB_DP_CONFIG) USB_DP_PERIPH | #endif #if defined(USB_DM_CONFIG) USB_DM_PERIPH #endif )); // // Setup the pins based on bl_config.h // #if defined(USB_VBUS_CONFIG) // // Set the VBUS pin to be an analog input. // HWREG(USB_VBUS_PORT + GPIO_O_DIR) &= ~(1 << USB_VBUS_PIN); HWREG(USB_VBUS_PORT + GPIO_O_AMSEL) |= (1 << USB_VBUS_PIN); #endif #if defined(USB_ID_CONFIG) // // Set the ID pin to be an analog input. // HWREG(USB_ID_PORT + GPIO_O_DIR) &= ~(1 << USB_ID_PIN); HWREG(USB_ID_PORT + GPIO_O_AMSEL) |= (1 << USB_ID_PIN); #endif #if defined(USB_DP_CONFIG) // // Set the DP pin to be an analog input. // HWREG(USB_DP_PORT + GPIO_O_DIR) &= ~(1 << USB_DP_PIN); HWREG(USB_DP_PORT + GPIO_O_AMSEL) |= (1 << USB_DP_PIN); #endif #if defined(USB_DM_CONFIG) // // Set the DM pin to be an analog input. // HWREG(USB_DM_PORT + GPIO_O_DIR) &= ~(1 << USB_DM_PIN); HWREG(USB_DM_PORT + GPIO_O_AMSEL) |= (1 << USB_DM_PIN); #endif } #endif //***************************************************************************** // //! Initialize the boot loader USB functions. //! //! This function initializes the boot loader USB functions and places the DFU //! device onto the USB bus. //! //! \return None. // //***************************************************************************** void USBBLInit(void) { // // Configure the USB Pins based on the bl_config.h settings. // #if defined(USB_VBUS_CONFIG) || defined(USB_ID_CONFIG) || \ defined(USB_DP_CONFIG) || defined(USB_DM_CONFIG) USBConfigurePins(); #endif // // Initialize a couple of fields in the device state structure. // g_sUSBDeviceState.ui32Configuration = DEFAULT_CONFIG_ID; // // Enable the USB controller. // HWREG(SYSCTL_RCGCUSB) = SYSCTL_RCGCUSB_R0; // // Wait for the peripheral ready // while((HWREG(SYSCTL_PRUSB) & SYSCTL_PRUSB_R0) != SYSCTL_PRUSB_R0) { } #if defined(TARGET_IS_TM4C129_RA0) || \ defined(TARGET_IS_TM4C129_RA1) || \ defined(TARGET_IS_TM4C129_RA2) // // Turn on USB Phy clock from PLL VCO // HWREG(USB0_BASE + USB_O_CC) = (USB_CC_CLKEN | (3 << USB_CC_CLKDIV_S)); #else // // Turn on USB Phy clock. // HWREG(SYSCTL_RCC2) &= ~SYSCTL_RCC2_USBPWRDN; #endif // // Clear any pending interrupts. // HWREGH(USB0_BASE + USB_O_TXIS); HWREGB(USB0_BASE + USB_O_IS); // // Enable USB Interrupts. // HWREGH(USB0_BASE + USB_O_TXIE) = USB_TXIS_EP0; HWREGB(USB0_BASE + USB_O_IE) = (USB_IS_DISCON | USB_IS_RESET); // // Default to the state where remote wakeup is disabled. // g_sUSBDeviceState.ui8Status = 0; g_sUSBDeviceState.bRemoteWakeup = false; // // Determine the self- or bus-powered state based on bl_config.h setting. // #if USB_BUS_POWERED g_sUSBDeviceState.ui8Status &= ~USB_STATUS_SELF_PWR; #else g_sUSBDeviceState.ui8Status |= USB_STATUS_SELF_PWR; #endif // // Attach the device using the soft connect. // HWREGB(USB0_BASE + USB_O_POWER) |= USB_POWER_SOFTCONN; // // Enable the USB interrupt. // HWREG(NVIC_EN1) = 1 << (INT_USB0 - 48); } //***************************************************************************** // // This function starts the request for data from the host on endpoint zero. // // \param pui8Data is a pointer to the buffer to fill with data from the USB // host. // \param ui32Size is the size of the buffer or data to return from the USB // host. // // This function handles retrieving data from the host when a custom command // has been issued on endpoint zero. When the requested data is received, // the function HandleEP0Data() will be called. // // \return None. // //***************************************************************************** void USBBLRequestDataEP0(uint8_t *pui8Data, uint32_t ui32Size) { // // Enter the RX state on end point 0. // g_eUSBDEP0State = USB_STATE_RX; // // Save the pointer to the data. // g_sUSBDeviceState.pui8EP0Data = pui8Data; // // Location to save the current number of bytes received. // g_sUSBDeviceState.ui32OUTDataSize = ui32Size; // // Bytes remaining to be received. // g_sUSBDeviceState.ui32EP0DataRemain = ui32Size; } //***************************************************************************** // //! This function requests transfer of data to the host on endpoint zero. //! //! \param pui8Data is a pointer to the buffer to send via endpoint zero. //! \param ui32Size is the amount of data to send in bytes. //! //! This function handles sending data to the host when a custom command is //! issued or non-standard descriptor has been requested on endpoint zero. //! //! \return None. // //***************************************************************************** void USBBLSendDataEP0(uint8_t *pui8Data, uint32_t ui32Size) { // // Return the externally provided device descriptor. // g_sUSBDeviceState.pui8EP0Data = pui8Data; // // The size of the device descriptor is in the first byte. // g_sUSBDeviceState.ui32EP0DataRemain = ui32Size; // // Save the total size of the data sent. // g_sUSBDeviceState.ui32OUTDataSize = ui32Size; // // Now in the transmit data state. // USBDEP0StateTx(); } //***************************************************************************** // //! This function generates a stall condition on endpoint zero. //! //! This function is typically called to signal an error condition to the host //! when an unsupported request is received by the device. It should be //! called from within the callback itself (in interrupt context) and not //! deferred until later since it affects the operation of the endpoint zero //! state machine. //! //! \return None. // //***************************************************************************** void USBBLStallEP0(void) { // // Perform a stall on endpoint zero. // HWREGB(USB0_BASE + USB_O_CSRL0) |= (USB_CSRL0_STALL | USB_CSRL0_RXRDYC); // // Enter the stalled state. // g_eUSBDEP0State = USB_STATE_STALL; } //***************************************************************************** // // This internal function reads a request data packet and dispatches it to // either a standard request handler or the registered device request // callback depending upon the request type. // // \return None. // //***************************************************************************** static void USBDReadAndDispatchRequest(void) { uint32_t ui32Size; tUSBRequest *pRequest; // // Cast the buffer to a request structure. // pRequest = (tUSBRequest *)g_pui8DataBufferIn; // // Set the buffer size. // ui32Size = EP0_MAX_PACKET_SIZE; // // Get the data from the USB controller end point 0. // USBEndpoint0DataGet(g_pui8DataBufferIn, &ui32Size); if(!ui32Size) { return; } // // See if this is a standard request or not. // if((pRequest->bmRequestType & USB_RTYPE_TYPE_M) != USB_RTYPE_STANDARD) { // // Pass this non-standard request on to the DFU handler // HandleRequests(pRequest); } else { // // Assure that the jump table is not out of bounds. // if((pRequest->bRequest < (sizeof(g_ppfnUSBDStdRequests) / sizeof(tStdRequest))) && (g_ppfnUSBDStdRequests[pRequest->bRequest] != 0)) { // // Jump table to the appropriate handler. // g_ppfnUSBDStdRequests[pRequest->bRequest](pRequest); } else { // // If there is no handler then stall this request. // USBBLStallEP0(); } } } //***************************************************************************** // // This is the low level interrupt handler for endpoint zero. // // This function handles all interrupts on endpoint zero in order to maintain // the state needed for the control endpoint on endpoint zero. In order to // successfully enumerate and handle all USB standard requests, all requests // on endpoint zero must pass through this function. The endpoint has the // following states: \b USB_STATE_IDLE, \b USB_STATE_TX, \b USB_STATE_RX, // \b USB_STATE_STALL, and \b USB_STATE_STATUS. In the \b USB_STATE_IDLE // state the USB controller has not received the start of a request, and once // it does receive the data for the request it will either enter the // \b USB_STATE_TX, \b USB_STATE_RX, or \b USB_STATE_STALL depending on the // command. If the controller enters the \b USB_STATE_TX or \b USB_STATE_RX // then once all data has been sent or received, it must pass through the // \b USB_STATE_STATUS state to allow the host to acknowledge completion of // the request. The \b USB_STATE_STALL is entered from \b USB_STATE_IDLE in // the event that the USB request was not valid. Both the \b USB_STATE_STALL // and \b USB_STATE_STATUS are transitional states that return to the // \b USB_STATE_IDLE state. // // \return None. // // USB_STATE_IDLE -*--> USB_STATE_TX -*-> USB_STATE_STATUS -*->USB_STATE_IDLE // | | | // |--> USB_STATE_RX - | // | | // |--> USB_STATE_STALL ---------->--------- // // ---------------------------------------------------------------- // | Current State | State 0 | State 1 | // | --------------------|-------------------|---------------------- // | USB_STATE_IDLE | USB_STATE_TX/RX | USB_STATE_STALL | // | USB_STATE_TX | USB_STATE_STATUS | | // | USB_STATE_RX | USB_STATE_STATUS | | // | USB_STATE_STATUS | USB_STATE_IDLE | | // | USB_STATE_STALL | USB_STATE_IDLE | | // ---------------------------------------------------------------- // //***************************************************************************** void USBDeviceEnumHandler(void) { uint32_t ui32EPStatus; // // Get the TX portion of the endpoint status. // ui32EPStatus = HWREGH(USB0_BASE + EP_OFFSET(USB_EP_0) + USB_O_TXCSRL1); // // Get the RX portion of the endpoint status. // ui32EPStatus |= ((HWREGH(USB0_BASE + EP_OFFSET(USB_EP_0) + USB_O_RXCSRL1)) << USB_RX_EPSTATUS_SHIFT); // // What state are we currently in? // switch(g_eUSBDEP0State) { // // Handle the status state, this is a transitory state from // USB_STATE_TX or USB_STATE_RX back to USB_STATE_IDLE. // case USB_STATE_STATUS: { // // Just go back to the idle state. // g_eUSBDEP0State = USB_STATE_IDLE; // // If there is a pending address change then set the address. // if(g_sUSBDeviceState.ui32DevAddress & DEV_ADDR_PENDING) { // // Clear the pending address change and set the address. // g_sUSBDeviceState.ui32DevAddress &= ~DEV_ADDR_PENDING; HWREGB(USB0_BASE + USB_O_FADDR) = (uint8_t)g_sUSBDeviceState.ui32DevAddress; } // // If a new packet is already pending, we need to read it // and handle whatever request it contains. // if(ui32EPStatus & USB_DEV_EP0_OUT_PKTRDY) { // // Process the newly arrived packet. // USBDReadAndDispatchRequest(); } break; } // // In the IDLE state the code is waiting to receive data from the host. // case USB_STATE_IDLE: { // // Is there a packet waiting for us? // if(ui32EPStatus & USB_DEV_EP0_OUT_PKTRDY) { // // Yes - process it. // USBDReadAndDispatchRequest(); } break; } // // Data is still being sent to the host so handle this in the // EP0StateTx() function. // case USB_STATE_TX: { USBDEP0StateTx(); break; } // // Handle the receive state for commands that are receiving data on // endpoint zero. // case USB_STATE_RX: { uint32_t ui32DataSize; // // Set the number of bytes to get out of this next packet. // if(g_sUSBDeviceState.ui32EP0DataRemain > EP0_MAX_PACKET_SIZE) { // // Don't send more than EP0_MAX_PACKET_SIZE bytes. // ui32DataSize = EP0_MAX_PACKET_SIZE; } else { // // There was space so send the remaining bytes. // ui32DataSize = g_sUSBDeviceState.ui32EP0DataRemain; } // // Get the data from the USB controller end point 0. // USBEndpoint0DataGet(g_sUSBDeviceState.pui8EP0Data, &ui32DataSize); // // If there we not more that EP0_MAX_PACKET_SIZE or more bytes // remaining then this transfer is complete. If there were exactly // EP0_MAX_PACKET_SIZE remaining then there still needs to be // null packet sent before this is complete. // if(g_sUSBDeviceState.ui32EP0DataRemain < EP0_MAX_PACKET_SIZE) { // // Need to ack the data on end point 0 in this case // without setting data end. // USBDevEndpoint0DataAck(true); // // Return to the idle state. // g_eUSBDEP0State = USB_STATE_IDLE; // // If there is a receive callback then call it. // if(g_sUSBDeviceState.ui32OUTDataSize != 0) { // // Call the receive handler to handle the data // that was received. // HandleEP0Data(g_sUSBDeviceState.ui32OUTDataSize); // // Indicate that there is no longer any data being waited // on. // g_sUSBDeviceState.ui32OUTDataSize = 0; } } else { // // Need to ack the data on end point 0 in this case // without setting data end. // USBDevEndpoint0DataAck(false); } // // Advance the pointer. // g_sUSBDeviceState.pui8EP0Data += ui32DataSize; // // Decrement the number of bytes that are being waited on. // g_sUSBDeviceState.ui32EP0DataRemain -= ui32DataSize; break; } // // The device stalled endpoint zero so check if the stall needs to be // cleared once it has been successfully sent. // case USB_STATE_STALL: { // // If we sent a stall then acknowledge this interrupt. // if(ui32EPStatus & USB_DEV_EP0_SENT_STALL) { // // Clear the stall condition. // HWREGB(USB0_BASE + USB_O_CSRL0) &= ~(USB_DEV_EP0_SENT_STALL); // // Reset the global end point 0 state to IDLE. // g_eUSBDEP0State = USB_STATE_IDLE; } break; } // // Halt on an unknown state, but only in DEBUG mode builds. // default: { #ifdef DEBUG while(1); #endif break; } } } //***************************************************************************** // // This function handles bus reset notifications. // // This function is called from the low level USB interrupt handler whenever // a bus reset is detected. It performs tidy-up as required and resets the // configuration back to defaults in preparation for descriptor queries from // the host. // // \return None. // //***************************************************************************** void USBDeviceEnumResetHandler(void) { // // Disable remote wakeup signalling (as per USB 2.0 spec 9.1.1.6). // g_sUSBDeviceState.ui8Status &= ~USB_STATUS_REMOTE_WAKE; g_sUSBDeviceState.bRemoteWakeup = false; // // Call the device dependent code to indicate a bus reset has occurred. // HandleReset(); // // Reset the default configuration identifier and alternate function // selections. // g_sUSBDeviceState.ui32Configuration = DEFAULT_CONFIG_ID; g_sUSBDeviceState.ui8AltSetting = 0; } //***************************************************************************** // // This function handles the GET_STATUS standard USB request. // // \param pUSBRequest holds the request type and endpoint number if endpoint // status is requested. // // This function handles responses to a Get Status request from the host // controller. A status request can be for the device, an interface or an // endpoint. If any other type of request is made this function will cause // a stall condition to indicate that the command is not supported. The // \e pUSBRequest structure holds the type of the request in the // bmRequestType field. If the type indicates that this is a request for an // endpoint's status, then the wIndex field holds the endpoint number. // // \return None. // //***************************************************************************** static void USBDGetStatus(tUSBRequest *pUSBRequest) { uint16_t ui16Data; // // Determine what type of status was requested. // switch(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M) { // // This was a Device Status request. // case USB_RTYPE_DEVICE: { // // Return the current status for the device. // ui16Data = g_sUSBDeviceState.ui8Status; break; } // // This was a Interface status request. // case USB_RTYPE_INTERFACE: { // // Interface status always returns 0. // ui16Data = 0; break; } // // This was an unknown request or a request for an endpoint (of which // we have none) so set a stall. // case USB_RTYPE_ENDPOINT: default: { // // Anything else causes a stall condition to indicate that the // command was not supported. // USBBLStallEP0(); return; } } // // Send the two byte status response. // g_sUSBDeviceState.ui32EP0DataRemain = 2; g_sUSBDeviceState.pui8EP0Data = (uint8_t *)&ui16Data; // // Send the response. // USBDEP0StateTx(); } //***************************************************************************** // // This function handles the CLEAR_FEATURE standard USB request. // // \param pUSBRequest holds the options for the Clear Feature USB request. // // This function handles device or endpoint clear feature requests. The // \e pUSBRequest structure holds the type of the request in the bmRequestType // field and the feature is held in the wValue field. For device, the only // clearable feature is the Remote Wake feature. This device request // should only be made if the descriptor indicates that Remote Wake is // implemented by the device. For endpoint requests the only clearable // feature is the ability to clear a halt on a given endpoint. If any other // requests are made, then the device will stall the request to indicate to // the host that the command was not supported. // // \return None. // //***************************************************************************** static void USBDClearFeature(tUSBRequest *pUSBRequest) { // // Determine what type of status was requested. // switch(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M) { // // This is a clear feature request at the device level. // case USB_RTYPE_DEVICE: { // // Only remote wake is clearable by this function. // if(USB_FEATURE_REMOTE_WAKE & pUSBRequest->wValue) { // // Clear the remote wake up state. // g_sUSBDeviceState.ui8Status &= ~USB_STATUS_REMOTE_WAKE; // // Need to ack the data on end point 0. // USBDevEndpoint0DataAck(true); } else { USBBLStallEP0(); } break; } // // This is an unknown request or one destined for an invalid endpoint. // case USB_RTYPE_ENDPOINT: default: { USBBLStallEP0(); return; } } } //***************************************************************************** // // This function handles the SET_FEATURE standard USB request. // // \param pUSBRequest holds the feature in the wValue field of the USB // request. // // This function handles device or endpoint set feature requests. The // \e pUSBRequest structure holds the type of the request in the bmRequestType // field and the feature is held in the wValue field. For device, the only // settable feature is the Remote Wake feature. This device request // should only be made if the descriptor indicates that Remote Wake is // implemented by the device. For endpoint requests the only settable feature // is the ability to issue a halt on a given endpoint. If any other requests // are made, then the device will stall the request to indicate to the host // that the command was not supported. // // \return None. // //***************************************************************************** static void USBDSetFeature(tUSBRequest *pUSBRequest) { // // Determine what type of status was requested. // switch(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M) { // // This is a set feature request at the device level. // case USB_RTYPE_DEVICE: { // // Only remote wake is setable by this function. // if(USB_FEATURE_REMOTE_WAKE & pUSBRequest->wValue) { // // Set the remote wakeup state. // g_sUSBDeviceState.ui8Status |= USB_STATUS_REMOTE_WAKE; // // Need to ack the data on end point 0. // USBDevEndpoint0DataAck(true); } else { USBBLStallEP0(); } break; } // // This is an unknown request or one destined for an invalid endpoint. // case USB_RTYPE_ENDPOINT: default: { USBBLStallEP0(); return; } } } //***************************************************************************** // // This function handles the SET_ADDRESS standard USB request. // // \param pUSBRequest holds the new address to use in the wValue field of the // USB request. // // This function is called to handle the change of address request from the // host controller. This can only start the sequence as the host must // acknowledge that the device has changed address. Thus this function sets // the address change as pending until the status phase of the request has // been completed successfully. This prevents the devices address from // changing and not properly responding to the status phase. // // \return None. // //***************************************************************************** static void USBDSetAddress(tUSBRequest *pUSBRequest) { // // The data needs to be acknowledged on end point 0 without setting data // end because there is no data coming. // USBDevEndpoint0DataAck(true); // // Save the device address as we cannot change address until the status // phase is complete. // g_sUSBDeviceState.ui32DevAddress = pUSBRequest->wValue | DEV_ADDR_PENDING; // // Transition directly to the status state since there is no data phase // for this request. // g_eUSBDEP0State = USB_STATE_STATUS; // // Clear the DFU status just in case we were in an error state last time // the device was accessed and we were unplugged and replugged (for a self- // powered implementation, of course). // HandleSetAddress(); } //***************************************************************************** // // This function handles the GET_DESCRIPTOR standard USB request. // // \param pUSBRequest holds the data for this request. // // This function will return all configured standard USB descriptors to the // host - device, config and string descriptors. Any request for a descriptor // which is not available will result in endpoint 0 being stalled. // // \return None. // //***************************************************************************** static void USBDGetDescriptor(tUSBRequest *pUSBRequest) { uint32_t ui32Stall; // // Default to no stall. // ui32Stall = 0; // // Which descriptor are we being asked for? // switch(pUSBRequest->wValue >> 8) { // // This request was for a device descriptor. // case USB_DTYPE_DEVICE: { // // Return the externally provided device descriptor. // g_sUSBDeviceState.pui8EP0Data = (uint8_t *)g_pui8DFUDeviceDescriptor; // // The size of the device descriptor is in the first byte. // g_sUSBDeviceState.ui32EP0DataRemain = g_pui8DFUDeviceDescriptor[0]; break; } // // This request was for a configuration descriptor. // case USB_DTYPE_CONFIGURATION: { uint8_t ui8Index; // // Which configuration are we being asked for? // ui8Index = (uint8_t)(pUSBRequest->wValue & 0xFF); // // Is this valid? // if(ui8Index != 0) { // // This is an invalid configuration index. Stall EP0 to // indicate a request error. // USBBLStallEP0(); g_sUSBDeviceState.pui8EP0Data = 0; g_sUSBDeviceState.ui32EP0DataRemain = 0; } else { // // Start by sending data from the beginning of the first // descriptor. // g_sUSBDeviceState.pui8EP0Data = (uint8_t *)g_pui8DFUConfigDescriptor; // // Get the size of the config descriptor (remembering that in // this case, we only have a single section) // g_sUSBDeviceState.ui32EP0DataRemain = *(uint16_t *)&(g_pui8DFUConfigDescriptor[2]); } break; } // // This request was for a string descriptor. // case USB_DTYPE_STRING: { int32_t i32Index; // // Determine the correct descriptor index based on the requested // language ID and index. // i32Index = USBDStringIndexFromRequest(pUSBRequest->wIndex, pUSBRequest->wValue & 0xFF); // // If the mapping function returned -1 then stall the request to // indicate that the request was not valid. // if(i32Index == -1) { USBBLStallEP0(); break; } // // Return the externally specified configuration descriptor. // g_sUSBDeviceState.pui8EP0Data = (uint8_t *)g_ppui8StringDescriptors[i32Index]; // // The total size of a string descriptor is in byte 0. // g_sUSBDeviceState.ui32EP0DataRemain = g_ppui8StringDescriptors[i32Index][0]; break; } // // Any other request is not handled by the default enumeration handler // so see if it needs to be passed on to another handler. // default: { // // All other requests are not handled. // USBBLStallEP0(); ui32Stall = 1; break; } } // // If there was no stall, ACK the data and see if data needs to be sent. // if(ui32Stall == 0) { // // Need to ack the data on end point 0 in this case without // setting data end. // USBDevEndpoint0DataAck(false); // // If this request has data to send, then send it. // if(g_sUSBDeviceState.pui8EP0Data) { // // If there is more data to send than is requested then just // send the requested amount of data. // if(g_sUSBDeviceState.ui32EP0DataRemain > pUSBRequest->wLength) { g_sUSBDeviceState.ui32EP0DataRemain = pUSBRequest->wLength; } // // Now in the transmit data state. Be careful to call the correct // function since we need to handle the config descriptor // differently from the others. // USBDEP0StateTx(); } } } //***************************************************************************** // // This function determines which string descriptor to send to satisfy a // request for a given index and language. // // \param ui16Lang is the requested string language ID. // \param ui16Index is the requested string descriptor index. // // When a string descriptor is requested, the host provides a language ID and // index to identify the string ("give me string number 5 in French"). This // function maps these two parameters to an index within our device's string // descriptor array which is arranged as multiple groups of strings with // one group for each language advertised via string descriptor 0. // // We assume that there are an equal number of strings per language and // that the first descriptor is the language descriptor and use this fact to // perform the mapping. // // \return The index of the string descriptor to return or -1 if the string // could not be found. // //***************************************************************************** static int32_t USBDStringIndexFromRequest(uint16_t ui16Lang, uint16_t ui16Index) { tString0Descriptor *pLang; uint32_t ui32NumLangs; uint32_t ui32NumStringsPerLang; uint32_t ui32Loop; // // First look for the trivial case where descriptor 0 is being // requested. This is the special case since descriptor 0 contains the // language codes supported by the device. // if(ui16Index == 0) { return(0); } // // How many languages does this device support? This is determined by // looking at the length of the first descriptor in the string table, // subtracting 2 for the header and dividing by two (the size of each // language code). // ui32NumLangs = (g_ppui8StringDescriptors[0][0] - 2) / 2; // // We assume that the table includes the same number of strings for each // supported language. We know the number of entries in the string table, // so how many are there for each language? This may seem an odd way to // do this (why not just have the application tell us in the device info // structure?) but it's needed since we didn't want to change the API // after the first release which did not support multiple languages. // ui32NumStringsPerLang = ((NUM_STRING_DESCRIPTORS - 1) / ui32NumLangs); // // Just to be sure, make sure that the calculation indicates an equal // number of strings per language. We expect the string table to contain // (1 + (strings_per_language * languages)) entries. // if((1 + (ui32NumStringsPerLang * ui32NumLangs)) != NUM_STRING_DESCRIPTORS) { return(-1); } // // Now determine which language we are looking for. It is assumed that // the order of the groups of strings per language in the table is the // same as the order of the language IDs listed in the first descriptor. // pLang = (tString0Descriptor *)(g_ppui8StringDescriptors[0]); // // Look through the supported languages looking for the one we were asked // for. // for(ui32Loop = 0; ui32Loop < ui32NumLangs; ui32Loop++) { // // Have we found the requested language? // if(pLang->wLANGID[ui32Loop] == ui16Lang) { // // Yes - calculate the index of the descriptor to send. // return((ui32NumStringsPerLang * ui32Loop) + ui16Index); } } // // If we drop out of the loop, the requested language was not found so // return -1 to indicate the error. // return(-1); } //***************************************************************************** // // This function handles the SET_DESCRIPTOR standard USB request. // // \param pUSBRequest holds the data for this request. // // This function currently is not supported and will respond with a Stall // to indicate that this command is not supported by the device. // // \return None. // //***************************************************************************** static void USBDSetDescriptor(tUSBRequest *pUSBRequest) { // // This function is not handled by default. // USBBLStallEP0(); } //***************************************************************************** // // This function handles the GET_CONFIGURATION standard USB request. // // \param pUSBRequest holds the data for this request. // // This function responds to a host request to return the current // configuration of the USB device. The function will send the configuration // response to the host and return. This value will either be 0 or the last // value received from a call to SetConfiguration(). // // \return None. // //***************************************************************************** static void USBDGetConfiguration(tUSBRequest *pUSBRequest) { uint8_t ui8Value; // // If we still have an address pending then the device is still not // configured. // if(g_sUSBDeviceState.ui32DevAddress & DEV_ADDR_PENDING) { ui8Value = 0; } else { ui8Value = (uint8_t)g_sUSBDeviceState.ui32Configuration; } g_sUSBDeviceState.ui32EP0DataRemain = 1; g_sUSBDeviceState.pui8EP0Data = &ui8Value; // // Send the single byte response. // USBDEP0StateTx(); } //***************************************************************************** // // This function handles the SET_CONFIGURATION standard USB request. // // \param pUSBRequest holds the data for this request. // // This function responds to a host request to change the current // configuration of the USB device. The actual configuration number is taken // from the structure passed in via \e pUSBRequest. // // \return None. // //***************************************************************************** static void USBDSetConfiguration(tUSBRequest *pUSBRequest) { // // Cannot set the configuration to one that does not exist so check the // enumeration structure to see how many valid configurations are present. // if(pUSBRequest->wValue > 1) { // // The passed configuration number is not valid. Stall the endpoint to // signal the error to the host. // USBBLStallEP0(); } else { // // Need to ack the data on end point 0. // USBDevEndpoint0DataAck(true); // // Save the configuration. // g_sUSBDeviceState.ui32Configuration = pUSBRequest->wValue; // // If passed a configuration other than 0 (which tells us that we are // not currently configured), configure the endpoints (other than EP0) // appropriately. // if(g_sUSBDeviceState.ui32Configuration) { // // Set the power state // #if USB_BUS_POWERED g_sUSBDeviceState.ui8Status &= ~USB_STATUS_SELF_PWR; #else g_sUSBDeviceState.ui8Status |= USB_STATUS_SELF_PWR; #endif } // // Do whatever needs to be done as a result of the config change. // HandleConfigChange(g_sUSBDeviceState.ui32Configuration); } } //***************************************************************************** // // This function handles the GET_INTERFACE standard USB request. // // \param pUSBRequest holds the data for this request. // // This function is called when the host controller request the current // interface that is in use by the device. This simply returns the value set // by the last call to SetInterface(). // // \return None. // //***************************************************************************** static void USBDGetInterface(tUSBRequest *pUSBRequest) { uint8_t ui8Value; // // If we still have an address pending then the device is still not // configured. // if(g_sUSBDeviceState.ui32DevAddress & DEV_ADDR_PENDING) { ui8Value = 0; } else { // // Is the interface number valid? // if(pUSBRequest->wIndex == 0) { // // Read the current alternate setting for the required interface. // ui8Value = g_sUSBDeviceState.ui8AltSetting; } else { // // An invalid interface number was specified. // USBBLStallEP0(); return; } } // // Send the single byte response. // g_sUSBDeviceState.ui32EP0DataRemain = 1; g_sUSBDeviceState.pui8EP0Data = &ui8Value; // // Send the single byte response. // USBDEP0StateTx(); } //***************************************************************************** // // This function handles the SET_INTERFACE standard USB request. // // \param pUSBRequest holds the data for this request. // // The DFU device supports a single interface with no alternate settings so // this handler is hardcoded assuming this configuration. // // \return None. // //***************************************************************************** static void USBDSetInterface(tUSBRequest *pUSBRequest) { if((pUSBRequest->wIndex == 0) && (pUSBRequest->wValue == 0)) { // // We were passed a valid interface number so acknowledge the request. // USBDevEndpoint0DataAck(true); } else { // // The values passed were not valid so stall endpoint 0. // USBBLStallEP0(); } } //***************************************************************************** // // This internal function handles sending data on endpoint zero. // // \return None. // //***************************************************************************** static void USBDEP0StateTx(void) { uint32_t ui32NumBytes; uint8_t *pui8Data; // // In the TX state on endpoint zero. // g_eUSBDEP0State = USB_STATE_TX; // // Set the number of bytes to send this iteration. // ui32NumBytes = g_sUSBDeviceState.ui32EP0DataRemain; // // Limit individual transfers to 64 bytes. // if(ui32NumBytes > EP0_MAX_PACKET_SIZE) { ui32NumBytes = EP0_MAX_PACKET_SIZE; } // // Save the pointer so that it can be passed to the USBEndpointDataPut() // function. // pui8Data = g_sUSBDeviceState.pui8EP0Data; // // Advance the data pointer and counter to the next data to be sent. // g_sUSBDeviceState.ui32EP0DataRemain -= ui32NumBytes; g_sUSBDeviceState.pui8EP0Data += ui32NumBytes; // // Put the data in the correct FIFO. // USBEndpoint0DataPut(pui8Data, ui32NumBytes); // // If this is exactly 64 then don't set the last packet yet. // if(ui32NumBytes == EP0_MAX_PACKET_SIZE) { // // There is more data to send or exactly 64 bytes were sent, this // means that there is either more data coming or a null packet needs // to be sent to complete the transaction. // USBEndpoint0DataSend(USB_TRANS_IN); } else { // // Now go to the status state and wait for the transmit to complete. // g_eUSBDEP0State = USB_STATE_STATUS; // // Send the last bit of data. // USBEndpoint0DataSend(USB_TRANS_IN_LAST); g_sUSBDeviceState.ui32OUTDataSize = 0; } } //***************************************************************************** // // Close the Doxygen group. //! @} // //***************************************************************************** #endif // USB_ENABLE_UPDATE
Best Regards,
Ralph Jacobi
Hi Ralph,
According to the instructions you provided, already the USB device can be successfully enumerated,
But the windows driver can not be installed.
We use this driver "SW-TM4C-2.1.4.178.PATCH-1.0".
Operating system: Windows 10
Ray Yang
Hi Ralph,
I can enter the following command on the application side,
to reset TM4C to bootloader mode, but then I encountered the USB enumeration failure again. (Port Reset Failed)
Please provide suggestions, thanks!
//
// Disable all processor interrupts. Instead of disabling them
// one at a time, a direct write to NVIC is done to disable all
// peripheral interrupts.
//
HWREG(NVIC_DIS0) = 0xffffffff;
HWREG(NVIC_DIS1) = 0xffffffff;
HWREG(NVIC_DIS2) = 0xffffffff;
HWREG(NVIC_DIS3) = 0xffffffff;
// Return control to the boot loader. This is a call to the
// SVC UpdateHandler in the boot loader and should never return.
// If it does, very bad things will likely happen.
(*((void (*)(void))(*(uint32_t *)0x2c)))();
Ray Yang
Hello Ray,
Is this happening with the boot loader built using the documentation you referenced before?
What have you changed since getting the proper enumeration versus now? You had the flash boot loader working before, so I'm really unclear what the issue is now.
Best Regards,
Ralph Jacobi
Hi Ralph,
I am developing based on this version of bootloaderusb_10Jun2022.zip, I can do it through TM4C by power on detection button to decide whether to enter bootloader mode, this is possible, USB enumeration is successful.
Then I use another way to reset the TM4C by issuing a command (jumpToBootloader()) from the application side,
into bootloader mode, the USB enumeration is failed.
The code is as follows.
void jumpToBootloader(void)
{
//
// Disable all processor interrupts. Instead of disabling them
// one at a time, a direct write to NVIC is done to disable all
// peripheral interrupts.
//
HWREG(NVIC_DIS0) = 0xffffffff;
HWREG(NVIC_DIS1) = 0xffffffff;
HWREG(NVIC_DIS2) = 0xffffffff;
HWREG(NVIC_DIS3) = 0xffffffff;
// Return control to the boot loader. This is a call to the
// SVC UpdateHandler in the boot loader and should never return.
// If it does, very bad things will likely happen.
(*((void (*)(void))(*(uint32_t *)0x2c)))();
}
Ray Yang
Hi Ray,
I will suggest you debug the problem by putting breakpoints and do single-step on bl_startup_ccs.s file. After you execute (*((void (*)(void))(*(uint32_t *)0x2c)))() the processor should jump to 0x2C for the SVC call. As you can see it will then jump to the vector at UpdateHandler.
.word 0 ;; Offset 28: Reserved .word UpdateHandler - 0x20000000 ;; Offset 2C: SVCall handler .word IntDefaultHandler ;; Offset 30: Debug monitor handler
Look at UpdateHandler and it eventually should call AppUpdaterUSB. Are you using the default AppUpdaterUSB that is in bl_usb.c or you have your custom function? You need to debug your code by starting from bl_startup_ccs.s file and then see if it jumps to AppUpdaterUSB or your custom function if you modify bl_startup_ccs.s. If you customize AppUpdaterUSB then you need to find out why it does not enumerate again.
UpdateHandler: .asmfunc ;; ;; Initialize the processor. ;; bl ProcessorInit ;; ;; Load the stack pointer from the vector table. ;; movs r0, #0x0000 ldr sp, [r0] ;; ;; Call the user-supplied low level hardware initialization function ;; if provided. ;; .if $$defined(BL_HW_INIT_FN_HOOK) bl BL_HW_INIT_FN_HOOK .endif ;; ;; Call the user-supplied re-initialization function if provided. ;; .if $$defined(BL_REINIT_FN_HOOK) .ref BL_REINIT_FN_HOOK bl BL_REINIT_FN_HOOK .endif ;; ;; Branch to the update handler. ;; .if $$defined(ENET_ENABLE_UPDATE) b UpdateBOOTP .elseif $$defined(CAN_ENABLE_UPDATE) .ref AppUpdaterCAN b AppUpdaterCAN .elseif $$defined(USB_ENABLE_UPDATE) .ref AppUpdaterUSB b AppUpdaterUSB .else b Updater .endif .endasmfunc
Hi Charles,
Thank you for your reply,
AppUpdaterUSB() and bl_startup_ccs.s from the bootloader example, they are default, I didn't modify it,
but I'll still try to find out the reason.
Ray Yang
Hi Ray,
After you loaded the application firmware and if you want to debug the bootloader then you need to load symbols for the bootloader program.