diff --git a/Demos/Host/LowLevel/MassStorageHost/Lib/MassStoreCommands.c b/Demos/Host/LowLevel/MassStorageHost/Lib/MassStoreCommands.c index 0d8a231f2e364b5c18f278344d3a323e73841237..c86e51b0c57b6c070dd304a662e2458c86eb27e9 100644 --- a/Demos/Host/LowLevel/MassStorageHost/Lib/MassStoreCommands.c +++ b/Demos/Host/LowLevel/MassStorageHost/Lib/MassStoreCommands.c @@ -110,20 +110,23 @@ static uint8_t MassStore_SendCommand(CommandBlockWrapper_t* const SCSICommandBlo */ static uint8_t MassStore_WaitForDataReceived(void) { - uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS; + uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS; + uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber(); /* Select the IN data pipe for data reception */ Pipe_SelectPipe(MASS_STORE_DATA_IN_PIPE); Pipe_Unfreeze(); - + /* Wait until data received in the IN pipe */ while (!(Pipe_IsINReceived())) { + uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber(); + /* Check to see if a new frame has been issued (1ms elapsed) */ - if (USB_INT_HasOccurred(USB_INT_HSOFI)) + if (CurrentFrameNumber != PreviousFrameNumber) { - /* Clear the flag and decrement the timeout period counter */ - USB_INT_Clear(USB_INT_HSOFI); + /* Save the new frame number and decrement the timeout period */ + PreviousFrameNumber = CurrentFrameNumber; TimeoutMSRem--; /* Check to see if the timeout period for the command has elapsed */ diff --git a/Demos/Host/LowLevel/StillImageHost/Lib/StillImageCommands.c b/Demos/Host/LowLevel/StillImageHost/Lib/StillImageCommands.c index a99a95680b61909b68a46cac818c84d233650fd6..861f55b5dee35f8eff6dec67f5bc031e715e517d 100644 --- a/Demos/Host/LowLevel/StillImageHost/Lib/StillImageCommands.c +++ b/Demos/Host/LowLevel/StillImageHost/Lib/StillImageCommands.c @@ -108,28 +108,28 @@ uint8_t SImage_ReceiveEventHeader(void) */ uint8_t SImage_ReceiveBlockHeader(void) { - uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS; + uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS; + uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber(); /* Unfreeze the data IN pipe */ Pipe_SelectPipe(SIMAGE_DATA_IN_PIPE); Pipe_Unfreeze(); /* Wait until data received on the IN pipe */ - while (!(Pipe_IsReadWriteAllowed())) + while (!(Pipe_IsINReceived())) { + uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber(); + /* Check to see if a new frame has been issued (1ms elapsed) */ - if (USB_INT_HasOccurred(USB_INT_HSOFI)) + if (CurrentFrameNumber != PreviousFrameNumber) { - /* Clear the flag and decrement the timeout period counter */ - USB_INT_Clear(USB_INT_HSOFI); + /* Save the new frame number and decrement the timeout period */ + PreviousFrameNumber = CurrentFrameNumber; TimeoutMSRem--; /* Check to see if the timeout period for the command has elapsed */ if (!(TimeoutMSRem)) - { - /* Return error code */ - return PIPE_RWSTREAM_Timeout; - } + return PIPE_RWSTREAM_Timeout; } Pipe_Freeze(); diff --git a/LUFA/Drivers/USB/Class/Host/MassStorage.c b/LUFA/Drivers/USB/Class/Host/MassStorage.c index 14b7741db313582052d4ba22606ed059a46368c0..dfa954c5c5537b643cbb9c72ffa67cf9620d1d7a 100644 --- a/LUFA/Drivers/USB/Class/Host/MassStorage.c +++ b/LUFA/Drivers/USB/Class/Host/MassStorage.c @@ -166,19 +166,21 @@ static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t* const MSInterfaceInf static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo) { - uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS; + uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS; + uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber(); Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber); Pipe_Unfreeze(); while (!(Pipe_IsINReceived())) { - if (USB_INT_HasOccurred(USB_INT_HSOFI)) + uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber(); + + if (CurrentFrameNumber != PreviousFrameNumber) { - USB_INT_Clear(USB_INT_HSOFI); - TimeoutMSRem--; + PreviousFrameNumber = CurrentFrameNumber; - if (!(TimeoutMSRem)) + if (!(TimeoutMSRem--)) return PIPE_RWSTREAM_Timeout; } diff --git a/LUFA/Drivers/USB/Class/Host/StillImage.c b/LUFA/Drivers/USB/Class/Host/StillImage.c index 42c3feca626e6caa118a47f9ebc8e7ae0ed773ab..e08fc76af31b7b129fc889afc35ca9e02e577f38 100644 --- a/LUFA/Drivers/USB/Class/Host/StillImage.c +++ b/LUFA/Drivers/USB/Class/Host/StillImage.c @@ -179,7 +179,8 @@ uint8_t SImage_Host_SendBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceIn uint8_t SImage_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfaceInfo, SI_PIMA_Container_t* const PIMAHeader) { - uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS; + uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS; + uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber(); if ((USB_HostState != HOST_STATE_Configured) || !(SIInterfaceInfo->State.IsActive)) return PIPE_RWSTREAM_DeviceDisconnected; @@ -187,17 +188,16 @@ uint8_t SImage_Host_ReceiveBlockHeader(USB_ClassInfo_SI_Host_t* const SIInterfac Pipe_SelectPipe(SIInterfaceInfo->Config.DataINPipeNumber); Pipe_Unfreeze(); - while (!(Pipe_IsReadWriteAllowed())) + while (!(Pipe_IsINReceived())) { - if (USB_INT_HasOccurred(USB_INT_HSOFI)) + uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber(); + + if (CurrentFrameNumber != PreviousFrameNumber) { - USB_INT_Clear(USB_INT_HSOFI); - TimeoutMSRem--; + PreviousFrameNumber = CurrentFrameNumber; - if (!(TimeoutMSRem)) - { - return PIPE_RWSTREAM_Timeout; - } + if (!(TimeoutMSRem--)) + return PIPE_RWSTREAM_Timeout; } Pipe_Freeze(); diff --git a/LUFA/Drivers/USB/HighLevel/Events.h b/LUFA/Drivers/USB/HighLevel/Events.h index 5c295b61fc212be1e861815151b58b72dda9ff08..ae7debbb73071658209d54ec31b223ca41ad51bd 100644 --- a/LUFA/Drivers/USB/HighLevel/Events.h +++ b/LUFA/Drivers/USB/HighLevel/Events.h @@ -180,6 +180,23 @@ */ void EVENT_USB_Host_DeviceEnumerationComplete(void); + /** Event for USB Start Of Frame detection, when enabled. This event fires at the start of each USB + * frame, once per millisecond, and is synchronized to the USB bus. This can be used as an accurate + * millisecond timer source when the USB bus is not suspended while in host mode. + * + * This event is time-critical; it is run once per millisecond and thus long handlers will significantly + * degrade device performance. This event should only be enabled when needed to reduce device wake-ups. + * + * \note This event is not normally active - it must be manually enabled and disabled via the + * \ref USB_Host_EnableSOFEvents() and \ref USB_Host_DisableSOFEvents() commands after enumeration of + * a USB device. + * \n\n + * + * \note This event does not exist if the USB_DEVICE_ONLY token is supplied to the compiler (see + * \ref Group_USBManagement documentation). + */ + void EVENT_USB_Host_StartOfFrame(void); + /** Event for USB device connection. This event fires when the AVR in device mode and the device is connected * to a host, beginning the enumeration process, measured by a rising level on the AVR's VBUS pin. * @@ -339,6 +356,7 @@ void EVENT_USB_Host_DeviceEnumerationFailed(const uint8_t ErrorCode, const uint8_t SubErrorCode) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub); + void EVENT_USB_Host_StartOfFrame(void) ATTR_WEAK ATTR_ALIAS(USB_Event_Stub); #endif #if defined(USB_CAN_BE_DEVICE) diff --git a/LUFA/Drivers/USB/LowLevel/Device.h b/LUFA/Drivers/USB/LowLevel/Device.h index 17984c719f83a8d39353a8c84b78677b2d935fa0..300793612576e0350c9203d5d8c7f9cd8f47867d 100644 --- a/LUFA/Drivers/USB/LowLevel/Device.h +++ b/LUFA/Drivers/USB/LowLevel/Device.h @@ -140,6 +140,14 @@ }; /* Inline Functions: */ + /** Returns the current USB frame number, when in device mode. Every millisecond the USB bus is active (i.e. enumerated to a host) + * the frame number is incremented by one. + */ + static inline uint16_t USB_Device_GetFrameNumber(void) + { + return UDFNUM; + } + /** Enables the device mode Start Of Frame events. When enabled, this causes the * \ref EVENT_USB_Device_StartOfFrame() event to fire once per millisecond, synchronized to the USB bus, * at the start of each USB frame when enumerated in device mode. diff --git a/LUFA/Drivers/USB/LowLevel/Endpoint.c b/LUFA/Drivers/USB/LowLevel/Endpoint.c index 4b2d1c059b2657267a1bfb06db0d35f17884bedc..fdb6c7469ecfbbdc34e7b86e714ab167af411f8a 100644 --- a/LUFA/Drivers/USB/LowLevel/Endpoint.c +++ b/LUFA/Drivers/USB/LowLevel/Endpoint.c @@ -142,6 +142,8 @@ uint8_t Endpoint_WaitUntilReady(void) uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS; #endif + uint16_t PreviousFrameNumber = USB_Device_GetFrameNumber(); + for (;;) { if (Endpoint_GetEndpointDirection() == ENDPOINT_DIR_IN) @@ -161,10 +163,12 @@ uint8_t Endpoint_WaitUntilReady(void) return ENDPOINT_READYWAIT_BusSuspended; else if (Endpoint_IsStalled()) return ENDPOINT_READYWAIT_EndpointStalled; - - if (USB_INT_HasOccurred(USB_INT_SOFI)) + + uint16_t CurrentFrameNumber = USB_Device_GetFrameNumber(); + + if (CurrentFrameNumber != PreviousFrameNumber) { - USB_INT_Clear(USB_INT_SOFI); + PreviousFrameNumber = CurrentFrameNumber; if (!(TimeoutMSRem--)) return ENDPOINT_READYWAIT_Timeout; diff --git a/LUFA/Drivers/USB/LowLevel/Host.c b/LUFA/Drivers/USB/LowLevel/Host.c index 5b7a714babb8772f8ac2dbf9a683393fb0d03c68..2b66e28b4b7cf783d98622a78aba5bff862907a7 100644 --- a/LUFA/Drivers/USB/LowLevel/Host.c +++ b/LUFA/Drivers/USB/LowLevel/Host.c @@ -194,16 +194,19 @@ void USB_Host_ProcessNextHostState(void) uint8_t USB_Host_WaitMS(uint8_t MS) { - bool BusSuspended = USB_Host_IsBusSuspended(); - uint8_t ErrorCode = HOST_WAITERROR_Successful; + bool BusSuspended = USB_Host_IsBusSuspended(); + uint8_t ErrorCode = HOST_WAITERROR_Successful; + uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber(); USB_Host_ResumeBus(); while (MS) { - if (USB_INT_HasOccurred(USB_INT_HSOFI)) + uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber(); + + if (CurrentFrameNumber != PreviousFrameNumber) { - USB_INT_Clear(USB_INT_HSOFI); + PreviousFrameNumber = CurrentFrameNumber; MS--; } @@ -245,11 +248,13 @@ static void USB_Host_ResetDevice(void) USB_Host_ResetBus(); while (!(USB_Host_IsBusResetComplete())); - USB_Host_ResumeBus(); - USB_INT_Clear(USB_INT_HSOFI); + bool HSOFIEnabled = USB_INT_IsEnabled(USB_INT_HSOFI); + USB_INT_Disable(USB_INT_HSOFI); + USB_INT_Clear(USB_INT_HSOFI); + for (uint8_t MSRem = 10; MSRem != 0; MSRem--) { /* Workaround for powerless-pull-up devices. After a USB bus reset, @@ -267,6 +272,9 @@ static void USB_Host_ResetDevice(void) _delay_ms(1); } + if (HSOFIEnabled) + USB_INT_Enable(USB_INT_HSOFI); + if (BusSuspended) USB_Host_SuspendBus(); diff --git a/LUFA/Drivers/USB/LowLevel/Host.h b/LUFA/Drivers/USB/LowLevel/Host.h index 8623c4ec6b254381261b2324418c727efedec8b2..40f630e845f29706aefac4e65da16084f310ce6e 100644 --- a/LUFA/Drivers/USB/LowLevel/Host.h +++ b/LUFA/Drivers/USB/LowLevel/Host.h @@ -245,6 +245,33 @@ }; /* Inline Functions: */ + /** Returns the current USB frame number, when in host mode. Every millisecond the USB bus is active (i.e. not suspended) + * the frame number is incremented by one. + */ + static inline uint16_t USB_Host_GetFrameNumber(void) + { + return UHFNUM; + } + + /** Enables the host mode Start Of Frame events. When enabled, this causes the + * \ref EVENT_USB_Host_StartOfFrame() event to fire once per millisecond, synchronized to the USB bus, + * at the start of each USB frame when a device is enumerated while in host mode. + */ + static inline void USB_Host_EnableSOFEvents(void) ATTR_ALWAYS_INLINE; + static inline void USB_Host_EnableSOFEvents(void) + { + USB_INT_Enable(USB_INT_HSOFI); + } + + /** Disables the host mode Start Of Frame events. When disabled, this stops the firing of the + * \ref EVENT_USB_Host_StartOfFrame() event when enumerated in host mode. + */ + static inline void USB_Host_DisableSOFEvents(void) ATTR_ALWAYS_INLINE; + static inline void USB_Host_DisableSOFEvents(void) + { + USB_INT_Disable(USB_INT_HSOFI); + } + /** Resets the USB bus, including the endpoints in any attached device and pipes on the AVR host. * USB bus resets leave the default control pipe configured (if already configured). * diff --git a/LUFA/Drivers/USB/LowLevel/Pipe.c b/LUFA/Drivers/USB/LowLevel/Pipe.c index a8eb50f639a1b2db8c6764e01688e99be7403bdd..5f1090245b13c8478a4073c1ac11aadf51ef5c84 100644 --- a/LUFA/Drivers/USB/LowLevel/Pipe.c +++ b/LUFA/Drivers/USB/LowLevel/Pipe.c @@ -133,6 +133,8 @@ uint8_t Pipe_WaitUntilReady(void) #else uint16_t TimeoutMSRem = USB_STREAM_TIMEOUT_MS; #endif + + uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber(); for (;;) { @@ -151,10 +153,12 @@ uint8_t Pipe_WaitUntilReady(void) return PIPE_READYWAIT_PipeStalled; else if (USB_HostState == HOST_STATE_Unattached) return PIPE_READYWAIT_DeviceDisconnected; - - if (USB_INT_HasOccurred(USB_INT_HSOFI)) + + uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber(); + + if (CurrentFrameNumber != PreviousFrameNumber) { - USB_INT_Clear(USB_INT_HSOFI); + PreviousFrameNumber = CurrentFrameNumber; if (!(TimeoutMSRem--)) return PIPE_READYWAIT_Timeout; diff --git a/LUFA/Drivers/USB/LowLevel/USBInterrupt.c b/LUFA/Drivers/USB/LowLevel/USBInterrupt.c index 1c6d6caa79e6765854ea3748d78afbfe84aa25ef..36541cf7fa6654e4802c7bb4a5151e5810aeaaae 100644 --- a/LUFA/Drivers/USB/LowLevel/USBInterrupt.c +++ b/LUFA/Drivers/USB/LowLevel/USBInterrupt.c @@ -209,6 +209,13 @@ ISR(USB_GEN_vect, ISR_BLOCK) USB_ResetInterface(); } + + if (USB_INT_HasOccurred(USB_INT_HSOFI) && USB_INT_IsEnabled(USB_INT_HSOFI)) + { + USB_INT_Clear(USB_INT_HSOFI); + + EVENT_USB_Host_StartOfFrame(); + } #endif #if defined(USB_CAN_BE_BOTH) diff --git a/LUFA/ManPages/ChangeLog.txt b/LUFA/ManPages/ChangeLog.txt index 0467e2815de65bf48f4098cb22dd5bd3bf17e07c..9a801b400d0c96a2478ca7c600a0010c035b0b4e 100644 --- a/LUFA/ManPages/ChangeLog.txt +++ b/LUFA/ManPages/ChangeLog.txt @@ -13,6 +13,9 @@ * - Moved the Pipe and Endpoint stream related code to two new USB library core source files EndpointStream.c and PipeStream.c * - Added board hardware driver support for the Olimex AVR-USB-162 development board (thanks to Steve Fawcett) * - Added board hardware driver support for the USBFOO development board + * - Added new USB_Device_GetFrameNumber() and USB_Host_GetFrameNumber() functions to retrieve the current USB frame number + * - Added new USB_Host_EnableSOFEvents(), USB_Host_DisableSOFEvents() and EVENT_USB_Host_StartOfFrame() for the user application + * handling of USB Start of Frame events while in USB Host mode * * <b>Changed:</b> * - Removed complicated logic for the Endpoint_ConfigureEndpoint() function to use inlined or function called versions @@ -29,6 +32,8 @@ * - Changed the signature of the CALLBACK_USB_GetDescriptor() callback function so that the descriptor pointer is const, to remove * the need for extra casting inside the callback (thanks to Jonathan Kollasch) * - Reduced HOST_DEVICE_SETTLE_DELAY_MS to 1000ms down from 1500ms to improve device compatibility while in USB Host mode + * - Changed over all demos, drivers and internal functions to use the current frame number over the Start of Frame flag where possible + * to free up the Start of Frame flag for interrupt use in the user application * * <b>Fixed:</b> * - Fixed USB_GetHIDReportItemInfo() function modifying the given report item's data when the report item does not exist